07.4.4.1.7 — Live Market Runtime & Advanced Trend Diagnostics

This commit is contained in:
2026-05-11 15:20:41 +03:00
parent fe33e0c026
commit ec9904f91d
7 changed files with 591 additions and 18 deletions

View File

@@ -126,12 +126,12 @@ async def auto_start(callback: CallbackQuery) -> None:
_, message = service.start() _, message = service.start()
AutoTradeRunner.start()
if callback.message is not None: if callback.message is not None:
await _prepare_auto_from_callback(callback) await _prepare_auto_from_callback(callback)
await render_auto_screen(callback.message, edit_mode=True) await render_auto_screen(callback.message, edit_mode=True)
AutoTradeRunner.start()
await callback.answer(message) await callback.answer(message)
@@ -153,12 +153,12 @@ async def auto_observe(callback: CallbackQuery) -> None:
_, message = service.observe() _, message = service.observe()
AutoTradeRunner.start()
if callback.message is not None: if callback.message is not None:
await _prepare_auto_from_callback(callback) await _prepare_auto_from_callback(callback)
await render_auto_screen(callback.message, edit_mode=True) await render_auto_screen(callback.message, edit_mode=True)
AutoTradeRunner.start()
await callback.answer(message) await callback.answer(message)

View File

@@ -179,16 +179,46 @@ class AutoTradeRunner:
MarketDataRunner.stop("auto") MarketDataRunner.stop("auto")
break break
service.run_cycle() try:
service.run_cycle()
except Exception as exc:
cls._log_refresh_error(
"auto_run_cycle_error",
{
"error": str(exc),
"error_type": type(exc).__name__,
"symbol": state.symbol,
"strategy": state.strategy,
"status": state.status,
},
)
current_event_version = EventBus.version() current_event_version = EventBus.version()
has_important_event = current_event_version != cls._last_event_version has_important_event = current_event_version != cls._last_event_version
if has_important_event: if has_important_event:
cls._last_event_version = current_event_version cls._last_event_version = current_event_version
await cls._handle_important_event(state) try:
await cls._handle_important_event(state)
except Exception as exc:
cls._log_refresh_error(
"auto_event_handler_error",
{
"error": str(exc),
"error_type": type(exc).__name__,
},
)
await cls._refresh_screen(force=has_important_event) try:
await cls._refresh_screen(force=has_important_event)
except Exception as exc:
cls._log_refresh_error(
"auto_refresh_loop_error",
{
"error": str(exc),
"error_type": type(exc).__name__,
},
)
await asyncio.sleep(cls._analysis_interval_seconds) await asyncio.sleep(cls._analysis_interval_seconds)

View File

@@ -53,6 +53,8 @@ class ScalpStrategy:
"strategy": self.name, "strategy": self.name,
"symbol": context.symbol, "symbol": context.symbol,
"error": str(exc), "error": str(exc),
"entry_block_reason": "MARKET_PRICE_ERROR",
"entry_block_message": "нет данных рынка",
}, },
) )
@@ -75,17 +77,25 @@ class ScalpStrategy:
if len(prices) > self._window_size: if len(prices) > self._window_size:
prices.pop(0) prices.pop(0)
base_payload = {
"strategy": self.name,
"symbol": symbol,
"price": current_price,
"runtime_window_ttl_seconds": self._window_ttl_seconds,
"runtime_window_size": len(prices),
}
if len(prices) < self._window_size: if len(prices) < self._window_size:
return SignalResult( return SignalResult(
signal=SignalType.HOLD, signal=SignalType.HOLD,
reason="Недостаточно данных для SCALP.", reason="Недостаточно данных для SCALP.",
confidence=0.0, confidence=0.0,
payload={ payload={
"strategy": self.name, **base_payload,
"symbol": symbol,
"price": current_price,
"window_size": len(prices), "window_size": len(prices),
"required_window_size": self._window_size, "required_window_size": self._window_size,
"entry_block_reason": "NOT_ENOUGH_LIVE_DATA",
"entry_block_message": "мало данных",
}, },
) )
@@ -98,9 +108,10 @@ class ScalpStrategy:
reason="Некорректная стартовая цена в окне SCALP.", reason="Некорректная стартовая цена в окне SCALP.",
confidence=0.0, confidence=0.0,
payload={ payload={
"strategy": self.name, **base_payload,
"symbol": symbol,
"prices": prices, "prices": prices,
"entry_block_reason": "INVALID_WINDOW_PRICE",
"entry_block_message": "ошибка цены",
}, },
) )
@@ -108,8 +119,7 @@ class ScalpStrategy:
direction_ratio = self._direction_ratio(prices, change_percent) direction_ratio = self._direction_ratio(prices, change_percent)
payload = { payload = {
"strategy": self.name, **base_payload,
"symbol": symbol,
"first_price": first_price, "first_price": first_price,
"current_price": last_price, "current_price": last_price,
"change_percent": round(change_percent, 5), "change_percent": round(change_percent, 5),
@@ -141,11 +151,23 @@ class ScalpStrategy:
payload=payload, payload=payload,
) )
expected_direction = "BUY" if change_percent >= 0 else "SELL"
entry_block_reason = (
"WEAK_UP_IMPULSE"
if expected_direction == "BUY"
else "WEAK_DOWN_IMPULSE"
)
return SignalResult( return SignalResult(
signal=SignalType.HOLD, signal=SignalType.HOLD,
reason="SCALP-импульс недостаточно сильный.", reason="SCALP-импульс недостаточно сильный.",
confidence=0.0, confidence=0.0,
payload=payload, payload={
**payload,
"entry_block_reason": entry_block_reason,
"entry_block_message": "слабый импульс",
"expected_direction": expected_direction,
},
) )
def _direction_ratio(self, prices: list[float], change_percent: float) -> float: def _direction_ratio(self, prices: list[float], change_percent: float) -> float:

