Skip to content

Latest commit

 

History

History
2608 lines (1785 loc) · 185 KB

File metadata and controls

2608 lines (1785 loc) · 185 KB

Архитектурные решения

Лог принятых решений. Каждая запись: дата, решение, причина, альтернативы.


2026-05-05 — v1.18.21: Inverse Funding Arbitrage в production (Phase D Variant K)

Контекст

После 30+ дней эмпирического тестирования всех стратегий через Bootstrap+DSR pipeline (Bailey & Lopez de Prado 2014) ни одна не прошла Deflated Sharpe Ratio с multiple testing correction. Сводная таблица результатов:

Стратегия Trades P(profit) DSR Status
B5 raw (replay-30d) 65 <50% 0%
B5 + R1/R3/R11 (calibrated) 24 ~70% 0% 🟡
Donchian D55 BTC bull 8 ~75% 5-12% 🟡 regime-dependent
Donchian multi-vote AND 0%
Liq Fade NO-SL <50% 0%
Funding Arb (positive, big-cap) 0 ❌ no setups
Pair Trading ETH/BTC 0%
Inverse Whale (fade pump) 0%
Vol-targeted sizing 0%
RSI-2 Connors 1h 0%
Inverse Funding Arb 80 86.9% 0% 🟡 BEST

Inverse funding arb на small-caps дал самый высокий P(profit) среди всех тестированных стратегий — но Bootstrap CI Sharpe [-0.08, +0.27] пересекает 0, и DSR=0% после Bonferroni correction. Решение: forward test 90 дней на $500 paper для финальной валидации.

Решение

Добавить четвёртую параллельную стратегию bot/funding_arb/ к существующим 3 (Phase B spot reversal, Phase B perp shorts, Trend-following). Полная изоляция — если стратегия провалится за 90 дней forward test, удаляется через DROP TABLE без последствий для остальных модулей.

Стратегия

LONG perpetual contracts на small-caps (INJ/JUP/WIF/TIA/SEI) когда funding rate ≤ -0.05% per 8h. Edge — funding income (shorts overcrowded → платят longs)

  • потенциальный short squeeze:
  • Entry: rate ≤ -0.0005 (-0.05% per 8h)
  • Exit: TP +5% / SL -3.5% / max_hold 7d / funding > -0.00005 (recovered)
  • Position: 30% × $500 = $150 на сделку, max 3 одновременно
  • Leverage: 1× (без плеча — edge от funding income, не плеча)
  • Hold: до 7 дней = 21 funding settlement events

Архитектура (полная изоляция)

bot/funding_arb/
├── __init__.py             # Pure logic re-exports (для unit-тестов)
├── inverse_strategy.py     # Pure logic (Decimal, immutable, без I/O)
├── funding_arb_risk_manager.py  # Validate entry, separate Redis namespace
├── funding_monitor.py      # Polling /fapi/v1/premiumIndex каждые 5 мин
├── funding_arb_trader.py   # Координатор signal→risk→executor
└── funding_arb_position_tracker.py  # Price exits + funding apply

alembic/versions/0004_trades_funding_arb_table.py:
- trades_funding_arb (с funding-specific полями)
- funding_payments (append-only audit, UNIQUE(trade_id, funding_time))
- funding_rates_live (TimescaleDB hypertable)

Изоляция через:

  • Отдельные Redis ключи: funding_arb:trading_deposit_usd, funding_arb:kill_switch, funding_arb:rate:{symbol}, funding_arb:funding_applied:{trade_id}:{YYYYMMDDHH}
  • Отдельная БД таблица (не мутирует trades/trades_perp/trades_trend)
  • Отдельный kill-switch (make funding-arb-kill-switch) — не выключает другие стратегии
  • TaskSupervisor: 19 → 22 задач (+3 funding_arb)
  • Default FUNDING_ARB_ENABLED=false через .env — явное opt-in

Альтернативы рассмотрены

A. Положить проект на полку (как рекомендовал статистический honest-reading)

  • За: ни одна стратегия не прошла DSR, научно правильно остановиться
  • Против: технически проект работает (3 стратегии в production), один marginally-positive результат стоит проверить out-of-sample

B. Hibernate mode + ждать накопления данных 3-6 месяцев

  • За: ноль риска, чистая статистика по существующим стратегиям
  • Против: 3-6 месяцев простоя, edge может вообще не проявиться у других стратегий

C. Live forward test на $50 micro deposit

  • За: реальные деньги — финальная валидация
  • Против: на $50 funding income $0.0075/cycle vs fees $0.012 — signal-to-noise <1
  • Math: 80 trades × ~7 days = 560 days = 1.5 year на $50 — слишком долго

D. ✅ Forward test на $500 paper (выбрано)

  • За: signal-to-noise ratio 7.5× (фактический edge различим), worst case -$50 drawdown приемлем, $0 реальных потерь
  • Против: paper не моделирует execution risk полностью (slippage идеализирован в коде но мы добавили asymmetric slippage matched с backtest)

E. Live forward test на $1000

  • За: больший signal-to-noise, faster statistics
  • Против: edge статистически не подтверждён → агрессивно рисковать $100+ drawdown преждевременно

Размер $500 — обоснование math

Параметр $50 $500 $1000
Размер позиции $15 $150 $300
Funding income/cycle (8h) $0.0075 $0.075 $0.15
Funding за 4 дня (12 cycles) $0.09 $0.90 $1.80
Directional PnL ±5% TP/SL ±$0.75 ±$7.50 ±$15
Comission per trade (round trip 0.08%) $0.012 $0.12 $0.24
Signal-to-noise (income / fees) 0.6× 7.5× 15×

$500 — sweet spot: signal-to-noise > 7× гарантирует различимый сигнал, worst case -$50 drawdown приемлем для гипотезы которая статистически не подтверждена.

Race condition защита

Funding payments каждые 8h (00/08/16 UTC) — потенциальный race между FundingMonitor (пишет в кэш) и PositionTracker (применяет funding).

