feat: math core v3 engine upgrade

This commit is contained in:
Celes Renata
2026-06-27 12:21:41 +00:00
parent 365bc5d4b7
commit b4bf0f2361
34 changed files with 11693 additions and 3 deletions
+97
View File
@@ -5,12 +5,15 @@ re-evaluates levels when volatility or market conditions change, detects
price crossings that should trigger exits, and tightens stops under
high-heat or high-severity-event conditions.
Also provides v3 regime-aware stop loss and take profit (Requirements 16.116.5).
All public methods are synchronous (pure computation, no DB access).
Persistence is handled by the caller (engine.py).
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime, timezone
from services.trading.models import (
@@ -20,6 +23,100 @@ from services.trading.models import (
StopTrigger,
)
# ---------------------------------------------------------------------------
# v3 Regime-Aware Stop Loss and Take Profit (Requirements 16.116.5)
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class V3StopLevels:
"""v3 stop-loss and take-profit levels computed from regime-aware volatility."""
stop_loss: float
take_profit: float
stop_distance_pct: float
reward_ratio: float
@dataclass(frozen=True)
class TrailingStopResult:
"""Result of trailing stop computation."""
trailing_stop: float
activated: bool
def compute_v3_stops(
entry_price: float,
atr_pct: float,
regime_atr_mult: float,
sigma_h: float,
reward_ratio: float,
) -> V3StopLevels:
"""Compute regime-aware stop loss and take profit.
stop_distance_pct = max(ATR_pct × regime_ATR_mult, sigma_h × 1.25, 0.005)
stop_loss = entry_price × (1 - stop_distance_pct)
take_profit = entry_price × (1 + b × stop_distance_pct)
Requirements: 16.1, 16.2, 16.3
"""
# Requirement 16.1: stop distance from regime-aware volatility
z_stop = 1.25
min_stop_pct = 0.005
stop_distance_pct = max(atr_pct * regime_atr_mult, sigma_h * z_stop, min_stop_pct)
# Requirement 16.2: stop loss for long position
stop_loss = entry_price * (1.0 - stop_distance_pct)
# Requirement 16.3: take profit using dynamic reward ratio
take_profit = entry_price * (1.0 + reward_ratio * stop_distance_pct)
return V3StopLevels(
stop_loss=stop_loss,
take_profit=take_profit,
stop_distance_pct=stop_distance_pct,
reward_ratio=reward_ratio,
)
def compute_trailing_stop(
existing_stop: float,
current_price: float,
entry_price: float,
take_profit: float,
atr_pct: float,
trailing_atr_mult: float,
sigma_h: float,
) -> TrailingStopResult:
"""Compute trailing stop level.
Activated when unrealized_gain >= 0.50 × TP distance.
trailing_stop = max(existing_stop, current_price × (1 - trailing_distance_pct))
trailing_distance_pct = max(ATR_pct × trailing_ATR_mult, sigma_h × 0.75)
Trailing stop is monotonically non-decreasing.
Requirements: 16.4, 16.5
"""
# Requirement 16.4: activation check
take_profit_distance = take_profit - entry_price
unrealized_gain = current_price - entry_price
# Activation threshold: gain >= 50% of TP distance
if take_profit_distance <= 0 or unrealized_gain < 0.50 * take_profit_distance:
# Not activated — return existing stop unchanged
return TrailingStopResult(trailing_stop=existing_stop, activated=False)
# Requirement 16.5: compute trailing stop
trailing_distance_pct = max(atr_pct * trailing_atr_mult, sigma_h * 0.75)
candidate_stop = current_price * (1.0 - trailing_distance_pct)
# Monotonically non-decreasing: never lower than existing stop
trailing_stop = max(existing_stop, candidate_stop)
return TrailingStopResult(trailing_stop=trailing_stop, activated=True)
class StopLossManager:
"""Compute and maintain dynamic stop-loss / take-profit levels."""