View File

@@ -64,6 +64,8 @@ class TrendStrategy:
"symbol": context.symbol, "symbol": context.symbol,
"error": str(exc), "error": str(exc),
"market_analysis": market.payload, "market_analysis": market.payload,
"entry_block_reason": "MARKET_SNAPSHOT_ERROR",
"entry_block_message": "нет данных рынка",
}, },
) )
@@ -80,6 +82,8 @@ class TrendStrategy:
"symbol": symbol, "symbol": symbol,
"snapshot": snapshot, "snapshot": snapshot,
"market_analysis": market.payload, "market_analysis": market.payload,
"entry_block_reason": "INVALID_MARKET_PRICE",
"entry_block_message": "нет цены",
}, },
) )
@@ -138,6 +142,8 @@ class TrendStrategy:
**base_payload, **base_payload,
"window_size": len(prices), "window_size": len(prices),
"required_window_size": self._window_size, "required_window_size": self._window_size,
"entry_block_reason": "NOT_ENOUGH_LIVE_DATA",
"entry_block_message": "мало данных",
}, },
) )
@@ -152,6 +158,8 @@ class TrendStrategy:
payload={ payload={
**base_payload, **base_payload,
"prices": prices, "prices": prices,
"entry_block_reason": "INVALID_WINDOW_PRICE",
"entry_block_message": "ошибка цены",
}, },
) )
@@ -185,7 +193,12 @@ class TrendStrategy:
signal=SignalType.HOLD, signal=SignalType.HOLD,
reason="TREND_UP есть, но live-импульс вверх недостаточно сильный.", reason="TREND_UP есть, но live-импульс вверх недостаточно сильный.",
confidence=0.0, confidence=0.0,
payload=payload, payload={
**payload,
"entry_block_reason": "WEAK_UP_IMPULSE",
"entry_block_message": "слабый импульс",
"expected_direction": "BUY",
},
) )
if market.state == MarketState.TREND_DOWN: if market.state == MarketState.TREND_DOWN:
@@ -204,14 +217,23 @@ class TrendStrategy:
signal=SignalType.HOLD, signal=SignalType.HOLD,
reason="TREND_DOWN есть, но live-импульс вниз недостаточно сильный.", reason="TREND_DOWN есть, но live-импульс вниз недостаточно сильный.",
confidence=0.0, confidence=0.0,
payload=payload, payload={
**payload,
"entry_block_reason": "WEAK_DOWN_IMPULSE",
"entry_block_message": "слабый импульс",
"expected_direction": "SELL",
},
) )
return SignalResult( return SignalResult(
signal=SignalType.HOLD, signal=SignalType.HOLD,
reason=f"Market state не подходит для TREND: {market.state.value}.", reason=f"Market state не подходит для TREND: {market.state.value}.",
confidence=0.0, confidence=0.0,
payload=payload, payload={
**payload,
"entry_block_reason": "MARKET_STATE_NOT_TREND",
"entry_block_message": "рынок флэт",
},
) )
def _analysis_price(self, snapshot: dict[str, object]) -> float: def _analysis_price(self, snapshot: dict[str, object]) -> float:

View File

