Лог принятых решений. Каждая запись: дата, решение, причина, альтернативы.
После 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 преждевременно
| Параметр | $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 приемлем для гипотезы которая статистически не подтверждена.
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).
| Сценарий | Действие |
|---|---|
| ✅ 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)
-
Bootstrap+DSR — обязательный quality gate для крипто-стратегий. После 13 failed экспериментов мы наконец-то имеем дисциплинированный способ оценить "это edge или data dredging".
-
P(profit) > 85% != tradeable edge, но это необходимое условие. Если P(profit) < 50% — стратегия гарантированно loser. Если P > 85% но Sharpe CI пересекает 0 — нужен forward test для финализации.
-
Полная изоляция модулей оплачивается. Spot/perp/trend не затронуты. Если funding arb провалится — DROP TABLE и git revert без последствий.
-
Single-writer pattern + UNIQUE constraints — must-have для audit logs финансовых операций. Funding payments не могут дублироваться.
-
Forward test на paper $500 — золотой middle ground между paper $50 (шум доминирует над сигналом) и live $1000 (реальные деньги без статистического подтверждения edge'а).
После 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.
- 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:
-
R1 (B3 в bear):
- Theoretical basis (squeeze fakeout в downtrend — учебник 1980-х)
- Per-rule impact +$437 на real outcomes (29 of 47 losses = 49% concentration)
- Effect size слишком большой для шума
-
R3 (alts при BTC weakness):
- Extension of R1 logic
- Per-rule impact +$404
- Theoretical (alts beta amplification в bear)
-
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.
Future strategies workflow:
- Opus reasoning → только генерация гипотез
- Per-rule impact analyzer на real outcomes → mandatory quality gate
- Out-of-sample test через 30+ дней → final verification
- Только тогда — 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
- Будет ли Opus в production с full context (news/macro/funding/Vision) также rationalize? Или там reasoning ground'ed в real signals?
- Достаточно ли theoretical + effect-size validation для future rules? Или нужен ещё один control mechanism?
После цепочки исследований за 1 день:
- Replay-30d с реальным Opus на 65 trades → -$352 catastrophic
- Meta-analysis Opus on Opus → 11 skip-rules
- Per-rule impact analyzer → 6 profit-positive, 4 negative
- v1.18.1 calibrated с R1+R3+R7-soft+R11
- 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).
-
R7-soft net negative на validation data. Не теоретически, не "может быть" — на 65 реальных trades с реальным Opus. -$48 это много.
-
Deep deviation НЕ значит "падающий нож". Реальные winners часто в этой зоне:
- ARB -55.6% → +$34
- DOT -44% → +$34
- DOT -43.2% → +$35
-
B5 winners плохо отличаются от losers по чисто-техническим данным (Δ confidence Opus = 0.01). Лучшая стратегия — дать Opus решать на event-by-event basis с полным production context (news/macro/funding/charts).
-
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
В реальной торговле:
- 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
- Если 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 рискованно
После 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).
-
Edges академически некоррелированы: spot reversal — mean-reversion на 4h, perp shorts — mean-reversion на топах 4h, trend-following — momentum на 1d. Разные timeframes + разные логики = реальная portfolio diversification.
-
Покрывают разные регимы: B5/B3 работают в bear/chop (capitulation candles), perp shorts — в distribution/topping, Donchian + EMA-200 — только в bull (filter активирует). Когда одна спит, другая работает.
-
Время дешевле параллельного 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.
-
Полная изоляция от Phase B: новый модуль
bot/trend_following/(5 файлов), новая модельTradeTrend(отдельная таблица), отдельные Redis keys (trend:trading_deposit_usd,trend:kill_switch), отдельные loss limits (−7/−15/−30%). Spot и perp инфраструктура НЕ затрагиваются. -
Без Claude в hot path: trend-following — детерминистический breakout, никаких LLM решений. Это категорически другое чем Phase B где Claude фильтрует. Plus: убирает один источник нестабильности — Claude API outage / cost spike не остановит trend.
-
Автономный координатор: TrendTrader не реактивный (как spot/perp Trader которые читают
bot_decisions), а проактивный — раз в день в 00:05-01:00 UTC проверяет signal черезcompute_donchian_signal. Дедуп через Redis ключtrend:last_check_date. -
Position size фиксированный: 60% депозита (не confidence-scaled как Phase B). Логика: 1d стратегия = 4-8 трейдов/год = редкие сигналы, можем позволить больший размер. На $600 paper это $360/сделку = разумная экспозиция.
-
Без 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 (возвращает structuredDonchianSignal)bot/trend_following/trend_risk_manager.py— TrendRiskManager (+TrendRiskValidation), все REJECT-кейсы кроме confidencebot/trend_following/trend_trader.py— автономный координатор с window check (00:05-01:00 UTC) + dedup поtrend:last_check_datebot/trend_following/trend_position_tracker.py— exit signal monitoring раз в час, kill-switch handlerbot/database/models.py—TradeTrendмодель (без FK на BotDecision — намеренно для чистого rollback)alembic/versions/0003_trades_trend_table.py— миграцияbot/main.py— TaskSupervisor 17 → 19 задачbot/notifications/telegram_notifier.py—notify_trend_position_opened/closedс emoji 📈dashboard/app.py— вкладка "📈 Trend" + sidebar секцияMakefile— 6 trend-related targetstests/test_trend_following.py— 19 unit-тестов
- 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)
- 1-3 закрытые сделки в expected range (+/- 5pp от backtest предсказания) → keep
- Если за 90 дней 0 сделок (нет breakout) — keep, ждём bull-фазы
- Если за 180 дней WR <25% или MaxDD >40% — soft-disable через
TREND_ENABLED=False
- Backtest proxy ≠ реальная торговля. Пока не знаем как D55 переведётся в paper.
- 1d таймфрейм медленный — статистика собирается долго (ожидаем 4-8 сделок/год на BTC). Через 30 дней может быть 0 сделок и это норма.
- 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 (см. альтернативы — отвергнуто).
После 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-событии.
- Нет unit-теста на полный поток
_analyze_event— есть только тесты_build_user_promptи_should_call_opus - С v1.15 до v1.16 B3 reversal-события не происходили:
- B5/B3 long редкие в bear (нет резких пробитий BB_lower)
- B5_short/B3_short детекторы появились только в v1.16 B3 (1 мая поздно вечером)
- В период между B3 деплоем и сегодняшней ночью реальных setups не было
- 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 без записи в БД.
- Импорт
from bot.trading.risk_manager import REVERSAL_EVENT_TYPESвbot/agents/event_analyzer.py - Регрессионные тесты
tests/test_event_analyzer_prompt.py::TestSymbolImports:test_module_imports_without_errors— re-import + hasattr checktest_reversal_event_types_contains_b5_b3_long_and_short— все 4 типа в frozensettest_analyze_event_method_uses_imported_reversal_types— inspect.getsource + namespace check
Тестов: 423 → 426.
Аналогичный баг был в 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 на уровне модуля, а не только конкретные функции.
- Дублировать REVERSAL_EVENT_TYPES в event_analyzer.py локально — отклонили, источник правды должен быть один (risk_manager). Дублирование = риск рассинхронизации при добавлении 5-го типа.
- Linter в CI (pyflakes/flake8) — следующий шаг, но требует CI настройки. На now достаточно регрессионного теста.
- 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=short→trades_perpзапись - Если Opus возвращает
skip→ видно reasoning в БД (раньше было silent NameError)
После 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_usdvsperp:trading_deposit_usd,bot:kill_switchvsperp: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-инфраструктурой.
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 (
- Long perp — отложен до Phase C. Сейчас perp только short. Это сознательное ограничение чтобы не пересекаться со spot (там уже long).
- Auto-recovery TradePerp в БД — при краше между open_position и INSERT мы шлём critical Telegram alert но НЕ восстанавливаем автоматически. Слишком рискованно без тщательного тестирования.
- 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 Bdocs/roadmap.md— обновлён со статусом Phase B и метриками наблюденияREADME.md— Архитектура, риск-лимиты, статус, 17 задач
| 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 секции) |
После v1.14 (multi-position paper) приняли решение усилить edge стратегии через современные технологии. Phase 1: Vision, Phase 2: clustering, Phase 3 — multi-agent — отложен до 30+ paper-сделок (нужна выборка для измерения delta).
Новый модуль 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 без объёма = слабый сетап).
Новый модуль 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 (parameterimages: list[bytes]дляcall/call_opus→ формирует content blocks с base64 PNG)event_analyzer._analyze_eventрендерит chart для B5/B3 → передаёт в Opusnews_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-флагами без отката кода.
После walk-forward на 9 парах (предыдущая запись) увидели:
- B5/B3 reversal — robust, +92%/+90% за 3 года
- H0 trend — катастрофа, Σ −84% за 4 bull-окна
Решили сделать 3 production-улучшения одним блоком:
- Squeeze-фильтр для B5 (вытащить единственное проигрышное окно distribution)
- Дифференцированный confidence-floor (защититься от слабого trend)
- Расширенные Telegram-уведомления (видеть все важные сигналы в paper trading)
Гипотеза: 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 оставлен для будущих экспериментов. Это полезный негативный результат — раньше думали что фильтр улучшит, теперь знаем точно что нет.
Проблема: 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_TRENDevent_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_075test_validate_entry_approves_trend_at_075test_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 — компромисс между «строго» и «не блокировать совсем».
Запрос: «нужны все важные уведомления — все решения и события high и выше».
Изменения (commit 524e5b8):
-
notify_decisionрасширен:- Раньше: только
proceedиabort - Теперь: все 4 типа (
proceed/skip/wait/abort) еслиconfidence is not None(Opus реально вызывался) - Auto-skipped без Opus (
confidence=None) — продолжаем НЕ алертить (шум фильтров_should_call_opus) - В сообщение добавлен
event_type
- Раньше: только
-
Новый
notify_high_priority_event— real-time алерты до Opus для приоритетных событий:lower_bb_reversal_4h(B5) — всеbb_squeeze_breakout_4h(B3) — всеnews_filtered— только high/critical impactprice_dump_1h— все (high)rsi_oversold— все (high)- НЕ алертим:
whale_buy_cluster(~22/день, флуд) иvolume_spike(medium, шум)
-
Подключение в
event_detector._record_trigger— алертит все триггеры (методnotify_high_priority_eventсам фильтрует). -
Дедуп: 5 мин для high_event на пару, 1 мин для decisions.
-
Детали в сообщениях: wick % для B5, breakout % + volume ratio для B3, RSI value, news preview/impact.
После 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) |
| Все зелёные | ✅ |
Утром того же дня 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 парах.
Окна детально:
| Окно | Эпоха | 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), не трогаем.
- Расширение пар × backfill = резкое улучшение статистики. Раньше думали что edge есть, но «кочка». 9 пар × 730 дней = твёрдый сигнал.
- Combo robust > soло robust для разных эпох. B5 проигрывает в distribution, B3 там вытягивает. Архитектурная диверсификация.
- Walk-forward по эпохам — обязательный стандарт. Один агрегат на 730 днях — недостаточно. Эпохальная стратификация раскрывает где edge real, где случайный.
После 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 измерим.
-
Только 2 пары (BTC+ETH). У нас 9 пар в production, но альты v1.11 (LINK/ADA/DOT/ATOM/ARB) — только 90 дней истории. Нужен backfill альтов до 730+ дней + повторить walk-forward на 9 парах. Тогда статистика реверсала вырастет 3-4x.
-
Только 6 полных окон (один — no-data, один — 14 дней). Если backfill сделать 1825 дней (5 лет) — получим 10 окон с захватом 2022 crypto winter и 2021 параболического bull. Это даст ещё более строгий тест. Но 5 лет назад рынок был структурно другой (no-ETF, до halving 2024) — результат может быть менее применим.
-
Без Claude — это proxy результат. Реальный production-сетап с Opus может вести себя иначе. Paper trading 2-4 недели даст delta vs proxy.
-
Прогнать всё сразу на 5 лет — отверг, потому что эпохи 2021-2022 структурно отличны от 2024-2026. Усреднение мешает интерпретации.
-
Только walk-forward (без stratify по эпохам) — у нас уже был такой прогон в v1.13c (
scripts/walk_forward_compare.py), он показал «83% positive окон» но не отвечал на ключевой вопрос «в каких именно эпохах». Stratified-анализ информативнее. -
Разделить эпохи по календарю (2023, 2024, 2025) — отверг как менее чистое: внутри одного года могут быть смены рынка (2024: bull → distribution → consolidation). Классификация по
regime_distribution_hoursотражает реальное состояние рынка в окне, не календарную метку.
-
Один агрегированный backtest = недостаточно для решения о live. Walk-forward с группировкой по эпохам — минимальный стандарт. До этого момента у нас было «B5 +68% за 730 дней, walk-forward 83% positive» — звучит хорошо, но не отвечало на «а что в bear?». Теперь отвечаем явно.
-
«Bull-beta» — реальный риск для крипто-стратегий. Огромное число backtest'ов 2023-2025 положительные просто потому что был bull. B5 прошёл этот фильтр.
-
Эпохальная стратификация автоматизируется через
regime_distribution_hours. Не нужно вручную метить периоды — backtest сам считает регим в каждом баре, агрегат по часам даёт точную картину.
После rollout v1.13c (B5/B3 в production) на дашборде увидели «Auto-skipped (без Opus) — регим bear, тип события news_filtered не приоритетный для этого регима». Это означало что Opus не вызывается несмотря на новый dormant fix. Ресерч выявил 5 проблем подряд которые без починки сделали бы 2-4 недели paper trading бесполезными.
Симптом: на дашборде 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.
После найденного бага запустили 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 | |
| BTC correlation stopper применяется к reversal | |
| NewsFilter (Haiku) фильтрация | ✅ OK |
| Telegram notifier для B5/B3 | ✅ OK через notify_decision |
Других блокирующих багов не найдено. Это даёт уверенность что pipeline целостный.
Гипотеза: 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
Декларация в 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, поэтому контракт сохраняется.
Идея от 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'ы. Кнопка «🔄 Обновить сейчас» остаётся для ручного обновления.
-
Тесты на интеграцию важнее unit-тестов. У нас были unit-тесты на детекторы B5/B3 (5+5+3 sanity), но не было теста «после события B5 в bear, дойдёт ли это до Opus». Только e2e-сценарий выявил бы Fix 1 раньше, чем дашборд показал «Auto-skipped».
-
Декларации в документации могут устаревать молча. Fix 4 — declaration «30-40% reversal» была верна до v1.12 Fix 2 (когда формула была
floor + (1-floor)×conf), а после изменения формулы перестала. Регрессионные тесты на cross-document consistency тоже полезны. -
Эмпирическое сравнение лучше предположений. Когда обнаружили конфликт «BTC stopper vs reversal», первая интуиция — exempt-ить. Но без ablation мы бы не знали порядок эффекта (+1%? +30%?). Цифра +12% Net без роста MaxDD дала однозначный ответ. Скрипт ablation остаётся в репо для будущих экспериментов.
-
Полный код-ресерч после крупного 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). Все зелёные.
После 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.
Протестировали на 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%).
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 добавлены как индикаторы
Проблема: старый 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 теперь activeDormant остался только как защита от сломанного 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-стратегии — выбор очевиден.
-
Не вносить B5/B3 в production: protected подход «proxy без Claude убыточен, дальше ничего не делаем». Проблема — это блокирует проект на годы (ждать pure bull-фазы).
-
B9 combo вместо B5+B3 отдельно: combo даёт меньше консистентности (66% vs 83% positive окон). Лучше держать B5 и B3 как отдельные сигналы — Opus сам поймёт когда их применять.
-
Условный dormant (только при
unknownИЛИbear+низкая_волатильность): слишком сложно. Простое правилоunknown onlyдостаточно. -
Поднять порог confidence для reversal до 0.8: это убьёт частоту срабатываний. Backtest показал что даже при средней confidence стратегия работает.
В 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 вытянет убыточную стратегию.
См. секцию ниже «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%)
Решение: 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 депозита.
Решение: PostgreSQL снаружи на 5433, Redis на 6380.
Причина: на сервере пользователя системные PG/Redis на стандартных портах (5432, 6379) — их используют другие проекты. Нельзя их трогать. Docker-сеть изолирована, но хост-порты конфликтуют.
Внутри docker-compose сети сервисы общаются по именам (postgres:5432, redis:6379) — там конфликтов нет.
Решение: MAX_POSITION_SIZE_PCT, STOP_LOSS_PCT и прочее — жёсткие константы в bot/config.py. Claude их не видит в промпте и не может изменить.
Причина: из Alpha Arena ноября 2025 — LLM могут обходить "текстовые" правила, особенно под давлением убытков. Риск-лимит должен быть физическим барьером.
Решение: не запрашиваем у Claude "проанализируй свои ошибки за неделю".
Причина: работа ATLAS (ACL 2026, NTUA) показала, что рефлексивное рассуждение не даёт систематического улучшения. Вместо этого — Adaptive-OPRO: эволюция промптов через отдельный LLM-оптимизатор с rolling window. Реализация на Этапе 8.
Решение: первичная фильтрация — Haiku 4.5 (дешёвый), финальные решения — Opus 4.7.
Оценка расходов: ~$2/мес Haiku + ~$5/мес Opus = $7/мес. На депозит $50 это 14% в месяц расходов — проект заведомо убыточен на таком капитале, что честно отражено в CLAUDE.md. Это учебный полигон.
Решение: вместо платного 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 сигналы.
Решение: пропускаем интеграцию Etherscan API.
Причины:
- BTC через него не виден (ETH-only)
- ERC-20 whale transfers — задержка 12-30 сек, для свинга не критично
- Whale Alert через Telegram уже даёт похожие on-chain сигналы
Если позже окажется нужен — добавим за час.
Решение: периодические задачи (F&G, CoinGecko раз в час) реализованы через простой asyncio.sleep в собственных классах. APScheduler не подключаем.
Причина: для двух часовых задач APScheduler — over-engineering. Декларативный синтаксис и job-store оправдают себя на Этапе 3+ когда появятся индикаторы (каждые 5 мин), чистка БД (раз в неделю), бэктесты (раз в день) и т.п.
Решение: PYTHONPATH=/app в docker-compose.yml, COPY до pip install в Dockerfile.
Причина: при первом деплое pip install -e . в Dockerfile запускался ДО COPY . ., поэтому пакет bot находился пустым. CLI-скрипты падали с ModuleNotFoundError: No module named 'bot'. PYTHONPATH чинит это на лету (без редеплоя), Dockerfile-фикс — для следующих сборок.
Решение: ./scripts:/app/scripts и ./data:/app/data примонтированы как volumes.
Причина:
- Новые скрипты в
scripts/сразу доступны безmake build. ./data/хранит Telegram session-файл, который должен переживать рестарт контейнера.- Изначально только
bot/был замонтирован — это вызвало ошибку «backfill_data.py not found» при первом запуске.
Решение: 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 без редеплоя.
Решение: ни один trading модуль не идёт напрямую в OrderExecutor — только через RiskManager.validate_entry(). Если RiskManager сказал REJECT — никаких исключений.
Причина: из Alpha Arena (Nof1, 2025) — Claude может давить под прессом убытков и подсовывать "правильно звучащие" reasoning'и для нарушения правил. Барьер должен быть физический (Python-код), а не риторический (промпт). Все жёсткие лимиты живут в bot/config.py как константы, проверяются в RiskManager, и Claude их вообще не видит в своих промптах — значит не может попросить их изменить.
Stale-фильтр: решения Opus старше 10 минут не исполняются. Цены за это время уже ушли, сетап мог развалиться. Лучше пропустить чем войти в устаревшее.
Решение: 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.
Решение: в paper-mode цена для проверки SL/TP берётся из последней закрытой 1h-свечи (БД), а не live из WebSocket. Симуляция исполняется только когда бар закрылся.
Причина: даёт детерминируемую и воспроизводимую симуляцию. WebSocket-цены меняются непрерывно, можно случайно получить "проскальзывание" которое в реальной торговле не воспроизведётся. Закрытая 1h-свеча — это реальная high/low за последний час, по которой можно судить достоверно сработал ли SL/TP.
Минус: симуляция в paper отстаёт от реальности на ≤1 час. Это компромисс ради воспроизводимости тестов на исторических данных.
Решение: 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 проще (< → <).
Решение: 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 минуты, потом кеш.
Решение: 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.
Решение: рефакторинг 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+ минут после рестарта — счётчик ребутов сбрасывается, при будущих сбоях бэкофф будет малым.
Решение: отдельный 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-алерт.
Решение: 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.
Решение: добавлено 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 детерминированное и хорошо документированное.
Решение: один 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) одинаковые. Поэтому общий образ — это естественное решение, а не хак.
Решение: в 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+ полей.
Решение: в 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-логикой.
Решение: в 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 точно его не подхватил.
Контекст: после Этапа 6.5 написали walk-forward backtest engine (scripts/backtest.py). Прогнали на 365 днях — получили 0 сделок (рынок все 365 дней был bear/chop). Расширили backfill до 730 дней — захватили реальную bull-фазу апреля-октября 2025 года. Прогнали walk-forward по 30-дневным окнам.
| Окно | Сделок | 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 включается:
- Только после реализации 3 улучшений (ATR / confidence / dormant)
- Только когда регим перейдёт в bull (ждём, может 1-3 месяца)
- С kill-switch на drawdown 15%+
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/год
- НЕ ослабляем фильтры в chop — proxy-тест показал что lenient-стратегия маржинальна (PF 0.976). Confluence-only это правильно.
- НЕ добавляем шорты или плечо — Claude bias к лонгам, мы это используем как фичу.
- НЕ оптимизируем threshold регима под bull-фазу — это overfitting к одному периоду.
- НЕ переходим на live до bull-фазы — на bear-рынке стратегия не торгует, расходы съедят депозит впустую.
Контекст: после реализации ATR-based stops + confidence-sizing + dormant mode прогнали backtest на 730 днях walk-forward (25 окон по 30 дней). Ожидали улучшения по всем метрикам.
| Метрика | Ожидал | Получили |
|---|---|---|
| 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) теряем больше из-за широких стопов
🌟 Чистый 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 сделок — правильно
- 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 стратегии — не баг, а особенность дизайна.
- НЕ переходить на live до начала чистого bull (max BTC > EMA-200 на 1d, удерживается ≥7 дней)
- Использовать dormant mode — экономит расходы во время не-bull
- Отслеживать regime transitions — после смены bull→chop первые 7 дней не торговать (доб. фильтр в будущем)
- Оставаться на $300 как и планировали — это баланс между «достаточно чтобы окупать расходы в bull» и «не больно потерять при ошибке»
- 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-периода.
Контекст: после серии backtest'ов с разными метриками (ATR vs fixed, lenient vs strict, 365 vs 730 дней) пользователь поднял ключевой вопрос:
«после тестов прошлых когда мы были в минусе то бот не учитывал новости и прочие факторы на которые мы опираемся и в чем в принципе смысл всей логики бота»
Это совершенно справедливое замечание. Зафиксировать как решение и контекст для будущих сессий.
Триггер (RSI/volume/dump)
↓
[НЕТ NewsFilter — нет исторических Telegram-данных]
[НЕТ EventAnalyzer — нет Claude]
↓
proxy_decide() — простое правило:
if regime in (bull, chop) and rsi не overbought:
return proceed
↓
RiskManager → SimulatedTrade
Триггер (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-результаты (особенно −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.
Решение: дефолт депозита в 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.
Контекст: добавили 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 пар. Причины:
- Backtest был без Claude (proxy decisions). Реальный Opus может отказывать на плохих XRP-сетапах через анализ новостей.
- Backtest был с lenient-chop (открывал в chop) и ATR-stops (которые тоже не помогли). Production strict mode может давать другую картину.
- Меняя ALLOWED_PAIRS до live — рискуем переоптимизировать под исторические данные (overfitting).
После 30+ live-сделок на $300:
- Прогнать симвoл-статистику на реальных данных
- Если XRP/AVAX продолжают терять — убрать из
ALLOWED_PAIRS - Заменить на LINK / DOGE / TON если хочется расширения
Принцип: данные → анализ → решение. Не наоборот.
Если бы 22 убыточные XRP-сделки не существовали:
- Total trades: 178 → 156
- Total PnL: −$36 → −$36 + $19 (избегаем XRP-потерь) = −$17
- Win rate: 35.96% → ~38%
Не game-changer, но улучшение. Если live подтвердит — убираем XRP первым.
Контекст: после всех экспериментов прогнали 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 теряет редкие хорошие средне-качественные сетапы вместе с шумом
🌟 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 работает.
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 по двум причинам:
- Разница в backtest минимальна (lenient −0.07% vs strict −0.54% за окно — статистически близко)
- Главное: в 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 исчерпал свою полезность. Дальше — наблюдение.
Контекст: проверяя что 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)) не срабатывал.
events.NewMessage(chats=...)для Telegram-каналов в Telethon работает нестабильно — зависит от формата chats (entity vs ID vs username) и версии библиотеки- Возможно нужно использовать events.ChannelMessage специально для каналов
- Возможно race condition при регистрации handler
Не углублялись в root cause — переход на более надёжный механизм важнее.
Переписали _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 заработал:
- 5 news_raw сохранены в БД
- NewsFilter (Haiku) обработал — 2 признал релевантными (
bullish, BTCUSDT) - 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.
Пользователь принёс 9 идей от Qwen AI о том как улучшить систему. Большинство — преждевременная оптимизация для системы где ещё нет ни одной живой сделки (ансамбль моделей, scale-out, корреляционный фильтр, ферма стратегий и т.д.).
После разбора только 2 идеи прошли фильтр "расширение контекста без слома работающего":
- Funding rates с Binance Futures
- Макро TradFi (DXY/US10Y/SPX)
Остальные либо требуют данных которых нет (нужны живые сделки), либо архитектурно избыточны (MAX_OPEN_POSITIONS=1 убивает корреляционный фильтр), либо опасны для философии проекта (шит-альты).
Реализовано: 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 не несёт сигнала, но и не мешает — токены минимальные.
Прошли через 3 источника за один вечер:
Логика: бесплатно, без ключей, годами стабильно. Тикеры 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 не разблочат. Нужен другой источник.
Логика: польский финансовый сайт, бесплатно, без ключей, не блокирует датацентры (раньше работал годами в 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.
Почему 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 →us10yDTWEXBGS— Nominal Broad U.S. Dollar Index →usd_idxSP500— S&P 500 closing price →spx
Облажался при выборе: классический 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).
Фикс: переименование ключа dxy → usd_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-индикатор.
Решение: компонент должен работать в idle-режиме, не падать.
Если ключа нет:
- Один WARNING при старте с инструкцией как получить ключ
- Никаких HTTP-запросов, никакого спама в логах
- Бот работает дальше, EventAnalyzer корректно обрабатывает
macro=None - Просто секция "## МАКРО" не появляется в промпте Opus
Это позволяет деплоить без ключа и добавить позже без лома.
Эти данные — только контекст для 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_contextJSONB → потом можно анализировать корреляции макро→решения
Тесты: +22 unit-теста (10 на FRED парсинг + 12 на funding rates).
-
Не верить "бесплатным API без ключей" — они умирают. Stooq до апреля 2026 был эталоном. Сейчас с captcha. Yahoo раньше работал, теперь блокирует датацентры. FRED стабилен потому что государственный — это нужно учитывать при выборе.
-
Проверять серии при выборе FRED-данных. Не предположил что DTWEXBGS — это broad TWI, не ICE DXY. Облажался один раз — лог
dxy=118пользователь сразу заметил. Урок: тратить минуту на проверку что выбираешь. -
Важно отличать "контекст" от "триггера". Все 9 предложений Qwen смешивали эти роли. Контекст обогащает решение, триггер инициирует его. Их добавление имеет разную стоимость и разные риски.
-
make buildне нужен для Python-правок. В docker-compose.yml код смонтирован volume'ом —make restartдостаточно. Это сэкономило 3 минуты × N перезапусков.
После сессии починки 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.
Выбраны топ-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 (недавно ребрендился).
Главный фильтр меняется с глобального на per-pair:
Старая логика (v1.10):
Можно лонг → BTC > EMA-200 1d (одно условие на ВСЕ пары)
Новая (v1.11):
Можно лонг по ALT → ALT > EMA-200 1d (своя для каждой пары)
Глобального BTC-фильтра больше нет. Бот может открывать лонг по альту даже когда BTC в transition.
Pure per-pair имеет очевидную опасность: при резком дампе BTC -5%+/час все альты валятся вместе. Защита через два новых stoppers:
Свежий price_dump_1h на BTCUSDT→ SKIP даже на сильном setup'е по альту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_PAIRSbot/data_sources/coingecko.py— SYMBOL_TO_CG_ID (chainlink/cardano/polkadot/cosmos/arbitrum)bot/agents/event_analyzer.py— SYSTEM_PROMPT (4 секции переписаны)
- Список торгуемых пар: 6 → 11 с описанием каждой
- Обязательные условия: пункт 1 (per-pair вместо BTC), новый пункт 7 (защита от BTC dump)
- Stoppers: per-pair фильтр, BTC.D >+1%/h, price_dump_1h на BTC
- Новый блок "PER-PAIR РЕЖИМ": явное описание trade-off с этой стратегии
- Сценарий A2: новый win-кейс — альт в собственном bull при BTC в transition
- Корреляции: добавлены LINK/ADA/DOT/ATOM/ARB (нарративы и beta)
- Принцип про корреляции: переписан с акцентом на per-pair риск
- Примеры 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_PAIRStest_smoke::test_coingecko_mapping_covers_all_pairs— все ALLOWED_PAIRS имеют CoinGecko IDtest_smoke::test_system_prompt_per_pair_filter_v1_11— регрессия на per-pair логику в SYSTEM_PROMPT (чтобы случайно не вернуть BTC-only фильтр)
Тестов: 101 → 103 зелёных.
Пользователь резонно заметил: 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 в разы. Проверим.
Создан docs/rollback.md — описывает как откатиться на v1.10 (если per-pair даст плохой результат) или на v1.9 (если что-то сломалось фундаментально). Принцип: всегда через git revert, без reset --hard.
-
Стратегия зависящая от единственного глобального фильтра — фрагильна. Пока BTC под EMA-200, бот молчит независимо от качества другого контекста. Per-pair фильтр это исправляет.
-
Pure per-pair требует явных stoppers против корреляционного риска. Иначе бот может войти в SOL когда BTC валится, и получить -8% за час.
-
Расширение пар через ALLOWED_PAIRS — низкая стоимость, высокий effect. 95% инфраструктуры уже автоматически работает с любым ALLOWED_PAIRS. Это правильная архитектура.
-
Документация отката заранее > попытки разобраться в кризисе. Создание
rollback.mdДО того как что-то сломалось — это инвестиция в будущую безопасность.
Полный ресерч проекта с разбором сильных/слабых сторон выявил 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_usdcompute_metricsвозвращаетgross_return_pct,fees_usd,fees_pct_of_depositprint_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 раз
-
Тесты, документация и код могут расходиться. Confidence-sizing был полностью оттестирован, но никем не вызывался. Регулярные code walkthrough важнее наращивания test coverage.
-
Default fail-open опасен в торговом коде. Last-resort fallback'и которые "разрешают" работу при сбоях — это пропуск катастрофы.
-
Race conditions сложно увидеть в коде. Trailing stop выглядел корректно при первом чтении. Только когда задумываешься "что если процесс упадёт между этими двумя строчками" — становится ясна проблема.
-
Backtest без расходов — это маркетинг, не аналитика. Любой strategy backtest должен начинаться с реалистичных commission/slippage.
-
Recovery должен детектить проблему даже если не может её решить. Auto-recovery опасен. Detection + alert почти всегда лучше.
Прогон 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)
Вывод:
- Стратегия в proxy-режиме (без Claude) убыточна даже без расходов: EV на сделку = −0.27%.
- Расходы критичны — 0.25% за круг даёт −18.83% за 2 года при текущей частоте сделок.
- Backtest не v1.11 — альты не работают. Синхронизация = отдельная задача (это всё равно proxy без Claude).
- Наша ставка: Claude поднимет WR с 35% до 45-50% через отсев слабых сетапов. Валидация — только paper trading.
CLAUDE.md обновлён — раздел "Ожидаемые результаты" заменён реальными цифрами + 4 сценария (pessimistic/base/optimistic/catastrophic).
После 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 — нет валидации
Принят гибридный путь:
- Поднять депозит paper до $2000 (5 × 35% = $700 × 5 = $3500 max notional влезает с буфером, размеры в % как в backtest)
MAX_OPEN_POSITIONS = 5- Новая константа
MAX_POSITIONS_PER_SYMBOL = 1(защита от двойной ставки на одну пару если B5 и B3 совпадут) - Расширить backtest engine под multi-position для валидации:
--max-open,--deposit,--max-per-symbol,--reversal-mode,--disable-btc-stopperCLI флаги; размер позиции от free_balance - Обязательный rollback-doc (
docs/rollback.md) для отката на single-position перед live
| Метрика | 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%
-
B5/B3 имеют real edge: PF 1.29-1.35, Sharpe positive, MaxDD ~19%. Это лучшее что у нас есть.
-
MAX=5 не улучшает per-trade edge — WR/PF/Sharpe ниже на небольшие величины. Но усиливает абсолютный compound в 1.7×. Trade-off: больше шума ради больше данных.
-
Walk-forward алармирует: 91% окон убыточны. Стратегия выживает за 3 года только за счёт sequence of returns (1-2 крупных bull-окна компенсируют все остальные). В live это означает что 9 из 11 первых "месяцев" мы будем терять, и положительные периоды редкие но крупные.
-
Это ПРОКСИ без Claude. Реальная ставка стратегии — что Claude поднимет WR с 35% до ≥45% через отсев катализаторов и плохих сетапов. Это будем измерять в paper.
После 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-position98a9d1f— 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 отрицательный → переписать стратегию