@@ -119,7 +119,17 @@ def _valid_plot_kwargs():
119119 'mav' : { 'Default' : None ,
120120 'Description' : 'Moving Average window size(s); (int or tuple of ints)' ,
121121 'Validator' : _mav_validator },
122+
123+ 'ema' : { 'Default' : None ,
124+ 'Description' : 'Exponential Moving Average window size(s); (int or tuple of ints)' ,
125+ 'Validator' : _mav_validator },
122126
127+ 'mavcolors' : { 'Default' : None ,
128+ 'Description' : 'color cycle for moving averages (list or tuple of colors)' +
129+ '(overrides mpf style mavcolors).' ,
130+ 'Validator' : lambda value : isinstance (value ,(list ,tuple )) and
131+ all ([mcolors .is_color_like (v ) for v in value ]) },
132+
123133 'renko_params' : { 'Default' : dict (),
124134 'Description' : 'dict of renko parameters; call `mpf.kwarg_help("renko_params")`' ,
125135 'Validator' : lambda value : isinstance (value ,dict ) },
@@ -454,6 +464,13 @@ def plot( data, **kwargs ):
454464 else :
455465 raise TypeError ('style should be a `dict`; why is it not?' )
456466
467+ if config ['mavcolors' ] is not None :
468+ config ['_ma_color_cycle' ] = cycle (config ['mavcolors' ])
469+ elif style ['mavcolors' ] is not None :
470+ config ['_ma_color_cycle' ] = cycle (style ['mavcolors' ])
471+ else :
472+ config ['_ma_color_cycle' ] = None
473+
457474 if not external_axes_mode :
458475 fig = plt .figure ()
459476 _adjust_figsize (fig ,config )
@@ -532,8 +549,10 @@ def plot( data, **kwargs ):
532549
533550 if ptype in VALID_PMOVE_TYPES :
534551 mavprices = _plot_mav (axA1 ,config ,xdates ,pmove_avgvals )
552+ emaprices = _plot_ema (axA1 , config , xdates , pmove_avgvals )
535553 else :
536554 mavprices = _plot_mav (axA1 ,config ,xdates ,closes )
555+ emaprices = _plot_ema (axA1 , config , xdates , closes )
537556
538557 avg_dist_between_points = (xdates [- 1 ] - xdates [0 ]) / float (len (xdates ))
539558 if not config ['tight_layout' ]:
@@ -599,6 +618,13 @@ def plot( data, **kwargs ):
599618 else :
600619 for jj in range (0 ,len (mav )):
601620 retdict ['mav' + str (mav [jj ])] = mavprices [jj ]
621+ if config ['ema' ] is not None :
622+ ema = config ['ema' ]
623+ if len (ema ) != len (emaprices ):
624+ warnings .warn ('len(ema)=' + str (len (ema ))+ ' BUT len(emaprices)=' + str (len (emaprices )))
625+ else :
626+ for jj in range (0 , len (ema )):
627+ retdict ['ema' + str (ema [jj ])] = emaprices [jj ]
602628 retdict ['minx' ] = minx
603629 retdict ['maxx' ] = maxx
604630 retdict ['miny' ] = miny
@@ -1140,10 +1166,7 @@ def _plot_mav(ax,config,xdates,prices,apmav=None,apwidth=None):
11401166 if len (mavgs ) > 7 :
11411167 mavgs = mavgs [0 :7 ] # take at most 7
11421168
1143- if style ['mavcolors' ] is not None :
1144- mavc = cycle (style ['mavcolors' ])
1145- else :
1146- mavc = None
1169+ mavc = config ['_ma_color_cycle' ]
11471170
11481171 for idx ,mav in enumerate (mavgs ):
11491172 mean = pd .Series (prices ).rolling (mav ).mean ()
@@ -1158,6 +1181,42 @@ def _plot_mav(ax,config,xdates,prices,apmav=None,apwidth=None):
11581181 mavp_list .append (mavprices )
11591182 return mavp_list
11601183
1184+
1185+ def _plot_ema (ax ,config ,xdates ,prices ,apmav = None ,apwidth = None ):
1186+ '''ema: exponential moving average'''
1187+ style = config ['style' ]
1188+ if apmav is not None :
1189+ mavgs = apmav
1190+ else :
1191+ mavgs = config ['ema' ]
1192+ mavp_list = []
1193+ if mavgs is not None :
1194+ shift = None
1195+ if isinstance (mavgs ,dict ):
1196+ shift = mavgs ['shift' ]
1197+ mavgs = mavgs ['period' ]
1198+ if isinstance (mavgs ,int ):
1199+ mavgs = mavgs , # convert to tuple
1200+ if len (mavgs ) > 7 :
1201+ mavgs = mavgs [0 :7 ] # take at most 7
1202+
1203+ mavc = config ['_ma_color_cycle' ]
1204+
1205+ for idx ,mav in enumerate (mavgs ):
1206+ # mean = pd.Series(prices).rolling(mav).mean()
1207+ mean = pd .Series (prices ).ewm (span = mav ,adjust = False ).mean ()
1208+ if shift is not None :
1209+ mean = mean .shift (periods = shift [idx ])
1210+ emaprices = mean .values
1211+ lw = config ['_width_config' ]['line_width' ]
1212+ if mavc :
1213+ ax .plot (xdates , emaprices , linewidth = lw , color = next (mavc ))
1214+ else :
1215+ ax .plot (xdates , emaprices , linewidth = lw )
1216+ mavp_list .append (emaprices )
1217+ return mavp_list
1218+
1219+
11611220def _auto_secondary_y ( panels , panid , ylo , yhi ):
11621221 # If mag(nitude) for this panel is not yet set, then set it
11631222 # here, as this is the first ydata to be plotted on this panel:
0 commit comments