improve stake overview UI, and integrate FNCV3
Browse files- dash/numerdash_app.py +171 -121
- project_tools/numerapi_utils.py +47 -33
dash/numerdash_app.py
CHANGED
|
@@ -98,7 +98,7 @@ def default_model_picker():
|
|
| 98 |
return picked_models
|
| 99 |
|
| 100 |
|
| 101 |
-
def model_fast_picker(
|
| 102 |
text_content = '''
|
| 103 |
fast model picker by CSV string.
|
| 104 |
example: "model1, model2, model3"
|
|
@@ -109,7 +109,7 @@ def model_fast_picker(models):
|
|
| 109 |
csv_parts = text.split(',')
|
| 110 |
for s in csv_parts:
|
| 111 |
m = s.strip()
|
| 112 |
-
if m not in
|
| 113 |
result_models.append(m)
|
| 114 |
return list(dict.fromkeys(result_models))
|
| 115 |
|
|
@@ -127,10 +127,11 @@ def generate_round_table(data, row_cts, c, r, sortcol='corrmmc'):
|
|
| 127 |
select_round = row_cts[c].slider('select a round', earliest_round, latest_round, suggest_round, 1)
|
| 128 |
# row_cts[c].write(select_round)
|
| 129 |
round_data = data[data['roundNumber']==select_round].sort_values(by=sortcol, ascending=False).reset_index(drop=True)
|
|
|
|
| 130 |
# round_data = round_data[round_data['model'].isin(models)].reset_index(drop=True)
|
| 131 |
-
latest_date = round_data['date'].values[0]
|
| 132 |
-
row_cts[c].write(f'round: {select_round}
|
| 133 |
-
row_cts[c].dataframe(round_data.drop(['roundNumber', '
|
| 134 |
|
| 135 |
|
| 136 |
|
|
@@ -148,10 +149,10 @@ def generate_dailyscore_metrics(data, row_cts, c, r):
|
|
| 148 |
pass
|
| 149 |
|
| 150 |
def get_roundmetric_data(data):
|
| 151 |
-
numfeats1 = ['corr', 'mmc', 'corrmmc', '
|
| 152 |
stat1 = ['sum', 'mean', 'count',
|
| 153 |
{'sharpe': project_utils.get_array_sharpe}] # {'ptp':np.ptp}]#{'sharp':project_utils.get_array_sharpe}]
|
| 154 |
-
numfeats2 = ['corr_pct', 'mmc_pct', '
|
| 155 |
stat2 = ['mean']#, {'sharp': project_utils.get_array_sharpe}]
|
| 156 |
|
| 157 |
roundmetric_agg_rcp = [
|
|
@@ -175,19 +176,20 @@ def generate_round_metrics(data, row_cts, c, r):
|
|
| 175 |
# st.write(data.columns.tolist())
|
| 176 |
for col in data.columns.tolist():
|
| 177 |
if select_metric =='corrmmc':
|
| 178 |
-
if (f'{select_metric}_' in col) or ('
|
| 179 |
cols += [col]
|
| 180 |
-
elif select_metric =='
|
| 181 |
-
if (f'{select_metric}_' in col) or ('
|
| 182 |
cols += [col]
|
| 183 |
else:
|
| 184 |
-
if (f'{select_metric}_' in col) and (not('corrmmc' in col)) and (not('
|
|
|
|
| 185 |
cols+= [col]
|
| 186 |
|
| 187 |
if select_metric != 'pct':
|
| 188 |
sort_col = select_metric+'_sharpe'
|
| 189 |
else:
|
| 190 |
-
sort_col = '
|
| 191 |
view_data = data[cols].sort_values(by=sort_col, ascending=False)
|
| 192 |
row_cts[c].dataframe(view_data)
|
| 193 |
pass
|
|
@@ -237,7 +239,7 @@ def round_view(data, select_perview, select_metric=None):
|
|
| 237 |
generate_round_table(data, row_cts, c, r)
|
| 238 |
if select_perview=='dailyscore_metric':
|
| 239 |
generate_dailyscore_metrics(data, row_cts, c, r)
|
| 240 |
-
if select_perview=='
|
| 241 |
generate_round_metrics(data, row_cts, c, r)
|
| 242 |
if select_perview=='dailyscore_chart':
|
| 243 |
dailyscore_chart(data, row_cts, c, r, select_metric)
|
|
@@ -246,26 +248,50 @@ def round_view(data, select_perview, select_metric=None):
|
|
| 246 |
|
| 247 |
|
| 248 |
def score_overview():
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 265 |
|
| 266 |
|
| 267 |
def data_operation():
|
| 268 |
# top_lb, top_tp3m, top_tp1y, special_list = sidebar_data_picker()
|
|
|
|
| 269 |
latest_round = project_utils.latest_round
|
| 270 |
models = []
|
| 271 |
benchmark_opt = st.sidebar.checkbox('download default models', value=True)
|
|
@@ -273,9 +299,9 @@ def data_operation():
|
|
| 273 |
model_dict = default_model_picker()
|
| 274 |
for k in model_dict.keys():
|
| 275 |
models += model_dict[k]
|
| 276 |
-
models = models + model_fast_picker(
|
| 277 |
if len(models)>0:
|
| 278 |
-
model_selection = st.multiselect('select models', models, default=models)
|
| 279 |
suggest_min_round = 182 #latest_round-50
|
| 280 |
min_round, max_round = st.slider('select tournament rounds', 200, latest_round, (suggest_min_round, latest_round), 1)
|
| 281 |
roundlist = [i for i in range(max_round, min_round-1, -1)]
|
|
@@ -297,13 +323,16 @@ def data_operation():
|
|
| 297 |
if prjreload:
|
| 298 |
project_utils.reload_project()
|
| 299 |
if len(model_df)>0:
|
| 300 |
-
rename_dict = {'corrPercentile': 'corr_pct', 'correlation':'corr', 'corrWMetamodel':'corr_meta', 'mmcPercentile':'mmc_pct', 'tcPercentile':'tc_pct'}
|
| 301 |
model_df.rename(columns=rename_dict, inplace=True)
|
| 302 |
model_df['corrmmc'] = model_df['corr'] + model_df['mmc']
|
| 303 |
-
model_df['
|
| 304 |
-
model_df['
|
| 305 |
-
model_df['
|
| 306 |
-
|
|
|
|
|
|
|
|
|
|
| 307 |
model_df = model_df[ord_cols]
|
| 308 |
if project_config.SAVE_LOCAL_COPY:
|
| 309 |
project_utils.pickle_data(project_config.MODEL_ROUND_RESULT_FILE, model_df)
|
|
@@ -313,8 +342,9 @@ def data_operation():
|
|
| 313 |
st.text('list of models being tracked')
|
| 314 |
st.write(model_dict)
|
| 315 |
try:
|
| 316 |
-
st.
|
| 317 |
-
st.write(
|
|
|
|
| 318 |
except:
|
| 319 |
st.write('model data was not retrieved')
|
| 320 |
|
|
@@ -373,6 +403,8 @@ def download_model_round_result(models, roundlist, show_info):
|
|
| 373 |
time.sleep(0.1)
|
| 374 |
my_bar.progress(percent_complete)
|
| 375 |
model_df = pd.concat(model_dfs, axis=0).sort_values(by=['roundNumber'], ascending=False).reset_index(drop=True)
|
|
|
|
|
|
|
| 376 |
model_df = model_df[model_df['roundNumber'].isin(roundlist)].reset_index(drop=True)
|
| 377 |
return model_df
|
| 378 |
|
|
@@ -396,9 +428,6 @@ def roundresult_chart(data, model_selection):
|
|
| 396 |
min_selectround, max_selectround = st.slider('select plotting round range', min_round, max_round,
|
| 397 |
(suggest_min_round, max_round), 1)
|
| 398 |
|
| 399 |
-
# min_selectround, max_selectround = placeholder.slider('select plotting round range', min_round, max_round,
|
| 400 |
-
# (suggest_min_round, max_round), 1)
|
| 401 |
-
|
| 402 |
select_metric = st.selectbox('Choose a metric', list(histtrend_opt.keys()), index=0,
|
| 403 |
format_func=lambda x: histtrend_opt[x])
|
| 404 |
round_range = [min_selectround, max_selectround]
|
|
@@ -409,17 +438,11 @@ def roundresult_chart(data, model_selection):
|
|
| 409 |
mean_df['mean'] = mean_df[select_metric]
|
| 410 |
merge_cols = ['model', 'model avg.', 'mean']
|
| 411 |
round_data = round_data.merge(right=mean_df[merge_cols], on='model', how='left').sort_values(by=['mean','model', 'roundNumber'], ascending=False)
|
| 412 |
-
fig = chart_pxline(round_data, 'roundNumber', y=select_metric, color='model avg.', hover_data=list(histtrend_opt.keys())+['
|
| 413 |
-
|
| 414 |
if fig is not None:
|
| 415 |
st.plotly_chart(fig, use_container_width=True)
|
| 416 |
-
dailyscore_data = data[(data['model'].isin(model_selection)) & data['roundNumber'].isin(round_list)].reset_index(drop=True)
|
| 417 |
-
dailyscore_data = dailyscore_data.merge(right=mean_df[merge_cols], on='model', how='left').sort_values(
|
| 418 |
-
by=['mean', 'model', 'roundNumber'], ascending=False)
|
| 419 |
-
round_view(dailyscore_data, 'dailyscore_chart', select_metric)
|
| 420 |
|
| 421 |
-
|
| 422 |
-
st.text(f'No data available for models: {models}')
|
| 423 |
|
| 424 |
|
| 425 |
|
|
@@ -427,22 +450,16 @@ def roundresult_chart(data, model_selection):
|
|
| 427 |
def histtrend():
|
| 428 |
# default_models = ['yxbot']
|
| 429 |
# models = default_models.copy()
|
| 430 |
-
|
|
|
|
| 431 |
model_selection = []
|
| 432 |
-
model_dict = model_data_picker(values=[False, False, False, False, True, True])
|
| 433 |
-
for k in model_dict.keys():
|
| 434 |
-
if model_dict[k] not in models:
|
| 435 |
-
models += model_dict[k]
|
| 436 |
-
|
| 437 |
default_models = model_fast_picker(models)
|
| 438 |
if len(models)>0:
|
| 439 |
if len(default_models)==0:
|
| 440 |
default_models = [models[0]]
|
| 441 |
model_selection = st.sidebar.multiselect('select models for chart', models, default=default_models)
|
| 442 |
|
| 443 |
-
|
| 444 |
-
if os.path.isfile(project_config.DASHBOARD_MODEL_RESULT_FILE) and len(model_selection)>0:
|
| 445 |
-
data = project_utils.load_data(project_config.DASHBOARD_MODEL_RESULT_FILE)
|
| 446 |
roundresult_chart(data, model_selection)
|
| 447 |
|
| 448 |
# fig = px.line(df, x='roundNumber', y='corr', color='model', hover_data=['corr_pct'])
|
|
@@ -458,31 +475,22 @@ def histtrend():
|
|
| 458 |
|
| 459 |
|
| 460 |
def model_evaluation():
|
| 461 |
-
|
|
|
|
| 462 |
model_selection = []
|
| 463 |
-
|
| 464 |
mean_scale = [-0.05, 0.1]
|
| 465 |
count_scale = [1, 50]
|
| 466 |
-
sharpe_scale = [-0.2,
|
| 467 |
pct_scale = [0, 1]
|
| 468 |
radar_scale = [0, 5]
|
| 469 |
|
| 470 |
-
for k in model_dict.keys():
|
| 471 |
-
if model_dict[k] not in models:
|
| 472 |
-
models += model_dict[k]
|
| 473 |
-
|
| 474 |
-
default_models = model_fast_picker(models)
|
| 475 |
if len(models)>0:
|
| 476 |
if len(default_models)==0:
|
| 477 |
-
|
| 478 |
-
default_models = 'integration_test'
|
| 479 |
-
else:
|
| 480 |
-
default_models = [models[0]]
|
| 481 |
-
|
| 482 |
model_selection = st.sidebar.multiselect('select models for chart', models, default=default_models)
|
| 483 |
|
| 484 |
-
if
|
| 485 |
-
data = project_utils.load_data(project_config.DASHBOARD_MODEL_RESULT_FILE)
|
| 486 |
round_data = data[data['model'].isin(model_selection)].drop_duplicates(['model', 'roundNumber'],keep='first').reset_index(drop=True)
|
| 487 |
min_round = int(round_data['roundNumber'].min())
|
| 488 |
max_round = int(round_data['roundNumber'].max())
|
|
@@ -493,18 +501,17 @@ def model_evaluation():
|
|
| 493 |
min_selectround, max_selectround = st.slider('select plotting round range', min_round, max_round,
|
| 494 |
(suggest_min_round, max_round), 1)
|
| 495 |
round_list = [r for r in range(min_selectround, max_selectround+1)]
|
| 496 |
-
defaultlist = ['corr_sharpe', '
|
|
|
|
|
|
|
| 497 |
|
| 498 |
select_metrics = st.multiselect('Metric Selection', list(model_eval_opt.keys()),
|
| 499 |
format_func=lambda x: model_eval_opt[x], default=defaultlist)
|
| 500 |
|
| 501 |
-
use_dailymetrics = ('id_corr_sharpe' in select_metrics) or (('id_mmc_sharpe' in select_metrics)) or ('id_corrmmc_sharpe' in select_metrics)
|
| 502 |
-
if use_dailymetrics:
|
| 503 |
-
st.write('use daily metrics')
|
| 504 |
|
| 505 |
round_data = round_data[round_data['roundNumber'].isin(round_list)].reset_index(drop=True)
|
| 506 |
#'need normalised radar chart + tabular view here
|
| 507 |
-
roundmetric_df = get_roundmetric_data(round_data).sort_values(by='
|
| 508 |
|
| 509 |
radarmetric_df = roundmetric_df.copy(deep=True)
|
| 510 |
for col in select_metrics:
|
|
@@ -574,7 +581,7 @@ def get_portfolio_overview(models, onlylatest=True):
|
|
| 574 |
try:
|
| 575 |
res_df = pd.concat(res_df, axis=0)
|
| 576 |
res_df['profitability'] = res_df['realised_pl']/(res_df['current_stake']-res_df['realised_pl'])
|
| 577 |
-
cols = ['model', 'date', 'current_stake', 'floating_stake', 'floating_pl', 'realised_pl', 'profitability']
|
| 578 |
|
| 579 |
# res_df['date'] = res_df['date'].dt.date
|
| 580 |
if onlylatest:
|
|
@@ -684,17 +691,23 @@ def check_session_state(key):
|
|
| 684 |
|
| 685 |
|
| 686 |
def stake_overview():
|
| 687 |
-
|
|
|
|
| 688 |
model_selection = []
|
| 689 |
-
|
|
|
|
| 690 |
for k in model_dict.keys():
|
| 691 |
-
|
| 692 |
-
models += model_dict[k]
|
| 693 |
|
| 694 |
default_models = model_fast_picker(models)
|
|
|
|
| 695 |
if len(models)>0:
|
|
|
|
|
|
|
| 696 |
model_selection = st.sidebar.multiselect('select models for chart', models, default=default_models)
|
|
|
|
| 697 |
redownload_data = False
|
|
|
|
| 698 |
if len(model_selection) > 0:
|
| 699 |
if 'stake_df' not in st.session_state:
|
| 700 |
redownload_data = True
|
|
@@ -705,34 +718,34 @@ def stake_overview():
|
|
| 705 |
ovdf = st.session_state['stake_df']
|
| 706 |
if redownload_data:
|
| 707 |
ovdf = get_portfolio_overview(model_selection, onlylatest=False)
|
| 708 |
-
print(ovdf.shape)
|
| 709 |
st.session_state['stake_df'] = ovdf
|
| 710 |
st.session_state['stake_overview_models'] = set(ovdf['model'].unique().tolist())
|
| 711 |
|
| 712 |
chartdf = ovdf.copy(deep=True)
|
| 713 |
ovdf = ovdf.drop_duplicates('model', keep='first')
|
| 714 |
ovdf = ovdf.sort_values(by='floating_pl', ascending=False).reset_index(drop=True)
|
| 715 |
-
if len(ovdf)>0:
|
| 716 |
-
|
|
|
|
| 717 |
ovdf.drop(['date'], axis=1, inplace=True)
|
| 718 |
stake_cts = st.columns(2)
|
| 719 |
pl_cts = st.columns(2)
|
| 720 |
date_label = st.empty()
|
| 721 |
get_stake_graph(chartdf)
|
| 722 |
-
ovdf_exp = st.expander('', expanded=True)
|
| 723 |
with ovdf_exp:
|
| 724 |
-
st.dataframe(ovdf, height=max_table_height)
|
| 725 |
total_current_stake = round(ovdf['current_stake'].sum(), 3)
|
| 726 |
total_floating_stake = round(ovdf['floating_stake'].sum(), 3)
|
| 727 |
rpl = round(ovdf['realised_pl'].sum(), 3)
|
| 728 |
fpl = round(ovdf['floating_pl'].sum(), 3)
|
| 729 |
current_stake_str = f'### Stake Balance: {total_current_stake:0.3f} NMR'
|
| 730 |
-
float_stake_str =
|
| 731 |
-
if rpl>=0:
|
| 732 |
real_pl_color = 'green'
|
| 733 |
else:
|
| 734 |
real_pl_color = 'red'
|
| 735 |
-
if fpl>=0:
|
| 736 |
float_pl_color = 'green'
|
| 737 |
else:
|
| 738 |
float_pl_color = 'red'
|
|
@@ -742,15 +755,36 @@ def stake_overview():
|
|
| 742 |
stake_cts[1].markdown(float_stake_str, unsafe_allow_html=True)
|
| 743 |
pl_cts[0].markdown(real_pl_str, unsafe_allow_html=True)
|
| 744 |
pl_cts[1].markdown(float_pl_str, unsafe_allow_html=True)
|
| 745 |
-
date_label.subheader(f'Date: {
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
| 751 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 752 |
|
| 753 |
-
round_view(liveround_stake_df,'live_round_stake')
|
| 754 |
|
| 755 |
|
| 756 |
|
|
@@ -766,12 +800,14 @@ def app_setting():
|
|
| 766 |
|
| 767 |
|
| 768 |
def performance_overview():
|
|
|
|
| 769 |
select_app = st.sidebar.selectbox("", list(pfm_opt.keys()), index=0, format_func=lambda x: pfm_opt[x])
|
| 770 |
if select_app=='data_op':
|
| 771 |
data_operation()
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
|
|
|
|
| 775 |
if select_app=='historic_trend':
|
| 776 |
histtrend()
|
| 777 |
if select_app=='model_evaluation':
|
|
@@ -795,13 +831,14 @@ def show_content():
|
|
| 795 |
app_opt = {
|
| 796 |
'performance_overview' : 'Performance Overview',
|
| 797 |
'stake_overview': 'Stake Overview',
|
| 798 |
-
'app_setting':''
|
| 799 |
}
|
| 800 |
|
| 801 |
|
| 802 |
pfm_opt = {
|
| 803 |
'data_op': 'Download Score Data',
|
| 804 |
-
'liveround_view': '
|
|
|
|
| 805 |
'historic_trend': 'Historic Trend',
|
| 806 |
'model_evaluation': 'Model Evaluation',
|
| 807 |
}
|
|
@@ -839,23 +876,26 @@ id_metric_score_dic = {
|
|
| 839 |
|
| 840 |
|
| 841 |
roundmetric_opt ={'corr':'Corr metrics',
|
| 842 |
-
'
|
|
|
|
|
|
|
|
|
|
| 843 |
'corrmmc' : 'CorrMMC metrics',
|
| 844 |
-
'
|
| 845 |
-
'pct' : 'Pecentage metrics'
|
| 846 |
-
|
| 847 |
}
|
| 848 |
|
| 849 |
|
| 850 |
histtrend_opt = {
|
| 851 |
'corr':'Correlation',
|
| 852 |
'mmc': 'MMC',
|
| 853 |
-
'
|
| 854 |
-
'corr2mmc': 'Correlation+2*MMC',
|
| 855 |
'corr_pct': 'Correlation Percentile',
|
|
|
|
| 856 |
'mmc_pct':'MMC Percentile',
|
| 857 |
-
'
|
| 858 |
-
'
|
|
|
|
|
|
|
| 859 |
|
| 860 |
}
|
| 861 |
|
|
@@ -863,20 +903,19 @@ histtrend_opt = {
|
|
| 863 |
model_eval_opt = {
|
| 864 |
'corr_sharpe' : 'Correlation Sharpe',
|
| 865 |
'mmc_sharpe' : 'MMC Sharpe',
|
|
|
|
|
|
|
| 866 |
'corrmmc_sharpe' : 'Correlation+MMC Sharpe',
|
| 867 |
-
'corr2mmc_sharpe': 'Correlation+2*MMC Sharpe',
|
| 868 |
'corr_mean':'Avg. Correlation',
|
| 869 |
-
'
|
| 870 |
'count': 'Number of Rounds',
|
|
|
|
|
|
|
| 871 |
'corrmmc_mean': 'Avg. Correlation+MMC',
|
| 872 |
-
'corr2mmc_mean': 'Avg. Correlation+2*MMC',
|
| 873 |
'corr_pct_mean': 'Avg. Correlation Percentile',
|
| 874 |
'mmc_pct_mean': 'Avg. MMC Percentile',
|
| 875 |
-
'
|
| 876 |
-
'
|
| 877 |
-
'id_corr_sharpe': 'Daily Score corr sharpe',
|
| 878 |
-
'id_mmc_sharpe': 'Daily Score mmc sharpe',
|
| 879 |
-
'id_corrmmc_sharpe': 'Daily Score corrmmc sharpe',
|
| 880 |
}
|
| 881 |
|
| 882 |
stakeoverview_plot_opt = {
|
|
@@ -889,10 +928,16 @@ stakeoverview_plot_opt = {
|
|
| 889 |
def show_session_status_info():
|
| 890 |
# 'raw_performance_data'
|
| 891 |
key1 = 'model_data'
|
|
|
|
| 892 |
if check_session_state(key1) is None:
|
| 893 |
st.write(f'{key1} is None')
|
| 894 |
else:
|
| 895 |
st.write(f'{key1} shape is {st.session_state[key1].shape}')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 896 |
pass
|
| 897 |
|
| 898 |
|
|
@@ -904,8 +949,8 @@ with height_exp:
|
|
| 904 |
max_height = st.slider('Please choose the height for plots', 100, 1000, 400, 50)
|
| 905 |
max_table_height = st.slider('Please choose the height for tables', 100, 1000, 500, 50)
|
| 906 |
|
| 907 |
-
st.title('Numerai Dashboard')
|
| 908 |
|
|
|
|
| 909 |
# key = 'pfm_default_model'
|
| 910 |
# if check_session_state('pfm_default_model') is None:
|
| 911 |
# st.write('set value')
|
|
@@ -916,6 +961,11 @@ st.title('Numerai Dashboard')
|
|
| 916 |
# st.write(st.session_state)
|
| 917 |
|
| 918 |
df = get_saved_data()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 919 |
show_session_status_info()
|
| 920 |
# st.write(f'{key} is {chkval}')
|
| 921 |
|
|
|
|
| 98 |
return picked_models
|
| 99 |
|
| 100 |
|
| 101 |
+
def model_fast_picker(model_list):
|
| 102 |
text_content = '''
|
| 103 |
fast model picker by CSV string.
|
| 104 |
example: "model1, model2, model3"
|
|
|
|
| 109 |
csv_parts = text.split(',')
|
| 110 |
for s in csv_parts:
|
| 111 |
m = s.strip()
|
| 112 |
+
if (m in model_list): #and (m not in preselected_models):
|
| 113 |
result_models.append(m)
|
| 114 |
return list(dict.fromkeys(result_models))
|
| 115 |
|
|
|
|
| 127 |
select_round = row_cts[c].slider('select a round', earliest_round, latest_round, suggest_round, 1)
|
| 128 |
# row_cts[c].write(select_round)
|
| 129 |
round_data = data[data['roundNumber']==select_round].sort_values(by=sortcol, ascending=False).reset_index(drop=True)
|
| 130 |
+
round_resolved_time = round_data['roundResolveTime'][0]
|
| 131 |
# round_data = round_data[round_data['model'].isin(models)].reset_index(drop=True)
|
| 132 |
+
# latest_date = round_data['date'].values[0]
|
| 133 |
+
row_cts[c].write(f'round: {select_round} resolved time: {round_resolved_time}')
|
| 134 |
+
row_cts[c].dataframe(round_data.drop(['roundNumber', 'roundResolveTime'], axis=1), height=max_table_height-100)
|
| 135 |
|
| 136 |
|
| 137 |
|
|
|
|
| 149 |
pass
|
| 150 |
|
| 151 |
def get_roundmetric_data(data):
|
| 152 |
+
numfeats1 = ['corr', 'mmc', 'tc', 'corrmmc', 'corrtc', 'fncV3', 'fncV3_pct']
|
| 153 |
stat1 = ['sum', 'mean', 'count',
|
| 154 |
{'sharpe': project_utils.get_array_sharpe}] # {'ptp':np.ptp}]#{'sharp':project_utils.get_array_sharpe}]
|
| 155 |
+
numfeats2 = ['corr_pct', 'mmc_pct', 'tc_pct','corrtc_avg_pct', 'corrmmc_avg_pct']
|
| 156 |
stat2 = ['mean']#, {'sharp': project_utils.get_array_sharpe}]
|
| 157 |
|
| 158 |
roundmetric_agg_rcp = [
|
|
|
|
| 176 |
# st.write(data.columns.tolist())
|
| 177 |
for col in data.columns.tolist():
|
| 178 |
if select_metric =='corrmmc':
|
| 179 |
+
if (f'{select_metric}_' in col) or ('corrmmc_avg_' in col):
|
| 180 |
cols += [col]
|
| 181 |
+
elif select_metric =='corrtc':
|
| 182 |
+
if (f'{select_metric}_' in col) or ('corrtc_avg_' in col):
|
| 183 |
cols += [col]
|
| 184 |
else:
|
| 185 |
+
# if (f'{select_metric}_' in col) and (not('corrmmc' in col)) and (not('corrtc' in col)):
|
| 186 |
+
if (f'{select_metric}_' in col):
|
| 187 |
cols+= [col]
|
| 188 |
|
| 189 |
if select_metric != 'pct':
|
| 190 |
sort_col = select_metric+'_sharpe'
|
| 191 |
else:
|
| 192 |
+
sort_col = 'corr_pct_mean'
|
| 193 |
view_data = data[cols].sort_values(by=sort_col, ascending=False)
|
| 194 |
row_cts[c].dataframe(view_data)
|
| 195 |
pass
|
|
|
|
| 239 |
generate_round_table(data, row_cts, c, r)
|
| 240 |
if select_perview=='dailyscore_metric':
|
| 241 |
generate_dailyscore_metrics(data, row_cts, c, r)
|
| 242 |
+
if select_perview=='metric_view':
|
| 243 |
generate_round_metrics(data, row_cts, c, r)
|
| 244 |
if select_perview=='dailyscore_chart':
|
| 245 |
dailyscore_chart(data, row_cts, c, r, select_metric)
|
|
|
|
| 248 |
|
| 249 |
|
| 250 |
def score_overview():
|
| 251 |
+
if 'model_data' in st.session_state:
|
| 252 |
+
data = st.session_state['model_data'].copy()
|
| 253 |
+
data = data.drop_duplicates(['model', 'roundNumber'], keep='first')
|
| 254 |
+
roundview = st.expander('round performance overview', expanded=True)
|
| 255 |
+
with roundview:
|
| 256 |
+
round_view(data, 'round_result')
|
| 257 |
+
else:
|
| 258 |
+
st.write('model data missing, please go to the Dowanload Score Data section to download model data first')
|
| 259 |
+
|
| 260 |
+
def metric_overview():
|
| 261 |
+
if 'model_data' in st.session_state:
|
| 262 |
+
data = st.session_state['model_data'].copy()
|
| 263 |
+
st.subheader('Select Round Data')
|
| 264 |
+
latest_round = int(data['roundNumber'].max())
|
| 265 |
+
earliest_round = int(data['roundNumber'].min())
|
| 266 |
+
if (latest_round - earliest_round) > 10:
|
| 267 |
+
# suggest_round = int(latest_round - (latest_round - earliest_round) / 2)
|
| 268 |
+
suggest_round = 280
|
| 269 |
+
else:
|
| 270 |
+
suggest_round = earliest_round
|
| 271 |
+
select_rounds = st.slider('select a round', earliest_round, latest_round, (suggest_round, latest_round - 1), 1)
|
| 272 |
+
data=data.drop_duplicates(['model', 'roundNumber'], keep='first')
|
| 273 |
+
data = data[(data['roundNumber'] >= select_rounds[0]) & (data['roundNumber'] <= select_rounds[1])].reset_index(drop=True)
|
| 274 |
+
roundmetrics_data = get_roundmetric_data(data)
|
| 275 |
+
min_count = int(roundmetrics_data['count'].min())
|
| 276 |
+
max_count = int(roundmetrics_data['count'].max())
|
| 277 |
+
if min_count < max_count:
|
| 278 |
+
select_minround = st.sidebar.slider('miminum number of rounds', min_count, max_count, min_count, 1)
|
| 279 |
+
else:
|
| 280 |
+
select_minround = min_count
|
| 281 |
+
roundmetrics_data = roundmetrics_data[roundmetrics_data['count'] >= select_minround].reset_index(drop=True)
|
| 282 |
+
metricview_exp = st.expander('metric overview', expanded=True)
|
| 283 |
+
dataview_exp = st.expander('full data view', expanded=False)
|
| 284 |
+
with metricview_exp:
|
| 285 |
+
round_view(roundmetrics_data, 'metric_view')
|
| 286 |
+
with dataview_exp:
|
| 287 |
+
st.write(roundmetrics_data)
|
| 288 |
+
else:
|
| 289 |
+
st.write('model data missing, please go to the Dowanload Score Data section to download model data first')
|
| 290 |
|
| 291 |
|
| 292 |
def data_operation():
|
| 293 |
# top_lb, top_tp3m, top_tp1y, special_list = sidebar_data_picker()
|
| 294 |
+
full_model_list = st.session_state['models']
|
| 295 |
latest_round = project_utils.latest_round
|
| 296 |
models = []
|
| 297 |
benchmark_opt = st.sidebar.checkbox('download default models', value=True)
|
|
|
|
| 299 |
model_dict = default_model_picker()
|
| 300 |
for k in model_dict.keys():
|
| 301 |
models += model_dict[k]
|
| 302 |
+
models = models + model_fast_picker(full_model_list)
|
| 303 |
if len(models)>0:
|
| 304 |
+
model_selection = st.multiselect('select models', st.session_state['models'], default=models)
|
| 305 |
suggest_min_round = 182 #latest_round-50
|
| 306 |
min_round, max_round = st.slider('select tournament rounds', 200, latest_round, (suggest_min_round, latest_round), 1)
|
| 307 |
roundlist = [i for i in range(max_round, min_round-1, -1)]
|
|
|
|
| 323 |
if prjreload:
|
| 324 |
project_utils.reload_project()
|
| 325 |
if len(model_df)>0:
|
| 326 |
+
rename_dict = {'corrPercentile': 'corr_pct', 'correlation':'corr', 'corrWMetamodel':'corr_meta', 'mmcPercentile':'mmc_pct', 'tcPercentile':'tc_pct', 'fncV3Percentile':'fncV3_pct'}
|
| 327 |
model_df.rename(columns=rename_dict, inplace=True)
|
| 328 |
model_df['corrmmc'] = model_df['corr'] + model_df['mmc']
|
| 329 |
+
model_df['corrmmc_avg_pct'] = (model_df['corr_pct'] + model_df['mmc_pct'])/2
|
| 330 |
+
model_df['corrtc'] = model_df['corr'] + model_df['tc']
|
| 331 |
+
model_df['corrtc_avg_pct'] = (model_df['corr_pct'] + model_df['tc_pct'])/2
|
| 332 |
+
# st.write(model_df.head(5))
|
| 333 |
+
# ord_cols = ['model','corr', 'mmc', 'tc', 'corrmmc', 'corrtc', 'corr_pct', 'tc_pct', 'corrtc_avg_pct','corr_meta', 'mmc_pct', 'corrmmc_avg_pct', 'roundNumber', 'roundResolveTime']
|
| 334 |
+
ord_cols = ['model','corr', 'tc', 'corrtc', 'corr_pct', 'tc_pct', 'corrtc_avg_pct','corr_meta', 'fncV3', 'fncV3_pct','corrmmc_avg_pct', 'roundNumber', 'roundResolveTime', 'mmc', 'corrmmc','mmc_pct']
|
| 335 |
+
|
| 336 |
model_df = model_df[ord_cols]
|
| 337 |
if project_config.SAVE_LOCAL_COPY:
|
| 338 |
project_utils.pickle_data(project_config.MODEL_ROUND_RESULT_FILE, model_df)
|
|
|
|
| 342 |
st.text('list of models being tracked')
|
| 343 |
st.write(model_dict)
|
| 344 |
try:
|
| 345 |
+
dshape = st.session_state['model_data'].shape
|
| 346 |
+
st.write(f'downloaded model result data shape is {dshape}')
|
| 347 |
+
st.write(model_df)
|
| 348 |
except:
|
| 349 |
st.write('model data was not retrieved')
|
| 350 |
|
|
|
|
| 403 |
time.sleep(0.1)
|
| 404 |
my_bar.progress(percent_complete)
|
| 405 |
model_df = pd.concat(model_dfs, axis=0).sort_values(by=['roundNumber'], ascending=False).reset_index(drop=True)
|
| 406 |
+
model_df['roundResolveTime'] = pd.to_datetime(model_df['roundResolveTime'])
|
| 407 |
+
model_df['roundResolveTime'] = model_df['roundResolveTime'].dt.strftime(project_config.DATETIME_FORMAT3)
|
| 408 |
model_df = model_df[model_df['roundNumber'].isin(roundlist)].reset_index(drop=True)
|
| 409 |
return model_df
|
| 410 |
|
|
|
|
| 428 |
min_selectround, max_selectround = st.slider('select plotting round range', min_round, max_round,
|
| 429 |
(suggest_min_round, max_round), 1)
|
| 430 |
|
|
|
|
|
|
|
|
|
|
| 431 |
select_metric = st.selectbox('Choose a metric', list(histtrend_opt.keys()), index=0,
|
| 432 |
format_func=lambda x: histtrend_opt[x])
|
| 433 |
round_range = [min_selectround, max_selectround]
|
|
|
|
| 438 |
mean_df['mean'] = mean_df[select_metric]
|
| 439 |
merge_cols = ['model', 'model avg.', 'mean']
|
| 440 |
round_data = round_data.merge(right=mean_df[merge_cols], on='model', how='left').sort_values(by=['mean','model', 'roundNumber'], ascending=False)
|
| 441 |
+
fig = chart_pxline(round_data, 'roundNumber', y=select_metric, color='model avg.', hover_data=list(histtrend_opt.keys())+['roundResolveTime'],x_range=round_range)
|
|
|
|
| 442 |
if fig is not None:
|
| 443 |
st.plotly_chart(fig, use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
|
| 445 |
+
|
|
|
|
| 446 |
|
| 447 |
|
| 448 |
|
|
|
|
| 450 |
def histtrend():
|
| 451 |
# default_models = ['yxbot']
|
| 452 |
# models = default_models.copy()
|
| 453 |
+
data = st.session_state['model_data'].copy()
|
| 454 |
+
models = data['model'].unique().tolist()
|
| 455 |
model_selection = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
default_models = model_fast_picker(models)
|
| 457 |
if len(models)>0:
|
| 458 |
if len(default_models)==0:
|
| 459 |
default_models = [models[0]]
|
| 460 |
model_selection = st.sidebar.multiselect('select models for chart', models, default=default_models)
|
| 461 |
|
| 462 |
+
if len(model_selection)>0:
|
|
|
|
|
|
|
| 463 |
roundresult_chart(data, model_selection)
|
| 464 |
|
| 465 |
# fig = px.line(df, x='roundNumber', y='corr', color='model', hover_data=['corr_pct'])
|
|
|
|
| 475 |
|
| 476 |
|
| 477 |
def model_evaluation():
|
| 478 |
+
data = st.session_state['model_data'].copy()
|
| 479 |
+
models = data['model'].unique().tolist()
|
| 480 |
model_selection = []
|
| 481 |
+
default_models = model_fast_picker(models)
|
| 482 |
mean_scale = [-0.05, 0.1]
|
| 483 |
count_scale = [1, 50]
|
| 484 |
+
sharpe_scale = [-0.2, 2]
|
| 485 |
pct_scale = [0, 1]
|
| 486 |
radar_scale = [0, 5]
|
| 487 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 488 |
if len(models)>0:
|
| 489 |
if len(default_models)==0:
|
| 490 |
+
default_models = [models[0]]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 491 |
model_selection = st.sidebar.multiselect('select models for chart', models, default=default_models)
|
| 492 |
|
| 493 |
+
if len(model_selection)>0:
|
|
|
|
| 494 |
round_data = data[data['model'].isin(model_selection)].drop_duplicates(['model', 'roundNumber'],keep='first').reset_index(drop=True)
|
| 495 |
min_round = int(round_data['roundNumber'].min())
|
| 496 |
max_round = int(round_data['roundNumber'].max())
|
|
|
|
| 501 |
min_selectround, max_selectround = st.slider('select plotting round range', min_round, max_round,
|
| 502 |
(suggest_min_round, max_round), 1)
|
| 503 |
round_list = [r for r in range(min_selectround, max_selectround+1)]
|
| 504 |
+
# defaultlist = ['corr_sharpe', 'tc_sharpe', 'corrtc_sharpe','corr_mean', 'tc_mean' 'corrtc_mean', 'corrtc_avg_pct','count']
|
| 505 |
+
|
| 506 |
+
defaultlist = ['corr_sharpe', 'tc_sharpe', 'corrtc_sharpe', 'corr_mean', 'tc_mean', 'corrtc_mean', 'corrtc_avg_pct_mean']
|
| 507 |
|
| 508 |
select_metrics = st.multiselect('Metric Selection', list(model_eval_opt.keys()),
|
| 509 |
format_func=lambda x: model_eval_opt[x], default=defaultlist)
|
| 510 |
|
|
|
|
|
|
|
|
|
|
| 511 |
|
| 512 |
round_data = round_data[round_data['roundNumber'].isin(round_list)].reset_index(drop=True)
|
| 513 |
#'need normalised radar chart + tabular view here
|
| 514 |
+
roundmetric_df = get_roundmetric_data(round_data).sort_values(by='corrtc_sharpe', ascending=False).reset_index(drop=True)
|
| 515 |
|
| 516 |
radarmetric_df = roundmetric_df.copy(deep=True)
|
| 517 |
for col in select_metrics:
|
|
|
|
| 581 |
try:
|
| 582 |
res_df = pd.concat(res_df, axis=0)
|
| 583 |
res_df['profitability'] = res_df['realised_pl']/(res_df['current_stake']-res_df['realised_pl'])
|
| 584 |
+
cols = ['model', 'date', 'current_stake', 'floating_stake', 'floating_pl', 'realised_pl', 'profitability', 'roundNumber', 'roundResolved', 'payout']
|
| 585 |
|
| 586 |
# res_df['date'] = res_df['date'].dt.date
|
| 587 |
if onlylatest:
|
|
|
|
| 691 |
|
| 692 |
|
| 693 |
def stake_overview():
|
| 694 |
+
# data = st.session_state['models'].copy()
|
| 695 |
+
models = st.session_state['models'].copy()
|
| 696 |
model_selection = []
|
| 697 |
+
baseline_models = []
|
| 698 |
+
model_dict = default_model_picker()
|
| 699 |
for k in model_dict.keys():
|
| 700 |
+
baseline_models += model_dict[k]
|
|
|
|
| 701 |
|
| 702 |
default_models = model_fast_picker(models)
|
| 703 |
+
|
| 704 |
if len(models)>0:
|
| 705 |
+
# if len(default_models)==0:
|
| 706 |
+
# default_models = baseline_models[0]
|
| 707 |
model_selection = st.sidebar.multiselect('select models for chart', models, default=default_models)
|
| 708 |
+
|
| 709 |
redownload_data = False
|
| 710 |
+
# download = st.sidebar.button('download stake data')
|
| 711 |
if len(model_selection) > 0:
|
| 712 |
if 'stake_df' not in st.session_state:
|
| 713 |
redownload_data = True
|
|
|
|
| 718 |
ovdf = st.session_state['stake_df']
|
| 719 |
if redownload_data:
|
| 720 |
ovdf = get_portfolio_overview(model_selection, onlylatest=False)
|
|
|
|
| 721 |
st.session_state['stake_df'] = ovdf
|
| 722 |
st.session_state['stake_overview_models'] = set(ovdf['model'].unique().tolist())
|
| 723 |
|
| 724 |
chartdf = ovdf.copy(deep=True)
|
| 725 |
ovdf = ovdf.drop_duplicates('model', keep='first')
|
| 726 |
ovdf = ovdf.sort_values(by='floating_pl', ascending=False).reset_index(drop=True)
|
| 727 |
+
if len(ovdf) > 0:
|
| 728 |
+
overview_cols = ['model', 'current_stake', 'floating_stake', 'floating_pl', 'realised_pl']
|
| 729 |
+
date_text = datetime.datetime.now().strftime(project_config.DATETIME_FORMAT3)
|
| 730 |
ovdf.drop(['date'], axis=1, inplace=True)
|
| 731 |
stake_cts = st.columns(2)
|
| 732 |
pl_cts = st.columns(2)
|
| 733 |
date_label = st.empty()
|
| 734 |
get_stake_graph(chartdf)
|
| 735 |
+
ovdf_exp = st.expander('stake data overview', expanded=True)
|
| 736 |
with ovdf_exp:
|
| 737 |
+
st.dataframe(ovdf[overview_cols], height=max_table_height)
|
| 738 |
total_current_stake = round(ovdf['current_stake'].sum(), 3)
|
| 739 |
total_floating_stake = round(ovdf['floating_stake'].sum(), 3)
|
| 740 |
rpl = round(ovdf['realised_pl'].sum(), 3)
|
| 741 |
fpl = round(ovdf['floating_pl'].sum(), 3)
|
| 742 |
current_stake_str = f'### Stake Balance: {total_current_stake:0.3f} NMR'
|
| 743 |
+
float_stake_str = f'### Floating Balance: {total_floating_stake:0.3f} NMR'
|
| 744 |
+
if rpl >= 0:
|
| 745 |
real_pl_color = 'green'
|
| 746 |
else:
|
| 747 |
real_pl_color = 'red'
|
| 748 |
+
if fpl >= 0:
|
| 749 |
float_pl_color = 'green'
|
| 750 |
else:
|
| 751 |
float_pl_color = 'red'
|
|
|
|
| 755 |
stake_cts[1].markdown(float_stake_str, unsafe_allow_html=True)
|
| 756 |
pl_cts[0].markdown(real_pl_str, unsafe_allow_html=True)
|
| 757 |
pl_cts[1].markdown(float_pl_str, unsafe_allow_html=True)
|
| 758 |
+
date_label.subheader(f'Date: {date_text}')
|
| 759 |
+
if st.sidebar.checkbox('show breakdown by live rounds', value=False):
|
| 760 |
+
liveround_exp = st.expander('show breakdown by live rounds (requires extra data downloading)',expanded=True)
|
| 761 |
+
with liveround_exp:
|
| 762 |
+
stake_models = ovdf['model'].tolist()
|
| 763 |
+
liveround_stake_df = get_stake_by_liverounds(stake_models)
|
| 764 |
+
round_view(liveround_stake_df,'live_round_stake')
|
| 765 |
+
if st.sidebar.checkbox('show resolved round summary', value=False):
|
| 766 |
+
resolvedround_exp = st.expander('show resolved rounds summary for selected model group', expanded=True)
|
| 767 |
+
with resolvedround_exp:
|
| 768 |
+
get_roundresolve_history(chartdf)
|
| 769 |
+
# st.write(chartdf)
|
| 770 |
+
|
| 771 |
+
|
| 772 |
+
def get_roundresolve_history(data):
|
| 773 |
+
resolved_rounds = data[data['roundResolved'] == True]['roundNumber'].unique().tolist()
|
| 774 |
+
rsdf = data[data['roundResolved'] == True].reset_index(drop=True)
|
| 775 |
+
rs_date = rsdf[['date', 'roundNumber']].drop_duplicates('roundNumber').reset_index(drop=True)
|
| 776 |
+
numfeats = ['current_stake', 'payout']
|
| 777 |
+
stat1 = ['sum']
|
| 778 |
+
agg_rcp = [[['roundNumber'], numfeats, stat1]]
|
| 779 |
+
res = project_utils.groupby_agg_execution(agg_rcp, rsdf)['roundNumber'].sort_values(by='roundNumber',
|
| 780 |
+
ascending=False)
|
| 781 |
+
res = res.merge(right=rs_date, on='roundNumber')
|
| 782 |
+
|
| 783 |
+
rename_dict = {'roundNumber': 'Round', 'roundNumber_current_stake_sum': 'Total Stake',
|
| 784 |
+
'roundNumber_payout_sum': 'Round P/L', 'date': 'Resolved Date'}
|
| 785 |
+
res.rename(columns=rename_dict, inplace=True)
|
| 786 |
+
st.write(res)
|
| 787 |
|
|
|
|
| 788 |
|
| 789 |
|
| 790 |
|
|
|
|
| 800 |
|
| 801 |
|
| 802 |
def performance_overview():
|
| 803 |
+
# st.sidebar.subheader('Choose a Table View')
|
| 804 |
select_app = st.sidebar.selectbox("", list(pfm_opt.keys()), index=0, format_func=lambda x: pfm_opt[x])
|
| 805 |
if select_app=='data_op':
|
| 806 |
data_operation()
|
| 807 |
+
if select_app=='liveround_view':
|
| 808 |
+
score_overview()
|
| 809 |
+
if select_app=='metric_view':
|
| 810 |
+
metric_overview()
|
| 811 |
if select_app=='historic_trend':
|
| 812 |
histtrend()
|
| 813 |
if select_app=='model_evaluation':
|
|
|
|
| 831 |
app_opt = {
|
| 832 |
'performance_overview' : 'Performance Overview',
|
| 833 |
'stake_overview': 'Stake Overview',
|
| 834 |
+
# 'app_setting':''
|
| 835 |
}
|
| 836 |
|
| 837 |
|
| 838 |
pfm_opt = {
|
| 839 |
'data_op': 'Download Score Data',
|
| 840 |
+
'liveround_view': 'Round Overview',
|
| 841 |
+
'metric_view':'Metric Overview',
|
| 842 |
'historic_trend': 'Historic Trend',
|
| 843 |
'model_evaluation': 'Model Evaluation',
|
| 844 |
}
|
|
|
|
| 876 |
|
| 877 |
|
| 878 |
roundmetric_opt ={'corr':'Corr metrics',
|
| 879 |
+
'tc': 'TC metrics',
|
| 880 |
+
'corrtc': 'CorrTC metrics',
|
| 881 |
+
'fncV3': 'FNCV3 metrics',
|
| 882 |
+
'pct': 'Pecentage metrics',
|
| 883 |
'corrmmc' : 'CorrMMC metrics',
|
| 884 |
+
'mmc': 'MMC metrics'
|
|
|
|
|
|
|
| 885 |
}
|
| 886 |
|
| 887 |
|
| 888 |
histtrend_opt = {
|
| 889 |
'corr':'Correlation',
|
| 890 |
'mmc': 'MMC',
|
| 891 |
+
'tc' : 'TC',
|
|
|
|
| 892 |
'corr_pct': 'Correlation Percentile',
|
| 893 |
+
'tc_pct' : 'TC Percentile',
|
| 894 |
'mmc_pct':'MMC Percentile',
|
| 895 |
+
'corrmmc': 'Correlation+MMC',
|
| 896 |
+
'corrtc': 'Correlation+TC',
|
| 897 |
+
'corrtc_avg_pct': 'Correlation+TC Average Percentile',
|
| 898 |
+
'corrmmc_avg_pct': 'Correlation+MMC Average Percentile',
|
| 899 |
|
| 900 |
}
|
| 901 |
|
|
|
|
| 903 |
model_eval_opt = {
|
| 904 |
'corr_sharpe' : 'Correlation Sharpe',
|
| 905 |
'mmc_sharpe' : 'MMC Sharpe',
|
| 906 |
+
'tc_sharpe' : 'TC Sharpe',
|
| 907 |
+
'corrtc_sharpe': 'Correlation+TC Sharpe',
|
| 908 |
'corrmmc_sharpe' : 'Correlation+MMC Sharpe',
|
|
|
|
| 909 |
'corr_mean':'Avg. Correlation',
|
| 910 |
+
'tc_mean': 'Avg. TC',
|
| 911 |
'count': 'Number of Rounds',
|
| 912 |
+
'mmc_mean':'Avg. MMC',
|
| 913 |
+
'corrtc_mean': 'Avg. Correlation+TC',
|
| 914 |
'corrmmc_mean': 'Avg. Correlation+MMC',
|
|
|
|
| 915 |
'corr_pct_mean': 'Avg. Correlation Percentile',
|
| 916 |
'mmc_pct_mean': 'Avg. MMC Percentile',
|
| 917 |
+
'corrmmc_avg_pct_mean': 'Avg. Correlation+MMC Percentile',
|
| 918 |
+
'corrtc_avg_pct_mean': 'Avg. Correlation+TC Percentile',
|
|
|
|
|
|
|
|
|
|
| 919 |
}
|
| 920 |
|
| 921 |
stakeoverview_plot_opt = {
|
|
|
|
| 928 |
def show_session_status_info():
|
| 929 |
# 'raw_performance_data'
|
| 930 |
key1 = 'model_data'
|
| 931 |
+
key2 = 'models'
|
| 932 |
if check_session_state(key1) is None:
|
| 933 |
st.write(f'{key1} is None')
|
| 934 |
else:
|
| 935 |
st.write(f'{key1} shape is {st.session_state[key1].shape}')
|
| 936 |
+
|
| 937 |
+
if check_session_state(key2) is None:
|
| 938 |
+
st.write(f'{key2} is None')
|
| 939 |
+
else:
|
| 940 |
+
st.write(f'{key2} list has {len(st.session_state[key2])} models')
|
| 941 |
pass
|
| 942 |
|
| 943 |
|
|
|
|
| 949 |
max_height = st.slider('Please choose the height for plots', 100, 1000, 400, 50)
|
| 950 |
max_table_height = st.slider('Please choose the height for tables', 100, 1000, 500, 50)
|
| 951 |
|
|
|
|
| 952 |
|
| 953 |
+
st.title('Numerai Dashboard')
|
| 954 |
# key = 'pfm_default_model'
|
| 955 |
# if check_session_state('pfm_default_model') is None:
|
| 956 |
# st.write('set value')
|
|
|
|
| 961 |
# st.write(st.session_state)
|
| 962 |
|
| 963 |
df = get_saved_data()
|
| 964 |
+
|
| 965 |
+
if check_session_state('models') is None:
|
| 966 |
+
with st.spinner('updating model list'):
|
| 967 |
+
st.session_state['models'] = numerapi_utils.get_lb_models()
|
| 968 |
+
|
| 969 |
show_session_status_info()
|
| 970 |
# st.write(f'{key} is {chkval}')
|
| 971 |
|
project_tools/numerapi_utils.py
CHANGED
|
@@ -11,43 +11,44 @@ napi = numerapi.NumerAPI()
|
|
| 11 |
# def get_round
|
| 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 |
def get_portfolio_overview(models, onlylatest=True):
|
| 37 |
res_df = []
|
| 38 |
for m in models:
|
| 39 |
-
try:
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
except:
|
| 47 |
-
|
| 48 |
if len(res_df)>0:
|
| 49 |
res_df = pd.concat(res_df, axis=0)
|
| 50 |
-
res_df['date'] = res_df['date'].dt.date
|
| 51 |
if onlylatest:
|
| 52 |
return res_df.sort_values(by='floating_pl', ascending=False).reset_index(drop=True)
|
| 53 |
else:
|
|
@@ -189,6 +190,9 @@ def daily_submissions_performances_V3(modelname: str) -> List[Dict]:
|
|
| 189 |
mmcPercentile
|
| 190 |
tc
|
| 191 |
tcPercentile
|
|
|
|
|
|
|
|
|
|
| 192 |
corrWMetamodel
|
| 193 |
payout
|
| 194 |
roundResolved
|
|
@@ -214,8 +218,18 @@ def daily_submissions_performances_V3(modelname: str) -> List[Dict]:
|
|
| 214 |
return performances
|
| 215 |
|
| 216 |
|
| 217 |
-
|
| 218 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
|
| 220 |
|
| 221 |
|
|
@@ -377,7 +391,7 @@ def get_model_history_v3(model):
|
|
| 377 |
res['date'] = pd.to_datetime(res['roundResolveTime']).dt.date
|
| 378 |
|
| 379 |
res['realised_pl'] = res['payout_cumsum']
|
| 380 |
-
latest_realised_pl = res[res['roundResolved'] == True]['payout_cumsum'].
|
| 381 |
res.loc[res['roundResolved'] == False, 'realised_pl'] = latest_realised_pl
|
| 382 |
|
| 383 |
res['floating_pl'] = 0
|
|
|
|
| 11 |
# def get_round
|
| 12 |
|
| 13 |
|
| 14 |
+
# depreciated
|
| 15 |
+
# def get_model_history(model):
|
| 16 |
+
# res = napi.daily_user_performances(model)
|
| 17 |
+
# res = pd.DataFrame.from_dict(res)
|
| 18 |
+
# res['payoutPending'] = res['payoutPending'].astype(np.float64)
|
| 19 |
+
# res['payoutSettled'] = res['payoutSettled'].astype(np.float64)
|
| 20 |
+
# res['stakeValue'] = res['stakeValue'].astype(np.float64)
|
| 21 |
+
# res['deltaRatio'] = res['payoutPending'] / res['stakeValue']
|
| 22 |
+
# res['realised_pl'] = project_utils.series_reverse_cumsum(res['payoutSettled'])
|
| 23 |
+
# res['floating_pl'] = project_utils.series_reverse_cumsum(res['payoutPending']) - res['realised_pl']
|
| 24 |
+
# res['current_stake'] = res['stakeValue'] - res['floating_pl']
|
| 25 |
+
# rename_dict = {'stakeValue':'floating_stake'}
|
| 26 |
+
# res = res.rename(columns=rename_dict)
|
| 27 |
+
# # res['equity'] = res['stakeValue'] + res['floating_pl']
|
| 28 |
+
# # cols = res.columns.tolist()
|
| 29 |
+
# # res = res[['model'] + cols]
|
| 30 |
+
#
|
| 31 |
+
# res['model'] = model
|
| 32 |
+
# cols = ['model', 'date', 'current_stake', 'floating_stake', 'payoutPending', 'floating_pl', 'realised_pl']
|
| 33 |
+
# res = res[cols]
|
| 34 |
+
# return res
|
| 35 |
|
| 36 |
|
| 37 |
def get_portfolio_overview(models, onlylatest=True):
|
| 38 |
res_df = []
|
| 39 |
for m in models:
|
| 40 |
+
# try:
|
| 41 |
+
print(f'extracting information for model {m}')
|
| 42 |
+
if onlylatest:
|
| 43 |
+
mdf = get_model_history_v3(m).loc[0:0]
|
| 44 |
+
else:
|
| 45 |
+
mdf = get_model_history_v3(m)
|
| 46 |
+
res_df.append(mdf)
|
| 47 |
+
# except:
|
| 48 |
+
# print(f'no information for model {m} is available')
|
| 49 |
if len(res_df)>0:
|
| 50 |
res_df = pd.concat(res_df, axis=0)
|
| 51 |
+
# res_df['date'] = res_df['date'].dt.date
|
| 52 |
if onlylatest:
|
| 53 |
return res_df.sort_values(by='floating_pl', ascending=False).reset_index(drop=True)
|
| 54 |
else:
|
|
|
|
| 190 |
mmcPercentile
|
| 191 |
tc
|
| 192 |
tcPercentile
|
| 193 |
+
tcMultiplier
|
| 194 |
+
fncV3
|
| 195 |
+
fncV3Percentile
|
| 196 |
corrWMetamodel
|
| 197 |
payout
|
| 198 |
roundResolved
|
|
|
|
| 218 |
return performances
|
| 219 |
|
| 220 |
|
| 221 |
+
def get_lb_models(limit=20000, offset=0):
|
| 222 |
+
query = """
|
| 223 |
+
query($limit: Int, $offset: Int){
|
| 224 |
+
v2Leaderboard(limit:$limit, offset:$offset){
|
| 225 |
+
username
|
| 226 |
+
}
|
| 227 |
+
}
|
| 228 |
+
"""
|
| 229 |
+
arguments = {'limit':limit, 'offset':offset}
|
| 230 |
+
data = napi.raw_query(query, arguments)['data']['v2Leaderboard']
|
| 231 |
+
model_list = [i['username'] for i in data]
|
| 232 |
+
return model_list
|
| 233 |
|
| 234 |
|
| 235 |
|
|
|
|
| 391 |
res['date'] = pd.to_datetime(res['roundResolveTime']).dt.date
|
| 392 |
|
| 393 |
res['realised_pl'] = res['payout_cumsum']
|
| 394 |
+
latest_realised_pl = res[res['roundResolved'] == True]['payout_cumsum'].values[0]
|
| 395 |
res.loc[res['roundResolved'] == False, 'realised_pl'] = latest_realised_pl
|
| 396 |
|
| 397 |
res['floating_pl'] = 0
|