plotguy 1.1__tar.gz → 1.2.1__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-1.1 → plotguy-1.2.1}/PKG-INFO +1 -1
- {plotguy-1.1 → plotguy-1.2.1}/plotguy/__init__.py +14 -2
- {plotguy-1.1 → plotguy-1.2.1}/plotguy/components.py +36 -12
- {plotguy-1.1 → plotguy-1.2.1}/plotguy/equity_curves.py +15 -4
- {plotguy-1.1 → plotguy-1.2.1}/plotguy.egg-info/PKG-INFO +1 -1
- {plotguy-1.1 → plotguy-1.2.1}/setup.py +1 -1
- {plotguy-1.1 → plotguy-1.2.1}/README.md +0 -0
- {plotguy-1.1 → plotguy-1.2.1}/plotguy/aggregate.py +0 -0
- {plotguy-1.1 → plotguy-1.2.1}/plotguy/signals.py +0 -0
- {plotguy-1.1 → plotguy-1.2.1}/plotguy.egg-info/SOURCES.txt +0 -0
- {plotguy-1.1 → plotguy-1.2.1}/plotguy.egg-info/dependency_links.txt +0 -0
- {plotguy-1.1 → plotguy-1.2.1}/plotguy.egg-info/requires.txt +0 -0
- {plotguy-1.1 → plotguy-1.2.1}/plotguy.egg-info/top_level.txt +0 -0
- {plotguy-1.1 → plotguy-1.2.1}/setup.cfg +0 -0
|
@@ -94,6 +94,7 @@ def apply_pnl(row):
|
|
|
94
94
|
if date == open_date:
|
|
95
95
|
# Unrealized pnl on the open date, record on df_daily
|
|
96
96
|
df_daily.at[open_date, 'action'] = 'open'
|
|
97
|
+
df_daily.at[open_date, 'signal_value'] = df_daily.at[open_date, 'bah'] # Mark the open position for analysi chart
|
|
97
98
|
|
|
98
99
|
unrealized_pnl = num_of_share * multiplier * (now_close - open_price)# - commission
|
|
99
100
|
unrealized_pnl = round(unrealized_pnl, 3)
|
|
@@ -449,6 +450,7 @@ def resample_summary_to_daily(para_combination, folder=''):
|
|
|
449
450
|
pl.lit(None).alias('action'),
|
|
450
451
|
pl.lit(None).alias('realized_pnl'),
|
|
451
452
|
pl.lit(None).alias('unrealized_pnl'),
|
|
453
|
+
pl.lit(None).alias('signal_value'), # for the position of analysis chart
|
|
452
454
|
pl.lit(None).alias('commission'),
|
|
453
455
|
])
|
|
454
456
|
.collect()
|
|
@@ -457,7 +459,7 @@ def resample_summary_to_daily(para_combination, folder=''):
|
|
|
457
459
|
df_daily = df.to_pandas()
|
|
458
460
|
df_daily.index = pd.to_datetime(df_daily['datetime'], format='%Y-%m-%d')
|
|
459
461
|
|
|
460
|
-
# Apply apply_pnl on
|
|
462
|
+
# Apply apply_pnl on backtest here
|
|
461
463
|
apply_pnl.last_realized_capital = last_realized_capital
|
|
462
464
|
apply_pnl.multiplier = multiplier
|
|
463
465
|
apply_pnl.df_daily = df_daily
|
|
@@ -591,7 +593,7 @@ def cal_performance(para_combination):
|
|
|
591
593
|
signal_year_mean = np.mean(signal_year_count)
|
|
592
594
|
cov = round(signal_year_std / signal_year_mean, 3)
|
|
593
595
|
|
|
594
|
-
result_dict['
|
|
596
|
+
result_dict['cov_count'] = cov
|
|
595
597
|
|
|
596
598
|
# Win rate by year
|
|
597
599
|
for year in year_list:
|
|
@@ -607,6 +609,7 @@ def cal_performance(para_combination):
|
|
|
607
609
|
# Performance by year
|
|
608
610
|
first_equity_value = 0
|
|
609
611
|
last_equity_value = 0
|
|
612
|
+
year_return_list = []
|
|
610
613
|
for year in year_list:
|
|
611
614
|
if not df.loc[df['year'] == year].empty: # if trade
|
|
612
615
|
if first_equity_value == 0: # if 1st year, set beginning as the first equity_value
|
|
@@ -615,14 +618,23 @@ def cal_performance(para_combination):
|
|
|
615
618
|
yearly_return = (last_equity_value - first_equity_value) / first_equity_value
|
|
616
619
|
if np.isnan(yearly_return):
|
|
617
620
|
result_dict[f'{year}_return'] = 0
|
|
621
|
+
year_return_list.append(0)
|
|
618
622
|
else:
|
|
619
623
|
result_dict[f'{year}_return'] = int(yearly_return * 100)
|
|
624
|
+
year_return_list.append(int(yearly_return * 100))
|
|
620
625
|
|
|
621
626
|
else: # no trade
|
|
622
627
|
result_dict[f'{year}_return'] = '-----'
|
|
628
|
+
year_return_list.append(0)
|
|
623
629
|
|
|
624
630
|
first_equity_value = last_equity_value
|
|
625
631
|
|
|
632
|
+
# cov_return
|
|
633
|
+
return_year_std = np.std(year_return_list)
|
|
634
|
+
return_year_mean = np.mean(year_return_list)
|
|
635
|
+
cov_return = round(return_year_std / return_year_mean, 3)
|
|
636
|
+
result_dict['cov_return'] = cov_return
|
|
637
|
+
|
|
626
638
|
result_dict['risk_free_rate'] = risk_free_rate
|
|
627
639
|
|
|
628
640
|
# BaH Performance
|
|
@@ -38,8 +38,10 @@ class Components:
|
|
|
38
38
|
{'label': 'MDD Percentage <', 'value': 'mdd_pct<'},
|
|
39
39
|
{'label': 'Trade Count >', 'value': 'num_of_trade>'},
|
|
40
40
|
{'label': 'Trade Count <', 'value': 'num_of_trade<'},
|
|
41
|
-
{'label': 'COV >', 'value': '
|
|
42
|
-
{'label': 'COV <', 'value': '
|
|
41
|
+
{'label': 'COV (Count) >', 'value': 'cov_count>'},
|
|
42
|
+
{'label': 'COV (Count) <', 'value': 'cov_count<'},
|
|
43
|
+
{'label': 'COV (Return) >', 'value': 'cov_return>'},
|
|
44
|
+
{'label': 'COV (Return) <', 'value': 'cov_return<'},
|
|
43
45
|
{'label': 'Win Rate >', 'value': 'win_rate>'},
|
|
44
46
|
{'label': 'Win Rate <', 'value': 'win_rate<'},
|
|
45
47
|
],
|
|
@@ -226,7 +228,8 @@ class Components:
|
|
|
226
228
|
'net_profit_to_mdd',
|
|
227
229
|
'return_to_bah',
|
|
228
230
|
'win_rate',
|
|
229
|
-
'
|
|
231
|
+
'cov_count',
|
|
232
|
+
'cov_return',
|
|
230
233
|
'total_commission',
|
|
231
234
|
'return_on_capital',
|
|
232
235
|
'annualized_return',
|
|
@@ -254,7 +257,8 @@ class Components:
|
|
|
254
257
|
df['annualized_return'] = "{:.0%}".format(df['annualized_return'] / 100)
|
|
255
258
|
df['annualized_std'] = "{:.0%}".format(df['annualized_std'] / 100)
|
|
256
259
|
|
|
257
|
-
df['
|
|
260
|
+
df['cov_count'] = round(df['cov_count'], 2)
|
|
261
|
+
df['cov_return'] = round(df['cov_return'], 2)
|
|
258
262
|
|
|
259
263
|
try:
|
|
260
264
|
df['win_rate'] = "{:.0%}".format( float(df['win_rate']) / 100)
|
|
@@ -280,7 +284,8 @@ class Components:
|
|
|
280
284
|
per_col_1_1.append(html.Div('Net Profit/MDD'))
|
|
281
285
|
per_col_1_1.append(html.Div('Return-BaH % Diff.'))
|
|
282
286
|
per_col_1_1.append(html.Div('Win Rate'))
|
|
283
|
-
per_col_1_1.append(html.Div('COV'))
|
|
287
|
+
per_col_1_1.append(html.Div('COV (Count)'))
|
|
288
|
+
per_col_1_1.append(html.Div('COV (Return)'))
|
|
284
289
|
per_col_1_1.append(html.Div('Total Commission'))
|
|
285
290
|
per_col_1_1.append(html.Div('Risk Free Rate'))
|
|
286
291
|
|
|
@@ -401,7 +406,8 @@ class Components:
|
|
|
401
406
|
'annualized_return': 'Annualized Return',
|
|
402
407
|
'annualized_sr': 'Sharp Ratio',
|
|
403
408
|
'mdd_pct':'MDD Percentage',
|
|
404
|
-
'
|
|
409
|
+
'cov_count':'COV (Count)',
|
|
410
|
+
'cov_return': 'COV (Return)',
|
|
405
411
|
'win_rate':'Win Rate',
|
|
406
412
|
'return_to_bah': 'Return/BnH % Diff.',
|
|
407
413
|
'exclude': 'Exclude',
|
|
@@ -494,8 +500,15 @@ class Components:
|
|
|
494
500
|
else:
|
|
495
501
|
df_signal_list = pd.read_csv(save_path, index_col=0)
|
|
496
502
|
|
|
503
|
+
|
|
497
504
|
df_signal_list['date'] = pd.to_datetime(df_signal_list['date'], format='%Y-%m-%d')
|
|
498
|
-
|
|
505
|
+
|
|
506
|
+
try:
|
|
507
|
+
df_signal_list['datetime'] = pd.to_datetime(df_signal_list['datetime'], format='%Y-%m-%d %H:%M:%S')
|
|
508
|
+
except:
|
|
509
|
+
df_signal_list = df_signal_list.reset_index()
|
|
510
|
+
df_signal_list['datetime'] = pd.to_datetime(df_signal_list['datetime'], format='%Y-%m-%d %H:%M:%S')
|
|
511
|
+
|
|
499
512
|
df_signal_list = df_signal_list.loc[
|
|
500
513
|
(df_signal_list['date'] >= chart3_start) & (df_signal_list['date'] <= chart3_end)]
|
|
501
514
|
|
|
@@ -585,7 +598,8 @@ class Components:
|
|
|
585
598
|
hovertemplate = hovertemplate + "MDD Percentage : " + "{:.0%}".format(
|
|
586
599
|
graph_df.iloc[i]['mdd_pct'] / 100) + "<br>"
|
|
587
600
|
hovertemplate = hovertemplate + "Trade Count : " + str(graph_df.iloc[i]['num_of_trade']) + "<br>"
|
|
588
|
-
hovertemplate = hovertemplate + "COV : " + str(round(graph_df.iloc[i]['
|
|
601
|
+
hovertemplate = hovertemplate + "COV (Count) : " + str(round(graph_df.iloc[i]['cov_count'], 2)) + "<br>"
|
|
602
|
+
hovertemplate = hovertemplate + "COV (Return) : " + str(round(graph_df.iloc[i]['cov_return'], 2)) + "<br>"
|
|
589
603
|
try:
|
|
590
604
|
hovertemplate = hovertemplate + "Win Rate : " + "{:.0%}".format(
|
|
591
605
|
float(graph_df.iloc[i]['win_rate']) / 100) + "<br>"
|
|
@@ -1041,6 +1055,7 @@ class Components:
|
|
|
1041
1055
|
|
|
1042
1056
|
dict = {}
|
|
1043
1057
|
# parameters = ast.literal_eval(row['para_combination'])
|
|
1058
|
+
|
|
1044
1059
|
dict['para_combination'] = ast.literal_eval(row['para_combination'])
|
|
1045
1060
|
para_combination = ast.literal_eval(row['para_combination'])
|
|
1046
1061
|
dict['para_combination'] = para_combination
|
|
@@ -1133,7 +1148,7 @@ class Components:
|
|
|
1133
1148
|
performance_text.append(html.Div(f'{item} : {_value}', style={'line-height': line_height}))
|
|
1134
1149
|
|
|
1135
1150
|
if key == 'return_on_capital':
|
|
1136
|
-
item = '
|
|
1151
|
+
item = 'ReturnOnCapital'
|
|
1137
1152
|
_value = "{:.0%}".format(value/100)
|
|
1138
1153
|
performance_text.append(html.Div(f'{item} : {_value}', style={'line-height': line_height}))
|
|
1139
1154
|
|
|
@@ -1296,6 +1311,7 @@ class Components:
|
|
|
1296
1311
|
year_win_rate_col = []
|
|
1297
1312
|
year_return_col = []
|
|
1298
1313
|
|
|
1314
|
+
year_return_list = []
|
|
1299
1315
|
for year in year_list:
|
|
1300
1316
|
year_col.append(html.Div(year))
|
|
1301
1317
|
year_count.append(int(total_dict[f'{year}']))
|
|
@@ -1305,7 +1321,13 @@ class Components:
|
|
|
1305
1321
|
year_return = total_dict[f'{year}_return']
|
|
1306
1322
|
year_return_col.append(html.Div( "{:.0%}".format(year_return) ))
|
|
1307
1323
|
|
|
1308
|
-
|
|
1324
|
+
try:
|
|
1325
|
+
year_return_list.append(float(year_return))
|
|
1326
|
+
except:
|
|
1327
|
+
year_return_list.append(0)
|
|
1328
|
+
|
|
1329
|
+
cov_count = round(np.std(year_count) / np.mean(year_count), 2)
|
|
1330
|
+
cov_return = round(np.std(year_return_list) / np.mean(year_return_list), 2)
|
|
1309
1331
|
|
|
1310
1332
|
div = html.Div([
|
|
1311
1333
|
|
|
@@ -1318,7 +1340,8 @@ class Components:
|
|
|
1318
1340
|
html.Div('Net Profit'),
|
|
1319
1341
|
html.Div('Net Profit/MDD'),
|
|
1320
1342
|
html.Div('Win Rate'),
|
|
1321
|
-
html.Div('COV'),
|
|
1343
|
+
html.Div('COV (Count)'),
|
|
1344
|
+
html.Div('COV (Return)'),
|
|
1322
1345
|
html.Div('Total Commission'),
|
|
1323
1346
|
html.Div('Risk Free Rate'),
|
|
1324
1347
|
html.Div(style={'height': '10px'}),
|
|
@@ -1335,7 +1358,8 @@ class Components:
|
|
|
1335
1358
|
html.Div(net_profit),
|
|
1336
1359
|
html.Div(net_profit_to_mdd),
|
|
1337
1360
|
html.Div(win_rate),
|
|
1338
|
-
html.Div(
|
|
1361
|
+
html.Div(cov_count),
|
|
1362
|
+
html.Div(cov_return),
|
|
1339
1363
|
html.Div(total_commission),
|
|
1340
1364
|
html.Div("{:.2%}".format(risk_free_rate_float / 100)),
|
|
1341
1365
|
html.Div(style={'height': '10px'}),
|
|
@@ -92,10 +92,12 @@ class Plot:
|
|
|
92
92
|
|
|
93
93
|
app = Dash(__name__, external_stylesheets=[dbc.themes.SUPERHERO], suppress_callback_exceptions=True)
|
|
94
94
|
|
|
95
|
-
my_css_data = """
|
|
95
|
+
my_css_data = """
|
|
96
|
+
body {
|
|
96
97
|
background-color: #1a2245;
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
+
|
|
100
|
+
/* width */
|
|
99
101
|
::-webkit-scrollbar {
|
|
100
102
|
width: 10px !important;
|
|
101
103
|
display: block !important;
|
|
@@ -114,6 +116,7 @@ class Plot:
|
|
|
114
116
|
background: #154360;
|
|
115
117
|
border-radius: 10px;
|
|
116
118
|
}
|
|
119
|
+
|
|
117
120
|
"""
|
|
118
121
|
innerHtmlText = "<style>%s</style>" % my_css_data
|
|
119
122
|
|
|
@@ -206,7 +209,7 @@ class Plot:
|
|
|
206
209
|
html.Div(children=dbc.Row([
|
|
207
210
|
dbc.Col(width=1),
|
|
208
211
|
dbc.Col(children=html.Div([
|
|
209
|
-
html.Div(style={'height': '0.5px'}),
|
|
212
|
+
html.Div(style={'height': '0.5px',}),
|
|
210
213
|
dcc.DatePickerRange(
|
|
211
214
|
id='chart3_date',
|
|
212
215
|
style={'margin-left':'15px'},
|
|
@@ -679,7 +682,15 @@ class Plot:
|
|
|
679
682
|
if not save_path in list(saved_df['path']):
|
|
680
683
|
|
|
681
684
|
para_pop = self.para_combination.copy()
|
|
682
|
-
|
|
685
|
+
try:
|
|
686
|
+
para_pop.pop('df')
|
|
687
|
+
except:
|
|
688
|
+
pass
|
|
689
|
+
|
|
690
|
+
try:
|
|
691
|
+
para_pop.pop('holiday_list')
|
|
692
|
+
except:
|
|
693
|
+
pass
|
|
683
694
|
|
|
684
695
|
df_dict = {'path': save_path,
|
|
685
696
|
'para_combination':str(para_pop),
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|