The Problem
I noticed the model was not making ANY trades for over a week. Every day, the model generated 30+ buy signals, but the portfolio manager - which acts as a gatekeeper - blocked ALL of them due to negative momentum.
Root Cause Analysis
1. Stale momentum data:
- Using articles from the last 10 days (now 3 days)
- Momentum was calculated from prices 5-20 days old
- By the time you made trading decisions, that momentum was ancient history
2. The momentum paradox:
momentum_strength = lag_ret_5d - lag_ret_20d- This measures deceleration, not absolute direction
- Example: Stock up 20% over 20 days, then pulls back 4% in last 5 days = -24% momentum_strength
- The filter was blocking strong stocks taking healthy pullbacks
The Backtest Evidence
Ran analysis on 31,600 test samples and found:
OLD filter (momentum_strength >= 0.1):
- Blocked 89% of stocks
- Blocked stocks: +0.64% avg return, 59.1% win rate ✅ BETTER
- Allowed stocks: +0.23% avg return, 55.7% win rate ❌ WORSE
Best performing cohort (which were blocking):
- "Strong deceleration" (<-0.15 momentum)
- Returns: +1.05% (1d), +2.58% (3d), +2.04% (5d)
- Win rates: 61.6%, 67.4%, 63.4%
The filter was blocking the best opportunities.
The Solution
OLD: Only buy if momentum_strength > 0
NEW: Buy if EITHER:
lag_ret_20d > 10%(strong 20-day uptrend), OR0 < momentum_strength < 15%(mild positive momentum)
Why this works (at least according to the backtest):
- Captures pullbacks in strong uptrends (mean reversion plays)
- Captures steady risers (not overextended)
- Blocks actual falling knives (negative long-term trend)
- Blocks momentum chasers at the top (>15% recent momentum)
Results
- 28/30 signals now pass the filter (vs 0/30 before)
- Deployed 9 trades today with the new logic
- All are strong stocks pulling back (exactly what backtest said to buy)
Now we wait to see if these actually perform as the backtest predicted.
No comments:
Post a Comment