Тема
Разбор торговой сессии harvester-engine 11–14 сентября 2026
Дата составления: 15.09.2026. Наблюдения относятся к UTC 14.09.2026.
Граница воспроизводимости. Отчёт составлен по живым read-only запросам, выполненным штатным
scripts/analysis/forensics.sh, SQLitepositionsиorders, витрине ClickHousepositions_wide, экономическому ledger,stop_frames,admission_attempts, эпохамconfigиruns, а также по прочитанной реализации. Отдельный неизменяемый экспорт исходных ответов в этой работе не сохранён. Поэтому приведённые числа подтверждают тот прогон, но не дают полной автономной повторяемости без повторного доступа к тем же источникам.Отчёт фиксирует исследование и дефекты аналитической поверхности. Исправление скриптов подготовлено в отдельном worktree
fix/analytics-report-defects, но на момент составления не слито и не развёрнуто. Новые торговые пороги этим отчётом не назначаются.
1. Окно и деньги
| Показатель | Значение | Источник |
|---|---|---|
| Позиций | 22 | SQLite positions / ClickHouse ledger |
| Первое исполнение BUY | 11.09 18:48:18.264 UTC | запрос исполнений входа |
| Последнее закрытие | 14.09 15:25:35.746 UTC | positions.closed_at |
| BUY cash | $173.59025 | экономический ledger |
| Net returns | $169.09061 | экономический ledger |
| Итог | −$4.49964 | разность cash и returns |
Положительный результат был у 18 позиций и составил +$8.19974. Четыре отрицательные позиции дали −$12.69938. Сумма сходится: 8.19974 − 12.69938 = −4.49964.
| Финальная причина в позиции | Количество | PnL |
|---|---|---|
exit_target | 16 | +$7.402139 |
| Выходы maker-заявками по рангу | 2 | −$4.000000 |
resolution | 4 | −$7.901779 |
| Итого | 22 | −$4.499640 |
Экономический журнал даёт дополнительное разложение того же потока:
| Группа ledger | Количество | Shares | Cash | Fees | PnL |
|---|---|---|---|---|---|
| BUY fills | 23 prints | 186.469563 | −$173.59025 | — | — |
| SELL fills | 26 fills | −175.410000 | +$161.16482 | $0.04398 | −$3.045068 |
| Settlement | 4 | −11.050790 | +$7.92579 | — | −$1.446299 |
| Итого | — | — | −$4.49964 | — | −$4.491367 |
Сумма SELL cash уже указана после комиссии; повторно вычитать $0.04398 из $169.09061 нельзя. 23 записи BUY включают два частичных исполнения одного входного ордера; количество записей исполнения не равно числу позиций.
Cash-result совпадает. Разница между ledger realised −$4.491367 и суммой positions.realized_pnl_micro_usd −$4.499640 составляет $0.008273 и объясняется residual basis. Это не независимый аудит кошелька или on-chain cash-flow: отдельный неизменяемый экспорт в работе не сохранён и новая RPC сверка не выполнялась.
Финальная причина позиции скрывает часть stop-истории: частичный защитный SELL может быть записан в orders, после чего остаток доезжает до redeem и финальная строка получает resolution.
В исследованном окне встречались конфигурационные эпохи v66-r3…v72-r3. Новый max_entry_price=.75 вступил 13.09 в 09:17:52 UTC, уже после последнего входа в 06:31:58 UTC; следовательно, сравнение эффекта этого изменения по данным данного окна не доказано. В отчёте не делается причинный вывод о влиянии max_entry_price.
В проверенных эпохах также зафиксированы изменения: v66 — budget/market 5, DCA выключен; v67 — budget 10, DCA включён с inside-spread; v68 — min_probability_rank=4, max_shares=10, fill_budget=18000, reprice tolerance 50, entry_window=NULL; v70 — total_budget=990 вместо 100, circuit loss 15; v71 — reactive drift 10 вместо 20; v72 — предел цены входа .75 вместо .95 (сохранённые значения 750 и 950). Обозначения в этом абзаце сокращённые; это перечень наблюдавшихся изменений, а не готовый набор ключей и значений для записи в config.db. Единицы остальных параметров здесь не переопределяются. Одновременно менялось несколько условий, поэтому причинный эффект отдельного параметра не выделен.
Основной зафиксированный build сессии: ddefc9506e7f95090f6041c74a9fe89c7331eda9.
2. Wellington: фактическая защитная цепочка
Позиция:
text
CID: 0xb8212f3b1e91a749efb92941ba93606d38f7ad57d6b5130de09319284419d5dd
signal: 1789212094637-000000000733-89dbbb5c75fbb662
BUY: 10 @ 0.92, 12.09 11:24:49.948 UTCПеред стопом были три rank-maker SELL: .71 в 01:14:54.857, .70 в 01:15:54.870 и .69 в 01:16:55.855 UTC; fills не было. В 01:17:07.247 сработал stop-preemption, в 01:17:07.249 был создан stop-ордер, а в 01:17:07.348 состоялось исполнение FAK-ордера с ролью sharp_stop_confirmed. Все перечисленные времена защитных продаж относятся к 14.09 UTC:
text
SELL fill: 8.33 @ 0.12
gross: 0.9996
fee: 0.04398
net: 0.95562
остаток: 1.67; settlement 14.09 12:23:00.890 UTC
redeem: @ 1.00; финальное подтверждение 12:28:40.655 UTC
PnL: −6.57438Кадр стопа в 01:17:06.928 имел bid=.13, ask=.47, threshold=.35, возраст 20 ms и debounce 60 s. Это был кадр fired=1. Вокруг эпизода записано 256 кадров и четыре эпизода, из них 254 кадра с fired=1; взведение зафиксировано в 01:16:06.921 UTC. Данные покрывают только интервал 01:17:06.928…01:26:45.262 и не являются непрерывной будущей ликвидностью.
Текущий пол исполнения вычисляется как floor = threshold − margin и удерживает стоп только при bid < floor (strategy.rs:6103, runtime_config.rs:360). Для этого кадра при margin < .22 bid .13 ниже пола и стоп удерживается; при margin = .22 пол равен .13, строгое условие не выполняется; при большем отступе этот bid также проходит. Это объясняет ценовое условие, но не выбирает значение отступа и не доказывает исполнение альтернативной заявки. Формула имеет нижнее ограничение в один pip; пример выше относится к указанному диапазону цен. Gamma подтвердил итог NO=1: это объясняет выплату остатка, но один такой случай не обосновывает отключение стопа. Арифметика фактического результата: −9.20 + 0.99960 − 0.04398 + 1.67 = −6.57438.
3. Контрольный Karachi
| Событие | Факт |
|---|---|
12.09, CID 0xe6d8e5f78f4e6f17e6edd63024d10c1276f1c7d720593412f7b2f0fd4b334f8a | BUY 7 @ .68, фактически 3.125; остаток ордера отменён как strategy_entry_withdraw; resolution 0; loss −$2.125 |
13.09, CID 0x4a9bf9ca45852af7de919d5b2a1e20a8210449516c7432f7fd93a61a1bece765 | BUY 10 @ .95; rank SELL .70 без fill, затем .69 с fill; NO=0; сохранено 6.9 против удержания |
14.09, CID 0x75bcb515d56eea1bb05e73acae0184618f97011bae8b6ae6a521483ab0241052 | BUY 10 @ .91; rank SELL .78 без fill, затем .77 с fill; Gamma наблюдал NO=.9995, финальный исход ещё не подтверждён; текущий loss −$1.4 |
Karachi показывает противоположную цену удержания: при разрешённом NO=0 позиция теряет весь остаток. Два описанных эпизода недостаточны для выбора числового stop-floor.
Положительные факторы сессии: 16 целевых выходов дали +$7.402139, один исполненный ранговый выход в Karachi 13.09 сохранил $6.9 против нулевой выплаты при удержании, а кадр Wellington был свежим (20 ms). Отрицательные факторы: четыре убыточные позиции перекрыли результат 18 прибыльных; Wellington FAK создал остаток меньше минимального размера SELL, допускаемого движком; частичные BUY-позиции ниже этого размера также не могут пройти обычный выход или стоп через ExitSizeDecision::DustStranded. Дополнительно аналитика ошибочно пометила реальные частичные покупки как entry_filled=N.
4. Дефекты аналитики
4.1. forensics.sh исключает реальные BUY-филлы
В scripts/analysis/forensics.sh:248 проверка entry_filled требует status='FILLED'. В наблюдавшихся строках позиций 251, 254 и 263 были реальные BUY-филлы, но соответствующий ордер завершился не статусом FILLED; для Karachi подтверждён статус CANCELLED с причиной strategy_entry_withdraw. Такой вход исключается из отчёта, хотя позиция существует. Это расходится с фактической моделью данных: единицей экономического анализа должен быть каждый реальный BUY-fill.
README scripts/analysis/README.md:163-171 отдельно документирует dust и отсутствие survivorship, но теперь согласовано считать в EV все фактические BUY-филлы. Исправление должно менять критерий на наличие положительного fill, сохраняя отдельную маркировку частичного и dust-входа.
4.2. cmd_positions создаёт ложный PHANTOM для REDEEMED
cmd_positions (scripts/analysis/forensics.sh:1275) применяет phantom-проверку к REDEEMED-позиции. Для строки 251 это даёт ложный phantom, хотя её финальный статус означает redeem-путь и не доказывает отсутствие реального выхода. Эта ошибка создаёт ложную метку PHANTOM у позиции. Глобальный предикат SCH_PHANTOM_PRED (forensics.sh:253) используется в отдельном контуре очистки stop-выборки; прямое влияние именно этой ложной метки на весь EV-отчёт в данной работе не измерено.
4.3. stops ищет финальную причину вместо stop-цепочки
SCH_STOP_PRED в scripts/analysis/forensics.sh:244 фильтрует только exit_reason LIKE 'stop_loss%'. Позиция Wellington в финальной строке имеет resolution, поэтому cmd_stops не показывает её защитную цепочку, несмотря на подтверждённый sharp_stop_confirmed SELL и fill 8.33 @ .12.
Роли stop-ордеров уже являются отдельными сохраняемыми значениями sharp_stop, sharp_stop_confirmed, sharp_stop_partial и sharp_stop_confirmed_partial (ports/intent_role.rs:124-135). Для анализа попыток и фактических филлов нужно читать эту колонку и связывать цепочку по token_id + signal_id, а финальную exit_reason использовать только как результат позиции.
4.4. stop-counterfactual дублирует эпохи и выбирает неправильный exit
В ClickHouse-ветке stop-counterfactual соединение positions_wide с stop_frames идёт только по signal_uid (forensics.sh:2080-2130). Для Wellington это даёт две строки эпох/состояний: v71/closed_at=NULL/exit=NULL и v72/resolution/exit=1. В расчёте dfact (:2264-2273) выбирается финальная цена 1 и размер кадра 10, хотя фактический stop-fill был 8.33 @ .12.
Приоритет класса fire корректен: cls сначала проверяет ep_fired=1 (:2218), поэтому Wellington не является подтверждённым no-fire. Дефект состоит в связывании фактического выхода и дублировании эпох: counterfactual строка остаётся, но её денежная интерпретация неверна.
4.5. ClickHouse-витрина обнуляет фактический остаток закрытой позиции
В marts.rs:165-188 ветка закрытых позиций безусловно ставит нулевой inventory, если closed_at заполнен, без проверки завершённости redeem. Для Mexico, SQLite position 263, SQLite хранит остаток 8773 micro-shares и redeem_status=FAILED, тогда как positions_wide показывает inventory 0. Поэтому статус позиции, остаток и результат погашения нельзя сводить в один признак «закрыта». Это дефект витрины/классификации, а не доказательство денежной потери.
4.6. Варианты стопа и частичного входа
| Вариант | Возможная выгода | Риск/цена | Как проверять |
|---|---|---|---|
Существующий floor = threshold − margin | Ограничивает слишком дешёвое исполнение и сохраняет текущий контракт | Ниже пола позиция может дойти до нулевой выплаты | Исправленная выборка stop-fill и контрфактов по фиксированным горизонтам |
| Нижний предел цены выключен | Продажу не блокирует это ценовое условие | Это условие не ограничивает цену исполнения; возможна продажа на кратком провале | Полная серия фактических цен исполнений и глубины |
| Адаптивный пол | Может учитывать глубину, время и восстановление | Новый контракт и сложность без достаточных данных | Непрерывная книга/очередь, latency, recovery и сравнимые эпохи |
Рекомендация — сначала исследовать существующий пол. Порог и отступ не назначены. Полное отключение стоп-защиты также не обосновано: Karachi 13.09 показывает риск удержания до нулевой выплаты.
Для частичного входа остаются разные ограничения: сохранение контекста добора, оставшийся бюджет и минимальный размер заявки. Восстановление исходной закреплённой цены вместе с ограниченным DCA — исследовательское направление (strategy.rs:9851). Переход к FOK или taker-поведению требует отдельной оценки стоимости исполнения и проверки фактических fill-результатов; он не следует из этой сессии.
| Вариант частичного входа | Возможная выгода | Ограничение и проверка |
|---|---|---|
| Восстановить исходный контекст цены и использовать DCA в прежних лимитах | Устранить пропуск добора только из-за рестарта | Проверить актуальность цены, сетку, бюджет и отсутствие повторного BUY; восстановление контекста само по себе не решает недостаток бюджета |
| Сохранить текущую механику | Не вводить новую торговую логику | Измерять капитал и время в остатках; проблема пропуска DCA после рестарта остаётся |
| Изменить способ входа на FOK либо немедленное исполнение | Проверить возможность уменьшения частичных входов | Сравнить пропущенные входы, фактические исполнения, комиссии и цену; FAK сам по себе не исключает частичного исполнения |
Минимальный размер исходной maker-заявки не гарантирует такого же минимального размера фактического исполнения. Исследование DCA должно учитывать это отдельно.
5. Отдельный остаток Mexico и граница денежной сверки
Для Mexico (CID 0xe585ec89c7ebdba6839e836db032e86e602cdf50ba921e08bbc407ab8d52e0ae, SQLite position 263) закрытая строка содержит остаток 8773 micro-shares и redeem_status=FAILED в SQLite; ClickHouse positions_wide показывает нулевой inventory_shares. Экономический ledger даёт realised −4.491367, а positions — −4.499640; расхождение 0.008273 объясняется residual basis. По имеющимся данным это не доказанная потеря денег: для такого вывода нужен отдельный разбор redeem-транзакции, остатка и записи ledger. Причина redeem FAILED в этой работе не исследована.
Идентификатор позиции: pos-2484906-ord-directional-entry-1789236285461-000000119175-8926c09a4ed57761-1789236285461-000000119176.
Реконструкция остатка по журналу исполнений: два BUY на 3.880878 и 3.157895 доли (cost=3.659667 и 2.977894), всего 7.038773 доли и 6.637561 стоимости; SELL 7.030000 долей дал net 6.959700, basis 6.629288, realized 0.330412; остаток 0.008773 доли имеет basis 0.008273, а строка позиции отражает realized 0.322139. Это объясняет, почему ledger и позиция имеют разные realized при совпадающем cash-result.
Отдельная частичная Mexico-позиция: CID 0x04a1086fe2baea70f43270ca9ca9e204c627bf9d6e5862a78fc32cac8df315e5, BUY 1.30579 @ .81, redeem 1, PnL +$0.248101.
6. Существующие механизмы и их границы
Пол исполнения и план защитной продажи уже существуют. Их наблюдаемость включает pm_engine_stop_execution_floor_held_total, pm_engine_stop_exit_plan_total{kind} и pm_engine_exit_residual_stranded_total{origin}. Проверка наличия кода не доказывает, что каждый механизм был реально использован в последнем runtime. DCA-метрика присутствует в исходниках сборки 40329ef828bb4016ea515976c37429e530c9cf82, которую сообщает запись runs для запуска r76-c4ca86abf2834ff8954bd189a7f1c602 от 14.09 19:07:01.622 UTC. Включение коммита 6c19b8a2 проверено через git merge-base --is-ancestor. Это более поздний запуск, чем последнее закрытие исследуемой сессии; проверка манифеста развёртывания здесь не выполнялась. Фактическая запись метрики pm_engine_dca_skip_total{reason} в этой сессии отдельно не проверена.
Семантика этих рядов ограничивает выводы: pm_engine_dca_skip_total{reason} считает такты/оценки, а не эпизоды; pm_engine_stop_exit_plan_total{kind} растёт только после успешного emit_order для плана FAK/FOK и не включает синхронные отказы, обычные лимитные, ручные и аварийные продажи; у него семь значений kind. Отказ FloorUnreachable учитывается отдельно в pm_engine_stop_execution_floor_held_total. Ряд pm_engine_exit_residual_stranded_total{origin} считает эпизод по сигналу в памяти с origin=partial_sell или entry_shortfall; после рестарта тот же остаток может быть посчитан повторно. Эти ограничения описаны в docs/operations/alerts-and-monitoring.md.
Семь значений плана: top_absorbs, remainder_sellable, named_cap, deepened, shrunk, tail_unavoidable, book_unknown. Счётчик удержания ценовым ограничением считает оценки, поэтому его нельзя приравнивать к числу уникальных стоп-эпизодов.
Причины пропуска DCA: restore_backoff, buy_already_resting, target_price_not_pinned, pinned_price_off_grid, remaining_below_min_size, no_progress_limit, post_only_would_cross. Существуют и сообщения в логах; это не означает наличие полной единой истории решений с ценой, бюджетом, книгой и последующими исполнениями. Новая метрика не восстанавливает события прошлой версии задним числом.
В strategies/directional/strategy.rs:9851 при отсутствии контекста закреплённой цены происходит пропуск; восстановление цены после рестарта ещё не реализовано и является отдельным направлением исследования. Восстановление контекста не устраняет другой отказ — оставшийся бюджет может не покрывать минимальную заявку. Также не следует утверждать, что биржа запрещает FAK меньше 5 долей: в этой работе подтверждён только внутренний гейт движка.
7. Что нужно измерить перед выбором пола
До числового решения требуется восстановить исправленную выборку:
- все фактические BUY-филлы, включая
CANCELLED-ордера с положительнымfilled_shares; - все попытки стопа по
orders.exit_role, их нулевые, частичные и полные исполнения, связывая цепочку повторной продажи поtoken_id + signal_id; - для каждого решения — книгу, best bid/ask, глубину, возраст, latency, конфигурационную эпоху, threshold и фактически применённый floor;
- цену и ликвидность после решения на фиксированных горизонтах и до resolution;
- полный путь решений
entry → reprice → DCA, чтобы не смешивать эпохи и действия; - непрерывную историю будущей книги и очереди. Текущие
stop_framesпокрывают отдельные кадры и не доказывают непрерывную будущую ликвидность; - residual/redeem reconciliation и причину
redeem FAILEDдля Mexico.
В проверенной выборке 22 связанных со входами записи admission_attempts с возрастами книги 18…2639 ms, что укладывается в лимит 3000 ms. Это подтверждает возраст этих записей, но не доказывает непрерывность всей ленты и не заменяет историю книги и очереди. Возраст книги при входе Wellington составил 32 ms, при рассмотренном стопе — 20 ms. Эти замеры не подтверждают устаревшую книгу как причину данных двух решений.
8. Рекомендация и статус
Первый шаг — исправить аналитические связи и повторить ограниченный анализ. До этого нельзя надёжно сравнивать долю проигравших позиций, закрытых реальным stop-fill, среднюю фактическую цену stop-fill, качество стопов и стоимость удержания ниже пола.
После исправления следует сначала проверить существующий простой механизм floor = threshold − margin в теневом/наблюдаемом режиме. Он сохраняет maker-only rank-защиту, потому что floor применяется только к stop-пути до отмены rank-владельца (strategy.rs:6103), а rank SELL имеет отдельную maker-only валидацию. Новый адаптивный floor или новый торговый контракт следует рассматривать только после серии полных stop-контрфактов; текущих данных для такого решения нет.
Статус работы: исправление аналитических отчётов подготовлено в отдельном рабочем дереве, но не завершено — полный набор проверок не выполнен, изменения не слиты и не развёрнуты.
Пользователь согласовал одну работу класса «дефект» без новой карточки OpenSpec и включение всех реальных покупок в EV, в том числе частичных и мелких остатков. Это согласование исправления отчётов не является выбором новых торговых параметров.
9. Источники и пределы доказательности
Для живых результатов использованы запросы к SQLite и ClickHouse, перечисленные во введении. Команда forensics.sh positions --engine --json воспроизвела ложные entry_filled=N и PHANTOM; команда stops сообщила об отсутствии стоп-закрытий при фактической цепочке Wellington. Ограниченный запрос к positions_wide FINAL и stop_frames воспроизвёл две строки разных эпох. Полный stop-counterfactual с запросами будущих цен не запускали.
Прочитанные источники реализации и описания:
- Штатная форензика (
scripts/analysis/forensics.sh): фильтры входов и стопов,cmd_positions, соединение данных и денежная формулаstop-counterfactual. - Контракт аналитических команд (
scripts/analysis/README.md): прежнее исключение частичных входов и границы выводов об EV. - Проекция позиций (
crates/pm-engine/src/observability/analytics/marts.rs):position_row, обнуление остатка при заполненномclosed_at. - Реестр позиций (
crates/pm-engine/src/engine/position_registry.rs): сохранение остатка после продажи и расчёт результата закрытой позиции. - Стратегия (
crates/pm-engine/src/strategies/directional/strategy.rs): ценовой запрет до отмены существующего выхода, причины пропуска DCA. - Параметры исполнения (
crates/pm-engine/src/strategies/directional/runtime_config.rs): расчёт нижнего предела цены. - Решение о размере выхода (
crates/pm-engine/src/strategies/directional/exit_size_decision.rs):DustStrandedдля остатка ниже минимального размера. - Роли заявок (
crates/pm-engine/src/ports/intent_role.rs): различение защитных продаж. - Метрики: единицы счётчиков и ограничения.
Строки исходников в тексте относятся к прочитанной версии до исправления отчётов; после изменения файлов их номера могут сместиться. Таблицы этого отчёта сохраняют результаты анализа, но не заменяют отсутствующий неизменяемый экспорт всех 22 позиций и исходных ответов. Полную построчную ведомость всех позиций здесь не восстанавливаем по памяти. Отдельный аудит кошелька и ончейн-балансов, причина redeem_status=FAILED, исполнение альтернативных заявок и прибыльность нового алгоритма остаются непроверенными. Один результат сессии не доказывает устойчивый EV.