import matplotlib.pyplot as plt import pandas as pd import numpy as np import json from pure_funcs import round_dynamic, denumpyize, candidate_to_live_config from njit_funcs import round_up from procedures import dump_live_config def dump_plots(result: dict, fdf: pd.DataFrame, df: pd.DataFrame): plt.rcParams['figure.figsize'] = [29, 18] pd.set_option('precision', 10) def gain_conv(x): return x * 100 - 100 lines = [] lines.append(f"exchange {result['exchange'] if 'exchange' in result else 'unknown'}") lines.append(f"symbol {result['symbol'] if 'symbol' in result else 'unknown'}") lines.append(f"gain percentage {round_dynamic(result['result']['gain'] * 100 - 100, 4)}%") lines.append(f"average_daily_gain percentage {round_dynamic((result['result']['average_daily_gain'] - 1) * 100, 3)}%") lines.append(f"sharpe_gain_ratio percentage {round_dynamic(result['result']['sharpe_gain_ratio'] * 100, 3)}%") lines.append(f"closest_bkr percentage {round_dynamic(result['result']['closest_bkr'] * 100, 4)}%") lines.append(f"starting balance {round_dynamic(result['starting_balance'], 3)}") for key in [k for k in result['result'] if k not in ['gain', 'average_daily_gain', 'closest_bkr', 'do_long', 'do_shrt']]: lines.append(f"{key} {round_dynamic(result['result'][key], 6)}") lines.append(f"long: {result['do_long']}, short: {result['do_shrt']}") longs = fdf[fdf.type.str.contains('long')] shrts = fdf[fdf.type.str.contains('shrt')] lines.append(f"n long ientries {len(longs[longs.type == 'long_ientry'])}") lines.append(f"n long rentries {len(longs[longs.type == 'long_rentry'])}") lines.append(f"n long ncloses {len(longs[longs.type == 'long_nclose'])}") lines.append(f"n long scloses {len(longs[longs.type == 'long_sclose'])}") lines.append(f"long pnl sum {longs.pnl.sum()}") lines.append(f"n shrt ientries {len(shrts[shrts.type == 'shrt_ientry'])}") lines.append(f"n shrt rentries {len(shrts[shrts.type == 'shrt_rentry'])}") lines.append(f"n shrt ncloses {len(shrts[shrts.type == 'shrt_nclose'])}") lines.append(f"n shrt scloses {len(shrts[shrts.type == 'shrt_sclose'])}") lines.append(f"shrt pnl sum {shrts.pnl.sum()}") live_config = candidate_to_live_config(result) dump_live_config(live_config, result['plots_dirpath'] + 'live_config.json') json.dump(denumpyize(result), open(result['plots_dirpath'] + 'result.json', 'w'), indent=4) print('writing backtest_result.txt...') with open(f"{result['plots_dirpath']}backtest_result.txt", 'w') as f: for line in lines: print(line) f.write(line + '\n') print('plotting balance and equity...') plt.clf() fdf.balance.plot() fdf.equity.plot() plt.savefig(f"{result['plots_dirpath']}balance_and_equity.png") plt.clf() longs.pnl.cumsum().plot() plt.savefig(f"{result['plots_dirpath']}pnl_cumsum_long.png") plt.clf() shrts.pnl.cumsum().plot() plt.savefig(f"{result['plots_dirpath']}pnl_cumsum_shrt.png") plt.clf() fdf.adg.plot() plt.savefig(f"{result['plots_dirpath']}adg.png") print('plotting backtest whole and in chunks...') n_parts = max(3, int(round_up(result['n_days'] / 14, 1.0))) for z in range(n_parts): start_ = z / n_parts end_ = (z + 1) / n_parts print(f'{z} of {n_parts} {start_ * 100:.2f}% to {end_ * 100:.2f}%') fig = plot_fills(df, fdf.iloc[int(len(fdf) * start_):int(len(fdf) * end_)], bkr_thr=0.1) fig.savefig(f"{result['plots_dirpath']}backtest_{z + 1}of{n_parts}.png") fig = plot_fills(df, fdf, bkr_thr=0.1) fig.savefig(f"{result['plots_dirpath']}whole_backtest.png") print('plotting pos sizes...') plt.clf() longs.psize.plot() shrts.psize.plot() plt.savefig(f"{result['plots_dirpath']}psizes_plot.png") def plot_fills(df, fdf_, side: int = 0, bkr_thr=0.1): plt.clf() fdf = fdf_.set_index('timestamp') dfc = df.iloc[::max(1, int(len(df) * 0.00001))] dfc = dfc[(dfc.timestamp > fdf.index[0]) & (dfc.timestamp < fdf.index[-1])].set_index('timestamp') dfc = dfc.loc[fdf.index[0]:fdf.index[-1]] dfc.price.plot(style='y-') if side >= 0: longs = fdf[fdf.type.str.contains('long')] lnentry = longs[(longs.type == 'long_ientry') | (longs.type == 'long_rentry')] lhentry = longs[longs.type == 'long_hentry'] lnclose = longs[longs.type == 'long_nclose'] lsclose = longs[longs.type == 'long_sclose'] lnentry.price.plot(style='b.') lhentry.price.plot(style='bx') lnclose.price.plot(style='r.') lsclose.price.plot(style=('rx')) longs.where(longs.pprice != 0.0).pprice.fillna(method='ffill').plot(style='b--') if side <= 0: shrts = fdf[fdf.type.str.contains('shrt')] snentry = shrts[(shrts.type == 'shrt_ientry') | (shrts.type == 'shrt_rentry')] shentry = shrts[shrts.type == 'shrt_hentry'] snclose = shrts[shrts.type == 'shrt_nclose'] ssclose = shrts[shrts.type == 'shrt_sclose'] snentry.price.plot(style='r.') shentry.price.plot(style='rx') snclose.price.plot(style='b.') ssclose.price.plot(style=('bx')) shrts.where(shrts.pprice != 0.0).pprice.fillna(method='ffill').plot(style='r--') if 'bkr_price' in fdf.columns: fdf.bkr_price.where(fdf.bkr_diff < bkr_thr, np.nan).plot(style='k--') return plt