Тема
Incident 2026-07-15 — стоп-каскад: 3 whipsaw из 4 стопов + учётный каскад fill-конвейера
Статус: расследование ЗАВЕРШЕНО (2026-07-17, workflow wf_8261b409: 9 агентов, 264 tool-вызова; классификация стопов верифицирована независимо по CLOB prices-history + Gamma). План исправлений одобрен оператором 2026-07-17. Фиксы — см. §Исправления.
Итог в деньгах (сверено с on-chain pUSD до $0.00003)
Эпоха с Reset 2026-07-15 00:56:53 UTC, старт cash $22.003709. За 03:20–11:06 UTC — 11 входов (maker BUY 5sh, все по ask 0.87–0.95); больше входов не было: в 11:26:16 circuit breaker (3 стоп-аута подряд) включил entry-drain, который держится до снятия оператором. Экономика дня: 7 виннеров +$2.43, 4 стоп-капитуляции −$6.63 → истинный поток −$4.196456 (кэш $17.807283 до внешнего депозита +$6.00 2026-07-17 09:41 UTC, tx 0x94dff1e9…). Booked realized был −$6.176456: расхождение ровно $1.98 — учётный каскад позиции 228 (см. ниже), исправлен в БД 2026-07-17 12:40 UTC (бэкап engine.db.bak-fillrace228-20260717-124039, CAS-UPDATE realized −1 675 000 → +305 000, size 2M → 0; после коррекции сумма БД = on-chain бит-в-бит).
Ключевой факт: отбор рынков был ХОРОШИМ, убыток сделали стопы
10 из 11 рынков разрешились NO=1 в нашу пользу (единственный фундаментальный лузер — Istanbul 27°C). Все 11 входов прошли по аскам из зоны 0.85–0.95, открытой расширением бенда 2026-07-15 02:02 (старый верх 0.85 заблокировал бы все 11). Стопы против удержания до резолюции: −$3.32 (три whipsaw стоили $5.86, Istanbul сэкономил $2.54). В 2 из 3 whipsaw цена FAK-филла ниже минимума всей последующей минутной истории CLOB — капитуляция продавала в яму сквозь тонкую книгу.
Позиции дня
| Поз. | Рынок (July 15) | Вход UTC @цена | Исход | PnL |
|---|---|---|---|---|
| 223 | Tokyo 35°C | 03:20 @0.921 | exit 0.99 (мин 0.874) | +$0.345 |
| 224 | Seoul 29°C | 03:31 @0.940 | exit 0.99 (мин 0.735 — ближе всех к стопу, confirm корректно молчал) | +$0.25 |
| 225 | Seoul 26°C | 04:00 @0.895 | exit 0.99 за 26 мин | +$0.475 |
| 226 | Wuhan 39°C | 04:18 @0.939 | exit 0.99 | +$0.255 |
| 227 | Guangzhou 32°C | 04:27 @0.880 | exit 0.99 partial 4.9916sh; residual 0.0084sh REDEEMED | +$0.550 |
| 228 | Chongqing 42°C | 04:54 @0.929 | exit 0.99 полные 5sh (учётный каскад, исправлен) | +$0.305 |
| 229 | Beijing 39°C | 07:14 @0.938 | СТОП 07:23 net 0.6396 — whipsaw | −$1.492 |
| 230 | Istanbul 27°C | 09:05 @0.930 | СТОП 11:26 net 0.5075 — justified (YES выиграл) | −$2.112 |
| 231 | Moscow 22°C | 09:06 @0.933 | СТОП 11:00 net 0.5295 — whipsaw (fair в моменте) | −$2.017 |
| 232 | Moscow 25°C | 09:22 @0.940 | exit 0.99 (мин 0.83) | +$0.25 |
| 233 | Moscow 24°C | 11:06 @0.860 | СТОП 12:02 net 0.6589 — whipsaw (quote-phantom) | −$1.005 |
На событии Moscow одновременно жили 3 бакета (22/24/25°C) — 2 стопнулись на одной траектории температуры (концентрационный дефект selection-слоя).
Анатомия 4 стопов (все хронологии из docker-логов + лент Data API)
- 229 Beijing — whipsaw, предотвратимый. ARMED 07:18 (bid 0.654), debounce сбрасывался (bid возвращался >0.70), confirm 07:23:08 по ОДНОМУ прямому SELL-принту 200sh @0.6653 — при mid ≈0.80 (отскок 0.6965→0.815 уже шёл) и комплемент-потоке, имплицировавшем NO ≥0.731 весь эпизод (max BUY Yes 0.269). Через 6 минут mid >0.9; резолюция NO=1. Стоп-филл 0.6396 ниже любого последующего принта дня.
- 230 Istanbul — justified. Полтора часа осцилляций с корректным молчанием confirm (V-отскоки без принтов), с 11:06 монотонные lower-highs крупными принтами (0.78→…→0.56), confirm 11:26:16 по синтетике BUY Yes 37.82sh @0.44 → NO 0.56 (порог−14c). После стопа рынок умер до 0.0005, YES выиграл. Этот стоп = 3-й подряд → breaker TRIPPED (cause=ConsecutiveStopOuts{3}).
- 231 Moscow 22 — whipsaw по исходу, fair в моменте. Бид <0.70 ~100 мин, объёмный вакуум (~$40 ленты на весь обвал 0.93→0.54 — quote-pulling, не traded-капитуляция), confirm по синтетике 4.37sh @0.458 → 0.542 ≈ fair 50/50 момента; после нашего выхода дно 0.384, восстановление одним снапом 0.75→0.9985 сразу после endDate 12:00Z. Настройками стопа не предотвращался; предотвращался только гейтом на стороне входа.
- 233 Moscow 24 — whipsaw, предотвратимый (quote-phantom). Вход по ask 0.86 при bid ≈0.63 — позиция родилась с бидом ниже порога и провела 96% жизни в ARMED (54 мин, bid 0.57–0.68). Лента за все 54 мин НИ РАЗУ не печатала ≤0.70; за 64–66с до выстрела — покупки NO по 0.885–0.90. Confirm 12:02:35 по одному синтетическому принту 8sh @0.68 (порог−2c). Через 34 мин >0.9; резолюция NO=1.
Виннеры: ни один из 7 не опускался ниже 0.70 за время удержания — ложных срабатываний по виннерам ноль; проблема исключительно в качестве confirm-принта у пограничных обвалов.
EV (Harvester Yield Calculator v2, exit=0.99)
Как исполнено: p_e=0.9186, r=1.0 (стоп-контур механически исправен — контраст с инцидентом 07-14), s_eff=0.584 → w*=0.824 при факте w=7/11=0.636 → edge_margin −0.19. Counterfactual удержания (только оценка зоны, не EV-вердикт): w=10/11=0.909 < w*(r=0)=0.928 — зона 0.85–0.95 не окупается даже без стопов при июльском винрейте. Drain-период 15–17.07: 90 кандидатов прошли бы отбор, гипотетический NO-winrate ~93.5% (62 резолвлено, ride-to-resolution, без модели филлов) при w*≈0.89–0.90 — простой почти ничего не стоил.
LDI (первые форвард-данные F9): на входе ≈0 у всех 11 позиций — будущих стопников от виннеров не отличал; watch_arm_fak_states пуста (стоп-стейт не персистится).
Учётный каскад позиции 228 (fill-конвейер; гипотеза lost-update ОПРОВЕРГНУТА кодом)
Exit SELL 5@0.99 исполнен биржей двумя принтами в одну ms (2+3 акции; Data API подтверждает ровно два принта, дублей нет). Каскад: (1) коррелятор дважды учёл 2sh — пути apply_order_update (delta=size_matched−cum) и apply_trade (delta=matched) делят общий cumulative без взаимной идемпотентности (correlator.rs:397-501); порядок UPDATE-раньше-Trade даёт фантомный cum=4; (2) букинг второго филла откатился целиком по UNIQUE events.event_uid — uid имеет ms-разрешение (position_registry.rs:465), driver деградировал потерю букинга до error-лога + continue (strategy_driver.rs:610-707); (3) реальный принт 3sh отброшен инвариантом 4+3>5 (correlator.rs:423-439); (4) терминальный delta=1 закрыл позицию: realized −1.675 вместо +0.305, residual 2sh на CLOSED (AUDIT#9 честно записал — log-only). За день 7 InvariantViolation, из них 6 — безвредный паттерн 2×full-size; вредит только сплит-филл в одну ms. Отравлены были: realized, budget remaining (−$1.98), вход rolling-24h breaker, EV-датасет. Класс — семья PM-ENGINE-29 («филл-учёт молча расходится с биржей, движок продолжает»), но другой путь; PM-ENGINE-29 (absent-путь order_router) остаётся эскалированным отдельно.
Попутные находки
- Поз. 227: exit-cancel на 4.9916/5sh — синтетический Cancelled(Reconciled) после user-WS reconnect (биржа считала ордер полностью исполненным); residual 0.0084sh — артефакт «price quarantined» 15-знаковой fill-цены; доехал до REDEEMED, ущерб ~0. → PM-ENGINE-33.
- Первый эмит exit после КАЖДОГО филла отклоняется CLOB'ом «balance settling» (окно 4–5с без exit и без стопа, retry закрывает). → PM-ENGINE-34.
- entry_halt_state.triggered_at пишется в секундах, рендерится как 1970 (sec vs ms).
- Мост денег: несведённый микро-остаток $0.00003 (округление fees/redeem) — отдельная сверка fills-детализации по правилу no-dust.
- Drain не имеет собственного счётчика в funnel и виден только как entry_attempts>0 без ордеров; сигналы гаснут на debug-уровне (за 2 суток — 13975 тихо закрытых сигналов).
Решения оператора (2026-07-17)
План одобрен целиком (~/.claude/plans/live-peppy-goblet.md): P0 — fill-пайплайн exactly-once; двухисточниковое подтверждение стопа; born-armed вето входа; P1 — лимит 1 бакет/событие; drain-видимость; offline-свип порога. Открытые решения оператора: верх бенда (рекомендация 950→850), снятие drain (/api/local/resume), re-anchor бюджета (депозит $6 на кошельке), деплой.
Исправления
- 2026-07-17 12:40 UTC: коррекция БД поз. 228 (см. §Итог в деньгах) — применена, сумма эпохи сходится с on-chain бит-в-бит.
- Fill-пайплайн exactly-once — MERGED 6382ccdb (ветка fix/fill-pipeline-exactly-once, 6 коммитов fe26e082..6f5e8ef9): cross-path идемпотентность коррелятора (эффективный cum = max(Σ dedup-Trade, max UPDATE)), FillIdentity (exchange trade_id вместо ms-ts) + идемпотентный гейт has_event_uid, AccountingGuard (потеря money-bearing букинга / AUDIT#9 leftover / InvariantViolation → persistent drain reason=accounting_invariant + алярм; «continue without booking» устранён), GROSS-деривация цены принта (fee не искажает exit_price_pip), straddle-observability, empty-trade_id guard. Регрессия: реальный кадр-порядок 228 (UPDATE(2)→Trade(2)→ Trade(3)→UPDATE(5) в одну ms → exactly-once, realized +0.305). Адверсариальное ревью: 3 находки закрыты дофиксом; PM-ENGINE-35 (рестарт-гидрация OrderRegistry) заведён.
- Анти-whipsaw стоп-контур — MERGED (ветка fix/stop-confirm-corroboration, 7 коммитов 2dbb4ee5..6ca99ec1): двухисточниковая корроборация trade-confirm (deep∧large эскейп; прямой принт ↔ согласие комплемента; синтетика ↔ согласие прямой ленты; отказ ⇒ ARMED), born-armed вето входа (bid < стоп-порога на решении), selection-вето max_concurrent_per_event=1, детектор усечения окна свидетелей (PM-ENGINE-37 — полный фикс буфера), новые REQUIRED-ручки stop_loss.confirm_* + selection.max_concurrent_per_event (миграция config-migration-2026-07-17-stop-confirm-corroboration.sql — применять ПЕРЕД бинарём). Оракулы на числах дня: Beijing/Moscow24 → блок, Moscow22/Istanbul/Jeddah → выстрел. Ревью: WAF-дыра selection структурно закрыта существующим fail-fast; PM-ENGINE-36 (own-fill при RTDS off) заведён.
- Drain-видимость — MERGED 01403b0d (ветка fix/drain-visibility, 5 коммитов 03efdf77..df866c07): entry_halt статус + 6 счётчиков аддитивно в EntryFunnelTick (wire-совместимость покрыта тестом старого payload'а), blocked_drain в воронке, TG-напоминание об активном drain раз в 24ч + «entry halt cleared», SPA-баннер (PrimeVue), triggered_at приведён к ms (легаси-чтение толерантно).
- Финальные гейты после трёх merge: cargo test --workspace 4818 passed / 0 failed, clippy --workspace -D warnings чисто; фронтенд 629 bun-тестов + vue-tsc чисто.
- Предеплойные техдолг-фиксы — MERGED (решение оператора 2026-07-17): PM-ENGINE-31 staleness-probe стоп-контура (ревью-дофиксы: fill-дизамбигуация ExecutedUnbooked→drain, bound==probed release, placed_at рехидрация); PM-ENGINE-35 гидрация OrderRegistry + PM-ENGINE-29 interim terminal-but-budget-held (DCA-guard); PM-ENGINE-32(а/б)+33(а). Merge order_router.rs (tangle) резолвлен вручную, отдельный ревьюер подтвердил все 6 money-пунктов корректны. Гейты после всех merge: workspace 4857/0 + clippy чист.
- ДЕПЛОЙ 2026-07-17 ~19:50 UTC (
deploy-vps.sh engine-bot): бенд верх 950→850, бюджет anchor 28.003739 (remaining=23.807283=on-chain бит-в-бит; realized движка −4.196456 после коррекции 228). Миграция config-migration-2026-07-17 применена ПЕРЕД бинарём (5 REQUIRED-ключей verified; бэкап config.db.bak-stopconfirm-*). Startup: selection_cutoff=REMOVED, breaker 3/$7, без panic. Drain снят POST /api/local/resume (breaker не ре-drain — streak заслонён 232 exit_target). 0 позиций/ордеров. - НЕ верифицировано live (правило micro-live-verify): стоп-контур (confirm-корроборация/probe/капитуляция) в live не срабатывал — первая реальная капитуляция = верификация. Отложено оператору: SPA drain-баннер (engine-spa деплой), d_fav 2→1 (данные развернули рекомендацию).
Уроки
- Стоп-контур, который механически РАБОТАЕТ (r=1.0), переносит проблему из «стоп не исполнился» в «стоп стреляет по шуму»: качество confirm-принта = новый money-путь. Один принт ≤ порога — недостаточное основание капитуляции, когда второй источник (комплемент / прямая лента) противоречит.
- Вход по ask в книге с широким спредом рождает позицию с бидом ниже стоп-порога — стоп-машина с первой минуты в ARMED и ждёт любого шумового принта (Moscow 24).
- Расширение бенда — это изменение w*: верх 0.95 поднимает break-even winrate к ~0.93, которых июльский рынок не даёт. «Хотя бы небольшая доходность вместо простоя» при недостаточном винрейте = отрицательное ожидание с узким выигрышем и толстым хвостом.
- Филлы одного ордера, пришедшие сплитом в одну миллисекунду, — реальный биржевой паттерн; учёт филлов обязан быть exactly-once относительно БИРЖЕВОЙ истины (trade_id), а не времени доставки.
- Breaker сработал как задуман и спас от дальнейшей экспозиции, но «тихий» drain на двое суток — операционная дыра видимости.