refactor(auto): add runtime state reset helpers

This commit is contained in:
2026-07-02 21:18:58 +03:00
parent 2785f83260
commit af276b1ce4
2 changed files with 477 additions and 223 deletions

View File

@@ -11,6 +11,19 @@ from src.core.event_bus import EventBus
from src.core.numbers import safe_float
from src.core.types import NumericLike
from src.trading.auto.state import AutoTradeState
from src.trading.auto.state_reset import (
reset_adaptive_size_state,
reset_autonomous_runtime_state,
reset_cycle_statistics_state,
reset_execution_runtime_state,
reset_flip_runtime_state,
reset_loss_cooldown_state,
reset_market_analysis_state,
reset_position_protection_state,
reset_position_semantics_state,
reset_runtime_expiration_state,
reset_signal_runtime_state,
)
from src.trading.execution.engine import ExecutionEngine
from src.trading.strategies.base import BaseStrategy, StrategyContext
from src.trading.strategies.registry import StrategyRegistry
@@ -141,9 +154,8 @@ class AutoLifecycleMixin(
state.status = "RUNNING"
# При ручном запуске из OBSERVING очищаем старую cooldown-блокировку,
# чтобы запуск не наследовал паузу прошлого цикла.
state.loss_cooldown_active = False
state.loss_cooldown_reason = None
state.last_loss_monotonic_at = None
reset_loss_cooldown_state(state)
state.execution_block_title = None
state.execution_block_message = None
state.execution_block_action = None
@@ -168,21 +180,16 @@ class AutoLifecycleMixin(
state.status = "RUNNING"
self._reset_signal_tracking()
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.loss_cooldown_active = False
state.loss_cooldown_reason = None
state.last_loss_monotonic_at = None
state.execution_block_title = None
state.execution_block_message = None
state.execution_block_action = None
state.cycle_trade_fees_usd = 0.0
state.cycle_overnight_fees_usd = 0.0
reset_cycle_statistics_state(state)
reset_loss_cooldown_state(state)
reset_flip_runtime_state(state)
state.cycle_started_at = time.monotonic()
state.cycle_number = int(getattr(state, "cycle_number", 0) or 0) + 1
state.last_signal = "HOLD"
state.signal_started_at = time.monotonic()
state.cycle_number = int(getattr(state, "cycle_number", 0) or 0) + 1
state.last_flip_old_side = None
state.last_flip_new_side = None
@@ -227,30 +234,13 @@ class AutoLifecycleMixin(
)
if previous_status == "OFF":
state.cycle_realized_pnl_usd = 0.0
state.cycle_closed_trades = 0
state.cycle_losing_trades = 0
state.cycle_consecutive_losses = 0
state.loss_cooldown_active = False
state.loss_cooldown_reason = None
state.last_loss_monotonic_at = None
state.cycle_winning_trades = 0
state.cycle_trade_fees_usd = 0.0
state.cycle_overnight_fees_usd = 0.0
reset_cycle_statistics_state(state)
reset_loss_cooldown_state(state)
reset_flip_runtime_state(state)
reset_execution_runtime_state(state)
reset_position_semantics_state(state)
state.cycle_started_at = time.monotonic()
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.position_stall_state = None
state.position_stall_reason = None
state.position_mfe_percent = None
state.position_mae_percent = None
state.execution_block_title = None
state.execution_block_message = None
state.execution_block_action = None
state.execution_block_reason = None
self._log_auto_status_changed(
previous_status=previous_status,
@@ -279,31 +269,14 @@ class AutoLifecycleMixin(
return state, "Автоторговля уже выключена."
state.status = "OFF"
state.cycle_realized_pnl_usd = 0.0
state.cycle_closed_trades = 0
state.cycle_losing_trades = 0
state.cycle_consecutive_losses = 0
state.loss_cooldown_active = False
state.loss_cooldown_reason = None
state.last_loss_monotonic_at = None
state.execution_block_title = None
state.execution_block_message = None
state.execution_block_action = None
state.execution_block_reason = None
state.cycle_winning_trades = 0
state.cycle_trade_fees_usd = 0.0
state.cycle_overnight_fees_usd = 0.0
reset_cycle_statistics_state(state)
reset_loss_cooldown_state(state)
reset_execution_runtime_state(state)
reset_adaptive_size_state(state)
reset_flip_runtime_state(state)
reset_position_semantics_state(state)
state.cycle_started_at = None
state.adaptive_size_changed_at = None
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.position_stall_state = None
state.position_stall_reason = None
state.position_mfe_percent = None
state.position_mae_percent = None
self.stop_loop()
EventBus.emit(
@@ -390,116 +363,21 @@ class AutoLifecycleMixin(
state = self.get_state()
state.adaptive_size_base = None
state.adaptive_size_final = None
state.adaptive_size_multiplier = None
state.adaptive_size_reason = None
state.adaptive_size_factors = None
state.effective_risk_percent = None
state.effective_target_risk_usd = None
state.execution_size_adjustment_reason = None
reset_adaptive_size_state(state)
reset_signal_runtime_state(state)
reset_execution_runtime_state(state)
reset_market_analysis_state(state)
reset_runtime_expiration_state(state)
reset_position_semantics_state(state)
reset_position_protection_state(state)
reset_autonomous_runtime_state(state)
reset_loss_cooldown_state(state)
state.last_signal = "HOLD"
state.last_signal_repeat_count = 0
state.last_signal_confidence = 0.0
state.last_signal_reason = None
state.decision_status = "WAITING"
state.decision_reason = None
state.is_signal_confirmed = False
state.is_signal_ready = False
state.signal_confirmation_seconds = 0
state.signal_confirmation_required_seconds = self._confirm_min_duration_seconds
state.signal_confirmation_missing_repeats = self._confirm_repeats
state.signal_confirmation_progress = 0.0
state.signal_confirmation_reason = None
state.signal_started_at = None
state.signal_updated_at = None
state.execution_block_reason = None
state.execution_semantic_status = None
state.execution_semantic_message = None
state.execution_semantic_reason = None
state.execution_quality = None
state.execution_quality_reason = None
state.execution_quality_message = None
state.execution_price_source = None
state.execution_price_age_seconds = None
state.execution_bid_price = None
state.execution_ask_price = None
state.execution_last_price = None
state.execution_price_freshness = None
state.execution_confidence_score = None
state.execution_confidence_level = None
state.execution_confidence_required_score = self._execution_confidence_required_score
state.execution_confidence_reason = None
state.execution_confidence_factors = None
state.market_state = None
state.market_trend = None
state.market_volatility = None
state.market_analysis_interval = None
state.market_analysis_reason = None
state.market_analysis_updated_at = None
state.market_runtime_degraded = False
state.market_trend_strength = None
state.market_trend_quality = None
state.market_phase = None
state.market_phase_direction = None
state.market_structure = None
state.market_structure_reason = None
state.market_score = None
state.market_score_label = None
state.market_long_score = None
state.market_short_score = None
state.last_closed_candle_change_percent = None
state.last_closed_candle_direction = None
state.current_interval_change_percent = None
state.current_interval_direction = None
state.current_interval_label = None
state.market_trend_gap_percent = None
state.market_trend_consistency = None
state.market_trend_efficiency = None
state.trend_quality_score = None
state.ema_distance_atr_ratio = None
state.ema_distance_state = None
state.entry_timing_state = None
state.entry_timing_reason = None
state.ema_fast_slope_percent = None
state.ema_slow_slope_percent = None
state.candle_noise_score = None
state.price_position_score = None
state.htf_interval = None
state.htf_atr_percent = None
state.htf_atr_percent_baseline = None
state.htf_volatility_ratio = None
state.htf_volatility = None
state.htf_market_state = None
state.htf_trend = None
state.htf_trend_strength = None
state.htf_trend_quality = None
state.htf_market_phase = None
state.htf_alignment = None
state.htf_confirmation_score = None
state.htf_reason = None
state.entry_block_reason = None
state.entry_block_message = None
state.momentum_state = None
state.momentum_direction = None
state.momentum_change_percent = None
state.momentum_strength = None
state.breakout_level = None
state.breakout_distance_percent = None
state.breakout_reason = None
state.runtime_expired_reason = None
state.runtime_expired_message = None
state.snapshot_age_seconds = None
state.spread_percent = None
state.execution_confidence_required_score = (
self._execution_confidence_required_score
)
state.position_pnl_percent = None
state.position_hold_seconds = None
@@ -513,58 +391,6 @@ class AutoLifecycleMixin(
state.position_adverse_momentum = False
state.position_exit_pressure = None
state.position_lifecycle_stage = None
state.position_hold_quality = None
state.position_decay_state = None
state.position_exit_confidence = None
state.position_exit_signal = None
state.position_intelligence_reason = None
state.position_recommended_action = None
state.position_peak_pnl_usd = None
state.position_peak_pnl_percent = None
state.position_mfe_percent = None
state.position_mae_percent = None
state.position_fatigue_score = None
state.position_fatigue_state = None
state.position_giveback_percent = None
state.position_conviction_state = None
state.position_exit_urgency = None
state.position_reversal_risk = None
state.position_stall_state = None
state.position_stall_reason = None
state.position_protection_status = None
state.position_protection_reason = None
state.break_even_armed = False
state.break_even_price = None
state.trailing_stop_active = False
state.trailing_stop_price = None
state.profit_lock_active = False
state.profit_lock_price = None
state.runtime_protection_action = None
state.runtime_protection_reason = None
state.runtime_protection_updated_at = None
state.autonomous_action = None
state.autonomous_action_reason = None
state.autonomous_action_confidence = None
state.autonomous_protection_required = False
state.autonomous_reduce_required = False
state.autonomous_exit_required = False
state.autonomous_last_action = None
state.autonomous_last_action_reason = None
state.autonomous_last_action_at = None
state.last_loss_monotonic_at = None
# Сброс именно runtime-блокировки, чтобы после нового запуска
# не оставалась старая пауза после прошлой убыточной сделки.
state.loss_cooldown_active = False
state.loss_cooldown_reason = None
state.execution_block_title = None
state.execution_block_message = None
state.execution_block_action = None
def _build_strategy_context(self) -> StrategyContext:
state = self.get_state()

View File

@@ -0,0 +1,428 @@
# app/src/trading/auto/state_reset.py
from __future__ import annotations
"""
Centralized runtime reset helpers for AutoTrade.
Helpers для сброса отдельных частей AutoTradeState.
ВАЖНО:
Все функции этого файла отвечают только за очистку runtime-состояния.
Каждая функция отвечает только за одну смысловую область 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 src.trading.auto.state import AutoTradeState
# -----------------------------------------------------------------------------
# Adaptive Position Sizing
# -----------------------------------------------------------------------------
# Runtime-параметры, связанные с динамическим изменением размера позиции.
# Сбрасываются при начале нового цикла или полном сбросе runtime.
# -----------------------------------------------------------------------------
def reset_adaptive_size_state(state: AutoTradeState) -> None:
state.adaptive_size_base = None
state.adaptive_size_final = None
state.adaptive_size_multiplier = None
state.adaptive_size_reason = None
state.adaptive_size_factors = None
state.effective_risk_percent = None
state.effective_target_risk_usd = None
state.execution_size_adjustment_reason = None
state.adaptive_size_changed_at = None
# -----------------------------------------------------------------------------
# Signal Runtime
# -----------------------------------------------------------------------------
# Сбрасывает только runtime сигнала.
# Не затрагивает market context, позицию или protection.
# -----------------------------------------------------------------------------
def reset_signal_runtime_state(state: AutoTradeState) -> None:
state.last_signal = "HOLD"
state.last_signal_repeat_count = 0
state.last_signal_confidence = 0.0
state.last_signal_reason = None
state.signal_started_at = None
state.signal_updated_at = None
state.signal_confirmation_seconds = 0
state.signal_confirmation_missing_repeats = 0
state.signal_confirmation_progress = 0.0
state.signal_confirmation_reason = None
state.decision_status = "WAITING"
state.decision_reason = None
state.is_signal_confirmed = False
state.is_signal_ready = False
# -----------------------------------------------------------------------------
# Execution Runtime
# -----------------------------------------------------------------------------
# Сбрасывает все runtime-данные, связанные с execution layer:
# semantic status, quality, pricing snapshot и confidence.
# -----------------------------------------------------------------------------
def reset_execution_runtime_state(state: AutoTradeState) -> None:
state.execution_block_reason = None
state.execution_block_title = None
state.execution_block_message = None
state.execution_block_action = None
state.execution_semantic_status = None
state.execution_semantic_message = None
state.execution_semantic_reason = None
state.execution_quality = None
state.execution_quality_reason = None
state.execution_quality_message = None
state.execution_price_source = None
state.execution_price_age_seconds = None
state.execution_bid_price = None
state.execution_ask_price = None
state.execution_last_price = None
state.execution_price_freshness = None
state.execution_confidence_score = None
state.execution_confidence_level = None
state.execution_confidence_reason = None
state.execution_confidence_factors = None
state.snapshot_age_seconds = None
state.spread_percent = None
# -----------------------------------------------------------------------------
# Market Analysis Runtime
# -----------------------------------------------------------------------------
# Полностью очищает runtime-анализ рынка.
# Используется при истечении TTL или полном сбросе runtime.
# -----------------------------------------------------------------------------
def reset_market_analysis_state(state: AutoTradeState) -> None:
state.market_state = None
state.market_trend = None
state.market_volatility = None
state.market_trend_strength = None
state.market_trend_quality = None
state.market_phase = None
state.market_phase_direction = None
state.market_score = None
state.market_score_label = None
state.market_long_score = None
state.market_short_score = None
state.last_closed_candle_change_percent = None
state.last_closed_candle_direction = None
state.current_interval_change_percent = None
state.current_interval_direction = None
state.current_interval_label = None
state.market_structure = None
state.market_structure_reason = None
state.market_trend_gap_percent = None
state.market_trend_consistency = None
state.market_trend_efficiency = None
state.trend_quality_score = None
state.ema_distance_atr_ratio = None
state.ema_distance_state = None
state.entry_timing_state = None
state.entry_timing_reason = None
state.ema_fast_slope_percent = None
state.ema_slow_slope_percent = None
state.candle_noise_score = None
state.price_position_score = None
state.htf_interval = None
state.htf_atr_percent = None
state.htf_atr_percent_baseline = None
state.htf_volatility_ratio = None
state.htf_volatility = None
state.htf_market_state = None
state.htf_trend = None
state.htf_trend_strength = None
state.htf_trend_quality = None
state.htf_market_phase = None
state.htf_alignment = None
state.htf_confirmation_score = None
state.htf_reason = None
state.momentum_state = None
state.momentum_direction = None
state.momentum_change_percent = None
state.momentum_strength = None
state.breakout_level = None
state.breakout_distance_percent = None
state.breakout_reason = None
state.market_analysis_interval = None
state.market_analysis_reason = None
state.market_analysis_updated_at = None
state.entry_block_reason = None
state.entry_block_message = None
state.market_runtime_degraded = False
# -----------------------------------------------------------------------------
# Runtime Expiration
# -----------------------------------------------------------------------------
# Причина последнего автоматического сброса runtime.
# -----------------------------------------------------------------------------
def reset_runtime_expiration_state(state: AutoTradeState) -> None:
state.runtime_expired_reason = None
state.runtime_expired_message = None
# -----------------------------------------------------------------------------
# Position Runtime
# -----------------------------------------------------------------------------
def reset_position_runtime_state(state: AutoTradeState) -> None:
state.position_side = "NONE"
state.entry_price = None
state.position_size = None
state.position_opened_monotonic_at = None
state.unrealized_pnl_usd = None
state.position_pnl_percent = None
state.position_hold_seconds = None
state.position_pressure = None
state.position_health_score = None
state.position_health_status = None
state.position_health_reason = None
state.position_risk_level = None
state.position_risk_reason = None
state.position_trend_alignment = None
state.position_adverse_momentum = False
state.position_exit_pressure = None
# -----------------------------------------------------------------------------
# Position Semantics / Intelligence
# -----------------------------------------------------------------------------
def reset_position_semantics_state(state: AutoTradeState) -> None:
state.position_lifecycle_stage = None
state.position_hold_quality = None
state.position_decay_state = None
state.position_exit_confidence = None
state.position_exit_signal = None
state.position_intelligence_reason = None
state.position_recommended_action = None
state.position_peak_pnl_usd = None
state.position_peak_pnl_percent = None
state.position_mfe_percent = None
state.position_mae_percent = None
state.position_fatigue_score = None
state.position_fatigue_state = None
state.position_giveback_percent = None
state.position_conviction_state = None
state.position_exit_urgency = None
state.position_reversal_risk = None
state.position_stall_state = None
state.position_stall_reason = None
# -----------------------------------------------------------------------------
# Protection Runtime
# -----------------------------------------------------------------------------
def reset_position_protection_state(state: AutoTradeState) -> None:
state.position_protection_status = None
state.position_protection_reason = None
state.break_even_armed = False
state.break_even_price = None
state.trailing_stop_active = False
state.trailing_stop_price = None
state.profit_lock_active = False
state.profit_lock_price = None
state.runtime_protection_action = None
state.runtime_protection_reason = None
state.runtime_protection_updated_at = None
# -----------------------------------------------------------------------------
# Autonomous Management
# -----------------------------------------------------------------------------
def reset_autonomous_runtime_state(state: AutoTradeState) -> None:
state.autonomous_action = None
state.autonomous_action_reason = None
state.autonomous_action_confidence = None
state.autonomous_protection_required = False
state.autonomous_reduce_required = False
state.autonomous_exit_required = False
state.autonomous_last_action = None
state.autonomous_last_action_reason = None
state.autonomous_last_action_at = None
# -----------------------------------------------------------------------------
# Loss Cooldown
# -----------------------------------------------------------------------------
def reset_loss_cooldown_state(state: AutoTradeState) -> None:
state.last_loss_monotonic_at = None
state.loss_cooldown_active = False
state.loss_cooldown_reason = None
# -----------------------------------------------------------------------------
# Flip Runtime
# -----------------------------------------------------------------------------
def reset_flip_runtime_state(state: AutoTradeState) -> None:
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_flip_at = None
state.last_flip_block_reason = None
# -----------------------------------------------------------------------------
# Last Execution Runtime
# -----------------------------------------------------------------------------
def reset_last_execution_state(state: AutoTradeState) -> None:
state.last_execution_action = 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
# -----------------------------------------------------------------------------
def reset_full_runtime_state(state: AutoTradeState) -> None:
reset_cycle_statistics_state(state)
reset_adaptive_size_state(state)
reset_signal_runtime_state(state)
reset_execution_runtime_state(state)
reset_market_analysis_state(state)
reset_runtime_expiration_state(state)
reset_position_runtime_state(state)
reset_position_semantics_state(state)
reset_position_protection_state(state)
reset_autonomous_runtime_state(state)
reset_loss_cooldown_state(state)
reset_flip_runtime_state(state)
reset_last_execution_state(state)
# Alias на случай старого имени.
def reset_runtime_state(state: AutoTradeState) -> None:
reset_full_runtime_state(state)
# -----------------------------------------------------------------------------
# Lifecycle Scenario Resets
# -----------------------------------------------------------------------------
def reset_after_auto_start(state: AutoTradeState) -> None:
reset_cycle_statistics_state(state)
reset_loss_cooldown_state(state)
reset_adaptive_size_state(state)
reset_signal_runtime_state(state)
reset_execution_runtime_state(state)
reset_runtime_expiration_state(state)
reset_flip_runtime_state(state)
def reset_after_auto_stop(state: AutoTradeState) -> None:
reset_full_runtime_state(state)
def reset_after_symbol_or_strategy_change(state: AutoTradeState) -> None:
reset_adaptive_size_state(state)
reset_signal_runtime_state(state)
reset_execution_runtime_state(state)
reset_market_analysis_state(state)
reset_runtime_expiration_state(state)
def reset_after_position_closed(state: AutoTradeState) -> None:
reset_position_runtime_state(state)
reset_position_semantics_state(state)
reset_position_protection_state(state)
reset_autonomous_runtime_state(state)
reset_flip_runtime_state(state)
def reset_after_market_runtime_expired(state: AutoTradeState) -> None:
reset_market_analysis_state(state)
def reset_after_signal_runtime_expired(state: AutoTradeState) -> None:
reset_signal_runtime_state(state)
reset_execution_runtime_state(state)