07.4.4.1.6 — Signal Aging & Runtime Expiration
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
|
||||
from src.integrations.exchange.service import ExchangeService
|
||||
from src.trading.strategies.base import StrategyContext
|
||||
from src.trading.strategies.signals import SignalResult, SignalType
|
||||
@@ -11,6 +13,8 @@ class ScalpStrategy:
|
||||
name = "SCALP"
|
||||
|
||||
_price_window: dict[str, list[float]] = {}
|
||||
_window_ttl_seconds = 30
|
||||
_price_window_updated_at: dict[str, float] = {}
|
||||
|
||||
# короткое окно = быстрая реакция
|
||||
_window_size = 4
|
||||
@@ -24,6 +28,7 @@ class ScalpStrategy:
|
||||
def reset_runtime(self, symbol: str | None = None) -> None:
|
||||
if symbol is None:
|
||||
self._price_window.clear()
|
||||
self._price_window_updated_at.clear()
|
||||
return
|
||||
|
||||
normalized_symbol = symbol.upper()
|
||||
@@ -34,6 +39,7 @@ class ScalpStrategy:
|
||||
|
||||
for key in keys_to_delete:
|
||||
self._price_window.pop(key, None)
|
||||
self._price_window_updated_at.pop(key, None)
|
||||
|
||||
def analyze(self, context: StrategyContext) -> SignalResult:
|
||||
try:
|
||||
@@ -53,8 +59,18 @@ class ScalpStrategy:
|
||||
symbol = ticker.symbol
|
||||
current_price = float(ticker.price)
|
||||
|
||||
now = time.monotonic()
|
||||
previous_updated_at = self._price_window_updated_at.get(symbol)
|
||||
|
||||
if (
|
||||
previous_updated_at is not None
|
||||
and now - previous_updated_at > self._window_ttl_seconds
|
||||
):
|
||||
self._price_window.pop(symbol, None)
|
||||
|
||||
prices = self._price_window.setdefault(symbol, [])
|
||||
prices.append(current_price)
|
||||
self._price_window_updated_at[symbol] = now
|
||||
|
||||
if len(prices) > self._window_size:
|
||||
prices.pop(0)
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
|
||||
from src.integrations.exchange.service import ExchangeService
|
||||
from src.trading.market_analysis.models import MarketState
|
||||
from src.trading.market_analysis.service import MarketAnalysisService
|
||||
@@ -13,6 +15,8 @@ class TrendStrategy:
|
||||
name = "TREND"
|
||||
|
||||
_price_window: dict[str, list[float]] = {}
|
||||
_window_ttl_seconds = 60
|
||||
_price_window_updated_at: dict[str, float] = {}
|
||||
|
||||
# короткое окно оставляем как дополнительное подтверждение импульса
|
||||
_window_size = 8
|
||||
@@ -25,6 +29,7 @@ class TrendStrategy:
|
||||
def reset_runtime(self, symbol: str | None = None) -> None:
|
||||
if symbol is None:
|
||||
self._price_window.clear()
|
||||
self._price_window_updated_at.clear()
|
||||
return
|
||||
|
||||
normalized_symbol = symbol.upper()
|
||||
@@ -35,6 +40,7 @@ class TrendStrategy:
|
||||
|
||||
for key in keys_to_delete:
|
||||
self._price_window.pop(key, None)
|
||||
self._price_window_updated_at.pop(key, None)
|
||||
|
||||
def analyze(self, context: StrategyContext) -> SignalResult:
|
||||
market = MarketAnalysisService().analyze(
|
||||
@@ -77,8 +83,18 @@ class TrendStrategy:
|
||||
},
|
||||
)
|
||||
|
||||
now = time.monotonic()
|
||||
previous_updated_at = self._price_window_updated_at.get(symbol)
|
||||
|
||||
if (
|
||||
previous_updated_at is not None
|
||||
and now - previous_updated_at > self._window_ttl_seconds
|
||||
):
|
||||
self._price_window.pop(symbol, None)
|
||||
|
||||
prices = self._price_window.setdefault(symbol, [])
|
||||
prices.append(current_price)
|
||||
self._price_window_updated_at[symbol] = now
|
||||
|
||||
if len(prices) > self._window_size:
|
||||
prices.pop(0)
|
||||
@@ -96,6 +112,8 @@ class TrendStrategy:
|
||||
"market_analysis_interval": market.interval,
|
||||
"market_analysis_reason": market.reason,
|
||||
"market_analysis": market.payload,
|
||||
"runtime_window_ttl_seconds": self._window_ttl_seconds,
|
||||
"runtime_window_size": len(prices),
|
||||
}
|
||||
|
||||
if not market.is_trade_allowed:
|
||||
|
||||
Reference in New Issue
Block a user