95 KiB
Техническое задание
RequestLatencyLab: подготовка и проведение экспериментов для статьи 2
Статус: черновик. Не утверждено.
Копия исходного текста ТЗ, полученного с файлами спецификации. Контрольная сумма исходного файла RequestLatencyLab_TZ_RU.md (SHA-256) в спецификации:
d7548c7e71eedd7acaf74a2240179ff9d82bddeb741d398f728acfad80ec9c44. Исходный файл не изменяется; эта копия размещена в Docs для комплектности репозитория.
До утверждения ТЗ ведётся как единый рабочий документ без номера версии. Правки вносятся в текущий черновик и не оформляются как новые версии ТЗ. Эксперименты этим документом не считаются выполненными.
Уточнение пользователя: заданы рабочий каталог в Shared Projects, исходные каталоги LifecycleBenchmark и OrderLifecycle и отдельный Git-репозиторий в пространстве dng на MQL5 Forge. Создание удалённого репозитория выполняется после реализации. Этот черновик фиксирует требования, а не подтверждает создание каталога Windows, изменение исходников, сборку или публикацию.
Предлагаемый способ поставки зависимостей: использовать код из указанных пользователем каталогов через зафиксированный снимок и выделенные переиспользуемые модули. Способ фиксации зависимостей — проектное решение ТЗ для воспроизводимой сборки; сами пути и место публикации заданы пользователем.
Основание: редакторское задание пользователя; раздел «Статья 2. Измеряем наблюдаемую задержку торгового запроса» в MQL5_EXECUTION_MICROSTRUCTURE_ARTICLE_PLANS_RU.md; терминология GLOSSARY.md. Драфт статьи 1 и LifecycleBenchmark используются как исходный материал, но не как доказательство результатов новой лаборатории.
Сохраняются исходная структура LatencySample и все пять экспериментов в заданном порядке. Число наблюдений на ветвь сравнения, параметры ожидания, классификатор рынка и правила статистического расчёта ниже — методические решения этого ТЗ, а не дословные требования редактора. Документированные свойства MQL5 отмечены ссылками [D1]–[D12]; остальные числовые настройки являются параметрами предлагаемого протокола.
1. Цель, границы и комплект результатов
Разработать средствами MQL5 лабораторию, которая связывает торговый запрос с его событиями, измеряет локальные интервалы, проводит заданные серии и сохраняет отчёт, пригодный для повторного расчёта. Использовать термин client-observed request latency — задержка торгового запроса, наблюдаемая со стороны клиентского терминала.
Не измерять и не имитировать под видом измерений отдельные задержки сети, risk engine, gateway, поставщика ликвидности или matching engine. Синтетические проверки отделять от наблюдений на демонстрационном счёте.
В комплект входят:
- RequestLatencyLab.mq5 и вспомогательные .mqh: модели, сборщик, реестр запросов, сверка, запуск серий, статистика, хранение и панель;
- MQL5-программы подготовки рыночной классификации, повторного расчёта отчётов и автоматических тестов;
- README.md, CSV_SCHEMA.md, описание протокола, файлы настроек .set, сохранённые планы отправки;
- исходные журналы, CSV-отчёты, протоколы проверок, таблицы и иллюстрации для всех пяти экспериментов.
Сбор, расчёт метрик, статистика и подготовка результатов выполняются на MQL5. Внешние DLL, Python и платные компоненты не должны требоваться читателю. Новый проект обязан переиспользовать подходящий код LifecycleBenchmark и OrderLifecycle из каталогов раздела 2. Автономность означает сборку из нового репозитория с включёнными зафиксированными зависимостями, а не отказ от библиотек статьи 1.
В комплект также входят RequestLatencyLab.mqproj, dependencies.lock.json, Docs/DependencyChanges.md и .gitignore. Для каждого заимствованного модуля должно быть видно его происхождение и место использования в новом проекте. Простое хранение старых файлов без использования их кода не выполняет требование переиспользования.
2. Среда, размещение, зависимости и ограничения безопасности
2.1. Рабочий каталог и место публикации
Корень нового проекта, заданный пользователем:
C:\Users\EAPro\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Shared Projects\mql5-execution-microstructure-02-request-latency
Перенос строки после Terminal в сообщении пользователя является форматированием: фактический путь один, без разрыва строки и без дополнительного уровня каталога.
Основной советник RequestLatencyLab.mq5 и файл проекта RequestLatencyLab.mqproj находятся в этом корне. Собственные .mqh, программы подготовки данных, анализатор, тесты и настройки располагаются внутри того же проекта. Не создавать отдельную независимую рабочую копию исходников в другом каталоге терминала. Способ установки или запуска собранных программ описать в README; каталог исходников от этого не меняется.
Исходный каталог измерителя статьи 1:
C:\Users\EAPro\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Shared Projects\mql5-execution-microstructure\Experts\LifecycleBenchmark\
Исходный каталог регистратора статьи 1:
C:\Users\EAPro\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Shared Projects\mql5-execution-microstructure\Experts\OrderLifecycle\
Относительно корня нового проекта эти источники находятся по адресам:
..\mql5-execution-microstructure\Experts\LifecycleBenchmark\
..\mql5-execution-microstructure\Experts\OrderLifecycle\
Это адреса источников для проверки и импорта зависимостей, а не обязательные внешние пути для каждой последующей сборки опубликованного проекта.
Параметры будущего репозитория:
| Поле | Значение |
|---|---|
| Сервис | MQL5 Forge |
| Пространство владельца | dng |
| Адрес пространства | https://forge.mql5.io/dng |
| Имя репозитория | mql5-execution-microstructure-02-request-latency |
| Целевой адрес страницы | https://forge.mql5.io/dng/mql5-execution-microstructure-02-request-latency |
| Момент создания удалённого репозитория | После реализации и проверки кода |
Целевой адрес не является подтверждением существования репозитория. Точный адрес для Git clone/push берётся из созданного репозитория; не подставлять предположительный SSH-адрес, порт или URL API. Права доступа и видимость не выводятся из имени пространства и не изменяются произвольно. Если репозиторий с таким именем уже существует, сначала проверить его назначение и историю; запрещены перезапись существующей истории и принудительный push.
2.2. Основание для переиспользования
В составе текущих приложений получены LifecycleBenchmark.mq5, OrderLifecycleRecorder.mq5 и TradeLifecycle.mqh. Первые два содержат собственные обработчики событий и являются исходниками советников. TradeLifecycle.mqh содержит структуры, вспомогательные функции и CTradeLifecycle. Подключение двух советников целиком в новый советник не является выбранным способом интеграции: переиспользуемый код из них выделяется в .mqh без исходных обработчиков и глобального состояния.
| Исходник | Что использовать | Что изменить или проверить при интеграции |
|---|---|---|
| LifecycleBenchmark.mq5 | Реализации MinValue, MaxValue, AvgValue, Percentile; приёмы измерения длительности вызова, представления результатов и экспорта | Выделить статистические функции в .mqh. Добавить проверки границ, выделения памяти и пустой выборки. Сохранить линейную интерполяцию процентилей; в исходной функции p задан в шкале 0–100. Согласовать CSV с разделом 8 и корзины с разделом 7 |
| OrderLifecycleRecorder.mq5 | BuildRequest, PreCheck, нормализация параметров и вспомогательные торговые функции | Убрать зависимость выделенных функций от Inp*/EXT*. Передавать конфигурацию явно. Проверять шаг цены и объёма, режим исполнения и результат проверки по требованиям настоящего ТЗ. Не переносить автоматические повторы и безусловное подробное журналирование в измеряемый путь |
| TradeLifecycle.mqh | Форматы TradeEvent/PendingRequest, справочники RetcodeName/ShortTypeName/IsPendingType, существующий код накопления и проверки торговых сущностей | Подключать через адаптер. Не подменять редакторскую LatencySample старой структурой. Не сужать ulong sequence до uint local_seq. Различать тикет и идентификатор позиции. Проверять результат и полноту конкретного измерения, а не только последнюю цепочку класса |
Таблица описывает план интеграции, а не утверждает готовность этих функций к новому протоколу. Источником является текущий приложенный код, не более ранний листинг статьи. В частности, в приложенной версии CTradeLifecycle уже есть m_chain_start и EventInLastChain; при реализации необходимо учитывать именно эту версию.
Реестр всех LatencySample, политика T6, обработка поздних событий, планировщик пяти экспериментов и классификация рынка остаются ответственностью новых модулей. Их нельзя заменить старым ожиданием единственного активного замера EXT_wait_index/EXT_wait_comment. Сам по себе результат CTradeLifecycle::IsComplete не устанавливает T6 без проверок раздела 4.
Адаптер вправе использовать библиотечные структуры и проверенные вспомогательные функции без запуска старого диагностического цикла целиком. В MINIMAL нельзя вызывать наследуемые методы с неконтролируемым Print/PrintFormat, немедленной очисткой позиций или выводом на график. Доступность соответствующих участков кода проверяется при интеграции, а необходимые изменения документируются и покрываются тестами.
Одинаковые помощники из двух советников не должны превращаться в две расходящиеся реализации в новом проекте. Для общей функции выбирается один исходный вариант, изменения фиксируются, а вызовы сводятся к одному переиспользуемому модулю.
Исходные каталоги статьи 1 не изменять в рамках этого задания. Если выделение общего интерфейса потребует изменений там, такие изменения оформляются отдельной согласованной задачей. Доработки для статьи 2 выполнять в новом проекте, сохраняя исходные заголовки авторства и применимые лицензионные условия. Перед публикацией проверить условия в исходном проекте, не назначать лицензию по предположению.
2.3. Фиксация зависимостей и структура поставки
При начале реализации сопоставить приложенные файлы с файлами в двух исходных каталогах. Расхождение не устранять молча: сохранить различия и явно зафиксировать выбранную исходную редакцию. Приложенные файлы являются проверяемыми снимками; их тождество текущим файлам Windows пока не подтверждено.
Зафиксированный снимок хранится в Dependencies/Article01. Файлы .mq5 в этом снимке служат исходной контрольной версией для выделения кода и не включаются в новую единицу компиляции. Рабочие заимствованные модули помещаются в Include/RequestLatencyLab/Legacy. Подходящие компоненты TradeLifecycle.mqh используются адаптером из зафиксированного снимка; необходимые изменения не вносятся скрыто в контрольную копию.
Минимальная структура:
mql5-execution-microstructure-02-request-latency/
├── RequestLatencyLab.mq5
├── RequestLatencyLab.mqproj
├── Include/
│ └── RequestLatencyLab/
│ ├── ... собственные модули лаборатории
│ └── Legacy/
│ ├── BenchmarkStatistics.mqh
│ ├── TradeRequestTools.mqh
│ └── LifecycleAdapter.mqh
├── Dependencies/
│ └── Article01/
│ ├── LifecycleBenchmark/
│ │ └── LifecycleBenchmark.mq5
│ └── OrderLifecycle/
│ ├── OrderLifecycleRecorder.mq5
│ └── TradeLifecycle.mqh
├── Scripts/
├── Tests/
├── Presets/
├── Data/
├── Docs/
│ ├── RequestLatencyLab_TZ_RU.md
│ └── DependencyChanges.md
├── dependencies.lock.json
├── CSV_SCHEMA.md
├── README.md
├── CHANGELOG.md
└── .gitignore
Перечень собственных модулей определяется составом результатов раздела 1. Все файлы проекта и подключения собственных зависимостей должны использовать переносимые пути. Абсолютный путь C:\Users\EAPro и идентификатор каталога терминала не зашиваются в #include и обязательные настройки сборки. Их место — описание авторской среды и локальная конфигурация развёртывания.
В dependencies.lock.json для каждой заимствованной единицы фиксируются: исходный проект и относительный путь, исходный commit при наличии, SHA-256 исходного файла, путь контрольного снимка, путь используемого модуля, SHA-256 его версии и статус DIRECT/ADAPTED/REFERENCE_ONLY. Если commit не установлен, указывается отсутствие значения и используется файловая контрольная сумма; вымышленные версии запрещены. Включить также все фактически необходимые транзитивные зависимости.
В Docs/DependencyChanges.md указать исходные функции или диапазоны строк, причину адаптации, изменённые интерфейсы, ограничения и проверяющие тесты. Отдельно перечислить намеренно не перенесённое поведение: политика повторов, прежние сроки ожидания, схема CSV, глобальный активный замер и безусловное журналирование.
Обновление исходного проекта статьи 1 не должно автоматически менять код внутри серии. Обновление зависимости — отдельное изменение с новым lock-файлом, контрольной суммой и повторными тестами. Для официальных измерений запрещены незаписанные изменения рабочих зависимостей. Проверка чистой сборки должна проходить без соседнего каталога mql5-execution-microstructure; системные компоненты установленного MetaTrader 5 допускаются, их сборка фиксируется.
Data содержит только отобранные данные поставки и тестовые наборы. Полный профиль терминала, пароли, токены, персональные настройки и необработанные приватные торговые данные не включаются в Git. Компиляционные кэши, временные файлы, локальные журналы и автоматически созданные .ex5 исключаются из исходного репозитория; проверенные бинарные файлы при необходимости передаются отдельно с соответствующей версией исходников. Рабочий экспорт и состав публикуемой выборки описать раздельно; исходные исследовательские данные не удалять ради публикации.
2.4. Ограничения безопасности
Поддержать LOCAL_ONLY, PENDING_CREATE_DELETE и MARKET_ORDER. По умолчанию выбран LOCAL_ONLY. Для торговых режимов по протоколу 0.1 разрешён только демонстрационный счёт. Запуск серии требует явного действия оператора.
В пределах сравнения фиксируются сервер, счёт, символ, модель учёта позиций, объём, режим исполнения, допустимое отклонение, алгоритм выбора цены, сборка терминала, версия советника и все настройки измерителя. Реальные значения вносятся в manifest перед основными сериями; ТЗ не назначает конкретного брокера или символ за пользователя.
До старта проверить торговые разрешения, соединение, доступность котировки и спецификации символа, допустимость объёма, заполнения и цен. Неизбежные различия спецификации MARKET и PENDING в эксперименте 2 перечисляются раздельно и не маскируются как одинаковые настройки. Основной объём — минимальный допустимый для выбранного символа. Он не меняется внутри сравнения. Цены приводятся к шагу цены, объём — к шагу объёма. Режим заполнения выбирается по документированным ограничениям символа и типа операции; нельзя молча менять его после отказа. Для отложенных ордеров используется RETURN, для рыночных — заранее выбранный допустимый режим. [D10]
На тестируемом символе не должно быть сторонних позиций, ордеров, ручной торговли или других торгующих советников. При их обнаружении серия останавливается. Особенно важно не пытаться приписать общую неттинговую позицию советнику только по Magic Number последней сделки.
Одновременно допускается не более одной основной незавершённой операции. После неё выполняется служебное закрытие позиции либо удаление ордера. Эти запросы имеют собственные sequence и request_id, признак role=CLEANUP и parent_sequence. Они не входят в основные 100 наблюдений.
Нельзя отправлять закрытие из OnTradeTransaction сразу после первой сделки. Сначала завершаются наблюдение и сверка измеряемой операции. Любое аварийное вмешательство до окончания окна наблюдения получает отметку measurement_interrupted; затронутые временные точки не используются как незагрязнённые измерения.
Превышение времени ожидания не запускает автоматическую повторную рыночную заявку. При неопределённом исходе запрещены новые основные запросы до выяснения состояния. Служебные повторы допустимы только после сверки предыдущей попытки, каждый — отдельной записью; лимит задаётся до запуска.
При потере связи, ошибке записи, переполнении буфера, нарушении принадлежности объектов или неустранённом остатке прекращается новая торговля. Файл отчёта должен содержать причину остановки и список непроверенных объектов. Неизвестный исход не трактуется как отсутствие позиции.
3. Контракт данных и временных меток
3.1. Обязательная структура
Имена, типы и порядок полей редакторской структуры сохраняются:
struct LatencySample
{
uint request_id;
ulong sequence;
ulong send_start_us;
ulong send_return_us;
ulong request_event_us;
ulong order_event_us;
ulong first_deal_us;
ulong final_event_us;
uint retcode;
bool completed;
};
Один LatencySample соответствует одному фактическому вызову OrderSend либо OrderSendAsync, в том числе вызову с неуспешным возвратом. Запись резервируется до отправки. Проверки, после которых торговая функция не вызывалась, сохраняются в журнале подготовки, но не изображаются как отправленные запросы.
request_id берётся из MqlTradeResult. Идентификатор устанавливает терминал при отправке обеими функциями. Глобальный ключ измерения — session_id + sequence, а не один request_id. [D3]
В этом ТЗ retcode в обязательной структуре хранит код из соответствующего TRADE_TRANSACTION_REQUEST. Если такого события нет, retcode не считается известным: в памяти 0 с отдельным признаком отсутствия, в CSV — пустое поле. Код непосредственного возврата функции хранится отдельно в send_retcode. Это исключает смешение начального результата OrderSendAsync с результатом серверной обработки. [D2, D3]
completed означает, что исход операции подтверждён на момент формирования отчёта. Это не синоним полного исполнения и не признак наличия всех временных меток. Подтверждённый отказ также может иметь completed=true.
3.2. Дополнительные данные
Их хранить в связанной служебной структуре, не изменяя обязательную LatencySample:
| Группа | Обязательные данные |
|---|---|
| Идентификация | campaign_id, experiment_id, series_id, session_id, condition_id, sequence, parent_sequence, role |
| Параметры запроса | mode, action, order_type, side, symbol, requested_volume, type_filling, request_price, deviation, magic, comment |
| Результат отправки | send_ok, send_retcode, send_retcode_external, send_last_error, request_retcode_external |
| Связи | order_ticket, список deal_ticket, position_ticket, position_identifier, метод и статус корреляции |
| Сделки | last_deal_us, deal_count, executed_volume, объём из callback и из истории, полнота покрытия сделок метками |
| Качество | маски применимости и наличия T0–T6, presence для retcode, recovered, conflict, collection_closed, deadline_exceeded, measurement_interrupted |
| Завершение | outcome, final_source, confirmation_record_id, observation_deadline_us, collection_deadline_us, collection_close_us |
| Рынок | Bid, Ask, spread, tick_time_msc, границы окна признаков, частота котировок, диапазон Mid, market_regime, calibration_id |
| Диагностика | is_warmup, logging_mode, длительность обработчика, длительность сверки, запрошенный и фактический интервал таймера |
position_ticket и position_identifier не объединять. В MQL5 это разные свойства; устойчивый идентификатор связывает историю позиции. [D11]
Наличие метки определять флагом, а не выражением timestamp>0. Ноль может быть допустимым значением локального счётчика или измеренной длительности. Неприменимое, отсутствующее и восстановленное значение должны различаться.
3.3. Значение точек
Все локальные длительности рассчитываются по GetMicrosecondCount внутри одного запуска MQL5-программы. Этот счётчик отсчитывает время работы программы, а не календарное время и не время с запуска терминала. [D1]
| Точка | Поле | Правило регистрации |
|---|---|---|
| T0 | send_start_us | Непосредственно перед вызовом отправки; подготовка запроса, OrderCheck и получение контекста рынка уже закончены |
| T1 | send_return_us | Первая метка непосредственно после возврата торговой функции, до журналирования и анализа результата |
| T2 | request_event_us | Метка входа в обработчик соответствующего TRADE_TRANSACTION_REQUEST |
| T3 | order_event_us | Метка входа в обработчик первого связанного ORDER_ADD; наличие ордера в истории не заменяет эту метку |
| T4 | first_deal_us | Наименьшая метка входа среди связанных торговых DEAL_ADD |
| T5 | last_deal_us в служебной структуре | Наибольшая метка входа среди связанных торговых DEAL_ADD |
| T6 | final_event_us | Время окончания первой успешной проверки, подтвердившей исход конкретной операции |
T5 предусмотрена общим планом статьи, но отсутствует в краткой редакторской структуре. Поэтому она добавляется в сопутствующие данные явно, а не переименовывает final_event_us.
T4 и T5 относятся к порядку наблюдения callback, а не к восстановленному порядку исполнения на сервере. Метрику до последней сделки публиковать как полную только при подтверждённом покрытии всех сделок ордера; иначе last_deal_us — диагностическая метка последней наблюдавшейся сделки.
В начале OnTradeTransaction сначала снимается время, затем сохраняются тип и значимые данные. request и result читаются только для REQUEST. Порядок связанных транзакций не фиксирован. [D4]
Полученный позже идентификатор может позволить связать ранее сохранённый callback: в этом случае используется его исходная локальная метка. Сделка, найденная только в истории, такой метки не получает. Серверные DEAL_TIME_MSC и другие календарные поля сохраняются отдельно и не подставляются в T0–T6. [D12]
Не вычитать из локального счётчика время тика, TimeCurrent или TimeTradeServer. Микросекундная единица записи сама по себе не является доказательством микросекундной точности всего измерения.
3.4. Метрики
| Идентификатор | Формула | Назначение |
|---|---|---|
| call_duration_us | T1−T0 | Продолжительность вызова |
| request_delay_us | T2−T0 | Время до наблюдаемого результата обработки запроса |
| order_delay_us | T3−T0 | Время до наблюдаемого ORDER_ADD |
| first_deal_delay_us | T4−T0 | Время до первого наблюдаемого исполнения |
| last_deal_delay_us | T5−T0 | Время до последнего наблюдаемого исполнения при полном покрытии |
| final_state_delay_us | T6−T0 | Время до подтверждения исхода лабораторией |
| remaining_after_return_us | T6−T1 | Время от возврата функции до подтверждения |
| request_first_deal_offset_us | T2−T4 | Знаковая разность: положительная — REQUEST наблюдался позже сделки |
Метрики рассчитываются только при наличии применимых исходных точек. Разность T2−T4 вычисляется в знаковом типе без предварительного беззнакового вычитания. Название ACK для T1 не используется: успешный возврат OrderSendAsync не гарантирует получение и принятие запроса сервером. [D2]
4. Связывание событий и завершение наблюдения
Реестр хранит все записи серии до завершения экспорта, а не только текущий ожидаемый запрос. Первичный мост REQUEST — result.request_id. Далее используются result.order/result.deal, trans.order/trans.deal и DEAL_ORDER из истории. Magic Number, символ и комментарий — дополнительные проверки, а не доказательство уникальности события. [D3, D5, D12]
Неоднозначное событие сохраняется без догадки о принадлежности. Позднее допускается разрешить связь по точным идентификаторам. При неразрешённой неоднозначности затронутые метрики помечаются непригодными; исходная строка не удаляется.
Создание и удаление одного pending order — два разных запроса с общим order_ticket. Общий тикет не разрешает переносить timestamp создания в измерение удаления. Реестр хранит действие, обе записи запросов и связь служебной операции с основной.
Повторный deal_ticket не увеличивает deal_count и executed_volume. Все торговые сделки данного ордера учитываются независимо от DEAL_ENTRY; нельзя суммировать только входящие сделки и объявлять результат объёмом любого запроса. Исправления DEAL_UPDATE/DELETE сохраняются и вызывают повторную сверку; исходные события остаются в журнале. Ранее зарегистрированная T6 не переписывается: при опровержении исхода сохраняется отдельная корректировка, а исходная метрика помечается конфликтной.
Правила T6
| Операция или исход | Достаточные данные для подтверждения |
|---|---|
| MARKET_ORDER, полное исполнение | Идентифицирован конкретный ордер; подтверждено конечное состояние в истории; сделки по этому ордеру согласованы с исполненным объёмом; активного остатка нет |
| MARKET_ORDER, частичное завершение | Известен конечный статус ордера и фактический исполненный объём; остаток больше не активен; outcome отличается от полного исполнения |
| PENDING_CREATE | Подтверждён созданный ордер с ожидаемыми параметрами и активным состоянием; его будущего исполнения не ждём |
| PENDING_DELETE, служебная операция | Подтверждены результат удаления, отсутствие соответствующего активного ордера и отменённое состояние в истории; исполнение вместо отмены — отдельный исход |
| Однозначный отказ | Получен документированный окончательный отказ по данному действию из синхронного результата либо REQUEST; отсутствуют противоречащие данные |
| Неопределённость | Нет достаточного подтверждения; completed=false, T6 отсутствует |
Наличие позиции или одной сделки недостаточно для вывода о полном исполнении. Сверяется именно ордер, а не вся история по symbol+magic. Объём сравнивается в целых шагах объёма с проверкой корректности преобразования. Для основного протокола перед заявкой экспозиция по символу нулевая; состояние позиции после исполнения служит дополнительной сверкой.
T6 не привязывается к TRADE_TRANSACTION_POSITION. Этот тип описывает изменение позиции вне исполнения сделки. [D5]
Для положительных исходов проверка использует один и тот же набор условий в sync и async. Реализовать событийный запуск адресной сверки после появления данных; таймер — резерв. Записывать final_source, время проверки и использованные факты. T6 не переносится назад на время ранее возникшего серверного события. Если проверка нашла факты до доставки некоторых callback, T6 может предшествовать их локальным меткам.
Время ожидания и поздние события
Предлагаемые параметры протокола: InpOutcomeTimeoutMs=5000, InpLateGraceMs=1000. Основное окно каждой записи — [T0, T0+5000 мс]; позднее окно заканчивается в T0+6000 мс. Эти значения не являются характеристиками брокера.
deadline_exceeded означает, что T6 отсутствует в основном окне. Этот факт сохраняется, даже если затем исход подтверждён. Отдельно учитываются отсутствующие T2, T3 и T4. Отказ не заменяется timeout, а timeout не заменяется отказом.
collection_closed фиксируется, когда подтверждён исход и собраны ожидаемые для него события либо истёк поздний срок. По истечении срока отсутствие обязательных данных явно отмечается. После этого переход к очистке допустим только при известном торговом состоянии. Реестр остаётся доступным: ещё более поздние транзакции сохраняются как поздние и не попадают задним числом в основное распределение. Любые последующие дополнения до окончания запуска сохраняют исходную дату закрытия окна и признаки своевременности.
Служебные операции не перекрывают незакрытое окно основной записи, кроме аварийного вмешательства с отметкой measurement_interrupted. Такое ограничение предотвращает внесение ожидания служебного OrderSend в метки ещё ожидаемых событий.
При штатном завершении сохранить все записи. При перезапуске начать новый session_id и новую серию; старые локальные метки не продолжать. Для аварийного завершения нужен журнал намерений перед отправкой и контрольные сохранения в безопасных точках. Если последние данные утрачены, запланированная попытка остаётся DISPATCH_UNCERTAIN, а не исчезает или получает придуманные T0/T1. Побитовая сохранность данных при аппаратном сбое без соответствующего подтверждения не обещается.
5. Общий протокол серий
Размер выборки — пять серий по 100 основных вызовов на каждое сравниваемое условие. Это выбранная трактовка редакторского пункта 4. Не 100 успешных исполнений и не 100 запросов, разделённых пополам между ветвями.
Для парного эксперимента получается пять пар серий, по 100 вызовов A и B в каждой, то есть 1000 основных вызовов. Один запуск может содержать обе перемешанные ветви, сохраняя отдельные condition_id. Подготовить новый session_id и прогрев для каждой следующей пары.
Эксперименты 1, 2, 3 и 5 используют отдельные основные наборы: суммарно 4000 вызовов при завершённом протоколе. Эксперимент 4 отдельно анализирует пять серий ASYNC из эксперимента 1 и не создаёт фиктивно новую выборку. Повторное использование явно фиксируется в experiment_manifest.csv. Прогрев, пилот и очистка увеличивают фактический торговый бюджет и считаются отдельно.
Перед каждой ветвью в каждой серии выполнить 10 прогревочных вызовов с role=WARMUP; они не входят в 100 основных. Число 10 фиксируется до измерений и не увеличивается по результатам первых задержек.
Для управляемых факторов в экспериментах 1, 2 и 5 заранее создать сбалансированный план небольших перемешанных блоков. Каждый блок содержит по 10 запросов каждой ветви, по 5 Buy и Sell внутри ветви; 10 блоков дают по 100 запросов. Генератор, seed и получившийся план сохраняются. Прогрев обеих ветвей заканчивается до основных наблюдений.
Режимы не закрепляются за направлением: нельзя отправлять только Buy синхронно, а Sell асинхронно. На каждые 100 основных запросов одной ветви приходится 50 Buy и 50 Sell. Порядок задаётся до получения результатов.
Предлагаемые общие настройки: минимальная пауза после завершения предыдущего цикла и его очистки — 1000 мс; резервный таймер — 20 мс; не более одного основного запроса в работе. Фактическое расписание сохраняется. Просроченные слоты не отправляются пачкой. Не использовать Sleep или активное ожидание для ожидания торговых событий.
Такой последовательный протокол измеряет задержку одиночных запросов, а не пропускную способность и не преимущество параллельной отправки. Запрошенный период таймера не приравнивается к фактическому: события таймера могут обрабатываться позднее или объединяться. [D8]
Между парными ветвями меняется только исследуемый фактор. В эксперименте 2 смена операции закономерно меняет поля запроса и допустимую политику заполнения: обе спецификации фиксируются заранее, а результат относится к сравнению двух сценариев, не к изолированному влиянию одного поля. При незапланированном изменении сборки, версии кода, filling или алгоритма сверки создаётся новый configuration_id. Для рынка это не обещает неизменность внешней среды: дата, время, spread, режим рынка и параметры соединения сохраняются как контекст.
Неуспешные вызовы входят в 100 попыток. Их нельзя заменять дополнительными успешными запросами. Отказ OrderCheck до фактической отправки сохраняется отдельно; систематические ошибки подготовки останавливают серию. Незавершённые серии не достраиваются после перезапуска до вида одного непрерывного прогона.
До основных измерений провести LOCAL_ONLY и пилот. По пилоту проверить работоспособность, выбрать допустимые условия и зафиксировать конфигурацию. Данные пилота не входят в итоговые сравнения. Любое последующее изменение протокола создаёт новую версию.
6. Обязательные эксперименты
Эксперимент 1. Синхронная отправка против асинхронной
Вопрос: различаются ли продолжительность вызова, время до первой сделки и время подтверждения результата при одинаковом протоколе?
A — MARKET_ORDER, SYNC, MINIMAL. B — MARKET_ORDER, ASYNC, MINIMAL. По 5×100 основных вызовов на ветвь, сбалансированное чередование согласно разделу 5. Рыночные признаки сохраняются; выводы дополнительно проверяются в сопоставимых сегментах времени суток, стороны и рыночного режима.
Основные показатели: call_duration_us, first_deal_delay_us, final_state_delay_us. Дополнительные: request_delay_us, remaining_after_return_us, request_first_deal_offset_us, доля отказов, отсутствие меток и превышения срока.
Гипотеза о меньшем времени возврата ASYNC проверяется отдельно от гипотез о времени до сделки и финала. Нельзя использовать малую call_duration как доказательство ускорения исполнения. Успешный OrderSend также не следует отождествлять с завершением всех событий заявки. [D2, D9]
Результат: таблица по каждой паре серий и объединённым выборкам, гистограммы основных метрик, распределение знака T2−T4. По каждой разности привести размер действительной выборки. Нельзя объяснять наблюдаемую разницу конкретным внутренним компонентом брокера.
Эксперимент 2. Рыночная операция против отложенной
Вопрос: как меняются наблюдаемые интервалы для исполнения рыночной заявки и размещения отложенного ордера?
A — MARKET_ORDER, ASYNC, MINIMAL. B — PENDING_CREATE_DELETE, ASYNC, MINIMAL. В B основное измерение относится к PENDING_CREATE; удаление — отдельная CLEANUP-запись. По 5×100 основных запросов на ветвь.
Используются Buy/Sell и соответствующие Buy Limit/Sell Limit. До серии фиксируется расстояние D от рынка в шагах цены. Buy Limit размещается ниже текущего Bid на D шагов, Sell Limit — выше Ask. Расстояние проверяется с учётом торговых ограничений; значение и правила округления не подстраиваются по результату каждого отказа.
Сравнивать call_duration_us, request_delay_us и order_delay_us. final_state_delay_us показывать с явным указанием разных конечных условий: исполнение для рынка, подтверждение размещения для pending. first_deal_delay_us у нормального размещения pending не применяется и не равна нулю.
Не включать в задержку размещения время ожидания достижения цены. Если pending успел исполниться, пометить UNEXPECTED_ACTIVATION и провести сверку. Такая запись остаётся в счётчиках попыток, но не изображается как обычное размещение без исполнения. Если активное состояние не было подтверждено, T6 размещения не восстанавливать из поздней истории как якобы наблюдавшееся.
Результат: таблица общих интервалов, отдельная статистика удаления и число непредусмотренных активаций. Время удаления не прибавляется к времени размещения.
Эксперимент 3. Спокойный рынок против быстрого рынка
Вопрос: различаются ли наблюдаемые задержки при заранее определённых режимах движения котировок?
Обе ветви — MARKET_ORDER, ASYNC, MINIMAL. A — QUIET, B — FAST. По 5×100 основных запросов на режим. Это наблюдательное сравнение: режим рынка не рандомизируется.
Рыночный режим определяется до отправки и без использования latency. Предлагаемый классификатор рынка:
- Окно признаков W=60 секунд, полностью предшествующее снимку котировки перед отправкой. При миллисекундной границе b использовать [b−60000, b−1], где b — time_msc опорной котировки. Сохранить полученные до T0 тики, границы, время расчёта и контрольное значение набора. Возраст расчёта по локальному счётчику перед T0 не должен превышать 1000 мс; иначе обновить данные до отправки.
- По COPY_TICKS_INFO рассчитать f=N/W — число обновлений Bid/Ask в секунду; r=(max(Mid)−min(Mid))/tick_size — диапазон Mid в шагах цены. Использовать валидные двусторонние котировки. Число вызовов OnTick не является счётчиком всех тиков, поэтому не используется для классификации. [D6, D7]
- На отдельном предшествующем калибровочном наборе не менее 1000 непересекающихся валидных минутных окон, охватывающем не менее пяти торговых сессий, рассчитать p50 и p90 для f и r. Период, символ, правила качества и значения порогов сохранить до основной серии.
- QUIET: f≤p50(f) и r≤p50(r). FAST: f≥p90(f) и r≥p90(r). Прочие случаи — INTERMEDIATE. Если пороги вырождаются либо данные неполны, режим UNKNOWN; классификатор нельзя считать пригодным к сбору двух различимых групп.
Указанные 60 секунд, объём калибровки и границы p50/p90 — определения данного протокола, а не универсальный стандарт спокойного и быстрого рынка.
Окна допустимого календарного сбора фиксируются заранее. Для каждого режима отбираются первые подходящие возможности отправки с соблюдением паузы и баланса сторон, а не запросы с удобным результатом. Пропущенные возможности и причины ожидания сохраняются. Время отсутствия подходящего режима не порождает искусственные торговые запросы.
В журнал попадают ошибки CopyTicksRange, неполные диапазоны и проблемные котировки. Нельзя уменьшать частоту искусственным удалением одинаковых по миллисекунде, но разных тиков. Возвращённый неполный диапазон с ошибкой не считается полным. [D6]
Основные показатели: first_deal_delay_us, final_state_delay_us, p95/p99 и доли неполных наблюдений. Дополнительные — call_duration_us и request_delay_us. Сравнение повторить по сторонам; показать состав групп по spread и времени суток. Если сопоставимого покрытия нет, прямо указать ограничение, а не делать причинный вывод.
Результат: калибровочный отчёт, распределение рыночных признаков, пять серий для каждого режима и таблица latency. При недоборе FAST эксперимент получает INSUFFICIENT_DATA. Искусственная пауза в обработчике или синтетический поток не заменяют быстрый реальный рынок.
Эксперимент 4. Пять серий по 100 запросов
Вопрос: насколько меняются результаты повторных запусков с одной конфигурацией?
Используются пять ASYNC-серий эксперимента 1, по 100 основных запросов каждая. В experiment_manifest указываются исходные ключи; строки samples не копируются и не считаются новыми наблюдениями.
Для каждой серии сравнить число попыток, число доступных меток, mean, median, p95, p99, maximum, доли отказов, deadline_exceeded и пропусков. Основная метрика — first_deal_delay_us; дополнительно анализируется final_state_delay_us.
Объединённые показатели рассчитывать из исходных 500 записей, а не усреднением пяти медиан или пяти p99. Сохранять различия между сериями и сопутствующие условия, в том числе время суток, режим рынка, spread, ping и длительности обработчика.
Результат: таблица пяти серий, диаграмма медианы и p95 по сериям, объединённое распределение и протокол повторного пересчёта. Пять запусков называются повторными, но не автоматически статистически независимыми. Воспроизводимость означает повторение процедуры и сопоставимость отчёта, а не одинаковые значения задержек.
Эксперимент 5. Подробное логирование против минимального
Вопрос: меняет ли диагностический вывод измеряемые задержки при неизменном сборе первичных данных?
A — MARKET_ORDER, ASYNC, MINIMAL. B — MARKET_ORDER, ASYNC, VERBOSE. По 5×100 основных запросов на ветвь. Сбалансированный порядок блоков фиксируется заранее. Режим хранится в записи запроса; позднее событие не получает режим новой заявки по ошибке.
MINIMAL: одинаковый для обеих ветвей сбор первичных записей в подготовленную память, без штатного Print/PrintFormat на каждый запрос или callback. Обязательные сообщения об ошибках безопасности сохраняются в обеих ветвях.
VERBOSE: тот же сбор плюс один фиксированный PrintFormat после регистрации каждого связанного callback и один после регистрации возврата отправки. Набор полей строки одинаков: тип, ключ запроса, тикеты, применимые цена/объём и код результата. Формирование строки и вывод входят в диагностическую длительность обработчика. Время снимается до логирования.
Не менять одновременно запись CSV, частоту сверки, отрисовку, алгоритм корреляции или состав рынка. Печать не дополнять Sleep или активным ожиданием. Панель во время основных измерений отключена в обеих ветвях. Не отправлять сделки и не выполнять полные проходы по истории из обработчика.
Основные показатели: first_deal_delay_us, final_state_delay_us и распределение длительности OnTradeTransaction. Дополнительные: остальные интервалы, пропущенные метки и состояние собственного буфера. Отсутствие различий — допустимый результат.
Результат: таблица парных серий и две группы гистограмм. Потеря callback сама по себе не доказывает переполнение внутренней очереди терминала; уровень уверенности в такой интерпретации должен быть указан отдельно.
7. Статистический контракт
Для каждого experiment_id, condition_id, series_id и каждой метрики формируется отдельная строка summary. Дополнительно создаётся строка объединённой выборки. Основные результаты не смешиваются с WARMUP, CLEANUP, PILOT и SYNTHETIC.
Считать n_attempted, n_applicable, n_not_applicable, n_applicability_unknown, n_valid, n_missing, n_late, n_conflict и n_interrupted. Выполняется n_attempted = n_applicable + n_not_applicable + n_applicability_unknown. Категории пригодности внутри метрики взаимоисключающие и в сумме дают n_applicable. Основной статус выбирается в порядке conflict, interrupted, late, missing, valid; дополнительные признаки могут сосуществовать.
Основное распределение включает непосредственно зарегистрированные, непротиворечивые метки в окне до T0+InpOutcomeTimeoutMs. Для late строится отдельная диагностическая сводка. Отказы анализируются отдельно от успешных исходов для request_delay и final_state_delay; результаты разных исходов нельзя незаметно объединять в одну сравнительную среднюю. Для first_deal явно указать условие включения — наблюдалась торговая сделка данного запроса.
На допустимой выборке рассчитывать минимум, среднее, медиану, p90, p95, p99, p99.9, максимум и выборочное стандартное отклонение с делителем n−1. При n=0 показатели пустые; при n=1 стандартное отклонение пустое.
Процентили: линейная интерполяция по h=(n−1)p; i=floor(h), a=h−i; Q(p)=x[i]+a·(x[min(i+1,n−1)]−x[i]) в отсортированном массиве. p50 является медианой. Метод и версия указываются в summary.
p99.9 сохраняется, поскольку предусмотрен редакторским планом, но сопровождается tail_expected_n=n·(1−p) и предупреждением, если это число меньше 10. Для n=100 и n=500 это соответственно 0,1 и 0,5; таким значением нельзя описывать устойчивую оценку редкого хвоста. То же правило диагностики применяется к p95/p99. Порог 10 — предупредительное правило данного ТЗ, не доказательство достаточной точности при его достижении.
Доля превышения срока = число основных попыток без подтверждённого T6 к сроку / число основных попыток. Доля пропуска метки = число применимых наблюдений без этой метки к сроку / число наблюдений, для которых метка применима. Если применимость не установлена из-за неизвестного исхода, это отдельная категория, а не автоматически отсутствие сделки.
Выбросы не удаляются по величине latency. Технически повреждённые записи исключаются только с кодом причины и остаются в raw/samples. Средние и квантили по сохранившимся измерениям явно обозначаются условными, если часть наблюдений не завершена.
Для парных сравнений сохранять разность B−A и относительное изменение для mean/median/p95, если знаменатель определён и не равен нулю. Рассчитывать их по каждой паре серий и для объединённых данных. Автоматически не объявлять статистическую значимость: отдельный план вывода с учётом зависимости измерений потребуется до использования таких формулировок.
Гистограмма неотрицательных интервалов: [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,128), [128,256), [256,+∞) мс. Для каждой корзины — число и доля. Это категориальные диапазоны разной ширины; высоты не называются плотностью. Знаковая разность T2−T4 в эти корзины не помещается: для неё сохраняются исходные значения и доли знаков <0, =0, >0.
8. CSV и воспроизводимость отчёта
Формат: UTF-8, разделитель запятая, десятичная точка, первая строка — заголовок, окончания строк CRLF. Строки с запятыми, кавычками или переводами строк экранируются единообразно. 64-битные идентификаторы записываются десятичными целыми без преобразования через double. Булевы поля — 0/1. Отсутствующие значения — пустые поля; причина задаётся статусом. При открытии в табличных редакторах идентификаторы импортируются как текст.
В manifest дополнительно фиксируются имя нового проекта, версия приложения, commit сборки при наличии, признак незаписанных изменений, SHA-256 исходного пакета и SHA-256 dependencies.lock.json. Контрольная сумма пакета рассчитывается по отсортированному списку относительных путей и SHA-256 фактически используемых исходников; не включать само вычисляемое значение в его вход. Вместе с архивом измерений хранить соответствующий lock-файл и состав исходного пакета. Идентификация кода, схемы CSV и зафиксированного протокола нужна для воспроизводимости измерений и не является нумерацией черновика ТЗ.
Все имена, типы, порядок, единицы и правила отсутствия полей закрепляются в CSV_SCHEMA.md до основной серии. Несовместимое изменение повышает schema_version и запрещает автоматическое объединение без миграции.
| Файл | Содержимое |
|---|---|
| manifest.csv | key/value-паспорт запуска, версия протокола/схемы/кода, конфигурация, сборка, сервер, псевдоним счёта, символ, модель учёта, параметры и коды завершения |
| schedule.csv | Запланированные роли, условия, направления и порядок отправки; фактический статус слота и причины пропусков |
| samples.csv | Одна строка на фактический вызов отправки: обязательная структура, служебные признаки, контекст и рассчитанные интервалы |
| events.csv | Неизменяемые первичные SEND/RETURN, торговые callback, проверочные снимки, сроки, закрытие сбора и вмешательства |
| deals.csv | По одному уникальному deal_ticket с order_ticket, объёмом, типом, свойствами истории, меткой callback и её наличием |
| summary.csv | Статистика по метрике, условию, исходу и серии; размеры и качество выборок |
| histogram.csv | Метрика, условие, серия, границы корзины, count и share |
| market_windows.csv | Признаки и метки рыночного режима; ссылка на сохранённый набор тиков и calibration_id |
| checks.csv | Результаты автоматических проверок и ссылки на проблемные записи |
| experiment_manifest.csv | Связь пяти экспериментов с исходными запусками, включая явное повторное использование данных в пункте 4 |
В samples обязательные поля LatencySample сохраняются под исходными именами. Новые поля добавляются после них в порядке, определённом CSV_SCHEMA. В manifest указываются источник и часовая шкала календарных меток. Нельзя выдавать серверное время за UTC без установленного преобразования. Полный логин, пароль и иные секреты в публикуемые файлы не включаются.
Для events обязательны session_id, event_sequence, record_kind, local_time_us, transaction_type, request_id/order_ticket/deal_ticket по применимости, время входа/выхода, исходные данные и ссылка на результат корреляции. Проверочный снимок содержит время проверки, идентификатор операции, статус ордера, объёмы, проверенные тикеты, наличие активного остатка и outcome. Это позволяет проверить источник T6, а не только разность двух чисел.
Первичные записи во время окна измерения накапливаются одинаково в обеих ветвях. Тяжёлый экспорт, сортировка, перцентили и отрисовка выполняются после закрытия окна и перед следующей паузой либо после серии. Для файловых функций с возвращаемым результатом проверяется результат; для завершения записи дополнительно проверяются ошибки, размер и возможность контрольного чтения. От функций без возвращаемого значения не требуется несуществующий код возврата. Счётчики буфера и потерь обязательны; бесшумное перезаписывание запрещено.
MQL5-анализатор повторно читает CSV, пересчитывает интервалы, summary и histogram. Целые метки и счётчики должны совпасть точно; вещественные показатели — в пределах max(10^−9, 10^−12·|x|) в единицах экспортируемого показателя при достаточной точности сериализации. Схема задаёт не менее 16 значащих цифр для вычисляемых double. Для одинаковых исходных CSV сравниваются таблицы в каноническом порядке; служебное время генерации не участвует.
Свежий запуск не обязан воспроизводить прежние latency. Он обязан сохранять те же определения, форматы и доступность контекста, позволяющие объяснить состав сравниваемых групп.
9. Автоматические проверки
Проверки выполняются MQL5-программами на синтетических входах с управляемым тестовым временем. Этот режим не создаёт измерения «задержки брокера». Для live остаётся GetMicrosecondCount; тестовый источник времени не включается скрыто.
Обязательные группы:
- Разные допустимые порядки REQUEST, ORDER_ADD, DEAL_ADD и HISTORY_ADD; отложенная корреляция сохраняет исходную метку.
- Несколько сделок, повтор одного deal_ticket, отмена неисполненного остатка; полный объём не приписывается первой сделке.
- Поздний REQUEST, отсутствие REQUEST при известном исполнении, отказ без ордера, неопределённый исход при timeout.
- Создание и удаление одного pending order с разными request_id; общие order_ticket не смешивают замеры.
- Событие другого запроса, другой сессии, символа и Magic Number; неразрешённая неоднозначность не получает фиктивной привязки.
- Сделка найдена только в истории; факт исполнения восстанавливается без callback-времени.
- T6 до позднего callback, проверка таймером, превышение срока с последующим результатом; T6 не переносится назад.
- Неожиданная активация pending, ошибка очистки, перезапуск, аварийно неполный журнал, нехватка памяти и ошибка записи.
- Ноль как валидная метка/интервал; отрицательная T2−T4; крупные ulong-идентификаторы и CSV с кавычками.
- Статистика на пустом массиве, одном элементе, чётном и нечётном размере; известные процентили и все границы корзин.
- Рыночные пороги, одинаковые миллисекунды разных тиков, неполная история, отсутствие заглядывания за границу окна, вырожденная калибровка.
- Повторный пересчёт CSV, отделение прогрева и очистки, контроль 100 попыток, повторное использование данных эксперимента 4 без дублирования.
- Контрольные суммы зависимостей, отсутствие незафиксированного внешнего подключения, сборка из нового проекта без соседнего исходного каталога статьи 1.
- Проверки адаптированного кода: согласованность процентилей с исходным алгоритмом на допустимых входах; корректная обработка пустой выборки и ошибок; отсутствие исходных обработчиков событий и конфликтующего глобального состояния; отсутствие неконтролируемого подробного вывода в MINIMAL.
- После публикации — чистое клонирование, совпадение commit и dependencies.lock.json, сборка основного советника, анализатора и тестов, повторение LOCAL_ONLY и пересчёта контрольного CSV без торговых операций.
Инварианты: при наличии T0/T1 выполняется T1≥T0; при наличии T4/T5 — T5≥T4; completed=true требует подтверждающего снимка либо однозначного подтверждённого отказа и T6; уникальные сделки не учитываются дважды; в штатно завершённом запуске число строк samples равно числу зарегистрированных фактических вызовов; аварийная неопределённость учитывается отдельным статусом. Не устанавливается ложное правило T0<T1<T2<T3<T4<T5<T6.
Проверка совпадения времени T6 с записью подтверждения обязательна. Пропуски, нарушения и исключения должны иметь машинно читаемый код причины.
10. Порядок подготовки и проведения
Подготовка исходной базы. В заданном каталоге Shared Projects подготовить новый проект. Сопоставить приложенные файлы с исходными каталогами LifecycleBenchmark и OrderLifecycle. Зафиксировать снимки и dependencies.lock.json, выделить переиспользуемые .mqh и оформить изменения, не изменяя исходный проект статьи 1.
Подготовка инструмента. Реализовать модули и адаптеры, скомпилировать без ошибок и предупреждений, выполнить синтетические проверки, проверить CSV-пересчёт. Проверить автономную сборку с зафиксированными библиотеками. Все .mq5/.mqh, .mqproj и настройки передать в составе нового проекта.
Пилот на демо. Проверить допустимый filling, объём и цены, принадлежность сделок, очистку, фактическую работу таймера и отсутствие тяжёлых операций в окне наблюдения. Пилот не используется для выбора «выгодных» результатов. Зафиксировать хеш/версию кода и конфигурацию.
Публикация реализованного кода. После реализации и проверки инструмента создать отдельный Git-репозиторий mql5-execution-microstructure-02-request-latency в пространстве dng на MQL5 Forge. Корень репозитория совпадает с корнем нового проекта. Сохранить проверенные исходники, зависимости, тесты, настройки и документацию; настроить origin по фактическому адресу репозитория. Выполнить обычный push без перезаписи чужой истории. Если доступа нет, зафиксировать статус NOT_PUBLISHED и причину, а не считать публикацию завершённой.
Проверка опубликованной поставки. Из чистого клона без исходного соседнего проекта проверить сборку, LOCAL_ONLY и повторный расчёт контрольного CSV. Сопоставить опубликованный commit с проверенным локальным и зафиксировать метку версии. Сохранить протокол сборки и тестов. Автоматическая проверка поставки не запускает торговые запросы. Публикация проверенного кода не означает выполнения пяти рыночных экспериментов.
Подготовка рынка. Сохранить предшествующий калибровочный набор, пороги QUIET/FAST и разрешённые окна сбора. Проверить, что два класса различимы. Задать до запуска предельное календарное окно сбора и лимит торговых попыток; при недоборе не ослаблять критерии задним числом.
Основные измерения. Выполнить эксперименты 1, 2, 3 и 5 по сохранённым планам. Для каждого запуска сохранить паспорт, все попытки, отклонения и очистку. Эксперимент 4 сформировать как самостоятельный анализ пяти серий ASYNC из первого эксперимента.
Проверка результатов. Повторно получить отчёты из CSV на MQL5, сверить суммы, причинные связи, пропуски и версии. Неудачные и прерванные запуски включить в журнал исследования.
Материал для автора. Для каждого эксперимента подготовить условия, таблицу, иллюстрацию, размер каждой выборки, технические ограничения и вывод. Отдельно обозначить наблюдение, расчёт и предположение. Наличие ожидаемого эффекта не является условием успешного эксперимента.
11. Критерии приёмки
Разделяются готовность программы и готовность экспериментального материала.
Программа готова, если размещена в заданном рабочем каталоге, использует задокументированный код двух исходных проектов, автономно собирается с зафиксированными依赖, проходит все обязательные тесты, поддерживает три режима и оба способа отправки, не смешивает основные и служебные запросы, сохраняет неполные записи и повторно рассчитывает отчёт из CSV.
Поставка опубликована, если отдельный репозиторий создан в заданном пространстве MQL5 Forge, опубликованный commit совпадает с проверенным, доступны lock-файл и история адаптации, а чистый клон проходит сборку и локальные проверки без соседнего каталога статьи 1. Одного создания пустого репозитория либо локального git init недостаточно. В отчёте сдачи указать фактический URL, commit, метку версии и результат проверки клона. Не объединять статусы готовности программы, публикации и проведения экспериментов.
Материал для статьи готов, если для всех пяти пунктов есть самостоятельный результат с источниками, выполнены предусмотренные 5×100 попыток на условие и доступны исходные данные, конфигурация, версия и контрольные отчёты. Для основного сравнения должны существовать измерения целевой метрики в обеих группах; размер и ограничения оставшихся выборок публикуются. Недобор оформляется без фиктивной замены. Эксперимент с INSUFFICIENT_DATA не считается завершённым сравнением и не даёт права на положительный или отрицательный вывод о различии режимов.
Обязательные основания для остановки приёмки: отсутствие фактического переиспользования исходного кода, незафиксированные либо отсутствующие зависимости, несоответствие опубликованного и проверенного commit; придуманные временные метки; подмена REQUEST результатом возврата функции; смешение запросов; скрытая потеря строк; объединение разных версий схемы или протокола; загрязнение меток служебной торговлей без отметки; подмена FAST искусственным замедлением; отсутствие исходных данных для опубликованного числа.
Сопоставимость нового отчёта не означает совпадения задержек с предыдущим запуском. Подтверждением служат одинаковые определения измерений, проверяемая принадлежность событий, единый протокол и прозрачный состав выборок.
Итоговый критерий: повторный запуск создаёт сопоставимый CSV-отчёт; повторный расчёт тех же исходных файлов восстанавливает опубликованные показатели; текст статьи отделяет наблюдения и расчёты от предположений о ненаблюдаемой инфраструктуре.
Источники документированных свойств MQL5
Исходное редакторское задание и GLOSSARY.md задают цель, термины и пять экспериментов. Следующие ссылки используются только для проверки свойств платформы; они не задают наши размеры выборок, классификатор рынка или параметры ожидания.
[D1] GetMicrosecondCount: https://www.mql5.com/ru/docs/common/getmicrosecondcount
[D2] OrderSendAsync: https://www.mql5.com/ru/docs/trading/ordersendasync
[D3] MqlTradeResult: https://www.mql5.com/ru/docs/constants/structures/mqltraderesult
[D4] OnTradeTransaction: https://www.mql5.com/ru/docs/event_handlers/ontradetransaction
[D5] MqlTradeTransaction: https://www.mql5.com/ru/docs/constants/structures/mqltradetransaction
[D6] CopyTicksRange: https://www.mql5.com/ru/docs/series/copyticksrange
[D7] OnTick: https://www.mql5.com/ru/docs/event_handlers/ontick
[D8] OnTimer: https://www.mql5.com/ru/docs/event_handlers/ontimer
[D9] OrderSend: https://www.mql5.com/ru/docs/trading/ordersend
[D10] Свойства ордеров и режимы заполнения: https://www.mql5.com/ru/docs/constants/tradingconstants/orderproperties
[D11] Свойства позиций: https://www.mql5.com/ru/docs/constants/tradingconstants/positionproperties
[D12] Свойства сделок: https://www.mql5.com/ru/docs/constants/tradingconstants/dealproperties
Источники кода
Контрольные суммы полученных в беседе файлов, вычисленные по их исходным байтам:
| Файл | Размер, байт | SHA-256 |
|---|---|---|
| LifecycleBenchmark.mq5 | 37519 | 430abc7d254c7f18c8db4f48f1a44be48a0c5cf338bd16aa4d621ffd4654a8d9 |
| OrderLifecycleRecorder.mq5 | 35548 | 27463190954b5200444781ba4a49bb167c210087ad511a39616cfc807b69ea84 |
| TradeLifecycle.mqh | 39132 | 0b3d409a1da0fa05bad541944b9922ca6beeb26a2920836d408efdaf930bce30 |
При несовпадении с локальной исходной базой эти суммы не заменяются задним числом. Фактическая принятая зависимость фиксируется отдельно в dependencies.lock.json.