Promote production portfolio strategy
This commit is contained in:
@@ -14,8 +14,8 @@ Once a day (default 07:00). Steps run **in dependency order**, each consuming th
|
||||
|
||||
1. **OHLCV** — fetch the latest daily bars for every tracked ticker (Alpaca); new tickers backfill ~5 years.
|
||||
2. **Sentiment** — fetch sentiment for the names that matter and are stale (> 5 days): top-pick feeders (residual-momentum leaders with a tradeable long setup), the watchlist, and open paper trades, plus a top-N-by-composite discovery net. Runs *before* the scan so the scan sees fresh sentiment.
|
||||
3. **R:R Scan** — recompute S/R zones, the 5-dimension scores and long/short setups (ATR stops, S/R targets) for every ticker, and attach each ticker's residual 12‑1 momentum activation percentile.
|
||||
4. **Outcome Eval** — resolve setups that hit target/stop or expired (default 30 trading days) and auto-close paper trades per the exit policy (default: hold 30 trading days with the initial stop — the backtest-validated exit).
|
||||
3. **R:R Scan** — recompute S/R zones, the 5-dimension scores and long/short setups (ATR stops, S/R targets) for every ticker, and attach each ticker's residual 12‑1 momentum activation percentile plus the promoted 80/20 production rank.
|
||||
4. **Outcome Eval** — resolve setups that hit target/stop or expired (default 30 trading days) and auto-close paper trades per the exit policy (default: 3x ATR trail with a 30-trading-day max hold).
|
||||
5. **Market Regime** — recompute the regime index (breadth/trend).
|
||||
6. **Regime Monitor** — observational early-warning snapshot (VIX, credit spreads via FRED); feeds nothing else.
|
||||
|
||||
@@ -34,7 +34,7 @@ Fundamentals (weekly, early Monday) · Alerts (hourly, Telegram) · Backtest (we
|
||||
1. **Composite score** — technical, S/R-quality, sentiment, fundamental and momentum sub-scores (0–100) combine into a weighted composite (weights configurable; missing dimensions re-normalize).
|
||||
2. **Setups** — the scanner builds long/short setups with ATR stops and S/R targets, then adds a confidence score, conflict flags and a target reach-probability.
|
||||
3. **Activation gate** — a setup *qualifies* only if it clears the R:R floor **and** ranks in the top residual-momentum percentile of the universe (the validated edge is long-only; the confidence floor was ablated to zero effect and defaults off).
|
||||
4. **Top pick** — the highest residual-momentum qualified setup; highlighted on the Dashboard and labelled on the ticker page.
|
||||
4. **Top pick** — qualified setups are ordered by the production rank: 80% residual momentum percentile + 20% 6-month realized-volatility percentile. The #1 is highlighted on the Dashboard and labelled on the ticker page.
|
||||
|
||||
## Strategy Status — What's Validated and What Isn't
|
||||
|
||||
@@ -42,7 +42,7 @@ Fundamentals (weekly, early Monday) · Alerts (hourly, Telegram) · Backtest (we
|
||||
|
||||
| Component | Verdict | Evidence |
|
||||
|---|---|---|
|
||||
| **Residual 12-1 cross-sectional momentum** (the activation gate, long-only) | **Production ranking — in-sample edge** | Promoted July 2026 after the portfolio variant beat raw 80 on CAGR, Sharpe and drawdown. Raw 12-1 remains a fallback only when benchmark data is unavailable |
|
||||
| **Residual 12-1 cross-sectional momentum** (the activation gate, long-only) | **Production gate — in-sample edge** | Promoted July 2026 after the portfolio variant beat raw 80 on CAGR, Sharpe and drawdown. Raw 12-1 remains a fallback only when benchmark data is unavailable |
|
||||
| S/R setup engine (ATR stops, S/R targets, reach-probability) | **Filter/execution context, not the exit** | R:R/room-to-run still earns its keep as a filter, but S/R targets underperform the time exit. The probability model is display-only |
|
||||
| Composite score + 5 dimensions | **Display/ranking only** | Sub-scores are hand-built heuristics; none has a measured IC. Note: the "momentum" *dimension* is 5/20-day ROC — NOT the validated 12-1 factor (that lives in `momentum_service`) |
|
||||
| LLM sentiment | Display + a bounded composite adjustment (± weight × 100 pts around neutral 50) | Deliberately kept out of the setup engine; no point-in-time history to validate against yet |
|
||||
@@ -54,23 +54,34 @@ Caveats on the momentum result: in-sample, roughly one market regime, costs/slip
|
||||
|
||||
### Current production baseline
|
||||
|
||||
Use this as a regression guardrail for future strategy changes, not as a return promise. Backtest run: 506 tickers, weekly cadence, 30-trading-day horizon, 2022-06-28 → 2026-07-01, 0.1% per-side costs, price-only SPY benchmark.
|
||||
Use this as a regression guardrail for future strategy changes, not as a return promise. Backtest run: local production SQLite snapshot, 506 tickers, weekly cadence, 30-trading-day horizon, 2022-06-28 → 2026-07-01, 0.1% per-side costs, price-only SPY benchmark.
|
||||
|
||||
| Item | Current baseline |
|
||||
|---|---|
|
||||
| Strategy version | `residual_momentum_12_1_rr_time_v2` |
|
||||
| Strategy version | `residual_highvol_80_20_atr_trail3_v1` |
|
||||
| Production gate | Long-only, residual 12-1 momentum percentile >= 80, R:R floor on, NEUTRAL excluded, confidence floor effectively off |
|
||||
| Exit | Hold 30 trading days with the initial ATR stop |
|
||||
| Qualified setups | 1,810 |
|
||||
| Qualified net expectancy | +0.16R per setup |
|
||||
| Profit factor | 1.27 |
|
||||
| Portfolio CAGR | +40.4% |
|
||||
| Portfolio total return | +289.4% vs SPY +95.9% |
|
||||
| Max drawdown | -26.1% |
|
||||
| Sharpe | 1.52 daily, annualized |
|
||||
| Robustness | 30d hold remains +0.16R net/trade after removing the top 5% winners |
|
||||
| Production rank | 80% residual momentum percentile + 20% 6-month realized-volatility percentile |
|
||||
| Exit | Initial ATR stop plus 3x ATR trailing stop, max 30 trading days |
|
||||
| Portfolio CAGR | +44.4% |
|
||||
| Portfolio total return | +336.6% vs SPY +95.7% |
|
||||
| Max drawdown | -23.8% |
|
||||
| Sharpe | 1.72 daily, annualized |
|
||||
| Trades | 376 |
|
||||
| Average hold | 14.7 trading days |
|
||||
|
||||
Nearest challengers from the same run: legacy raw 80 was weaker (+33.8% CAGR, -28.8% max drawdown, Sharpe 1.32); raw 90 was close but had lower Sharpe and worse drawdown (+40.4% CAGR, -27.6% max drawdown, Sharpe 1.49); residual 80 / max 15 removed book-full skips but did not improve CAGR, drawdown, Sharpe or closed trades.
|
||||
Promotion evidence from the same snapshot:
|
||||
|
||||
| Candidate | CAGR | Max DD | Sharpe | Trades | Read |
|
||||
|---|---:|---:|---:|---:|---|
|
||||
| Legacy residual 80 + 30d hold | +34.8% | -24.4% | 1.51 | 339 | Previous production baseline |
|
||||
| Residual/high-vol 80/20 + 30d hold | +39.2% | -23.9% | 1.55 | 345 | Better entry rank, slightly lower drawdown |
|
||||
| Residual/high-vol 80/20 + 3x ATR trail | +44.4% | -23.8% | 1.72 | 376 | Promoted: better CAGR, Sharpe, and drawdown |
|
||||
| Pure high-vol 80 + 30d hold | +37.7% | -37.6% | 1.22 | 491 | Rejected: standalone volatility was too volatile |
|
||||
| Low-vol 80 + 30d hold | +0.4% | -23.1% | 0.09 | 257 | Rejected: no useful edge |
|
||||
|
||||
The conclusion is not "trade high volatility alone." Keep residual momentum as the entry gate, use realized volatility only as a small ranking tilt, and add the ATR trail as defensive exit discipline.
|
||||
|
||||
Live-ranking note: the backtest ranks residual momentum and volatility inside each weekly setup-candidate cross-section. The live scanner computes the same 80/20 formula across the current ticker universe before scanning so every generated setup carries a stable ticker-level rank. That is the production approximation; reconcile it later only if candidate-only post-scan ranking proves materially different.
|
||||
|
||||
### The iron rule for strategy changes
|
||||
|
||||
@@ -84,15 +95,16 @@ Corollaries: never let an unvalidated score gate setups; the outcome evaluator m
|
||||
|
||||
### Highest-value next experiments (in order)
|
||||
|
||||
1. **Raw 90 challenger** — keep comparing raw 12-1 momentum at cutoff 90 against production residual 80; promote only if it beats residual production on Sharpe and drawdown without a meaningful CAGR hit.
|
||||
2. **Capacity check** — keep only the residual 80 / max 15 portfolio row as a guardrail; max 20 and raw max 15 added no information in the July 2026 run.
|
||||
3. **Signal context snapshots** — accumulate point-in-time composite/sentiment/fundamental context for every new setup so the discretionary overlay can be tested forward-only.
|
||||
4. **More breadth, not more history** — widening the ranked universe (e.g. `nasdaq_all`) strengthens each week's cross-section and the IC t-stat, even if only the top slice is traded. (Deeper history was considered and declined.)
|
||||
1. **Forward monitor the promoted strategy** — the production UI now behaves like a portfolio monitor for the current strategy, with selectable lookbacks and SPY comparison.
|
||||
2. **Trailing-stop sensitivity** — locally compare 2.5x, 3x, and 3.5x ATR trails before changing the promoted 3x default.
|
||||
3. **Capacity check** — retest residual/high-vol 80/20 with a max-15 weekly book cap; promote only if it improves drawdown or trade quality without costing too much CAGR.
|
||||
4. **Signal context snapshots** — accumulate point-in-time composite/sentiment/fundamental context for every new setup so the discretionary overlay can be tested forward-only.
|
||||
5. **More breadth, not more history** — widening the ranked universe (e.g. `nasdaq_all`) strengthens each week's cross-section and the IC t-stat, even if only the top slice is traded. (Deeper history was considered and declined.)
|
||||
|
||||
## Key Use Cases
|
||||
|
||||
- **Find today's best long setup.** On the **Dashboard**, the *Top Setups* table lists qualified setups ranked by residual momentum with the #1 flagged "Top pick". Each row opens the ticker page for the chart, scores, S/R targets and entry/stop.
|
||||
- **Track a trade you took.** Mark a setup as a **paper trade**: it's marked-to-market against the latest close, auto-closed by the active exit policy (default: 30 trading days with the initial stop), and its sentiment stays fresh while open. *Signals → Track Record* shows the realized edge.
|
||||
- **Find today's best long setup.** On the **Dashboard**, the *Top Setups* table lists residual-gated qualified setups ranked by the production 80/20 residual/high-vol score, with the #1 flagged "Top pick". Each row opens the ticker page for the chart, scores, S/R targets and entry/stop.
|
||||
- **Track a trade you took.** Mark a setup as a **paper trade**: it's marked-to-market against the latest close, auto-closed by the active exit policy (default: 3x ATR trail with a 30-trading-day max hold), and its sentiment stays fresh while open. *Signals → Track Record* shows the realized edge.
|
||||
|
||||
## Stack
|
||||
|
||||
@@ -123,7 +135,7 @@ Corollaries: never let an unvalidated score gate setups; the outcome evaluator m
|
||||
- Risk:Reward scanner — long and short setups, ATR-based stops, S/R-based targets, configurable R:R threshold (default 1.5:1)
|
||||
- Activation gate — qualifies setups on a residual-momentum percentile floor plus an R:R floor (validated long-only edge)
|
||||
- Recommendation layer — directional confidence, conflict detection, per-target reach-probability
|
||||
- Paper trading — take a setup, mark-to-market vs. latest close, auto-close per the exit policy (default: hold 30 trading days with the initial stop; trailing / target-stop selectable), realized track record + outcome evaluation
|
||||
- Paper trading — take a setup, mark-to-market vs. latest close, auto-close per the exit policy (default: 3x ATR trail with a 30-trading-day max hold; time / percent-trailing / target-stop selectable), realized track record + outcome evaluation
|
||||
- Market-regime index + FRED early-warning monitor (VIX, credit spreads); weekly backtest + manual event study
|
||||
- Telegram alerts (e.g. regime-quadrant changes)
|
||||
- User-curated watchlist (cap: 20), enriched with composite score, R:R and S/R summary
|
||||
@@ -280,12 +292,16 @@ python scripts/create_backtest_snapshot.py \
|
||||
|
||||
```bash
|
||||
# macOS/Linux
|
||||
python scripts/run_backtest_snapshot.py backtest_snapshots/prod.sqlite --workers 8
|
||||
python scripts/run_backtest_snapshot.py backtest_snapshots/prod.sqlite --workers 6
|
||||
|
||||
# Windows PowerShell
|
||||
.venv\Scripts\python.exe scripts\run_backtest_snapshot.py backtest_snapshots\prod.sqlite --workers 12 --allow-spawn
|
||||
.venv\Scripts\python.exe scripts\run_backtest_snapshot.py backtest_snapshots\prod.sqlite --workers 6 --allow-spawn
|
||||
```
|
||||
|
||||
On an 8-thread machine, `--workers 6` is a good starting point: it leaves a
|
||||
couple of threads for Windows, the shell, and browser/UI work while still using
|
||||
most of the CPU.
|
||||
|
||||
The runner writes `reports/backtest-<timestamp>.json` and prints the headline
|
||||
metrics. Keep the SSH tunnel open only while creating the snapshot; the backtest
|
||||
run itself is local/offline. `backtest_snapshots/` and generated backtest reports
|
||||
|
||||
Reference in New Issue
Block a user