Методика и контрольХронология бэктеста

Причинность бэктеста и порядок модельного исполнения

Редакция от 20.10.2026 для интерфейса 0.11.0 и отдельного движка breadth-allocation-1.0.1. Рыночный срез заморожен на 16.10.2026. Документ дополняет docs/BREADTH_ALLOCATION_RU.md и описывает проверенную последовательность расчёта, единицы журнала и пределы проверки.

Результат и точный объём проверки

node tests/backtest-causality.mjs формирует протокол work/review/causality-audit.json. На проверенной редакции все 16 проверок имеют результат PASS; общий статус — PASS_WITH_DATA_LIMITATIONS, поле temporal_code_checks — PASS.

Это означает: в проверенных сценариях будущие допустимые наблюдения не меняют прошлые оценки, веса и исполнения; новые веса начинают получать доходность после модельного закрытия исполнения. Проверка не подтверждает строгую point-in-time доступность исходных данных и не доказывает возможность реального исполнения по расчётным уровням.

Проверяемая проекция — public/breadth-strategy/data.json:

ХарактеристикаЗафиксированное значение
Версия данных99f1e4afa8abbf45111499c8ae1da6fc935581ae242710f7d5f08aa3fd1b84b0
Физический SHA-256 входного JSONfcdfd39433cc5b0e440f4abec505294905fce8e3b9cb667ecfdb614cc3e4b3a4
Оценочный календарь2 965 сессий, 05.01.2015–16.10.2026
Доступные активы18
История месячного индикатора226 срезов; ранняя диагностика не означает портфельный бэктест с 2008 года
Начальный сценарий проверкиMCFTR / MM_CBR, порог 0 п.п., капитал 1 000 000 рублей, издержки 10 б.п. оборота
Исполнения начального сценария142 события модельной ребалансировки, включая первоначальное инвестирование

Финансовый выпуск 0.5.0, движок статического конструктора 0.5.0-rc.2, месячный архив 1.0.0 и принятое исследование breadth 1.3.0 сохраняют свои версии. Исходные данные и числовые результаты архивного сценария 1.3.0 с порогом 20 п.п. не переписываются. Проверка новой страницы не заменяет воспроизведение этого архива и не переносит его условия в новый движок.

Какой сигнал используется

Индикатор обновляется по сохранённому месячному расписанию. Это не внутридневное срабатывание и не ежедневная проверка пересечения порога. signal_date обозначает завершённую сигнальную сессию, предшествующую плановому исполнению. Сигнал с датой, равной плановой дате исполнения либо более поздней, отклоняется при проверке входов.

Состав сигнала — исторические участники IMOEX независимо от выбранной пары инвестиционных активов. Положительная категория включает TRI выше либо равный SMA200; неизвестные сигналы остаются в общем знаменателе:

B = (above + equal) / total
tau = threshold_pp / 100
w_defensive = max(0, 1 - B - tau)
w_primary = 1 - w_defensive

Порог по умолчанию равен 0 п.п. Целевые веса — результат формулы для следующей ребалансировки. Между исполнениями фактические модельные веса изменяются вслед за уровнями активов и могут отличаться от целевых. Отсутствующий индикатор не заменяется нулевой шириной рынка.

Сохранённый вход содержит исторический состав на плановую дату исполнения, а TRI/SMA — на предыдущее закрытие. Доказательства того, что именно этот будущий вступающий в силу состав был опубликован к сигнальному закрытию, в полном объёме отсутствуют. Это отдельное ограничение знания состава на дату сигнала; неравенство дат его не устраняет.

После сигнала: когда и по какому уровню происходит операция

Правило движка — next_eligible_common_close, то есть первая допустимая общая дата закрытия после сигнала и не раньше плановой даты. На каждой дате порядок следующий:

  1. Переоценить прежние количества условных единиц текущими уровнями. Вся

доходность интервала до этого закрытия принадлежит прежним позициям.

  1. Выбрать последнее уже наступившее месячное решение с signal_date строго

раньше текущей даты.

  1. Проверить can_rebalance обоих выбранных активов, включая актив с

нулевым целевым весом. При отсутствии допуска любой стороны отложить всю ребалансировку.

  1. На допустимом закрытии рассчитать оборот обеих сторон, вычесть издержки и

