refactor(auto): improve runtime reset structure and observing UI

This commit is contained in:
2026-07-02 21:59:22 +03:00
parent af276b1ce4
commit 954ca0e427
3 changed files with 81 additions and 104 deletions

View File

@@ -1535,8 +1535,16 @@ def _trade_word(value: int) -> str:
def _cycle_summary_lines(state) -> list[str]: def _cycle_summary_lines(state) -> list[str]:
# Единый блок статистики текущего цикла. status = str(getattr(state, "status", "") or "").upper()
# Показываем номер цикла всегда, даже если закрытых сделок ещё нет.
# В режиме наблюдения торгового цикла нет:
# бот только анализирует рынок и не исполняет сделки.
if status == "OBSERVING":
return ["🔬 Анализ рынка"]
if status != "RUNNING":
return []
cycle_trades = int(getattr(state, "cycle_closed_trades", 0) or 0) cycle_trades = int(getattr(state, "cycle_closed_trades", 0) or 0)
cycle_pnl = float(getattr(state, "cycle_realized_pnl_usd", 0.0) or 0.0) cycle_pnl = float(getattr(state, "cycle_realized_pnl_usd", 0.0) or 0.0)

View File

@@ -152,6 +152,9 @@ class AutoLifecycleMixin(
if state.status == "OBSERVING": if state.status == "OBSERVING":
state.status = "RUNNING" state.status = "RUNNING"
if state.cycle_started_at is None:
state.cycle_started_at = time.monotonic()
state.cycle_number = int(getattr(state, "cycle_number", 0) or 0) + 1
# При ручном запуске из OBSERVING очищаем старую cooldown-блокировку, # При ручном запуске из OBSERVING очищаем старую cooldown-блокировку,
# чтобы запуск не наследовал паузу прошлого цикла. # чтобы запуск не наследовал паузу прошлого цикла.
reset_loss_cooldown_state(state) reset_loss_cooldown_state(state)
@@ -185,19 +188,11 @@ class AutoLifecycleMixin(
reset_flip_runtime_state(state) reset_flip_runtime_state(state)
state.cycle_started_at = time.monotonic() state.cycle_started_at = time.monotonic()
state.cycle_number = int(getattr(state, "cycle_number", 0) or 0) + 1
state.last_signal = "HOLD" state.last_signal = "HOLD"
state.signal_started_at = time.monotonic() state.signal_started_at = time.monotonic()
state.cycle_number = int(getattr(state, "cycle_number", 0) or 0) + 1 state.cycle_number = int(getattr(state, "cycle_number", 0) or 0) + 1
state.last_flip_old_side = None
state.last_flip_new_side = None
state.last_flip_pnl_usd = None
state.last_flip_reason = None
state.last_flip_monotonic_at = None
state.last_signal = "HOLD"
state.signal_started_at = time.monotonic()
EventBus.emit( EventBus.emit(
"auto_status_changed", "auto_status_changed",
@@ -240,7 +235,7 @@ class AutoLifecycleMixin(
reset_execution_runtime_state(state) reset_execution_runtime_state(state)
reset_position_semantics_state(state) reset_position_semantics_state(state)
state.cycle_started_at = time.monotonic() state.cycle_started_at = None
self._log_auto_status_changed( self._log_auto_status_changed(
previous_status=previous_status, previous_status=previous_status,

View File

@@ -1,56 +1,20 @@
# app/src/trading/auto/state_reset.py # app/src/trading/auto/state_reset.py
from __future__ import annotations
""" """
Centralized runtime reset helpers for AutoTrade. Centralized runtime reset helpers for AutoTrade.
Helpers для сброса отдельных частей AutoTradeState.
ВАЖНО: Файл содержит только чистые функции сброса AutoTradeState.
Все функции этого файла отвечают только за очистку runtime-состояния. Без EventBus, JournalService, ExecutionEngine и другой бизнес-логики.
Каждая функция отвечает только за одну смысловую область runtime.
Функции намеренно не используют EventBus, JournalService,
ExecutionEngine или другие сервисы. Они изменяют только
поля AutoTradeState.
Это позволяет безопасно использовать их из разных runtime-компонентов
без изменения бизнес-логики.
ВАЖНО:
Они не должны изменять пользовательские настройки:
• symbol
• strategy
• leverage
• risk_percent
• stop_loss_percent
• take_profit_percent
• allocated_balance_usd
Их задача — заменить сотни ручных присваиваний вида
state.xxx = None
state.yyy = False
state.zzz = 0
едиными helper-функциями.
Используются из:
• auto_lifecycle.py
• signal_runtime.py
• execution.py
• других runtime-модулей.
""" """
from __future__ import annotations
from src.trading.auto.state import AutoTradeState from src.trading.auto.state import AutoTradeState
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Adaptive Position Sizing # Adaptive Position Sizing
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Runtime-параметры, связанные с динамическим изменением размера позиции.
# Сбрасываются при начале нового цикла или полном сбросе runtime.
# -----------------------------------------------------------------------------
def reset_adaptive_size_state(state: AutoTradeState) -> None: def reset_adaptive_size_state(state: AutoTradeState) -> None:
state.adaptive_size_base = None state.adaptive_size_base = None
@@ -67,9 +31,6 @@ def reset_adaptive_size_state(state: AutoTradeState) -> None:
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Signal Runtime # Signal Runtime
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Сбрасывает только runtime сигнала.
# Не затрагивает market context, позицию или protection.
# -----------------------------------------------------------------------------
def reset_signal_runtime_state(state: AutoTradeState) -> None: def reset_signal_runtime_state(state: AutoTradeState) -> None:
state.last_signal = "HOLD" state.last_signal = "HOLD"
@@ -79,7 +40,6 @@ def reset_signal_runtime_state(state: AutoTradeState) -> None:
state.signal_started_at = None state.signal_started_at = None
state.signal_updated_at = None state.signal_updated_at = None
state.signal_confirmation_seconds = 0 state.signal_confirmation_seconds = 0
state.signal_confirmation_missing_repeats = 0 state.signal_confirmation_missing_repeats = 0
state.signal_confirmation_progress = 0.0 state.signal_confirmation_progress = 0.0
@@ -94,24 +54,29 @@ def reset_signal_runtime_state(state: AutoTradeState) -> None:
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Execution Runtime # Execution Runtime
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Сбрасывает все runtime-данные, связанные с execution layer:
# semantic status, quality, pricing snapshot и confidence.
# -----------------------------------------------------------------------------
def reset_execution_runtime_state(state: AutoTradeState) -> None: def reset_execution_block_state(state: AutoTradeState) -> None:
state.execution_block_reason = None state.execution_block_reason = None
state.execution_block_title = None state.execution_block_title = None
state.execution_block_message = None state.execution_block_message = None
state.execution_block_action = None state.execution_block_action = None
def reset_execution_semantic_state(state: AutoTradeState) -> None:
state.execution_semantic_status = None state.execution_semantic_status = None
state.execution_semantic_message = None state.execution_semantic_message = None
state.execution_semantic_reason = None state.execution_semantic_reason = None
def reset_execution_quality_state(state: AutoTradeState) -> None:
state.execution_quality = None state.execution_quality = None
state.execution_quality_reason = None state.execution_quality_reason = None
state.execution_quality_message = None state.execution_quality_message = None
state.snapshot_age_seconds = None
state.spread_percent = None
def reset_execution_pricing_state(state: AutoTradeState) -> None:
state.execution_price_source = None state.execution_price_source = None
state.execution_price_age_seconds = None state.execution_price_age_seconds = None
state.execution_bid_price = None state.execution_bid_price = None
@@ -119,66 +84,74 @@ def reset_execution_runtime_state(state: AutoTradeState) -> None:
state.execution_last_price = None state.execution_last_price = None
state.execution_price_freshness = None state.execution_price_freshness = None
def reset_execution_confidence_state(state: AutoTradeState) -> None:
state.execution_confidence_score = None state.execution_confidence_score = None
state.execution_confidence_level = None state.execution_confidence_level = None
state.execution_confidence_reason = None state.execution_confidence_reason = None
state.execution_confidence_factors = None state.execution_confidence_factors = None
state.snapshot_age_seconds = None
state.spread_percent = None def reset_execution_runtime_state(state: AutoTradeState) -> None:
reset_execution_block_state(state)
reset_execution_semantic_state(state)
reset_execution_quality_state(state)
reset_execution_pricing_state(state)
reset_execution_confidence_state(state)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Market Analysis Runtime # Market Runtime
# -----------------------------------------------------------------------------
# Полностью очищает runtime-анализ рынка.
# Используется при истечении TTL или полном сбросе runtime.
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def reset_market_analysis_state(state: AutoTradeState) -> None: def reset_market_base_state(state: AutoTradeState) -> None:
state.market_state = None state.market_state = None
state.market_trend = None state.market_trend = None
state.market_volatility = None state.market_volatility = None
state.market_trend_strength = None state.market_trend_strength = None
state.market_trend_quality = None state.market_trend_quality = None
state.market_phase = None state.market_phase = None
state.market_phase_direction = None state.market_phase_direction = None
def reset_market_score_state(state: AutoTradeState) -> None:
state.market_score = None state.market_score = None
state.market_score_label = None state.market_score_label = None
state.market_long_score = None state.market_long_score = None
state.market_short_score = None state.market_short_score = None
def reset_market_candle_state(state: AutoTradeState) -> None:
state.last_closed_candle_change_percent = None state.last_closed_candle_change_percent = None
state.last_closed_candle_direction = None state.last_closed_candle_direction = None
state.current_interval_change_percent = None state.current_interval_change_percent = None
state.current_interval_direction = None state.current_interval_direction = None
state.current_interval_label = None state.current_interval_label = None
def reset_market_structure_state(state: AutoTradeState) -> None:
state.market_structure = None state.market_structure = None
state.market_structure_reason = None state.market_structure_reason = None
def reset_market_trend_quality_state(state: AutoTradeState) -> None:
state.market_trend_gap_percent = None state.market_trend_gap_percent = None
state.market_trend_consistency = None state.market_trend_consistency = None
state.market_trend_efficiency = None state.market_trend_efficiency = None
state.trend_quality_score = None state.trend_quality_score = None
state.ema_distance_atr_ratio = None state.ema_distance_atr_ratio = None
state.ema_distance_state = None state.ema_distance_state = None
state.entry_timing_state = None state.entry_timing_state = None
state.entry_timing_reason = None state.entry_timing_reason = None
state.ema_fast_slope_percent = None state.ema_fast_slope_percent = None
state.ema_slow_slope_percent = None state.ema_slow_slope_percent = None
state.candle_noise_score = None state.candle_noise_score = None
state.price_position_score = None state.price_position_score = None
def reset_market_htf_state(state: AutoTradeState) -> None:
state.htf_interval = None state.htf_interval = None
state.htf_atr_percent = None state.htf_atr_percent = None
state.htf_atr_percent_baseline = None state.htf_atr_percent_baseline = None
@@ -195,30 +168,41 @@ def reset_market_analysis_state(state: AutoTradeState) -> None:
state.htf_confirmation_score = None state.htf_confirmation_score = None
state.htf_reason = None state.htf_reason = None
def reset_market_momentum_state(state: AutoTradeState) -> None:
state.momentum_state = None state.momentum_state = None
state.momentum_direction = None state.momentum_direction = None
state.momentum_change_percent = None state.momentum_change_percent = None
state.momentum_strength = None state.momentum_strength = None
state.breakout_level = None state.breakout_level = None
state.breakout_distance_percent = None state.breakout_distance_percent = None
state.breakout_reason = None state.breakout_reason = None
def reset_market_analysis_meta_state(state: AutoTradeState) -> None:
state.market_analysis_interval = None state.market_analysis_interval = None
state.market_analysis_reason = None state.market_analysis_reason = None
state.market_analysis_updated_at = None state.market_analysis_updated_at = None
state.entry_block_reason = None state.entry_block_reason = None
state.entry_block_message = None state.entry_block_message = None
state.market_runtime_degraded = False state.market_runtime_degraded = False
def reset_market_analysis_state(state: AutoTradeState) -> None:
reset_market_base_state(state)
reset_market_score_state(state)
reset_market_candle_state(state)
reset_market_structure_state(state)
reset_market_trend_quality_state(state)
reset_market_htf_state(state)
reset_market_momentum_state(state)
reset_market_analysis_meta_state(state)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Runtime Expiration # Runtime Expiration
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Причина последнего автоматического сброса runtime.
# -----------------------------------------------------------------------------
def reset_runtime_expiration_state(state: AutoTradeState) -> None: def reset_runtime_expiration_state(state: AutoTradeState) -> None:
state.runtime_expired_reason = None state.runtime_expired_reason = None
@@ -229,13 +213,15 @@ def reset_runtime_expiration_state(state: AutoTradeState) -> None:
# Position Runtime # Position Runtime
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def reset_position_runtime_state(state: AutoTradeState) -> None: def reset_position_identity_state(state: AutoTradeState) -> None:
state.position_side = "NONE" state.position_side = "NONE"
state.entry_price = None state.entry_price = None
state.position_size = None state.position_size = None
state.position_opened_monotonic_at = None state.position_opened_monotonic_at = None
state.unrealized_pnl_usd = None state.unrealized_pnl_usd = None
def reset_position_health_state(state: AutoTradeState) -> None:
state.position_pnl_percent = None state.position_pnl_percent = None
state.position_hold_seconds = None state.position_hold_seconds = None
state.position_pressure = None state.position_pressure = None
@@ -249,9 +235,10 @@ def reset_position_runtime_state(state: AutoTradeState) -> None:
state.position_exit_pressure = None state.position_exit_pressure = None
# ----------------------------------------------------------------------------- def reset_position_runtime_state(state: AutoTradeState) -> None:
# Position Semantics / Intelligence reset_position_identity_state(state)
# ----------------------------------------------------------------------------- reset_position_health_state(state)
def reset_position_semantics_state(state: AutoTradeState) -> None: def reset_position_semantics_state(state: AutoTradeState) -> None:
state.position_lifecycle_stage = None state.position_lifecycle_stage = None
@@ -297,7 +284,7 @@ def reset_position_protection_state(state: AutoTradeState) -> None:
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Autonomous Management # Autonomous Runtime
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def reset_autonomous_runtime_state(state: AutoTradeState) -> None: def reset_autonomous_runtime_state(state: AutoTradeState) -> None:
@@ -314,7 +301,7 @@ def reset_autonomous_runtime_state(state: AutoTradeState) -> None:
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Loss Cooldown # Loss Cooldown / Cycle / Flip / Last Execution
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def reset_loss_cooldown_state(state: AutoTradeState) -> None: def reset_loss_cooldown_state(state: AutoTradeState) -> None:
@@ -323,9 +310,15 @@ def reset_loss_cooldown_state(state: AutoTradeState) -> None:
state.loss_cooldown_reason = None state.loss_cooldown_reason = None
# ----------------------------------------------------------------------------- def reset_cycle_statistics_state(state: AutoTradeState) -> None:
# Flip Runtime state.cycle_realized_pnl_usd = 0.0
# ----------------------------------------------------------------------------- state.cycle_closed_trades = 0
state.cycle_winning_trades = 0
state.cycle_losing_trades = 0
state.cycle_consecutive_losses = 0
state.cycle_trade_fees_usd = 0.0
state.cycle_overnight_fees_usd = 0.0
def reset_flip_runtime_state(state: AutoTradeState) -> None: def reset_flip_runtime_state(state: AutoTradeState) -> None:
state.last_flip_old_side = None state.last_flip_old_side = None
@@ -337,29 +330,11 @@ def reset_flip_runtime_state(state: AutoTradeState) -> None:
state.last_flip_block_reason = None state.last_flip_block_reason = None
# -----------------------------------------------------------------------------
# Last Execution Runtime
# -----------------------------------------------------------------------------
def reset_last_execution_state(state: AutoTradeState) -> None: def reset_last_execution_state(state: AutoTradeState) -> None:
state.last_execution_action = None state.last_execution_action = None
state.last_execution_reason = None state.last_execution_reason = None
# -----------------------------------------------------------------------------
# Cycle Statistics
# -----------------------------------------------------------------------------
def reset_cycle_statistics_state(state: AutoTradeState) -> None:
state.cycle_realized_pnl_usd = 0.0
state.cycle_closed_trades = 0
state.cycle_winning_trades = 0
state.cycle_losing_trades = 0
state.cycle_consecutive_losses = 0
state.cycle_trade_fees_usd = 0.0
state.cycle_overnight_fees_usd = 0.0
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Full Runtime Reset # Full Runtime Reset
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -380,7 +355,6 @@ def reset_full_runtime_state(state: AutoTradeState) -> None:
reset_last_execution_state(state) reset_last_execution_state(state)
# Alias на случай старого имени.
def reset_runtime_state(state: AutoTradeState) -> None: def reset_runtime_state(state: AutoTradeState) -> None:
reset_full_runtime_state(state) reset_full_runtime_state(state)