M9d Round 2 — Fresh Triple Audit

3 новые личности × обновлённая M9d (с апрелем) | Sharpe 8.48 · PnL $182K · N=32,227 · 2026-04-19
Обновлённые числа M9d (апрель возвращён):
Sharpe raw
8.48
Sharpe conservative
6.83
Linear PnL 3.3y
$182K
WR (LONG / SHORT)
67.1% / 54.3%
Kurtosis
6.71
CVaR 99%
-$923
Max losing streak
6 days
Autocorr lag-1
0.122
Trades / day
41
1. Bayesian Statistician
2. Portfolio Manager
3. ML Production Engineer
Synthesis
Σ
Dr. Raj Venkatesan
Bayesian statistician, PhD Stanford, 10 лет в robo-advisor risk
"Classical p-values говорят 'не отвергаем null'. Я хочу знать вероятность что стратегия РЕАЛЬНО работает после того как я увидел эти данные."

CRITICAL #1: Prior предсказывает Sharpe 8.48 = почти невозможно

Возьмём informed prior: Sharpe distribution retail intraday strategies.

Prior (log-normal based on hedge fund survey + academic lit):
  P(true Sharpe > 1) = 30%   (decent strategy)
  P(true Sharpe > 2) = 8%    (good)
  P(true Sharpe > 4) = 0.5%  (excellent, Medallion tier)
  P(true Sharpe > 6) = 0.01% (physically implausible without HFT)
  P(true Sharpe > 8) = 10^-6 (lottery ticket)

Likelihood: sharpe_hat=8.48, N=736 days
  SE(sharpe_hat) ≈ sqrt((1 + 8.48^2/2) / 736) ≈ 0.24

Posterior (Bayesian update):
  P(true Sharpe > 4 | data) ≈ 65%
  P(true Sharpe > 6 | data) ≈ 15%
  P(true Sharpe > 7 | data) ≈ 3%

  Expected posterior Sharpe ≈ 3.8 - 4.5

Наблюдаемый 8.48 настолько экстремален, что prior тянет posterior ВНИЗ сильно. Это называется Bayesian shrinkage.

Вывод: С вероятностью ~65% реальный Sharpe > 4 (ещё отлично). С вероятностью < 3% он > 7. Планируй жить с Sharpe 3-5, не 8.

CRITICAL #2: Kurtosis 6.71 = fat tails не учтены в Sharpe

Kurtosis normal = 3. Наблюдаемый = 6.71 → tail risk в 2.2x выше normal.

Sharpe ratio предполагает нормальное распределение. При k=6.71:

EventNormal (Sharpe 8.48)Adjusted (k=6.71)
Day loss > 2σ2.3% дней~4.5% дней
Day loss > 4σ0.003% дней~0.8% дней (1 в 125)
Year max DD estimate-$3K-$8K to -$15K

Наблюдаемый max_losing_streak = 6 дней. При true Sharpe 8.48 вероятность такой полосы ≈ 0.5^6 × days ≈ 1 шанс из 1000. Наблюдаемый = 1 за 736 дней → consistent с true Sharpe ~2-3, не 8.

HIGH #3: Multiple Comparisons — M1..M9d = 10 моделей

В файле моделей: M1, M2, M3, M4, M5, M6, M7, M8, M9, M9d. Каждая "улучшала" предыдущую.

Family-wise error rate (FWER):
  10 моделей × тестируем на тех же данных
  P(at least one false positive) = 1 - (1-0.05)^10 = 40%

Даже с Bonferroni:
  p_adjusted = 0.05 / 10 = 0.005
  Но при Sharpe 8.48 с SE 0.24 → z-score = 35 → still significant

Статистически M9d переживает коррекцию Бонферрони. Но selection bias реален: вы выбрали M9d потому что она победила. Из 10 вариантов хотя бы один случайно выиграет.

Тест: сгенерируй 10 синтетических "моделей" из random rules, запусти на тех же данных. Если best-of-10 Sharpe > 5 → selection bias = real.

MEDIUM #4: PEAD weights = single snapshot на TRAIN

В scoring_v4_oos.py PEAD и ticker biases computed ONCE на весь TRAIN (до 2024-12-31), потом применены как constants на TEST.

Это НЕ true expanding window. Реальная expanding window:

for date in sorted(test_dates):
    train_subset = all_data[data.date < date]
    biases = compute(train_subset)  # re-fit на каждой дате
    score_today = apply(biases, today_row)

Текущий подход = "frozen biases". Это OK если distribution stable, но каждый месяц без retrain = risk of stale bias.

LOW #5: Sharpe credible interval

Posterior distribution for true Sharpe (Bayesian with informed prior):

|
|
|

5% — median — 95% credible interval: 2.1 — 4.2 — 6.8

Best estimate true Sharpe = 4.2. Plan для worst-case: Sharpe 2.1 → $180/day становится $45/day.

📈
Sarah Chen
PM, $200M AUM intraday book, ex-Millennium
"Sharpe это одно, а Kelly fraction и correlation — другое. Ты можешь взорвать счёт с Sharpe 8 если плохо сайзишь."