Решение:

  • Single-writer pattern: только PositionTracker мутирует trade.funding_income_usd. FundingMonitor пишет ТОЛЬКО в кэш Redis и funding_rates_live (read-only для других модулей).
  • Idempotency через UNIQUE(trade_id, funding_time) в funding_payments — при повторе через crash recovery DB вернёт IntegrityError, мы поймаем и skip.
  • Redis dedup: funding_arb:funding_applied:{trade_id}:{YYYYMMDDHH} — TTL 24h. Защищает от множественных вызовов в течение одного 8h-окна (если PositionTracker tick'нет дважды в течение 60s tolerance).

Stop conditions (90 дней forward test)

Сценарий Действие
✅ N≥30 trades И WR≥45% И Net>+$30 Upgrade $500 → $1000
✅ N≥50 trades И WR≥50% И Net>+$80 Upgrade $1000 → $3000
🟡 N<30 за 90 дней Продлить ещё 90 дней (рынок спокойный)
🟡 N≥30 И WR 40-44% Soft-disable, переписать threshold
❌ N≥30 И (WR<40% или Net<-$50) DROP TABLE + git revert
❌ MaxDD > 30% в любой момент Немедленный kill-switch + investigation

Метрики для оценки

  • Equity formula: start + Σ(closed.pnl_usd) + Σ(open.floating_direction_pnl) + Σ(open.funding_income_so_far)
  • Funding share of Net PnL: Σ(funding_income) / abs(Σ(net_pnl)) × 100% — показывает какая доля прибыли от funding vs price movement
  • Avg funding events per trade: total_funding_payments / trades — ожидаем 6-12 (avg hold 2-4 дня = 6-12 settlements)

Файлы

  • Production: bot/funding_arb/*.py (5 модулей, ~2200 строк)
  • БД: alembic/versions/0004_trades_funding_arb_table.py
  • Models: bot/database/models.py (+TradeFundingArb/FundingPayment/FundingRateLive)
  • Config: bot/config.py (+FUNDING_ARB_* константы)
  • Main: bot/main.py (+3 task регистрации)
  • Telegram: bot/notifications/telegram_notifier.py (+4 notify методов)
  • Dashboard: dashboard/app.py (+data fetchers + render_funding_arb)
  • Makefile: +7 funding-arb-* целей
  • Tests: tests/test_inverse_strategy.py (41), tests/test_funding_arb_risk_manager.py (23)

Главные lessons learned

  1. Bootstrap+DSR — обязательный quality gate для крипто-стратегий. После 13 failed экспериментов мы наконец-то имеем дисциплинированный способ оценить "это edge или data dredging".

  2. P(profit) > 85% != tradeable edge, но это необходимое условие. Если P(profit) < 50% — стратегия гарантированно loser. Если P > 85% но Sharpe CI пересекает 0 — нужен forward test для финализации.

  3. Полная изоляция модулей оплачивается. Spot/perp/trend не затронуты. Если funding arb провалится — DROP TABLE и git revert без последствий.

  4. Single-writer pattern + UNIQUE constraints — must-have для audit logs финансовых операций. Funding payments не могут дублироваться.

  5. Forward test на paper $500 — золотой middle ground между paper $50 (шум доминирует над сигналом) и live $1000 (реальные деньги без статистического подтверждения edge'а).


2026-05-03 (глубокая ночь) — Synthetic Control Test: data dredging confirmed

Контекст

После v1.18.2 deploy AI-review (Qwen 8.5, Grok 8.2, DeepSeek 8.0) единогласно указали на возможный data snooping bias в нашей meta-analysis methodology. Qwen предложил synthetic control test как scientific safeguard.

Что сделали

Запустили два negative control теста ($0.53 total):

Тест 1 — Shuffle (weak control):

  • Те же 65 reasonings, но outcomes shuffle между trades
  • Сохранили 47/18 loss/win ratio (потенциальный design bias)
  • Opus нашёл 7 patterns + 8 skip-rules

Тест 2 — Strict (truly random 50/50):

  • Те же reasonings, полностью random outcomes (TP +4.75% / SL -2.85%)
  • Distribution 28W/37L (random)
  • Opus нашёл 6 patterns + 8 rules

Результаты

75% pattern overlap между real и truly random data:

Pattern Real Strict (random 50/50)
"Кластеризация в bear"
"B5 weak wick <0.40%" ✅ (тот же threshold!)
"B3/B5 при regime<0.40 И BTC<EMA"
"B5 pair deep under EMA-200"

И diagnosis identical pattern во всех трёх:

"B3/reversal не требует trend-фильтров... в bear-режиме fakeouts"

Эта фраза появляется и в truly random outcomes. Opus генерирует diagnosis из reasoning text structure, не из outcome relationships.

Вердикт

🔴 FAIL — META-ANALYSIS = DATA DREDGING (confirmed)

Opus в truly random data находит 75% patterns что в real. Это значит Opus rationalizes на основе reasoning text, не находит causal relationships с outcomes.

Implications для проекта

❌ Что разрушено

  • Trust в Opus meta-analysis для future strategies
  • Confidence Opus как фильтр (Δ=0.01 plus rationalization)
  • B5 rules R7-R10 были fake patterns (правильно удалили в v1.18.2)

✅ Что НЕ разрушено

R1, R3, R11 остаются валидны через независимую validation:

  1. R1 (B3 в bear):

    • Theoretical basis (squeeze fakeout в downtrend — учебник 1980-х)
    • Per-rule impact +$437 на real outcomes (29 of 47 losses = 49% concentration)
    • Effect size слишком большой для шума
  2. R3 (alts при BTC weakness):

    • Extension of R1 logic
    • Per-rule impact +$404
    • Theoretical (alts beta amplification в bear)
  3. R11 (BTC ATR > 5%):

    • Common-sense catastrophic safety
    • Не основан на Opus reasoning
    • Activates rarely (catastrophic only)

Главный методологический урок

Per-rule impact analyzer на real outcomes — единственный trusted quality gate.

Reasoning Opus может звучать убедительно даже на полностью случайных данных. Не доверять Opus meta-analysis без validation через real numbers.

Что меняется в workflow

Future strategies workflow:

  1. Opus reasoning → только генерация гипотез
  2. Per-rule impact analyzer на real outcomes → mandatory quality gate
  3. Out-of-sample test через 30+ дней → final verification
  4. Только тогда — production deploy

Альтернативы рассмотрены

  • Признать что v1.18.2 = data dredging: отвергнуто — R1/R3/R11 имеют independent validation (theoretical + effect size + per-rule impact)
  • Откатить hard rules полностью: отвергнуто — мы бы вернулись к -$352/мес, знание о B3 в bear известно из academic literature
  • Не доверять никаким Opus rules без 6+ months validation: слишком жёстко, игнорирует theoretical support

Open questions

  1. Будет ли Opus в production с full context (news/macro/funding/Vision) также rationalize? Или там reasoning ground'ed в real signals?
  2. Достаточно ли theoretical + effect-size validation для future rules? Или нужен ещё один control mechanism?

2026-05-03 (поздняя ночь) — v1.18.2: финальные calibrated rules после real Opus validation

Контекст

После цепочки исследований за 1 день:

  1. Replay-30d с реальным Opus на 65 trades → -$352 catastrophic
  2. Meta-analysis Opus on Opus → 11 skip-rules
  3. Per-rule impact analyzer → 6 profit-positive, 4 negative
  4. v1.18.1 calibrated с R1+R3+R7-soft+R11
  5. Real Opus validation на всех 65 → подтвердил +$36 New Net PnL (improvement +$389)

После validation deep analysis показал что R7-soft (B5 deviation < -40%) на самом деле режет больше wins чем losses:

Count Sum
R7-soft skipped losses 3 -$45
R7-soft skipped wins 4 +$111
NET impact -$48

Конкретно: ARBUSDT при deviation -55.6% дал +$34 за 8 часов. DOTUSDT при -44% дал +$34. Это bear-rally rebounds — именно edge стратегии reversal.

Решение

Удалить R7-soft полностью. Оставить только:

  • R1_B3_BEAR (regime < 0.50)
  • R3_B3_ALT_BTC_DEEP (alt при BTC<-3%)
  • R11_BTC_CASCADE (BTC ATR > 5%)

B5 теперь без programmatic filter — только R11 (catastrophic).

Причина

  1. R7-soft net negative на validation data. Не теоретически, не "может быть" — на 65 реальных trades с реальным Opus. -$48 это много.

  2. Deep deviation НЕ значит "падающий нож". Реальные winners часто в этой зоне:

    • ARB -55.6% → +$34
    • DOT -44% → +$34
    • DOT -43.2% → +$35
  3. B5 winners плохо отличаются от losers по чисто-техническим данным (Δ confidence Opus = 0.01). Лучшая стратегия — дать Opus решать на event-by-event basis с полным production context (news/macro/funding/charts).

  4. Hard rules должны быть для ясных catastrophes, не для "кажется опасный сетап". Только R1 (B3 в bear, WR 14.7%) + R11 (extreme volatility) подходят под этот критерий.

Альтернативы рассмотрены

  • Оставить R7-soft на -40% — отвергнуто, slight net negative
  • Поднять до -60% — отвергнуто, на 65 trades не сработает (max был -55.6% и это win)
  • Удалить R11 — отвергнуто, R11 защищает от единственного реально катастрофического сценария (BTC flash dump)

Финальные числа

  • Original PnL за 30 дней: -$352.89
  • After v1.18.1 (с R7-soft): +$36.26 (improvement +$389)
  • After v1.18.2 (без R7-soft): +$84.36 (improvement +$437)
  • 41 → 34 hard rule skip (на 7 меньше)
  • Это означает 7 trades теперь идут в Opus вместо auto-skip → реальный Opus context

Production effect

В реальной торговле:

  • Hard rules применяются ДО Opus call (экономия на Claude)
  • B5 события → все идут в Opus (Vision API + news + macro + funding)
  • Бот за 30 дней ожидает ~30-40 reversal events:
    • ~50-60% auto-skipped по R1/R3/R11 (без Claude cost)
    • ~40-50% → реальный Opus с full production context

Risks

  • Если Opus в production тоже rubber-stamper → тогда все B5 trades идут как есть. WR 37.5% × R:R 1.96 = positive EV.
  • Если реальный production-context (news/macro) меняет картину → результат может быть лучше (мы тестировать не можем без months of paper).

Что не делается (и почему)

  • Не переключаемся на live $300 до 30+ paper trades (нужна реальная статистика)
  • Не убираем Opus полностью — он не вредит (rubber-stamps), и в production имеет полный context который replay не имел
  • Не добавляем дополнительные правила — overfitting на 65 trades рискованно

2026-05-03 (день) — v1.17: Donchian Trend-Following как третья параллельная стратегия

Контекст

После 14+ failed Phase D backtest экспериментов (scalp на 15m −98%, funding arb на big-cap не работает из-за биржевого cap, pair trading break-even, inverse whale break-even...) нашли первый clear positive edge: Donchian breakout на 1d. Прошёл 3 раунда validation:

  • Round 1 (parameter sweep): 4/6 параметров positive — robust pattern, не overfit на period=20
  • Round 2 (EMA-200 macro filter): 4/5 walk-forward окон positive (vs 4/5 без filter, но avg APR упал до +4.75%) — filter спасает −35% в bear-фазах через cut'ат entry до начала deep drawdown
  • Round 3 (multi-period voting + D55 walk-forward): D55 BTC + EMA-200 filter дал лучший risk-adjusted profile — Sharpe 5.20 на full period, +12.88% APR в walk-forward, MaxDD ≤ 30%

Решение

Внедрить D55 BTC + EMA-200 filter как третью параллельную стратегию в production к существующим Phase B (spot reversal на 4h) и Phase B (perp shorts на 4h).

Причина (зачем параллельно, не "слить")

  1. Edges академически некоррелированы: spot reversal — mean-reversion на 4h, perp shorts — mean-reversion на топах 4h, trend-following — momentum на 1d. Разные timeframes + разные логики = реальная portfolio diversification.

  2. Покрывают разные регимы: B5/B3 работают в bear/chop (capitulation candles), perp shorts — в distribution/topping, Donchian + EMA-200 — только в bull (filter активирует). Когда одна спит, другая работает.

  3. Время дешевле параллельного backfill: запускаем все три сразу, через 60 дней получаем 3 независимых датасета для решения "что keep / что drop".

Альтернативы рассмотрены

  • Опция B (cascade — Donchian как master filter для Phase B): отвергнута. B5 доказан в bear-режимах (+14.19% bear walk-forward), cascade убил бы edge.
  • Опция C (заменить одну из Phase B стратегий на Donchian): отвергнута. Phase B сама ещё не валидирована в paper, рано отказываться.
  • Опция D (положить ещё на полку до накопления Phase B статистики): отвергнута. Опытный долгий backtest с правильной academic basis (Fama 1970, Faber 2007, Antonacci 2014). Параллельный paper test снижает opportunity cost.

Архитектурные принципы

  1. Полная изоляция от Phase B: новый модуль bot/trend_following/ (5 файлов), новая модель TradeTrend (отдельная таблица), отдельные Redis keys (trend:trading_deposit_usd, trend:kill_switch), отдельные loss limits (−7/−15/−30%). Spot и perp инфраструктура НЕ затрагиваются.

  2. Без Claude в hot path: trend-following — детерминистический breakout, никаких LLM решений. Это категорически другое чем Phase B где Claude фильтрует. Plus: убирает один источник нестабильности — Claude API outage / cost spike не остановит trend.

  3. Автономный координатор: TrendTrader не реактивный (как spot/perp Trader которые читают bot_decisions), а проактивный — раз в день в 00:05-01:00 UTC проверяет signal через compute_donchian_signal. Дедуп через Redis ключ trend:last_check_date.

  4. Position size фиксированный: 60% депозита (не confidence-scaled как Phase B). Логика: 1d стратегия = 4-8 трейдов/год = редкие сигналы, можем позволить больший размер. На $600 paper это $360/сделку = разумная экспозиция.

  5. Без TP/SL по дизайну: trend-following exit только по signal change (close < 20-day low = Turtle exit). Это не баг, а feature — даём тренду развиться, не режем raid'ом на SL. Trailing logic уже встроен в Donchian (20-day low растёт когда цена растёт).

Реализация

  • bot/trend_following/donchian_strategy.py — pure logic (compute_donchian_signal/exit), копия scripts/backtest_trend_1d.py:compute_signal адаптированная под production (возвращает structured DonchianSignal)
  • bot/trend_following/trend_risk_manager.py — TrendRiskManager (+TrendRiskValidation), все REJECT-кейсы кроме confidence
  • bot/trend_following/trend_trader.py — автономный координатор с window check (00:05-01:00 UTC) + dedup по trend:last_check_date
  • bot/trend_following/trend_position_tracker.py — exit signal monitoring раз в час, kill-switch handler
  • bot/database/models.pyTradeTrend модель (без FK на BotDecision — намеренно для чистого rollback)
  • alembic/versions/0003_trades_trend_table.py — миграция
  • bot/main.py — TaskSupervisor 17 → 19 задач
  • bot/notifications/telegram_notifier.pynotify_trend_position_opened/closed с emoji 📈
  • dashboard/app.py — вкладка "📈 Trend" + sidebar секция
  • Makefile — 6 trend-related targets
  • tests/test_trend_following.py — 19 unit-тестов

Аллокация капитала на $2000 paper

  • 40% = $800 — Spot reversal (B5/B3 long на 4h via Phase B)
  • 30% = $600 — Perp shorts (B5_short/B3_short на 4h via Phase B demo)
  • 30% = $600 — Trend-following (D55 + EMA-200 на 1d, BTCUSDT)

Метрики успеха через 60 дней

  • 1-3 закрытые сделки в expected range (+/- 5pp от backtest предсказания) → keep
  • Если за 90 дней 0 сделок (нет breakout) — keep, ждём bull-фазы
  • Если за 180 дней WR <25% или MaxDD >40% — soft-disable через TREND_ENABLED=False

Риски

  1. Backtest proxy ≠ реальная торговля. Пока не знаем как D55 переведётся в paper.
  2. 1d таймфрейм медленный — статистика собирается долго (ожидаем 4-8 сделок/год на BTC). Через 30 дней может быть 0 сделок и это норма.
  3. MaxDD 30% — большой по сравнению со spot reversal (18-19%). $600 × 30% = $180 — допустимо для paper.

Что не сделано (намеренно)

  • Не расширили TREND_PAIRS за рамки BTCUSDT. Combined backtest (BTC+ETH) дал 4/5 окон positive (+12.25% APR), но менее robust на bear-окне 2022. ETH добавим если первая BTC-сделка пройдёт успешно.
  • Не сделали short-trend (есть в backtest шорты, но shorts на 1d на споте невозможны, на perp — Phase C).
  • Не интегрировали Donchian как master filter для Phase B (см. альтернативы — отвергнуто).

2026-05-03 (утро) — HOTFIX: NameError REVERSAL_EVENT_TYPES в event_analyzer.py

Контекст

После 2.5 дней работы Phase B (B1+B2+B3+B4+B5) ночью 3 мая в 02:00 UTC сработали первые 3 реальных reversal-триггера в production:

  • BNBUSDT B5_SHORT (event #8146, wick 0.18%)
  • ADAUSDT B5_SHORT (event #8147, wick 0.34%)
  • DOTUSDT B5_SHORT (event #8248, wick 0.32%)

Все 3 пришли в Telegram через notify_high_priority_event — событие в очереди для Opus. Но 0 decisions создалось, 0 perp-сделок открылось.

Расследование

Симптом: processed=true для всех 3 events, но bot_decisions для них пусто.

Лог-trace показал:

ERROR EventAnalyzer: ошибка анализа event #8146
File "/app/bot/agents/event_analyzer.py", line 1141, in _analyze_event
    and event.event_type in REVERSAL_EVENT_TYPES
NameError: name 'REVERSAL_EVENT_TYPES' is not defined

Корень бага

В v1.15 (1 мая) добавили Vision API код в _analyze_event:

if (
    self.settings.enable_vision_api
    and event.event_type in REVERSAL_EVENT_TYPES   # ← line 1141
    and event.symbol
):
    chart_png = await render_setup_chart(...)

Но REVERSAL_EVENT_TYPES определён в bot.trading.risk_manager и не импортирован в bot.agents.event_analyzer. NameError при первом же вызове на reversal-событии.

Почему баг проспал 2.5 дня

  1. Нет unit-теста на полный поток _analyze_event — есть только тесты _build_user_prompt и _should_call_opus
  2. С v1.15 до v1.16 B3 reversal-события не происходили:
    • B5/B3 long редкие в bear (нет резких пробитий BB_lower)
    • B5_short/B3_short детекторы появились только в v1.16 B3 (1 мая поздно вечером)
    • В период между B3 деплоем и сегодняшней ночью реальных setups не было
  3. Vision-код ни разу не выполнялся до 02:00 UTC 3 мая → NameError ни разу не triggered

Чего стоил баг

Симуляция через scripts/simulate_missed_events.py (одноразовый ad-hoc через docker exec):

  • Параметры: PERP_LEVERAGE=2×, margin 32.5% (50% × confidence 0.65), SL +2.5%, TP −5%
  • За 6 часов после открытия:
    • Все 3 пары пошли против short (fake breakouts на слабых wick'ах)
    • BNBUSDT: −0.11% (entry $616.22 → текущая $616.88)
    • ADAUSDT: −0.16% (entry $0.2481 → $0.2485)
    • DOTUSDT: −0.33% (entry $1.2070 → $1.2110)
    • Floating PnL: −$3.89 (−0.39%)
  • Expected value через 72h time_stop ≈ −$13 (учитывая 50% bull breakout / 35% squeeze continues / 15% bear move)

Парадокс: Opus с правильным reasoning скорее всего skip-нул бы 2-3 из 3 (слабые wick'и + BTC bullish 4h + RSI 57 далеко от oversold для contrarian short). То есть реально потерянных денег ≈ $0-10, но 3 события статистики ушли в /dev/null без записи в БД.

Фикс (commit 9b4db58)

  1. Импорт from bot.trading.risk_manager import REVERSAL_EVENT_TYPES в bot/agents/event_analyzer.py
  2. Регрессионные тесты tests/test_event_analyzer_prompt.py::TestSymbolImports:
    • test_module_imports_without_errors — re-import + hasattr check
    • test_reversal_event_types_contains_b5_b3_long_and_short — все 4 типа в frozenset
    • test_analyze_event_method_uses_imported_reversal_types — inspect.getsource + namespace check

Тестов: 423 → 426.

Lesson learned

Аналогичный баг был в v1.10 (NameError 'target' в funding-секции _build_user_prompt). После него я добавил TestBuildUserPrompt::test_full_context_does_not_crash. Этот тест покрывал _build_user_prompt, но не _analyze_event — где была новая дыра.

Правило: каждый раз когда добавляем module-level символ в код функции — нужен import-time check (либо линтер flake8/pyflakes, либо unit-тест с reload). Регрессионный тест должен проверять namespace на уровне модуля, а не только конкретные функции.

Альтернативы которые отклонили

  1. Дублировать REVERSAL_EVENT_TYPES в event_analyzer.py локально — отклонили, источник правды должен быть один (risk_manager). Дублирование = риск рассинхронизации при добавлении 5-го типа.
  2. Linter в CI (pyflakes/flake8) — следующий шаг, но требует CI настройки. На now достаточно регрессионного теста.
  3. Re-process 3 застрявших events через UPDATE events SET processed=false WHERE id IN (...) — отклонили, события 8h-старые, контекст рынка ушёл, Opus получит несвежий market_regime → риск ошибочного proceed.

Файлы изменены

  • bot/agents/event_analyzer.py (+1 import line, +5 lines docstring)
  • tests/test_event_analyzer_prompt.py (+56 строк, +3 теста, новый класс TestSymbolImports)
  • CLAUDE.md, docs/decisions.md

Метрика успеха

В следующие 24-72 часа должны увидеть:

  • Любой B5/B3 trigger создаёт bot_decisions запись (с confidence != NULL если Opus вызвался)
  • Если Opus возвращает proceed + side=shorttrades_perp запись
  • Если Opus возвращает skip → видно reasoning в БД (раньше было silent NameError)

2026-05-02 (утро) — v1.16 Phase B завершена: paper-perp на demo.binance.com (5 sub-фаз)

Контекст

После v1.15 (Vision API + News Clustering) встал вопрос: как ускорить сбор статистики и расширить edge? Phase A (comparative backtest spot vs perpetual futures на 1095 днях) показала жирные цифры:

Конфиг Net 3 года PF MaxDD
spot 1× (текущий) +179% 1.35 18%
perp 1× (long only) +89% 1.21 16%
perp 2× (long only) +654% 1.30 31%
shorts only (B5+B3) +153% 1.27 22%
combined long+short 2× +3146% 1.41 38%

Пользователь принял решение полностью реализовать paper-perp на demo.binance.com (виртуальные $5K USDT, EU-доступно через demo endpoint вместо geo-blocked testnet). Real money НИКОГДА до 2-3 месяцев успешного paper. Long-perp отложен до Phase C — пока в B4 только short-зеркала.

Архитектурное решение: параллельные подсистемы

Spot и perp работают независимо друг от друга:

  • Своя модель БД (Trade vs TradePerp)
  • Свои Redis ключи (trading:deposit_usd vs perp:trading_deposit_usd, bot:kill_switch vs perp:kill_switch)
  • Свои loss limits (-5/-15/-25 vs -7/-20/-35 — у perp выше из-за 2× volatility)
  • Свои Trader/Tracker (Trader+PositionTracker vs PerpTrader+PerpPositionTracker)
  • Свои API ключи (BINANCE_API_KEY vs BINANCE_FUTURES_API_KEY)

Spot vs perp разделение по side в decision: long → spot, short → perp.

Если Phase B провалится → DROP TABLE trades_perp + git revert. Spot бот продолжит работать без изменений. Это критично — вся Phase B построена как аддитивный слой над существующей spot-инфраструктурой.

5 sub-фаз — что сделано в каждой

Sub-phase B1 (фундамент): TradePerp модель (id, decision_id, symbol, side='long'|'short', mode='paper_testnet'|'live', entry/exit/qty/leverage/ margin/sl/tp/liquidation/funding_paid/status), Alembic миграция 0002, PerpRiskManager (10 проверок: side, leverage cap, margin/free_balance, per-symbol лимит, daily/weekly/monthly losses, kill_switch), PerpOrderExecutor (futures_create_order MARKET/STOP_MARKET/TAKE_PROFIT_MARKET с reduceOnly, set_leverage, emergency_close при ошибке SL/TP placement, демо-mode через монки-патч FUTURES_URL='https://demo-fapi.binance.com/fapi').

Sub-phase B2 (мониторинг): PerpPositionTracker (~640 строк) — 16-я задача под TaskSupervisor, polling каждые 30s. Проверяет: time_stop (72h), mark_price через futures_mark_price, liquidation warning (если |current-liq| < 10% от entry), funding payments каждые 8h (00:00/08:00/16:00 UTC) через futures_income_history(incomeType=FUNDING_FEE) — авторитетный источник от Binance. Trailing breakeven SL при +3%. Exit detection через futures_position_information (positionAmt=0 → закрыто). Loss limits с отдельным perp:kill_switch. PnL для short = (entry - exit) × qty (зеркально long). Funding хранится отдельно от pnl_usd.

Sub-phase B3 (детекторы): _check_upper_bb_rejection_4h (B5_short: high ≥ BB_upper И close < open) и _check_bb_squeeze_breakdown_4h (B3_short: squeeze + close < BB_lower + volume) в production event_detector.py. Backtest Phase A shorts only Net +153% за 3 года. DECISION_JSON_SCHEMA расширена полем side: enum [long, short]. SYSTEM_PROMPT переписан: 2 новых блока в секции REVERSAL с зеркальной семантикой (SL +2.5% выше entry для short, TP −5% ниже). Spot Trader защита: при side='short' skip с reason='spot_no_shorts' (был в B3, изменён в B4).

Sub-phase B4 (координатор): PerpTrader (~430 строк) — 17-я задача, зеркало spot Trader. SELECT bot_decisions WHERE final_decision='proceed' AND executed=False → парсим [PROPOSED]: side=short ... → skip if not short → check event_type ∈ PERP_SHORT_TRIGGERS → PerpRiskManager.validate_entry → PerpOrderExecutor.open_position на demo → INSERT TradePerp → notify_perp_position_opened → mark executed=True. Pending tracker через Redis для recovery при крашах. Spot Trader изменён: при side='short' ставит Redis flag decision:processed_by_spot:{id} (TTL 24h) + return, БЕЗ executed=True. PerpTrader подхватит executed=False decision. Race condition spot vs perp решён через side разделение.

Sub-phase B5 (дашборд): Streamlit вкладка "📐 Perp" с 4 секциями (Баланс/Открытые/Закрытые с метриками/Сравнение Spot vs Perp). Открытые позиции — карточки с floating PnL (правильный знак для short), liquidation distance (⚠️ <10%), funding paid, hold time. Sidebar расширен секцией "📐 Perp (demo)" с equity и open count. 5 новых data fetchers с TTL=10s. Try/except wrapping для graceful degradation при отсутствии ключей.

Что НЕ внедрено

  1. Long perp — отложен до Phase C. Сейчас perp только short. Это сознательное ограничение чтобы не пересекаться со spot (там уже long).
  2. Auto-recovery TradePerp в БД — при краше между open_position и INSERT мы шлём critical Telegram alert но НЕ восстанавливаем автоматически. Слишком рискованно без тщательного тестирования.
  3. Streamlit тесты — рендеринг тестировать сложно (нужен headless browser). Data fetchers покрыты implicitly через PerpRiskManager / PerpPositionTracker тесты.

Цифры

  • 17 параллельных задач под TaskSupervisor (15 spot + 2 perp)
  • 423+ unit-тестов (было 396 после v1.16 B3, +19 в B4 + 7 от B2 + B1)
  • Файлов добавлено: bot/database/models.py (+TradePerp), 0002 миграция, bot/trading/perp_.py (4 новых модуля), tests/test_perp_.py (3 файла)
  • Файлов изменено: bot/agents/event_analyzer.py (SYSTEM_PROMPT short
    • side в schema), bot/analysis/event_detector.py (+2 детектора), bot/trading/risk_manager.py (REVERSAL_EVENT_TYPES расширен), bot/main.py (+2 регистрации), bot/notifications/telegram_notifier.py (+4 perp методов), dashboard/app.py (+~270 строк), CLAUDE.md/rollback.md/ README.md/decisions.md/roadmap.md
  • 5 коммитов в Phase B (по одному на каждую sub-фазу) + 1 fix-коммит (test_event_detector_reversal_short B3 vs B4 механизм)

Метрика успеха

За 1-3 месяца наблюдения paper-perp:

  • WR ≥40% (proxy ~35%, Claude должен дать +5pp)
  • PF ≥1.2
  • MaxDD ≤25%
  • Avg funding cost / сделку ≤$1
  • 0 liquidation events (если хоть одна — проблема в risk management)
  • ≥10 закрытых сделок в первый месяц

Точка решения через 30 perp-сделок:

  • WR ≥45% → Phase B валидна, обсуждаем Phase C (live perp на $300-500 real)
  • WR 35-45% → переписать SYSTEM_PROMPT для shorts
  • WR <35% → отключить shorts через PERP_ALLOWED_SIDES=("long",)

Что задокументировано

  • CLAUDE.md — 5 changelog записей (по одной на sub-фазу) с детальным описанием каждой
  • docs/rollback.md — 5 секций отката (B1-B5) + полный откат Phase B
  • docs/roadmap.md — обновлён со статусом Phase B и метриками наблюдения
  • README.md — Архитектура, риск-лимиты, статус, 17 задач

Коммиты Phase B

Commit Sub-phase Что
c94fe69 B1 init Фундамент: TradePerp + PerpRiskManager + PerpOrderExecutor
466fb15 B1 fix Demo endpoint поддержка (testnet → demo.binance.com)
01a1738 B2 PerpPositionTracker + 4 perp telegram методов
4c78ee4 B3 B5_short/B3_short детекторы + side в JSON schema
d776702 B4 PerpTrader + spot delegate через Redis flag
598a22f B4 fix Регрессионный тест после изменения механизма spot
2f6bf17 B5 Dashboard tab 📐 Perp (sidebar + 4 секции)

2026-05-01 (вечер) — v1.15: Vision API для B5/B3 + News Clustering через embeddings

Контекст

После v1.14 (multi-position paper) приняли решение усилить edge стратегии через современные технологии. Phase 1: Vision, Phase 2: clustering, Phase 3 — multi-agent — отложен до 30+ paper-сделок (нужна выборка для измерения delta).

Phase 1 — Vision API (chart_renderer.py)

Новый модуль bot/agents/chart_renderer.py рендерит свечной график 4h × 50 баров с overlay BB + EMA через mplfinance → PNG bytes. На срабатывании B5/B3 reversal-сетапа Opus получает картинку через Vision API в дополнение к цифрам.

SYSTEM_PROMPT расширен секцией «📊 Анализ графика» с правилами что искать: длинный wick, BB-расширение/squeeze, контекст тренда, объём. Опровержение визуального и цифрового — Opus должен явно указать в reasoning.

Стоимость: ~$0.01/image × 3-5 reversal/неделя = ~$2/мес. Latency: +1.5-2 сек. Цель: +3-7pp WR через отсев "ловли ножа" (длинный wick без объёма = слабый сетап).

Phase 2 — News Clustering (news_clusterer.py)

Новый модуль bot/agents/news_clusterer.py с OpenAI text-embedding-3-small ($0.02/1M токенов). При создании news_raw считаем embedding текста, сравниваем с recent window последних 200 эмбеддингов в Redis (TTL 24h) через cosine similarity. При sim > 0.85 — скипаем без вызова Haiku (4 канала часто пишут одну новость → ×4 экономия).

Pass-through режим если нет OPENAI_API_KEY (graceful degradation). Цель: экономия $5-10/мес на Claude.

Изменения

  • bot/agents/claude_client.py расширен под Vision API (parameter images: list[bytes] для call/call_opus → формирует content blocks с base64 PNG)
  • event_analyzer._analyze_event рендерит chart для B5/B3 → передаёт в Opus
  • news_filter._filter_one проверяет дубликат до Haiku
  • Feature-флаги: ENABLE_VISION_API, ENABLE_NEWS_CLUSTERING, NEWS_CLUSTERING_THRESHOLD в .env
  • Защита: enable_vision_api=False или ошибка mplfinance/OpenAI → fallback на старый text-only флоу

Цифры

  • Тестов: 212 → 226+ (+5 chart_renderer + 14 news_clusterer)
  • Файлы: pyproject.toml (mplfinance, openai), bot/config.py, 2 новых модуля, 3 модифицированных, 2 файла тестов, .env.example

Метрика успеха

За 2 недели paper после деплоя:

  • WR (vision+clustering) ≥ WR (без них) + 3pp
  • duplicates_skipped ≥ 30% от news_raw
  • Vision-cost ≤ $5/мес

Если не достигнуто — отключаем feature-флагами без отката кода.


2026-04-29 (поздний вечер) — v1.13e: MIN_CONFIDENCE_FOR_TREND=0.75 + Telegram + ablation squeeze

Контекст

После walk-forward на 9 парах (предыдущая запись) увидели:

  • B5/B3 reversal — robust, +92%/+90% за 3 года
  • H0 trend — катастрофа, Σ −84% за 4 bull-окна

Решили сделать 3 production-улучшения одним блоком:

  1. Squeeze-фильтр для B5 (вытащить единственное проигрышное окно distribution)
  2. Дифференцированный confidence-floor (защититься от слабого trend)
  3. Расширенные Telegram-уведомления (видеть все важные сигналы в paper trading)

Fix 1 — Squeeze-фильтр для B5: ablation отвергнут ❌

Гипотеза: B5 в окне 2024-04→2024-10 (Net −0.42% на BTC+ETH прогоне) проигрывает потому что в distribution-периоде BB-полосы сжимаются. Если добавить условие «B5 НЕ срабатывает при bb_squeeze=True» — должны убрать ложные сигналы.

Метод: в scripts/backtest.py добавлен новый trigger lower_bb_reversal_no_squeeze (тот же B5 + проверка bb_squeeze=False). В walk_forward_epochs.py добавлена стратегия B5_no_squeeze для прямого сравнения с B5.

Результат на 9 парах × 3 года:

Эпоха B5 (текущий) B5_no_squeeze Δ
Bull avg +14.86% +16.01% +1.15pp ≈
Bear +14.19% +3.77% −10.42pp
Chop +1.78% +2.10% +0.32pp ≈
Σ за 3 года +75.42% +69.92% −5.50pp

Вывод: гипотеза опровергнута. Squeeze-фильтр режет +1pp в bull (мелочь), но теряет −10pp в bear. Причина: в bear-фазе BB сжимаются именно при капитуляции (медленное равномерное падение), B5 в squeeze ловит именно то, что нужно. Даже в проблемном окне 2024 H1: B5 −2.85% vs B5_no_squeeze −4.19% — фильтр тоже хуже там.

Решение: в production НЕ вносим. Backtest-код с lower_bb_reversal_no_squeeze оставлен для будущих экспериментов. Это полезный негативный результат — раньше думали что фильтр улучшит, теперь знаем точно что нет.

Fix 2 — Дифференцированный confidence-floor (TREND=0.75, REVERSAL=0.5) ✅

Проблема: MIN_CONFIDENCE_FOR_TRADE = 0.5 единый для всех событий. Walk-forward показал что trend в proxy = катастрофа (Σ −84%). Если Opus в production даёт trend с conf 0.55 — мы войдём в почти-точно-убыточную сделку.

Решение (commit 1940b25):

# bot/trading/risk_manager.py
MIN_CONFIDENCE_FOR_TRADE = Decimal("0.5")  # для reversal
MIN_CONFIDENCE_FOR_TREND = Decimal("0.75")  # для всего остального

REVERSAL_EVENT_TYPES = frozenset({
    "lower_bb_reversal_4h",
    "bb_squeeze_breakout_4h",
})

# В validate_entry:
is_reversal = event_type in REVERSAL_EVENT_TYPES
min_conf_floor = MIN_CONFIDENCE_FOR_TRADE if is_reversal else MIN_CONFIDENCE_FOR_TREND

event_type=None → fail-closed (применяем строгий trend-floor 0.75). Это безопаснее: если по какой-то причине event_type не передан, лучше пропустить сделку, чем войти с фантомным reversal.

Trader получает event_type через JOIN с Event:

event_type = await self._fetch_event_type(decision.triggered_by_event_id)
validation = await self.risk_manager.validate_entry(..., event_type=event_type)

SYSTEM_PROMPT обновлён — Opus теперь знает что для trend-сетапов должен быть conf ≥ 0.75 (с обоснованием через walk-forward цифры).

Регрессионные тесты (+4 в test_risk_manager.py):

  • test_validate_entry_rejects_trend_below_075
  • test_validate_entry_approves_trend_at_075
  • test_validate_entry_no_event_type_uses_trend_floor (fail-closed)
  • test_validate_entry_b3_uses_reversal_floor

Эффект в production:

  • Trend-сделки станут редкими — Opus должен быть очень уверен
  • Если Opus не даёт trend с 0.75+ ни разу за 2-4 недели → значит trend в принципе не работает в текущей фазе, оставляем только reversal
  • Reversal (B5/B3) продолжают работать как раньше с floor 0.5

Альтернативы которые отвергли:

  • Полное отключение trend в production — слишком радикально. Лучше дать Opus шанс вытянуть верх 25% сетапов, чем выкинуть всё. Если paper покажет что 0 trend-сделок за месяц — тогда отключим.
  • Floor 0.85 — слишком строго, может полностью убить trend-вход. 0.75 — компромисс между «строго» и «не блокировать совсем».

Fix 3 — Расширенные Telegram-уведомления ✅

Запрос: «нужны все важные уведомления — все решения и события high и выше».

Изменения (commit 524e5b8):

  1. notify_decision расширен:

    • Раньше: только proceed и abort
    • Теперь: все 4 типа (proceed/skip/wait/abort) если confidence is not None (Opus реально вызывался)
    • Auto-skipped без Opus (confidence=None) — продолжаем НЕ алертить (шум фильтров _should_call_opus)
    • В сообщение добавлен event_type
  2. Новый notify_high_priority_event — real-time алерты до Opus для приоритетных событий:

    • lower_bb_reversal_4h (B5) — все
    • bb_squeeze_breakout_4h (B3) — все
    • news_filtered — только high/critical impact
    • price_dump_1h — все (high)
    • rsi_oversold — все (high)
    • НЕ алертим: whale_buy_cluster (~22/день, флуд) и volume_spike (medium, шум)
  3. Подключение в event_detector._record_trigger — алертит все триггеры (метод notify_high_priority_event сам фильтрует).

  4. Дедуп: 5 мин для high_event на пару, 1 мин для decisions.

  5. Детали в сообщениях: wick % для B5, breakout % + volume ratio для B3, RSI value, news preview/impact.

Статус production

После v1.13e бот работает в самой консервативной конфигурации за всю историю проекта:

  • B5/B3 reversal — основной источник сделок (доказано)
  • Trend — только редкие очень-уверенные случаи (conf ≥ 0.75)
  • News medium impact в bear → skip
  • News high impact в bear → Opus
  • BTC stopper exempt для reversal
  • Все защитные слои активны
  • Telegram-алерты на все важные события

Готов к Этапу 7 (live $300) с очень высокой уверенностью.

Тестовая регрессия

Этап Tests
До v1.13e 172
После v1.13e 176 (+4 на confidence floor)
Все зелёные

2026-04-29 (вечер) — Walk-forward на 9 парах: B5 + B3 оба ROBUST, +90%/+92% за 3 года

Контекст

Утром того же дня walk-forward на 2 парах (BTC+ETH) показал что B5 робастный, B3 — partial (chop −2.92%, но всего 3 сделки). Главное ограничение — у альтов v1.11 (LINK/ADA/DOT/ATOM/ARB) было только 90 дней истории, на них walk-forward невозможен. Сделали backfill 5 альтов до 1095 дней (~5-8 минут на пару, всего ~30 минут) и повторили walk_forward_epochs на 9 парах.

Результат (730+ дней, 6 полных окон)

Окна детально:

Окно Эпоха H0 baseline B5 B3
2023-10 → 2024-04 bull (89%) 143 / 29% / −23.53% 80 / 34% / +13.52% 24 / 46% / +19.19%
2024-04 → 2024-10 bull (60%) 90 / 26% / −27.77% 94 / 31% / −0.42% 28 / 46% / +18.80%
2024-10 → 2025-04 bull (61%) 98 / 22% / −33.76% 95 / 43% / +41.50% 35 / 34% / +15.74%
2025-04 → 2025-10 bull (79%) 76 / 45% / +0.59% 66 / 42% / +21.49% 27 / 59% / +28.49%
2025-10 → 2026-04 bear (78%) 12 / 17% / −10.24% 81 / 38% / +14.19% 28 / 39% / +8.18%
2026-04-14 → 2026-04-29 chop (68%) 0 / 0% / 0.00% 4 / 50% / +1.78% 6 / 33% / +0.32%

(Окно 2023-04 → 2023-10 — no-data из-за <200 1d свечей в начале backfill.)

Агрегаты:

Эпоха окон H0 avg B5 avg B3 avg
🟢 Bull-dominant 4 −21.12% +19.02% (3/4) +20.55% (4/4)
🔴 Bear-dominant 1 −10.24% +14.19% +8.18%
🟡 Chop-dominant 1 n/a +1.78% +0.32%

Финальные суммы за 3 года в proxy без Claude:

  • B5: +92.06% Net (на $300 → $576)
  • B3: +90.40% Net (на $300 → $571)
  • B5 + B3 combined потенциал: +180% за 3 года = **+60% годовых** в proxy
  • H0 trend: −95% катастрофа

Главные наблюдения

1. Оба ROBUST. B5 положителен во всех 3 эпохах, B3 тоже (раньше был partial). Это закрывает главный риск что edge — bull-beta. Стратегии работают на разных рынках, разных парах, разных регимах.

2. Альты усилили B5/B3 в bear/bull драматически.

Стратегия / эпоха BTC+ETH (4 пары) 9 пар Прирост
B5 bull avg +13.50% +19.02% +5.52pp
B5 bear +3.36% +14.19% +10.83pp
B3 bull avg +3.37% +20.55% +17.18pp

Reasons:

  • В bear альты падают глубже → больше «капитуляционных» свечей с low ≤ BB_lower → больше successful B5
  • В bull альты дают много volatility expansion после squeeze → больше B3 setups с follow-through

3. Trend катастрофически плох на альтах. Σ за 4 bull-окна −84.47% (vs −66.89% на BTC+ETH). Альты в trend без Claude — мёртвая стратегия. Гипотеза «Claude поднимет WR на +30 пп» становится ещё менее реалистичной.

4. Единственный прокол B5 — окно 2024-04 → 2024-10 (Net −0.42%). Это период distribution после первого ETF-rally (BTC $60K → $73K → $54K → $66K). В широкой консолидации BB-полосы сжимаются, B5 даёт false positives. Кандидат на squeeze-фильтр: «B5 НЕ срабатывает если bb_squeeze=True». В этом же окне B3 даёт +18.80% — он сам отсеивает плохие squeeze (потому что требует именно squeeze + breakout).

5. B3 в этом проблемном окне вытягивает. B3 + B5 как combo получился бы устойчивее любого по отдельности. На текущей архитектуре они работают параллельно — оба в production.

Что меняется в плане

  • Этап 7 (live $300) готов с высокой уверенностью. Не нужен bull, не нужен Claude-edge для базовой работоспособности — B5/B3 в чистом proxy дают +60% годовых.
  • Backfill альтов до 1095 дней зафиксирован — это даёт реальное преимущество в production (бот теперь видит 9 пар × все паттерны)
  • 🎯 Кандидат на следующий фикс: squeeze-фильтр для B5 (попытка вытащить окно 2024 H1)
  • ⚠️ Trend стратегии нужно либо отключить, либо радикально ужесточить. −84.47% на 4 bull-окнах — это не «маржинально», это убыточный архетип. Кандидат на отключение или жёсткое ужесточение MIN_CONFIDENCE_FOR_TRADE до 0.85.

Ограничения

  • 1 окно на bear и chop эпохи — статистика не идеальна, но направление сильное (B5 +14% в bear vs H0 −10%)
  • Окно 2026-04-14 → 2026-04-29 — всего 14 дней, мало для эпохи
  • 1095 дней не покрывают 2022 crypto winter — для совсем строгого теста нужен 5-летний backfill (опционально, не блокирует live)

Альтернативы которые отвергли

  • 5-летний backfill сейчас — отвергли. 2022 winter был структурно другой рынок (pre-FTX-collapse, pre-ETF, pre-halving 2024). Усреднение мешает интерпретации. Лучше — paper trading на текущей структуре, потом 5-летний прогон отдельно.
  • Подгонка параметров B5/B3 на bull-окнах — отвергли (overfitting risk). Структура условий простая (low ≤ bb_lower + green; squeeze + breakout + volume), не трогаем.

Уроки

  1. Расширение пар × backfill = резкое улучшение статистики. Раньше думали что edge есть, но «кочка». 9 пар × 730 дней = твёрдый сигнал.
  2. Combo robust > soло robust для разных эпох. B5 проигрывает в distribution, B3 там вытягивает. Архитектурная диверсификация.
  3. Walk-forward по эпохам — обязательный стандарт. Один агрегат на 730 днях — недостаточно. Эпохальная стратификация раскрывает где edge real, где случайный.

2026-04-29 — Walk-forward по эпохам подтвердил: B5 ROBUST

Контекст

После v1.13d у нас были positive 730-дневные результаты для B5 (+68% Net) и B3 (+22.6%) в proxy без Claude. Но один прогон на одном агрегированном периоде не доказывает что edge не overfit. Главный риск: B5 мог быть bull-beta — стратегия которая «работает» только потому что период доминантно bullish (2023 H2 → 2025 H1). Если так, в bear-фазе B5 развалится.

Чтобы проверить, написал scripts/walk_forward_epochs.py (commit d27f037):

  • 6 окон × 180 дней на 3-летнем диапазоне (2023-04 → 2026-04)
  • Каждое окно классифицируется по доминирующему регими через regime_distribution_hours из metrics
  • Stratified-агрегаты: avg Net и positive ratio по эпохам отдельно
  • Финальный вердикт: ROBUST (положителен во всех эпохах) / PARTIAL / не работает

Backfill 1095 дней BTC+ETH (~50 000 свечей × 2 пары × 3 ТФ).

Результат

Окна (отсортированы хронологически):

Окно Эпоха H0 baseline B5 B3
2023-10 → 2024-04 bull (89%) 80 trades, −1.02% 37, +17.26% 10, +11.57%
2024-04 → 2024-10 bull (60%) 67, −26.39% 56, −1.81% 10, −0.90%
2024-10 → 2025-04 bull (62%) 78, −32.72% 47, +35.74% 9, +0.93%
2025-04 → 2025-10 bull (79%) 59, −6.76% 34, +2.81% 14, +1.89%
2025-10 → 2026-04 bear (78%) 5, −4.60% 51, +3.36% 15, +6.04%
2026-04-14 → 2026-04-29 chop (72%) 0, +0.00% 2, +2.67% 3, −2.92%

(Окно 2023-04 → 2023-10 — «no-data»: BTC 1d свечей < 200 в начале backfill, EMA-200 не считается. Не критично.)

Агрегаты по эпохам:

Эпоха Окон B5 avg Net B5 positive B3 avg Net H0 avg Net
🟢 bull-dominant 4 +13.50% 3/4 +3.37% −16.72%
🔴 bear-dominant 1 +3.36% 1/1 +6.04% −4.60%
🟡 chop-dominant 1 +2.67% 1/1 −2.92% n/a

Вердикт по робастности:

  • B5 lower_bb_reversal: ✅ ROBUST — положителен во всех 3 эпохах. Это не bull-beta, реальный технический паттерн.
  • B3 bb_squeeze_breakout: ⚠️ PARTIAL — положителен в bull/bear, отрицателен в chop (но всего 3 сделки в одном окне — статистический шум, не делаем выводов)
  • H0 baseline (trend): ❌ катастрофа — Σ за 4 bull-окна −66.89% Net. Per-pair фильтр + BTC stopper не вытягивают proxy без Claude.

Главные находки

1. B5 в bear-эпохе работает. В окне 2025-10 → 2026-04 (78% времени bear, после ATH BTC $122K → $77K):

  • B5: +3.36% Net на 51 сделке, WR 39%
  • H0: −4.60% Net на 5 сделках (из-за per-pair фильтра почти не торговал)
  • Δ = +8 процентных пунктов в одном окне в самой неблагоприятной фазе

Это именно то, ради чего v1.13c затевался. На эпохальном уровне подтверждено что reversal-стратегии — не просто запасной план для chop, а самостоятельный паттерн с positive edge в любых условиях.

2. Trend в proxy без Claude — мёртвая стратегия. Не «средняя», не «маржинальная» — −16.72% avg Net на bull-окне. Гипотеза «Claude добавит +10пп к WR и trend станет profitable» теперь выглядит крайне сомнительной — нужно +30-40пп, что нереалистично. Реальный план дальше:

  • Reversal-стратегии — основная ставка для live
  • Trend оставить только для случаев когда Opus видит очень сильный позитивный катализатор (например, новость + per-pair bull + confluence одновременно). Раннее ужесточение MIN_CONFIDENCE_FOR_TRADE = 0.7 для trend (не reversal) — кандидат на следующий фикс.

3. B5 единственный прокол — окно 2024 H1. B5 потерял −1.81% во втором bull-окне. Это период после первого ETF-ралли BTC до $73K, прошёл через distribution в 2024 Q3 ($50-65K). В этом окне volatility упала, BB-полосы сжались, lower BB reversal даёт ложные сигналы. Возможный фикс: добавить фильтр «B5 не срабатывает если BB squeeze активен» — потому что в squeeze BB_lower близко к BB_middle, и reversal там не работает (нет места для движения). Кандидат на проверку, но не блокер.

Что меняется в плане проекта

  • B5 готов к live с высокой уверенностью (3 эпохи validated, не требует bull-фазы)
  • Bull-фаза больше не блокер для перехода на Этап 7 — мы уже в bear, B5 в proxy положителен
  • Депозит $300 → ~$360-380/год в чистом proxy без Claude (Net B5 за 3 года ≈ +50% gross / 3 = +17%/год). С Claude должно быть лучше, но это уже в paper trading измерим.

Ограничения теста

  1. Только 2 пары (BTC+ETH). У нас 9 пар в production, но альты v1.11 (LINK/ADA/DOT/ATOM/ARB) — только 90 дней истории. Нужен backfill альтов до 730+ дней + повторить walk-forward на 9 парах. Тогда статистика реверсала вырастет 3-4x.

  2. Только 6 полных окон (один — no-data, один — 14 дней). Если backfill сделать 1825 дней (5 лет) — получим 10 окон с захватом 2022 crypto winter и 2021 параболического bull. Это даст ещё более строгий тест. Но 5 лет назад рынок был структурно другой (no-ETF, до halving 2024) — результат может быть менее применим.

  3. Без Claude — это proxy результат. Реальный production-сетап с Opus может вести себя иначе. Paper trading 2-4 недели даст delta vs proxy.

Альтернативы которые отвергли

  1. Прогнать всё сразу на 5 лет — отверг, потому что эпохи 2021-2022 структурно отличны от 2024-2026. Усреднение мешает интерпретации.

  2. Только walk-forward (без stratify по эпохам) — у нас уже был такой прогон в v1.13c (scripts/walk_forward_compare.py), он показал «83% positive окон» но не отвечал на ключевой вопрос «в каких именно эпохах». Stratified-анализ информативнее.

  3. Разделить эпохи по календарю (2023, 2024, 2025) — отверг как менее чистое: внутри одного года могут быть смены рынка (2024: bull → distribution → consolidation). Классификация по regime_distribution_hours отражает реальное состояние рынка в окне, не календарную метку.

Уроки

  1. Один агрегированный backtest = недостаточно для решения о live. Walk-forward с группировкой по эпохам — минимальный стандарт. До этого момента у нас было «B5 +68% за 730 дней, walk-forward 83% positive» — звучит хорошо, но не отвечало на «а что в bear?». Теперь отвечаем явно.

  2. «Bull-beta» — реальный риск для крипто-стратегий. Огромное число backtest'ов 2023-2025 положительные просто потому что был bull. B5 прошёл этот фильтр.

  3. Эпохальная стратификация автоматизируется через regime_distribution_hours. Не нужно вручную метить периоды — backtest сам считает регим в каждом баре, агрегат по часам даёт точную картину.


2026-04-28 (вечер) — v1.13d: Цепочка фиксов после v1.13c rollout

Контекст

После rollout v1.13c (B5/B3 в production) на дашборде увидели «Auto-skipped (без Opus) — регим bear, тип события news_filtered не приоритетный для этого регима». Это означало что Opus не вызывается несмотря на новый dormant fix. Ресерч выявил 5 проблем подряд которые без починки сделали бы 2-4 недели paper trading бесполезными.

Fix 1 — _should_call_opus блокировал B5/B3 в bear

Симптом: на дашборде SKIP с reasoning «Auto-skipped (без Opus)» при regime=bear, dormant_mode=(nil).

Причина: в bot/agents/event_analyzer.py:929 функция _should_call_opus имела старую логику v1.10:

# bear / unknown — не вызываем Opus вообще
return False

Это блокировало всё в bear, включая B5/B3 и high-impact news. То есть весь edge v1.13c (Net +67.6% / +22.6% в backtest) был де-факто отключён в production.

Решение (commit c5da159):

  • B5/B3 (lower_bb_reversal_4h, bb_squeeze_breakout_4h) — всегда зовут Opus в любом регими (REVERSAL set до проверки regime)
  • bear + news_filtered с impact=high → Opus (катализатор reversal)
  • bear + остальное → skip (volume/RSI/whale/dump в bear исторически работают плохо)
  • unknown → skip (там обычно dormant активен)

Регрессионные тесты: новый файл tests/test_event_analyzer_should_call_opus.py с 21 тестом. Главный — test_b5_lower_bb_reversal_always_calls_opus — итерируется по всем 4 регимам и проверяет что B5/B3 всегда возвращают True.

Fix 2 — Полный аудит на похожие пропуски

После найденного бага запустили Explore-агента с детальным заданием: найти все места где код фильтрует по regime или event_type, проверить совместимость с v1.13c. Результат:

Категория Статус
Регим-фильтры (event_analyzer, news_filter, dormant) ✅ OK после Fix 1
Event-типы (ANALYZABLE_EVENT_TYPES, EVENT_PRIORITY, DEDUP_TTL, TRIGGER_SEVERITY) ✅ B5/B3 везде есть
Position sizing для reversal ⚠️ Нюанс — см. Fix 4
BTC correlation stopper применяется к reversal ⚠️ Критично — см. Fix 3
NewsFilter (Haiku) фильтрация ✅ OK
Telegram notifier для B5/B3 ✅ OK через notify_decision

Других блокирующих багов не найдено. Это даёт уверенность что pipeline целостный.

Fix 3 — BTC stopper режет B5 без снижения риска

Гипотеза: B5 ловит low ≤ BB_lower на 4h. На альтах при дампе BTC цены тоже валятся → BB_lower пробивается → B5 срабатывает. Но в этот же момент BTC stopper активен (флаг bot:btc_dump_stopper_active TTL=4h) → SYSTEM_PROMPT инструктирует Opus skip. Результат: B5 в bear почти всегда блокируется.

Эксперимент: новый скрипт scripts/ablation_btc_stopper.py прогоняет B5 и B3 в двух режимах:

  • WITH_STOPPER: production-default (decide_reversal_proxy получает btc_dump_active=True)
  • NO_STOPPER: новый параметр disable_btc_stopper=True в BacktestEngine — не передавать stopper в decide-функции

Изменение в scripts/backtest.py: новый параметр disable_btc_stopper: bool = False в BacktestEngine.__init__. Когда True, в строке 1313 btc_dump_active_for_decide принудительно становится False (но btc_dump_stopper_hours всё равно считается для diagnostics).

Результат на 730 днях (commit b0af2a9):

Стратегия Mode Trades WR% Net% Gross% MaxDD%
B5 WITH_STOPPER 173 45.7 +68.00 +101.66 11.76
B5 NO_STOPPER 177 46.3 +79.98 +115.93 11.76
B3 WITH_STOPPER 64 37.5 +22.58 +32.81 4.14
B3 NO_STOPPER 64 37.5 +22.58 +32.81 4.14

Главные цифры:

  • B5 без stopper: +12% Net больше, MaxDD не вырос (0.00%)
  • StopH = 80h за 17 520h (0.46% времени активен)
  • B3 нейтрален — он редкий триггер, мало пересечений

Интерпретация: Stopper удалял прибыльные сделки (на это указывает что WR без stopper выше: 46.3% vs 45.7%). Это не trade-off «edge vs risk» — это чистая потеря edge без снижения риска. Stopper защищает trend, не reversal.

Решение (commit 9976f2f):

В bot/agents/event_analyzer.py SYSTEM_PROMPT секция REVERSAL переписана:

  • «Не требуй»: добавлено «BTC dump для reversal — это контр-аргумент, не stopper» с цифрой +12% Net без MaxDD
  • «Требуй»: вместо «нет дампа BTC» — «дамп не катастрофический (>−10%/4h)»
  • «Отдавай предпочтение reversal над trend»: добавлено «BTC stopper активен на стандартных порогах = именно тот момент»

В _build_user_prompt при активном btc_dump_stopper:

is_reversal = event.event_type in {"lower_bb_reversal_4h", "bb_squeeze_breakout_4h"}
if is_reversal:
    # текст с пояснением что это контр-трендовый сетап
else:
    # старый текст "Сильный сигнал к SKIP"

Альтернативный подход который отвергли: exempt в event_detector.py (не ставить Redis-флаг для reversal-событий). Проблема — флаг отражает состояние рынка, не зависит от типа триггера. Если ставить только для trend, race condition: кто первым пришёл (B5 vs trend), тот определяет активен ли stopper. Наш подход — флаг ставится всегда, decision-логика различает event_type — правильнее.

Регрессионные тесты (3 новых в tests/test_event_detector_reversal.py):

  • test_system_prompt_reversal_exempt_from_btc_stopper — должна быть фраза «контр-аргумент» + цифра 12% + катастрофический дамп
  • test_system_prompt_reversal_size_50_60 — секция параметров reversal содержит «50-60»
  • test_user_prompt_btc_stopper_oversees_reversal_event_type_build_user_prompt должен различать event_type

Fix 4 — Размер reversal противоречил реальности

Декларация в CLAUDE.md и SYSTEM_PROMPT: «position_size_pct: 30-40% для reversal».

Реальность после v1.12 Fix 2 (формула scaling = confidence): Opus указывает size=35%, RiskManager умножает на confidence=0.7 → final = 24.5%, а не 30-40%. То есть с момента v1.12 Fix 2 декларация и реальность разошлись.

Решение (commit 9976f2f, часть): SYSTEM_PROMPT инструктирует Opus указывать position_size_pct: 50-60 для reversal. После confidence-scaling (×0.65-0.75) финал = 33-45%, что и хотели изначально. CLAUDE.md разделы «⭐ Reversal-сетапы» и «Управление позицией» переписаны под новую формулу.

Альтернатива которую отвергли: убрать confidence-scaling для reversal. Это специальный кейс в коде, который усложняет систему ради consistency декларации. Проще обновить декларацию (и инструкцию Opus) — единственное место где Opus видит размер это SYSTEM_PROMPT, поэтому контракт сохраняется.

Fix 5 — Дашборд: гистограмма confidence + отключить auto-refresh

Идея от Qwen-ревью: «если медиана confidence стабильно <0.6 — промпт или контекст не работают». Раннее обнаружение проблемы качества Opus до того как накопится статистика по WR.

Решение (commit e06a37e):

  • На странице «Решения» — гистограмма confidence Opus (бины по 0.1)
  • Разделение trend vs reversal через JOIN BotDecision → Event для event_type
  • Auto-skipped (без confidence) исключены — гистограмма только для реальных Opus-решений
  • 4 метрики: всего, медиана общая, медиана trend, медиана reversal
  • Auto-refresh default 30s → 0. Постоянное обновление через meta-refresh ломало скролл и раскрытые expander'ы. Кнопка «🔄 Обновить сейчас» остаётся для ручного обновления.

Уроки

  1. Тесты на интеграцию важнее unit-тестов. У нас были unit-тесты на детекторы B5/B3 (5+5+3 sanity), но не было теста «после события B5 в bear, дойдёт ли это до Opus». Только e2e-сценарий выявил бы Fix 1 раньше, чем дашборд показал «Auto-skipped».

  2. Декларации в документации могут устаревать молча. Fix 4 — declaration «30-40% reversal» была верна до v1.12 Fix 2 (когда формула была floor + (1-floor)×conf), а после изменения формулы перестала. Регрессионные тесты на cross-document consistency тоже полезны.

  3. Эмпирическое сравнение лучше предположений. Когда обнаружили конфликт «BTC stopper vs reversal», первая интуиция — exempt-ить. Но без ablation мы бы не знали порядок эффекта (+1%? +30%?). Цифра +12% Net без роста MaxDD дала однозначный ответ. Скрипт ablation остаётся в репо для будущих экспериментов.

  4. Полный код-ресерч после крупного rollout — обязательно. Нашли Fix 1 (критичный) только потому что пользователь обратил внимание на одно решение на дашборде. Без этого баг жил бы 2-4 недели paper trading и обнаружили бы только по нулевой статистике reversal-сделок.

Тестовая регрессия

До После Прирост Файл
134 147 +13 v1.13c (test_event_detector_reversal)
147 168 +21 Fix 1 (test_event_analyzer_should_call_opus)
168 171 +3 Fix 3+4 (test_event_detector_reversal продолжение)
171 172 +1 прочее (фактический счёт после прогона на сервере)

Тестов: 147 → 172 (+25). Все зелёные.


2026-04-28 — v1.13c: Reversal-стратегии B5 и B3 в production

Контекст

После v1.13a (исключение XRP/AVAX) и v1.12 ext (BTC stopper) фундаментальная проблема осталась: backtest без Claude в proxy убыточен (Net −23% за 730 дней). Ablation показал что никакая комбинация фильтров не делает trend-стратегию положительной — EV на сделку = −0.27%. Текущая логика confluence_setup (2+ любых триггера) хуже простого volume_spike (WR 12.5% vs 37.4%).

Решили искать стратегии с положительным EV в proxy. Логика: если стратегия в чистом proxy убыточна, Claude должен «вытаскивать» её — это слишком тонкое улучшение для надёжного измерения. Если же стратегия в proxy уже положительная, Claude должен её улучшать, а не спасать. Это даёт измеримый baseline.

Эксперимент: 8 reversal/contrarian гипотез

Протестировали на 730 днях (2024-04-28 → 2026-04-28), 9 пар, реальные fees+slippage:

ID Стратегия Net WR Сделок
B1 RSI(2) extreme + MACD divergence −5.2% 38% 12
B2 Williams %R reversal +2.1% 40% 22
B3 bb_squeeze_breakout_4h +22.6% 48.2% 27
B4 Z-score reversal −8.5% 35% 15
B5 lower_bb_reversal_4h +67.6% 45.7% 105
B6 Mayer Multiple < 0.85 −3.0% 33% 9
B7 return_24h extremes +0.5% 42% 18
B8 Wick rejection +5.2% 41% 20
B9 Combo (B3+B5+B8) +44% 46% 152

Walk-forward (8 окон × 90 дней) для топ-3 (B5, B3, B9):

  • B5: 6 из 7 окон positive (83%), ни одно окно ниже −5%
  • B3: 5 из 6 окон positive (83%)
  • B9: 4 из 6 окон positive (66%)

83% positive окон для B5 и B3 — это уровень consistency которого мы ни разу не видели у trend-стратегий (там даже у baseline было максимум 60%).

Что внесено в production

1. Новые индикаторы (bot/analysis/indicators.py):

  • bb_width — относительная ширина BB полос ((upper - lower) / middle)
  • bb_squeeze — флаг True/False (текущий bb_width ≤ 25-перцентиль bb_width за последние 60 баров)
  • bb_width_p25_60 — порог для дебага
  • signals.bb_squeeze — флаг для Claude

2. Детекторы (bot/analysis/event_detector.py):

  • _check_lower_bb_reversal_4h(symbol) — B5: проверяет low ≤ bb_lower И close > open на последней закрытой 4h-свече
  • _check_bb_squeeze_breakout_4h(symbol) — B3: проверяет bb_squeeze=True И close > bb_upper И volume_ratio > 1.5 (или volume_ratio отсутствует — не блокируем)
  • Добавлены в DEDUP_TTL (4 часа = одна 4h-свеча) и TRIGGER_SEVERITY (high)
  • Создают events строки с event_type соответствующего trigger_type, raw_data содержит wick_below_bb_pct (B5) или breakout_pct (B3)

3. SYSTEM_PROMPT Opus (bot/agents/event_analyzer.py):

  • Большая новая секция ⭐ REVERSAL SETUPS (v1.13c) с явными правилами
  • Для reversal-сетапов НЕ требуется <пара> > EMA-200 1d — наоборот, мы ловим капитуляцию ниже
  • НЕ требуется bull-регим — работают в bear/chop
  • Размер 30-40% (меньше чем trend), hold 48-72h, conf 0.6-0.75
  • ANALYZABLE_EVENT_TYPES и EVENT_PRIORITY расширены новыми типами (priority=70)

4. Тесты (tests/test_event_detector_reversal.py, новый файл, 13 тестов):

  • 5 для B5: trigger при low+green, без trigger на red, без trigger когда low > BB_lower, без indicators, без bb_lower
  • 5 для B3: trigger при squeeze+breakout+volume, без squeeze, close ≤ bb_upper, volume_ratio < 1.5, volume_ratio=None passes
  • 3 sanity: TTL содержит новые типы, severity указано, SYSTEM_PROMPT содержит «REVERSAL SETUPS»

Тестов: 134 → 147 (+13 reversal).

5. Backtest engine (scripts/backtest.py):

  • Добавлен --reversal-mode флаг (отдельный pipeline для proxy reversal-логики)
  • decide_reversal_proxy() — другая логика чем decide_proxy (не требует bull, не требует above_ema_200)
  • Williams %R, RSI(2), Z-score, BB squeeze, Mayer Multiple, return_24h добавлены как индикаторы

Связанный фикс — dormant mode под reversal

Проблема: старый DormantController (v1.8) отключал NewsFilter+EventAnalyzer при regime ∈ ("bear", "unknown") >24h. Логика была: «trend-стратегия в bear бесполезна, экономим $7/мес». После v1.13c это убивает B5/B3 — они работают именно в bear (low BB touch чаще всего происходит при капитуляции).

Решение (bot/dormant_controller.py):

DORMANT_TRIGGER_REGIMES = ("unknown",)  # было ("bear", "unknown")
ACTIVE_REGIMES = ("bull", "chop", "bear")  # bear теперь active

Dormant остался только как защита от сломанного regime classifier (когда он не может посчитать score из-за отсутствия BTC 1d данных или ошибки в indicators-задаче). Telegram-алерт переписан под этот новый смысл — «BOT WENT DORMANT (regime=unknown)» с инструкцией проверить indicators-task и БД.

Trade-off:

  • ❌ Теряем экономию $7/мес Claude в bear (раньше dormant активировался ~5 мес/год при bear-фазах)
  • ✅ B5/B3 продолжают работать когда они нужны больше всего
  • ✅ Backtest на 730 днях показал что эти стратегии дают +67.6% и +22.6% Net именно в проблемных периодах

Экономия $7/мес < потенциальная прибыль reversal-стратегии — выбор очевиден.

Альтернативы которые отвергли

  1. Не вносить B5/B3 в production: protected подход «proxy без Claude убыточен, дальше ничего не делаем». Проблема — это блокирует проект на годы (ждать pure bull-фазы).

  2. B9 combo вместо B5+B3 отдельно: combo даёт меньше консистентности (66% vs 83% positive окон). Лучше держать B5 и B3 как отдельные сигналы — Opus сам поймёт когда их применять.

  3. Условный dormant (только при unknown ИЛИ bear+низкая_волатильность): слишком сложно. Простое правило unknown only достаточно.

  4. Поднять порог confidence для reversal до 0.8: это убьёт частоту срабатываний. Backtest показал что даже при средней confidence стратегия работает.

Ставка на paper trading

В paper trading будем измерять delta vs proxy backtest:

  • Если Claude улучшает WR с 45.7% (B5 proxy) до 50%+ — стратегия сильна, переходим к live
  • Если WR ровно как в proxy — Claude бесполезен, но стратегия положительная сама по себе (можно работать без Opus, экономить $7/мес)
  • Если WR падает ниже proxy — Claude активно мешает (теоретически возможно если он отвергает хорошие reversal-сетапы из-за «слишком рискованно»)

Это первый раз когда у нас есть позитивный baseline для сравнения качества Claude-фильтра. До v1.13c мы могли только надеяться что Opus вытянет убыточную стратегию.


2026-04-28 — v1.13a: Исключение XRP и AVAX (структурная убыточность)

См. секцию ниже «Per-pair фильтр + расширение до 11 пар (v1.11)» и v1.13 в CLAUDE.md changelog. Краткое резюме:

  • Backtest 730 дней: AVAX 0% WR за 8 сделок, XRP 25.9% WR за 27 сделок
  • Ablation: возврат этих пар в combo-стратегию ухудшал Net на −4.35% (самый значимый эффект из 4 ablation-вариантов)
  • Внесено: ALLOWED_PAIRS сужен с 11 до 9 (без XRPUSDT, AVAXUSDT)
  • Обновлены SYSTEM_PROMPT'ы Haiku и Opus, тесты test_smoke (+2 явные негативные проверки)
  • Не внесено: bull_only, time_stop 120h, R:R 1:1.5 — backtest показал что они хороши соло, но антагонистичны в combo, проваливаются в forward (combo проигрывал baseline в bull-окнах на −12.6%)

2026-04-22 — Выбор технологического стека

Решение: Python 3.12 + PostgreSQL 16 + TimescaleDB + Redis 7 + Docker.

Причины:

  • Python — у пользователя и на сервере уже стоит, богатая экосистема (pandas-ta, python-binance, telethon, anthropic SDK).
  • PostgreSQL + TimescaleDB — свечи это time-series, hypertable даёт автоматическое партиционирование и быстрые range-запросы.
  • Redis — кэш цен, очередь событий, флаги (kill-switch).
  • Docker — изоляция от системного PG/Redis на сервере (они заняты другими проектами).

Альтернативы:

  • Go/Rust — быстрее, но у пользователя нет опыта и AI на Python даёт более качественный код.
  • SQLite — проще, но нет time-series оптимизаций.
  • ClickHouse — мощнее для аналитики, но оверкилл для $50 депозита.

2026-04-22 — Нестандартные внешние порты (5433, 6380)

Решение: PostgreSQL снаружи на 5433, Redis на 6380.

Причина: на сервере пользователя системные PG/Redis на стандартных портах (5432, 6379) — их используют другие проекты. Нельзя их трогать. Docker-сеть изолирована, но хост-порты конфликтуют.

Внутри docker-compose сети сервисы общаются по именам (postgres:5432, redis:6379) — там конфликтов нет.


2026-04-22 — Риск-лимиты в коде, не в промпте

Решение: MAX_POSITION_SIZE_PCT, STOP_LOSS_PCT и прочее — жёсткие константы в bot/config.py. Claude их не видит в промпте и не может изменить.

Причина: из Alpha Arena ноября 2025 — LLM могут обходить "текстовые" правила, особенно под давлением убытков. Риск-лимит должен быть физическим барьером.


2026-04-22 — НЕ делаем еженедельную рефлексию Claude

Решение: не запрашиваем у Claude "проанализируй свои ошибки за неделю".

Причина: работа ATLAS (ACL 2026, NTUA) показала, что рефлексивное рассуждение не даёт систематического улучшения. Вместо этого — Adaptive-OPRO: эволюция промптов через отдельный LLM-оптимизатор с rolling window. Реализация на Этапе 8.


2026-04-22 — Каскад моделей: Haiku → Opus

Решение: первичная фильтрация — Haiku 4.5 (дешёвый), финальные решения — Opus 4.7.

Оценка расходов: ~$2/мес Haiku + ~$5/мес Opus = $7/мес. На депозит $50 это 14% в месяц расходов — проект заведомо убыточен на таком капитале, что честно отражено в CLAUDE.md. Это учебный полигон.


2026-04-26 — Whale Alert заменён на Binance aggTrade WebSocket

Решение: вместо платного Whale Alert API ($30+/мес) детектируем китовую активность через бесплатный Binance aggTrade WebSocket. Порог в USD задаётся через .env (WHALE_THRESHOLD_USD).

Причина: Whale Alert убил free tier за последний год. Покупать $30/мес на проект с $50 депозитом смысла нет.

Разница:

  • Whale Alert: on-chain переводы (cold→exchange и т.п.), задержка 30s+, $1M+ норма
  • Binance aggTrade: биржевые сделки, real-time, разбиваются на части → $100K-$500K порог уместнее

Калибровка: написан scripts/aggtrade_observer.py — собирает 2-минутный сэмпл и показывает распределение трейдов по объёму. На спокойном рынке (суббота 00:00 UTC) топ-1% сделок ≈ $15K, топ-0.5% ≈ $73K. Стартовый порог $100K.

Альтернатива: Twitter @WhaleAlertChannel в Telegram (бесплатный кусок) — добавлен в TELEGRAM_CHANNELS, дублирует on-chain сигналы.


2026-04-26 — Etherscan не используем

Решение: пропускаем интеграцию Etherscan API.

Причины:

  • BTC через него не виден (ETH-only)
  • ERC-20 whale transfers — задержка 12-30 сек, для свинга не критично
  • Whale Alert через Telegram уже даёт похожие on-chain сигналы

Если позже окажется нужен — добавим за час.


2026-04-26 — APScheduler отложен

Решение: периодические задачи (F&G, CoinGecko раз в час) реализованы через простой asyncio.sleep в собственных классах. APScheduler не подключаем.

Причина: для двух часовых задач APScheduler — over-engineering. Декларативный синтаксис и job-store оправдают себя на Этапе 3+ когда появятся индикаторы (каждые 5 мин), чистка БД (раз в неделю), бэктесты (раз в день) и т.п.


2026-04-26 — PYTHONPATH=/app + правильный порядок COPY в Dockerfile

Решение: PYTHONPATH=/app в docker-compose.yml, COPY до pip install в Dockerfile.

Причина: при первом деплое pip install -e . в Dockerfile запускался ДО COPY . ., поэтому пакет bot находился пустым. CLI-скрипты падали с ModuleNotFoundError: No module named 'bot'. PYTHONPATH чинит это на лету (без редеплоя), Dockerfile-фикс — для следующих сборок.


2026-04-26 — Volume mount для scripts/ и data/

Решение: ./scripts:/app/scripts и ./data:/app/data примонтированы как volumes.

Причина:

  • Новые скрипты в scripts/ сразу доступны без make build.
  • ./data/ хранит Telegram session-файл, который должен переживать рестарт контейнера.
  • Изначально только bot/ был замонтирован — это вызвало ошибку «backfill_data.py not found» при первом запуске.

2026-04-26 — Telegram session-авторизация: один раз вручную через CLI

Решение: scripts/telegram_login.py запускается интерактивно для получения SMS-кода. Сессия сохраняется в /app/data/cryptobot.session (через volume mount), *.session в gitignore.

Альтернатива: автоматический логин при каждом старте — отвергнут. Telegram отправляет SMS-код, ввод требует TTY, в фоне это не работает чисто.

Канал-набор стартовый: @binance_announcements (новые листинги — главный триггер из CLAUDE.md), @WhaleAlert (бесплатный кусок Whale Alert). Меняется через TELEGRAM_CHANNELS в .env без редеплоя.


2026-04-26 — RiskManager как единственный gateway перед сделкой

Решение: ни один trading модуль не идёт напрямую в OrderExecutor — только через RiskManager.validate_entry(). Если RiskManager сказал REJECT — никаких исключений.

Причина: из Alpha Arena (Nof1, 2025) — Claude может давить под прессом убытков и подсовывать "правильно звучащие" reasoning'и для нарушения правил. Барьер должен быть физический (Python-код), а не риторический (промпт). Все жёсткие лимиты живут в bot/config.py как константы, проверяются в RiskManager, и Claude их вообще не видит в своих промптах — значит не может попросить их изменить.

Stale-фильтр: решения Opus старше 10 минут не исполняются. Цены за это время уже ушли, сетап мог развалиться. Лучше пропустить чем войти в устаревшее.


2026-04-26 — OCO ордер как атомарная защита, force-close при сбое

Решение: live-mode открывает позицию двумя ордерами: (1) market BUY, (2) OCO SELL с TP+SL. Если OCO упал после market BUY — позиция остаётся открытая БЕЗ защиты. В таком случае немедленно закрываем market SELL'ом.

Альтернатива: одиночные SL и TP лимит-ордера. Отвергнут — нет атомарности, при срабатывании одного второй надо отменять руками, можно пропустить и удержать защиту неполной.

Trailing stop через replace OCO: при +3% отменяем текущий OCO и ставим новый с SL=entry (breakeven). На testnet это иногда замедляет, но логика прозрачнее чем расчёт через STOP_LOSS_LIMIT updates.


2026-04-26 — Paper-mode: симуляция через свечи, не через WebSocket-цены

Решение: в paper-mode цена для проверки SL/TP берётся из последней закрытой 1h-свечи (БД), а не live из WebSocket. Симуляция исполняется только когда бар закрылся.

Причина: даёт детерминируемую и воспроизводимую симуляцию. WebSocket-цены меняются непрерывно, можно случайно получить "проскальзывание" которое в реальной торговле не воспроизведётся. Закрытая 1h-свеча — это реальная high/low за последний час, по которой можно судить достоверно сработал ли SL/TP.

Минус: симуляция в paper отстаёт от реальности на ≤1 час. Это компромисс ради воспроизводимости тестов на исторических данных.


2026-04-26 — Telegram-нотификатор: graceful degradation + дедуп через Redis

Решение: TelegramNotifier — singleton (get_notifier()), используется из любого модуля через from bot.notifications.telegram_notifier import get_notifier. Если TELEGRAM_BOT_TOKEN или TELEGRAM_CHAT_ID пустые — методы молча skip'ают без ошибок.

Причина: алерты — вспомогательная функция. Бот должен работать даже если Telegram настроен криво. Все вызовы из других модулей обёрнуты в try/except чтобы упавший алерт не уронил основной поток.

Дедуп через Redis: TTL 10 минут на одинаковый event-key (например close:trade_id_42). Защита от спама когда тот же триггер сработает повторно из-за реконнекта или дублирующего поллинга.

Rate limit: asyncio.Lock + min 2 секунды между сообщениями. Telegram блокирует ботов которые превышают 30 сообщений/минуту.

HTML formatting: используем HTML-режим (не MarkdownV2) — он гибче, эмодзи рендерятся стабильнее, escape проще (<&lt;).


2026-04-26 — Streamlit dashboard как отдельный Docker-сервис

Решение: dashboard/app.py запускается отдельным контейнером cryptobot-dashboard через docker compose up dashboard. Использует тот же Dockerfile и базовый образ что бот, но другую command (streamlit run).

Альтернатива: Streamlit как дополнительная задача внутри основного процесса бота. Отвергнута — Streamlit держит свой web-server, не дружит с asyncio event-loop основного бота, может крашить весь процесс при ошибке.

Plus от отдельного контейнера:

  • Если dashboard упадёт — бот продолжит торговать
  • Можно остановить только dashboard для экономии памяти (make dashboard-stop)
  • Перезагрузка кода dashboard не требует рестарта бота
  • Изоляция деплоя: dashboard может использовать другие зависимости (plotly, etc.)

Trade-off: ~150 МБ дополнительной памяти. На 2 ГБ VPS терпимо, но если будут проблемы — можно отключать.

Plotly как зависимость: добавлен в pyproject.toml, поэтому пересобирается образ при make dashboard. Один раз ~3 минуты, потом кеш.


2026-04-26 — Trade #1 (синтетический): валидация всего pipeline за 15 секунд

Решение: scripts/test_paper_trade.py создаёт искусственное proceed-решение в БД, ждёт 15 секунд, проверяет что Trader → RiskManager → OrderExecutor отработали корректно.

Причина: на CHOP-режиме Opus месяцами может ничего не решать. Без принудительного теста невозможно проверить что новая trading-инфраструктура работает. Скрипт даёт valid signal end-to-end за 15 секунд вместо ожидания рынка.

Полезность: при изменении любого модуля trading (risk_manager, executor, tracker) — make test-paper мгновенно покажет сломалось ли что-то. Это интеграционный smoke-тест без необходимости поднимать тестовый рынок.

Trade #1 продолжает жить в БД как реальная paper-позиция. PositionTracker мониторит её и закроет либо по time stop (72ч), либо по SL/TP если цена выйдет за пределы. Это полезно — мы получим первый реальный закрытый Trade с алертом в Telegram, что валидирует и Notifier.


2026-04-26 — TaskSupervisor: auto-restart упавших async-задач

Решение: рефакторинг bot/main.py — теперь все 12 параллельных задач управляются через TaskSupervisor. При падении задачи с unhandled exception — автоматический рестарт с экспоненциальным бэкоффом (0, 5, 15, 30, 60, 120, 300 секунд), счётчик сбрасывается после 10 минут стабильной работы.

Причина: в peer-review Kimi справедливо указал — старая _check_task_alive только логировала падение, не перезапускала. Если WebSocket-задача упадёт ночью с unhandled exception, бот «частично работает» 12 часов до утра. Это критическая дыра для автономного бота.

Telegram-алерт при краше через TelegramNotifier с дедупом 10 минут — пользователь сразу видит проблему. Если задача стабильна 10+ минут после рестарта — счётчик ребутов сбрасывается, при будущих сбоях бэкофф будет малым.


2026-04-26 — External watchdog: dead man's switch через Redis

Решение: отдельный Docker-сервис cryptobot-watchdog (bot/watchdog.py). Бот пишет в Redis ключ bot:heartbeat (TTL 5 мин) каждый tick. Watchdog независимо проверяет этот ключ раз в минуту. Если устарел >5 мин или отсутствует → критический алерт в Telegram («БОТ МОЛЧИТ»), recovery-алерт когда heartbeat возобновится.

Альтернатива (отвергнута): heartbeat-watcher как ещё одна async-задача в основном процессе бота. Если основной процесс упал целиком (OOM, panic exit) — внутренний watcher тоже упал. Только внешний watchdog даёт настоящий dead man's switch.

Альтернатива 2 (отвергнута): cron job на хосте. Усложняет деплой (cron на сервере + Docker внутри = две системы для пользователя без программистского бэкграунда). Отдельный контейнер проще.

Дедуп алертов: флаг bot:watchdog:alerted (TTL 30 мин), чтобы не спамить одинаковыми сообщениями. Снимается при возврате heartbeat → recovery-алерт.


2026-04-26 — Cost cap для Claude API: hard block при превышении дневного бюджета

Решение: pre-flight проверка перед каждым client.messages.create(). Дневной бюджет: $1 для paper, $5 для live. При достижении — ClaudeBudgetExceededError, все вызовы блокируются до 00:00 UTC. Warning в Telegram при 80%.

Причина: страховка от runaway-сценария. Если в коде появится бесконечный цикл вызывающий Opus, или EventAnalyzer начнёт обрабатывать одно и то же событие повторно — за час можем сжечь $50+. Hard cap = физический предохранитель.

Дедуп алертов: warning отправляется один раз в день, blocked — один раз в день. Используем Redis-флаги с TTL 2 дня для надёжности.

Сброс счётчика: автоматический по дате (key с датой), TTL 7 дней — после полуночи UTC новый счётчик начинает с $0.


2026-04-26 — Unit-тесты для critical-path: RiskManager, OrderExecutor, PositionTracker

Решение: добавлено 40+ юнит-тестов с in-memory моками (FakeAsyncRedis, MockAsyncSession, AsyncMock для Binance). Покрытие:

  • RiskManager (16 тестов): kill-switch, whitelist пар, граничные SL/TP (-3%/-2%, +4%/+6%), все три лимита убытков (daily/weekly/monthly), мин/макс размер позиции, обрезка proposed > 50%
  • OrderExecutor (10 тестов): paper-mode записи, live market BUY → OCO SELL цепочка, критический сценарий — force-close при отказе OCO после успешного BUY, округление по precision пары
  • PositionTracker (12 тестов): time stop, paper SL/TP симуляция, trailing stop при +3%, kill-switch propagation, daily loss limit → автоматический kill-switch, PnL math с Decimal

Альтернатива (отвергнута): интеграционные тесты с реальной БД и Binance Testnet. Слишком медленно (CI 5+ минут), требуют ключей, нестабильны при API-сбоях. Юнит-тесты с моками: 40 тестов за 1-2 секунды, можно запускать после каждого изменения.

Trade-off: моки могут расходиться с реальным поведением Binance API. Но для critical-path (риск-логика, force-close) это приемлемо — поведение API детерминированное и хорошо документированное.


2026-04-26 — Общий Docker-образ для bot/dashboard/watchdog

Решение: один image crypto-event-bot:latest собирается сервисом bot, и переиспользуется dashboard и watchdog (depends_on: bot: condition: service_started). Раньше каждый сервис строил свой образ.

Причина: на 20 ГБ VPS первый запуск с тремя независимыми сборками (bot ~1.5 ГБ × 3 = 4.5 ГБ) приводил к no space left on device. Один общий образ занимает 1.5 ГБ — экономия 3 ГБ.

Код в трёх сервисах одинаковый — отличается только command:. У dashboard это streamlit, у watchdog — python -m bot.watchdog, у bot — python -m bot.main. Зависимости (pyproject.toml) одинаковые. Поэтому общий образ — это естественное решение, а не хак.


2026-04-26 — Чанкование backfill INSERT под лимит PostgreSQL bind-параметров

Решение: в bot/data_sources/binance_client.py:backfill() вставка идёт чанками по 2000 строк через цикл вместо одного pg_insert(...).values(candles).

Причина: PostgreSQL имеет жёсткий лимит 65535 bind-параметров на запрос (16-bit). У PriceCandle 8 столбцов в INSERT, значит за один запрос можно вставить максимум 65535/8 ≈ 8191 строк. На 1h × 365 дней = 8760 свечей backfill падал с ошибкой для всех 6 пар одновременно.

При days=90 (старый дефолт) было 2160 строк × 8 = 17 280 — влезало. После апгрейда на год истории — стало валиться.

Размер чанка 2000 выбран с большим запасом: 2000 × 8 = 16 000 параметров, безопасно для будущих расширений модели до 30+ полей.


2026-04-26 — Watchdog: startup grace period + видимый healthy-лог

Решение: в bot/watchdog.py добавлен grace period 120 секунд от старта watchdog — в это окно отсутствие heartbeat не считается ошибкой. Healthy-проверки логируются на INFO раз в 10 проверок (≈10 минут), вместо постоянного debug.

Причина 1 — grace period: gonкa старта контейнеров. Watchdog зависит от bot через depends_on: service_started, но service_started гарантирует только что контейнер запустился, а не что приложение успело записать первый heartbeat. На наблюдении: watchdog запустился в 13:36:16, bot записал heartbeat в 13:36:21 — 5 секунд расхождения, watchdog ловил false positive «БОТ МОЛЧИТ» и слал тревожный Telegram-алерт при каждом make restart.

Причина 2 — видимый INFO: до фикса healthy-проверки шли на logger.debug и при стандартном LOG_LEVEL=INFO watchdog выглядел молчащим (после первой строки 🐕 Watchdog запущен — тишина). Это маскировало настоящие проблемы с watchdog (например если сам watchdog завис). Теперь раз в 10 минут видно строку 🐕 Healthy | heartbeat age=Xs tick=#N checks=N alerts=0 — пульс самого watchdog.

Альтернатива (отвергнута): использовать depends_on: service_healthy для bot. Не работает — у bot service нет healthcheck в docker-compose.yml, добавление healthcheck требует команды внутри контейнера, и это создаёт циклическую зависимость с heartbeat-логикой.


2026-04-26 — Маунт tests/ и pyproject.toml в bot-контейнер

Решение: в docker-compose.yml для сервиса bot добавлены volumes ./tests:/app/tests и ./pyproject.toml:/app/pyproject.toml. Старый интеграционный скрипт scripts/test_claude.py переименован в scripts/check_claude_integration.py.

Причина: pytest с testpaths = ["tests"] в pyproject.toml не находил папку (она была только в Docker-образе через COPY ., но после volume-маунтов ./bot, ./scripts и пр. — /app/tests не маунтилась и оставалась только то что закопировано). Pytest fallback-режимом находил scripts/test_claude.py (старый ручной интеграционный скрипт без conftest), пытался его собрать, валился с fixture 'client' not found. Маунт исправляет это — теперь любые правки в tests/ сразу видны контейнеру без пересборки. Переименование script — defensive: убирает префикс test_, чтобы pytest точно его не подхватил.


2026-04-26 — Этап 6.7: backtest на 2 годах данных. Главный вердикт стратегии

Контекст: после Этапа 6.5 написали walk-forward backtest engine (scripts/backtest.py). Прогнали на 365 днях — получили 0 сделок (рынок все 365 дней был bear/chop). Расширили backfill до 730 дней — захватили реальную bull-фазу апреля-октября 2025 года. Прогнали walk-forward по 30-дневным окнам.

Главный результат: стратегия имеет edge ТОЛЬКО в bull-фазе

Окно Сделок Win Rate Return
Apr-May 2025 (bull) 20 50.0% +12.61%
May-Jun 2025 (bull) 11 27.3% −4.08%
Jun-Jul 2025 (bull) 10 70.0% +6.81% ✅✅
Jul-Aug 2025 (bull) 20 40.0% +5.89%
Aug-Sep 2025 (transition) 17 35.3% −5.63%
Sep-Oct 2025 (top) 11 9.1% −4.95%
Oct-Nov 2025 (decline) 2 0.0% −1.25%
Nov 2025-Apr 2026 (bear) 0 0%

Регим за 2 года: bull 38.2%, bear 39.2%, chop 22.6%

В bull-фазе изолированно (5 окон, 78 сделок):

  • Avg win rate: ~44%
  • Avg return: +3.1% / месяц
  • 4 из 5 окон позитивные

В целом за 365 дней (lenient mode, все режимы):

  • 129 сделок, WR 35.66%
  • Profit factor 0.976 (на грани)
  • Max drawdown 24.61%
  • Total return −2.06%

Что это означает

Стратегия работает как задумано (event-driven swing, только лонг). Её edge — buying weakness в восходящем тренде. В bear/chop она правильно простаивает. Это не баг — это специально спроектированная пассивность.

Главное ограничение: чистый PnL отрицательный из-за затрат на Claude API ($7/мес) когда бот в простое. На депозите $50 это математически убыточно даже в нормальные годы.

На депозите $300 — экономика работает только при dormant mode (отключение Claude в bear). Без него:

  • 4-5 bull-месяцев × +5% × $300 = +$60-75
  • 12 мес × $7 Claude = −$84
  • Net: −$10..−$20/год — на грани

С dormant mode + 3 улучшениями (см. ниже):

  • 4-5 bull-месяцев × $300 при WR 42-45% = +$80-100
  • 4-5 мес активный Claude = −$30
  • Net: +$50-80/год (16-26% годовых) — разумно

Решение пользователя

Депозит увеличен до $300. Live включается:

  1. Только после реализации 3 улучшений (ATR / confidence / dormant)
  2. Только когда регим перейдёт в bull (ждём, может 1-3 месяца)
  3. С kill-switch на drawdown 15%+

3 ключевых улучшения для повышения edge

1. ATR-based dynamic stops: SL/TP адаптируются к волатильности пары. Сейчас фиксированные −2.5% / +5% — на BTC это норм, на AVAX/SOL вылетает по шуму.

  • BTC: SL = entry − 1.5×ATR(14), TP = entry + 3×ATR(14) (≈ 1:2 R:R)
  • AVAX/SOL: SL = entry − 2.5×ATR(14), TP = entry + 4×ATR(14)
  • Ожидаемый эффект: WR 36% → 42-45%, drawdown 24% → 12-15%

2. Confidence-scaled position sizing: размер позиции 25-50% депозита в зависимости от уверенности Opus.

  • confidence 0.5 → 25% депозита
  • confidence 0.7 → 35% депозита
  • confidence 0.9+ → 50% депозита
  • Если confidence < 0.5 → skip
  • Эффект: меньше потери на низкокачественных сетапах

3. Dormant mode: автоматическое отключение NewsFilter и EventAnalyzer при bear/unknown >24h.

  • Heartbeat и regime classifier продолжают работать
  • При смене регима на chop/bull — auto-resume + Telegram-алерт
  • Экономия: $7 × 8 bear-месяцев = ~$56/год

Не делаем (анти-паттерны после backtest)

  1. НЕ ослабляем фильтры в chop — proxy-тест показал что lenient-стратегия маржинальна (PF 0.976). Confluence-only это правильно.
  2. НЕ добавляем шорты или плечо — Claude bias к лонгам, мы это используем как фичу.
  3. НЕ оптимизируем threshold регима под bull-фазу — это overfitting к одному периоду.
  4. НЕ переходим на live до bull-фазы — на bear-рынке стратегия не торгует, расходы съедят депозит впустую.

2026-04-26 — Этап 6.7+: ATR-стопы НЕ дали улучшения. Honest postmortem.

Контекст: после реализации ATR-based stops + confidence-sizing + dormant mode прогнали backtest на 730 днях walk-forward (25 окон по 30 дней). Ожидали улучшения по всем метрикам.

Реальные результаты vs ожидания

Метрика Ожидал Получили
Win rate 42-45% 35.39%
Profit factor 1.3-1.5 0.878
Max drawdown 12-15% 19.31%
Total return за 2 года +20% −12.34%

Что сработало частично:

  • Max drawdown улучшился с 24.61% (без улучшений) до 19.31% — confidence-sizing работает
  • Trailing-be exits удвоились (15 → 29) — защита прибыли работает
  • Avg win стал больше (3.42% → 3.84%) — TP работает шире

Что НЕ сработало:

  • ATR-multipliers слишком широкие на altcoins → avg loss вырос с −2.33% до −3.05%
  • TP-clamp на +12% обрезает крупные движения (R:R деградирует с 1:2 до 1:1.3)
  • В transitions (bull→chop) теряем больше из-за широких стопов

Walk-forward по типам окон

🌟 Чистый bull (Jun-Sep 2025):

  • 3 окна подряд: WR 70%, 33%, 85.7% → returns +5.30%, +6.70%, +7.94%
  • Сумма за 3 месяца bull: +19.94% ✅ — стратегия работает

💀 Transitions (bull→chop переходы):

  • Sep-Oct 2025: WR 8.3%, return −9.37%
  • Jan 2025: WR 18.2%, return −12.97%
  • Длинные стопы съедают прибыли bull-окон

💤 Dormant (bear/unknown, 11 окон): 0 сделок — правильно

Итоговый расчёт на $300 с улучшениями

  • Bull-окна (3-4/год): +$60-70
  • Transitions: −$40-50
  • Active мес × $7 Claude: −$21-28
  • Dormant мес × $0: $0
  • Net ≈ $0..−$10/год — на грани убытка

Решение

ATR-stops НЕ становятся дефолтом в production (хотя реализованы и тестируются). Опциональны через флаг --atr-stops для будущих экспериментов с более мягкими множителями.

Что остаётся как production:

  • ✅ Confidence-scaled position sizing — улучшил drawdown, безопаснее
  • ✅ Dormant mode — экономия на bear-периодах работает математически
  • ❌ ATR-stops — отложены, пока используем фиксированные −2.5%/+5%

Главный вывод: наша стратегия работает только в чистом bull-тренде. На transitions она теряет. Это фундаментальное ограничение long-only стратегии — не баг, а особенность дизайна.

Что делать с этим знанием

  1. НЕ переходить на live до начала чистого bull (max BTC > EMA-200 на 1d, удерживается ≥7 дней)
  2. Использовать dormant mode — экономит расходы во время не-bull
  3. Отслеживать regime transitions — после смены bull→chop первые 7 дней не торговать (доб. фильтр в будущем)
  4. Оставаться на $300 как и планировали — это баланс между «достаточно чтобы окупать расходы в bull» и «не больно потерять при ошибке»

Что потенциально улучшит edge (отложено)

  • ATR с меньшими multipliers (BTC 1.0x, AVAX 1.5x) и без TP-clamp до +12%
  • Regime transition filter — skip первые 7 дней после смены регима
  • On-chain signals (exchange reserves, MVRV) — для подтверждения bottom
  • Multi-agent ensemble (Opus + Sonnet консенсус) — для качественных сетапов

Это всё для Этапа 8 / после первого реального bull-периода.


2026-04-26 — Важный инсайт от пользователя: backtest НЕ показывает реальную работу бота

Контекст: после серии backtest'ов с разными метриками (ATR vs fixed, lenient vs strict, 365 vs 730 дней) пользователь поднял ключевой вопрос:

«после тестов прошлых когда мы были в минусе то бот не учитывал новости и прочие факторы на которые мы опираемся и в чем в принципе смысл всей логики бота»

Это совершенно справедливое замечание. Зафиксировать как решение и контекст для будущих сессий.

Что backtest реально проверял

Триггер (RSI/volume/dump)
  ↓
[НЕТ NewsFilter — нет исторических Telegram-данных]
[НЕТ EventAnalyzer — нет Claude]
  ↓
proxy_decide() — простое правило:
  if regime in (bull, chop) and rsi не overbought:
    return proceed
  ↓
RiskManager → SimulatedTrade

Что бот РЕАЛЬНО делает в production

Триггер (RSI/volume/dump/whale_buy_cluster/news_filtered)
  ↓
NewsFilter (Haiku) — 4 Telegram-канала, фильтр market impact
  ↓
EventAnalyzer (Opus 4.7 + adaptive thinking + effort=high)
  читает: индикаторы 3 ТФ + регим + киты + новости + F&G
  думает: «есть ли причины НЕ открывать лонг?»
  отвечает: proceed/skip/abort + reasoning + confidence
  ↓
RiskManager → OrderExecutor (реальная сделка с OCO на бирже)

Что это означает для интерпретации backtest

Минусовые backtest-результаты (особенно −14% в Sep-Oct 2025) = поведение БЕЗ качественного фильтра Claude. В реальности:

  • Sep-Oct 2025 был период коррекции после ATH $122K — Claude бы видел макро-новости и отсек большинство сетапов
  • Transitions (bull→chop переходы) — главное место где Claude должен помогать
  • Bull-окна где proxy дал +5-8%/мес — Claude не должен ухудшить, может улучшить

Как этот инсайт меняет наши решения

Backtest = floor (нижняя граница) качества стратегии. Не показатель реальности.

Production paper trading = реальный тест где Claude вживую принимает решения с реальными новостями, китами, sentiment'ом. Этого мы НЕ имеем в backtest.

2-4 недели наблюдения paper trading дадут:

  • Сколько раз Claude сказал "skip" в bull (фильтрация качества)
  • Сколько раз "proceed" с reasoning (мы это всё логируем в bot_decisions)
  • Какие сделки получились хорошими, какие плохими
  • Главное: измерим разницу между proxy backtest и реальным Claude

Конкретно

Если paper trading даст:

  • WR ≥ 50% (vs proxy backtest 40%) → Claude добавляет 10pp edge → стратегия точно плюсовая на bull
  • WR ~ 40% → Claude работает как «filter that doesn't filter» → нужен тюнинг промптов (Этап 8)
  • WR < 35% → стратегия плоха в принципе, идём в Этап 8 с фундаментальным пересмотром

Вывод

Не делать выводы о стратегии из backtest без Claude. Backtest валидировал что:

  • ✅ Технический скелет работает
  • ✅ Риск-менеджмент корректен
  • ✅ Регим-классификатор различает bull/chop/bear
  • ✅ ATR-стопы хуже фиксированных (на proxy-данных)

Что Claude реально делает — увидим только в paper trading.


2026-04-26 — Депозит увеличен с $50 до $300 (production-конфигурация)

Решение: дефолт депозита в RiskManager._get_current_deposit() и paper-balance в OrderExecutor.get_account_balance_usdt() изменены с $50.00 на $300.00. Соответствующие unit-тесты обновлены.

Причина: backtest показал что на $50 экономика проекта математически убыточна при любом реалистичном WR из-за фиксированных расходов на Claude API ($7/мес ≈ $84/год). На $300 экономика становится marginal в текущих рыночных условиях и phosphорная в bull-фазе.

Расчёты (на основе backtest 730 дней без Claude):

Сценарий $50 $300
Best окно (+8%) +$4 +$24
Worst окно (−14%) −$7 −$42
Расходы Claude/мес $7 (14% депозита) $7 (2.3% депозита)
Чистый PnL/год (текущий рынок) −$80 −$25 до +$50
Чистый PnL/год (чистый bull) +$10 +$60-90

На $300:

  • Худший случай не убивает депозит (−14% × max_position 50% = $21 потерь)
  • Расходы Claude становятся незаметным процентом
  • В bull-фазе доходность 20-30% годовых становится реалистичной

На $300 пользователь готов к риску потерять до $50 (≈17% депозита) на тестировании в первые 1-2 месяца live.


2026-04-26 — Распределение PnL по парам: не все ALLOWED_PAIRS равны

Контекст: добавили symbol_stats в backtest reporter. Прогнали 730 дней (lenient + ATR + confidence). Результаты по парам:

Пара Сделок Win Rate Avg PnL Вердикт
BNBUSDT 37 48.6% +0.61%
ETHUSDT 24 45.8% +0.73%
SOLUSDT 18 38.9% +1.90% ✅ редко но мощно
BTCUSDT 63 36.5% −0.26% ≈ break-even
AVAXUSDT 14 21.4% −1.65%
XRPUSDT 22 9.1% −2.52% ❌❌

Ключевые инсайты

1. BTC доминирует по частоте (63 сделки = 35%), но НЕ по прибыли. Слишком медленный, TP +5% редко достигается, SL часто на консолидации.

2. BNB и ETH — лучшие для нашей event-driven стратегии. WR выше 45%, avg PnL положительный. Это подтверждает что стратегия работает, просто не на всех парах одинаково.

3. XRP — катастрофически плохо работает. WR 9.1% — это случайность хуже бросания монеты. Возможные причины:

  • XRP сильно двигается на regulatory news (которых event detector не видит)
  • Высокая манипулятивность (тонкая ликвидность vs BTC)
  • Volume spikes на XRP в основном шум

4. AVAX слабо работает (WR 21.4%) — слишком волатильно для фиксированных стопов −2.5%.

Что НЕ меняем сейчас

ALLOWED_PAIRS остаются те же 6 пар. Причины:

  1. Backtest был без Claude (proxy decisions). Реальный Opus может отказывать на плохих XRP-сетапах через анализ новостей.
  2. Backtest был с lenient-chop (открывал в chop) и ATR-stops (которые тоже не помогли). Production strict mode может давать другую картину.
  3. Меняя ALLOWED_PAIRS до live — рискуем переоптимизировать под исторические данные (overfitting).

План на будущее

После 30+ live-сделок на $300:

  1. Прогнать симвoл-статистику на реальных данных
  2. Если XRP/AVAX продолжают терять — убрать из ALLOWED_PAIRS
  3. Заменить на LINK / DOGE / TON если хочется расширения

Принцип: данные → анализ → решение. Не наоборот.

Симуляция «если бы исключили XRP»

Если бы 22 убыточные XRP-сделки не существовали:

  • Total trades: 178 → 156
  • Total PnL: −$36 → −$36 + $19 (избегаем XRP-потерь) = −$17
  • Win rate: 35.96% → ~38%

Не game-changer, но улучшение. Если live подтвердит — убираем XRP первым.


2026-04-26 — Финальный backtest: strict mode (production-конфиг) НЕ лучше lenient

Контекст: после всех экспериментов прогнали walk-forward на 730 днях с production-конфигурацией: strict mode (как в Event Detector в bot/) + confidence-sizing, без ATR-stops, без lenient.

Результаты сравнения

Конфигурация Trades WR Avg return/окно +/- окон
ATR + confidence + lenient 178 35.4% −0.69% 5/8
Confidence-only + lenient 178 39.8% −0.07% 10/8
Strict + confidence (production!) ~150 33.9% −0.54% 7/6
Fixed stops + lenient 178 39.8% −0.09% 9/9

Удивительная находка

Strict mode оказался НЕ лучше lenient mode по PnL. Хотя по дизайну strict должен отсекать шум:

  • В chop пропускает только confluence_setup и rsi_oversold
  • В bear/unknown — ничего

Объяснение:

  • Confluence — редкое событие (190 за 2 года в lenient, ещё меньше уникальных в strict)
  • volume_spike сетапы которые отсеялись в strict — оказались на самом деле средне-качественными, не катастрофически плохими
  • Strict теряет редкие хорошие средне-качественные сетапы вместе с шумом

Лучшие/худшие strict-окна

🌟 Bull-фаза 2025 (Apr-Sep) — стратегия работает:

  • Apr-May: WR 38.9%, +5.11%
  • Jun-Jul: WR 85.7%, +7.19% (4 из 7 трейдов в плюс)
  • Aug-Sep: WR 54.5%, +2.39%

💀 Transitions — ужасны:

  • Jan-Feb 2025: WR 20%, −7.65%
  • Sep-Oct 2025: WR 5.9%, −10.27% (топ + начало decline)

💤 Bear (Nov 2025 - Apr 2026): 5 окон, 0 сделок — dormant работает.

Окончательное решение по strategy

Production-конфигурация остаётся как было:

  • Strict mode (_should_call_opus() в EventAnalyzer)
  • Fixed stops −2.5%/+5%
  • Confidence-scaled sizing 25-50%
  • Dormant mode при bear >24h
  • ATR-stops опциональны (не дефолт)

Не меняем strict → lenient по двум причинам:

  1. Разница в backtest минимальна (lenient −0.07% vs strict −0.54% за окно — статистически близко)
  2. Главное: в production есть Claude, которого нет в backtest. Claude может фильтровать качественнее любой rule-based проверки. Strict mode даёт Claude больше места для решения на confluence-сетапах (которые приоритетны).

Финальный вердикт по стратегии

Backtest без Claude = floor качества. Мы не можем измерить production-производительность без живого Claude. Дальнейшие выводы — только из paper trading с реальным Opus принимающим решения.

Технически проект готов к live на $300. Решающие критерии:

  • ✅ Регим перейдёт в bull (BTC > EMA-200 на 1d ≥7 дней)
  • ✅ Paper trading 2-4 недели подтвердит что Claude действительно фильтрует transitions

Backtest исчерпал свою полезность. Дальше — наблюдение.


2026-04-26 — БАГ: Telegram push-handler не работал. Фикс: переход на poll-режим

Контекст: проверяя что pipeline новостей работает, обнаружили что в БД 0 событий news_raw за 2.5+ часа работы. Логи 📨 TG heartbeat показывали получено: 0 | events: 0.

Диагностика

scripts/check_telegram.py (новый диагностический скрипт) показал что в каналах есть свежие сообщения:

  • cryptobosh: пост 1.7h назад
  • mozartcrypto: пост 1.7h назад

Но Telethon push-handler @client.on(events.NewMessage(chats=resolved_entities)) не срабатывал.

Гипотезы причин

  1. events.NewMessage(chats=...) для Telegram-каналов в Telethon работает нестабильно — зависит от формата chats (entity vs ID vs username) и версии библиотеки
  2. Возможно нужно использовать events.ChannelMessage специально для каналов
  3. Возможно race condition при регистрации handler

Не углублялись в root cause — переход на более надёжный механизм важнее.

Решение: poll-режим

Переписали _connect_and_listen с push на polling каждые 60 секунд:

# Было (push):
@self._client.on(events.NewMessage(chats=resolved_entities))
async def _handler(event): await self._handle_new_message(event)

# Стало (poll):
async for msg in self._client.iter_messages(entity, min_id=last_seen_id, limit=30):
    await self._save_message(msg, entity)

Дедуп через Redis: hash telegram:last_seen_msg_id хранит max msg_id для каждого канала. На каждом poll берём только сообщения с id > last_seen, потом обновляем last_seen.

Init last_seen на старте: при первом запуске берём id последнего сообщения как baseline (НЕ загружаем всю историю канала).

Подтверждение работы

После рестарта (тест: ручной сброс last_seen на 5 сообщений раньше):

📨 [cryptobosh] +5 новых сообщений
📨 TG heartbeat | каналов: 4 | polls: 31 | получено: 5 | events: 5

Полный pipeline заработал:

  1. 5 news_raw сохранены в БД
  2. NewsFilter (Haiku) обработал — 2 признал релевантными (bullish, BTCUSDT)
  3. EventAnalyzer (Opus) получил high-impact news, принял SKIP с confidence 0.72 (правильно для CHOP-режима)

Это первый момент в проекте когда полный pipeline новостей работает end-to-end.

Выводы

  • Push-handler Telethon ненадёжен для каналов — poll лучше
  • Poll-режим с правильным дедупом через Redis работает 100%
  • Дополнительный bonus: poll проще отлаживать (есть явный лог каждого цикла)
  • 60-секундная задержка приемлема для свинг-стратегии (не HFT)

Технически проект готов к 2-4 неделям наблюдения paper trading с полностью рабочим pipeline.


2026-04-26 — Расширение контекста для Opus: Funding rates + Macro

Триггер

Пользователь принёс 9 идей от Qwen AI о том как улучшить систему. Большинство — преждевременная оптимизация для системы где ещё нет ни одной живой сделки (ансамбль моделей, scale-out, корреляционный фильтр, ферма стратегий и т.д.).

После разбора только 2 идеи прошли фильтр "расширение контекста без слома работающего":

  • Funding rates с Binance Futures
  • Макро TradFi (DXY/US10Y/SPX)

Остальные либо требуют данных которых нет (нужны живые сделки), либо архитектурно избыточны (MAX_OPEN_POSITIONS=1 убивает корреляционный фильтр), либо опасны для философии проекта (шит-альты).

Решение 1: Funding rates как контекст, не как триггер

Реализовано: bot/data_sources/funding_rates.py. Раз в 15 минут опрашиваем https://fapi.binance.com/fapi/v1/premiumIndex для 6 пар, классифицируем как neutral/hot_long_bias/extreme_long_bias и наоборот для шортов, кешируем в Redis ключ funding:current.

Решение НЕ создавать events (не триггер): funding rate сам по себе не повод открывать сделку, но как фон для Opus — даёт сигнал перегретости деривативов. Если со временем увидим в логах что Opus полезно реагирует на extreme funding — добавим триггер funding_extreme. Сначала наблюдение, потом усложнение.

Пороги (эмпирические):

  • ±0.05% (0.0005) за 8h-период → hot bias
  • ±0.10% (0.001) → extreme bias
  • Между — neutral

При neutral эта секция в промпте Opus не несёт сигнала, но и не мешает — токены минимальные.

Решение 2: Макро через FRED, не Yahoo и не Stooq

Прошли через 3 источника за один вечер:

Попытка 1: Yahoo Finance v8 chart API

Логика: бесплатно, без ключей, годами стабильно. Тикеры DX-Y.NYB, ^TNX, ES=F.

Результат на сервере (VPS):

Macro: ES=F — оба endpoint'а упали: 429 Too Many Requests
Macro: DX-Y.NYB — 429
Macro: ^TNX — 429

3/3 запроса с обоих query1/query2 endpoint'ов получили 429 одновременно. Это постоянная блокировка IP-диапазона датацентра — Yahoo Finance давно агрессивно блокирует Hetzner/DigitalOcean/AWS/etc для предотвращения скрейпинга. Известная проблема, из-за неё в библиотеке yfinance идёт постоянная борьба с обходом блокировок.

Вердикт: ждать бесполезно, IP не разблочат. Нужен другой источник.

Попытка 2: Stooq.com CSV

Логика: польский финансовый сайт, бесплатно, без ключей, не блокирует датацентры (раньше работал годами в open-source проектах). Тикеры ^dxy, ^tnx, ^spx через endpoint /q/d/l/?s=...&d1=...&d2=...&i=d.

Результат: WebFetch вернул не CSV, а страницу с инструкцией:

1. Access the key page at /q/d/?s=^dxy&get_apikey
2. Complete CAPTCHA verification
3. Copy the CSV download link with <apikey>
4. Append &apikey=XXX to subsequent requests

Stooq в апреле 2026 ввели обязательный API key с captcha. Это новая политика, раньше работало без ключа. Получение ключа требует ручного действия (captcha) — для нашего use case это компромисс.

Финал: FRED API (Federal Reserve Economic Data)

Решение: переход на FRED.

Почему FRED:

  • Государственный источник (St. Louis Fed) — не банкротится, политика API стабильна десятилетиями
  • Бесплатно, лимиты практически неограниченные (тысячи запросов в минуту)
  • Регистрация ключа 5 минут: https://fredaccount.stlouisfed.org/apikey
  • Без captcha — обычная форма с email
  • Не блокирует датацентры (государственный источник публичных данных)

Минус: только daily-данные с задержкой ~1 рабочий день. Для часового опроса swing-стратегии (горизонт часы-дни) этого достаточно — мы не торгуем интрадей-макро.

Серии:

  • DGS10 — Market Yield on 10-Year Treasury Constant Maturity → us10y
  • DTWEXBGS — Nominal Broad U.S. Dollar Index → usd_idx
  • SP500 — S&P 500 closing price → spx

Подвох: DTWEXBGS ≠ ICE DXY

Облажался при выборе: классический ICE DXY (тот что котируется ~100-105 у трейдеров) — это коммерческий индекс ICE, на FRED его нет. Доступен только на Yahoo/Stooq/Bloomberg/etc, которые мы уже отбросили.

FRED DTWEXBGS — Trade Weighted U.S. Dollar Index: Broad Goods. База январь 2006 = 100. Шкала ~115-125. Это другая корзина — шире, включает CNY и развивающиеся рынки.

После запуска в логе:

📈 Macro | dxy=118.08(-0.24%) us10y=4.34(+0.93%) spx=7165.08(+0.80%)

dxy=118 бросалось в глаза и путало (ожидаемо ~100).

Фикс: переименование ключа dxyusd_idx в коде (Redis, market_context, промпт). В подсказке для Opus добавлено явное уточнение:

_Подсказка: USD-idx = Broad Trade-Weighted USD index (FRED, шкала ~118,
не классический ICE DXY ~100). Важна динамика: рост USD-idx и US10Y
= risk-off для крипты, рост SPX = общий риск-аппетит.
Данные daily, задержка ~1 рабочий день — для свинга норм._

Функционально не теряем: DTWEXBGS и ICE DXY 95% времени двигаются синхронно (оба следят за силой доллара). Для нашей цели важна динамика и delta_24h, а не абсолютное значение. DTWEXBGS даже более полный TWI-индикатор.

Поведение без FRED_API_KEY

Решение: компонент должен работать в idle-режиме, не падать.

Если ключа нет:

  • Один WARNING при старте с инструкцией как получить ключ
  • Никаких HTTP-запросов, никакого спама в логах
  • Бот работает дальше, EventAnalyzer корректно обрабатывает macro=None
  • Просто секция "## МАКРО" не появляется в промпте Opus

Это позволяет деплоить без ключа и добавить позже без лома.

Решение НЕ добавлять macro/funding в event_detector

Эти данные — только контекст для Opus, не самостоятельный триггер. Не добавляем event_type='funding_extreme' или event_type='macro_risk_off' сейчас по той же логике что funding: сначала видим как Opus с этим работает, потом решаем нужны ли отдельные триггеры. Иначе разрастётся EventDetector раньше времени.

Технические детали реализации

bot/data_sources/macro.py (~330 строк):

  • httpx async client, последовательные запросы с задержкой 0.3с
  • Парсинг observations с обработкой "." (FRED помечает выходные/праздники)
  • Берём первые 2 валидных значения для расчёта change_pct_24h
  • Кеш в Redis ключ macro:current (общий JSON по 3 сериям)

bot/data_sources/funding_rates.py (~250 строк):

  • Один запрос без symbol параметра — Binance возвращает массив всех Futures-пар
  • Фильтруем по нашим 6 ALLOWED_PAIRS
  • Конвертация: lastFundingRate (доли) → rate_pct_8h + annualized_pct
  • Кеш в Redis ключ funding:current

bot/agents/event_analyzer.py:

  • _gather_context параллельно тянет macro:current и funding:current
  • _build_user_prompt рендерит секции МАКРО (TradFi) и FUNDING {symbol} с подсказками
  • _record_decision сохраняет компактный снимок в bot_decisions.market_context JSONB → потом можно анализировать корреляции макро→решения

Тесты: +22 unit-теста (10 на FRED парсинг + 12 на funding rates).

Уроки сессии

  1. Не верить "бесплатным API без ключей" — они умирают. Stooq до апреля 2026 был эталоном. Сейчас с captcha. Yahoo раньше работал, теперь блокирует датацентры. FRED стабилен потому что государственный — это нужно учитывать при выборе.

  2. Проверять серии при выборе FRED-данных. Не предположил что DTWEXBGS — это broad TWI, не ICE DXY. Облажался один раз — лог dxy=118 пользователь сразу заметил. Урок: тратить минуту на проверку что выбираешь.

  3. Важно отличать "контекст" от "триггера". Все 9 предложений Qwen смешивали эти роли. Контекст обогащает решение, триггер инициирует его. Их добавление имеет разную стоимость и разные риски.

  4. make build не нужен для Python-правок. В docker-compose.yml код смонтирован volume'ом — make restart достаточно. Это сэкономило 3 минуты × N перезапусков.


2026-04-27 (вечер) — Per-pair фильтр + расширение до 11 пар (v1.11)

Триггер

После сессии починки EventAnalyzer NameError пользователь поднял правильный вопрос: "Это очень долгое тестирование, может тянуться неделями. Даже если будет плюс или нет — мы не узнаем. Слишком много ресурсов и внимания тратится без результата."

И предложил добавить альткоинов чтобы ускорить.

Анализ ситуации

Я честно сказал что просто добавить альткоины проблему не решит, потому что главный фильтр в стратегии — BTC > EMA-200 на 1d. Пока BTC под EMA-200, любой сигнал на любой паре автоматически = SKIP. Расширение списка пар без изменения фильтра = ноль новых сделок.

Backtest подтверждает: edge стратегии есть только в чистом bull (BTC выше EMA-200), а в CHOP/transitions она теряет −8% до −14%. Стратегия по дизайну ждёт bull-фазы.

Предложенные варианты

Я предложил три:

  • A: per-pair EMA фильтр + 5 ликвидных топ-25 альтов (рекомендация)
  • B: mean-reversion как параллельная стратегия для CHOP (большая работа)
  • C: смягчение глобального фильтра (BTC > EMA-50 4h вместо EMA-200 1d) — рискованно

Категорически отверг шит-альты:

  • Низкая ликвидность → проскальзывание убивает edge
  • Pump and dump риск
  • Корреляция с BTC всё равно высокая (0.7-0.9 для топ-100)
  • Нарушает философию проекта

Выбор пользователя

Пользователь выбрал Вариант A, причём в AGGRESSIVE варианте:

"Backtest мы уже делали — он не даёт результата потому что суть в том чтобы опираться на новости и анализировать всё с помощью Opus. Делаем без soft BTC filter, агрессивно."

Это разумно — backtest действительно бесполезен для оценки нашей стратегии (он использует proxy-правила без Claude и без новостей). Реальная ценность системы — в качественной фильтрации Opus, а это можно проверить только в live paper trading.

Решение: 5 новых пар

Выбраны топ-25 альты с глубокой ликвидностью на Binance spot и наличием в Binance Futures (для funding rates):

Пара Mcap Нарратив Корреляция с BTC
LINKUSDT #15 Oracles, RWA ~0.6-0.7 (низкая)
ADAUSDT #7 L1 ~0.65-0.75
DOTUSDT #18 Polkadot, parachains средняя
ATOMUSDT #25 Cosmos, IBC ~0.55-0.7 (одна из самых низких в топ-30)
ARBUSDT #20 L2 Ethereum бета ~1.2 от ETH

Не брал DOGE/SHIB/PEPE (мем-коины, движения от твитов Маска), TRX (манипуляции), TON (низкая глубина), NEAR/APT/SUI (мало истории), POL (недавно ребрендился).

Решение: pure per-pair, без soft BTC filter

Главный фильтр меняется с глобального на per-pair:

Старая логика (v1.10):

Можно лонг → BTC > EMA-200 1d (одно условие на ВСЕ пары)

Новая (v1.11):

Можно лонг по ALT → ALT > EMA-200 1d (своя для каждой пары)

Глобального BTC-фильтра больше нет. Бот может открывать лонг по альту даже когда BTC в transition.

Защита от корреляционного риска

Pure per-pair имеет очевидную опасность: при резком дампе BTC -5%+/час все альты валятся вместе. Защита через два новых stoppers:

  1. Свежий price_dump_1h на BTCUSDT → SKIP даже на сильном setup'е по альту
  2. BTC.D растёт >+1% за час → деньги уходят из альтов в BTC, давление

Также Opus инструктирован в SYSTEM_PROMPT проверять движения BTC за 1-4h перед лонгом по альту.

Технические детали

Большая часть инфраструктуры автоматически расширилась через ALLOWED_PAIRS:

  • WebSocket: 18 → 33 стрима (11 × 3)
  • Funding rates (фильтр по ALLOWED_PAIRS)
  • Indicators task
  • EventDetector (per-pair triggers)
  • CoinGecko (через SYMBOL_TO_CG_ID)

Вручную правил:

  • bot/config.py — ALLOWED_PAIRS
  • bot/data_sources/coingecko.py — SYMBOL_TO_CG_ID (chainlink/cardano/polkadot/cosmos/arbitrum)
  • bot/agents/event_analyzer.py — SYSTEM_PROMPT (4 секции переписаны)

Переработанные секции SYSTEM_PROMPT

  1. Список торгуемых пар: 6 → 11 с описанием каждой
  2. Обязательные условия: пункт 1 (per-pair вместо BTC), новый пункт 7 (защита от BTC dump)
  3. Stoppers: per-pair фильтр, BTC.D >+1%/h, price_dump_1h на BTC
  4. Новый блок "PER-PAIR РЕЖИМ": явное описание trade-off с этой стратегии
  5. Сценарий A2: новый win-кейс — альт в собственном bull при BTC в transition
  6. Корреляции: добавлены LINK/ADA/DOT/ATOM/ARB (нарративы и beta)
  7. Принцип про корреляции: переписан с акцентом на per-pair риск
  8. Примеры reasoning: per-pair логика, упоминание проверки BTC за 1-4h

Депозит и риск-параметры

Депозит обновлён в SYSTEM_PROMPT с $50 на $300 (был обновлён в коде ещё в Этапе 6.7, но в промпте оставался $50).

Размер позиции: 25-50% депозита через confidence-scaling = $75-150 на сделку. При confidence=1.0 максимум $150, при confidence=0.5 минимум $75.

Контрольные тесты

  • test_smoke::test_config_importable — проверка что все 11 пар в ALLOWED_PAIRS
  • test_smoke::test_coingecko_mapping_covers_all_pairs — все ALLOWED_PAIRS имеют CoinGecko ID
  • test_smoke::test_system_prompt_per_pair_filter_v1_11 — регрессия на per-pair логику в SYSTEM_PROMPT (чтобы случайно не вернуть BTC-only фильтр)

Тестов: 101 → 103 зелёных.

Почему НЕ делал backtest перед внедрением

Пользователь резонно заметил: backtest бесполезен. Backtest engine использует proxy-правила вместо Opus + новостей + китов. На исторических данных нельзя смоделировать качественный фильтр Opus. Backtest скажет "стратегия в CHOP теряет" но он уже это сказал — поэтому новых данных не даст. Реальная проверка — только paper trading.

Состояние при деплое

Рынок в broad sell-off:

  • BTC: $77,900 → $76,788 (-1.4% за час до деплоя)
  • Все 11 пар в красном за 24h: ARB -4.45%, DOT -3.63%, ETH -3.25%
  • F&G: 47 (Neutral)
  • Регим: CHOP, score=0.45
  • BTC -8.1% от EMA-200 1d (по-прежнему ниже)

Скорее всего первое решение Opus в новой логике будет SKIP из-за свежего BTC dump'а — что правильно. Per-pair режим работает агрессивно когда BTC стабилен и осторожно когда BTC валится.

Ожидаемые результаты

  • Раньше: confluence_setup только по BTC → раз в час → SKIP по BTC<EMA-200
  • Сейчас: confluence_setup может детектиться по любой из 11 пар, на каждой парс per-pair оценка → до 5-10× больше шансов на PROCEED

Это должно ускорить paper trading в разы. Проверим.

Документ rollback

Создан docs/rollback.md — описывает как откатиться на v1.10 (если per-pair даст плохой результат) или на v1.9 (если что-то сломалось фундаментально). Принцип: всегда через git revert, без reset --hard.

Уроки

  1. Стратегия зависящая от единственного глобального фильтра — фрагильна. Пока BTC под EMA-200, бот молчит независимо от качества другого контекста. Per-pair фильтр это исправляет.

  2. Pure per-pair требует явных stoppers против корреляционного риска. Иначе бот может войти в SOL когда BTC валится, и получить -8% за час.

  3. Расширение пар через ALLOWED_PAIRS — низкая стоимость, высокий effect. 95% инфраструктуры уже автоматически работает с любым ALLOWED_PAIRS. Это правильная архитектура.

  4. Документация отката заранее > попытки разобраться в кризисе. Создание rollback.md ДО того как что-то сломалось — это инвестиция в будущую безопасность.


27 апреля 2026 — v1.12: 6 production-фиксов перед Этапом 7

Контекст

Полный ресерч проекта с разбором сильных/слабых сторон выявил 6 критичных мест где код либо не соответствовал заявленному поведению, либо мог дать неожиданное поведение в продакшене. Все 6 закрыты в одной итерации. Каждый — отдельный коммит для возможности точечного отката.

Какие фиксы и почему

Fix 1 — Fail-closed на Redis-fail в _get_current_deposit

Проблема: _get_current_deposit() при недоступности Redis возвращал дефолт $300 (fail-open). Это позволяло торговать с неактуальным депозитом — например, после серии убытков, которые ещё не записались в Redis.

Решение: метод возвращает Decimal | None. None означает "Redis недоступен или повреждённое значение". validate_entry() REJECT-ит с понятным reason.

Цена: при кратковременной недоступности Redis бот не торгует. Это правильное поведение — лучше пропустить сделку, чем войти с фантомным депозитом.

Fix 2 — Подключить confidence-sizing в validate_entry

Проблема: метод scale_position_size_by_confidence() существовал и был покрыт 5 unit-тестами. Но grep -rn по bot/ показал что он нигде не вызывается в продакшен-цепочке. Если Opus предлагал size=50% при confidence=0.55, бот реально брал 50% депозита вместо обещанных в CLAUDE.md 27.5%. То есть промпт Opus инструктировал самостоятельно учитывать confidence в размере, но жёсткой страховки в коде не было.

Решение:

  • Добавил параметр confidence: Decimal | None в validate_entry()
  • Вызвал scale_position_size_by_confidence(size_pct, confidence) после получения proposed_size
  • При confidence < MIN_CONFIDENCE_FOR_TRADE (0.5) — REJECT
  • В trader.py передаю decision.confidence напрямую

Заодно исправил формулу: была floor + (1-floor)×conf (давала 37.5% при conf=0.5), стала scaling = confidence как обещано в CLAUDE.md (25% при conf=0.5). Старая формула была согласована с тестами, но не с документацией. Документация важнее, потому что это источник истины для пользователя.

Fix 3 — Trailing stop без race condition

Проблема: в _maybe_move_trailing_live сначала вызывался cancel_all_orders, потом create_oco_order. Между этими шагами позиция голая на бирже. Если процесс упадёт или create вернёт ошибку — позиция без OCO защиты.

Решение:

  • Cancel обёрнут в try (transient errors не блокируют create)
  • Sleep уменьшен 500ms → 300ms (минимизация gap)
  • Retry на create_oco_order (1 попытка) — для transient API ошибок
  • Если breakeven OCO не получился: fallback — попытка восстановить оригинальный OCO с исходным SL (хоть какая-то защита)
  • Если и fallback упал: критический Telegram-алерт notify_kill_switch с текстом "позиция БЕЗ OCO"
  • Pending-флаг trailing_pending:{trade.id} (TTL=5 мин) для будущего recovery

Fix 4 — Gap risk в paper-симуляции SL/TP

Проблема: _check_paper_exit использовал только current_price (close 1h-свечи). Если low свечи пробил SL, а close выше — paper не закрывал позицию, хотя в реальности SL сработал бы по low.

Решение: новый метод _get_last_candle_lhc(symbol) возвращает (low, high, close). В _check_paper_exit логика стала асимметричной:

  • SL: если low ≤ sl_price → exit по min(low, sl_price) (worst-case, market sell на пробой)
  • TP: если high ≥ tp_price → exit ровно по tp_price (limit-fill semantics)
  • Оба пробиты в одной свече → приоритет SL (порядок событий внутри свечи неизвестен)
  • Fallback на close при отсутствии свечи в БД

Цена: paper результаты будут хуже на 0.5-1.5% за сделку. Это правильное приближение к реалу.

Fix 5 — Комиссии и slippage в backtest

Проблема: backtest НЕ учитывал расходы. Комментарий в начале файла честно говорил "можно добавить позже". Это завышало результаты на 30-50%.

Решение:

  • COMMISSION_PCT = 0.1 (Binance taker × 2 = 0.2% за круг)
  • SLIPPAGE_PCT = 0.05 (применяется к entry + market exits)
  • MARKET_EXIT_REASONS = {"sl", "trailing_be", "time_stop"} — для них slippage применяется
  • TP — limit-ордер, slippage НЕ применяется к exit
  • CLI: --commission, --slippage, --no-fees
  • SimulatedTrade расширен: gross_pnl_usd, fees_usd, slippage_cost_usd
  • compute_metrics возвращает gross_return_pct, fees_usd, fees_pct_of_deposit
  • print_report показывает блок "Расходы" с разбивкой gross→net

Fix 6 — Pending orders recovery

Проблема: в _open_long_live sequence Market BUY → Create OCO → INSERT Trade в БД. Если процесс упадёт между market BUY и DB INSERT — позиция на бирже без записи в БД, потерянная.

Решение через Redis pending-tracker:

  • В OrderExecutor: _redis: aioredis.Redis | None (lazy-init в __aenter__)
  • ДО market BUY: SET pending_trade:{decision_id} с JSON-payload (symbol, qty, started_at), TTL=600s
  • ПОСЛЕ успешного DB INSERT: DEL ключ
  • В error-paths: удаляем только если позиция точно закрыта (BUY fail / OCO fail + emergency close OK)

На старте Trader.run() — _recover_pending_trades():

  • SCAN всех pending_trade:* ключей
  • Для каждого: критический Telegram-алерт + удаление ключа

ВАЖНО: автоматическое восстановление Trade в БД НЕ делаем — это слишком рискованно без тщательного тестирования на testnet.

Тестирование

Локального Python-окружения с зависимостями нет (Mac), Docker недоступен. Тесты будут прогнаны на сервере после git pull. Все 9 изменённых .py файлов прошли ast.parse (syntax valid).

Изменения в тестах:

  • test_risk_manager.py: +4 новых, обновлены 4 (новая формула confidence)
  • test_position_tracker.py: +9 новых (5 trailing live, 4 paper gap)
  • test_order_executor.py: +5 новых (pending tracker)
  • test_trader.py: новый файл, 3 теста (recovery)

Тестов: было 103 → стало ~130.

Что меняется в ожиданиях

Цифры в CLAUDE.md — теоретические, без расходов. После Fix 5 backtest покажет правду:

  • Win rate: примерно тот же (~47%)
  • Gross return: тот же
  • Net return: −30-50% от gross (фиксированные расходы)
  • Sharpe: +30-50% (защитные фиксы 1, 3, 6 уменьшают волатильность)
  • Вероятность катастрофы — ↓ в 5-10 раз

Уроки

  1. Тесты, документация и код могут расходиться. Confidence-sizing был полностью оттестирован, но никем не вызывался. Регулярные code walkthrough важнее наращивания test coverage.

  2. Default fail-open опасен в торговом коде. Last-resort fallback'и которые "разрешают" работу при сбоях — это пропуск катастрофы.

  3. Race conditions сложно увидеть в коде. Trailing stop выглядел корректно при первом чтении. Только когда задумываешься "что если процесс упадёт между этими двумя строчками" — становится ясна проблема.

  4. Backtest без расходов — это маркетинг, не аналитика. Любой strategy backtest должен начинаться с реалистичных commission/slippage.

  5. Recovery должен детектить проблему даже если не может её решить. Auto-recovery опасен. Detection + alert почти всегда лучше.

Реальные цифры backtest (после Fix 5)

Прогон 27 апреля 2026 на 730 днях (2024-04-27 → 2026-04-27). 11 пар, 17 519 1h-баров. 128 unit-тестов прошли зелёными перед прогоном.

Сравнение с расходами / без расходов:

Метрика С fees+slippage --no-fees Разница
Сделок 151 151
Win rate 34.44% 35.76% −1.3%
Net PnL −$69.02 −$12.54 −$56.48
Net Return −23.01% −4.18% −18.83%
Max DD 24.79% 18.14% +6.65%
Profit factor 0.766 0.956

Расходы съели 18.83% депозита за 2 года — это больше, чем сам убыток стратегии без расходов. То есть расходы оказались важнее чем edge стратегии. Это объясняет почему до Fix 5 backtest был «оптимистичным».

По триггерам (важная находка):

  • volume_spike: 139 сделок, WR 37.4% — основа
  • confluence_setup: 8 сделок, WR 12.5% — ХУЖЕ простого volume
  • rsi_oversold: 4 сделки, WR 25%

Текущая логика confluence (2+ любых триггера = CRITICAL severity) не работает как сильный сигнал. Кандидат на пересмотр в v1.13.

По парам:

  • ETHUSDT: WR 47.1%, avg +1.18% — единственный edge
  • BTCUSDT: WR 40.7%, avg −0.50%
  • BNB/SOL/XRP/AVAX: WR 15-33%, убыточны
  • LINK/ADA/DOT/ATOM/ARB: 0 сделок (старая BTC-only логика backtest, не v1.11)

Вывод:

  1. Стратегия в proxy-режиме (без Claude) убыточна даже без расходов: EV на сделку = −0.27%.
  2. Расходы критичны — 0.25% за круг даёт −18.83% за 2 года при текущей частоте сделок.
  3. Backtest не v1.11 — альты не работают. Синхронизация = отдельная задача (это всё равно proxy без Claude).
  4. Наша ставка: Claude поднимет WR с 35% до 45-50% через отсев слабых сетапов. Валидация — только paper trading.

CLAUDE.md обновлён — раздел "Ожидаемые результаты" заменён реальными цифрами + 4 сценария (pessimistic/base/optimistic/catastrophic).

1 мая 2026 — v1.14: Multi-position режим в paper для ускорения сбора статистики

Контекст

После v1.13e+2 (фикс indicators.valid, коммит 29c37b4) reversal-стратегия B5/B3 наконец заработала end-to-end. За первые 30 часов production поймали 2 сетапа: BNB B5 (открыт, wick=0.009%) и ATOM B5 (отвергнут, wick=0.383%). ATOM был сильно качественнее, но потерян из-за MAX_OPEN_POSITIONS=1.

Вопрос: повышать ли лимит для paper-фазы?

Что обсуждали

За повышение (аргументы пользователя):

  • Paper это тестовый стенд, не реальные деньги
  • Чем больше сделок — тем быстрее статистика
  • % метрики (WR, avg win/loss, MaxDD) инвариантны к депозиту → math применима
  • В live можно вернуть параметры обратно

Против:

  • При $300 физически невозможно открыть 5 позиций × 35% = $525
  • Корреляционный риск (BTC dump → 5 позиций в SL разом)
  • Backtest engine не поддерживал multi-position — нет валидации

Решение

Принят гибридный путь:

  1. Поднять депозит paper до $2000 (5 × 35% = $700 × 5 = $3500 max notional влезает с буфером, размеры в % как в backtest)
  2. MAX_OPEN_POSITIONS = 5
  3. Новая константа MAX_POSITIONS_PER_SYMBOL = 1 (защита от двойной ставки на одну пару если B5 и B3 совпадут)
  4. Расширить backtest engine под multi-position для валидации: --max-open, --deposit, --max-per-symbol, --reversal-mode, --disable-btc-stopper CLI флаги; размер позиции от free_balance
  5. Обязательный rollback-doc (docs/rollback.md) для отката на single-position перед live

Backtest-валидация (1095 дней, 9 пар, B5+B3 only)

Метрика MAX=1, $300 MAX=5, $2000 Дельта
Total Trades 470 1622 ×3.5
Win Rate 38.72% 35.33% −3.4pp
Avg win +4.21% +4.29%
Avg loss −1.91% −1.80%
Profit Factor 1.346 1.294 −0.05
Max Drawdown 18.26% 18.90% +0.64pp
Sharpe-like 0.143 0.111 −0.03
Net Return +178% +308% +130pp
Final Deposit $834 $8156

По триггерам в MAX=1:

  • B5 (lower_bb_reversal): 377 trades, WR 38.7%, avg +0.43% → ~+162% Net
  • B3 (bb_squeeze_breakout): 93 trades, WR 38.7%, avg +0.61% → ~+57% Net
  • Combined: +178%

Walk-forward на MAX=5 (90-day windows):

  • 11 окон с торговлей из 13 (первые 2 без BTC 1d данных для warm-up)
  • Только 1 окно положительное (April-July 2025: +6%)
  • Avg окно: −30.86%
  • Best: +6%, Worst: −59.46%

Главные выводы

  1. B5/B3 имеют real edge: PF 1.29-1.35, Sharpe positive, MaxDD ~19%. Это лучшее что у нас есть.

  2. MAX=5 не улучшает per-trade edge — WR/PF/Sharpe ниже на небольшие величины. Но усиливает абсолютный compound в 1.7×. Trade-off: больше шума ради больше данных.

  3. Walk-forward алармирует: 91% окон убыточны. Стратегия выживает за 3 года только за счёт sequence of returns (1-2 крупных bull-окна компенсируют все остальные). В live это означает что 9 из 11 первых "месяцев" мы будем терять, и положительные периоды редкие но крупные.

  4. Это ПРОКСИ без Claude. Реальная ставка стратегии — что Claude поднимет WR с 35% до ≥45% через отсев катализаторов и плохих сетапов. Это будем измерять в paper.

Критерии для перехода на live

После 30+ paper-сделок:

  • ✅ WR ≥ 40% (значит Claude действительно помогает)
  • ✅ Net % match с backtest или лучше
  • ✅ MaxDD ≤ 25%
  • ✅ Хотя бы 1 положительная неделя
  • ✅ Claude-расход ≤ 15% от профита

Если WR=35% (как proxy) — переписывать стратегию, не идти в live.

Что задокументировано

  • docs/rollback.md (новый, 200+ строк) — пошаговый откат + pre-live чек-лист
  • CLAUDE.md — раздел v1.14 с цифрами backtest, ссылка на rollback.md
  • Этот файл — детальное обоснование решения

Файлы изменены

  • bot/config.py (+ 8 строк)
  • bot/trading/risk_manager.py (+ 30 строк)
  • dashboard/app.py (+ 100 строк, новая секция «Баланс»)
  • scripts/backtest.py (+ 90 строк, multi-position support + CLI)
  • tests/test_risk_manager.py (+ 4 теста)
  • tests/test_backtest_multi_position.py (+ 5 тестов, новый файл)
  • Тестов: 203 → 212

Коммиты

  • 1e5aa91 — feat(v1.14): paper-режим расширен
  • 25ecdc0 — feat(backtest v1.14): multi-position
  • 98a9d1f — fix(backtest): --reversal-mode CLI

Метрика успеха

Через 4-6 недель paper:

  • Если WR ≥ 45% + Net Return ≥ +20% → переход на live $300 с MAX=1
  • Если WR 35-45% + marginal positive → продолжить paper ещё 4 недели
  • Если WR < 35% или Net отрицательный → переписать стратегию