Цель — не просто «обучить модель», а получить три независимо проверяемых результата:
LEVEL — где находится значимый уровень и какова вероятность, что он удержится/сломается.
CONTEXT — что рынок сейчас делает: продолжение, пауза, принятие, ретест, ловушка, разворот.
SIGNAL — есть ли сейчас конкретная ситуация с положительным математическим ожиданием после комиссии, проскальзывания и задержки.
И только когда эти три части согласованы:
LEVEL + CONTEXT + EXECUTION
↓
FINAL SIGNAL
—
Целевой POTOK
Я бы довёл архитектуру до такой:
RAW FEED
Trades + Book
↓
────────────────────────────────
CORE MICROSTRUCTURE
Aggregate / Sweep / Pull / REST
DOM lifecycle / Ghost / Migration
Flow windows
────────────────────────────────
↓
RAW EVIDENCE
без порогов и без clamp
↓
┌─────────────────┬─────────────────┐
│ LEVEL ENGINE │ SCENARIO ENGINE │
│ где деньги │ что происходит │
│ hold / break │ context / phase │
└─────────────────┴─────────────────┘
↓
CANDIDATE ENGINE
↓
Quality Gate
↓
calibrated probability
↓
SIGNAL
А визуал уже только отображает результат этой системы.
—
Этап A. v0.73 — Identity & Determinism
Это следующий этап, и я считаю его обязательным до ScnLadder, V-разворотов и новых сигналов.
A1. event_uid
Добавляем настоящий 16-байтный идентификатор события:
struct UUIDv7
{
uchar bytes[16];
};
и:
PotokEvent.event_uid
StorageEventRow.event_uid
Но предложенный генератор с MathRand() я не стал бы использовать в таком виде.
Причина: мы одновременно хотим:
одни и те же исходные данные + один config → идентичная база.
Случайный хвост UUID это нарушит.
Поэтому делаем deterministic UUIDv7:
48 bit time_msc
4 bit version=7
12 bit ordinal внутри ms
62 bit deterministic hash
Hash строим из стабильных данных:
symbol
first_time_msc
last_time_msc
direction
first_px_tick
last_px_tick
volume
trades
ordinal
config_hash
UUID остаётся валидным UUIDv7, сортируется по времени, но повторный replay получает тот же event_uid.
A2. scenario_uid
В ScenarioState:
UUIDv7 scenario_uid;
Он рождается один раз:
ScnStart()
и НЕ меняется при:
PRESSURE
→ STALL
→ VACUUM
→ BREAK
→ ACCEPT
...
Это один сценарий.
A3. Не current_scenario_id, а scenario_uid
В events добавляем:
scenario_uid BLOB(16)
scn_phase INTEGER
scn_step INTEGER
Это лучше, чем INTEGER current_scenario_id.
Получится точная связь:
event
↓
scenario_uid
↓
конкретный сценарий
↓
phase/step в момент event
И JOIN уже элементарный:
SELECT *
FROM events e
JOIN scn_transitions s
ON e.scenario_uid = s.scenario_uid
A4. Разделяем scenarios и scn_transitions
Сейчас наша таблица scenario фактически уже похожа на журнал переходов: туда пишутся from_phase/to_phase.
Я бы в новой схеме сделал две сущности:
scenarios
---------
scenario_uid
start_time_msc
dir
start_px_tick
config_hash
scn_transitions
---------------
scenario_uid
time_msc
from_phase
to_phase
step
anchor_tick
reason
evidence...
scenarios — рождение.
scn_transitions — история жизни.
Никаких постоянных UPDATE не требуется.
A5. config_hash
В meta:
code_version
schema_version
feature_schema_version
config_hash
symbol
tick_size
digits
server
session_start
Причём config_hash — хеш всех Inputs, влияющих на алгоритм.
Это позволит потом сказать:
этот результат получен алгоритмом 0.80 при конфигурации 79A3....
A6. Golden Replay
Здесь есть важная вещь, которой нет даже в представленном плане.
Чтобы проверить настоящий детерминизм, мало два раза прочитать таблицу events.
Нужно иметь эталонный кусок сырого потока:
Trades
BookEvents
их точный порядок
timestamps
и дважды прогнать через Core.
Иначе мы проверяем только БД, а не алгоритм.
Поэтому делаем небольшой Golden Feed Recorder для тестовых сессий.
Гейт v0.73:
same raw feed
+ same config
=
same events
same scenario transitions
same level transitions
same UUIDs
—
Этап B. v0.74 — Raw Feature Layer
Это один из самых важных этапов всего проекта.
Ваш файл совершенно правильно ставит сырые признаки как критический этап: сейчас большинство данных уже существует, но итоговые score смешивают математику, веса и clamp.
Например сейчас:
FlowInitiativeScore()
сразу делает:
dominance
speed clamp
tempo clamp
move clamp
DOM bias
weights
→