Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2024-05-18 - Added Tooltip Concrete Examples for Quant/Financial Parameters
**Learning:** Users in data-heavy or financial applications often face cognitive load parsing abstract parameters like "bps" (basis points) or statistical quantiles. Tooltips that only repeat the label are unhelpful.
**Action:** Always provide concrete numerical examples in tooltips for abstract or scaled units (e.g., `10 bps = 0.10%`, `0.80 = top 20%`) to immediately anchor the user's understanding.
46 changes: 31 additions & 15 deletions src/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,14 @@ def get_cache_key(*args) -> str:
else:
factor_window = st.slider("Factor Beta Window (days)", 20, 252, 63, 7)
vol_window = st.slider("Regime Vol Window (days)", 10, 60, 21, 5)
adv_pct = st.slider("ADV Participation %", 0.01, 0.30, float(DEFAULT_ADV_PCT), 0.01)
adv_pct = st.slider(
"ADV Participation %",
0.01,
0.30,
float(DEFAULT_ADV_PCT),
0.01,
help="Maximum allowed percentage of Average Daily Volume to trade (e.g., 0.10 = 10%).",
)

st.markdown("---")
st.subheader("4. Research Rigor")
Expand All @@ -185,12 +192,25 @@ def get_cache_key(*args) -> str:
st.info("Using full-sample quantiles (exploratory mode)")

vol_q_high = st.slider(
"High Volatility Quantile", 0.5, 0.95, DEFAULT_VOL_QUANTILE_HIGH, 0.05
"High Volatility Quantile",
0.5,
0.95,
DEFAULT_VOL_QUANTILE_HIGH,
0.05,
help="Quantile threshold defining 'High Volatility' (e.g., 0.80 = top 20% most volatile days).",
)

if mode == "Single-Asset":
st.subheader("5. Backtest Settings")
bt_cost = st.number_input("Transaction Cost (bps)", value=DEFAULT_COST_BPS, step=1) / 10000
bt_cost = (
st.number_input(
"Transaction Cost (bps)",
value=DEFAULT_COST_BPS,
step=1,
help="Cost per trade in basis points (e.g., 10 bps = 0.10%).",
)
/ 10000
)
allow_short = st.checkbox("Allow Short Selling?", value=False)
else:
st.subheader("5. Alert Thresholds")
Expand Down Expand Up @@ -650,11 +670,11 @@ def get_cache_key(*args) -> str:
# --- Regime Detection ---
# Using 21-day annualized vol with option for out-of-sample analysis
df = signals.detect_volatility_regime(
df,
vol_col='Vol_21d',
quantile_high=vol_q_high,
df,
vol_col="Vol_21d",
quantile_high=vol_q_high,
quantile_low=0.25,
use_expanding=use_oos # Toggle between in-sample and out-of-sample
use_expanding=use_oos, # Toggle between in-sample and out-of-sample
)

# --- Dashboard Header ---
Expand All @@ -672,14 +692,12 @@ def get_cache_key(*args) -> str:
h4.metric("Trend Status", "BULLISH" if latest['Close'] > latest[f'SMA_{sma_window}'] else "BEARISH")

# --- Backtest (cached for reuse) ---
df['Signal_Trend'] = np.where(df['Close'] > df[f'SMA_{sma_window}'], 1, -1 if allow_short else 0)
bt_cache_key = get_cache_key(
signal_cache_key, bt_cost, allow_short, use_oos, vol_q_high
)
df["Signal_Trend"] = np.where(df["Close"] > df[f"SMA_{sma_window}"], 1, -1 if allow_short else 0)
bt_cache_key = get_cache_key(signal_cache_key, bt_cost, allow_short, use_oos, vol_q_high)

if bt_cache_key not in st.session_state.backtest_results:
with st.spinner("Running backtest simulation..."):
res_df = backtester.run_backtest(df, 'Signal_Trend', cost_bps=bt_cost, rebalance_freq='M')
res_df = backtester.run_backtest(df, "Signal_Trend", cost_bps=bt_cost, rebalance_freq="M")
st.session_state.backtest_results[bt_cache_key] = res_df

res_df = st.session_state.backtest_results[bt_cache_key]
Expand All @@ -705,9 +723,7 @@ def get_cache_key(*args) -> str:
transition_stats = regime_analysis.compute_transition_stats(
res_df['Strategy_Net_Return'], res_df['Vol_Regime']
)
sweep_df = sweep.run_sma_regime_sweep(
df, DEFAULT_SMA_SWEEP, mom_window, vol_q_high, use_oos
)
sweep_df = sweep.run_sma_regime_sweep(df, DEFAULT_SMA_SWEEP, mom_window, vol_q_high, use_oos)
else:
cond_stats = pd.DataFrame()
bench_cond = pd.DataFrame()
Expand Down
Loading