Spaces:
Sleeping
Sleeping
anaucoin commited on
Commit ·
769eef4
1
Parent(s): 7a98ad5
theme updates and chart constant
Browse files
app.py
CHANGED
|
@@ -435,73 +435,70 @@ def runapp() -> None:
|
|
| 435 |
c = st.columns(9)
|
| 436 |
with c[4]:
|
| 437 |
submitted = st.form_submit_button("Get Cookin'!")
|
| 438 |
-
|
| 439 |
if submitted and principal_balance * lev > dollar_cap:
|
| 440 |
lev = np.floor(dollar_cap/principal_balance)
|
| 441 |
st.error(f"WARNING: (Starting Balance)*(Leverage) exceeds the ${dollar_cap} limit. Using maximum available leverage of {lev}")
|
| 442 |
|
| 443 |
-
|
| 444 |
-
df = df[(df[dateheader] >= startdate) & (df[dateheader] <= enddate)]
|
| 445 |
-
signal_map = {'Long': 1, 'Short':-1}
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
if len(df) == 0:
|
| 449 |
-
st.error("There are no available trades matching your selections. Please try again!")
|
| 450 |
-
no_errors = False
|
| 451 |
-
|
| 452 |
-
if no_errors:
|
| 453 |
-
if bot_selections == "Cinnamon Toast":
|
| 454 |
-
dca_map = {1: dca1/100, 2: dca2/100, 3: dca3/100, 4: dca4/100, 1.1: dca5/100, 2.1: dca6/100}
|
| 455 |
-
df['DCA %'] = df['DCA'].map(dca_map)
|
| 456 |
-
df['Calculated Return %'] = df['Signal'].map(signal_map)*(df['DCA %'])*(1-fees)*((df['Sell Price']-df['Buy Price'])/df['Buy Price'] - fees) #accounts for fees on open and close of trade
|
| 457 |
-
df['DCA'] = np.floor(df['DCA'].values)
|
| 458 |
-
|
| 459 |
-
df['Return Per Trade'] = np.nan
|
| 460 |
-
df['Balance used in Trade'] = np.nan
|
| 461 |
-
df['New Balance'] = np.nan
|
| 462 |
-
|
| 463 |
-
g = df.groupby('Exit Date').sum(numeric_only=True)['Calculated Return %'].reset_index(name='Return Per Trade')
|
| 464 |
-
df.loc[df['DCA']==1.0,'Return Per Trade'] = 1+lev*g['Return Per Trade'].values
|
| 465 |
-
|
| 466 |
-
df['Compounded Return'] = df['Return Per Trade'].cumprod()
|
| 467 |
-
df.loc[df['DCA']==1.0,'New Balance'] = [min(dollar_cap/lev, bal*principal_balance) for bal in df.loc[df['DCA']==1.0,'Compounded Return']]
|
| 468 |
-
df.loc[df['DCA']==1.0,'Balance used in Trade'] = np.concatenate([[principal_balance], df.loc[df['DCA']==1.0,'New Balance'].values[:-1]])
|
| 469 |
-
else:
|
| 470 |
-
df['Calculated Return %'] = df['Signal'].map(signal_map)*(1-fees)*((df['Sell Price']-df['Buy Price'])/df['Buy Price'] - fees) #accounts for fees on open and close of trade
|
| 471 |
-
df['Return Per Trade'] = np.nan
|
| 472 |
-
g = df.groupby('Exit Date').sum(numeric_only=True)['Calculated Return %'].reset_index(name='Return Per Trade')
|
| 473 |
-
df['Return Per Trade'] = 1+lev*g['Return Per Trade'].values
|
| 474 |
-
|
| 475 |
-
df['Compounded Return'] = df['Return Per Trade'].cumprod()
|
| 476 |
-
df['New Balance'] = [min(dollar_cap/lev, bal*principal_balance) for bal in df['Compounded Return']]
|
| 477 |
-
df['Balance used in Trade'] = np.concatenate([[principal_balance], df['New Balance'].values[:-1]])
|
| 478 |
-
df['Net P/L Per Trade'] = (df['Return Per Trade']-1)*df['Balance used in Trade']
|
| 479 |
-
df['Cumulative P/L'] = df['Net P/L Per Trade'].cumsum()
|
| 480 |
-
|
| 481 |
-
if bot_selections == "Cinnamon Toast" or bot_selections == "Cosmic Cupcake":
|
| 482 |
-
cum_pl = df.loc[df.drop('Drawdown %', axis=1).dropna().index[-1],'Cumulative P/L'] + principal_balance
|
| 483 |
-
#cum_sdp = sd_df.loc[sd_df.drop('Drawdown %', axis=1).dropna().index[-1],'Cumulative P/L (+)'] + principal_balance
|
| 484 |
-
#cum_sdm = sd_df.loc[sd_df.drop('Drawdown %', axis=1).dropna().index[-1],'Cumulative P/L (-)'] + principal_balance
|
| 485 |
-
else:
|
| 486 |
-
cum_pl = df.loc[df.dropna().index[-1],'Cumulative P/L'] + principal_balance
|
| 487 |
-
#cum_sdp = sd_df.loc[sd_df.dropna().index[-1],'Cumulative P/L (+)'] + principal_balance
|
| 488 |
-
#cum_sdm = sd_df.loc[sd_df.dropna().index[-1],'Cumulative P/L (-)'] + principal_balance
|
| 489 |
-
#sd = 2*.00026
|
| 490 |
-
#sd_df = get_sd_df(get_sd_df(df.copy(), sd, bot_selections, dca1, dca2, dca3, dca4, dca5, dca6, fees, lev, dollar_cap, principal_balance)
|
| 491 |
-
|
| 492 |
-
effective_return = 100*((cum_pl - principal_balance)/principal_balance)
|
| 493 |
|
| 494 |
-
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 505 |
|
| 506 |
# with col2:
|
| 507 |
# st.write("95% of trades should fall within this 2 std. dev. range.")
|
|
@@ -515,67 +512,70 @@ def runapp() -> None:
|
|
| 515 |
# f"" ,#${cum_sdm:.2f}"
|
| 516 |
# f"{100*(cum_sdm-principal_balance)/(principal_balance):.2f} %",
|
| 517 |
# )
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
# fig.add_traces(go.Scatter(x=sd_df['Exit Date'], y = sd_df['Cumulative P/L (+)'],line_shape='spline',
|
| 533 |
# line = dict(smoothing = 1.3, color='rgba(31, 119, 200,0)'), showlegend = False)
|
| 534 |
# )
|
| 535 |
-
|
| 536 |
# fig.add_traces(go.Scatter(x=sd_df['Exit Date'], y = sd_df['Cumulative P/L (-)'],
|
| 537 |
# line = dict(smoothing = 1.3, color='rgba(31, 119, 200,0)'), line_shape='spline',
|
| 538 |
# fill='tonexty',
|
| 539 |
# fillcolor = 'rgba(31, 119, 200,.2)', name = '+/- Standard Deviation')
|
| 540 |
# )
|
| 541 |
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
|
| 554 |
-
|
| 555 |
-
|
| 556 |
-
|
| 557 |
-
|
| 558 |
-
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
| 563 |
-
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
|
|
|
|
|
|
|
|
|
| 579 |
st.write()
|
| 580 |
df['Per Trade Return Rate'] = df['Return Per Trade']-1
|
| 581 |
|
|
@@ -588,7 +588,7 @@ def runapp() -> None:
|
|
| 588 |
|
| 589 |
totals['Cum. P/L'] = cum_pl-principal_balance
|
| 590 |
totals['Cum. P/L (%)'] = 100*(cum_pl-principal_balance)/principal_balance
|
| 591 |
-
|
| 592 |
if df.empty:
|
| 593 |
st.error("Oops! None of the data provided matches your selection(s). Please try again.")
|
| 594 |
else:
|
|
@@ -650,7 +650,7 @@ def runapp() -> None:
|
|
| 650 |
"",#f"{(1+get_rolling_stats(df,otimeheader, 30))*principal_balance:.2f}",
|
| 651 |
f"{get_rolling_stats(df,lev, otimeheader, 180):.2f}%",
|
| 652 |
)
|
| 653 |
-
|
| 654 |
if bot_selections == "Cinnamon Toast":
|
| 655 |
if submitted:
|
| 656 |
grouped_df = df.groupby('Exit Date').agg({'Signal':'min','Entry Date': 'min','Exit Date': 'max','Buy Price': 'mean',
|
|
@@ -663,10 +663,7 @@ def runapp() -> None:
|
|
| 663 |
'Net P/L Per Trade':'Net P/L',
|
| 664 |
'Calculated Return %':'P/L %'}, inplace=True)
|
| 665 |
else:
|
| 666 |
-
|
| 667 |
-
df['DCA %'] = df['DCA'].map(dca_map)
|
| 668 |
-
df['Calculated Return %'] = (df['DCA %'])*(1-fees)*((df['Sell Price']-df['Buy Price'])/df['Buy Price'] - fees) #accounts for fees on open and close of trade
|
| 669 |
-
|
| 670 |
grouped_df = df.groupby('Exit Date').agg({'Signal':'min','Entry Date': 'min','Exit Date': 'max','Buy Price': 'mean',
|
| 671 |
'Sell Price' : 'max',
|
| 672 |
'P/L per token': 'mean',
|
|
|
|
| 435 |
c = st.columns(9)
|
| 436 |
with c[4]:
|
| 437 |
submitted = st.form_submit_button("Get Cookin'!")
|
| 438 |
+
signal_map = {'Long': 1, 'Short':-1}
|
| 439 |
if submitted and principal_balance * lev > dollar_cap:
|
| 440 |
lev = np.floor(dollar_cap/principal_balance)
|
| 441 |
st.error(f"WARNING: (Starting Balance)*(Leverage) exceeds the ${dollar_cap} limit. Using maximum available leverage of {lev}")
|
| 442 |
|
| 443 |
+
df = df[(df[dateheader] >= startdate) & (df[dateheader] <= enddate)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
|
| 445 |
+
if submitted and len(df) == 0:
|
| 446 |
+
st.error("There are no available trades matching your selections. Please try again!")
|
| 447 |
+
no_errors = False
|
| 448 |
+
|
| 449 |
+
if no_errors:
|
| 450 |
+
if bot_selections == "Cinnamon Toast":
|
| 451 |
+
dca_map = {1: dca1/100, 2: dca2/100, 3: dca3/100, 4: dca4/100, 1.1: dca5/100, 2.1: dca6/100}
|
| 452 |
+
df['DCA %'] = df['DCA'].map(dca_map)
|
| 453 |
+
df['Calculated Return %'] = df['Signal'].map(signal_map)*(df['DCA %'])*(1-fees)*((df['Sell Price']-df['Buy Price'])/df['Buy Price'] - fees) #accounts for fees on open and close of trade
|
| 454 |
+
df['DCA'] = np.floor(df['DCA'].values)
|
| 455 |
+
|
| 456 |
+
df['Return Per Trade'] = np.nan
|
| 457 |
+
df['Balance used in Trade'] = np.nan
|
| 458 |
+
df['New Balance'] = np.nan
|
| 459 |
+
|
| 460 |
+
g = df.groupby('Exit Date').sum(numeric_only=True)['Calculated Return %'].reset_index(name='Return Per Trade')
|
| 461 |
+
df.loc[df['DCA']==1.0,'Return Per Trade'] = 1+lev*g['Return Per Trade'].values
|
| 462 |
+
|
| 463 |
+
df['Compounded Return'] = df['Return Per Trade'].cumprod()
|
| 464 |
+
df.loc[df['DCA']==1.0,'New Balance'] = [min(dollar_cap/lev, bal*principal_balance) for bal in df.loc[df['DCA']==1.0,'Compounded Return']]
|
| 465 |
+
df.loc[df['DCA']==1.0,'Balance used in Trade'] = np.concatenate([[principal_balance], df.loc[df['DCA']==1.0,'New Balance'].values[:-1]])
|
| 466 |
+
else:
|
| 467 |
+
df['Calculated Return %'] = df['Signal'].map(signal_map)*(1-fees)*((df['Sell Price']-df['Buy Price'])/df['Buy Price'] - fees) #accounts for fees on open and close of trade
|
| 468 |
+
df['Return Per Trade'] = np.nan
|
| 469 |
+
g = df.groupby('Exit Date').sum(numeric_only=True)['Calculated Return %'].reset_index(name='Return Per Trade')
|
| 470 |
+
df['Return Per Trade'] = 1+lev*g['Return Per Trade'].values
|
| 471 |
+
|
| 472 |
+
df['Compounded Return'] = df['Return Per Trade'].cumprod()
|
| 473 |
+
df['New Balance'] = [min(dollar_cap/lev, bal*principal_balance) for bal in df['Compounded Return']]
|
| 474 |
+
df['Balance used in Trade'] = np.concatenate([[principal_balance], df['New Balance'].values[:-1]])
|
| 475 |
+
df['Net P/L Per Trade'] = (df['Return Per Trade']-1)*df['Balance used in Trade']
|
| 476 |
+
df['Cumulative P/L'] = df['Net P/L Per Trade'].cumsum()
|
| 477 |
+
|
| 478 |
+
if bot_selections == "Cinnamon Toast" or bot_selections == "Cosmic Cupcake":
|
| 479 |
+
cum_pl = df.loc[df.drop('Drawdown %', axis=1).dropna().index[-1],'Cumulative P/L'] + principal_balance
|
| 480 |
+
#cum_sdp = sd_df.loc[sd_df.drop('Drawdown %', axis=1).dropna().index[-1],'Cumulative P/L (+)'] + principal_balance
|
| 481 |
+
#cum_sdm = sd_df.loc[sd_df.drop('Drawdown %', axis=1).dropna().index[-1],'Cumulative P/L (-)'] + principal_balance
|
| 482 |
+
else:
|
| 483 |
+
cum_pl = df.loc[df.dropna().index[-1],'Cumulative P/L'] + principal_balance
|
| 484 |
+
#cum_sdp = sd_df.loc[sd_df.dropna().index[-1],'Cumulative P/L (+)'] + principal_balance
|
| 485 |
+
#cum_sdm = sd_df.loc[sd_df.dropna().index[-1],'Cumulative P/L (-)'] + principal_balance
|
| 486 |
+
#sd = 2*.00026
|
| 487 |
+
#sd_df = get_sd_df(get_sd_df(df.copy(), sd, bot_selections, dca1, dca2, dca3, dca4, dca5, dca6, fees, lev, dollar_cap, principal_balance)
|
| 488 |
+
|
| 489 |
+
effective_return = 100*((cum_pl - principal_balance)/principal_balance)
|
| 490 |
+
|
| 491 |
+
st.header(f"{bot_selections} Results")
|
| 492 |
+
with st.container():
|
| 493 |
+
|
| 494 |
+
if len(bot_selections) > 1:
|
| 495 |
+
col1, col2 = st.columns(2)
|
| 496 |
+
with col1:
|
| 497 |
+
st.metric(
|
| 498 |
+
"Total Account Balance",
|
| 499 |
+
f"${cum_pl:.2f}",
|
| 500 |
+
f"{100*(cum_pl-principal_balance)/(principal_balance):.2f} %",
|
| 501 |
+
)
|
| 502 |
|
| 503 |
# with col2:
|
| 504 |
# st.write("95% of trades should fall within this 2 std. dev. range.")
|
|
|
|
| 512 |
# f"" ,#${cum_sdm:.2f}"
|
| 513 |
# f"{100*(cum_sdm-principal_balance)/(principal_balance):.2f} %",
|
| 514 |
# )
|
| 515 |
+
if bot_selections == "Cinnamon Toast" or bot_selections == "Cosmic Cupcake":
|
| 516 |
+
#st.line_chart(data=df.drop('Drawdown %', axis=1).dropna(), x='Exit Date', y='Cumulative P/L', use_container_width=True)
|
| 517 |
+
dfdata = df.drop('Drawdown %', axis=1).dropna()
|
| 518 |
+
#sd_df = sd_df.drop('Drawdown %', axis=1).dropna()
|
| 519 |
+
else:
|
| 520 |
+
#st.line_chart(data=df.dropna(), x='Exit Date', y='Cumulative P/L', use_container_width=True)
|
| 521 |
+
dfdata = df.dropna()
|
| 522 |
+
#sd_df = sd_df.dropna()
|
| 523 |
+
|
| 524 |
+
# Create figure
|
| 525 |
+
fig = go.Figure()
|
| 526 |
+
|
| 527 |
+
pyLogo = Image.open("logo.png")
|
| 528 |
+
|
| 529 |
# fig.add_traces(go.Scatter(x=sd_df['Exit Date'], y = sd_df['Cumulative P/L (+)'],line_shape='spline',
|
| 530 |
# line = dict(smoothing = 1.3, color='rgba(31, 119, 200,0)'), showlegend = False)
|
| 531 |
# )
|
| 532 |
+
|
| 533 |
# fig.add_traces(go.Scatter(x=sd_df['Exit Date'], y = sd_df['Cumulative P/L (-)'],
|
| 534 |
# line = dict(smoothing = 1.3, color='rgba(31, 119, 200,0)'), line_shape='spline',
|
| 535 |
# fill='tonexty',
|
| 536 |
# fillcolor = 'rgba(31, 119, 200,.2)', name = '+/- Standard Deviation')
|
| 537 |
# )
|
| 538 |
|
| 539 |
+
# Add trace
|
| 540 |
+
fig.add_trace(
|
| 541 |
+
go.Scatter(x=dfdata['Exit Date'], y=np.round(dfdata['Cumulative P/L'].values,2), line_shape='spline',
|
| 542 |
+
line = {'smoothing': 1.0, 'color' : 'rgba(90, 223, 137, 1)'},
|
| 543 |
+
name='Cumulative P/L')
|
| 544 |
+
)
|
| 545 |
+
buyhold = (principal_balance/dfdata['Buy Price'][dfdata.index[0]])*(dfdata['Buy Price']-dfdata['Buy Price'][dfdata.index[0]])
|
| 546 |
+
fig.add_trace(go.Scatter(x=dfdata['Exit Date'], y=np.round(buyhold.values,2), line_shape='spline',
|
| 547 |
+
line = {'smoothing': 1.0, 'color' :'rgba(33, 212, 225, 1)'}, name = 'Buy & Hold Return')
|
| 548 |
+
)
|
| 549 |
+
|
| 550 |
+
fig.add_layout_image(
|
| 551 |
+
dict(
|
| 552 |
+
source=pyLogo,
|
| 553 |
+
xref="paper",
|
| 554 |
+
yref="paper",
|
| 555 |
+
x = 0.05, #dfdata['Exit Date'].astype('int64').min() // 10**9,
|
| 556 |
+
y = .85, #dfdata['Cumulative P/L'].max(),
|
| 557 |
+
sizex= .9, #(dfdata['Exit Date'].astype('int64').max() - dfdata['Exit Date'].astype('int64').min()) // 10**9,
|
| 558 |
+
sizey= .9, #(dfdata['Cumulative P/L'].max() - dfdata['Cumulative P/L'].min()),
|
| 559 |
+
sizing="contain",
|
| 560 |
+
opacity=0.2,
|
| 561 |
+
layer = "below")
|
| 562 |
+
)
|
| 563 |
+
|
| 564 |
+
#style layout
|
| 565 |
+
fig.update_layout(
|
| 566 |
+
height = 600,
|
| 567 |
+
xaxis=dict(
|
| 568 |
+
title="Exit Date",
|
| 569 |
+
tickmode='array',
|
| 570 |
+
),
|
| 571 |
+
yaxis=dict(
|
| 572 |
+
title="Cumulative P/L"
|
| 573 |
+
),
|
| 574 |
+
plot_bgcolor = 'rgba(10, 10, 10, 1)'
|
| 575 |
+
)
|
| 576 |
+
|
| 577 |
+
st.plotly_chart(fig, theme=None, use_container_width=True,height=600)
|
| 578 |
+
if submitted:
|
| 579 |
st.write()
|
| 580 |
df['Per Trade Return Rate'] = df['Return Per Trade']-1
|
| 581 |
|
|
|
|
| 588 |
|
| 589 |
totals['Cum. P/L'] = cum_pl-principal_balance
|
| 590 |
totals['Cum. P/L (%)'] = 100*(cum_pl-principal_balance)/principal_balance
|
| 591 |
+
|
| 592 |
if df.empty:
|
| 593 |
st.error("Oops! None of the data provided matches your selection(s). Please try again.")
|
| 594 |
else:
|
|
|
|
| 650 |
"",#f"{(1+get_rolling_stats(df,otimeheader, 30))*principal_balance:.2f}",
|
| 651 |
f"{get_rolling_stats(df,lev, otimeheader, 180):.2f}%",
|
| 652 |
)
|
| 653 |
+
|
| 654 |
if bot_selections == "Cinnamon Toast":
|
| 655 |
if submitted:
|
| 656 |
grouped_df = df.groupby('Exit Date').agg({'Signal':'min','Entry Date': 'min','Exit Date': 'max','Buy Price': 'mean',
|
|
|
|
| 663 |
'Net P/L Per Trade':'Net P/L',
|
| 664 |
'Calculated Return %':'P/L %'}, inplace=True)
|
| 665 |
else:
|
| 666 |
+
|
|
|
|
|
|
|
|
|
|
| 667 |
grouped_df = df.groupby('Exit Date').agg({'Signal':'min','Entry Date': 'min','Exit Date': 'max','Buy Price': 'mean',
|
| 668 |
'Sell Price' : 'max',
|
| 669 |
'P/L per token': 'mean',
|