CRITICAL #1: Sector Concentration = убьёт в Tech-panic day

41 trade/day, ~55% Tech names (NVDA, AMD, TSLA, SMCI, MSTR, COIN, PLTR и т.д.). Корреляция Tech names внутри дня ≈ 0.6-0.8.

SetupIndependent (assumption)Реальность (ρ=0.7)
41 trades × $1000 × ret std 1%Daily std = $64Daily std = $540
99% VaR day-$150-$1,250
3-sigma event-$192-$1,620

Sharpe 8.48 в бэктесте возможен только потому что Tech rally с 2023 был продолжительным. В Tech-drawdown (Q3 2022-style) 41 correlated LONG = single concentrated bet.

Fix: max 8 positions per sector/day, max 25% daily BP в одном секторе.

CRITICAL #2: Kelly Criterion — вы переразмерены

Фактические метрики: WR 61.2%, avg win ≈ +0.42%, avg loss ≈ -0.30% (rough estimate из PnL/N).

Kelly fraction per trade:
  p = 0.612, q = 0.388
  b = avg_win / avg_loss ≈ 1.40
  f* = (p*b - q) / b = (0.612*1.40 - 0.388) / 1.40 = 33.3% per trade

Но 41 trades/day × 33% = 1,365% BP → НЕВОЗМОЖНО

Реально: Full Kelly distributed:
  Per trade f = 33% / sqrt(41 trades) = 5.2%
  Per trade $ = 5.2% × $100K = $5,200

Текущее sizing A+ = $1,500 (1.5% BP)  →  Half-Kelly х 3 = Quarter-Kelly

Вывод: Вы недосайжены в 3-4 раза ПО KELLY. НО — Kelly на переоценённом Sharpe переоценивает sizing. С истинным Sharpe 4 правильный sizing близок к текущему. Не увеличивай sizing пока live Sharpe не подтверждён.

HIGH #3: Autocorrelation 0.122 = regime clustering

Positive autocorr → winning days группируются, losing тоже. Max streak 6 дней loss = реальная проблема для психики трейдера и для margin.

ScenarioLinear DD10x size DDCompound 3x DD
Max streak × avg loss-$2.4K-$24K-$72K
Psychological limit (retail)OKHardRuined

Sharpe 8.48 не защищает от 6-day streak. При scaling до $1M BP (4x sizes) → $24K DD нормально. При compound 3x → blow-up risk.

HIGH #4: SHORT WR 54.3% = edge marginal после costs

LONG WR 67.1%, SHORT WR 54.3%. Разница 12.8pp.

SHORT P&L = $39,874 / 15,248 trades = $2.61 per short trade
After 15bps slippage + locate fee $0.02/sh:
  avg SHORT trade cost ≈ $2-3
  Net SHORT edge ≈ $0 после realistic costs

LONG P&L = $132,514 / 16,979 = $7.80 per long trade
After 15bps:
  avg LONG cost ≈ $1.50
  Net LONG edge = $6.30

Action: рассмотри LONG-only вариант (как старый M6). Потеряешь diversification, но SHORT может быть value-destructive после realistic costs. Сделай A/B test: M9d-LongOnly vs M9d-Both.

MEDIUM #5: Risk budgeting по grades не оптимален

Текущий sizing:

GradeSizeImplied WRActual WR
A+$1,500 (1.5%)≥70%74%
A$1,000 (1.0%)65-70%65%
B+$500 (0.5%)55-60%56%

Ratio 3:2:1 (A+:A:B+). Kelly predicts оптимально ~4:2:1 (A+ больше, B+ меньше). Текущий B+ $500 почти не приносит edge после costs.

Альтернатива: A+ = $2,000, A = $1,000, B+ = $0 (skip). Или risk-parity: все equal по $1K риска.

🤖
Alex Kuznetsov
Senior ML Engineer, ex-Netflix Recommender, 8 лет production ML
"Я видел модели с AUC 0.95 которые ломаются в production. Backtest — это 20% задачи. Оставшиеся 80% — это pipeline, drift, monitoring."

CRITICAL #1: Training-Serving Skew — реальная проблема

Модель учится на TRAIN parquet с 222 columns, pre-computed факторами. В 9:28 live нужно вычислить те же 222 features за секунды.

Риски:

FeatureTrainServingSkew риск
SPY_gapEnd-of-day Datum snapshotReal-time 9:28 feedНизкий (простой)
rel_auctionComputed from 9:28-9:30 imbalanceNeed NASDAQ NOII feedВЫСОКИЙ
market_breadthPost-market countМало кто считает в 9:28ВЫСОКИЙ
stretch_925_pctPM aggregationНужен точно тот же алгоритмСредний
TTN tags (good_news etc)Enriched parquetTTN live API + composite logicВЫСОКИЙ

Если live feature value ≠ train value даже на 5% → scoring ошибается → grade drift → wrong trades.

Fix: Сохранить snapshot features в 9:28 live, через неделю сравнить с back-filled TRAIN version тех же дат. Mean diff > 0.1 σ → skew confirmed.

CRITICAL #2: Feature Leakage через data builder

В 01_data_builder.py:

