Финансовый выпуск 0.5.1 — исправления выплат и корпоративных действий, 21.10.2026
Выпуск 0.5.1 исправляет подтверждённые ошибки реестра выплат финансовой базы 0.5.0 и одно незаписанное дробление. Рыночный срез (16.10.2026), календарь, цены, состав индекса, синтетические модели, денежная подбаза и расчётный движок 0.5.0-rc.2 не менялись. Индикатор ширины рынка выпущен как 1.3.1: в нём заново оценены только участники, чей ряд полной доходности изменился. Архивный сценарий с фиксированным сдвигом 20 п.п. сохранён как результат 1.3.0.
Идентичность
| Параметр | 0.5.0 | 0.5.1 |
|---|---|---|
| Файл | PortfolioLab_Financial_0_5_0.sqlite | PortfolioLab_Financial_0_5_1.sqlite |
| SHA-256 файла | 060537796eea…b634 | d4a69da49bf4905735407087b78e337b3235fef6fe1a705302664ca60fcee96f |
| Размер, байт | 311 996 416 | 308 666 368 |
| data_release | 0.5.0-synthetic9-2026-10-18 | 0.5.1-corrections-2026-10-21 |
| data_version | e43569f3…83f1 | f04fde3fb10a9fa455a92548be25ec0f3580898db7e6c76180a16913cf132b1f |
| Пространство имён D1 | re43569f3_ | rf04fde3f_ |
| Строк проекции (42 таблицы) | 1 946 745 | 1 946 772 |
| manifest_sha256 | e58b0b33…29d7 | e3b149a186765e2e9f6e8863be129ee1626f8e968728af27febcecd562f73551 |
| SQL-мастер (финансы + mm_, SQLite 3.53.1) | d58b5104…dac1 | fc60eab7a94e14b8954eac5ae93b3ba2ed70c2ce5e9bce1729ef8618f86acaf4 |
| Индикатор ширины | 1.3.0, 6d220910…58ca | 1.3.1, 5a61a8075492412909804e2cc0c95ab7ab8aedcd9e9bb07c6ef5010bf68955ac |
| Вход аллокации | 99f1e4af…84b0 | 13afdf89a8914f7c95c52481d7c9769caefddfb9c988035917cc5279ce07de7b |
| Архив индекса (провенанс) | faf79a3f…b0d8 | 278de29d6802eddfe24337f4e7946d41347da9db69b8ef1621ff89f9cc202179 |
data_version 0.5.1 = SHA-256(data_version 0.5.0 ‖ SHA-256 перечня исправлений ‖ SHA-256 сборщика). Метаданные базы содержат ссылки на предыдущий выпуск, перечень и сборщик.
Как получен выпуск
Исходный архив акций (moex_factors.sqlite), из которого движок собирает базовый слой, в рабочем окружении отсутствует, поэтому полная пересборка из первоисточника невозможна. 0.5.1 — документированный корректирующий выпуск поверх принятой 0.5.0:
db/corrections-0.5.1.jsonперечисляет 23 решения. У каждого — действие, причина и файлы-доказательства с SHA-256 (control/evidence_0_5_1/).scripts/build_financial_0_5_1.pyоткрывает 0.5.0 только для чтения, проверяет её SHA-256 и хеши всех доказательств и применяет изменения к копии.- Ряд полной доходности базы удовлетворяет
TR_t = TR_{t−1}·(P_t·k + D)/P_{t−1}. Поэтому исправление на дату E умножает все уровни с даты E на постоянный множитель. Удаление выплаты D даётP/(P+D), добавление —(P+D)/P, замена суммы —(P+D₁)/(P+D₀), дробление 1:k —k. Перед применением сборщик проверяет, что в 0.5.0 дневная доходность на дату E точно равна формуле со старыми данными; иначе сборка останавливается. - Удалённые записи переносятся в
event_exclusionsвместе с полным содержимым и зависимыми строками. Сырые строкиdistribution_evidenceне удаляются. Новые решения записаны вevent_reviewsиsources. - Сборка детерминирована: два запуска дают побайтно одинаковый файл.
Исправления
| № | Бумага | Событие | Решение | Множитель TR с даты | Основание |
|---|---|---|---|---|---|
| 01 | GAZP | 52,53 ₽, экс-дата 19.07.2022 | удалить: ГОСА 30.06.2022 решило не платить за 2021 год | 0,782970 (−21,70%) | новость 30.06.2022, dohod.ru |
| 02 | MAGN | 3,55 ₽, 31.03.2022 | удалить: дивиденд за 4 кв. 2021 отменён | 0,925184 (−7,48%) | dohod.ru, investfuture |
| 03 | NLMK | 2,60 ₽, 09.01.2023 | удалить: за 2022 год дивиденды не объявлялись | 0,976991 (−2,30%) | эмитент, dohod.ru |
| 04 | GMKN | 248,48 ₽, 05.06.2014 | удалить дубль: реестр 06.06.2014 — дата решения | вне окна TR | эмитент |
| 05 | PHOR | 21 ₽, 30.12.2016 | удалить: такой выплаты нет | 0,991985 (−0,80%) | эмитент |
| 06 | PHOR | 126 ₽, 11.10.2023 | удалить: ВОСА 30.09.2023 «решение не принято» | 0,981579 (−1,84%) | эмитент |
| 07 | PHOR | 201 ₽, 04.07.2025 | удалить: ВОСА 24.06.2025 «решение не принято» | 0,967685 (−3,23%) | эмитент |
| 08 | MSTT | 11,29 ₽, 20.12.2019 | удалить: ВОСА 12.12.2019 не состоялось (нет кворума) | 0,912946 (−8,71%) | НРД 577974, 568534 |
| 09 | MSNG | 0,2261 ₽, 03.03.2026 | удалить: «решение о выплате не принято общим собранием» | 0,907618 (−9,24%) | НРД 1360329 |
| 10 | RTKM | 5,9155 ₽, 28.04.2016 | удалить дубль: 03.05.2016 — реестр для участия в ГОСА | 0,944144 (−5,59%) | НРД 179443, 183026 |
| 11 | RTKMP | 5,9155 ₽, 28.04.2016 | удалить дубль, как № 10 | 0,924802 (−7,52%) | НРД 179443 |
| 12 | GMKN | 248,0 → 248,48 ₽, 16.06.2014 | точная сумма эмитента | 1,000070 (+0,007%) | эмитент |
| 13 | RTKM | 5,92 → 5,915466946266 ₽, 07.07.2016 | точная сумма решения ГОСА | 0,999952 | НРД 179443 |
| 14 | RTKMP | 5,92 → 5,915466946266 ₽, 07.07.2016 | как № 13 | 0,999939 | НРД 179443 |
| 15 | PHOR | 25 → 250 ₽, 27.10.2011 | 250 ₽ на акцию до дробления (3 111 927 000 ₽ на 12 447 708 акций) | 1,020064 (+2,01%) | НРД 49355 (решение ВОСА 01.12.2011) |
| 16 | MSTT | +7,09 ₽, 15.07.2014 | добавить пропущенную выплату за 2013 год | 1,066573 (+6,66%) | investfunds, investmint, vsdelke, okama |
| 17 | MSTT | +7,09 ₽, 22.05.2015 | добавить выплату за 2014 год | 1,080477 (+8,05%) | те же |
| 18 | MSTT | +10,64 ₽, 08.07.2016 | добавить выплату за 2015 год | 1,120498 (+12,05%) | те же и 2stocks |
| 19 | PHOR | дробление 1:10, 26.03.2012 | записать корпоративное действие | ×10 (TR, price_level, PHOR_PRICE) | MOEX n422, ISS, НРД 49355 |
| 20 | MSTT | выделение АО «Дороги и Мосты», 12.10.2020 | раскрыть: новые акции не оценены в TR | — | НРД 656337 |
| 21 | NMTP | 0,06 ₽, реестр 12.07.2021 | подтверждено, без изменений | — | НРД 743310 |
| 22 | MDMG | 47 ₽, реестр 14.07.2026 | подтверждено, без изменений | — | НРД 1414829 |
| 23 | MCFTR | 09–11.01.2023 | база верна, расхождение на стороне okama | — | MOEX ISS |
Итог по последнему уровню полной доходности: GAZP −21,70%, MSNG −9,24%, MAGN −7,48%, RTKMP −7,53%, RTKM −5,59%, NLMK −2,30%, GMKN +0,007%, MSTT +17,89%. У PHOR провал на −90,8% 26.03.2012 снят; без учёта самого дробления уровень ниже на 3,88%.
Годовой контроль dividend_annual_control после исправлений согласован для GAZP 2022, GMKN 2014, MSNG 2026, NLMK 2023, PHOR 2023 и 2025, RTKM и RTKMP 2016. Расхождения MAGN 2022 и PHOR 2017 — перенос выплат между календарными годами у второго источника; суммы по смежным годам совпадают.
Исправления прежних выводов 2.4.2
- Вывод «GMKN: дубль 248 ₽ 16.06.2014, TR завышен на 3,7%» был ошибочным. Эмитент указывает реестр 17.06.2014 и 248,48 ₽. Ошибочна запись с реестром 06.06.2014, она лежит вне окна TR. Реальное влияние на ряд — только уточнение суммы, +0,007%.
- Вывод «MSTT 11,29 ₽ в декабре 2019 — база верна, okama ошибается» был ошибочным. Собрание 12.12.2019 не состоялось, выплаты не было.
- Выплаты MSTT 7,09 ₽ (2014 и 2015) есть не только в okama: их подтверждают investfunds, investmint и vsdelke, а цена на экс-даты падает на величину выплаты.
Ширина рынка 1.3.1
Принятое исследование 1.3.0 не пересчитывается целиком. scripts/correct_market_breadth.py берёт его участников и для девяти бумаг с изменённым рядом (GAZP, GMKN, MAGN, MSNG, MSTT, NLMK, PHOR, RTKM, RTKMP) пересчитывает отношение TR к SMA200 тем же правилом: 200 последовательных поддерживаемых уровней, те же даты. Перед изменением строки инструмент проверяет, что TR исследования равен финансовому TR с постоянным множителем и что отношение к SMA200 совпадает до 1e-9. Неизвестные статусы, идентичности, даты и все прочие участники не меняются.
Пересчитано 608 строк участников; статус изменился у 13 — во всех случаях с «выше» на «ниже». Число участников выше SMA200 изменилось в 12 месяцах:
| Месяц | Бумаги | Ширина 1.3.0 → 1.3.1 |
|---|---|---|
| 2016-08 | RTKM | 76,0% → 74,0% |
| 2016-10 | RTKMP | 76,0% → 74,0% |
| 2016-11 | RTKMP | 68,0% → 66,0% |
| 2016-12 | RTKM, RTKMP | 74,0% → 70,0% |
| 2017-08 | PHOR | 46,0% → 44,0% |
| 2022-09 | GAZP | 17,1% → 14,6% |
| 2022-11 | GAZP | 25,0% → 22,5% |
| 2022-12 | GAZP | 30,0% → 27,5% |
| 2023-01 | GAZP | 45,0% → 42,5% |
| 2023-02 | NLMK | 62,5% → 60,0% |
| 2024-03 | PHOR | 63,3% → 61,2% |
| 2026-04 | MSNG | 52,2% → 50,0% |
Полный перечень с прежними и новыми значениями: public/market-breadth/corrections-1.3.1.json. Выгрузки 1.3.0 сохранены в public/market-breadth/archive-1.3.0/.
Влияние на результаты
Отдельная стратегия аллокации MCFTR / MM_CBR, 05.01.2015–16.10.2026, 1 000 000 ₽, расходы 10 б.п.:
| τ | Капитал 0.5.0 / 1.3.0 | Капитал 0.5.1 / 1.3.1 | CAGR | Волатильность | Макс. просадка |
|---|---|---|---|---|---|
| 0 | 4 664 022 ₽ | 4 660 585 ₽ (−3 437 ₽) | 13,967% → 13,960% | 10,06% → 10,04% | −22,84% без изменений |
| 10 п.п. | 4 706 788 ₽ | 4 703 859 ₽ | 14,055% → 14,049% | 12,02% → 11,99% | −26,15% без изменений |
| 20 п.п. | 4 655 676 ₽ | 4 653 317 ₽ | 13,949% → 13,945% | 14,01% → 13,99% | −28,97% без изменений |
Ряды 100% MCFTR и 100% MM_CBR не изменились. Пять модельных портфелей состоят из фондов и индексов и не затронуты: изменились только ссылки провенанса. Пользовательские портфели с GAZP, MAGN, NLMK, PHOR, MSTT, MSNG, RTKM, RTKMP или GMKN после переключения дадут другие результаты, поэтому прежние паспорта расчётов нужно повторить.
Проверка
| Проверка | Результат |
|---|---|
Независимая сверка 0.5.1 с 0.5.0 (scripts/verify_financial_0_5_1.py) | 16/16 PASS. Изменились только 14 таблиц перечня. Ряды 232 незатронутых инструментов совпадают построчно. У затронутых рядов те же даты и признаки, а множители совпадают с документированными до 1e-12. Независимый пересчёт TR из цен, выплат и дроблений даёт ошибку ≤ 6e-16 |
| Повторная сборка | побайтно тот же SHA-256 |
SQL-проекция 0.5.1 (verify_database.py --available-inputs-only) | 42 таблицы, 1 946 772 строки по всем полям. Статус PASS_PARTIAL: базовая 0.4.3 и сырые входы синтетических моделей в окружении не восстановлены |
Независимая пересборка проекции (master42.py, SQLite 3.53.1, пакет SQL-склада) | мастер совпал побайтно; 42/42 таблицы, 541/541 пакет, manifest_sha256 совпадает |
Миграция drizzle/0003_financial_0_5_1.sql | 42 таблицы, 5 представлений, 5 индексов, без DROP. Пространства 0.5.0 и 0.4.3 остаются в схеме |
Загрузка через API (tests/sql-api.mjs, tests/launch-api.mjs) | PASS: 541 пакет записан и прочитан обратно по всем полям |
Python ↔ JS (tests/reconcile-engines.py) | PASS: 51 сценарий, 3 сравнения, максимальная разница NAV 2,5e-8 ₽ |
| Остальные контроли (parity, comparison, history, money-market, primary-review, workspace, модели, таймлапс, аллокация, хронология, шрифты, мобильные, interface-contract) | PASS |
Не выполнялось в этом окружении (нет входов или прав):
- полная пересборка из
moex_factors.sqliteиtools/control.py --full; tests/synthetic-models.py --rebuild— нет сырых входов; синтетические таблицы побайтно равны 0.5.0;tests/market-breadth.pyиtests/index-history.pyс архивами;- загрузка в рабочий D1 и HTTP-сверка;
- браузерная приёмка и нагрузка.
Открытые вопросы
- Выделение «Дорог и Мостов» из MSTT (12.10.2020) не оценено в TR. Акции новой компании не торгуются, достоверной оценки нет.
- Проверены все бумаги, которые выявили сверка с okama и годовой контроль. Остальные выплаты из одного источника (smart-lab) повторно не сверялись с НРД. Систематическая сверка всех одиночных записей с сообщениями DVCA/XMET НРД — следующий шаг.
- Прежние открытые вопросы 0.5.0 сохраняются: TCSG/AGRO RUB, неполные годовые реестры семи бумаг, правила 15 БПИФ,
available_at= NULL во всех 1 312 строкахevent_timing.
Запуск финансового выпуска 0.5.1 на сайте — порядок действий
Переключение выполняется в два развёртывания: сначала загрузка нового среза рядом с работающим, затем переключение. Сначала рабочий API продолжает отдавать запечатанный 0.5.0, а 0.5.1 загружается в собственное пространство таблиц rf04fde3f_ через временный маршрут /api/staging/. Только после полной сверки второе развёртывание делает 0.5.1 активным и убирает маршрут загрузки. Аудитория сайта не меняется: доступ остаётся закрытым, как раньше.
Развёртывание, секреты и запросы к рабочему сайту выполняет владелец. Ключи вводятся только в скрытый stdin загрузчика; в файлы, аргументы и журналы они не попадают.
0. Предусловия
- Рабочий сайт отдаёт 0.5.0:
GET /api/database/status→state: ready,data_version: e43569f3…83f1. - Есть checkout опубликованного коммита (UI 0.13.0, данные 0.5.0) и этот пакет 0.5.1.
- Python 3.12+, Node.js 22+ и для загрузчика
aiohttp(pip install aiohttp). - На D1 есть место ещё под ~1,95 млн строк. Пространства 0.4.3 и 0.5.0 не удаляются.
Локальная репетиция обеих фаз (рабочий 0.5.0 → загрузка 0.5.1 → переключение) уже выполнена:
python3 tests/prepare-staging-rehearsal.py
node tests/staging-rehearsal.mjs # tests/staging-rehearsal-validation.json: 10/10 PASS
1. Фаза 1 — развёртывание с маршрутом загрузки
python3 launch/apply_phase.py phase1 /path/to/live-checkout
Инструмент сначала проверяет, что checkout — проверенный рабочий 0.5.0: SHA-256 db/runtime-manifest.json, lib/sql-api.mjs, db/schema.ts и журнала миграций. Затем копирует файлы из launch/phase1-staging/:
| Файл | Назначение |
|---|---|
drizzle/0003_financial_0_5_1.sql, drizzle/meta/* | создают 42 таблицы, 5 представлений и 5 индексов rf04fde3f_; без DROP |
db/schema.ts, db/releases/base-schema-0-5-0.ts | граф схемы сохраняет 0.4.3 и 0.5.0 |
lib/sql-api-core.mjs, lib/sql-api.mjs | тот же API, отдельный экземпляр на каждый манифест; активный манифест остаётся 0.5.0 |
lib/sql-api-staging.mjs, app/api/staging/[...path]/route.ts | временный маршрут /api/staging/: только загрузка и чтение 0.5.1, расчёты запрещены |
db/next-runtime-manifest.json | манифест 0.5.1, manifest_sha256 e3b149a1…3551 |
Сборка npm run build должна показать маршруты /api/:path+ и /api/staging/:path+. После развёртывания проверить:
GET /api/database/status→ по-прежнему 0.5.0,ready;GET /api/staging/database/status→data_version f04fde3f…,state: uninitialized,expected_chunks: 541.
2. Загрузка 0.5.1
Нужны пакеты work/sql-seed/00000.json…00540.json и work/sql-seed/manifest.json из этого пакета; манифест совпадает с db/runtime-manifest.json побайтно.
python3 scripts/seed_site_database_async.py https://<адрес сайта> \
--manifest db/runtime-manifest.json --seed-dir work/sql-seed \
--api-prefix staging/ --workers 6 --report tests/staging-0.5.1-live-import.json
Загрузчик запрашивает ключ обхода и ключ импорта скрыто. Каждый пакет сверяется по SHA-256 и после записи читается обратно по всем полям. Повтор пакета допустим: ранее подтверждённый вернёт already_verified. finish проверяет число строк всех 42 таблиц, внешние ключи и метаданные, затем запечатывает выпуск (ready). После этого маршрут отвечает 403 на любую попытку загрузки.
Сверка загруженного среза до переключения. Скрипт сравнивает 290 историй со статическими выгрузками 0.5.1, а также каталог и денежную модель. Манифест и выгрузки он берёт из этого пакета, ключ обхода читает из скрытого stdin.
python3 tests/live-sql-api.py https://<адрес сайта> --api-prefix staging/ --report tests/staging-0.5.1-live-api-validation.json
3. Фаза 2 — переключение
Развернуть дерево этого пакета (данные 0.5.1, UI 0.13.0). Перед развёртыванием проверить:
python3 launch/apply_phase.py verify-phase2 .
Проверка требует, чтобы активный манифест был 0.5.1, временные файлы загрузки были удалены, миграция 0003 оставалась на месте, а public/data/catalog.json был выгрузкой 0.5.1.
После развёртывания:
GET /api/database/status→0.5.1,ready, 541/541 пакетов, 1 946 772 строки;- заголовок
x-portfoliolab-data-version: f04fde3f…во всех ответах API; GET /api/staging/...→ 404;- старые страницы с данными 0.5.0 получают при расчёте 409 «Версия страницы или данных изменилась» и должны обновиться — это штатное поведение;
python3 tests/live-launch.py https://<адрес сайта> --quick(секрет только через скрытый stdin).
Затем отозвать временный ключ импорта. Независимо от ключа запечатанные срезы закрыты для загрузки состоянием ready.
4. Откат
Откат — повторное развёртывание прежнего коммита 0.13.0 / 0.5.0. Таблицы 0.5.0 не изменялись (это проверено в репетиции по хешам манифеста), поэтому прежний код сразу работает со своим пространством. Строки готовых срезов не перезаписываются и не удаляются.
5. Чек-лист перед открытием
| Пункт | Статус |
|---|---|
| Финансовая база 0.5.1 собрана и независимо проверена (16/16) | готово |
| SQL-проекция и миграция 0.5.1, загрузка и чтение 541 пакета локально | готово |
| Репетиция двух фаз запуска | готово, 10/10 |
| Все контроли сайта на данных 0.5.1 | PASS, кроме не запускавшихся из-за отсутствия входов (см. RELEASE_0_5_1_RU.md) |
| Загрузка в рабочий D1 и HTTP-сверка | выполняет владелец по разделам 1–3 |
| Браузерная приёмка на телефоне и компьютере | не выполнена; статические и DOM-проверки её не заменяют |
| Нагрузочная проверка | не выполнена; лимит пилота — один активный расчёт на isolate |
| Права на использование данных (MOEX, ЦБ, агрегаторы, okama) для выбранной аудитории | не подтверждены |
TCSG/AGRO RUB, неполные годовые реестры, правила 15 БПИФ, available_at | открыты, раскрыты в методике |
| MSTT: невыясненная стоимость выделения «Дорог и Мостов» (2020) | раскрыто |
| Систематическая сверка одиночных выплат с сообщениями НРД | следующий шаг |
Без отдельного решения владельца аудитория не меняется и публичный доступ не открывается.