plotguy 2.2.4__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plotguy-2.2.4 → plotguy-2.3.0}/PKG-INFO +1 -1
- {plotguy-2.2.4 → plotguy-2.3.0}/plotguy/__init__.py +44 -4
- {plotguy-2.2.4 → plotguy-2.3.0}/plotguy/aggregate.py +1 -1
- {plotguy-2.2.4 → plotguy-2.3.0}/plotguy/components.py +54 -127
- {plotguy-2.2.4 → plotguy-2.3.0}/plotguy/equity_curves.py +27 -22
- {plotguy-2.2.4 → plotguy-2.3.0}/plotguy.egg-info/PKG-INFO +1 -1
- {plotguy-2.2.4 → plotguy-2.3.0}/setup.py +1 -1
- {plotguy-2.2.4 → plotguy-2.3.0}/README.md +0 -0
- {plotguy-2.2.4 → plotguy-2.3.0}/plotguy/signals.py +0 -0
- {plotguy-2.2.4 → plotguy-2.3.0}/plotguy.egg-info/SOURCES.txt +0 -0
- {plotguy-2.2.4 → plotguy-2.3.0}/plotguy.egg-info/dependency_links.txt +0 -0
- {plotguy-2.2.4 → plotguy-2.3.0}/plotguy.egg-info/requires.txt +0 -0
- {plotguy-2.2.4 → plotguy-2.3.0}/plotguy.egg-info/top_level.txt +0 -0
- {plotguy-2.2.4 → plotguy-2.3.0}/setup.cfg +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import warnings
|
|
2
2
|
warnings.simplefilter("ignore", UserWarning)
|
|
3
|
+
#warnings.simplefilter("ignore", RuntimeWarning)
|
|
3
4
|
|
|
4
5
|
import datetime
|
|
5
6
|
import os
|
|
@@ -12,6 +13,7 @@ import requests
|
|
|
12
13
|
import pandas as pd
|
|
13
14
|
import numpy as np
|
|
14
15
|
import io
|
|
16
|
+
import re
|
|
15
17
|
|
|
16
18
|
from .equity_curves import *
|
|
17
19
|
from .signals import *
|
|
@@ -135,6 +137,8 @@ def save_backtest_result(df, para_combination_item):
|
|
|
135
137
|
### for intraday ###
|
|
136
138
|
if intraday:
|
|
137
139
|
df_daily = df.resample('D').agg({'price': agg_price})
|
|
140
|
+
#df_daily = df.resample('D').agg({'price': agg_price, 'equity_value': agg_price})
|
|
141
|
+
df_daily = df_daily[df_daily['price'].notna()]
|
|
138
142
|
else:
|
|
139
143
|
df_daily = df
|
|
140
144
|
|
|
@@ -196,6 +200,7 @@ def save_backtest_result(df, para_combination_item):
|
|
|
196
200
|
yearly_stats_string += f'{year},year_trade_count:0.00,year_win_rate:00.00,year_return:-00.00|'
|
|
197
201
|
|
|
198
202
|
yearly_stats_string = yearly_stats_string[:-1]
|
|
203
|
+
correlation = 0
|
|
199
204
|
|
|
200
205
|
elif len(df_count) > 0:
|
|
201
206
|
|
|
@@ -277,8 +282,11 @@ def save_backtest_result(df, para_combination_item):
|
|
|
277
282
|
equity_net_profit = df.at[df.index[-1], 'equity_value'] - df.at[df.index[0], 'equity_value']
|
|
278
283
|
|
|
279
284
|
equity_return_on_capital = equity_net_profit / df.at[df.index[0], 'equity_value']
|
|
280
|
-
|
|
281
|
-
|
|
285
|
+
if 1 + equity_return_on_capital > 0:
|
|
286
|
+
equity_annualized_return = (np.sign(1 + equity_return_on_capital) * np.abs(1 + equity_return_on_capital)) ** (365 / holding_period_day) - 1
|
|
287
|
+
else:
|
|
288
|
+
equity_annualized_return = -1
|
|
289
|
+
|
|
282
290
|
equity_annualized_std = equity_pct_series.std() * math.sqrt(365)
|
|
283
291
|
equity_annualized_sr = (
|
|
284
292
|
equity_annualized_return - risk_free_rate / 100) / equity_annualized_std if equity_annualized_std != 0 else 0
|
|
@@ -290,8 +298,14 @@ def save_backtest_result(df, para_combination_item):
|
|
|
290
298
|
equity_annualized_sr = round(equity_annualized_sr, 2)
|
|
291
299
|
equity_net_profit_to_mdd = round(100 * equity_net_profit_to_mdd, 2)
|
|
292
300
|
|
|
301
|
+
df['equity_return'] = df['equity_value'].pct_change() * 100
|
|
302
|
+
df['price_return'] = df['price'].pct_change() * 100
|
|
303
|
+
|
|
304
|
+
correlation = df['equity_return'].corr(df['price_return'])
|
|
305
|
+
|
|
293
306
|
if long_short == 'short':
|
|
294
307
|
return_on_capital_diff = equity_annualized_return - (-1) * price_annualized_return
|
|
308
|
+
correlation *= -1
|
|
295
309
|
else:
|
|
296
310
|
### consider both long and long_short ###
|
|
297
311
|
return_on_capital_diff = equity_annualized_return - price_annualized_return
|
|
@@ -311,6 +325,7 @@ def save_backtest_result(df, para_combination_item):
|
|
|
311
325
|
cov_return = round(cov_return, 2)
|
|
312
326
|
cov_count = round(cov_count, 2)
|
|
313
327
|
total_commission = int(round(total_commission))
|
|
328
|
+
correlation = round(correlation, 3)
|
|
314
329
|
|
|
315
330
|
backtest_result_dict = {
|
|
316
331
|
'ref_code': ref_code,
|
|
@@ -342,6 +357,7 @@ def save_backtest_result(df, para_combination_item):
|
|
|
342
357
|
'yearly_stats_string': yearly_stats_string,
|
|
343
358
|
'cov_return': cov_return,
|
|
344
359
|
'cov_count': cov_count,
|
|
360
|
+
'correlation': correlation,
|
|
345
361
|
'total_commission': total_commission
|
|
346
362
|
}
|
|
347
363
|
|
|
@@ -384,16 +400,40 @@ def get_risk_free_rate(start_date, end_date):
|
|
|
384
400
|
# return app
|
|
385
401
|
|
|
386
402
|
|
|
387
|
-
def plot(mode, backtest_result_df = None, number_of_curves=20):
|
|
403
|
+
def plot(mode, backtest_result_df = None, number_of_curves=20, filter_list= []):
|
|
388
404
|
|
|
389
405
|
if mode == 'equity_curves':
|
|
390
|
-
|
|
406
|
+
if len(filter_list) > 0: filter_list = convert_filter_list(filter_list)
|
|
407
|
+
app = equity_curves.Plot(backtest_result_df, number_of_curves, filter_list)
|
|
391
408
|
|
|
392
409
|
if mode == 'aggregate':
|
|
393
410
|
app = aggregate.Aggregate()
|
|
394
411
|
|
|
395
412
|
return app
|
|
396
413
|
|
|
414
|
+
def convert_filter_list(filter_list):
|
|
415
|
+
'''
|
|
416
|
+
filter string as follows
|
|
417
|
+
equity_return_on_capital eg: 50% --> 50
|
|
418
|
+
equity_annualized_return eg: 50% --> 50
|
|
419
|
+
return_on_capital_diff eg: 50% --> 50
|
|
420
|
+
equity_annualized_sr eg: 0.9
|
|
421
|
+
equity_mdd_pct eg: 50% --> 50
|
|
422
|
+
num_of_trade eg: 10
|
|
423
|
+
cov_count eg: 1
|
|
424
|
+
cov_return eg: 1
|
|
425
|
+
correlation eg: 0.5
|
|
426
|
+
win_rate eg: 50% --> 50
|
|
427
|
+
'''
|
|
428
|
+
|
|
429
|
+
for i in range(len(filter_list)):
|
|
430
|
+
filter = filter_list[i]
|
|
431
|
+
pattern = r'([a-zA-Z_]+)([<>=]+)(-?\d+\.?\d*)'
|
|
432
|
+
match = re.match(pattern, filter)
|
|
433
|
+
|
|
434
|
+
filter_list[i] = [match.group(1), match.group(2), match.group(3)]
|
|
435
|
+
|
|
436
|
+
return filter_list
|
|
397
437
|
|
|
398
438
|
def get_latest_fed_fund_rate():
|
|
399
439
|
url = "https://fred.stlouisfed.org/series/FEDFUNDS"
|
|
@@ -260,7 +260,7 @@ class Aggregate:
|
|
|
260
260
|
|
|
261
261
|
df_current = pd.DataFrame()
|
|
262
262
|
|
|
263
|
-
df_current[f'{row[
|
|
263
|
+
df_current[f'{row["folder"]}_{row["backtest_name"]}_{i}'] = df["equity_value"]
|
|
264
264
|
df_current.index = df.index
|
|
265
265
|
df_list.append(df_current.copy())
|
|
266
266
|
|
|
@@ -35,7 +35,6 @@ class Components:
|
|
|
35
35
|
children=dbc.Select(id='filter_name',
|
|
36
36
|
placeholder="Select Filter",
|
|
37
37
|
options=[
|
|
38
|
-
{'label': 'Exclude Stock', 'value': 'exclude'},
|
|
39
38
|
{'label': 'Return on Capital >', 'value': 'equity_return_on_capital>'},
|
|
40
39
|
{'label': 'Return on Capital <', 'value': 'equity_return_on_capital<'},
|
|
41
40
|
{'label': 'Annualized Return >', 'value': 'equity_annualized_return>'},
|
|
@@ -52,6 +51,8 @@ class Components:
|
|
|
52
51
|
{'label': 'COV (Count) <', 'value': 'cov_count<'},
|
|
53
52
|
{'label': 'COV (Return) >', 'value': 'cov_return>'},
|
|
54
53
|
{'label': 'COV (Return) <', 'value': 'cov_return<'},
|
|
54
|
+
{'label': 'Correlation <', 'value': 'correlation<'},
|
|
55
|
+
{'label': 'Correlation >', 'value': 'correlation>'},
|
|
55
56
|
{'label': 'Win Rate >', 'value': 'win_rate>'},
|
|
56
57
|
{'label': 'Win Rate <', 'value': 'win_rate<'},
|
|
57
58
|
],
|
|
@@ -176,79 +177,6 @@ class Components:
|
|
|
176
177
|
|
|
177
178
|
return checkbox_div, code_list
|
|
178
179
|
|
|
179
|
-
def update_stat_div(self, period, pct_mean, rise_mean, fall_mean):
|
|
180
|
-
div = html.Div([
|
|
181
|
-
|
|
182
|
-
dbc.Row([
|
|
183
|
-
dbc.Col(width=2),
|
|
184
|
-
dbc.Col(str(period[0]) + ' Days', width=2),
|
|
185
|
-
dbc.Col(str(period[1]) + ' Days', width=2),
|
|
186
|
-
dbc.Col(str(period[2]) + ' Days', width=2),
|
|
187
|
-
dbc.Col(str(period[3]) + ' Days', width=2),
|
|
188
|
-
dbc.Col(str(period[4]) + ' Days', width=2),
|
|
189
|
-
]),
|
|
190
|
-
|
|
191
|
-
dbc.Row([
|
|
192
|
-
dbc.Col('pct_change', width=2),
|
|
193
|
-
dbc.Col(f'{pct_mean[0]}%', width=2),
|
|
194
|
-
dbc.Col(f'{pct_mean[1]}%', width=2),
|
|
195
|
-
dbc.Col(f'{pct_mean[2]}%', width=2),
|
|
196
|
-
dbc.Col(f'{pct_mean[3]}%', width=2),
|
|
197
|
-
dbc.Col(f'{pct_mean[4]}%', width=2),
|
|
198
|
-
]),
|
|
199
|
-
|
|
200
|
-
dbc.Row([
|
|
201
|
-
dbc.Col('max_rise', width=2),
|
|
202
|
-
dbc.Col(f'{rise_mean[0]}%', width=2),
|
|
203
|
-
dbc.Col(f'{rise_mean[1]}%', width=2),
|
|
204
|
-
dbc.Col(f'{rise_mean[2]}%', width=2),
|
|
205
|
-
dbc.Col(f'{rise_mean[3]}%', width=2),
|
|
206
|
-
dbc.Col(f'{rise_mean[4]}%', width=2),
|
|
207
|
-
]),
|
|
208
|
-
|
|
209
|
-
dbc.Row([
|
|
210
|
-
dbc.Col('max_fall', width=2),
|
|
211
|
-
dbc.Col(f'{fall_mean[0]}%', width=2),
|
|
212
|
-
dbc.Col(f'{fall_mean[1]}%', width=2),
|
|
213
|
-
dbc.Col(f'{fall_mean[2]}%', width=2),
|
|
214
|
-
dbc.Col(f'{fall_mean[3]}%', width=2),
|
|
215
|
-
dbc.Col(f'{fall_mean[4]}%', width=2),
|
|
216
|
-
]),
|
|
217
|
-
|
|
218
|
-
])
|
|
219
|
-
|
|
220
|
-
return div
|
|
221
|
-
|
|
222
|
-
def generate_radioitems(self, para_dict):
|
|
223
|
-
radioitems_div = []
|
|
224
|
-
|
|
225
|
-
for i, key in enumerate(para_dict):
|
|
226
|
-
options = para_dict[key]
|
|
227
|
-
|
|
228
|
-
radioitems_div.append(html.Div(key,style={'color': 'Yellow','font-size': '14px'}))
|
|
229
|
-
|
|
230
|
-
radioitems_div.append(dcc.RadioItems(
|
|
231
|
-
id={'type': 'para_radioitems', 'index': i},
|
|
232
|
-
options=[{'label': k,
|
|
233
|
-
'value': k} for k in options],
|
|
234
|
-
labelStyle={'font-size': '13px'},
|
|
235
|
-
inputStyle={'margin-left': '10px', 'margin-right': '5px'}
|
|
236
|
-
|
|
237
|
-
), )
|
|
238
|
-
|
|
239
|
-
radioitems_div.append(html.Div(html.Img(),style={'height':'10px'}))
|
|
240
|
-
|
|
241
|
-
return radioitems_div
|
|
242
|
-
|
|
243
|
-
def selection_title(self, para_dict, values):
|
|
244
|
-
title = []
|
|
245
|
-
for i, key in enumerate(para_dict):
|
|
246
|
-
title.append(dbc.Row(
|
|
247
|
-
[dbc.Col(key, width=6),
|
|
248
|
-
dbc.Col(f'{values[i]}', style={'text-align': 'center'}, width=6)]))
|
|
249
|
-
|
|
250
|
-
return title
|
|
251
|
-
|
|
252
180
|
def update_performance_matrix(self, init_chart, para_keys_list, result_df, line_selected = 0):
|
|
253
181
|
|
|
254
182
|
if init_chart:
|
|
@@ -258,8 +186,6 @@ class Components:
|
|
|
258
186
|
ref_code = result_df.loc[line_selected].ref_code
|
|
259
187
|
|
|
260
188
|
yearly_stats_string = result_df.loc[line_selected]['yearly_stats_string']
|
|
261
|
-
print(result_df)
|
|
262
|
-
print(yearly_stats_string)
|
|
263
189
|
|
|
264
190
|
per_col1 =[]
|
|
265
191
|
per_col2 = []
|
|
@@ -270,6 +196,7 @@ class Components:
|
|
|
270
196
|
per_col_2_3 = [html.Div('BaH',style={'text-align': 'center', 'font-weight': 'bold', 'color':'yellow'})]
|
|
271
197
|
|
|
272
198
|
keys = ['num_of_trade',
|
|
199
|
+
'correlation',
|
|
273
200
|
'equity_net_profit',
|
|
274
201
|
'equity_net_profit_to_mdd',
|
|
275
202
|
'return_on_capital_diff',
|
|
@@ -330,39 +257,57 @@ class Components:
|
|
|
330
257
|
|
|
331
258
|
result_df['risk_free_rate'] = result_df['risk_free_rate'].apply(lambda x: f"{x:.2f} %")
|
|
332
259
|
|
|
260
|
+
div_padding = '5px'
|
|
261
|
+
|
|
333
262
|
per_col_1_1.append(html.Div('Number of Trade', style={'background-color': 'darkblue' }))
|
|
334
|
-
per_col_1_1.append(html.Div('
|
|
335
|
-
per_col_1_1.append(html.Div(
|
|
336
|
-
|
|
337
|
-
per_col_1_1.append(html.Div('
|
|
338
|
-
per_col_1_1.append(html.Div('
|
|
339
|
-
per_col_1_1.append(html.Div(
|
|
340
|
-
|
|
341
|
-
per_col_1_1.append(html.Div('
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
263
|
+
per_col_1_1.append(html.Div('Correlation'))
|
|
264
|
+
per_col_1_1.append(html.Div(style={'height': div_padding}))
|
|
265
|
+
|
|
266
|
+
per_col_1_1.append(html.Div('Net Profit', style={'background-color': 'darkblue' }))
|
|
267
|
+
per_col_1_1.append(html.Div('Net Profit/MDD'))
|
|
268
|
+
per_col_1_1.append(html.Div(style={'height': div_padding}))
|
|
269
|
+
|
|
270
|
+
per_col_1_1.append(html.Div('Return-BaH % Diff.', style={'background-color': 'darkblue' }))
|
|
271
|
+
per_col_1_1.append(html.Div('Win Rate'))
|
|
272
|
+
per_col_1_1.append(html.Div(style={'height': div_padding}))
|
|
273
|
+
|
|
274
|
+
per_col_1_1.append(html.Div('COV (Count)', style={'background-color': 'darkblue' }))
|
|
275
|
+
per_col_1_1.append(html.Div('COV (Return)'))
|
|
276
|
+
per_col_1_1.append(html.Div(style={'height': div_padding}))
|
|
277
|
+
|
|
278
|
+
per_col_1_1.append(html.Div('Total Commission', style={'background-color': 'darkblue' }))
|
|
279
|
+
per_col_1_1.append(html.Div('Risk Free Rate'))
|
|
280
|
+
|
|
281
|
+
per_col_2_1.append(html.Div('Return on Capital', style={'background-color': 'darkblue' }))
|
|
282
|
+
per_col_2_1.append(html.Div('Ann. Return'))
|
|
283
|
+
per_col_2_1.append(html.Div(style={'height': div_padding}))
|
|
284
|
+
per_col_2_1.append(html.Div('Ann. Std', style={'background-color': 'darkblue' }))
|
|
285
|
+
per_col_2_1.append(html.Div('Ann. Sharpe Ratio'))
|
|
286
|
+
per_col_2_1.append(html.Div(style={'height': div_padding}))
|
|
287
|
+
per_col_2_1.append(html.Div('MDD Dollar', style={'background-color': 'darkblue' }))
|
|
288
|
+
per_col_2_1.append(html.Div('MDD Percentage'))
|
|
289
|
+
|
|
290
|
+
for i in range(10):
|
|
351
291
|
content = result_df.iloc[0][keys[i]]
|
|
352
292
|
if i%2 == 1:
|
|
353
293
|
per_col_1_2.append(html.Div(content, style={'text-align': 'center', }))
|
|
294
|
+
per_col_1_2.append(html.Div(style={'height': div_padding}))
|
|
354
295
|
else:
|
|
355
|
-
per_col_1_2.append(html.Div(content, style={'text-align': 'center','background-color': 'darkblue'
|
|
356
|
-
|
|
296
|
+
per_col_1_2.append(html.Div(content, style={'text-align': 'center', 'background-color': 'darkblue'}))
|
|
297
|
+
|
|
298
|
+
for i in range(10, 16):
|
|
357
299
|
content = result_df.iloc[0][keys[i]]
|
|
358
300
|
if i%2 == 1:
|
|
359
301
|
per_col_2_2.append(html.Div(content, style={'text-align': 'center'}),)
|
|
302
|
+
per_col_2_2.append(html.Div(style={'height': div_padding}))
|
|
360
303
|
else:
|
|
361
304
|
per_col_2_2.append(html.Div(content, style={'text-align': 'center', 'background-color': 'darkblue'}),)
|
|
362
|
-
|
|
305
|
+
|
|
306
|
+
for i in range(16, 22):
|
|
363
307
|
content = result_df.iloc[0][keys[i]]
|
|
364
308
|
if i%2 == 1:
|
|
365
309
|
per_col_2_3.append(html.Div(content, style={'text-align': 'center'}))
|
|
310
|
+
per_col_2_3.append(html.Div(style={'height': div_padding}))
|
|
366
311
|
else:
|
|
367
312
|
per_col_2_3.append(html.Div(content, style={'text-align': 'center', 'background-color': 'darkblue'}))
|
|
368
313
|
|
|
@@ -443,12 +388,12 @@ class Components:
|
|
|
443
388
|
for idx , key in enumerate(para_keys_list):
|
|
444
389
|
if idx%2 == 0:
|
|
445
390
|
title.append(dbc.Row(
|
|
446
|
-
[dbc.Col(key,width=6),
|
|
447
|
-
dbc.Col(f'{result_df.iloc[0][key]}',style={ 'text-align': 'center'},width=6)]))
|
|
391
|
+
[dbc.Col(key,width=6, style={ 'background-color': 'darkblue', 'marginBottom': '6px'}),
|
|
392
|
+
dbc.Col(f'{result_df.iloc[0][key]}',style={ 'text-align': 'center', 'marginBottom': '6px', 'background-color': 'darkblue'},width=6)]))
|
|
448
393
|
else:
|
|
449
394
|
title.append(dbc.Row(
|
|
450
|
-
[dbc.Col(key,width=6
|
|
451
|
-
dbc.Col(f'{result_df.iloc[0][key]}',style={ 'text-align': 'center'
|
|
395
|
+
[dbc.Col(key,width=6),
|
|
396
|
+
dbc.Col(f'{result_df.iloc[0][key]}',style={ 'text-align': 'center'},width=6)]))
|
|
452
397
|
|
|
453
398
|
matrix_div = html.Div([
|
|
454
399
|
html.Div(style={'height': '8px', }),
|
|
@@ -457,6 +402,8 @@ class Components:
|
|
|
457
402
|
html.Div('Selected Curve', style={'color': 'Cyan',
|
|
458
403
|
'display': 'inline',
|
|
459
404
|
'font-size': '15px'}),
|
|
405
|
+
html.Div(style={'height': '1px', }),
|
|
406
|
+
|
|
460
407
|
html.Div('', id='save_status',
|
|
461
408
|
style={'color': 'Cyan',
|
|
462
409
|
'display': 'inline',
|
|
@@ -469,10 +416,12 @@ class Components:
|
|
|
469
416
|
html.Div(style={'height': '15px', }),
|
|
470
417
|
|
|
471
418
|
html.Div('Performance', style={'color': 'Cyan', 'font-size': '15px'}),
|
|
419
|
+
html.Div(style={'height': '2px', }),
|
|
472
420
|
html.Div(children=per_col1, style={'font-size': '11px','padding-left':'1px'}),
|
|
473
421
|
html.Div(style={'height': '15px', }),
|
|
474
422
|
|
|
475
423
|
html.Div('Comparison', style={'color': 'Cyan', 'font-size': '15px'}),
|
|
424
|
+
html.Div(style={'height': '1px', }),
|
|
476
425
|
html.Div(children=per_col2, style={'font-size': '11px','padding-right': '10px','padding-left':'1px'}),
|
|
477
426
|
html.Div(style={'height': '15px', }),
|
|
478
427
|
|
|
@@ -507,6 +456,7 @@ class Components:
|
|
|
507
456
|
'cov_return': 'COV (Return)',
|
|
508
457
|
'win_rate':'Win Rate',
|
|
509
458
|
'return_on_capital_diff': 'Return/BnH % Diff.',
|
|
459
|
+
'correlation': 'Correlation',
|
|
510
460
|
#'exclude': 'Exclude',
|
|
511
461
|
}
|
|
512
462
|
|
|
@@ -558,12 +508,11 @@ class Components:
|
|
|
558
508
|
return df_checked
|
|
559
509
|
|
|
560
510
|
def assign_colour(self, profile, degree):
|
|
561
|
-
if profile == 0: rgb = (0, int(252 - 252 * degree),
|
|
511
|
+
if profile == 0: rgb = (0, int(252 - 252 * degree), 0)
|
|
562
512
|
elif profile == 1: rgb = (int(252 - 252 * degree), 252, 0)
|
|
563
|
-
elif profile == 2: rgb = (252, 0, int(252 - 252 * degree))
|
|
564
|
-
elif profile == 3: rgb = (0, 252, int(252 * degree))
|
|
565
|
-
elif profile
|
|
566
|
-
elif profile == 5: rgb = (int(252 * degree), 0, 252)
|
|
513
|
+
elif profile == 2: rgb = (252, 0, int(round((252 - 252 * degree)/3)))
|
|
514
|
+
elif profile == 3: rgb = (0, 252, int(round((252 - 252 * degree)/3)))
|
|
515
|
+
elif profile >= 4: rgb = (252, int(252 * degree), 0)
|
|
567
516
|
return 'rgb' + str(rgb)
|
|
568
517
|
|
|
569
518
|
def generate_main_chart(self, graph_df, backtest_name, equity_curve_folder, para_keys_list):
|
|
@@ -767,28 +716,6 @@ class Components:
|
|
|
767
716
|
|
|
768
717
|
return fig_line
|
|
769
718
|
|
|
770
|
-
### for class signal ###
|
|
771
|
-
def generate_df_stat(self, df, period):
|
|
772
|
-
col_pct = 'pct_change_' + str(period)
|
|
773
|
-
col_rise = 'max_rise_' + str(period)
|
|
774
|
-
col_fall = 'max_fall_' + str(period)
|
|
775
|
-
df_his = df.copy()
|
|
776
|
-
df_his[col_pct] = df_his['close'].pct_change(period)
|
|
777
|
-
df_his[col_pct] = df_his[col_pct].shift(-1 * period)
|
|
778
|
-
df_his[col_pct] = df_his[col_pct] * 100
|
|
779
|
-
df_his[col_pct] = df_his[col_pct].map(lambda x: round(x, 2))
|
|
780
|
-
df_his[col_rise] = (df_his['high'].rolling(period).max().shift(-1 * (period)) / df_his['close']) - 1
|
|
781
|
-
df_his[col_fall] = (df_his['low'].rolling(period).min().shift(-1 * (period)) / df_his['close']) - 1
|
|
782
|
-
|
|
783
|
-
df_his = df_his[df_his['logic'] == 'trade_logic']
|
|
784
|
-
|
|
785
|
-
df_his[col_rise] = df_his[col_rise] * 100
|
|
786
|
-
df_his[col_fall] = df_his[col_fall] * 100
|
|
787
|
-
|
|
788
|
-
df_his[col_rise] = df_his[col_rise].map(lambda x: round(x, 2))
|
|
789
|
-
df_his[col_fall] = df_his[col_fall].map(lambda x: round(x, 2))
|
|
790
|
-
|
|
791
|
-
return round(df_his[col_pct].mean(), 2), round(df_his[col_rise].mean(), 2), round(df_his[col_fall].mean(), 2)
|
|
792
719
|
|
|
793
720
|
def aggregate_df(self):
|
|
794
721
|
all_str_dir = []
|
|
@@ -13,7 +13,7 @@ import os
|
|
|
13
13
|
|
|
14
14
|
class Plot:
|
|
15
15
|
|
|
16
|
-
filter_list = []
|
|
16
|
+
#filter_list = []
|
|
17
17
|
add_filter_btn_count = 0
|
|
18
18
|
main_chart_btn_clicks = 0
|
|
19
19
|
stra_alys_chart_btn_clicks = 0
|
|
@@ -24,7 +24,7 @@ class Plot:
|
|
|
24
24
|
select_all_status = False
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def __new__(self, backtest_result_df, number_of_curves):
|
|
27
|
+
def __new__(self, backtest_result_df, number_of_curves, filter_list= []):
|
|
28
28
|
|
|
29
29
|
self.chart_bg = '#1f2c56'
|
|
30
30
|
self.init_chart = True
|
|
@@ -49,6 +49,9 @@ class Plot:
|
|
|
49
49
|
para_keys_str = self.backtest_result_dict[self.backtest_result_key[0]]['para_keys_str']
|
|
50
50
|
self.para_keys_list = para_keys_str.split('|')
|
|
51
51
|
|
|
52
|
+
self.filter_list = filter_list
|
|
53
|
+
self.init_filter = True if len(self.filter_list) >0 else False
|
|
54
|
+
|
|
52
55
|
components = Components(number_of_curves)
|
|
53
56
|
|
|
54
57
|
self.start_year = datetime.datetime.strptime(self.start_date, '%Y-%m-%d').year
|
|
@@ -116,7 +119,7 @@ class Plot:
|
|
|
116
119
|
dbc.Col(html.Div([
|
|
117
120
|
html.Div(style={'height': '15px', }),
|
|
118
121
|
html.Div('Sorting Method', style={'color': 'Cyan', 'margin-left': '15px', 'font-size': '15px'}),
|
|
119
|
-
html.Div(style={'height': '
|
|
122
|
+
html.Div(style={'height': '22px', }),
|
|
120
123
|
sort_method_dropdown,
|
|
121
124
|
html.Div(style={'height': '15px', }),
|
|
122
125
|
html.Div('Parameters', style={'color': 'Cyan', 'margin-left': '15px', 'font-size': '15px'}),
|
|
@@ -247,7 +250,7 @@ class Plot:
|
|
|
247
250
|
if not add_filter_btn_clicks:
|
|
248
251
|
if not main_chart_btn_click:
|
|
249
252
|
#self.sort_method_current = sort_method
|
|
250
|
-
self.filter_list = []
|
|
253
|
+
#self.filter_list = []
|
|
251
254
|
self.add_filter_btn_count = 0
|
|
252
255
|
self.stra_alys_chart_btn_clicks = 0
|
|
253
256
|
self.save_clicks = 0
|
|
@@ -258,25 +261,27 @@ class Plot:
|
|
|
258
261
|
filter_input_div = filter_input
|
|
259
262
|
|
|
260
263
|
######################################################################
|
|
264
|
+
########################### filter reaction ##########################
|
|
261
265
|
|
|
262
|
-
if add_filter_btn_clicks:
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
266
|
+
if add_filter_btn_clicks != None and self.add_filter_btn_count!= None:
|
|
267
|
+
add_filter_btn_clicked = add_filter_btn_clicks > self.add_filter_btn_count
|
|
268
|
+
else:
|
|
269
|
+
add_filter_btn_clicked = False
|
|
270
|
+
|
|
271
|
+
if add_filter_btn_clicked or self.init_filter: ## Add btn Pressed
|
|
272
|
+
if not self.init_filter: self.add_filter_btn_count = add_filter_btn_clicks
|
|
273
|
+
if (filter_name != None and filter_input_value != None) or self.init_filter:
|
|
274
|
+
if not self.init_filter: self.filter_list.append([filter_name[0:-1], filter_name[-1], filter_input_value])
|
|
275
|
+
filter_div = components.update_filter_div(self.filter_list)
|
|
276
|
+
if len(self.filter_list) > 11:
|
|
277
|
+
filter_dropdown_div = filter_dropdown_disabled
|
|
278
|
+
filter_input_div = filter_input_disabled
|
|
279
|
+
_add_filter_save_btn_style = add_filter_save_btn_style_disabled
|
|
280
|
+
else:
|
|
281
|
+
filter_dropdown_div = filter_dropdown
|
|
282
|
+
filter_input_div = filter_input
|
|
283
|
+
self.init_chart = False
|
|
284
|
+
self.init_filter = False
|
|
280
285
|
|
|
281
286
|
else:
|
|
282
287
|
self.add_filter_btn_count = 0 # Necessary for initialization
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|