@@ -519,6 +519,62 @@
- подготовлена база для adaptive thresholds - подготовлена база для adaptive thresholds
- подготовлена база для signal freshness-aware execution - подготовлена база для signal freshness-aware execution
#### 07.4.4.1.7 ✅ Live Market Runtime & Advanced Trend Diagnostics
- внедрён полноценный live market runtime pipeline
- добавлен websocket-based realtime market runtime
- добавлен REST fallback для market runtime
- внедрён runtime-aware MarketPriceCache
- cache переведён на isolation по runtime_key
- добавлен market snapshot layer в ExchangeService
- добавлены get_market_snapshot и get_execution_snapshot
- добавлен get_fresh_market_snapshot
- добавлен refresh_market_snapshot_cache
- внедрена модель ExecutionPriceSnapshot
- execution pipeline получил поддержку bid/ask
- execution pipeline получил freshness tracking
- execution pipeline получил source tracking
- MarketDataRunner теперь обновляет runtime cache
- websocket runtime теперь автоматически reconnect'ится
- websocket runtime теперь безопасно fallback'ится в REST
- TrendStrategy переведена на market snapshot analysis
- TrendStrategy теперь использует bid/ask mid-price
- добавлен _analysis_price для execution-aware анализа
- добавлен direction_ratio analysis layer
- добавлен live impulse confirmation layer
- TREND теперь требует подтверждение live momentum
- live impulse теперь анализируется через runtime price windows
- улучшена фильтрация noise movement
- снижено количество ложных BUY/SELL импульсов
- TrendStrategy получила расширенные HOLD diagnostics
- HOLD ветки теперь передают entry_block_reason
- HOLD ветки теперь передают entry_block_message
- Telegram UI теперь отображает причины HOLD
- Telegram UI теперь отображает compact market states
- HOLD runtime теперь визуально подтверждает живой цикл
- HOLD timer сохранён как runtime heartbeat indicator
- AutoTradeRunner получил protected execution loop
- исключения стратегии больше не убивают runtime
- исключения UI refresh больше не убивают runtime
- исключения event handler больше не убивают runtime
- runtime loop теперь логирует auto_run_cycle_error
- runtime loop теперь логирует auto_refresh_loop_error
- защищён asyncio lifecycle автоторговли
- исправлен critical runtime bug с TrendStrategy.analyze
- восстановлен realtime refresh автоторговли
- исправлен freeze Telegram UI
- исправлено зависание market state на “Идёт анализ”
- исправлено зависание HOLD timer
- исправлена race condition между screen register и runner.start
- стабилизирована смена инструмента во время runtime
- подтверждена корректная работа websocket runtime
- подтверждена корректная работа REST fallback
- подготовлена база для spread-aware execution
- подготовлена база для stale snapshot protection
- подготовлена база для adaptive execution engine
- подготовлена база для execution quality metrics
- подготовлена база для advanced market diagnostics
- подготовлена база для multi-timeframe analysis
--- ---
### 07.4.5 ### 07.4.5

View File

@@ -495,6 +495,62 @@
- подготовлена база для adaptive thresholds - подготовлена база для adaptive thresholds
- подготовлена база для signal freshness-aware execution - подготовлена база для signal freshness-aware execution
#### 07.4.4.1.7 ✅ Live Market Runtime & Advanced Trend Diagnostics
- внедрён полноценный live market runtime pipeline
- добавлен websocket-based realtime market runtime
- добавлен REST fallback для market runtime
- внедрён runtime-aware MarketPriceCache
- cache переведён на isolation по runtime_key
- добавлен market snapshot layer в ExchangeService
- добавлены get_market_snapshot и get_execution_snapshot
- добавлен get_fresh_market_snapshot
- добавлен refresh_market_snapshot_cache
- внедрена модель ExecutionPriceSnapshot
- execution pipeline получил поддержку bid/ask
- execution pipeline получил freshness tracking
- execution pipeline получил source tracking
- MarketDataRunner теперь обновляет runtime cache
- websocket runtime теперь автоматически reconnect'ится
- websocket runtime теперь безопасно fallback'ится в REST
- TrendStrategy переведена на market snapshot analysis
- TrendStrategy теперь использует bid/ask mid-price
- добавлен _analysis_price для execution-aware анализа
- добавлен direction_ratio analysis layer
- добавлен live impulse confirmation layer
- TREND теперь требует подтверждение live momentum
- live impulse теперь анализируется через runtime price windows
- улучшена фильтрация noise movement
- снижено количество ложных BUY/SELL импульсов
- TrendStrategy получила расширенные HOLD diagnostics
- HOLD ветки теперь передают entry_block_reason
- HOLD ветки теперь передают entry_block_message
- Telegram UI теперь отображает причины HOLD
- Telegram UI теперь отображает compact market states
- HOLD runtime теперь визуально подтверждает живой цикл
- HOLD timer сохранён как runtime heartbeat indicator
- AutoTradeRunner получил protected execution loop
- исключения стратегии больше не убивают runtime
- исключения UI refresh больше не убивают runtime
- исключения event handler больше не убивают runtime
- runtime loop теперь логирует auto_run_cycle_error
- runtime loop теперь логирует auto_refresh_loop_error
- защищён asyncio lifecycle автоторговли
- исправлен critical runtime bug с TrendStrategy.analyze
- восстановлен realtime refresh автоторговли
- исправлен freeze Telegram UI
- исправлено зависание market state на “Идёт анализ”
- исправлено зависание HOLD timer
- исправлена race condition между screen register и runner.start
- стабилизирована смена инструмента во время runtime
- подтверждена корректная работа websocket runtime
- подтверждена корректная работа REST fallback
- подготовлена база для spread-aware execution
- подготовлена база для stale snapshot protection
- подготовлена база для adaptive execution engine
- подготовлена база для execution quality metrics
- подготовлена база для advanced market diagnostics
- подготовлена база для multi-timeframe analysis
--- ---
### 07.4.5 ### 07.4.5