установить новые количества условных единиц по точным уровням этой даты.

  1. Новые количества получают доходность следующего интервала.

Уровень сигнального закрытия не используется как уровень исполнения. Цена открытия следующей сессии и внутридневной момент сделки не моделируются. Входы и журнал содержат даты без времени суток; термин «закрытие» обозначает выбранную дневную расчётную отметку. Для индекса, синтетической модели и справочного ряда это условная экспозиция по разрешённому уровню.

Если общее исполнение отложено, прежние позиции продолжают действовать. Если до исполнения наступило новое месячное решение, оно заменяет ожидающее старое; отдельная задним числом исполненная операция по старому решению не создаётся. При старте пользовательского окна после плановой даты допускается последнее доступное месячное решение с сигнальной датой раньше фактического старта. Поэтому расстояние от плановой даты до начального исполнения не обязательно означает задержку уже открытого портфеля.

При пропуске оценки после первого наблюдения разрешено оценить открытую позицию последним прошлым уровнем. Такой перенос помечается valuation_carried и не разрешает исполнение. Первое будущее наблюдение не переносится назад для заполнения начальных пропусков. На всех допустимых исполнениях оба признака перенесённой оценки равны false.

input_age_days хранит переданный возраст исходного входа либо null. Он не является исходным временем публикации и сам по себе не доказывает ликвидность или исполнимость уровня. У синтетических и справочных рядов разрешённый уровень может опираться на ранее вступившее в силу значение.

Учёт капитала и издержек

Пусть L_P, L_D — уровни на закрытии исполнения, q_P, q_D — прежние условные количества, cash — ещё не инвестированный начальный капитал.

V_before = q_P * L_P + q_D * L_D + cash
T = abs(w_P * V_after - q_P * L_P)
  + abs(w_D * V_after - q_D * L_D)
cost = costBps / 10000 * T
V_after = V_before - cost
q_P_after = w_P * V_after / L_P
q_D_after = w_D * V_after / L_D

Уравнение для стоимости после издержек решается численно. Издержки относятся к сумме абсолютных изменений обеих позиций, включая первоначальное инвестирование. Целевые веса относятся к капиталу после издержек. После начального инвестирования свободный остаток модели равен нулю; MM_CBR является выбранным активом, а не этим техническим остатком. Налоги и финальная ликвидация не моделируются.

Единицы уровней: почему журнал не показывает цену пая в рублях

Журнал фиксирует точные значения series.levels из принятой проекции на дату исполнения. Масштаб ряда влияет на условное количество, но сам по себе не меняет доходность отношения уровней. Наименование исходного актива не меняет единицы опубликованного расчётного ряда.

АктивЕдиница *_level_unitЭкономический смысл
MCFTRindex_pointsПункты индекса полной доходности; индекс нельзя купить как пай. Дивиденды уже входят в ряд
Реальные БПИФ: SBMX, SBGB, LQDT, GOLD, TGLDnormalized_total_wealth_unitsНормированный уровень полной стоимости, созданный из истории фонда; это не исходная котировка в рублях за пай
MM_CBR и другие синтетические моделиnormalized_total_wealth_unitsРасчётные единицы модели. MM_CBR воспроизводит условное начисление по исторической ставке, а не реальную цену фонда
USD_RUB, EUR_RUB, CNY_RUB, GOLD_RUBnormalized_total_wealth_unitsНормированное представление официальных справочных значений Банка России, применённых по датам вступления в силу; это не исполнимая рыночная котировка

Поле *_execution_basis сохраняет политику исходного паспорта актива: hypothetical_at_observed_index_close, hypothetical_at_admitted_model_level, observed_tradable_fund_close либо hypothetical_at_effective_official_reference. Даже значение observed_tradable_fund_close описывает происхождение допуска фонда; в журнале используется нормированный уровень, а исходная котировка CLOSE в рублях за пай в этой проекции отсутствует. *_units_before и *_units_after — расчётные количества, а не число фактически купленных ценных бумаг.

