21 KiB
CSV-контракт RequestLatencyLab
Статус: черновик. Не утверждено. Без номера версии.
Приложение к Docs/RequestLatencyLab_TZ_RU.md (раздел 8). Имена файлов и формат —
проектные предложения спецификации RequestLatencyLab_Specification_RU.md.
Содержательно: один файл отчёта — одна ответственность; таблицы задают полный
порядок колонок; поля LatencySample сохраняются под исходными именами.
Общие правила
- UTF-8 без BOM при записи; один BOM допускается при чтении (реализация
CsvStorage.mqh: запись — UTF-8 без BOM, чтение допускает BOM). - Разделитель — запятая
,; десятичная точка; окончания строк CRLF. - Поля с запятой/кавычкой/переводом строки заключаются в кавычки; кавычка удваивается.
- Содержательная пустая строка пишется как
""; отсутствующее значение — пустое поле. Парсер сохраняет это различие (CCsv::ParseRow). - uint32/uint64/int32/int64 — точные десятичные целые без преобразования через double.
- Bool — 0/1. Double — конечное число, не менее 16 значащих цифр для вычисляемых показателей; NaN/Inf не допускаются.
- Неизвестное значение не подменяется нулём; причина — код статуса/presence.
- JSON-ячейки экранируются целиком как CSV-ячейка.
Основные файлы
manifest.csv
Паспорт запуска. Ключи (полный реестр): project_name, document_status, campaign_id, session_id, experiment_id, series_id, configuration_id, protocol_fingerprint, schema_fingerprint, schema_version, application_identifier, source_commit, source_dirty, source_package_sha256, dependencies_lock_sha256, schedule_sha256, data_origin, terminal_build, compiler_build, server_name, account_alias, account_margin_mode, symbol, point_size, price_tick_size, price_digits, volume_min, volume_max, volume_step, market_filling, pending_filling, deviation_points, pending_distance_ticks, magic, count_per_condition, warmup_per_condition, outcome_timeout_ms, late_grace_ms, pause_ms, timer_requested_ms, feature_window_sec, feature_max_age_ms, quote_max_age_ms, calibration_id, collection_windows, calendar_time_source, calendar_time_scale, start_calendar, end_calendar, generator_name, seed, cleanup_mode, cleanup_logging, cleanup_max_attempts, sample_capacity, event_capacity, error_reserve_capacity, volume_units_tolerance, address_read_budget, history_scan_budget, run_status, stop_reason, n_main_dispatched, n_warmup_dispatched, n_cleanup_dispatched, n_pilot_dispatched, n_dispatch_uncertain, records_attempted, records_accepted, records_persisted, records_lost, buffer_high_watermark, outstanding_objects, last_checkpoint_event_sequence, ping_before_run_us, ping_after_run_us, input_files, output_files.
Реализация: CCsvReport::BuildManifest (подмножество реестра текущей версии).
schedule.csv
session_id,row_id,row_kind,slot_id,experiment_id,series_id,condition_id,block_id,role, operation,side,mode,logging_mode,planned_order,sequence,parent_sequence,status, reason_code.
samples.csv
Первые 10 полей — LatencySample в исходном порядке: request_id, sequence, send_start_us, send_return_us, request_event_us, order_event_us, first_deal_us, final_event_us, retcode, completed. Далее: campaign_id, experiment_id, series_id, session_id, configuration_id, condition_id, slot_id, parent_sequence, cleanup_attempt, role, is_warmup, operation, mode, logging_mode, symbol, side, correlation_status, correlation_method, order_ticket, position_ticket, position_identifier, last_deal_us, deal_count, executed_volume, callback_volume, history_volume, deal_coverage_complete, present_mask, recovered, conflict, measurement_interrupted, scenario_deviation, outcome, outcome_at_final, final_source, trading_state_known, confirmation_invalidated, confirmation_record_id, current_confirmation_record_id, observation_deadline_us, collection_deadline_us, collection_close_us, collection_closed, deadline_exceeded, market_regime, calibration_id, bid_at_send, ask_at_send, spread_at_send, tick_time_msc, actual_type, actual_filling, deviation_points, comment, request_price, callback_coverage_complete, market_window_id, market_window_seq.
Аудит-4 (R4-B8): отсутствующее значение timestamps/retcode/объёмов пишется ПУСТЫМ
полем (а не 0); actual_type/actual_filling/deviation_points/comment/request_price
фиксируют фактический контракт запроса (для cleanup — контракт закрытия/удаления).
Аудит-5 (R5-S2): actual_type/actual_filling — допустимые нулевые коды
(ORDER_TYPE_BUY=0, ORDER_FILLING_FOK=0) записываются как 0; пустое поле
означает, что фактический контракт не зафиксирован (actual_known=false).
configuration_id всегда заполняется после Preflight и попадает в manifest/samples.
Аудит-8 (R8-S2): формат расширен до 68 колонок — market_window_id/market_window_seq
(связь строки с исходным окном E3, соответствие market_windows.csv по sequence;
market_window_seq=0/пустой id — запись без E3-контекста или до режима).
Аудит-5 (R5-B4): callback_coverage_complete — отдельный признак полноты ЛОКАЛЬНЫХ
callback-меток сделок (1 = все сделки ордера наблюдались через DEAL_ADD; сделка,
найденная только в истории, не даёт полного T5). deal_coverage_complete — признак
торгового результата (сумма объёмов равна запрошенному). T5-метрика использует
callback_coverage_complete.
events.csv
Append-only: session_id,event_sequence,record_kind,local_time_us,origin_sequence, target_sequence,ref_event_sequence,transaction_type,request_id,order_ticket,deal_ticket, position_ticket,handler_enter_us,handler_exit_us,payload_json,quality_code.
deals.csv
session_id,account_alias,deal_ticket,order_ticket,owner_sequence,symbol,deal_type,entry, reason,magic,position_ticket,position_identifier,callback_first_us,callback_event_id, has_callback,callback_volume,history_volume,history_price,deal_time_msc, history_read_event_id,recovered,correction_count,deleted,quality_codes.
summary.csv
experiment_id,condition_id,series_id,metric_id,outcome_group,population,observation_unit, segment_key,source_set_id,unit,n_attempted,n_applicable,n_not_applicable, n_applicability_unknown,n_valid,n_missing,n_late,n_conflict,n_interrupted,n_used,minimum, mean,median,p90,p95,p99,p999,maximum,stddev,percentile_method,method_fingerprint, p95_tail_expected_n,p99_tail_expected_n,p999_tail_expected_n,tail_warning_codes, n_deadline_exceeded,deadline_denominator,deadline_rate,n_timestamp_missing_at_deadline, missing_timestamp_rate,conditional_distribution.
histogram.csv
experiment_id,condition_id,series_id,metric_id,outcome_group,population,segment_key, bin_index,lower_us,upper_us,count,denominator,share. Только неотрицательные интервалы
([0,1),[1,2),[2,4),[4,8),[8,16),[16,32),[32,64),[64,128),[128,256),[256,+∞) мс).
Знаковая метрика T2−T4 в histogram НЕ включается (отдельный offset_signs.csv);
в summary группа исходов outcome_group = ALL | SUCCESS | REJECTED
(SUCCESS — базовые успешные исходы: не REJECTED и не UNKNOWN; ALL включает отказы);
CLEANUP-роль и warmup из summary/histogram исключаются; статистики считаются при
n_valid>=1 (min/mean/median/квантили), stddev при n_valid<2 остаётся пустым
(выборочное n-1 неприменимо). Категория LATE в online и offline определяется по
фактическому КОНЦУ метрики относительно observation_deadline_us, а не по флагу
deadline_exceeded (R5-B3): ранние точки остаются VALID даже при позднем T6.
market_windows.csv, checks.csv, experiment_manifest.csv
market_windows.csv — сохраняемые окна E3 (не более 4096):
session_id,dataset_id,window_id,sequence,calibration_id,symbol,from_msc,to_msc, anchor_tick_msc,n_returned,n_valid_info,quote_frequency_hz,mid_range_ticks,regime,valid, quality_codes,ticks_checksum. Аудит-8 (R8-S2): ticks_checksum — FNV-1a 64 по
(time_msc,bid,ask) валидных INFO-тиков окна; контрольная сумма используется
как ПРОВЕРКА при повторном чтении (CopyTicksRange(from_msc,to_msc) того же
диапазона), а НЕ как источник данных. Аудит-9 (R9-S3): сырые тики окна
удерживаются В ПАМЯТИ (ComputeWindowRawTicks) и выгружаются в
market_ticks.csv в safe-фазе ПОСЛЕ закрытия окна измерения и в ExportRun; аудит-10 R10-B4: файл имеет ЗАГОЛОВОК session_id,window_id,window_seq,time_msc,bid,ask,flags,volume, строки завершаются НАСТОЯЩИМ CRLF (не литеральным \r\n), bid/ask - точность %.17g (полный round-trip double); заголовок пишется при создании/пустом файле; для сессии файл с заголовком гарантируется (EnsureMarketTicksFile)
синхронная файловая запись внутри измерительной фазы запрещена (аудит-8 R8-B3),
поэтому выгрузка перенесена на post-close/export.
Зарезервированы контрактом: признаки/калибровка, результаты проверок, связь пяти
экспериментов (E4 — ссылки на E1, reuse=1, без копирования samples).
Дополнительные файлы
comparisons.csv (A_vs_B: n/mean/median/p95 для A и B, delta = B−A и относительное
изменение (B−A)/A по каждой метрике — ТЗ §7, стр. 419; sign дельты: B медленнее A —
положительная), offset_signs.csv
(NEGATIVE/ZERO/POSITIVE для T2−T4, вне latency-гистограммы), market_ticks.csv
market_ticks.csv (аудит-9 R9-S3: сырые тики окон E3, append-only; строки:
session_id,window_id,window_seq,time_msc,bid,ask,flags,volume; выгрузка из памяти
в safe-фазе после закрытия окна и в ExportRun; порядок одинаковых миллисекунд (R10-B4: заголовок 8 имён, реальный CRLF, %.17g)
сохраняется; сбой выгрузки — fail-closed, новые отправки блокируются), calibration.csv (реестр порогов; trading_session_count = число отдельных
календарных дат валидных окон, генератор считает реальные сессии и loader требует
=5; аудит-5: генератор НЕ сохраняет набор с <5 сессиями или <1000 окон — явный INSUFFICIENT_DATA; добавлены ключи
period_from_msc/period_to_msc),<calibration_id>_windows.csv(исходные окна калибровки:minute_start_msc,quote_frequency_hz,mid_range_ticks— для независимой проверки отсутствия пересечения калибровки и эксперимента и пересчёта порогов),summary_rebuilt.csv/histogram_rebuilt.csv/offset_signs_rebuilt.csv/comparisons_rebuilt.csv(offline-пересчёт:summary_rebuilt.csvиспользует ЕДИНУЮ 41-колоночную схему онлайн-summary; число строк контрольного чтения — от реально созданной таблицы с уникальными ключами; повреждённый/усечённый samples.csv отвергается, а не пересчитывается молча; группы ALL|SUCCESS|REJECTED, категории LATE по концу метрики, T5 поcallback_coverage_complete),intents.csv(устойчивый журнал намерений: строкиsession_id,sequence,kind, local_time_us;INTENTпишется ДО T0; INTENT без SEND_RETURN после сбоя/перезапуска учитывается какn_dispatch_uncertainв manifest — восстановление неопределённых попыток. Аудит-7 R7-S1/B1: запись — ровно n-1 полезный байт с начала без терминального NUL (FileWriteArray(handle,array, start,count)); cleanup-отправки пишутся в тот же журнал; синхронная запись SEND_RETURN перенесена ВНЕ измеряемой фазы T0..T1; при нечитаемости/повреждении журналаn_dispatch_uncertainпринимает sentinel ULONG_MAX (неопределённость не сужается до нуля; ветвь недоступности различима и НЕ преобразуется в обычный счётчик), повреждённая строка — +1 неопределённость. Аудит-10 R10-B2: INTENT_CANCELLED снимает неопределённость РОВНО с одной попытки того же sequence (хронологическая пара): повторный INTENT после отмены без SEND_RETURN остаётся неопределённым. Аудит-8 R8-B3:SEND_RETURNНЕ дописывается синхронно между T1 и обработкой callbacks (один поток исполнения советника): факт возврата буферизуется в памяти и дописывается в safe-фазе после закрытия окна (FlushPendingSendReturns); при аварии до этого попытка честно остаётся DISPATCH_UNCERTAIN. Аудит-8 R8-B4: подтверждённые ключи (sequence) набираются динамически без предела 256 — полностью парный запуск 5x100+очистки даёт 0 неопределённых, а не ложныеINTENT-без-возврата; короткое чтениеFileReadArray != FileSizeтакже даёт sentinel),checkpoint.marker(маркер согласованности завершённого checkpoint-набора samples/events; пишется последним и содержит ПОКОЛЕНИЕ экспортаgen=<N>; старый marker удаляется ДО перезаписи — при сбое между фазами остаётся отсутствующий marker, а не устаревший «успех»; checkpoint выполняется только в безопасной фазеCanCheckpointи его ошибка блокирует новые отправки) —summary_rebuilt_e4.csv(E4: pooled статистика из 500 первичных ASYNC-записей ПЯТИ РАЗНЫХ завершённых E1-серий + per-series строки со ссылками на исходные session_id; без копирования samples и без усреднения серийных медиан; аудит-5: проверяются 5 разных каталогов, уникальные session_id, ровноexpected_mainMAIN B-ASYNC записей на серию (по умолчанию 100), единый символ серий. Аудит-6: manifest.csv источника ОБЯЗАТЕЛЕН (отсутствие = отказ), допускается толькоrun_status=FINISHEDсn_main_dispatched>=expected_main; нормализованная конфигурация (configuration_id) и символ совпадают МЕЖДУ всеми пятью сериями; каждая строка принадлежит сессии серии; последовательности (sequence) уникальны внутри файла; pooled/per-series статистика считаются той же метрической семантикой валидности, что и остальные отчёты (R6-B2/B7). Аудит-7 (R7-B6): обычный E4 принимает только допустимое происхождениеdata_origin(по умолчаниюDEMO;SYNTHETIC-серии отвергаются code 41 вне отдельного синтетического режима);configuration_idСТРОК сверяется с manifest серии (code 42); столбецdata_originприсутствует во всех строках; добавлены показатели полнотыn_attempted, n_applicable, n_not_applicable, n_applicability_unknown, n_missing, n_late, n_conflict, n_interrupted, n_deadline_exceeded, deadline_denominator, deadline_rateпо сериям и pooled (числа нельзя вывести из одного n после фильтрации VALID).
Порядок и контроль
- Порядок строк — по первичному ключу; дубликат ключа — ошибка.
- Чтение samples.csv (rebuild-путь, аудит-6 R6-S1, аудит-7 R7-B4, аудит-8 R8-S1):
полная проверка заголовка (все 68 имён по порядку, перестановка колонок — отказ),
числовая валидация полей времени/масок (нечисловой токен — отказ), дубликаты
sequence — отказ. Деление файла на ЛОГИЧЕСКИЕ записи CSV: перевод строки
внутри кавычек — данные, а не разделитель; терминатор \r записи снимается один
раз (CR внутри данных не вырезается); пустые числовые ячейки сверяются с
present_mask(бит есть, ячейка пуста — отказ; бита нет, значение есть — отказ), т.е. несогласованный файл не заменяется нулями и не пропускается. Ёмкостьcapacity— число НАБЛЮДЕНИЙ; заголовок её НЕ расходует (головка + ровно capacity строк допустимы). Контрольное чтение (ReadBackVerifyFile) считает те же ЛОГИЧЕСКИЕ записи, что и reader (встроенный перевод строки в кавычках — данные), поэтому валидный multiline-экспорт не отвергается собственной проверкой. - Единая семантика online/offline (R6-B2): offline-путь восстанавливает запись в
RequestMetadata и считает категории/применимость/срок той же статической
CRequestTracker::EvaluateMetric; WARMUP-роль исключается одинаково во всех путях; deadline-счётчики summary совпадают с онлайн-экспортом. - Хеши наборов — SHA-256 по отсортированному списку путей (реализация —
CryptEncode(CRYPT_HASH_SHA256)в контрольных точках). - Генерационное время не участвует в числовом сравнении; пересчёт одних исходных байтов даёт точные целые поля и double в допуске max(1e-9, 1e-12*|x|).
- Повторный расчёт — только из архивных CSV (без обращения к текущему счёту).