Stage 07.4.3 — trend strategy, signal aggregation and journal UX improvements
This commit is contained in:
@@ -4,13 +4,14 @@ from __future__ import annotations
|
||||
|
||||
from src.trading.strategies.base import BaseStrategy
|
||||
from src.trading.strategies.hold import HoldStrategy
|
||||
from src.trading.strategies.trend import TrendStrategy
|
||||
|
||||
|
||||
class StrategyRegistry:
|
||||
# доступные стратегии
|
||||
_strategies: dict[str, BaseStrategy] = {
|
||||
"HOLD": HoldStrategy(),
|
||||
"TREND": HoldStrategy(),
|
||||
"TREND": TrendStrategy(),
|
||||
"GRID": HoldStrategy(),
|
||||
"SCALP": HoldStrategy(),
|
||||
}
|
||||
|
||||
91
app/src/trading/strategies/trend.py
Normal file
91
app/src/trading/strategies/trend.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# app/src/trading/strategies/trend.py
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from src.integrations.exchange.service import ExchangeService
|
||||
from src.trading.strategies.base import StrategyContext
|
||||
from src.trading.strategies.signals import SignalResult, SignalType
|
||||
|
||||
|
||||
class TrendStrategy:
|
||||
name = "TREND"
|
||||
|
||||
_last_prices: dict[str, float] = {}
|
||||
_threshold_percent = 0.02
|
||||
|
||||
# анализ простого тренда по изменению цены
|
||||
def analyze(self, context: StrategyContext) -> SignalResult:
|
||||
try:
|
||||
ticker = ExchangeService().get_price(context.symbol)
|
||||
except Exception as exc:
|
||||
return SignalResult(
|
||||
signal=SignalType.HOLD,
|
||||
reason="Не удалось получить рыночную цену. Безопасный HOLD.",
|
||||
confidence=0.0,
|
||||
payload={
|
||||
"strategy": self.name,
|
||||
"symbol": context.symbol,
|
||||
"error": str(exc),
|
||||
},
|
||||
)
|
||||
|
||||
symbol = ticker.symbol
|
||||
current_price = ticker.price
|
||||
previous_price = self._last_prices.get(symbol)
|
||||
|
||||
self._last_prices[symbol] = current_price
|
||||
|
||||
if previous_price is None or previous_price <= 0:
|
||||
return SignalResult(
|
||||
signal=SignalType.HOLD,
|
||||
reason="Недостаточно данных для определения тренда.",
|
||||
confidence=0.0,
|
||||
payload={
|
||||
"strategy": self.name,
|
||||
"symbol": symbol,
|
||||
"price": current_price,
|
||||
},
|
||||
)
|
||||
|
||||
change_percent = ((current_price - previous_price) / previous_price) * 100
|
||||
|
||||
if change_percent >= self._threshold_percent:
|
||||
return SignalResult(
|
||||
signal=SignalType.BUY,
|
||||
reason="Цена растёт выше порога тренда.",
|
||||
confidence=min(1.0, abs(change_percent) / self._threshold_percent),
|
||||
payload={
|
||||
"strategy": self.name,
|
||||
"symbol": symbol,
|
||||
"previous_price": previous_price,
|
||||
"current_price": current_price,
|
||||
"change_percent": round(change_percent, 5),
|
||||
},
|
||||
)
|
||||
|
||||
if change_percent <= -self._threshold_percent:
|
||||
return SignalResult(
|
||||
signal=SignalType.SELL,
|
||||
reason="Цена падает ниже порога тренда.",
|
||||
confidence=min(1.0, abs(change_percent) / self._threshold_percent),
|
||||
payload={
|
||||
"strategy": self.name,
|
||||
"symbol": symbol,
|
||||
"previous_price": previous_price,
|
||||
"current_price": current_price,
|
||||
"change_percent": round(change_percent, 5),
|
||||
},
|
||||
)
|
||||
|
||||
return SignalResult(
|
||||
signal=SignalType.HOLD,
|
||||
reason="Изменение цены ниже порога тренда.",
|
||||
confidence=0.0,
|
||||
payload={
|
||||
"strategy": self.name,
|
||||
"symbol": symbol,
|
||||
"previous_price": previous_price,
|
||||
"current_price": current_price,
|
||||
"change_percent": round(change_percent, 5),
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user