Like much of GUI code everywhere, this is a mess.
(*, results: pd.Series,
df: pd.DataFrame,
indicators: List[_Indicator],
filename='', plot_width=None,
plot_equity=True, plot_return=False, plot_pl=True,
plot_volume=True, plot_drawdown=False, plot_trades=True,
smooth_equity=False, relative_equity=True,
superimpose=True, resample=True,
reverse_indicators=True,
show_legend=True, open_browser=True)
| 188 | |
| 189 | |
| 190 | def plot(*, results: pd.Series, |
| 191 | df: pd.DataFrame, |
| 192 | indicators: List[_Indicator], |
| 193 | filename='', plot_width=None, |
| 194 | plot_equity=True, plot_return=False, plot_pl=True, |
| 195 | plot_volume=True, plot_drawdown=False, plot_trades=True, |
| 196 | smooth_equity=False, relative_equity=True, |
| 197 | superimpose=True, resample=True, |
| 198 | reverse_indicators=True, |
| 199 | show_legend=True, open_browser=True): |
| 200 | """ |
| 201 | Like much of GUI code everywhere, this is a mess. |
| 202 | """ |
| 203 | # We need to reset global Bokeh state, otherwise subsequent runs of |
| 204 | # plot() contain some previous run's cruft data (was noticed when |
| 205 | # TestPlot.test_file_size() test was failing). |
| 206 | if not filename and not IS_JUPYTER_NOTEBOOK: |
| 207 | filename = _windos_safe_filename(str(results._strategy)) |
| 208 | _bokeh_reset(filename) |
| 209 | |
| 210 | COLORS = [BEAR_COLOR, BULL_COLOR] |
| 211 | BAR_WIDTH = .8 |
| 212 | |
| 213 | assert df.index.equals(results['_equity_curve'].index) |
| 214 | equity_data = results['_equity_curve'].copy(deep=False) |
| 215 | trades = results['_trades'] |
| 216 | |
| 217 | plot_volume = plot_volume and not df.Volume.isnull().all() |
| 218 | plot_equity = plot_equity and not trades.empty |
| 219 | plot_return = plot_return and not trades.empty |
| 220 | plot_pl = plot_pl and not trades.empty |
| 221 | plot_trades = plot_trades and not trades.empty |
| 222 | is_datetime_index = isinstance(df.index, pd.DatetimeIndex) |
| 223 | |
| 224 | from .lib import OHLCV_AGG |
| 225 | # ohlc df may contain many columns. We're only interested in, and pass on to Bokeh, these |
| 226 | df = df[list(OHLCV_AGG.keys())].copy(deep=False) |
| 227 | |
| 228 | # Limit data to max_candles |
| 229 | if is_datetime_index: |
| 230 | df, indicators, equity_data, trades = _maybe_resample_data( |
| 231 | resample, df, indicators, equity_data, trades) |
| 232 | |
| 233 | df.index.name = None # Provides source name @index |
| 234 | df['datetime'] = df.index # Save original, maybe datetime index |
| 235 | df = df.reset_index(drop=True) |
| 236 | equity_data = equity_data.reset_index(drop=True) |
| 237 | index = df.index |
| 238 | |
| 239 | new_bokeh_figure = partial( # type: ignore[call-arg] |
| 240 | _figure, |
| 241 | x_axis_type='linear', |
| 242 | width=plot_width, |
| 243 | height=400, |
| 244 | # TODO: xwheel_pan on horizontal after https://github.com/bokeh/bokeh/issues/14363 |
| 245 | tools="xpan,xwheel_zoom,xwheel_pan,box_zoom,undo,redo,reset,save", |
| 246 | active_drag='xpan', |
| 247 | active_scroll='xwheel_zoom') |