forked from enarjord/passivbot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
plotting.py
131 lines (109 loc) · 5.45 KB
/
plotting.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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_ratio percentage {round_dynamic(result['result']['sharpe_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)
if fig is not None:
fig.savefig(f"{result['plots_dirpath']}backtest_{z + 1}of{n_parts}.png")
else:
print('no fills...')
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):
if fdf_.empty:
return
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