feat: trade analysis equity overlays, theme settings, chart fixes

Trade Analysis:
- Add toggleable equity curve overlays: Account total, By Strategy,
  By Symbol, By Day of Week — checkboxes above each chart
- Fix all chart backgrounds to transparent (inherit page theme)
- Fix grid and font colours to work on both dark and light backgrounds

Settings page:
- Full theme control: Dark / Light / Custom radio with Apply button
- Custom mode: colour pickers for accent, page bg, sidebar bg, text,
  font selector and base dark/light toggle
- Preview swatches before applying
- Discard / Reset to Dark button
- Text size: Normal / Large (+2px) / Extra Large (+4px) via CSS injection
- inject_theme_css() helper for app.py to apply font size on all pages
- Theme written to .streamlit/config.toml on apply
This commit is contained in:
unknown
2026-04-15 08:23:56 +10:00
parent 2215a5d727
commit a784d26875
6 changed files with 280 additions and 47 deletions
+76 -25
View File
@@ -234,27 +234,78 @@ def render():
c4.metric("Short Win Rate",f"{stats['short_win_rate']}%")
def render_equity_curve(df_plot, label="Equity Curve"):
import pandas as pd
df_s = df_plot.sort_values('close_time').copy()
df_s['cumulative'] = df_s['net_profit'].cumsum()
# ── Overlay toggles ───────────────────────────────────────────────
ov_cols = st.columns(4)
show_account = ov_cols[0].checkbox("Account total", value=True, key=f"eq_account_{label}")
show_strategy = ov_cols[1].checkbox("By Strategy", value=False, key=f"eq_strat_{label}")
show_symbol = ov_cols[2].checkbox("By Symbol", value=False, key=f"eq_sym_{label}")
show_dow = ov_cols[3].checkbox("By Day of Week", value=False, key=f"eq_dow_{label}")
COLORS = ['#7c6af7','#34C27A','#F5A623','#E05555','#4C8EF5',
'#A78BFA','#22D3EE','#FB923C','#F472B6','#86EFAC']
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df_s['close_time'], y=df_s['cumulative'],
mode='lines',
line=dict(color='#7c6af7', width=2),
fill='tozeroy',
fillcolor='rgba(124,106,247,0.08)',
name='Equity'
))
# Account total
if show_account:
df_s['_cum'] = df_s['net_profit'].cumsum()
fig.add_trace(go.Scatter(
x=df_s['close_time'], y=df_s['_cum'],
mode='lines', name='Account',
line=dict(color='#7c6af7', width=2),
fill='tozeroy', fillcolor='rgba(124,106,247,0.06)',
))
# By Strategy
if show_strategy and 'strategy' in df_s.columns:
for i, strat in enumerate(sorted(df_s['strategy'].dropna().unique())):
sub = df_s[df_s['strategy']==strat].copy()
sub['_cum'] = sub['net_profit'].cumsum()
fig.add_trace(go.Scatter(
x=sub['close_time'], y=sub['_cum'],
mode='lines', name=strat,
line=dict(color=COLORS[(i+1)%len(COLORS)], width=1.5, dash='dot'),
))
# By Symbol
if show_symbol and 'symbol' in df_s.columns:
for i, sym in enumerate(sorted(df_s['symbol'].dropna().unique())):
sub = df_s[df_s['symbol']==sym].copy()
sub['_cum'] = sub['net_profit'].cumsum()
fig.add_trace(go.Scatter(
x=sub['close_time'], y=sub['_cum'],
mode='lines', name=sym,
line=dict(color=COLORS[(i+2)%len(COLORS)], width=1.5, dash='dash'),
))
# By Day of Week
if show_dow and 'day_of_week' in df_s.columns:
dow_order = ['Monday','Tuesday','Wednesday','Thursday','Friday']
for i, dow in enumerate(dow_order):
sub = df_s[df_s['day_of_week']==dow].copy()
if sub.empty: continue
sub['_cum'] = sub['net_profit'].cumsum()
fig.add_trace(go.Scatter(
x=sub['close_time'], y=sub['_cum'],
mode='lines', name=dow,
line=dict(color=COLORS[(i+3)%len(COLORS)], width=1.5),
))
fig.update_layout(
title=label, height=300,
plot_bgcolor='rgba(10,10,15,1)',
paper_bgcolor='rgba(10,10,15,1)',
font=dict(color='#aaa', family='JetBrains Mono'),
xaxis=dict(gridcolor='rgba(255,255,255,0.04)'),
yaxis=dict(gridcolor='rgba(255,255,255,0.04)', tickprefix='$'),
margin=dict(l=60, r=20, t=40, b=40)
title=label, height=360,
plot_bgcolor='rgba(0,0,0,0)',
paper_bgcolor='rgba(0,0,0,0)',
font=dict(family='sans-serif'),
xaxis=dict(gridcolor='rgba(128,128,128,0.15)', showgrid=True),
yaxis=dict(gridcolor='rgba(128,128,128,0.15)', tickprefix='$', showgrid=True),
margin=dict(l=60, r=20, t=40, b=40),
legend=dict(bgcolor='rgba(0,0,0,0)', borderwidth=0),
hovermode='x unified',
)
st.plotly_chart(fig, use_container_width=True)
st.plotly_chart(fig, use_container_width=True, key=f"eq_fig_{label}")
def render_dow_chart(df_plot):
dow_order = ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday']
@@ -272,10 +323,10 @@ def render():
fig.add_trace(go.Bar(x=dow.index, y=losses_dow, name='Loss', marker_color='rgba(230,57,70,0.8)'))
fig.update_layout(
title='P&L by Day of Week', height=280, barmode='relative',
plot_bgcolor='rgba(10,10,15,1)', paper_bgcolor='rgba(10,10,15,1)',
font=dict(color='#aaa'), margin=dict(l=60, r=20, t=40, b=40),
xaxis=dict(gridcolor='rgba(255,255,255,0.04)'),
yaxis=dict(gridcolor='rgba(255,255,255,0.04)', tickprefix='$'),
plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)',
font=dict(family='sans-serif'), margin=dict(l=60, r=20, t=40, b=40),
xaxis=dict(gridcolor='rgba(128,128,128,0.15)'),
yaxis=dict(gridcolor='rgba(128,128,128,0.15)', tickprefix='$'),
legend=dict(bgcolor='rgba(0,0,0,0.3)')
)
st.plotly_chart(fig, use_container_width=True)
@@ -298,10 +349,10 @@ def render():
fig.add_trace(go.Bar(x=losses_h.index, y=losses_h, name='Loss', marker_color='rgba(230,57,70,0.8)'))
fig.update_layout(
title='P&L by Hour of Day', height=280, barmode='relative',
plot_bgcolor='rgba(10,10,15,1)', paper_bgcolor='rgba(10,10,15,1)',
font=dict(color='#aaa'), margin=dict(l=60, r=20, t=40, b=40),
xaxis=dict(gridcolor='rgba(255,255,255,0.04)', title='Hour (UTC)'),
yaxis=dict(gridcolor='rgba(255,255,255,0.04)', tickprefix='$'),
plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)',
font=dict(family='sans-serif'), margin=dict(l=60, r=20, t=40, b=40),
xaxis=dict(gridcolor='rgba(128,128,128,0.15)', title='Hour (UTC)'),
yaxis=dict(gridcolor='rgba(128,128,128,0.15)', tickprefix='$'),
legend=dict(bgcolor='rgba(0,0,0,0.3)')
)
st.plotly_chart(fig, use_container_width=True)