Files
dzentra_bot/docs/architecture/execution_refactoring.md

902 lines
31 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Execution Architecture Overview
## Архитектурные уровни
### Foundation
- constants.py
- models.py
- pricing.py
- calculations.py
- position_metrics.py
- resets.py
### Business Operations
- position_actions.py
- flip.py
- risk_close.py
### Runtime
- position_runtime.py
- position_protection.py
- runtime_actions.py
- position_exit_decision.py
### Orchestration
- supervisor.py
- engine.py
### Sizing
- sizing.py
# Execution refactoring roadmap
Цель: безопасный поэтапный рефакторинг `app/src/trading/execution`.
Принципы:
- сначала аудит;
- без изменения бизнес-логики;
- без изменения payload;
- без изменения EventBus;
- без изменения JournalService;
- без изменения ExecutionDecision;
- каждый шаг проверяется перезапуском бота.
## Статус файлов
| Файл | Статус | Комментарий |
|---|---|---|
| constants.py | Done | Этап 1 завершён |
| flip.py | Done stage 1 | Reject helper, payload builders, grouping |
| position_actions.py | Done stage 1 | Reject helper, payload builders, grouping |
| risk_close.py | Done | Risk close helper |
| calculations.py | Not audited | |
| engine.py | Not audited | |
| models.py | Not audited | |
| position_exit_decision.py | Not audited | |
| position_metrics.py | Not audited | |
| position_protection.py | Not audited | |
| position_runtime.py | Not audited | |
| pricing.py | Done | Добавлен `_build_execution_price()`, убраны дубли сборки ExecutionPrice |
| quality.py | Not audited | |
| resets.py | Not audited | |
| runtime_actions.py | Not audited | |
| sizing.py | Not audited | |
| supervisor.py | Not audited | |
Completed:
- constants.py
- models.py
- calculations.py
- pricing.py
- resets.py
- risk_close.py
- position_metrics.py
- position_runtime.py
- position_protection.py (safe refactoring)
- flip.py (safe refactoring)
- position_actions.py (safe refactoring)
- runtime_actions.py (safe refactoring)
- supervisor.py (safe refactoring)
- constants.py (completed)
## Правила аудита
Для каждого файла фиксируем:
- назначение;
- размер и сложность;
- зависимости;
- безопасные улучшения;
- что нельзя трогать;
- рекомендуемый следующий шаг.
## Порядок аудита
## Стандарт структуры ExecutionMixin
Порядок методов:
1. Payload builders
2. Journal helpers
3. Decision helpers
4. Validation / Checks
5. Execution methods
6. Utility methods
### Уже обработаны
- constants.py
- flip.py
- position_actions.py
- risk_close.py
### Этап A — маленькие и базовые файлы
1. quality.py
2. models.py
3. calculations.py
4. resets.py
5. pricing.py
6. engine.py
### Этап B — средние файлы
7. position_runtime.py
8. sizing.py
9. runtime_actions.py
10. position_exit_decision.py
### Этап C — крупные и рискованные файлы
11. position_metrics.py
12. supervisor.py
13. position_protection.py
## quality.py
Статус: Empty / candidate for removal later
Назначение:
- Файл существует, но сейчас не содержит логики.
Размер и сложность:
- 2 строки.
- Сложность отсутствует.
Зависимости:
- Нужно отдельно проверить, импортируется ли где-то `src.trading.execution.quality`.
Безопасные улучшения:
- Сейчас ничего не менять.
Что нельзя трогать:
- Не удалять файл до проверки импортов.
Рекомендуемый следующий шаг:
- Позже выполнить grep по проекту:
`grep -R "execution.quality\|from src.trading.execution import quality" app/src`
## models.py
Статус: Completed (без изменений)
Назначение:
- DTO результата выполнения торгового действия.
Размер:
- Отличный.
Связность:
- Минимальная.
Безопасные улучшения:
- Не требуются.
Что нельзя менять:
- Структуру ExecutionDecision.
- Имена полей.
- Поведение.
Итог:
Файл соответствует целевой архитектуре и рефакторинга не требует.
## calculations.py
Статус: Completed after minor cleanup
Назначение:
- Compatibility-wrapper для старых методов расчёта.
- Реальные расчёты централизованы в position_metrics.py.
Размер:
- Небольшой.
Связность:
- Зависит от PositionState и build_position_metrics().
- Связность нормальная.
Безопасные улучшения:
- Только косметика форматирования.
Что нельзя менять:
- Не удалять wrapper-методы.
- Не менять возвращаемые значения.
- Не переносить расчёты обратно в этот файл.
Итог:
Файл архитектурно нормальный. Основная логика уже вынесена в position_metrics.py.
## resets.py
Статус: Completed (без изменений)
Назначение:
- Централизованный reset состояния AutoTradeState.
Размер:
- Хороший.
Связность:
- Минимальная.
Безопасные улучшения:
- Пока не требуются.
Возможные будущие улучшения:
- Только группировка полей по смысловым секциям без изменения поведения.
Что нельзя менять:
- Состав очищаемых полей.
- Порядок вызова методов reset.
Итог:
Файл соответствует целевой архитектуре и рефакторинга не требует.
## pricing.py
Статус: Completed after minor cleanup
Назначение:
- Получение execution-цены для входа, выхода и market last.
- Проверка свежести execution snapshot.
- Нормализация bid/ask/last цены.
Размер:
- Нормальный.
Связность:
- Зависит от ExchangeService, AutoTradeState и ExecutionPrice.
- Связность ожидаемая для pricing-слоя.
Что сделано:
- Добавлен helper `_build_execution_price()`.
- Убраны повторяющиеся сборки `ExecutionPrice`.
- Логика выбора bid/ask/last не менялась.
- Проверка свежести snapshot не менялась.
Безопасные улучшения:
- Завершены.
Что нельзя менять:
- Роли pricing:
- `LONG_ENTRY_ASK`
- `SHORT_ENTRY_BID`
- `ENTRY_LAST`
- `LONG_EXIT_BID`
- `SHORT_EXIT_ASK`
- `EXIT_LAST`
- `MARKET_LAST`
- Логику выбора ask/bid для LONG/SHORT.
- Поведение `_ensure_fresh_snapshot()`.
Итог:
Файл соответствует целевой архитектуре. Рефакторинг на текущем этапе завершён.
## position_metrics.py
Статус: Audited / no changes now
Назначение:
- Центральная точка расчёта метрик открытой и планируемой позиции.
- Формирует PositionMetrics и PlannedPositionMetrics.
Размер:
- Большой, но оправданный.
- В файле много вычислений, но они хорошо разделены на helpers.
Связность:
- Основная связность нормальная: PositionState, NumericLike, safe_float.
- Потенциально спорная связность: `_trading_fee()` обращается к ExchangeService.
Что хорошо:
- Есть единая функция `build_position_metrics()`.
- Есть отдельная функция `build_planned_position_metrics()`.
- Расчёты вынесены в маленькие private helpers.
- Формулы читаемые.
Безопасные улучшения:
- Сейчас не требуются.
Что нельзя менять:
- Формулы PnL.
- Округления.
- Поведение при None/invalid values.
- Расчёт commission.
- Расчёт overnight cashflow.
- Поведение `_trading_fee()`.
Будущий возможный этап:
- Отдельно обсудить, нужно ли выносить получение trading fee из position_metrics.py.
- Но только после тестов и сверки PnL.
Итог:
Файл архитектурно важный и в целом хорошо организован. На текущем безопасном этапе правки не нужны.
## position_runtime.py
Статус: Audited / minor cleanup only
Назначение:
- Обновление runtime PnL открытой позиции.
- Синхронизация PositionState с AutoTradeState.
- Обновление runtime-памяти позиции: peak PnL, MFE/MAE, best/worst price, fatigue.
Размер:
- Средний.
Связность:
- Зависит от PositionState, AutoTradeState, ExecutionPrice и build_position_metrics().
- Связность ожидаемая.
Что хорошо:
- PnL и price move считаются через position_metrics.py.
- Runtime-память позиции вынесена в отдельный helper.
- Fatigue score/state вынесены отдельно.
Что настораживает:
- `_sync_state_from_position()` частично дублирует reset-логику из resets.py.
- Пока это не трогаем, чтобы не изменить поведение.
Безопасные улучшения:
- Только косметика форматирования.
Что нельзя менять:
- Поведение `_sync_state_from_position()`.
- Состав полей, которые сбрасываются при `position.side == "NONE"`.
- Логику peak PnL, MFE/MAE, best/worst price.
- Логику fatigue score.
Итог:
Файл можно оставить как есть. Возможный будущий этап — аккуратно сравнить reset-поля с resets.py, но без автоматического объединения.
# Progress
Completed:
- constants.py
- models.py
- calculations.py
- pricing.py
- resets.py
- risk_close.py
- position_metrics.py
- position_runtime.py
- flip.py (safe refactoring)
- position_actions.py (safe refactoring)
Current status:
- Центральные расчёты execution уже унифицированы.
- PnL рассчитывается только через position_metrics.py.
- Pricing унифицирован.
- Runtime обновляется через единый pipeline.
- Все изменения выполнены без изменения бизнес-логики.
# Architecture decisions
Принятые правила:
1. Любые вычисления позиции должны происходить только через position_metrics.py.
2. Pricing не должен содержать бизнес-логику.
3. Mixins должны иметь следующую структуру:
- helpers
- journal helpers
- validation
- execution
- utility
4. Все безопасные рефакторинги выполняются без изменения поведения execution.
## position_protection.py
Статус: Audited / candidate for safe payload extraction
Назначение:
- Runtime protection открытой позиции.
- Управляет break-even, profit lock и trailing stop.
- Проверяет причины закрытия позиции по protection-логике.
- Логирует события runtime protection.
Размер:
- Большой.
Связность:
- Зависит от PositionState, AutoTradeState, PositionMetrics, ExecutionPrice.
- Использует JournalService и EventBus для runtime protection событий.
- Использует build_position_metrics() для расчётов позиции.
Что хорошо:
- Цена выхода получается один раз в `_process_runtime_protection()`.
- PositionMetrics считается один раз.
- Break-even, profit lock и trailing stop разделены по отдельным методам.
- Закрытие позиции выполняется через общий `_close_position()`.
Что настораживает:
- Большой payload внутри `_log_runtime_protection_event()`.
- Константы thresholds пока находятся прямо в файле.
- Файл совмещает protection-логику и logging payload.
Безопасные улучшения:
- Вынести payload из `_log_runtime_protection_event()` в `_build_runtime_protection_payload()`.
Что нельзя менять:
- Protection thresholds.
- Логику активации break-even.
- Логику profit lock.
- Логику trailing stop.
- Порядок проверки close reason.
- forced_reason при закрытии.
- JournalService/EventBus события.
Итог:
Файл рабочий, но требует безопасного структурного улучшения: сначала вынести payload builder без изменения поведения.
## position_protection.py
Статус: Completed (safe refactoring stage 1)
Назначение:
- Runtime-защита открытой позиции.
- Управляет break-even, profit lock и trailing stop.
- Проверяет условия принудительного закрытия позиции.
- Формирует runtime protection события.
Размер:
- Большой.
Связность:
- PositionState
- AutoTradeState
- PositionMetrics
- ExecutionPrice
- JournalService
- EventBus
Что сделано:
- Добавлен helper `_build_runtime_protection_payload()`.
- Построение payload вынесено из `_log_runtime_protection_event()`.
- `_log_runtime_protection_event()` теперь отвечает только за:
- построение payload;
- запись в JournalService;
- публикацию EventBus.
- Поведение protection полностью сохранено.
Что НЕ изменялось:
- Break-even.
- Profit lock.
- Trailing stop.
- Protection thresholds.
- Алгоритм закрытия позиции.
- Journal payload.
- EventBus payload.
Что нельзя менять на следующих этапах:
- Последовательность обработки protection.
- Логику определения close reason.
- Формулы расчёта protection уровней.
- Runtime protection thresholds.
Возможный следующий этап:
- При необходимости вынести protection thresholds в отдельный constants.py,
но только после завершения всего безопасного рефакторинга execution.
Итог:
Файл приведён к единому стилю execution.
## position_exit_decision.py
Статус: Audited / no changes now
Назначение:
- Runtime-intelligence решение о закрытии позиции.
- Определяет close reason по giveback, time-decay, hard-loss и нормальному pullback.
Размер:
- Средний/большой.
Связность:
- Зависит от AutoTradeState, PositionState, PositionMetrics.
- Использует build_position_metrics().
- Использует get_position_exit_thresholds() из execution/constants.py.
Что хорошо:
- Расчёты позиции берутся из position_metrics.py.
- Thresholds вынесены из файла.
- Giveback и time-decay разделены по отдельным методам.
- Нет JournalService/EventBus/payload.
Что настораживает:
- Длинные методы `_giveback_close_reason()` и `_time_decay_close_reason()`.
- Много строковых close reason прямо внутри условий.
- Decision-методы частично изменяют state.
Безопасные улучшения:
- Сейчас не требуются.
Что нельзя менять:
- Порядок проверки giveback/time-decay.
- Порядок условий внутри `_giveback_close_reason()`.
- Порядок условий внутри `_time_decay_close_reason()`.
- Строковые close reason.
- Изменения state внутри decision-логики.
- Thresholds.
Будущий возможный этап:
- После завершения безопасного аудита можно отдельно обсудить вынос reason-кодов в constants.py.
- Дробление длинных методов делать только отдельным этапом с тестами.
Итог:
Файл архитектурно понятный, но чувствительный к порядку условий. На текущем этапе оставляем без изменений.
## runtime_actions.py
Статус: Audited / candidate for safe payload extraction
Назначение:
- Runtime autonomous actions для открытой позиции.
- Обрабатывает autonomous EXIT / REDUCE / PROTECT.
- Проверяет cooldown runtime actions.
- Логирует runtime action события.
Размер:
- Средний/большой.
Связность:
- Зависит от AutoTradeState, PositionState, ExecutionDecision.
- Использует JournalService и EventBus.
- Использует execution constants и get_position_exit_thresholds().
Что хорошо:
- Основной вход — `process_runtime_action()`.
- Cooldown вынесен в `_runtime_action_cooldown_active()`.
- Early exit guard вынесен в `_early_exit_guard_active()`.
- Закрытие позиции выполняется через общий `_close_position()`.
Что настораживает:
- Большой payload внутри `_log_runtime_action()`.
- `_log_runtime_action()` совмещает dedupe, payload, Journal, EventBus, state update и ExecutionDecision.
Безопасные улучшения:
- Вынести payload из `_log_runtime_action()` в `_build_runtime_action_payload()`.
Что нельзя менять:
- Порядок обработки action.
- Early exit guard.
- Confidence threshold.
- Cooldown logic.
- Deduplication key.
- State updates в `_log_runtime_action()`.
- Journal/EventBus payload.
Итог:
Файл рабочий. Первый безопасный шаг — вынести payload builder без изменения поведения.
## runtime_actions.py
Статус: Completed (safe refactoring stage 1)
Что сделано:
- Добавлен helper `_build_runtime_action_payload()`.
- Payload вынесен из `_log_runtime_action()`.
- `_log_runtime_action()` сохранил dedupe, JournalService, EventBus, state update и ExecutionDecision.
- Поведение runtime actions не менялось.
Что НЕ изменялось:
- Порядок обработки autonomous action.
- Cooldown logic.
- Early exit guard.
- Confidence threshold.
- Deduplication key.
- Journal/EventBus payload.
- State updates.
Итог:
Файл приведён к единому стилю execution.
## supervisor.py
Статус: Audited / candidate for safe payload extraction
Назначение:
- Execution supervisor перед исполнением торгового действия.
- Блокирует исполнение при emergency halt, cooldown, degraded market, stale execution, entry block, low confidence и signal conflict.
Размер:
- Средний/большой.
Связность:
- Зависит от AutoTradeState, ExecutionDecision, JournalService, EventBus.
- Использует execution thresholds/settings из состояния и констант engine.
Что хорошо:
- Основной вход — `_process_execution_supervisor()`.
- Причины блокировки разделены по отдельным методам.
- UI-тексты вынесены в `_human_execution_block()`.
- Есть dedupe через `_last_supervisor_block_key`.
Что настораживает:
- Большой payload внутри `_block_execution()`.
- `_block_execution()` совмещает state update, UI block, dedupe, payload, JournalService, EventBus и ExecutionDecision.
Безопасные улучшения:
- Вынести payload из `_block_execution()` в `_build_supervisor_block_payload()`.
Что нельзя менять:
- Порядок проверок в `_process_execution_supervisor()`.
- Логику emergency halt.
- Cooldown logic.
- Degraded market logic.
- Early impulse allowance.
- Stale execution logic.
- Entry block logic.
- Low execution confidence logic.
- Conflict signal logic.
- UI-тексты в `_human_execution_block()`.
- Dedupe key.
- Journal/EventBus payload.
Итог:
Файл рабочий. Первый безопасный шаг — вынести payload builder без изменения поведения.
## supervisor.py
Статус: Completed (safe refactoring stage 1)
Что сделано:
- Добавлен helper `_build_supervisor_block_payload()`.
- Payload вынесен из `_block_execution()`.
- `_block_execution()` сохранил:
- state update;
- UI block;
- dedupe;
- JournalService;
- EventBus;
- ExecutionDecision.
- Поведение supervisor не менялось.
Что НЕ изменялось:
- Порядок проверок supervisor.
- Emergency halt.
- Cooldown logic.
- Degraded market logic.
- Early impulse allowance.
- Stale execution logic.
- Entry block logic.
- Low confidence logic.
- Signal conflict logic.
- UI-тексты.
- Dedupe key.
- Journal/EventBus payload.
Итог:
Файл приведён к единому стилю execution.
## sizing.py
Статус: Audited / no logic changes
Назначение:
- Расчёт размера позиции по risk и stop-loss.
- Adaptive size multiplier.
- Market score для sizing.
- Синхронизация adaptive size/effective risk в AutoTradeState.
- Ограничение размера позиции по margin limit.
- Округление размера позиции.
Размер:
- Средний/большой.
Связность:
- Зависит от AutoTradeState, ExecutionPrice, safe_float.
- Активно изменяет поля AutoTradeState.
Что хорошо:
- Расчёт размера, multiplier, market score, margin limit и rounding разделены.
- Нет JournalService/EventBus/payload.
- `_sync_effective_risk_after_margin_limit()` вынесен отдельно.
Что настораживает:
- Очень чувствительный файл: любые изменения влияют на реальные размеры сделок.
- Много state updates.
- Повторяются вызовы `_sync_adaptive_size_state(...0...)`, но пока их лучше не трогать.
Безопасные улучшения:
- Только косметика форматирования.
Что нельзя менять:
- Формулу base size.
- Adaptive multiplier thresholds.
- Market score thresholds.
- Execution quality multipliers.
- Margin limit logic.
- Effective risk recalculation.
- Rounding logic.
Итог:
Файл архитектурно понятный, но очень чувствительный. На текущем этапе оставляем без изменения логики.
## engine.py
Статус: Audited / minor cleanup only
Назначение:
- Главная orchestration-точка execution layer.
- Управляет последовательностью execution pipeline.
Размер:
- Нормальный.
Связность:
- Собирает execution mixins.
- Использует AutoTradeState, ExecutionDecision и PositionState.
- Не содержит JournalService/EventBus/payload.
Что хорошо:
- `process()` имеет понятный последовательный pipeline.
- Бизнес-логика вынесена в mixins.
- Risk close, runtime protection, supervisor, flip и open position разделены.
- Нет прямых расчётов PnL/sizing/pricing внутри engine.
Pipeline:
1. Sync state.
2. Проверка RUNNING.
3. Update unrealized PnL.
4. Risk close.
5. Runtime protection.
6. Signal readiness.
7. Execution supervisor.
8. Duplicate signal guard.
9. Flip.
10. Open position.
11. Skip if no action.
Безопасные улучшения:
- Только косметика форматирования.
Что нельзя менять:
- Порядок pipeline.
- Состав mixins.
- Class-level настройки.
- Duplicate signal guard.
- Порядок flip/open position.
Итог:
Файл соответствует роли orchestration layer. Логических правок не требуется.
## flip.py
Статус: Completed (safe refactoring stage 1)
Что сделано:
- Добавлен helper `_reject_flip()`.
- Вынесены payload builders:
- `_build_flip_rejected_payload()`
- `_build_flip_blocked_payload()`
- `_build_flip_executed_payload()`
- Методы сгруппированы по смыслу:
- payload builders
- journal helpers
- decision helpers
- flip checks
- execution
- Поведение flip не менялось.
Что НЕ изменялось:
- `_flip_position()` не разбивался.
- `_flip_block_reason()` не разбивался.
- Алгоритм flip не менялся.
- Порядок проверок не менялся.
- Payload не расширялся.
- EventBus не менялся.
- JournalService не менялся.
- ExecutionDecision не менялся.
Что нельзя менять на текущем этапе:
- Порядок расчёта exit/entry price.
- Расчёт pnl.
- Обновление cycle stats.
- Логику loss cooldown.
- Создание новой PositionState.
- Порядок reset runtime/protection state.
- Порядок Journal/EventBus событий.
Будущий этап:
- Только после завершения всего аудита можно отдельно рассмотреть аккуратное разбиение `_flip_position()` на несколько внутренних шагов.
- Расширение payload для анализа стратегии делать отдельным этапом, не смешивать с safe refactoring.
Итог:
Файл приведён к единому стилю execution. На текущем безопасном этапе дополнительных правок не требуется.
## position_actions.py
Статус: Completed (safe refactoring stage 1)
Что сделано:
- Добавлен helper `_reject_position_open()`.
- Вынесены payload builders:
- `_build_position_open_rejected_payload()`
- `_build_position_opened_payload()`
- `_build_position_closed_payload()`
- Методы сгруппированы:
- trade id
- payload builders
- journal helpers
- decision helpers
- position actions
- Поведение открытия/закрытия позиции не менялось.
Что НЕ изменялось:
- `_open_position_if_empty()` не разбивался.
- `_close_position()` не разбивался.
- Алгоритм открытия позиции не менялся.
- Алгоритм закрытия позиции не менялся.
- Payload не расширялся.
- JournalService/EventBus не менялись.
- ExecutionDecision не менялся.
Что нельзя менять на текущем этапе:
- Порядок расчёта entry/exit price.
- Расчёт size.
- Margin limit.
- Расчёт pnl.
- Обновление cycle stats.
- Loss cooldown.
- Reset position/protection runtime.
- Порядок Journal/EventBus событий.
Итог:
Файл приведён к единому стилю execution. На текущем безопасном этапе дополнительных правок не требуется.
## constants.py
Статус: Completed
Назначение:
- Единая точка констант execution layer.
- Хранит execution actions, types, reasons, pricing modes, runtime actions, position health/risk/exit thresholds и flip filters.
Что сделано ранее:
- Удалены дубли констант.
- Константы сгруппированы по смысловым разделам.
- Сохранены существующие имена констант.
- Логика не менялась.
Что хорошо:
- Есть asset-specific thresholds.
- Есть helper `asset_symbol()`.
- Есть helper `get_position_thresholds()`.
- Health/exit thresholds доступны через отдельные helpers.
- `build_flip_action()` оставлен совместимым.
Что нельзя менять:
- Имена существующих констант.
- Значения thresholds.
- Структуру `DEFAULT_POSITION_THRESHOLDS`.
- Структуру `POSITION_THRESHOLDS_BY_ASSET`.
- Поведение helper-функций.
Итог:
Файл завершён. Дополнительных правок на safe stage не требуется.
# Safe refactoring stage 1 — completed
Статус: завершён.
Проверены все файлы `app/src/trading/execution`.
Итог:
- payload builders вынесены из крупных execution-файлов;
- reject/block helpers добавлены там, где это безопасно;
- pricing унифицирован через `_build_execution_price()`;
- position metrics признан центральной точкой расчётов;
- engine подтверждён как orchestration layer;
- бизнес-логика не менялась;
- payload не расширялся;
- бот после каждого шага успешно перезапускался.