Spaces:
Build error
Build error
anaucoin commited on
Commit ·
68a88c9
1
Parent(s): baf19dd
update app.py
Browse files
app.py
CHANGED
|
@@ -78,10 +78,16 @@ def my_style(v, props=''):
|
|
| 78 |
props = 'color:red' if v < 0 else 'color:green'
|
| 79 |
return props
|
| 80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
@st.cache(ttl=24*3600, allow_output_mutation=True)
|
| 82 |
def load_data(filename, otimeheader,fmat):
|
| 83 |
df = pd.read_csv(open(filename,'r'), sep='\t') # so as not to mutate cached value
|
| 84 |
-
df.columns = ['Trade','Signal','Entry Date','Buy Price', 'Sell Price','Exit Date', 'P/L per token', 'P/L %']
|
|
|
|
| 85 |
|
| 86 |
df['Buy Price'] = df['Buy Price'].str.replace('$', '', regex=True)
|
| 87 |
df['Sell Price'] = df['Sell Price'].str.replace('$', '', regex=True)
|
|
@@ -116,11 +122,11 @@ def load_data(filename, otimeheader,fmat):
|
|
| 116 |
return df
|
| 117 |
|
| 118 |
def runapp():
|
| 119 |
-
bot_selections = "
|
| 120 |
otimeheader = 'Entry Date'
|
| 121 |
-
plheader = '
|
| 122 |
fmat = '%Y-%m-%d %H:%M:%S'
|
| 123 |
-
dollar_cap =
|
| 124 |
fees = .075/100
|
| 125 |
st.header(f"{bot_selections} Performance Dashboard :bread: :moneybag:")
|
| 126 |
st.write("Welcome to the Trading Bot Dashboard by BreadBytes! You can use this dashboard to track " +
|
|
@@ -132,21 +138,13 @@ def runapp():
|
|
| 132 |
st.subheader("Choose your settings:")
|
| 133 |
no_errors = True
|
| 134 |
|
| 135 |
-
data = load_data("
|
| 136 |
df = data.copy(deep=True)
|
| 137 |
|
| 138 |
-
grouped_df = df.groupby('Exit Date').agg({'Signal':'min','Entry Date': 'min','Exit Date': 'max','Buy Price': 'mean',
|
| 139 |
-
'Sell Price' : 'max',
|
| 140 |
-
'P/L per token': 'mean',
|
| 141 |
-
'P/L %':lambda x: np.round(x.sum()/4,2)})
|
| 142 |
-
grouped_df.index = range(1, len(grouped_df)+1)
|
| 143 |
-
grouped_df.rename(columns={'Buy Price':'Avg. Buy Price',
|
| 144 |
-
'P/L per token':'Avg. P/L per token'}, inplace=True)
|
| 145 |
-
|
| 146 |
dateheader = 'Date'
|
| 147 |
theader = 'Time'
|
| 148 |
|
| 149 |
-
with st.form("user input"):
|
| 150 |
if no_errors:
|
| 151 |
with st.container():
|
| 152 |
col1, col2 = st.columns(2)
|
|
@@ -170,18 +168,18 @@ def runapp():
|
|
| 170 |
with st.container():
|
| 171 |
col1,col2 = st.columns(2)
|
| 172 |
with col2:
|
| 173 |
-
lev = st.number_input('Leverage', min_value=1, value=1, max_value=
|
| 174 |
with col1:
|
| 175 |
principal_balance = st.number_input('Starting Balance', min_value=0.00, value=1000.00, max_value= dollar_cap, step=.01)
|
| 176 |
|
| 177 |
#hack way to get button centered
|
| 178 |
c = st.columns(9)
|
| 179 |
with c[4]:
|
| 180 |
-
submitted = st.form_submit_button("Get Cookin'!")
|
| 181 |
|
| 182 |
signal_map = {'Long': 1, 'Short':-1} # 1 for long #-1 for short
|
| 183 |
|
| 184 |
-
df['Calculated Return %'] =
|
| 185 |
|
| 186 |
|
| 187 |
if submitted and principal_balance * lev > dollar_cap:
|
|
@@ -202,8 +200,7 @@ def runapp():
|
|
| 202 |
df['Balance used in Trade'] = np.concatenate([[principal_balance], df['New Balance'].values[:-1]])
|
| 203 |
df['Net P/L Per Trade'] = (df['Return Per Trade']-1)*df['Balance used in Trade']
|
| 204 |
df['Cumulative P/L'] = df['Net P/L Per Trade'].cumsum()
|
| 205 |
-
|
| 206 |
-
cum_pl = df.loc[df.dropna().index[-1],'Cumulative P/L'] + principal_balance
|
| 207 |
|
| 208 |
effective_return = 100*((cum_pl - principal_balance)/principal_balance)
|
| 209 |
|
|
@@ -215,12 +212,12 @@ def runapp():
|
|
| 215 |
f"{100*(cum_pl-principal_balance)/(principal_balance):.2f} %",
|
| 216 |
)
|
| 217 |
|
| 218 |
-
st.line_chart(data=df.dropna(), x='Exit Date', y='Cumulative P/L', use_container_width=True)
|
| 219 |
|
| 220 |
df['Per Trade Return Rate'] = df['Return Per Trade']-1
|
| 221 |
|
| 222 |
totals = pd.DataFrame([], columns = ['# of Trades', 'Wins', 'Losses', 'Win Rate', 'Profit Factor'])
|
| 223 |
-
data = get_hist_info(df.dropna(), principal_balance,'
|
| 224 |
totals.loc[len(totals)] = list(i for i in data)
|
| 225 |
|
| 226 |
totals['Cum. P/L'] = cum_pl-principal_balance
|
|
@@ -291,30 +288,36 @@ def runapp():
|
|
| 291 |
"",#f"{(1+get_rolling_stats(df,otimeheader, 30))*principal_balance:.2f}",
|
| 292 |
f"{get_rolling_stats(df,lev, otimeheader, 180):.2f}%",
|
| 293 |
)
|
|
|
|
| 294 |
if submitted:
|
| 295 |
grouped_df = df.groupby('Exit Date').agg({'Signal':'min','Entry Date': 'min','Exit Date': 'max','Buy Price': 'mean',
|
| 296 |
'Sell Price' : 'max',
|
| 297 |
'Net P/L Per Trade': 'mean',
|
| 298 |
-
'Calculated Return %' : lambda x: np.round(100*lev*x.sum(),
|
| 299 |
grouped_df.index = range(1, len(grouped_df)+1)
|
| 300 |
grouped_df.rename(columns={'Buy Price':'Avg. Buy Price',
|
| 301 |
'Net P/L Per Trade':'Net P/L',
|
| 302 |
'Calculated Return %':'P/L %'}, inplace=True)
|
| 303 |
-
else:
|
| 304 |
grouped_df = df.groupby('Exit Date').agg({'Signal':'min','Entry Date': 'min','Exit Date': 'max','Buy Price': 'mean',
|
| 305 |
'Sell Price' : 'max',
|
| 306 |
-
'P/L per token': 'mean',
|
| 307 |
-
'Calculated Return %' : lambda x: np.round(100*x.sum(),
|
| 308 |
grouped_df.index = range(1, len(grouped_df)+1)
|
| 309 |
grouped_df.rename(columns={'Buy Price':'Avg. Buy Price',
|
| 310 |
'P/L per token':'Net P/L',
|
| 311 |
-
'Calculated Return %':'P/L %'}, inplace=True)
|
|
|
|
| 312 |
st.subheader("Trade Logs")
|
| 313 |
grouped_df['Entry Date'] = pd.to_datetime(grouped_df['Entry Date'])
|
| 314 |
grouped_df['Exit Date'] = pd.to_datetime(grouped_df['Exit Date'])
|
| 315 |
-
st.dataframe(grouped_df.style.format({'Entry Date':'{:%m-%d-%Y %H:%M:%S}','Exit Date':'{:%m-%d-%Y %H:%M:%S}','Avg. Buy Price': '${:.2f}', 'Sell Price': '${:.2f}', 'Net P/L':'${:.
|
|
|
|
| 316 |
.applymap(my_style,subset=['Net P/L'])\
|
| 317 |
-
.applymap(my_style,subset=['P/L %'])
|
|
|
|
|
|
|
|
|
|
| 318 |
|
| 319 |
if __name__ == "__main__":
|
| 320 |
st.set_page_config(
|
|
|
|
| 78 |
props = 'color:red' if v < 0 else 'color:green'
|
| 79 |
return props
|
| 80 |
|
| 81 |
+
@st.experimental_memo
|
| 82 |
+
def cc_coding(row):
|
| 83 |
+
return ['background-color: lightgrey'] * len(row) if row['Exit Date'] <= datetime.strptime('2022-12-16 00:00:00','%Y-%m-%d %H:%M:%S').date() else [''] * len(row)
|
| 84 |
+
|
| 85 |
+
|
| 86 |
@st.cache(ttl=24*3600, allow_output_mutation=True)
|
| 87 |
def load_data(filename, otimeheader,fmat):
|
| 88 |
df = pd.read_csv(open(filename,'r'), sep='\t') # so as not to mutate cached value
|
| 89 |
+
df.columns = ['Trade','Signal','Entry Date','Buy Price', 'Sell Price','Exit Date', 'P/L per token', 'P/L %', 'Drawdown %']
|
| 90 |
+
# df.insert(1, 'Signal', ['Long']*len(df))
|
| 91 |
|
| 92 |
df['Buy Price'] = df['Buy Price'].str.replace('$', '', regex=True)
|
| 93 |
df['Sell Price'] = df['Sell Price'].str.replace('$', '', regex=True)
|
|
|
|
| 122 |
return df
|
| 123 |
|
| 124 |
def runapp():
|
| 125 |
+
bot_selections = "Cosmic Cupcake"
|
| 126 |
otimeheader = 'Entry Date'
|
| 127 |
+
plheader = 'P/L %'
|
| 128 |
fmat = '%Y-%m-%d %H:%M:%S'
|
| 129 |
+
dollar_cap = 100000.00
|
| 130 |
fees = .075/100
|
| 131 |
st.header(f"{bot_selections} Performance Dashboard :bread: :moneybag:")
|
| 132 |
st.write("Welcome to the Trading Bot Dashboard by BreadBytes! You can use this dashboard to track " +
|
|
|
|
| 138 |
st.subheader("Choose your settings:")
|
| 139 |
no_errors = True
|
| 140 |
|
| 141 |
+
data = load_data("CC-Trade-Log.csv",otimeheader,fmat)
|
| 142 |
df = data.copy(deep=True)
|
| 143 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
dateheader = 'Date'
|
| 145 |
theader = 'Time'
|
| 146 |
|
| 147 |
+
with st.form("user input", ):
|
| 148 |
if no_errors:
|
| 149 |
with st.container():
|
| 150 |
col1, col2 = st.columns(2)
|
|
|
|
| 168 |
with st.container():
|
| 169 |
col1,col2 = st.columns(2)
|
| 170 |
with col2:
|
| 171 |
+
lev = st.number_input('Leverage', min_value=1, value=1, max_value= 3, step=1)
|
| 172 |
with col1:
|
| 173 |
principal_balance = st.number_input('Starting Balance', min_value=0.00, value=1000.00, max_value= dollar_cap, step=.01)
|
| 174 |
|
| 175 |
#hack way to get button centered
|
| 176 |
c = st.columns(9)
|
| 177 |
with c[4]:
|
| 178 |
+
submitted = st.form_submit_button("Get Cookin'!")
|
| 179 |
|
| 180 |
signal_map = {'Long': 1, 'Short':-1} # 1 for long #-1 for short
|
| 181 |
|
| 182 |
+
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
|
| 183 |
|
| 184 |
|
| 185 |
if submitted and principal_balance * lev > dollar_cap:
|
|
|
|
| 200 |
df['Balance used in Trade'] = np.concatenate([[principal_balance], df['New Balance'].values[:-1]])
|
| 201 |
df['Net P/L Per Trade'] = (df['Return Per Trade']-1)*df['Balance used in Trade']
|
| 202 |
df['Cumulative P/L'] = df['Net P/L Per Trade'].cumsum()
|
| 203 |
+
cum_pl = df.loc[df.drop('Drawdown %', axis=1).dropna().index[-1],'Cumulative P/L'] + principal_balance
|
|
|
|
| 204 |
|
| 205 |
effective_return = 100*((cum_pl - principal_balance)/principal_balance)
|
| 206 |
|
|
|
|
| 212 |
f"{100*(cum_pl-principal_balance)/(principal_balance):.2f} %",
|
| 213 |
)
|
| 214 |
|
| 215 |
+
st.line_chart(data=df.drop('Drawdown %', axis=1).dropna(), x='Exit Date', y='Cumulative P/L', use_container_width=True)
|
| 216 |
|
| 217 |
df['Per Trade Return Rate'] = df['Return Per Trade']-1
|
| 218 |
|
| 219 |
totals = pd.DataFrame([], columns = ['# of Trades', 'Wins', 'Losses', 'Win Rate', 'Profit Factor'])
|
| 220 |
+
data = get_hist_info(df.drop('Drawdown %', axis=1).dropna(), principal_balance,'Per Trade Return Rate')
|
| 221 |
totals.loc[len(totals)] = list(i for i in data)
|
| 222 |
|
| 223 |
totals['Cum. P/L'] = cum_pl-principal_balance
|
|
|
|
| 288 |
"",#f"{(1+get_rolling_stats(df,otimeheader, 30))*principal_balance:.2f}",
|
| 289 |
f"{get_rolling_stats(df,lev, otimeheader, 180):.2f}%",
|
| 290 |
)
|
| 291 |
+
|
| 292 |
if submitted:
|
| 293 |
grouped_df = df.groupby('Exit Date').agg({'Signal':'min','Entry Date': 'min','Exit Date': 'max','Buy Price': 'mean',
|
| 294 |
'Sell Price' : 'max',
|
| 295 |
'Net P/L Per Trade': 'mean',
|
| 296 |
+
'Calculated Return %' : lambda x: np.round(100*lev*x.sum(),2)})
|
| 297 |
grouped_df.index = range(1, len(grouped_df)+1)
|
| 298 |
grouped_df.rename(columns={'Buy Price':'Avg. Buy Price',
|
| 299 |
'Net P/L Per Trade':'Net P/L',
|
| 300 |
'Calculated Return %':'P/L %'}, inplace=True)
|
| 301 |
+
else:
|
| 302 |
grouped_df = df.groupby('Exit Date').agg({'Signal':'min','Entry Date': 'min','Exit Date': 'max','Buy Price': 'mean',
|
| 303 |
'Sell Price' : 'max',
|
| 304 |
+
'P/L per token' : 'mean',
|
| 305 |
+
'Calculated Return %' : lambda x: np.round(100*x.sum(),2)})
|
| 306 |
grouped_df.index = range(1, len(grouped_df)+1)
|
| 307 |
grouped_df.rename(columns={'Buy Price':'Avg. Buy Price',
|
| 308 |
'P/L per token':'Net P/L',
|
| 309 |
+
'Calculated Return %':'P/L %'}, inplace=True)
|
| 310 |
+
|
| 311 |
st.subheader("Trade Logs")
|
| 312 |
grouped_df['Entry Date'] = pd.to_datetime(grouped_df['Entry Date'])
|
| 313 |
grouped_df['Exit Date'] = pd.to_datetime(grouped_df['Exit Date'])
|
| 314 |
+
st.dataframe(grouped_df.style.format({'Entry Date':'{:%m-%d-%Y %H:%M:%S}','Exit Date':'{:%m-%d-%Y %H:%M:%S}','Avg. Buy Price': '${:.2f}', 'Sell Price': '${:.2f}', 'Net P/L':'${:.2f}', 'P/L %':'{:.2f}%'})\
|
| 315 |
+
.apply(cc_coding, axis=1)\
|
| 316 |
.applymap(my_style,subset=['Net P/L'])\
|
| 317 |
+
.applymap(my_style,subset=['P/L %'])\
|
| 318 |
+
,use_container_width=True)
|
| 319 |
+
new_title = '<div style="text-align: right;"><span style="background-color:lightgrey;"> </span> Backtest Data</div>'
|
| 320 |
+
st.markdown(new_title, unsafe_allow_html=True)
|
| 321 |
|
| 322 |
if __name__ == "__main__":
|
| 323 |
st.set_page_config(
|