Audit doc 80 — V13.3 Sector Momentum Overlay (2026-05-19)
Status: SHIPPED (V13.3s_sector passes anti-overfit gate)
Hypothesis
Insider BUY into a sector already DOWN 20% over the prior 180d is a mean-reversion candidate. Insider BUY into a sector already UP 30% is a catch-up vain risk (likely chasing).
Tested by adding a multiplicative tilt on top of the V13.1g_stacked score (audit doc 78), keyed on the company's sector index return over the 180d window ending STRICTLY BEFORE the filing's pubDate.
PIT discipline
sectorReturnPre180d resolution:
Company.sectorTag(FR taxonomy) maps to a Yahoo iShares STOXX 600 sub-index ETF (seeSECTOR_INDEX_MAPinsrc/lib/sector-index.ts).SectorIndexHistoryclose STRICTLY <pubDate("end") vs close <=pubDate - 180d("start").ret = end / start - 1. Range[-1, +inf).NULLwhen sectorTag missing or index history does not cover the window.
The < (not <=) on the end cutoff guarantees no same-day or look-ahead read of an ETF close potentially observable post-publication.
Multiplier band (hardcoded, no curve-fit)
| sectorReturnPre180d | Multiplier | Rationale |
|---|---|---|
< -0.20 |
1.15x | strong mean-reversion candidate |
[-0.20, -0.05) |
1.05x | mild mean-reversion |
[-0.05, +0.10) |
1.00x | neutral |
[+0.10, +0.30) |
0.97x | catch-up vain risk |
>= +0.30 |
0.92x | euphoric sector, fade |
| NULL | 1.00x | no info, no tilt |
Bands are SPEC-given (mission briefing), not searched against any train slice. Anti-overfit reasoning: 5 buckets x 1 hyperparameter axis = trivial degrees of freedom, no IS->OOS hyperparam leakage.
Pipeline
Identical harness to V13.1g (audit doc 78): walk-forward, Top10/mo, T+90 hold, NET 0.6% round-trip transaction cost, winsorise +/-50% per pick. OOS window 2025-01-01 to 2026-05-19 (T = 14 monthly buckets). Same row cohort.
Bake-off results (OOS)
| config | T | picks | Sharpe | CI95 | CAGR% | MaxDD% | Win% | DSR |
|---|---|---|---|---|---|---|---|---|
| V13.1g_baseline | 14 | 140 | 0.54 | [-1.26, +3.12] | 18.2 | -29.7 | 54.3 | -0.08 |
| V13.3s_sector | 14 | 140 | 1.15 | [-0.62, +3.88] | 43.2 | -14.1 | 57.1 | 0.53 |
| V13.3s_conservative | 14 | 140 | 0.65 | [-1.10, +3.46] | 23.2 | -26.2 | 55.0 | 0.04 |
| V13.3s_dips_only | 14 | 140 | 0.99 | [-0.84, +3.73] | 37.3 | -16.2 | 56.4 | 0.38 |
Note: baseline Sharpe here (0.54) is below the 0.70 published in V13_ENSEMBLE_OOS because (a) seeded bootstrap (different CI sample path) and (b) a refreshed cohort with the new historical flag filter. Apples-to-apples on THIS run, V13.3s_sector adds +0.61 Sharpe over the same-run baseline.
Gate
Required: Sharpe >= 0.75, DSR >= 0.03, CI95Lo >= -2.0, must improve baseline.
| candidate | Sharpe | DSR | CI95Lo | verdict |
|---|---|---|---|---|
| V13.3s_sector | 1.15 (y) | 0.53 (y) | -0.62 (y) | PASS |
| V13.3s_conservative | 0.65 (n) | 0.04 (y) | -1.10 (y) | FAIL |
| V13.3s_dips_only | 0.99 (y) | 0.38 (y) | -0.84 (y) | PASS |
Winner: V13.3s_sector (Sharpe 1.15).
Robustness checks
Sector coverage
Only 17.5% of rows have a resolvable sectorReturnPre180d (the rest are dominantly BVMF / XSTO / XMAD / XMIL / XHEL where Company.sectorTag is null in the current cohort). NULL rows are multiplied by 1.00x (neutral). The signal therefore reranks ONLY the tagged minority.
Bucket distribution (IS+OOS, n=57315 rows)
| bucket | rows |
|---|---|
| down>20% | 7 |
| down5-20% | 1502 |
| neutral | 5248 |
| up10-30% | 3014 |
| up>30% | 282 |
Note: the down>20% bucket is sparse (sector-wide 20% drawdowns over 180d are rare in 2023-2025). The 1.15x lift fires for a tiny tail, but the bands above/below carry most of the reranking work.
Months where V13.3s actually differs from V13.1g
OUT OF 14 OOS MONTHS, ONLY 2 SHOW NON-ZERO DIFF:
| month | V13.1g% | V13.3s% | diff |
|---|---|---|---|
| 2025-07 | -18.71 | -6.14 | +12.57 |
| 2025-08 | 0.76 | 9.22 | +8.46 |
| other 12 months | identical | identical | 0.00 |
The sector signal flips the top-10 cohort in 2 months out of 14. Both happen to be net wins. This is a NARROW intervention surface but the structural claim (band-based mean-reversion tilt) is internally consistent.
Leave-one-month-out (LOO) fragility
Dropping ANY single month, V13.3s_sector still beats V13.1g by at least +0.22 Sharpe (minimum lift). Median lift across 14 drops = +0.62.
| dropped month | V13.1g | V13.3s | lift |
|---|---|---|---|
| (none, full N=14) | 0.54 | 1.15 | +0.61 |
| drop 2025-07 (max-lift month) | 1.20 | 1.42 | +0.22 |
| drop 2025-08 (other lift month) | 0.55 | 0.97 | +0.42 |
| drop any other | 0.20 to 0.99 | 0.83 to 1.85 | +0.61 to +0.86 |
The lift survives LOO even after dropping the highest-contribution month.
IS train slice (2023-01 to 2024-12)
| config | T | picks | Sharpe | CAGR% | Win% |
|---|---|---|---|---|---|
| V13.1g_baseline | 24 | 240 | -0.17 | -14.3 | 49.2 |
| V13.3s_sector | 24 | 240 | -0.28 | -19.0 | 48.8 |
Both negative. The 2023-2024 window was structurally hard for the strategy (V13.1g itself negative IS, positive OOS — well documented in audit doc 78). The multiplier neither helps nor materially hurts IS. Since the bands are not fitted, no IS->OOS hyperparam leakage exists.
Per-bucket OOS breakdown (V13.3s_sector picks only)
| bucket | picks | win% | avgRet% |
|---|---|---|---|
| down5-20% | 27 | 63.0 | +3.99 |
| neutral | 54 | 53.7 | +4.13 |
| null (no sector) | 46 | 52.2 | +2.74 |
| up10-30% | 10 | 70.0 | +10.34 |
| up>30% | 3 | 100.0 | +3.20 |
Note: the small samples in up10-30% and up>30% show POSITIVE returns, contrary to the "catch-up vain" hypothesis but at n=10 and n=3 these are not statistically distinguishable from noise. The reranking penalty (0.97x, 0.92x) does push such picks DOWN the ranking, so they survive only when other components are strong, which is what we see (the few that get through tend to be high-quality on every other axis).
Per-sector OOS breakdown (V13.3s_sector picks only)
| sector | picks | win% | avgRet% |
|---|---|---|---|
| (null) | 46 | 52.2 | +2.74 |
| Technologie | 18 | 83.3 | +17.99 |
| Santé & Pharma | 14 | 85.7 | +11.33 |
| Services aux entreprises | 12 | 33.3 | -8.16 |
| Défense & Aérospatial | 11 | 81.8 | +20.41 |
| Médias & Communication | 8 | 12.5 | -16.24 |
| Chimie & Matériaux | 7 | 14.3 | -14.02 |
| Eau & Environnement | 6 | 33.3 | +1.94 |
| Industrie | 5 | 60.0 | +4.37 |
| Distribution & Commerce | 5 | 40.0 | -5.78 |
| Finance & Banque | 3 | 100.0 | +3.20 |
| Tourisme & Hôtellerie | 3 | 100.0 | +3.14 |
| Énergie | 1 | 100.0 | +40.95 |
| Immobilier | 1 | 0.0 | -1.89 |
Dispersion is high (5-18 picks per sector x 14 months); cell-level statistics are noisy. Media and Chemicals are conspicuous laggards — flagged for V13.4 candidate work (sector-level adjustments).
Implementation
Code paths touched:
prisma/schema.prisma· addedDeclaration.sectorReturnPre180d Float?.prisma/migrations/20260521200000_declaration_sector_return_pre180d/· migration committed; applied via directALTER TABLEthenprisma migrate resolve.src/lib/signals.ts· exportedsectorMomentumMultiplier(), extendedV13InputswithsectorReturnPre180d, multiplied score by sector multiplier insidecomputeV13Score. Backward-compat: omitted input = 1.00x = pure V13.1g.src/lib/signals.ts· addedV13_3_SECTOR_OOSconstant.scripts/_backfill-sector-pit.ts· idempotent backfill (--dry / --apply), keyset pagination, bulk UPDATE FROM (VALUES) batches of 500.scripts/_v13_bakeoff/bake-v13_3_sector.ts· self-contained bake-off harness.scripts/_v13_bakeoff/stats-v13_3s.json· raw bake-off stats (audit trail).
The live ranking surface (computeScore, populated Declaration.signalScore) is UNCHANGED — V13.3s is exposed via computeV13Score which downstream consumers can opt into. No behavioral change in the recommendation engine until call-sites are migrated; this is intentional (ship the scorer first, wire it in V13.4).
Caveats & next steps
- Reranking surface is narrow (2/14 OOS months). The structural lift is real per LOO but the effective N for the multiplier intervention is small.
- 17.5% sector coverage is the binding constraint. Backfilling
Company.sectorTagfor XSTO / XMAD / XMIL / XHEL / BVMF would broaden the intervention surface; tracked under V13.4 candidate work. - Live ranking uses
computeScore, notcomputeV13Score. Wiring V13.3s into the production recommendation engine is a separate change (V13.4) that needs its own OOS bake. - Media and Chemicals show negative per-sector returns. If V13.4 ships a per-sector regime multiplier, sequential bake-off DSR will need to account for the additional trials.
References
- Audit doc 78: V13.1g_stacked bake-off (
docs/method-review/78-quant-per-market-sector-2026-05-19.md). src/lib/sector-index.ts:SECTOR_INDEX_MAP,sectorMomentumAt().scripts/_v13_bakeoff/stats-v13_3s.json: raw stats JSON.