Ответ на документ «События watchrobot», построчная сверка реализации с исходным техзаданием на метрики и план работ — сначала бесплатные и быстрые, потом контрактные.
Каждое утверждение ниже опирается либо на строку кода, либо на запрос к живой базе. Наличие модуля в репозитории доказательством не считалось: несколько правил написаны, покрыты тестами и при этом не выполняются в проде. Ссылки вида trusted_market.py:1062 — это точное место, где можно проверить.
Важная методологическая оговорка, которая касается всех статусов сразу.
Все 8 057 строк в таблице events записаны за последние 48 часов, а в
контейнере стенда стоит TRUSTED_EVENTS_ENABLED=0. То есть «доходит» сейчас
означает «правило прогоняется бэкфилл-ранами и даёт строки», а не «работает непрерывный
контур». Ниже слово «живой» используется именно в этом, ослабленном смысле.
Документ в целом добросовестный, и его методология лучше, чем у большинства отчётов такого рода. Но в нём девять фактических ошибок, и две из них изменили порядок работ.
Три решения в документе я бы сохранил как есть.
Контролёр вынесен в пункт 4 конвейера как «выключаемый». Подтвердил:
feed.coverage_gate, default=False, решение стейкхолдера
от 04.08 записано прямо в докстринге.
trusted_event_feed.py:44-54 · event_settings.py:110-118
Но следствие не проговорено. Каталог покрытия устроен fail-closed: ни один атом
не получает full по умолчанию. Значит, каждый статус
«доходит ✅» в таблице существует ровно потому, что гейт отключён. Включите его
обратно — и лента опустеет почти целиком, включая кривую, спреды и цену/объём.
Развилка бинарная, и её должен закрыть человек, а не код. Либо гейт не вернётся никогда — тогда 327 атомов, верификатор и материализатор превращаются в мёртвый груз, который вы продолжаете сопровождать. Либо вернётся при подписании контрактов — тогда в этот день лента гаснет, если атомы не промоутнуты заранее. Ни один из планов работ этого не учитывает.
41 798 баров по 339 облигациям, с 2021-09-30 по 2026-08-04 включительно,
лежат в ohlcv_daily. Ничего не докачивается.
ohlcv_daily ⋈ instruments → bond: 339 instr / 41 798 bars
Событий ноль потому, что вызов передаёт
evaluate_anomalies = kind == "stock", и ветка с
BOND_THRESHOLDS недостижима — вне trusted_rules.py
эта константа встречается только в тестах.
trusted_market.py:1062, :1201 · пороги на :638
Это не косметическая правка формулировки. Пока строка говорит «данные подтягиваются», пункт I.10 читается как «подождать», и из-за этого четыре требования ТЗ выпали из плана работ. На самом деле это одна строка кода и реплей по данным, которые уже собраны.
KEY_RATE_CHANGE_THRESHOLD_PP = Decimal("0.75"), и это ровно
M-RATE-1 из ТЗ. Направление события — conditional, а не
автоматический знак, и это правильно.
trusted_cbr.py:68, detect_key_rate_changes
Свечи есть у 53. Формулировка смешивает загруженность данными и наличие событий, а перечисление пяти тикеров создаёт впечатление полноты. distinct instrument_id, kind=price_volume_anomaly, active → 14
3635 событий вместо 681, последняя запись 15:00. Покрыто 140 облигаций из 473 — остальные не проходят гейт ликвидности либо не имеют сопоставимой базы. Разница между «2» и «333» существенна для планирования. distinct instrument_id, kind=credit_spread_move → 140 / 473
Все 60 видимых в ленте строк (12 active + 48 corrected) — это
WD — Отзыв кредитного рейтинга, все по облигациям Роснефти,
2020–2021, у всех direction=neutral. Отброшенные 426 — это
AF (342) и NW (84).
events kind=rating_action, группировка по коду действия
Формулировка «исторические 60 материальных событий показываются» создаёт впечатление, что пункт I.6 частично закрыт исторически. Он пуст: ни одного из требуемых ТЗ действий в ленте нет.
Обе записи имеют подтип payment_default_resolved (B-PAY-8) и
direction=positive: «обязательство исполнено — снят дефолт
по купону» и «…по погашению номинала». Событий самого факта невыплаты
(B-PAY-1…6) — ноль.
RU000A107AX1 · RU000A103SV6, cbonds-emission-default.v1
Пояснение «честные 2: наши эмитенты не дефолтились» не согласуется с этим: дефолты были, распознан только выход из них.
Воркер импортирует
reconcile_all_watched_factor_impacts as project_watched_factor_events
и вызывает его. Затенена одноимённая функция из
trusted_factor_projection — это неопрятно, но дефекта интеграции нет.
trusted_worker.py:57-59, вызов на :398
Импакты пишутся в event_impacts, а в ленте появляются как семейство
factor_exposure_move через маппинг родителя. По
events.kind там ноль по построению, независимо от работоспособности.
trusted_event_feed.py:247
Настоящие числа: event_impacts — 0 строк;
issuer_factor_profiles — 67 строк, все с ролью
rate_sensitive. Профилей выручки, долга, производителя и
потребителя нет ни одного.
По акциям — да, 202 активных события. По облигациям — ноль, и логика, описанная в той же ячейке («размах дня ≥1%, ≥3% за 5 сессий»), не выполняется вообще. Одна галочка на две асимметричные половины скрывает, что бо́льшая по объёму половина рынка не обслуживается.
Бесплатный адаптер витрины разбирает значения и выдаёт ровно метрики
ТЗ. Блокируют его две снимаемые без денег вещи: env-флаг
FNS_GIRBO_PUBLIC_UI_CONTRACT_VERIFIED (подтверждение письменного
разрешения на использование) и правило маршрутизации, уводящее trusted-режим
на платный REST.
trusted_fns_bfo.py:105-116 · trusted_worker.py:480-490
При этом платный REST значений не разбирает вообще — его собственный докстринг это фиксирует. То есть строка «ГИР БО открывает три семейства» описывает бесплатный адаптер, а рекомендация «купить REST» ведёт к источнику, после которого остаётся написать парсер документов. Разбор целиком — в разделе Г; в плане это решение 0.2, шаг 2.5 и условный шаг 3.4.
Ошибка Б.10 найдена при разборе альтернативных источников и изменила не только текст документа, но и порядок работ: платный ГИР БО ушёл из третьего приоритета в условный шаг.
Пункт «TRUSTED_EVENTS_ENABLED_STAGING=1 в protected .env» стоит шестым
в техническом хвосте раздела «что делать дальше». Ему там не место. Пока флага нет,
контур не работает — он воспроизводится руками, и вся база собрана ad-hoc прогонами
за двое суток. Это первая строка раздела «текущий статус», а не последняя строка
раздела «доделать».
Построчно, по номерам разделов и пунктов исходного документа. Привязка к
требованиям канонического каталога (B-CURVE-1, T-VOL-3,
M-FX-3 и т.д.), где она есть.
Соответствие: полное · частичное · нет · сверх ТЗ.
| № ТЗ | Требование | Реализация | Техстатус | Соответствие | Чего не хватает и в чём проблема трактовки |
|---|---|---|---|---|---|
| Раздел I. Облигации | |||||
| I.1 | Спреды по кривой 1–3 / 1–5 / 1–10 / 2–10 лет | yield_curve_move B-CURVE-1…4 |
живой · 2051 | частичное | Все четыре спреда, порог 10 б.п. от последней отправленной базы, подпороговые дрейфы копятся. Инверсия разобрана честно: inversion_started / deepened / normalized / ended плюс обычные flatten/steepen. Не хватает декомпозиции по ногам — yields_pct лежит в payload, но знак не различает «длинный конец вырос» и «короткий упал», а ТЗ различает явно. |
| I.2a | Долг / EBITDA | B-CREDIT-1/2 | кода нет | нет | Принципиально невыводимо из РСБУ: EBITDA там отсутствует, слово встречается в модуле ГИР БО один раз — в дисклеймере. Нужен point-in-time МСФО. Метод Cbonds отдаёт 401 — не входит в подписку. |
| I.2b | Чистый денежный поток | credit_metric_change B-CREDIT-3 |
реализовано, не запущено | частичное | Правило есть: negative_net_cash_flow и falling_net_cash_flow, оба из ТЗ. Только годовой РСБУ, поэтому событие приходит с опозданием до года. Блокер — не оплата REST. Парсер значений уже написан для бесплатной витрины; мешают env-флаг разрешения на её использование и правило маршрутизации, уводящее trusted-режим на платный REST, который значений не разбирает вовсе — см. раздел Г и решение 0.2. |
| I.2c | Покрытие процентов | B-CREDIT-4/5 | реализовано, не запущено | частичное | interest_coverage_below_2x реализован ровно по ТЗ. Числитель и знаменатель берутся из строк 2300/2330 РСБУ, а не из EBIT и процентных расходов по МСФО. Отдельного события «восстановление выше 2x» нет. Блокер — не оплата REST. Парсер значений уже написан для бесплатной витрины; мешают env-флаг разрешения на её использование и правило маршрутизации, уводящее trusted-режим на платный REST, который значений не разбирает вовсе — см. раздел Г и решение 0.2. |
| I.2d | Объём и доля короткого долга | B-CREDIT-6/7 | реализовано, не запущено | частичное | short_debt и short_debt_share_pct уже считаются. Событий не дают сознательно: комментарий в коде фиксирует, что заказчик задал уровни только для покрытия процентов и ЧДП. Это открытый вопрос к вам, а не пробел разработки (решение 0.3). Блокер — не оплата REST. Парсер значений уже написан для бесплатной витрины; мешают env-флаг разрешения на её использование и правило маршрутизации, уводящее trusted-режим на платный REST, который значений не разбирает вовсе — см. раздел Г и решение 0.2. trusted_fns_bfo.py:760-771, :946-948 |
| I.2e | Динамика общего долга | B-CREDIT-8 | реализовано, не запущено | частичное | То же: total_debt считается, порога существенности нет. Блокер — не оплата REST. Парсер значений уже написан для бесплатной витрины; мешают env-флаг разрешения на её использование и правило маршрутизации, уводящее trusted-режим на платный REST, который значений не разбирает вовсе — см. раздел Г и решение 0.2. |
| I.3a | Дефолт эмитента | default_or_missed_payment B-PAY-1…6 |
реализовано, не запущено | частичное | Cbonds-парсер работает, типы разведены («Технический дефолт» → B-PAY-5, severity high). Но живых событий факта дефолта ноль — обе записи в базе это снятие. Модификаторы ТЗ (срок до погашения, доля розничных держателей, ожидаемый recovery) не реализованы. |
| I.3b | Дефолт другого эмитента в секторе (заражение) | sector_contagion B-PAY-9 |
кода нет | нет | Нет производителя, нет отраслевой принадлежности as-of, нет versioned peer-универсума. Спецификация отмечает отдельно: опрос только по наблюдаемым бумагам этот атом не закрывает в принципе — нужен источник дефолтов по всему рынку. |
| I.3c | Блокировка счетов | account_restriction L-ACC-1 |
реализовано, не запущено | частичное | FINDPRS по верифицированному ИНН и универсальному БИК, опрос раз в сутки, якорь события — номер решения плюс дата плюс ИФНС плюс БИК банка. Не выставлены три env-флага подтверждения. Матчинг идёт по точному верифицированному ИНН, а их 17 на 71 эмитента: без шага 1.4 источник покроет четверть вселенной и будет выглядеть неисправным. Нет оценки масштаба: один счёт или вся расчётная инфраструктура. |
| I.3d | Уголовное дело | criminal_case_event L-CRIM-1/2 |
кода нет | нет | Ни источника, ни адаптера, ни правил матчинга и классификации возбуждения/прекращения. |
| I.3e | Претензии надзорных органов | L-REG-1/2 | кода нет | нет | Существующий legal_regulatory_event — это только банкротные сообщения Федресурса (L-BKR). Предписания ЦБ и ФАС, Росприроднадзор, налоговые претензии, обеспечительные меры и лицензии не покрыты никем. Матчинг идёт по точному верифицированному ИНН, а их 17 на 71 эмитента: без шага 1.4 источник покроет четверть вселенной и будет выглядеть неисправным. |
| I.3f | Обратный сценарий: разблокировка, снятие претензий, закрытие дела | L-ACC-2, L-CRIM-2, L-REG-2 | кода нет | нет | Код ФНС сознательно отказывается выводить разблокировку из исчезновения строки: unblock_inference_allowed: False в четырёх местах. Решение правильное, но требование остаётся незакрытым — нужен исторический фид ограничений. |
| I.4a | Смена топ-менеджмента | management_change G-MGMT-1/2 |
реализовано, не запущено | частичное | Производитель есть, но без словаря типов сообщений он raw-only. Есть бесплатный обходной путь: в leadintel на этом же сервере лежат ФИО и должность руководителя по ИНН — периодический дифф закрывает пункт в первом приближении без контракта (раздел Г, шаг 1.5). Нет оценки внезапности и значимости должности — без неё событие нейтрально, а не автоматически негативно, как читает ТЗ. |
| I.4b | Смена контролирующего собственника | ownership_change G-OWN-1 |
кода нет | нет | Ни контракта, ни адаптера. Нет различения технической перестройки структуры владения и реального перехода контроля. |
| I.4c | Продажа акций владельцами | G-OWN-2 / E-CORP-12 | кода нет | нет | Отдельный класс от смены собственника, и подменять одно другим нельзя. Нужен поток сделок инсайдеров и владельцев существенных долей. |
| I.4d | Позитив: сильная команда, стратегический инвестор | G-OWN-3/4 | кода нет | нет | Спецификация помечает G-OWN-4 как «не автоматизировать до policy approval». «Сильная команда» не формализуема без ручной оценки аналитика — и это честная позиция, а не отговорка. |
| I.5a | Спред конкретного эмитента | credit_spread_move B-SPREAD-1/2 |
живой · 3635 | частичное | Порог 25 б.п. и гейты (≥10 сделок, ≥1 млн ₽) подтверждены из payload события. База берётся только при совпадающем типе даты доходности. Покрыто 140 облигаций из 473 — это установившееся состояние, а не незаконченный прогон. |
| I.5b | Широкое расширение спредов по рынку или сектору | B-SPREAD-3…6 | кода нет | нет | Нет versioned корзины или индекса с составом as-of, нет breadth-метрики, нет отделения системного движения от идиосинкратического риска эмитента. |
| I.6a | Повышение и понижение рейтинга | rating_action B-RATING-1…4 |
реализовано, не запущено | частичное | Классификатор UP/DG написан, живых событий ноль. Живой поток лежит (CbrRatingsAmbiguousEmpty) — нужен ремонт парсера stateful-интерфейса. |
| I.6b | Улучшение и ухудшение прогноза | B-RATING-5/6 | реализовано, не запущено | частичное | То же самое, ноль событий. |
| I.6c | Постановка на пересмотр (watch) | B-RATING-7/8 | реализовано, не запущено | частичное | Спецификация держит эти атомы в статусе shadow: нужны отревьюенные направленные фикстуры watch. Ноль событий. |
| I.7a | Досрочное или добровольное погашение, call и put | bond_redemption B-RED-1…5 |
реализовано, не запущено | частичное | Маппинг НРД зашит в код, а не подаётся конфигом — это плюс. Но НРД работает в режиме «только текущий снимок»: историю жизненного цикла он не докажет. Контракта нет. Зашитый маппинг делает НРД заметно быстрее e-Disclosure после оплаты — поэтому в плане он стоит выше (шаг 3.2). |
| I.7b | Дисконт к номиналу → переоценка вверх | B-RED-6 | кода нет | нет | Нет сопоставления объявления с чистой ценой относительно номинала на дату объявления. База дисконта и политика ликвидности не утверждены. |
| I.7c | Mandatory call при росте ставок → реинвестиционный риск | B-RED-7 | кода нет | нет | Спорная трактовка в самом ТЗ. При росте ставок вынужденное реинвестирование происходит по более высокой доходности. Экономически call болезнен при падении ставок: эмитент отзывает дорогой долг, держатель теряет высокий купон. Формулировку стоит переписать до реализации. |
| I.8a | Пропуск купона, технический дефолт | B-PAY-1/3/5/6 | реализовано, не запущено | частичное | См. I.3a. Типы в коде разведены корректно, живых фактов нет. |
| I.8b | Переговоры о реструктуризации до формального дефолта | B-PAY-7 | кода нет | нет | Требует отдельного типа раскрытия из e-Disclosure. Это содержательно ценный пункт: он ловит момент до обвала, а не после. По коду в репозитории видно, что схема сообщения не несёт идентификатора выпуска, а словарь типов подаётся конфигом; насколько это отражает всю проделанную работу — судить по репозиторию нельзя, часть её может быть вне его. Объём после получения ключа уточнить у команды. |
| I.8c | Заражение соседних выпусков того же эмитента | B-PAY-10 | реализовано, не запущено | частичное | Отличается от I.3b и устроено умнее: работает по точной юридической идентичности эмитента, generic-профиль не нужен, покрывает и не удерживаемые в портфеле выпуски. Не срабатывал только потому, что нет родительских дефолтов. |
| I.9a | Размещение состоялось, сорвано или перенесено | bond_placement B-PLC-1/2 |
кода нет | нет | Производителя нет. Нужны итог размещения, объём, дата переноса или отмены. |
| I.9b | Переподписка книги, купон ниже ориентира | B-PLC-3/4 | кода нет | нет | Нужны книга заявок и сохранённый первоначальный ориентир купона. Ни один из подключённых источников этого не отдаёт. |
| I.9c | Первый день вторичных торгов относительно номинала | B-PLC-5/6 | кода нет | нет | price_volume_anomaly это не покрывает: он не знает, что день первый после размещения, не сравнивает цену с номиналом и не отслеживает давление продавцов 1–3 дня. Плюс «сильная распродажа» численно не определена. |
| I.10a | Цена облигации ≥1% внутри дня | T-PRICE (bond) | реализовано, не запущено | частичное | Порог и формула («внутри дня» = размах high−low к предыдущему закрытию, потому что дневная свеча не несёт тиков) написаны и покрыты юнит-тестами. Отключено булевым флагом. Ноль событий при 41 798 готовых баров. |
| I.10b | Цена облигации ≥3% за пять сессий | T-PRICE (bond) | реализовано, не запущено | частичное | То же самое, тем же флагом. |
| I.10c | Существенное изменение оборота облигации | T-VOL (bond) | реализовано, не запущено | частичное | Правило общее с акциями и распространяется на облигации автоматически. Отключено тем же флагом. |
| I.10d | Оборот при стабильной цене как смена держателя | T-VOL-3 (bond) | реализовано, не запущено | частичное | Механика нейтральной полосы ±1% реализована, для облигаций не прогоняется. |
| Раздел II. Общие темы | |||||
| II.1 | Неисполнение обязательств: невыплата и частичная выплата купона, непогашение и частичное погашение тела | B-PAY-1…4 | реализовано, не запущено | частичное | Полная невыплата покрыта правилом. Частичная выплата (B-PAY-2/4) требует полей «начислено / выплачено» — Cbonds их не даёт, нужен e-Disclosure или НРД. Живых фактов ноль. По коду в репозитории видно, что схема сообщения не несёт идентификатора выпуска, а словарь типов подаётся конфигом; насколько это отражает всю проделанную работу — судить по репозиторию нельзя, часть её может быть вне его. Объём после получения ключа уточнить у команды. |
| II.2 | Блокировка счетов со стороны ФНС | = I.3c | реализовано, не запущено | частичное | См. I.3c. Отдельно: ТЗ требует влияния и на акции, и на облигации — механизм issuer-scope это даёт, но без запуска потока проверить нечем. |
| Раздел III. Сырьё и капзатраты | |||||
| III.1a | Долгосрочные прогнозы цен по сырью, порог >10%, список из 12 товаров | commodity_forecast_move C-FCST-1 |
живой · 86 | частичное | Порог строго >10%, сравниваются только соседние винтажи одного бенчмарка по одному целевому году — методологически корректно. Покрыто 7 товаров из 12: нет алмазов, стали, вольфрама, марганца, лития. Спецификация отдельно фиксирует, что железная руда не прокси для стали. |
| III.1b | Прогнозы спроса и предложения (профицит негативен производителю) | C-FCST-2/3 | кода нет | нет | World Bank публикует только цены. Спрос и предложение не покрыты ни по одному из 12 товаров. Это половина требования III.1, которую легко не заметить за галочкой «доходит». |
| III.1c | Знак влияния для производителя и потребителя | C-FCST-4/5 | реализовано, не запущено | частичное | Логика знака написана полностью: производителю прямой знак, потребителю обратный, смешанная роль остаётся conditional. Профилей producer и consumer в базе ноль, поэтому событие остаётся глобальным и условным. |
| III.2 | Изменение CAPEX более чем на 10% | capex_change C-CAPEX-3/4 |
реализовано, не запущено | частичное | Порог строго >10%, направление conditional, и в payload честно записано interpretation: requires_capex_purpose_and_debt_context — это ровно двусторонняя трактовка из ТЗ. Но реализован факт отчётности; пересмотр плана капзатрат (C-CAPEX-1/2) кода не имеет. Связи с FCF, долгом и дивидендами нет. Блокер — не оплата REST. Парсер значений уже написан для бесплатной витрины; мешают env-флаг разрешения на её использование и правило маршрутизации, уводящее trusted-режим на платный REST, который значений не разбирает вовсе — см. раздел Г и решение 0.2. |
| Раздел IV. Календарь и анализ портфеля акций | |||||
| IV.1.1 | Заседание СД с вопросом о распределении прибыли | corporate_calendar E-CAL-1 |
реализовано, не запущено | частичное | Производитель НРД есть, включая повестку собрания. Для окраски нужны ожидаемый дивиденд и консенсус — их нет ни в одном источнике. |
| IV.1.2 | Ожидаемая дата публикации отчётности | E-CAL-2/3 | реализовано, не запущено | частичное | НРД даёт корпоративные действия, но не даты отчётности — нужен e-Disclosure. По коду в репозитории видно, что схема сообщения не несёт идентификатора выпуска, а словарь типов подаётся конфигом; насколько это отражает всю проделанную работу — судить по репозиторию нельзя, часть её может быть вне его. Объём после получения ключа уточнить у команды. Нет различения официальной, ожидаемой и фактической даты публикации. |
| IV.1.3 | Ранее анонсированные сущфакты | corporate_action E-CORP-1…9 |
реализовано, не запущено | частичное | Механизм маппинга есть, но самого словаря типов нет: он подаётся env-JSON и без флага активации адаптер возвращает None, то есть raw-only. Контракт — не последний шаг. По коду в репозитории видно, что схема сообщения не несёт идентификатора выпуска, а словарь типов подаётся конфигом; насколько это отражает всю проделанную работу — судить по репозиторию нельзя, часть её может быть вне его. Объём после получения ключа уточнить у команды. trusted_edisclosure.py:436 |
| IV.1.4 | Изменение или отмена назначенного события | E-CAL-4 | реализовано, не запущено | частичное | Жизненный цикл в адаптере НРД предусмотрен, поток выключен. |
| IV.2a | Факт против ожиданий, отклонение >20% | E-RES-1…5 | кода нет | нет | Консенсуса нет ни у одного подключённого источника. Прогноз компании — отдельный контрактный маршрут через файлы e-Disclosure, тоже не подключён. Это и есть настоящий «сюрприз» из ТЗ. |
| IV.2b | Факт против прошлого периода и АППГ | financial_result_surprise E-RES-10/11 |
реализовано, не запущено | частичное | Названо неверно, и код это признаёт: в payload зашито is_consensus_comparison: False, заголовок пишет «отклонился от предыдущего периода», а спецификация прямо требует «не называть surprise». Порог 20% совпадает. Покрыты выручка, операционная и чистая прибыль; EBITDA и EPS из РСБУ не выводятся. Блокер — не оплата REST. Парсер значений уже написан для бесплатной витрины; мешают env-флаг разрешения на её использование и правило маршрутизации, уводящее trusted-режим на платный REST, который значений не разбирает вовсе — см. раздел Г и решение 0.2. |
| IV.2c | Отраслевые уточнения: LFL, трафик, NIM, ROE | E-RES-6…9 | кода нет | нет | Метрики перечислены в каталоге как отдельные атомы, производителя нет. |
| IV.3 | Сырьевая чувствительность: доля >15%, цена сырья >10% за неделю или месяц | C-SPOT-1…4 | кода нет | нет | Частая ошибка трактовки. commodity_forecast_move — это пересмотр прогноза, а IV.3 требует движения фактической спот-цены. Это разные требования, и первое второе не закрывает. Источника спот-цен по сырью нет вообще. Порог 15% лежит в коде без входных данных. |
| IV.4 | Чувствительность к ставке: ND/EBITDA >3 и Δставки ≥0,75 п.п. | M-RATE-1 + M-RATE-2 | родитель живой · 20 импакт не запущен |
частичное | Порог ставки точен, направление conditional корректно. 67 профилей rate_sensitive существуют и дают ноль импактов, потому что под ними нет production source contract. Банки и финкомпании, к которым логика долговой нагрузки неприменима, не выделены. |
| IV.5 | Валютная чувствительность: доля ≥50%, курс >5% за неделю, >10% за месяц | M-FX-1/2 + M-FX-3/4/5 | родитель живой · 343 импакт не запущен |
частичное | Оба порога реализованы, включая недельный 5% с базой «последний официальный курс на дату минус семь дней». Порог 50% в коде. Профилей revenue и debt ноль. При совпадении обеих ролей код даёт conditional — это соответствует ТЗ («знак зависит от доминанты»), а не противоречит ему. Хеджи и естественное хеджирование не моделируются. |
| IV.6a | Сделка, M&A, байбэк, допэмиссия, неожиданные дивиденды | E-CORP-1…10 | реализовано, не запущено | частичное | См. IV.1.3. «Неожиданный дивиденд» (E-CORP-10) требует консенсуса — без него остаётся просто «дивиденд объявлен». «Выгодное M&A» спецификация оставляет условным до формальной оценочной модели, и это правильно. По коду в репозитории видно, что схема сообщения не несёт идентификатора выпуска, а словарь типов подаётся конфигом; насколько это отражает всю проделанную работу — судить по репозиторию нельзя, часть её может быть вне его. Объём после получения ключа уточнить у команды. |
| IV.6b | Сделки инсайдеров | E-CORP-11/12 | кода нет | нет | Ни источника, ни адаптера. |
| IV.6c | Окраска по комментариям аналитиков | E-CORP-13 | кода нет | нет | Спецификация помечает как gap вне первой очереди: нужен источник с именованным аналитиком, правила доверия и point-in-time консенсус. |
| IV.7a | Изменение цены акции более 10% за день | price_volume_anomaly T-PRICE-1/2 |
живой · 105 | полное | Строго >10%, через Decimal, чтобы ровно 10,00% не срабатывало из-за двоичного округления. Дивиденд возвращается в цену, сплит подавляется с указанием коэффициента, разрыв сессий больше 14 дней подавляется. Это единственный пункт ТЗ, закрытый без оговорок. |
| IV.7b | Объём ≥2× среднего за пять сессий как самостоятельная аномалия | T-VOL-1/2 | живой · 89 | частичное | Осознанное отступление от ТЗ. Самостоятельным событием объём становится только при ≥5×; 2× лишь подтверждает движение цены и повышает severity. Обоснование в коде: на пороге 2× 1669 строк из 1774 были объёмными, с медианой 2,57 — это дневной фон, который трейдер и так видит в терминале. Отступление разумное, но это ваше решение, а не разработки. |
| IV.7c | Всплеск объёма при стабильной цене | T-VOL-3 | живой · 8 | частичное | Нейтральная полоса ±1% определена явно, направление conditional, заголовок пишет «цена практически не изменилась». Гипотеза «смена держателя» из ТЗ сохранена. Не хватает только разметки «накопление / распределение» — а её по дневной свече достоверно и не получить. |
| Реализовано сверх ТЗ | |||||
| — | Биржевой режим дефолта TQRD | default_status_flag | живой · 0 | сверх ТЗ | Ноль честный: ни одна наблюдаемая бумага не в режиме «Облигации Д». Ценное наблюдение внутри кода: флаги HASDEFAULT на этом рынке мертвы — все 47 бумаг в TQRD показывают ноль, поэтому режим первичен. Ограничение: видит только текущий снимок, историю режимов не восстанавливает. |
| — | Ставка и курсы как самостоятельные глобальные события | M-RATE-1, M-FX-1/2 | живой · 363 | сверх ТЗ | В ТЗ это входы для IV.4 и IV.5, а не отдельный класс событий. Как самостоятельные факты полезны, но issuer-требование они не выполняют. |
| — | Отбрасывание подтверждений и первичных рейтингов | rating_action | живой | сверх ТЗ | Полезная фильтрация шума: 426 строк из 486. Но первичный рейтинг для только что размещённого выпуска — значимое событие; лучше выделить отдельным подтипом, чем отбрасывать. |
| — | Подавление дивидендного гэпа, сплитов, разрывов сессий, несовместимых единиц объёма | price-volume.v4 | живой | сверх ТЗ | Прямо требуется спецификацией, но в исходном ТЗ не описано. Без этого порог >10% срабатывал бы на каждой дивидендной отсечке голубых фишек — российские доходности регулярно превышают 10%. |
| — | Жизненный цикл active / corrected / retracted и реплей по версиям правил | — | живой | сверх ТЗ | 1572 из 1774 событий цены/объёма и 426 из 486 рейтингов ретрактированы при смене версии правила. В ТЗ этого нет, но без такого механизма исправление правила не откатывает уже сделанные выводы — и лента накапливает ложь. |
ТЗ почти целиком описывает негативные триггеры и почти не описывает обратные события. Снятие дефолтного статуса в коде есть, а разблокировки счетов, снятия претензий, прекращения дела и выхода из банкротных процедур в ТЗ нет как требований — только вскользь, в разделе I.3, как «обратный сценарий». Между тем это половина ценности: событие, которое никогда не гаснет, через год превращает карточку эмитента в кладбище.
Второе: ТЗ нигде не задаёт, что делать с эмитентом, у которого две роли сразу —
экспортёр с валютным долгом, производитель одного сырья и потребитель другого.
Код отвечает conditional, и это честно, но продуктово бесполезно.
Решение нужно принять на уровне ТЗ, а не догадываться в реализации.
Замерил, чтобы это перестало быть ощущением. За июль 2026 в ленту попало 746 видимых событий — около 25 в день. Из них 635 — движения G-спредов: 594 события за последние 30 дней по 83 бумагам, то есть примерно двадцать в день и по семь на бумагу в месяц. events, status IN (active,corrected), группировка по месяцу и типу
Но главная причина нечитаемости не в объёме, а в том, что ранжировать
поток нечем. Из 6255 видимых событий 6197 имеют
severity='medium'. Значение high стоит ровно у 47 строк
— это события цены и объёма, где сработало два предиката сразу. Ещё 58 строк
не имеют severity вовсе. То есть поле формально есть, фильтр по нему формально
работает, а информации в нём нет: отсортировать «сначала важное» физически
невозможно.
6197 medium · 47 high · 58 null
Два обстоятельства делают это срочным, а не косметическим.
Первое: будет хуже, причём от работ, которые я сам поставил первыми. Спреды сейчас считаются по 140 бумагам из 473 — доведение покрытия умножает поток примерно на 3,4 и даёт порядка двух тысяч событий в месяц. Включение облигационного правила цены и объёма (шаг 1.1) добавляет 339 инструментов туда, где сейчас работают 53. Обе работы правильные, но выпускать их без группировки и ранжирования — значит утопить ленту окончательно.
Второе: прецедент уже есть, и он показывает, что это лечится. Семейство цены и объёма ровно эту болезнь уже перенесло: версия правила v4 ретрактировала 1572 строки из 1774 — 89% — потому что объёмные события на пороге 2× составляли 94% ленты при медиане 2,57, то есть были обычным дневным фоном. Лечение состояло не в удалении требования, а в поднятии планки для самостоятельного события с сохранением числа в payload. К двум самым крупным семействам — спредам и кривой — это мышление не применяли ни разу.
Одна конкретная асимметрия, которая объясняет пилу по спредам. У кривой порог считается от последней отправленной базы, поэтому подпороговые дрейфы копятся и не порождают событий. У спредов сравниваются соседние ликвидные сессии — поэтому колебание вокруг 25 б.п. выдаёт событие каждые несколько дней по одной и той же бумаге. Это разное поведение двух соседних правил, а не разная природа рынка.
И самое полезное: правильное лекарство здесь — невыполненное требование ТЗ, а не костыль. Двадцать спредовых событий за день по 83 бумагам — это одно рыночное событие «спреды разъехались по рынку», а не двадцать независимых. Ровно это и есть B-SPREAD-3…6, пункт I.5b, который в таблице выше числится как «кода нет». Агрегат по рынку и сектору одновременно закрывает пункт ТЗ и схлопывает основной источник шума.
Цель, относительно которой отсортировано: максимум живых и корректно интерпретируемых требований ТЗ на единицу затрат. Без явной цели любой порядок субъективен — в исходном списке она не названа, и поэтому там смешаны скорость, покрытие и стоимость.
Единый список, проверенный на полноту: каждая позиция таблицы А, которая не закрыта полностью, попадает ровно в один шаг. Волны отсортированы по стоимости входа — от нуля до контрактов и собственной разработки. В конце отдельно названо то, что не закроется никогда, и почему это нормально.
Дословно: «казалось бы, надо собирать просто из надёжного источника метрики типа „объём торгов“, и ивенты, что они подскочили по сравнению с предыдущим значением на N процентов».
По большей части это подтверждается тем, что я нашёл, и подтверждается жёстко.
Контролёр покрытия за всё время дал отрицательную ценность. Единственное, что он делал — прятал от пользователя уже произведённые события: 60 рейтингов, дефолты, спреды. Его выключили решением стейкхолдера, и лента от этого только наполнилась. 327 атомов, верификатор и материализатор обслуживают механизм, который в проде выключен и без которого стало лучше.
Каталог требований — это план, скомпилированный в код.
116 требований, 120 определений, 327 атомов, версия каталога, планы
capability, семь разных статусов ожидания (policy_pending,
identity_pending, profile_pending и далее). Всё это
описывает работу, которая не сделана. Такое место — таблица в документе, а не
модуль на 1428 строк, который надо сопровождать.
Слой контрактов источника прямо сейчас мешает продукту работать. 67 профилей эмитентов существуют и дают ноль импактов, потому что под ними нет production source contract. То есть данные есть, правило есть, а событий нет из-за юридической формальности, которую никто не закрыл.
И самый неприятный аргумент в пользу этой позиции: вся эта машинерия строилась ради гарантий корректности — и не поймала ни одного из трёх реальных дефектов. Облигационное правило выключено булевым флагом. Парсер рейтингов молча падает. Семейство называется «сюрприз», сравнивая с прошлым годом, причём в его же payload записано, что консенсуса нет. Ни fail-closed гейт, ни 327 атомов, ни верификатор ничего из этого не заметили.
Одно исключение, и оно доказано вашими же данными. Версии
правил вместе с ретрактом и реплеем — не церемония. Когда порог по объёму
оказался неверным, price-volume.v4 ретрактировал 1572 строки из
1774. Без версионирования эти 1572 неверных события остались бы в ленте
навсегда, а исправление порога действовало бы только на будущее. Сегодняшняя
жалоба на нечитаемость ленты лечится ровно этим механизмом: поднять планку по
спредам и переиграть историю. Из всего перечисленного я бы оставил только его.
И одна ловушка в простой формулировке. «Подскочил на N% к предыдущему значению» — это буквально правило, которое дало 3635 спредовых событий и нечитаемую ленту: значение колеблется вокруг порога и выдаёт событие каждые несколько дней. У кривой этой болезни нет, потому что там порог считается от последней отправленной величины, а не от предыдущей. Одна строчка разницы, и её стоит перенести в упрощённую версию — это не защита машинерии, а конкретная дешёвая идея.
Хорошая новость: то, что вы описываете, уже лежит на дне этой системы.
detect_key_rate_changes — сорок строк. Правило цены и объёма — одна
функция с порогами. Простота, которую вы предлагаете, не требует переписывания,
она требует удаления обвязки. Это дешевле, чем кажется, и это же
естественная подготовка к переходу на калькуляторы плюс сигналы.
Ни один из этих пунктов не требует разработки, но каждый меняет содержание шагов ниже. Пока они открыты, любая оценка трудоёмкости — предположение.
Всё, что ниже, добавляет события в ленту, из которой fail-closed гейт может убрать их одним переключателем. Если гейт когда-нибудь вернётся, каждый шаг должен дополнительно включать промоушен атомов — это другая оценка.
С учётом позиции стейкхолдера выше решение формулируется резче: не «когда включим обратно», а что из этого сносим. Мой ответ по каждому куску — снести контролёр, верификатор и материализатор; каталог требований вернуть в документ; слой контрактов источника упростить до того, что реально блокирует юридически; оставить только версии правил с ретрактом и реплеем, потому что это единственный элемент, который уже доказал пользу на живых данных.
Снос стоит поставить перед волной 2, а не после: чем больше семейств оживёт, тем дороже будет вынимать обвязку из-под них.
Письменное разрешение на использование публичной витрины — и метрики появляются бесплатно, потому что парсер уже написан. Или оплата REST — и остаётся написать парсер скачанных документов. Сначала проверьте третий вариант: публикует ли ФНС ГИР БО в открытых данных единым архивом. От этого решения зависит, где стоят шесть позиций ТЗ.
Порог существенности для короткого долга (I.2d) и общего долга (I.2e) — метрики уже считаются и лежат мёртвым грузом. Порог объёма 2× или 5× (IV.7b) — код отступил от ТЗ обоснованно, но молча. И переписать I.7c: call болезнен при падении ставок, а не при росте.
Экспортёр с валютным долгом, производитель одного сырья и потребитель другого.
Код честно отвечает conditional, ТЗ ответа не даёт. Решать на
уровне ТЗ, иначе реализация будет угадывать.
trusted_source_rights.py отделяет «можем читать» от «можем
показывать пользователю»; коммерческие вендоры числятся необъявленными.
Объявляйте оба права при подключении, иначе позднее включение проверки
молча погасит часть ленты.
Шесть шагов. Закрывают восемь позиций ТЗ с нуля и снимают два предусловия, без которых последующие контракты дадут четверть ожидаемого покрытия.
Заменить evaluate_anomalies = kind == "stock" на условие,
допускающее bond. Пороги, формулы и юнит-тесты написаны,
данные собраны: 339 облигаций, 41 798 баров, история с сентября 2021.
Закрывает I.10a, I.10b, I.10c, I.10d. Универсум растёт с 53 инструментов до 392.
TRUSTED_EVENTS_ENABLED_STAGING=1. Пока флага нет, база собирается
ручными прогонами, и любая проверка «работает ли» недостоверна.
Предусловие для всего остального.
Правило, классификация действий и жизненный цикл написаны и отревьюены.
Живой поток падает на CbrRatingsAmbiguousEmpty — stateful-интерфейс.
Закрывает I.6a, I.6b, I.6c, представленные сейчас только отзывами рейтинга Роснефти пятилетней давности.
Сейчас 17 верифицированных ИНН на 71 эмитента. Федресурс и блокировки ФНС матчатся именно по точному верифицированному идентификатору — без этого шага оба источника дадут 24% покрытия и будут выглядеть неисправными.
Разовая проставка не решает задачу: инструменты приезжают из myavi в избранное,
и новый эмитент заводится сам. Точка входа уже есть — при неизвестном эмитенте
вызывается генератор сущности, который отдаёт
match_tokens, keywords, facets, kind, notes. Юридических
идентификаторов среди них нет. Резолв ИНН/ОГРН должен встать туда же,
в тот же шаг онбординга, и писать в issuer_identifiers
с verified и evidence_url.
routers/integration.py:_call_entity_gen · PROMPT_KEY_ENTITY_GEN
Источник данных — не Dadata, а leadintel на этом же сервере (см. раздел Г): 48 558 компаний, у всех ИНН и ОГРН, плюс готовый матчер по названию. Dadata остаётся фолбэком для того, чего там не нашлось.
Предусловие для I.3c, I.3e, II.2. Архитектурных решений не требует: идентификатор — не факт, у него нет вопроса авторитета.
В leadintel уже лежат director_name, director_inn
и director_position по ИНН. Периодический дифф даёт рабочий
сигнал без контракта с ЦРКИ и без внешнего API. Оговорка: ЕГРЮЛ отражает
смену с задержкой в дни-недели, то есть это подтверждение, а не опережение.
Закрывает I.4a в первом приближении; авторитетная версия придёт с e-Disclosure (шаг 3.3).
financial_result_change — факт к прошлому периоду, то, что
реализовано. financial_result_surprise — только против
point-in-time консенсуса, то, чего нет. Сделать до закупки любого источника
отчётности, иначе переименовывать придётся с живыми данными.
Чинит трактовку IV.2b и освобождает имя для IV.2a.
Сейчас 6197 видимых событий из 6255 имеют severity='medium',
high стоит у 47 строк, у 58 severity нет вовсе. Поле есть,
фильтр есть, информации нет — отсортировать «сначала важное» невозможно.
Это и делает ленту нечитаемой глазами, а не сам объём.
Каждое правило должно вычислять severity из своих же чисел, которые уже лежат в payload: во сколько раз превышен порог, ликвидность бумаги, размер дельты относительно исторического распределения. Ноль новых источников.
Ставить перед шагом 1.1, а не после. Включение облигационного правила добавляет 339 инструментов туда, где сейчас 53; выпускать это в ленту без ранжирования — значит утопить её окончательно.
Закрывают ещё тринадцать позиций, из них шесть — при условии, что решение 0.2 принято в пользу витрины. Шаги 2.6 и 2.7 добавлены после обратной связи стейкхолдера о нечитаемости ленты (см. конец раздела А).
Две бумаги падают на проверке артефактов. Отдельно разобрать, почему G-спреды покрывают 140 облигаций из 473: гейт ликвидности отсекает по делу или база не находится там, где должна.
Доводит I.5a до заявленного покрытия.
yields_pct уже лежит в payload; нужно, чтобы знак различал
«длинный конец вырос» и «короткий упал» — ТЗ различает явно, код пока нет.
Доводит I.1 до полного.
Порядок здесь важнее содержания: 67 профилей rate_sensitive уже
существуют и дают ноль импактов, потому что под ними нет production source
contract. Сначала решить, чем удостоверяется профиль. Затем минимальный набор
по наблюдаемой вселенной: чистый долг к EBITDA, доля валютной выручки, доля
валютного долга, профильный товар, роль производителя или потребителя, доля
сырья в выручке или себестоимости.
Закрывает IV.4, IV.5, III.1c — крупнейший продуктовый блок волны.
Код готов, источник бесплатный, нужны подтверждения машинного доступа. Но не выпускайте без ответа на вопрос снятия: код сознательно отказывается выводить разблокировку из исчезновения строки, значит без исторического фида вы публикуете негативное событие, которое никогда не гаснет.
Закрывает I.3c и II.2, половину I.3f оставляет открытой.
Парсер значений уже написан и выдаёт ровно метрики ТЗ. Помимо флага
FNS_GIRBO_PUBLIC_UI_CONTRACT_VERIFIED нужно поправить
_fns_bfo_adapter_enabled(): сейчас в trusted-режиме он всегда
уводит на платный REST, поэтому после шага 1.2 витрина станет недостижимой.
Закрывает I.2b, I.2c, I.2d, I.2e, III.2, IV.2b — шесть позиций бесплатно.
Двадцать спредовых событий за день по 83 бумагам — это одно рыночное событие «спреды разъехались по рынку», а не двадцать независимых. Versioned корзина с составом на дату, breadth-метрика, симметричные пороги на расширение и сужение.
Вынесено сюда из волны 4: в отличие от заражения, агрегат считается из наших собственных рядов G-спредов и внешнего источника не требует.
Закрывает I.5b и одновременно схлопывает главный источник шума в ленте — то есть это не борьба с симптомом, а невыполненное требование ТЗ, которое случайно оказалось и лекарством.
У кривой порог считается от последней отправленной базы, поэтому подпороговые дрейфы копятся и не порождают событий. У спредов сравниваются соседние ликвидные сессии — поэтому колебание вокруг 25 б.п. выдаёт событие каждые несколько дней по одной и той же бумаге. Это разное поведение двух соседних правил, а не разная природа рынка.
Требует бампа версии правила и реплея, поэтому не в первой волне. Проверить
на истории, сколько из 3635 строк переживут смену — по аналогии с
price-volume.v4, где отсеялось 89%.
Порядок определяется не ценой и не числом семейств, а дистанцией от платежа до события в ленте. По этому критерию Федресурс выигрывает у всех, а самый дорогой блок оказывается не самым срочным.
| № | Источник | Работа после оплаты | Закрывает | Комментарий |
|---|---|---|---|---|
| 3.1 | Федресурс | нет | I.3e (банкротная часть) | Единственный контракт без остаточной разработки: восемь типов схемы 3.9, матчинг, жизненный цикл — всё написано. Требует шага 1.4, иначе покроет 17 эмитентов из 71. |
| 3.2 | НРД | включить и проверить | I.7a · IV.1.1 · IV.1.4 · часть II.1 | Маппинг типов зашит в код, а не подаётся конфигом — это делает НРД быстрее e-Disclosure. Ограничение: режим «только текущий снимок», историю жизненного цикла не докажет. |
| 3.3 | e-Disclosure (шлюз ЦРКИ) | уточнить у команды | I.8b · II.1 полностью · IV.1.2 · IV.1.3 · IV.6a · I.4a авторитетно | Нужен выданный ключ шлюза; лежащие IFX_* — креды новостного фида и к шлюзу не подходят. По коду в репозитории видно, что схема сообщения не несёт идентификатора выпуска, а словарь «тип → атом» подаётся конфигом; но часть работы может лежать вне репозитория, поэтому остаточный объём после ключа надо уточнить у команды, а не оценивать по коду. |
| 3.4 | Платный REST ГИР БО — только если 0.2 решён против витрины | парсер документов | те же шесть, что и 2.5 | Адаптер скачивает файлы отчётности как байты и значения не разбирает. Покупает транспорт, а не метрики. Если витрина разрешена — этот пункт не нужен вовсе. |
| 3.5 | Point-in-time консенсус | сопоставление винтажей | IV.2a · часть IV.6a | Единственный способ получить настоящий «сюрприз» и «неожиданный дивиденд». Требует хранения оценки на дату до публикации, а не текущей. |
| 3.6 | МСФО point-in-time | нормализация | I.2a | Долг/EBITDA из РСБУ невыводим в принципе. Метод Cbonds отдаёт 401 — не входит в текущую подписку; нужен либо апгрейд тарифа, либо другой вендор. |
| 3.7 | Фид сделок инсайдеров | матчинг лиц | I.4c · IV.6b | Отдельный класс от смены собственника; подменять одно другим нельзя. |
| 3.8 | СПАРК: собственники | адаптер с нуля | I.4b | Ни контракта, ни кода. Нужно различать техническую перестройку владения и реальный переход контроля — иначе события будут ложными. |
| 3.9 | Уголовные и надзорные производства | адаптер с нуля | I.3d · I.3e полностью | Претензии надзорных органов шире банкротства: предписания ЦБ и ФАС, Росприроднадзор, налоговые претензии, обеспечительные меры, лицензии. |
| 3.10 | Исторический фид ограничений | жизненный цикл | I.3f | Единственный способ получить разблокировку, снятие претензий и закрытие дела честно, а не выводом из исчезновения строки. |
| 3.11 | Спот-цены по сырью | окна недели и месяца | IV.3 | Это не то же, что пересмотр прогноза World Bank. Разные горизонты, разные требования; первое второе не закрывает. |
| 3.12 | Прогнозы спроса и предложения | нормализация мер | III.1b | World Bank публикует только цены. Половина требования III.1, которую легко не заметить за галочкой «доходит». |
| 3.13 | Пять недостающих товаров | маппинг бенчмарков | III.1a полностью | Алмазы, сталь, вольфрам, марганец, литий. Железная руда не прокси для стали — спецификация фиксирует это отдельно. |
| 3.14 | Отраслевые метрики: LFL, трафик, NIM, ROE | производитель с нуля | IV.2c | Атомы в каталоге перечислены, кода нет. |
| 3.15 | Аналитические комментарии | классификатор + правила доверия | IV.6c | Спецификация помечает как gap вне первой очереди. Требует именованного аналитика, а не тональности новости. |
Здесь нет источника, который можно подключить: это новые модели данных и новая аналитика. Каждый пункт зависит от волн выше и до них бессмысленно доходить.
Ориентир купона, итоговый купон, объём книги, объём размещения, факт переноса
или отмены, поведение в первый день торгов относительно номинала.
price_volume_anomaly это не покрывает: он не знает, что день первый,
и не сравнивает цену с номиналом.
Закрывает I.9a, I.9b, I.9c.
Отраслевая классификация, peer group с составом на дату, отделение системного движения от специфического, правила каскада. Спецификация отдельно отмечает: опрос только по наблюдаемым бумагам этот атом не закрывает в принципе — нужен источник дефолтов по всему рынку.
Рыночный агрегат спредов (I.5b) отсюда вынесен в шаг 2.6: он считается из наших собственных рядов и не ждёт внешнего источника.
Закрывает I.3b.
Сопоставление объявления с чистой ценой относительно номинала (I.7b) и реинвестиционный эффект (I.7c). Второй пункт делать только после того, как формулировка ТЗ будет исправлена в решении 0.3 — иначе он будет реализован зеркально неверно.
Закрывает I.7b, I.7c.
Срок до погашения, доля розничных держателей, ожидаемый recovery — доводят I.3a и I.8a до полного. Отдельно: прогнозный CAPEX против фактического (сейчас реализован только факт) доводит III.2.
I.4d, «приход сильной команды». Спецификация помечает как неавтоматизируемое до утверждения политики. Формализовать «сильную» команду без ручной оценки аналитика нельзя, и попытка это сделать даст события, которым нельзя верить.
IV.7c, разметка накопления и распределения. Всплеск объёма при
стоящей цене фиксируется честно, но определить по дневной свече, кто накапливал
и кто распределял, недостоверно. Сейчас это conditional — и должно
им остаться.
I.2a, Долг/EBITDA из РСБУ. EBITDA в российском стандарте нет. Закроется только через МСФО (3.6), никакой парсер ГИР БО этого не изменит.
Итог по арифметике: из 56 позиций ТЗ одна закрыта полностью сейчас (IV.7a). Волны 1 и 2 доводят это примерно до двадцати — без единого контракта, если решение 0.2 принято в пользу витрины. Остальные тридцать шесть требуют денег, и три из них не закроются вовсе.
Вопрос поставлен правильно, и по ГИР БО ответ оказался неожиданным. Этот раздел — не приложение: его находка стала ошибкой Б.10, изменила формулировку блокера в восьми строках таблицы А и переставила пункт плана. Здесь собрано обоснование, ссылки на него расставлены по всему документу.
В коде два независимых адаптера ГИР БО, и они делают разные вещи.
trusted_fns_bfo.py — бесплатный, ходит во внутренний JSON публичной
витрины bo.nalog.gov.ru и разбирает значения в ровно
те метрики, которые нужны ТЗ: общий и короткий долг, доля короткого долга, ЧДП,
покрытие процентов, CAPEX-proxy, FCF-proxy, выручка. Из него же выходят правила
credit_metric_change, capex_change и annual-change.
trusted_fns_girbo_rest.py — платный, подписочный REST v1.0.3. И в его
собственном докстринге написано прямо: «does not parse financial statement
values and therefore makes no claim about IFRS, consolidated scope, EBITDA,
consensus, or semantic event coverage». Он скачивает файлы отчётности как
байты и складывает их в хранилище сырья. trusted_fns_girbo_rest.py:1-35
Из этого следует то, чего нет ни в одном плане: оплата подписки ФНС не даёт ни одного события. После неё остаётся написать парсер скачанных документов БФО — то есть ту самую работу, которая для витрины уже сделана. В плане работ пункт «платный REST ГИР БО открывает три семейства» переоценивает отдачу примерно вдвое.
Формулировка «публичный showcase-адаптер запрещён архитектурно» неточна. Он заблокирован двумя разными вещами, и обе снимаются без денег.
fns_girbo_enabled() требует
операторскую половину (она уже true в настройках) и
FNS_GIRBO_PUBLIC_UI_CONTRACT_VERIFIED — подтверждение
письменного разрешения на использование. Это юридический вопрос,
а не платёж и не техника. trusted_fns_bfo.py:105-116 · settings: source.fns_girbo.enabled=true
_fns_bfo_adapter_enabled()
отдаёт управление платному REST всякий раз, когда включён trusted-режим —
«две несовместимые схемы не должны писать один и тот же source/stream».
То есть как только вы поднимете контур (шаг 2 плана), бесплатная витрина
станет недостижимой независимо от флагов. trusted_worker.py:480-490
Развилка, которую стоит поставить перед стейкхолдером явно: получить письменное разрешение ФНС на использование витрины (бесплатно, но небыстро) — или заплатить за REST и дописать парсер документов. Третий вариант — проверить, публикует ли ФНС наборы бухотчётности ГИР БО в разделе открытых данных единым архивом: если да, это снимает и вопрос разрешения на витрину, и вопрос парсинга недокументированного транспорта. Этот вариант в коде не рассматривался вовсе.
Самый недооценённый источник — свой же. /home/www/leadintel,
база lead_intel на том же Postgres. Проверил содержимое:
matching_service,
brand_index) и таблица company_tickers — со схемой,
но пустая. Заполнить её для наших эмитентов один раз означает получить точный
двусторонний джойн тикер ↔ ИНН вместо сопоставления по имени.
director_name,
director_inn, director_position, founders,
status, liquidation_date, а также выручка, прибыль,
активы и численность.
Проверил на живых данных: Газпром — ИНН 7736050003, Миллер; Роснефть — 7706107510, Сечин; Лукойл — 7708004767. Всё сходится с реальностью.
Одна честная оговорка. Сопоставление по названию неоднозначно:
запрос «Лукойл» даёт головное ПАО и три дочерних общества с выручкой в сотни
миллиардов. Резолвер обязан иметь правило разрешения неоднозначности — правовая
форма плюс максимальная выручка плюс ручное подтверждение — и писать
verified только после него. Иначе вы привяжете события материнской
компании к «Лукойл-Пермь», и это будет хуже, чем отсутствие ИНН.
Интуиция верная, но применима не там, где кажется. Разберу по блокам ответа
findById/party.
management отдаёт ФИО и должность единоличного исполнительного
органа по ИНН. Периодический опрос с диффом даёт рабочий сигнал для
I.4a, который сейчас числится за контрактом e-Disclosure.
Оговорка: ЕГРЮЛ фиксирует смену с задержкой в дни-недели после решения, поэтому
для трейдера это подтверждение, а не опережение. Но лучше, чем ноль.
В базе 17 верифицированных ИНН и 17 ОГРН на 71 эмитента. issuer_identifiers: INN 17/17 verified, OGRN 17/17, всего issuers 71
А матчинг Федресурса и блокировок ФНС идёт именно по точному верифицированному ИНН или ОГРН. То есть если завтра придут креды Федресурса, покрытие составит 24% эмитентов — и это будет выглядеть как «источник работает плохо», хотя источник будет ни при чём.
Dadata по названию и МОЕХ-идентификатору закрывает ровно эту задачу, стоит копейки и не требует никаких архитектурных решений, потому что ИНН — не событие, а идентификатор: у него нет проблемы авторитета факта. Это подготовительный шаг к пунктам 8 и 9 плана, который надо сделать до них, а не после.
Все пять выводов ниже уже учтены в списке раздела В — здесь они собраны вместе, чтобы было видно, что именно изменилось от разбора альтернатив.
Одно предостережение по всем аггрегаторам сразу — и оно относится к leadintel
тоже. В архитектуре уже есть уровень авторитета
contracted_aggregator_with_primary_provenance, так что и Dadata,
и собственный агрегатор туда формально помещаются. Но у неё есть и отдельный гейт прав на показ:
trusted_source_rights.py отделяет «можем читать» от «можем показывать
пользователю», и коммерческие вендоры там числятся необъявленными. Подключая
любой новый источник, объявляйте оба права сразу, иначе позже включение проверки
прав молча погасит часть ленты.
Отдельный механизм, спроектированный стейкхолдером и заведённый в бэклог как T-0496. Он закрывает те же пункты ТЗ, но с другой стороны — из новостей, а не из официального источника, и потому доступен раньше и без контрактов.
Служебный сигнал не подписываемый и не создаёт тегов: он просто знает состав избранного компании. Новости матчатся на его ключевые слова, и при совпадении уходят в стандартный ИИ-триаж — но с дополнительным условием, что новость должна попасть хотя бы в одного эмитента или инструмент из избранного.
Ключевые слова сигнал пишет и обновляет сам, но целятся они в события, а не в эмитентов: попадание в конкретную бумагу — отдельный шаг. После триажа анализатор не только пишет разбор, но и может создать событие с пометкой «кандидат» — это полноценное событие системы, просто с иной достоверностью. В ленте новость и порождённое событие склеиваются в тему с пилюлей «Событие [N]»; если позже приходит подтверждение из официального источника, в теме оказываются все трое.
Ключевое отличие от калькуляторов: кандидат — это утверждение, прочитанное в тексте, а не вычисленное из ряда. Поэтому он не заменяет официальный факт, а предшествует ему. Решение стейкхолдера от 4 августа: в первой версии дублирование с калькулятором допустимо — «если есть новость, значит есть повод»; разделение ответственности делается позже, отдельным этапом.
| № | Сигнал | Что ловит | Закрывает | Почему именно новостями |
|---|---|---|---|---|
| S1 | Корпоративные действия и структура капитала | Размещение состоялось, сорвано или перенесено; переподписка книги; купон ниже ориентира; оферта и досрочное погашение; созыв СД о прибыли; дивиденды; байбэк; допэмиссия; крупная сделка; M&A | I.7a · I.9a · I.9b · I.9c · IV.1.1 · IV.1.3 · IV.1.4 · IV.6a | Восемь позиций ТЗ, все заперты за контрактами НРД и ЦРКИ. При этом объявляются публично раньше, чем приходят по контрактному каналу. |
| S2 | Платёжный стресс и дефолт | Пропуск купона, технический дефолт, неисполнение оферты, переговоры о реструктуризации до формального дефолта, дефолт сопоставимого эмитента в секторе | I.3a · I.3b · I.8a · I.8b · I.8c · II.1 | I.8b — единственный пункт ТЗ, ловящий момент до обвала, и он принципиально новостной: в официальный источник переговоры не попадают вообще. Плюс сегодня в базе ноль событий факта невыплаты. |
| S3 | Надзор, суд, правоохрана — и обратные события | Уголовное дело, предписания ЦБ и ФАС, претензии Росприроднадзора и налоговой, обеспечительные меры, лицензии, блокировка счетов — и симметрично: снятие претензий, разблокировка, прекращение дела | I.3c · I.3d · I.3e · I.3f · II.2 | Крупнейший кластер «кода нет». И единственный практичный способ получить обратные события: у ФНС снятие принципиально не выводится из исчезновения строки, а исторического фида ограничений нет. Новость о разблокировке есть всегда. |
| S4 | Контроль, собственность и менеджмент | Смена контролирующего собственника, вход стратегического инвестора, продажа доли владельцем, сделки инсайдеров, внезапный уход или назначение первых лиц | I.4a · I.4b · I.4c · I.4d · IV.6b | I.4d спецификация помечает как неавтоматизируемое детерминированным правилом — «сильная команда» не формализуема. Это ровно случай, где кандидат является правильным ответом, а не суррогатом. Плюс ЕГРЮЛ по публичным АО даёт номинальных учредителей, то есть по I.4b/I.4c новости объективно точнее реестра. |
| S5 | Результаты против ожиданий и сырьевые ориентиры | Факт выше или ниже консенсуса и гайденса, пересмотр прогноза компании, объявленные даты отчётности, LFL и трафик у ритейла, NIM и ROE у банков, прогнозы спроса и предложения по сырью, пересмотр плана капзатрат | IV.2a · IV.2c · IV.1.2 · III.1a (5 товаров) · III.1b · C-CAPEX-1/2 | Весь блок требует либо платного консенсус-вендора, либо источников, которых нет ни у кого из подключённых. При этом «отчиталась хуже ожиданий» и «понизила прогноз по литию» — стандартный новостной жанр. |
| S6 | Рейтинговые действия | Повышение и понижение рейтинга эмитента и выпуска, изменение прогноза, watch и пересмотр, отзыв, присвоение первичного рейтинга | I.6a · I.6b · I.6c | Калькулятор сейчас мёртв: живой поток репозитория ЦБ падает, и в ленте нет ни одного апгрейда или даунгрейда — только отзывы рейтингов Роснефти 2020–2021. Сигнал подменяет сломанный калькулятор немедленно и остаётся полезным после ремонта. |
| S7 | Рыночные движения, ставки и чувствительности | Резкое движение цены или оборота, расширение и сужение спредов, наклон кривой, решение по ставке и его эффект на закредитованных, курс и экспортёры, спот по профильному сырью | I.1 · I.5a · I.5b · I.10a–d · IV.3 · IV.4 · IV.5 · IV.7a–c | Новость про движение цены — это освещение события, а не конкурирующий источник числа; механизм тем поглощает такой случай корректно. Плюс честно закрываются дыры, которых у калькулятора нет по устройству: внутридневное движение, сглаженное дневной свечой, и бумаги вне покрытия. |
Семь сигналов дают новостной слой по всем 56 позициям ТЗ. Это не отменяет ни одного пункта плана: кандидат — не подтверждённый факт, и каталог покрытия по-прежнему закрывается калькуляторами и официальными источниками.
Но это радикально меняет что видит пользователь, пока идут волны 2 и 3. Сегодня по семнадцати позициям ТЗ в ленте нет ничего вообще — ни строки, ни намёка. С сигналами по ним появляется освещение с первого дня, а официальный факт приезжает позже и садится в ту же тему.
Два пункта, которые от этого становятся важнее, чем выглядели. Ранжирование (шаг 1.7) — потому что семь сигналов добавят в ленту ещё один поток, а severity уже сейчас не несёт информации. И замер матчера новость→эмитент: портфельный гейт опирается на него, а по прошлым замерам около 95% строк ленты не имеют серверной привязки к эмитенту. Если это так, выход кандидатов будет близок к нулю — и это надо измерить до постройки, а не после.