# Line 432-434: gap_pct uses entry_930
gap_pct = (entry_930 - prev_close) / prev_close * 100

# Line 440: direction assigned from gap_pct
direction = "LONG" if gap_pct > 0 else "SHORT"

# Line 443: ret_dir uses direction
ret_dir = np.where(direction=="LONG", ret_955, -ret_955)

Если entry_930 = close of 9:30 bar → direction определяется по данным из 9:30:59. Но "decision time" в модели = 9:28. Вы не можете знать direction в 9:28 если direction = f(9:30 data).

Это — training leak. Training учится предсказывать ret_dir, но direction сам коррелирует с ret_955 (одни и те же данные). WR искусственно завышен.

Verify:

u = pd.read_parquet('universe_scored_v4.parquet')
# pm-based direction (legit)
u['dir_pm'] = np.where(u.pm_close > u.prev_close, 'LONG', 'SHORT')
mismatch = (u.direction != u.dir_pm).mean()
print(f'Direction mismatch PM vs entry: {mismatch:.1%}')
# Если > 3% → real impact on live performance

HIGH #3: Model Decay — нет retrain schedule

Модель frozen 2026-04-19. Market regime меняется. PEAD weights, factor weights, ticker biases — всё устаревает.

Типичные signs of decay:

Proposal:

Monthly retrain:
  - recompute factor weights on expanding TRAIN
  - recompute ticker biases
  - A/B test: new vs frozen на следующий месяц
  - deploy new IF: OOS Sharpe(new) > Sharpe(frozen) × 0.9
  - fallback: keep frozen, alert human

HIGH #4: No Monitoring Dashboard

Нет production observability. Нужны dashboards:

MetricAlert ThresholdAction
Daily P&L vs expected< -3σ for 3 daysPause trading
Win Rate rolling 20d< 55% (drops 6pp)Retrain trigger
Slippage (actual vs model)> 20bpsReview execution
Feature NaN rate> 5%Data pipeline alert
Scoring latency> 30 secInfra alert
Grade distribution driftKS test p<0.01Factor distribution changed

MEDIUM #5: Failure Modes не документированы

Что делать если:

Каждый из этих сценариев случается 1-2 раза в месяц. Без runbook каждый раз = ad-hoc decisions → inconsistent execution → sharpe decay.

LOW #6: Data Lineage unclear

universe_scored_v4.parquet имеет 224 columns. Какая column из какого source script? Нет lineage docs. При debug проблемы невозможно быстро найти источник.

Fix: Column provenance metadata в parquet (pandas meta).

Synthesis: консолидация 3 аудитов

Новые критические находки (не покрытые Round 1)

#FindingАудиторAction
1Posterior Sharpe 3-5 (shrinkage)BayesianPlan для Sharpe 4, не 8
2Kurtosis 6.71 → fat tails не в SharpeBayesianSortino + CVaR гораздо важнее
3Sector concentration = hidden riskPMMax 8 positions/sector/day
4SHORT edge ≈ 0 после costsPMA/B test LONG-only
5Training-serving skew рискMLLive feature snapshot + weekly compare
6Feature leakage через directionMLRecompute direction из pm_close
7Нет model decay monitoringMLMonthly retrain + A/B gate
8Failure modes не документированыMLRunbook для 6 сценариев

Приоритетный Action Plan

Week 1 (must)

  1. Verify direction mismatch (pm_close vs entry_930) — diagnostic
  2. Recompute direction из pm_close, rerun M9d
  3. Add realistic costs (15bps + locate) в build_m9d
  4. LONG-only A/B test vs current both-direction
  5. Sector concentration cap (max 8/sector/day)

Month 1 (should)

  1. Monthly retrain pipeline + A/B gate
  2. Live monitoring dashboard (6 metrics)
  3. Failure runbook (6 scenarios)
  4. Live feature snapshot для skew detection
  5. Permutation test (10 random models comparison)
  6. Compute actual Sortino ratio (better than Sharpe для fat tails)

Revised Expected Performance

Backtest M9dRound 1 correctionsRound 2 corrections
Sharpe raw8.483.0-5.03.0-4.5
Sortinon/an/a2.0-3.0 (fat tails)
Avg daily ($100K BP)$234$120-180$100-150
Annual return56%30-45%25-40%
Max 6-day DD realistic-$2.4K-$4K-$6-10K (fat tail)
Probability live Sharpe > 4Unknown50%35-50%

Bottom Line

M9d = viable production strategy, но с оговорками:

  1. Размер ожиданий: Sharpe 3-5, не 8. Returns 25-40% annual, не 56%.
  2. Sector diversification: обязательно лимиты иначе Tech-panic = blow-up.
  3. LONG-only вариант: вероятно better risk-adjusted чем both-direction.
  4. Infrastructure: monitoring + retrain + runbooks = 50% успеха в production.
  5. Paper trade 30 days до scaling. Compare live Sharpe vs backtest Sharpe → если live < 2 → halt.

Даже на worst-case (Sharpe 2, 25% annual) — эта стратегия всё ещё лучше 95% institutional funds. Не упусти возможность из-за перфекционизма, но и не переразмерься на иллюзии Sharpe 8.