@@ -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 ) },
@@ -450,6 +460,13 @@ def plot( data, **kwargs ):
450460 else :
451461 raise TypeError ('style should be a `dict`; why is it not?' )
452462
463+ if config ['mavcolors' ] is not None :
464+ config ['_ma_color_cycle' ] = cycle (config ['mavcolors' ])
465+ elif style ['mavcolors' ] is not None :
466+ config ['_ma_color_cycle' ] = cycle (style ['mavcolors' ])
467+ else :
468+ config ['_ma_color_cycle' ] = None
469+
453470 if not external_axes_mode :
454471 fig = plt .figure ()
455472 _adjust_figsize (fig ,config )
@@ -528,8 +545,10 @@ def plot( data, **kwargs ):
528545
529546 if ptype in VALID_PMOVE_TYPES :
530547 mavprices = _plot_mav (axA1 ,config ,xdates ,pmove_avgvals )
548+ emaprices = _plot_ema (axA1 , config , xdates , pmove_avgvals )
531549 else :
532550 mavprices = _plot_mav (axA1 ,config ,xdates ,closes )
551+ emaprices = _plot_ema (axA1 , config , xdates , closes )
533552
534553 avg_dist_between_points = (xdates [- 1 ] - xdates [0 ]) / float (len (xdates ))
535554 if not config ['tight_layout' ]:
@@ -595,6 +614,13 @@ def plot( data, **kwargs ):
595614 else :
596615 for jj in range (0 ,len (mav )):
597616 retdict ['mav' + str (mav [jj ])] = mavprices [jj ]
617+ if config ['ema' ] is not None :
618+ ema = config ['ema' ]
619+ if len (ema ) != len (emaprices ):
620+ warnings .warn ('len(ema)=' + str (len (ema ))+ ' BUT len(emaprices)=' + str (len (emaprices )))
621+ else :
622+ for jj in range (0 , len (ema )):
623+ retdict ['ema' + str (ema [jj ])] = emaprices [jj ]
598624 retdict ['minx' ] = minx
599625 retdict ['maxx' ] = maxx
600626 retdict ['miny' ] = miny
@@ -1129,10 +1155,7 @@ def _plot_mav(ax,config,xdates,prices,apmav=None,apwidth=None):
11291155 if len (mavgs ) > 7 :
11301156 mavgs = mavgs [0 :7 ] # take at most 7
11311157
1132- if style ['mavcolors' ] is not None :
1133- mavc = cycle (style ['mavcolors' ])
1134- else :
1135- mavc = None
1158+ mavc = config ['_ma_color_cycle' ]
11361159
11371160 for idx ,mav in enumerate (mavgs ):
11381161 mean = pd .Series (prices ).rolling (mav ).mean ()
@@ -1147,6 +1170,42 @@ def _plot_mav(ax,config,xdates,prices,apmav=None,apwidth=None):
11471170 mavp_list .append (mavprices )
11481171 return mavp_list
11491172
1173+
1174+ def _plot_ema (ax ,config ,xdates ,prices ,apmav = None ,apwidth = None ):
1175+ '''ema: exponential moving average'''
1176+ style = config ['style' ]
1177+ if apmav is not None :
1178+ mavgs = apmav
1179+ else :
1180+ mavgs = config ['ema' ]
1181+ mavp_list = []
1182+ if mavgs is not None :
1183+ shift = None
1184+ if isinstance (mavgs ,dict ):
1185+ shift = mavgs ['shift' ]
1186+ mavgs = mavgs ['period' ]
1187+ if isinstance (mavgs ,int ):
1188+ mavgs = mavgs , # convert to tuple
1189+ if len (mavgs ) > 7 :
1190+ mavgs = mavgs [0 :7 ] # take at most 7
1191+
1192+ mavc = config ['_ma_color_cycle' ]
1193+
1194+ for idx ,mav in enumerate (mavgs ):
1195+ # mean = pd.Series(prices).rolling(mav).mean()
1196+ mean = pd .Series (prices ).ewm (span = mav ,adjust = False ).mean ()
1197+ if shift is not None :
1198+ mean = mean .shift (periods = shift [idx ])
1199+ emaprices = mean .values
1200+ lw = config ['_width_config' ]['line_width' ]
1201+ if mavc :
1202+ ax .plot (xdates , emaprices , linewidth = lw , color = next (mavc ))
1203+ else :
1204+ ax .plot (xdates , emaprices , linewidth = lw )
1205+ mavp_list .append (emaprices )
1206+ return mavp_list
1207+
1208+
11501209def _auto_secondary_y ( panels , panid , ylo , yhi ):
11511210 # If mag(nitude) for this panel is not yet set, then set it
11521211 # here, as this is the first ydata to be plotted on this panel:
0 commit comments