Из нормированного уровня нельзя восстановить подтверждённую цену заявки, число лотов либо официальный аукционный fill. MOEX отдельно определяет официальную цену закрытия через LEGALCLOSEPRICE; последняя сделка может отличаться от неё. Поэтому дневной ряд нельзя автоматически описывать как гарантированное исполнение на аукционе закрытия. Спрос, предложение, очередь заявок, лотность, ликвидность, спред и внутридневное проскальзывание в этом движке не рассчитываются.

Контракт журнала и манифеста

Каждый элемент result.events — событие расчёта и исполнения месячной ребалансировки, включая первоначальное инвестирование; это не отдельный биржевой fill. Событие может иметь нулевой торговый оборот.

Поля событияСодержание
signal_date, planned_date, execution_dateСигнальное закрытие, плановая и фактическая модельная даты
execution_model, weights_effectivenext_eligible_common_close, after_execution_close
primary_symbol, defensive_symbolТочные коды выбранной пары
primary_level, defensive_levelТочные допущенные уровни на закрытии исполнения
primary_level_unit, defensive_level_unitЕдиницы уровней из таблицы выше
primary_execution_basis, defensive_execution_basisПолитики допуска активов из входных метаданных
primary_input_age_days, defensive_input_age_daysВозраст входа из проекции либо null; дата публикации не выводится из возраста
primary_valuation_carried, defensive_valuation_carriedПризнаки переноса оценки; на допустимом исполнении false
primary_units_before, defensive_units_before, primary_units_after, defensive_units_afterКоличества условных единиц до и после операции
primary_value_before, defensive_value_before, primary_value_after, defensive_value_afterСтоимость каждой позиции в рублях до и после операции
cash_before, cash_afterТехнический остаток начального капитала; после инвестирования равен нулю
breadth, primary_weight, defensive_weightСигнал и целевые веса на капитал после издержек
value_before, value_after, costОбщая стоимость до/после операции и удержанные издержки, рублей
traded_notional, turnoverСуммарный оборот обеих сторон в рублях и его доля в value_before
delay_daysКалендарная разница фактической и плановой дат, без предположения о числе торговых сессий

result.execution и manifest.execution также сохраняют:

execution_model = next_eligible_common_close
signal_timing = prior_closed_session
weights_effective = after_execution_close
return_interval_rule = pre_trade_holdings_earn_return_through_execution_close
source_timestamp_certification = false

Манифест сохраняет версию движка, версию данных, параметры и фактическое окно. run_sha256 идентифицирует канонические параметры и версии запуска; он не заменяет физические хеши данных, исходного кода и протокола контроля.

Что проверяют 16 тестов причинности

№Проверка
1Усечение всех будущих входов на шести датах сохраняет доступный прошлый префикс: дневные оценки, целевые и фактические веса, отметки, бенчмарки и события
2Допустимые изменения будущих уровней в 32 и 1/32 раза не меняют прошлые оценки и исполнения
3Независимость от будущих цен проверяется для всех 18 выбираемых активов в их общем окне
4Удаление будущих уровней и разрешений не меняет завершённый более ранний расчёт
5Изменение будущих breadth с согласованными счётчиками не меняет прошлые цели и доходность
6Удаление будущих сигналов сохраняет прошлый результат
7Ручной пример 100 → 200 → 400 подтверждает: сигнальная отметка не является исполнением; прежняя позиция получает доходность до закрытия исполнения, новая — следующий интервал
8Сигнальная дата в день планового исполнения или позже отклоняется
9Каждая сторона отдельно блокирует исполнение, в том числе при нулевом целевом весе
10Чередующиеся пропуски обеих сторон откладывают операцию до общей допустимой даты; будущая отметка не заполняет пропуск назад
11Начальный пропуск не заполняется первым будущим наблюдением
12Новый наступивший сигнал заменяет ожидающее старое решение без дополнительного прошлого исполнения
13Все 142 исполнения начального сценария проходят строго после сигнала на первой общей допустимой дате
14В статическом конструкторе календарная ребалансировка происходит после доходности прежних позиций; сигнал breadth в нём не применяется
15Будущие котировки не меняют прошлый результат статического конструктора
16Происхождение данных явно сохраняет отсутствие строгой point-in-time сертификации

Даты усечения первого теста: 30.06.2016, 30.12.2019, 24.03.2022, 25.03.2022, 30.09.2024 и 30.09.2026. Сравнивается весь доступный общий префикс; если на конечной дате отсутствует исходная отметка одной стороны, фактическое окно корректно заканчивается раньше.