View File

@@ -0,0 +1,387 @@
# 07.4.4.1.7 — Live Market Runtime & Advanced Trend Diagnostics
## Цель этапа
Перевести автоторговлю с простой polling-модели в полноценный live runtime pipeline с realtime market snapshots, websocket runtime, устойчивым execution loop и прозрачной диагностикой причин HOLD.
Этап решает несколько критичных проблем:
- UI автоторговли визуально “замирал”;
- HOLD мог выглядеть как зависший;
- рынок отображался как “Идёт анализ” слишком долго;
- стратегии использовали только last price;
- runtime loop мог полностью остановиться после исключения стратегии;
- пользователь не видел причин отсутствия входа;
- live execution pipeline не был устойчив к websocket/runtime ошибкам.
---
# Что было до этапа
До внедрения нового runtime pipeline:
- стратегии использовали упрощённый get_price();
- live bid/ask не использовались;
- отсутствовал execution snapshot layer;
- runtime loop мог полностью упасть при exception внутри стратегии;
- websocket runtime не имел безопасного fallback поведения;
- UI не показывал диагностический контекст HOLD;
- market analysis был слабо связан с live market execution;
- Telegram UI не показывал причину отсутствия входа в позицию.
Из-за этого пользователь видел:
text ⏳ Рынок · Идёт анализ
даже когда runtime уже фактически остановился.
---
# Что внедрено
## 1. Live market runtime pipeline
Введён полноценный runtime pipeline:
text Exchange WS ↓ MarketDataRunner ↓ MarketPriceCache ↓ ExchangeService.get_market_snapshot() ↓ Strategy analyze() ↓ AutoTradeService ↓ Telegram UI
Теперь стратегии работают не с одиночной ценой, а с realtime market snapshot.
---
## 2. Market snapshot layer
В ExchangeService добавлены:
python get_market_snapshot() refresh_market_snapshot_cache() get_execution_snapshot() get_fresh_market_snapshot()
Теперь runtime может:
- получать bid/ask;
- понимать freshness snapshot;
- использовать cache/runtime isolation;
- безопасно fallback'иться на REST.
---
## 3. Execution snapshot model
Добавлена модель:
python ExecutionPriceSnapshot
Теперь execution pipeline знает:
- last price;
- bid price;
- ask price;
- freshness;
- возраст snapshot;
- источник snapshot.
Это подготовило основу для:
- execution quality scoring;
- spread analysis;
- slippage protection;
- stale execution protection.
---
## 4. MarketPriceCache runtime isolation
MarketPriceCache переведён на runtime-aware architecture:
python (runtime_key, symbol)
Теперь:
- AUTO runtime;
- DEBUG runtime;
- future paper/live runtimes
не конфликтуют между собой.
---
## 5. Websocket runtime
Внедрён live websocket runtime через:
python MarketDataRunner
Теперь runtime:
- держит live stream;
- обновляет cache;
- следит за runtime lifecycle;
- автоматически reconnect'ится;
- умеет fallback в REST.
---
## 6. REST fallback layer
Добавлен безопасный fallback:
python _rest_fallback_once()
Если websocket отключается:
text WS disconnect ↓ REST snapshot refresh ↓ runtime продолжает жить
Автоторговля больше не “умирает” полностью при потере websocket.
---
## 7. Runtime stability protection
AutoTradeRunner получил защищённый execution loop.
Теперь:
python service.run_cycle()
выполняется внутри protected try/except.
Даже если стратегия падает:
- UI остаётся жив;
- runtime остаётся жив;
- websocket продолжает работать;
- HOLD timer продолжает тикать;
- ошибка уходит в журнал.
---
## 8. Protected UI refresh loop
Защищены:
python _handle_important_event() _refresh_screen()
Теперь единичная ошибка Telegram/UI/runtime:
- не убивает asyncio task;
- не ломает live screen;
- не останавливает автоторговлю.
---
## 9. Runtime startup stabilization
Изменён порядок запуска:
Было:
text runner.start() ↓ screen.register()
Стало:
text screen.register() ↓ runner.start()
Это устранило race condition между:
- запуском runtime;
- регистрацией Telegram screen;
- первым refresh cycle.
---
# Улучшения аналитики
## 10. TrendStrategy переведена на market snapshot analysis
TrendStrategy теперь анализирует:
python bid_price ask_price last_price
а не только одиночный ticker price.
---
## 11. Mid-price analysis
Добавлен:
python _analysis_price()
Теперь стратегия использует:
python (bid + ask) / 2
как основную execution-aware цену анализа.
Это снижает шум:
- spread spikes;
- случайных last trades;
- микродвижений.
---
## 12. Live impulse confirmation
TREND больше не принимает решение только по market analysis.
Теперь требуется:
text market trend + live impulse + direction consistency
---
## 13. Direction ratio analysis
Добавлен:
python _direction_ratio()
Теперь стратегия оценивает:
- сколько движений были вверх;
- сколько вниз;
- насколько импульс последовательный.
Это защищает от:
text хаотического шума
и уменьшает ложные входы.
---
## 14. Runtime price windows
TREND и SCALP получили собственные live price windows.
Теперь анализируется:
python изменение цены во времени
а не только моментальный snapshot.
---
## 15. TREND impulse confirmation
TREND теперь требует:
python change_percent >= threshold direction_ratio >= min_ratio
Только после этого:
python BUY / SELL
становится валидным.
---
## 16. HOLD diagnostics layer
Практически все HOLD-сценарии получили diagnostics payload:
python entry_block_reason entry_block_message
Теперь UI знает:
- почему нет входа;
- почему HOLD продолжается;
- что именно заблокировало execution.
---
## 17. Market state visualization
Telegram UI теперь отображает:
text 📈 Тренд · Вверх 📉 Тренд · Вниз 🟰 Рынок · Флэт ⚠️ Рынок · Высокая волатильность
Вместо “чёрного ящика”.
---
## 18. HOLD explanation layer
Теперь пользователь видит:
text Ожидание · слабый импульс Ожидание · мало данных Ожидание · волатильность
Это резко повысило прозрачность runtime.
---
## 19. Live HOLD timer
HOLD timer сохранён намеренно:
text Сигнал 🟡 HOLD · 2м 05с
Теперь это индикатор:
- живого runtime;
- живого UI refresh;
- активного execution loop;
- актуального market cycle.
---
# Что было исправлено в процессе этапа
Во время интеграции был найден критичный runtime bug:
text TrendStrategy.analyze() оказалась вне класса
Из-за этого:
text AutoTradeRunner._worker() падал полностью
После исправления:
- runtime loop восстановлен;
- UI refresh восстановлен;
- HOLD timer снова realtime;
- market diagnostics снова обновляются.
---
# Проверка этапа
Проверено:
- websocket runtime работает;
- REST fallback работает;
- HOLD timer realtime;
- UI не замирает;
- market state обновляется;
- смена инструмента работает;
- runtime survives exceptions;
- Telegram refresh стабилен;
- snapshot runtime обновляется;
- HOLD diagnostics отображаются корректно.
---
# Что подготовлено для следующих этапов
Подготовлена база для:
text adaptive execution engine spread-aware execution advanced diagnostics market freshness scoring multi-timeframe analysis signal persistence scoring adaptive thresholds execution quality metrics
---
# Итог этапа
Этап 07.4.4.1.7 завершил переход автоторговли к:
text живому realtime market runtime
Теперь система:
- использует live market snapshots;
- имеет websocket runtime;
- имеет REST fallback;
- не умирает при exception;
- показывает причины HOLD;
- отображает состояние рынка;
- поддерживает execution-aware analysis;
- подготовлена к advanced execution engine.