07.4.4.1.7 — Live Market Runtime & Advanced Trend Diagnostics
This commit is contained in:
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
Reference in New Issue
Block a user