# Learning-loop review — 2026-09-01 436 closed trades reviewed, 150 currently open. Proposal only — nothing here is applied automatically (CLAUDE.md §4: the AI review proposes, dan disposes). # 1. Is overall expectancy holding? Pooled expectancy is **+0.82% per trade** across **436 closed trades**, profit factor 1.60, win rate 63.3% (Wilson lower bound 58.7%). At n=436 this comfortably clears the ~20-trade minimum, so the headline number is not noise in the "too few trades" sense. But the pooled figure conflates accounts with materially different risk configs (per-account risk multipliers differ 10–80x between `paper-main`, `Paper02qsr`, and `live-1`). Per account: paper-main net +$2,850/351 trades, Paper02qsr +$148/28 trades, live-1 **-$95/57 trades**. The only live-money account is currently net negative, though at 57 trades and with a price-biased subsample (small notional cap → only cheap shares), this is not yet a reliable signal either way. Bottom line: expectancy is holding in aggregate, but that aggregate is dominated by simulated fills, and the one real-money account looks weaker on a still-small sample. # 2. Biggest drag bucket Several cuts clear n≥20: by-strategy (orb-v1 n=68, qsr n=340), by-RSI (rsi 30-40 n=95), by-MA50-distance (<-10% n=51), by-relvol (relvol 0.8-1.2 n=26, relvol<0.8 n=307), by-regime (SPY>MA200 n=352), by-exit-reason (stop_loss n=145, take_profit n=158, trailing_stop n=84), and a couple of symbol/strategy+symbol cells (NVO n=25, VST n=23). The largest drag by dollars and by expectancy is **exit reason = stop_loss**: n=145, expectancy **-5.31%**, profit factor 0.01, total P&L **-$4,546** — this single bucket is bigger in magnitude than the entire system's net profit. This is not a "signal band" comparison subject to the 2.48pp forward-return noise floor (that floor applies to splitting entries by predictive indicator value on 5-day forward returns); this is a deterministic accounting of which exit mechanism fired, which the doc explicitly says needs no statistical test ("whether stops actually fire"). At n=145 and a ~10pp gap versus take_profit/trailing_stop, this is real, not noise, by any standard. The smaller entry-side candidates (rsi 30-40 at -0.78% vs pool 0.82%, gap ≈1.6pp; <-10% MA50 at -0.77%, gap ≈1.59pp) are both **below the 2.48pp noise floor** — real bucket, clears the 20-trade bar, but the gap is unresolvable with current data. Flagging explicitly: these look like drags but the sample cannot tell us they're real. # 3. Entry problem, exit problem, or regime problem? Overall MAE/MFE: winners' MAE avg **-1.78%**, losers' MAE avg **-5.16%**, losers' MFE avg **+1.15%**. - Losers' MFE of only +1.15% is modest, not the "was up 3%, exited -2%" signature the doc calls a take-profit problem. So this isn't primarily an exit/target problem — we are not leaving much on the table before losers turn into losses. - Losers' MAE (-5.16%) sits close to the system's `maxStopPct` (8%) and to the realized -5.31% stop_loss expectancy — i.e., the stop is roughly capturing the actual adverse move, not clipping trades on ordinary noise before they could recover. That rules out "stop too tight relative to ATR" as the story here. - Regime: the only regime bucket with n≥20 is SPY>MA200 (n=352, expectancy 0.68%), which is close to the pooled 0.82% figure — no strong regime signature detectable from this cut (the "unknown" comparison group is a missing-data bucket, not a real bear-regime sample). Net read: the stop_loss drag looks like a **genuine entry/signal-timing problem** — trades that go against us keep going against us until the (appropriately-sized) stop, rather than being knocked out by noise or having winners given back at the exit. That diagnosis is consistent with an entry-signal issue, which is exactly the kind of claim rule 6 says we cannot resolve with the current sample (see #4). # 4. Proposed parameter change The natural next step given #3 would be to tighten an entry filter (RSI band, MA50-distance band, etc.). **I am declining to propose that.** Both entry-side candidate gaps (RSI 30-40: ~1.6pp; MA50 <-10%: ~1.59pp) are smaller than the 2.48pp noise floor for band-vs-band comparisons on this journal, and QSR's own power-check shows we're years away from resolving edges in the 0.25–0.50% range (493 symbol-days needed for a 0.50% edge; we have 81 → projected revisit **2027-01-08**). Proposing an entry-threshold change here would be exactly the mistake rule 6 warns against — a null or a hit would both be uninterpretable. Instead, a change that doesn't depend on out-predicting the market: **`qsr.maxHoldDays`, currently `null` (no time stop) → `20`.** Reasoning, from closed-trade evidence only: winning exits resolve quickly — `take_profit` averages 5.0 days hold, `trailing_stop` averages 9.5 days — while `stop_loss` trades average 6.7 days before failing. Almost nothing productive is happening past ~10 days in the closed-trade data (`time_stop` bucket, n=3, is essentially unused because there's no cap to trigger it). Capping hold time at 20 days is a capital-turnover/risk-sizing change, not a signal bet, is trivially reversible, and is justified purely by realized holding-time-to-outcome data rather than any bucket-vs-bucket comparison — so it is fair game at any sample size per the doc's own carve-out. # 5. Notable open positions Not evidence for #4, but worth flagging: a large number of QSR positions have been open **20–41 days** with no calendar exit possible (`maxHoldDays: null`), several meaningfully underwater right now — HDB -4.84% (two lots, 41.3d), CDNS -6.28% (6.1d), URI -6.09% (5.3d), BTI -2.45% (multiple lots, 20–22d), CARR -2.78% (multiple lots, 5–6d), ENB -0.21% to -0.09% for 18–32 days. This pattern of stale, unresolved positions is exactly what motivates the maxHoldDays proposal above — it's color/motivation, not statistical proof, since these trades have no confirmed outcome yet. # 6. QSR shadow comparison note The shadow window (2026-08-09 → 2026-08-23) is closed, so a full outcome backtest comparing legacy would-have-bought trades to the real newlyA trades can now be requested. Qualitatively: the legacy isTriggered+isBuy/buyZonePct method fired only **48 times across 18 tickers** in the window, while the live newlyA method produced **171 closed + 131 open entries across 40 tickers** — roughly 4x the ticker breadth and a much higher firing rate. Ticker overlap is partial (10 of legacy's 18 tickers — AEP, SU, COHR, TRP, BTI, ENB, NKE, ITUB, EBAY, VALE — also appear under newlyA), meaning the two methods are picking substantially different names, not just re-timing the same ones. This is an observation for a human to weigh when requesting the fuller backtest — it is not evidence for the parameter change above.