Проверки статического конструктора выполнены без внешних денежных потоков. Его расписание подтверждённых концов месяцев строится по полному известному календарю; исторические версии публикации торгового календаря не проверены. Валидация всего входа включает будущие записи: некорректная будущая запись может отклонить запуск. Независимость числового прошлого проверена для допустимых изменений будущих данных.

Ограничения исходных данных и допустимый вывод

Строгий point-in-time означает использование именно тех сведений и версий, которые были доступны участнику в соответствующий исторический момент. Порядок вычислений и проверка этой доступности — отдельные задачи.

В текущем срезе остаются открытыми:

пересмотров, включая ретроспективные корпоративные корректировки;

сигнальное закрытие;

винтажа исторической идентичности в 37 месяцах. Точные наборы выпусков согласованы для 223 из 226 месячных срезов; принятый индикатор не менялся;

и вся история корпоративных действий отдельно не сертифицированы;

отсутствие симуляции реальных заявок, открытия, ликвидности и проскальзывания.

Протокол не является полным повторным построением исходных архивов, визуальным или браузерным аудитом либо подтверждением фактической торговли. Результат бэктеста остаётся гипотетическим. Перебор порогов является анализом чувствительности на истории, а не доказательством будущей оптимальности.

Корректная краткая формулировка результата:

> В проверенной последовательности расчёта использование будущих наблюдений > для прошлых оценок и исполнения не обнаружено. Строгая историческая > доступность всех исходных данных не подтверждена. Операции моделируются по > допущенным дневным расчётным уровням, а не по подтверждённым ценам реальных > биржевых сделок.

Воспроизведение и сохранение результата

Выполнить из корня репозитория с закреплёнными входами и соответствующей редакцией кода:

node tests/backtest-causality.mjs

Сохранить протокол work/review/causality-audit.json вместе с точным commit, параметрами запуска, версией данных и хешами. Протокол фиксирует физический хеш входного JSON и хеши динамического движка, статического движка и теста. Каталог work/ является рабочим: его файл следует включить в постоянный контрольный комплект, а не считать сам каталог резервной копией.

Для восстановления исходников руководствоваться docs/PROJECT_CONTINUITY_RU.md и docs/PROJECT_DATA_REGISTRY_RU.md. Не загружать источники заново под видом того же винтажа и не заменять принятые хеши для устранения сбоя теста. Для воспроизведения конкретного пользовательского расчёта нужны тот же JSON, код, манифест параметров и фактическое окно. Новый рыночный срез или изменение правил требуют отдельной версии и нового протокола.

Первичные отраслевые источники

Эти материалы поддерживают определения и принципы проверки; они не сертифицируют формулу PortfolioLab и не означают соответствие GIPS.

  1. Московская биржа — индекс MCFTR и полная доходность.

Полная доходность включает изменение стоимости составляющих и реинвестирование дивидендов. Повторное добавление дивидендов к MCFTR недопустимо в принятом расчёте.

  1. Московская биржа — ценовые показатели фондового рынка.

Официальная цена закрытия публикуется как LEGALCLOSEPRICE; её следует отличать от иных дневных показателей.

  1. Московская биржа — технология аукциона закрытия, PDF.

На страницах 5 и 8 документа разобраны возможное различие последней сделки и официальной цены закрытия и исполнение заявки MOC на аукционе. Эти описания не подтверждают участие модельного портфеля в аукционе; текущее расписание не переносится автоматически на всю историю.

  1. CFA Institute — Backtesting & Simulation.

Бэктест приближает реальный инвестиционный процесс: правила, построение портфеля, ребалансировка, последующий результат. Отдельно учитываются look-ahead bias и survivorship bias.

  1. CFA Institute Research Foundation — Investment Model Validation: A Guide for Practitioners, Joseph Simonian, 2024, PDF.

Страницы PDF 18–19 описывают исторический состав инвестиционной вселенной и использование только доступной тогда информации; страница 54 — документацию для воспроизведения данных, тестов, метрик и решений.

Финансовый выпуск 0.5.0 · движок 0.5.0-rc.2 · интерфейс 0.13.0 · рыночный срез 16.10.2026Наверх ↑