59
59
Center of mass: :math:`\alpha = 1 / (1 + com)`,
60
60
span : float, optional
61
61
Specify decay in terms of span, :math:`\alpha = 2 / (span + 1)`
62
+ halflife : float, optional
63
+ Specify decay in terms of halflife, :math: `\alpha = 1 - exp(log(0.5) / halflife)`
62
64
min_periods : int, default 0
63
65
Number of observations in sample to require (only affects
64
66
beginning)
@@ -338,25 +340,29 @@ def _process_data_structure(arg, kill_inf=True):
338
340
# Exponential moving moments
339
341
340
342
341
- def _get_center_of_mass (com , span ):
342
- if span is not None :
343
- if com is not None :
344
- raise Exception ("com and span are mutually exclusive" )
343
+ def _get_center_of_mass (com , span , halflife ):
344
+ valid_count = len ([ x for x in [ com , span , halflife ] if x is not None ])
345
+ if valid_count > 1 :
346
+ raise Exception ("com, span, and halflife are mutually exclusive" )
345
347
348
+ if span is not None :
346
349
# convert span to center of mass
347
350
com = (span - 1 ) / 2.
348
-
351
+ elif halflife is not None :
352
+ # convert halflife to center of mass
353
+ decay = 1 - np .exp (np .log (0.5 ) / halflife )
354
+ com = 1 / decay - 1
349
355
elif com is None :
350
- raise Exception ("Must pass either com or span " )
356
+ raise Exception ("Must pass one of com, span, or halflife " )
351
357
352
358
return float (com )
353
359
354
360
355
361
@Substitution ("Exponentially-weighted moving average" , _unary_arg , "" )
356
362
@Appender (_ewm_doc )
357
- def ewma (arg , com = None , span = None , min_periods = 0 , freq = None , time_rule = None ,
363
+ def ewma (arg , com = None , span = None , halflife = None , min_periods = 0 , freq = None , time_rule = None ,
358
364
adjust = True ):
359
- com = _get_center_of_mass (com , span )
365
+ com = _get_center_of_mass (com , span , halflife )
360
366
arg = _conv_timerule (arg , freq , time_rule )
361
367
362
368
def _ewma (v ):
@@ -377,9 +383,9 @@ def _first_valid_index(arr):
377
383
378
384
@Substitution ("Exponentially-weighted moving variance" , _unary_arg , _bias_doc )
379
385
@Appender (_ewm_doc )
380
- def ewmvar (arg , com = None , span = None , min_periods = 0 , bias = False ,
386
+ def ewmvar (arg , com = None , span = None , halflife = None , min_periods = 0 , bias = False ,
381
387
freq = None , time_rule = None ):
382
- com = _get_center_of_mass (com , span )
388
+ com = _get_center_of_mass (com , span , halflife )
383
389
arg = _conv_timerule (arg , freq , time_rule )
384
390
moment2nd = ewma (arg * arg , com = com , min_periods = min_periods )
385
391
moment1st = ewma (arg , com = com , min_periods = min_periods )
@@ -393,9 +399,9 @@ def ewmvar(arg, com=None, span=None, min_periods=0, bias=False,
393
399
394
400
@Substitution ("Exponentially-weighted moving std" , _unary_arg , _bias_doc )
395
401
@Appender (_ewm_doc )
396
- def ewmstd (arg , com = None , span = None , min_periods = 0 , bias = False ,
402
+ def ewmstd (arg , com = None , span = None , halflife = None , min_periods = 0 , bias = False ,
397
403
time_rule = None ):
398
- result = ewmvar (arg , com = com , span = span , time_rule = time_rule ,
404
+ result = ewmvar (arg , com = com , span = span , halflife = halflife , time_rule = time_rule ,
399
405
min_periods = min_periods , bias = bias )
400
406
return _zsqrt (result )
401
407
@@ -404,17 +410,17 @@ def ewmstd(arg, com=None, span=None, min_periods=0, bias=False,
404
410
405
411
@Substitution ("Exponentially-weighted moving covariance" , _binary_arg , "" )
406
412
@Appender (_ewm_doc )
407
- def ewmcov (arg1 , arg2 , com = None , span = None , min_periods = 0 , bias = False ,
413
+ def ewmcov (arg1 , arg2 , com = None , span = None , halflife = None , min_periods = 0 , bias = False ,
408
414
freq = None , time_rule = None ):
409
415
X , Y = _prep_binary (arg1 , arg2 )
410
416
411
417
X = _conv_timerule (X , freq , time_rule )
412
418
Y = _conv_timerule (Y , freq , time_rule )
413
419
414
- mean = lambda x : ewma (x , com = com , span = span , min_periods = min_periods )
420
+ mean = lambda x : ewma (x , com = com , span = span , halflife = halflife , min_periods = min_periods )
415
421
416
422
result = (mean (X * Y ) - mean (X ) * mean (Y ))
417
- com = _get_center_of_mass (com , span )
423
+ com = _get_center_of_mass (com , span , halflife )
418
424
if not bias :
419
425
result *= (1.0 + 2.0 * com ) / (2.0 * com )
420
426
@@ -423,15 +429,15 @@ def ewmcov(arg1, arg2, com=None, span=None, min_periods=0, bias=False,
423
429
424
430
@Substitution ("Exponentially-weighted moving " "correlation" , _binary_arg , "" )
425
431
@Appender (_ewm_doc )
426
- def ewmcorr (arg1 , arg2 , com = None , span = None , min_periods = 0 ,
432
+ def ewmcorr (arg1 , arg2 , com = None , span = None , halflife = None , min_periods = 0 ,
427
433
freq = None , time_rule = None ):
428
434
X , Y = _prep_binary (arg1 , arg2 )
429
435
430
436
X = _conv_timerule (X , freq , time_rule )
431
437
Y = _conv_timerule (Y , freq , time_rule )
432
438
433
- mean = lambda x : ewma (x , com = com , span = span , min_periods = min_periods )
434
- var = lambda x : ewmvar (x , com = com , span = span , min_periods = min_periods ,
439
+ mean = lambda x : ewma (x , com = com , span = span , halflife = halflife , min_periods = min_periods )
440
+ var = lambda x : ewmvar (x , com = com , span = span , halflife = halflife , min_periods = min_periods ,
435
441
bias = True )
436
442
return (mean (X * Y ) - mean (X ) * mean (Y )) / _zsqrt (var (X ) * var (Y ))
437
443
0 commit comments