Эксплуатация на VPS¶
Цель VPS-контура - запустить Китобоя так, чтобы он мог жить без ручного присмотра, но при этом не имел права тихо ломаться.
До боевых ордеров live должен пройти период наблюдения:
2-4 недели без ручного вмешательства
Что должно быть на VPS¶
Минимально:
репозиторий Decima-8-Sanctum
собранный decima8/build-os/d8_agent_cli
собранный store/market/build/market_to_vsb
собранный store/market/build/market_bake_brain_specs
Python окружение
Bybit ключи в защищенном env/config
директория store/market/runs/live
логирование stdout/stderr
мониторинг диска
systemd или аналогичный supervisor
Что должно запускаться¶
Базовый live:
python3 store/market/tools/whaler_s300_stage_live.py \
--env mainnet \
--category linear \
--symbol BTCUSDT
До включения боевых ордеров:
inventory = paper/dry-run
order executor = disabled
После включения боевых ордеров:
director -> order intent -> risk gate -> exchange executor -> exchange reconciliation
Нельзя смешивать paper и real¶
Боевой слой должен быть отдельным:
director decision
-> order intent
-> risk gate
-> exchange order
-> exchange fill
-> reconciled inventory
Paper inventory не должен притворяться биржевым балансом.
Нужны два состояния:
model_inventory
exchange_inventory
И отдельная сверка:
model position == exchange position
model qty == exchange qty
model side == exchange side
Health metrics¶
Минимальные метрики:
process_alive
start_time
uptime_seconds
last_trade_time
last_ws_message_time
last_frame_time
last_s300_time
last_s1800_time
last_director_write_time
ws_messages
trades
frames
reconnects
signals
decisions
equity
position_side
position_qty
realized_pnl
mark_pnl
drawdown
free_disk_gb
Файлы мониторинга¶
Каждый live run должен иметь:
director.json
director.tsv
director.html
mtf.s300.html
mtf.s1800.html
frames.mtf.s300.jsonl
frames.mtf.s1800.jsonl
tape.mtf.s300.raw8.vsb
tape.mtf.s1800.raw8.vsb
director.json - машинное состояние.
director.tsv - таблица решений.
director.html - человеческий монитор.
Аварийные условия¶
Kill switch должен срабатывать при:
нет ws messages дольше N секунд
нет trades дольше N секунд при активном рынке
нет новых frames дольше N секунд
director не обновлялся дольше N секунд
reconnect storm
exchange inventory != model inventory
max daily loss
max weekly loss
max consecutive losses
disk free ниже порога
исключение в order executor
неизвестный position side
битый config
Kill switch должен:
запретить новые входы
записать причину
отправить alert
по настройке закрыть позицию или оставить только manual mode
Диск¶
Диск уже был реальной проблемой. Поэтому на VPS нельзя бесконечно копить тяжелые артефакты.
Сохранять постоянно:
director.json
director.tsv
director.html
frames.mtf.s300.jsonl
frames.mtf.s1800.jsonl
логи решений
логи ордеров
Сжимать или удалять по retention policy:
сырой trade stream
старые tape.raw8.vsb
старые html heatmaps
временные run.jsonl
debug reports
Минимальная политика:
последние 7 дней: полный live context
последние 30 дней: director + frames + order logs
старше 30 дней: сжатые summaries
Alerts¶
Нужны alerts:
процесс упал
нет данных
много reconnects
позиция открыта слишком долго
дневной лимит близко
kill switch active
диск заполнен
расхождение inventory
ошибка ордера
Канал может быть любым: Telegram, email, webhook. Важно, чтобы alert содержал:
symbol
run id
time
severity
reason
position
equity
последний decision
ссылка/путь на director.html
Перед боевыми ордерами¶
Checklist:
- live работает 2-4 недели без ручного вмешательства;
- live vs offline replay сверены на одном периоде;
- funding учтен;
- slippage учтен;
- комиссия соответствует бирже;
- max daily loss задан;
- max weekly loss задан;
- kill switch проверен;
- dry-run order intents пишутся корректно;
- exchange reconciliation реализован;
- order executor умеет idempotency;
- все решения директора журналируются;
- есть способ быстро отключить торговлю.
Боевой order executor¶
Executor не должен принимать "сигналы". Он должен принимать только decision/order intent от директора.
Пример order intent:
{
"run_id": "s300_stage_BTCUSDT_20260613_022832",
"symbol": "BTCUSDT",
"decision_id": "2026-06-13T02:28:32Z-000123",
"action": "open_short",
"side": "Sell",
"reduce_only": false,
"notional_fraction": 0.5,
"reason": "v42 signal S42011, s1800 phase allows short",
"max_slippage_bps": 5.0
}
Executor отвечает:
принял
проверил риск
отправил ордер
получил fill
сверил позицию
записал результат
Идемпотентность¶
Каждый order intent должен иметь уникальный id.
Если процесс перезапустился, он не должен повторно открыть позицию по старому решению.
Правило:
один decision_id -> максимум один exchange order
Режимы запуска¶
Нужно явно различать:
observe: live data + director, без inventory
paper: live data + director + paper inventory
dry-run-orders: order intents пишутся, но не отправляются
testnet: боевые вызовы на testnet
mainnet-small: mainnet минимальным размером
mainnet: полноценный режим
Переход между режимами должен быть config change, а не правка кода.