build 050: switch MarketAnalysisService to canonical candles

This commit is contained in:
2026-07-15 22:54:40 +03:00
parent 16ed64f7c6
commit c8d33f8baa
3 changed files with 879 additions and 10 deletions

View File

@@ -3,6 +3,7 @@
from __future__ import annotations
from enum import StrEnum
from math import isfinite
from src.core.numbers import safe_float
from src.integrations.exchange.service import ExchangeService
@@ -240,7 +241,7 @@ class MarketAnalysisService:
limit: int = 200,
) -> MarketAnalysisResult:
try:
batch = ExchangeService().get_klines(
candles = ExchangeService().get_candles(
symbol=symbol,
interval=interval,
limit=limit,
@@ -253,18 +254,38 @@ class MarketAnalysisService:
htf_interval=self._htf_interval,
)
candles = batch.candles
closes = [item.close_price for item in candles]
analysis_symbol = candles[0].symbol if candles else symbol
if len(candles) < self._min_candles:
return build_unknown_market_analysis_result(
symbol=batch.symbol,
symbol=analysis_symbol,
interval=interval,
reason="Недостаточно свечей для анализа рынка.",
candles_count=len(candles),
htf_interval=self._htf_interval,
)
closes: list[float] = []
for candle in candles:
close_price_value = safe_float(candle.close_price)
if (
close_price_value is None
or not isfinite(close_price_value)
):
return build_unknown_market_analysis_result(
symbol=analysis_symbol,
interval=interval,
reason=(
"Получены некорректные цены закрытия свечей."
),
candles_count=len(candles),
htf_interval=self._htf_interval,
)
closes.append(close_price_value)
close_price = closes[-1] if closes else None
ema_fast = ema(closes, self._fast_ema_period)
ema_slow = ema(closes, self._slow_ema_period)
@@ -279,7 +300,7 @@ class MarketAnalysisService:
or atr_value is None
):
return build_unknown_market_analysis_result(
symbol=batch.symbol,
symbol=analysis_symbol,
interval=interval,
reason="Недостаточно данных для расчёта EMA / ATR.",
candles_count=len(candles),
@@ -303,7 +324,7 @@ class MarketAnalysisService:
htf_context = build_htf_volatility_context(
self,
symbol=batch.symbol,
symbol=analysis_symbol,
base_interval=interval,
)
@@ -483,7 +504,7 @@ class MarketAnalysisService:
phase_window=self._phase_window,
)
# Текущая свеча — последняя свеча из batch.
# Текущая свеча — последняя свеча из canonical candles.
# Обычно это ещё формирующаяся свеча текущего 5m-интервала.
current_interval_change_percent = self._candle_change_percent(
candles,
@@ -563,7 +584,7 @@ class MarketAnalysisService:
htf_trend_context = build_htf_trend_context(
self,
symbol=batch.symbol,
symbol=analysis_symbol,
base_interval=interval,
local_state=state,
local_trend=trend,
@@ -681,7 +702,7 @@ class MarketAnalysisService:
)
payload = build_market_analysis_payload(
symbol=batch.symbol,
symbol=analysis_symbol,
interval=interval,
state=state,
trend=trend,
@@ -744,7 +765,7 @@ class MarketAnalysisService:
)
return build_market_analysis_result(
symbol=batch.symbol,
symbol=analysis_symbol,
interval=interval,
state=state,
trend=trend,