From 8e1c09ad6645c803a38337fcf74e6b41e67e1548 Mon Sep 17 00:00:00 2001 From: Sergey Date: Wed, 13 May 2026 10:18:43 +0300 Subject: [PATCH] 07.4.4.1.10.2 Human-readable formatter --- app/src/trading/diagnostics/formatter.py | 200 +++++++++++ docs/roadmap/master-roadmap.md | 22 ++ docs/roadmap/stage-07-auto-trading-roadmap.md | 50 +++ ...-07_4_4_1_10_2-human_readable_formatter.md | 315 ++++++++++++++++++ 4 files changed, 587 insertions(+) create mode 100644 app/src/trading/diagnostics/formatter.py create mode 100644 docs/stages/stage-07_4_4_1_10_2-human_readable_formatter.md diff --git a/app/src/trading/diagnostics/formatter.py b/app/src/trading/diagnostics/formatter.py new file mode 100644 index 0000000..dff2e56 --- /dev/null +++ b/app/src/trading/diagnostics/formatter.py @@ -0,0 +1,200 @@ +# app/src/trading/diagnostics/formatter.py + +from __future__ import annotations + +from typing import Any + + +class SemanticDiagnosticFormatter: + def format(self, snapshot: dict[str, Any]) -> str: + sections: list[str] = [] + + status = snapshot.get("status", {}) + signal = snapshot.get("signal", {}) + market = snapshot.get("market", {}) + momentum = snapshot.get("momentum", {}) + execution = snapshot.get("execution", {}) + adaptive = snapshot.get("adaptive_size", {}) + runtime = snapshot.get("runtime_health", {}) + summary = snapshot.get("summary", {}) + position = snapshot.get("position", {}) + + sections.extend( + [ + "🧠 Semantic Runtime Diagnostics", + "", + self._status_block(status), + self._signal_block(signal), + self._market_block(market), + self._momentum_block(momentum), + self._execution_block(execution), + self._adaptive_block(adaptive), + self._position_block(position), + self._runtime_block(runtime), + self._summary_block(summary), + ] + ) + + return "\n".join( + line + for line in sections + if line is not None + ).strip() + + def _status_block(self, data: dict[str, Any]) -> str: + return ( + "📦 Runtime\n" + f"• Status: {data.get('status')}\n" + f"• Symbol: {data.get('symbol')}\n" + f"• Strategy: {data.get('strategy')}\n" + f"• Configured: {self._bool(data.get('is_configured'))}\n" + ) + + def _signal_block(self, data: dict[str, Any]) -> str: + return ( + "📡 Signal\n" + f"• Signal: {data.get('signal')}\n" + f"• Confidence: {self._float(data.get('confidence'))}\n" + f"• Decision: {data.get('decision_status')}\n" + f"• Confirmed: {self._bool(data.get('is_confirmed'))}\n" + f"• Ready: {self._bool(data.get('is_ready'))}\n" + f"• Repeats: {data.get('repeat_count')}\n" + f"• Progress: {self._percent(data.get('confirmation_progress'))}\n" + f"• Age: {self._seconds(data.get('age_seconds'))}\n" + f"• Reason: {data.get('reason')}\n" + ) + + def _market_block(self, data: dict[str, Any]) -> str: + return ( + "📈 Market\n" + f"• State: {data.get('state')}\n" + f"• Trend: {data.get('trend')}\n" + f"• Volatility: {data.get('volatility')}\n" + f"• Strength: {data.get('trend_strength')}\n" + f"• Quality: {data.get('trend_quality')}\n" + f"• Phase: {data.get('phase')}\n" + f"• Phase Direction: {data.get('phase_direction')}\n" + f"• Entry Block: {data.get('entry_block_message')}\n" + f"• Analysis Age: {self._seconds(data.get('age_seconds'))}\n" + ) + + def _momentum_block(self, data: dict[str, Any]) -> str: + return ( + "⚡ Momentum / Breakout\n" + f"• State: {data.get('state')}\n" + f"• Direction: {data.get('direction')}\n" + f"• Strength: {self._float(data.get('strength'))}\n" + f"• Change %: {self._float(data.get('change_percent'))}\n" + f"• Breakout Level: {self._float(data.get('breakout_level'))}\n" + f"• Breakout Distance %: " + f"{self._float(data.get('breakout_distance_percent'))}\n" + f"• Is Breakout: {self._bool(data.get('is_breakout'))}\n" + f"• Reason: {data.get('breakout_reason')}\n" + ) + + def _execution_block(self, data: dict[str, Any]) -> str: + return ( + "🛡 Execution\n" + f"• Quality: {data.get('quality')}\n" + f"• Semantic Status: {data.get('semantic_status')}\n" + f"• Confidence Score: " + f"{self._float(data.get('confidence_score'))}\n" + f"• Confidence Level: {data.get('confidence_level')}\n" + f"• Spread %: {self._float(data.get('spread_percent'))}\n" + f"• Snapshot Age: " + f"{self._seconds(data.get('snapshot_age_seconds'))}\n" + f"• Runtime Degraded: " + f"{self._bool(data.get('market_runtime_degraded'))}\n" + f"• Reason: {data.get('semantic_reason')}\n" + ) + + def _adaptive_block(self, data: dict[str, Any]) -> str: + return ( + "🧮 Adaptive Sizing\n" + f"• Multiplier: {self._float(data.get('multiplier'))}\n" + f"• Effective Risk %: " + f"{self._float(data.get('effective_risk_percent'))}\n" + f"• Effective Risk USD: " + f"{self._float(data.get('effective_target_risk_usd'))}\n" + f"• Reason: {data.get('reason')}\n" + ) + + def _position_block(self, data: dict[str, Any]) -> str: + return ( + "📌 Position\n" + f"• Side: {data.get('side')}\n" + f"• Entry: {self._float(data.get('entry_price'))}\n" + f"• Size: {self._float(data.get('size'))}\n" + f"• Unrealized PnL: " + f"{self._float(data.get('unrealized_pnl_usd'))}\n" + f"• Realized PnL: " + f"{self._float(data.get('realized_pnl_usd'))}\n" + f"• Last Action: {data.get('last_execution_action')}\n" + ) + + def _runtime_block(self, data: dict[str, Any]) -> str: + return ( + "🧬 Runtime Health\n" + f"• Runtime Degraded: " + f"{self._bool(data.get('is_runtime_degraded'))}\n" + f"• Signal Age: " + f"{self._seconds(data.get('signal_age_seconds'))}\n" + f"• Market Age: " + f"{self._seconds(data.get('market_age_seconds'))}\n" + f"• Expired Reason: " + f"{data.get('runtime_expired_reason')}\n" + f"• Has Market Data: " + f"{self._bool(data.get('has_market_data'))}\n" + f"• Has Momentum Data: " + f"{self._bool(data.get('has_momentum_data'))}\n" + ) + + def _summary_block(self, data: dict[str, Any]) -> str: + blockers = data.get("blockers") or [] + + if blockers: + blockers_text = ", ".join(str(item) for item in blockers) + else: + blockers_text = "none" + + return ( + "🧾 Summary\n" + f"• Market: {data.get('market')}\n" + f"• Phase: {data.get('phase')}\n" + f"• Momentum: {data.get('momentum')}\n" + f"• Execution: {data.get('execution')}\n" + f"• Position: {data.get('position')}\n" + f"• Ready: {self._bool(data.get('is_ready'))}\n" + f"• Blocked: {self._bool(data.get('is_blocked'))}\n" + f"• Blockers: {blockers_text}\n" + ) + + def _bool(self, value: object) -> str: + return "YES" if bool(value) else "NO" + + def _float(self, value: object) -> str: + if value is None: + return "—" + + try: + return f"{float(value):.4f}" + except Exception: + return str(value) + + def _percent(self, value: object) -> str: + if value is None: + return "—" + + try: + return f"{float(value) * 100:.1f}%" + except Exception: + return str(value) + + def _seconds(self, value: object) -> str: + if value is None: + return "—" + + try: + return f"{int(float(value))}s" + except Exception: + return str(value) \ No newline at end of file diff --git a/docs/roadmap/master-roadmap.md b/docs/roadmap/master-roadmap.md index a1a92c9..2a92d02 100644 --- a/docs/roadmap/master-roadmap.md +++ b/docs/roadmap/master-roadmap.md @@ -1183,6 +1183,28 @@ - execution runtime подготовлен к professional observability layer - execution runtime подготовлен к institutional execution diagnostics +#### 07.4.4.1.10.2 ✅ Human-readable formatter +- реализован human-readable diagnostic formatter +- реализован presentation layer для semantic diagnostics +- реализован человекочитаемый runtime diagnostic report +- реализовано форматирование signal diagnostics +- реализовано форматирование decision diagnostics +- реализовано форматирование market semantic diagnostics +- реализовано форматирование momentum / breakout diagnostics +- реализовано форматирование execution quality diagnostics +- реализовано форматирование execution confidence diagnostics +- реализовано форматирование adaptive sizing diagnostics +- реализовано форматирование runtime health diagnostics +- реализовано форматирование position diagnostics +- diagnostic snapshot теперь можно выводить в Telegram +- diagnostic snapshot теперь можно использовать для journal diagnostics +- diagnostic snapshot теперь можно использовать для debug output +- diagnostic layer стал explainable +- diagnostic layer стал user-readable +- diagnostic layer подготовлен к Telegram Diagnostic Screen +- diagnostic layer подготовлен к Diagnostic Journal Layer +- diagnostic layer подготовлен к Auto-refresh Diagnostic UI + --- ### 07.4.5 diff --git a/docs/roadmap/stage-07-auto-trading-roadmap.md b/docs/roadmap/stage-07-auto-trading-roadmap.md index 13e153d..798e6bb 100644 --- a/docs/roadmap/stage-07-auto-trading-roadmap.md +++ b/docs/roadmap/stage-07-auto-trading-roadmap.md @@ -1133,6 +1133,56 @@ --- +### 07.4.4.1.10 Semantic Runtime Diagnostics & Observability + +#### 07.4.4.1.10.1 ✅ Semantic Diagnostic Snapshot Builder +- реализован semantic diagnostic snapshot builder +- реализован diagnostic runtime aggregation layer +- реализован единый semantic diagnostic snapshot +- реализована агрегация signal diagnostics +- реализована агрегация decision diagnostics +- реализована агрегация market semantic diagnostics +- реализована агрегация momentum / breakout diagnostics +- реализована агрегация execution quality diagnostics +- реализована агрегация execution confidence diagnostics +- реализована агрегация adaptive sizing diagnostics +- реализована агрегация runtime expiration diagnostics +- runtime diagnostics вынесены в отдельный read-only слой +- diagnostic layer не меняет торговую логику +- diagnostic layer подготовлен к Telegram Diagnostic Screen +- diagnostic layer подготовлен к Human-readable formatter +- diagnostic layer подготовлен к Diagnostic Journal Layer +- diagnostic layer подготовлен к Auto-refresh Diagnostic UI +- execution runtime стал explainability-ready +- execution runtime стал diagnostic-aware +- execution runtime стал semantic-state-aware +- execution runtime подготовлен к professional observability layer +- execution runtime подготовлен к institutional execution diagnostics + +#### 07.4.4.1.10.2 ✅ Human-readable formatter +- реализован human-readable diagnostic formatter +- реализован presentation layer для semantic diagnostics +- реализован человекочитаемый runtime diagnostic report +- реализовано форматирование signal diagnostics +- реализовано форматирование decision diagnostics +- реализовано форматирование market semantic diagnostics +- реализовано форматирование momentum / breakout diagnostics +- реализовано форматирование execution quality diagnostics +- реализовано форматирование execution confidence diagnostics +- реализовано форматирование adaptive sizing diagnostics +- реализовано форматирование runtime health diagnostics +- реализовано форматирование position diagnostics +- diagnostic snapshot теперь можно выводить в Telegram +- diagnostic snapshot теперь можно использовать для journal diagnostics +- diagnostic snapshot теперь можно использовать для debug output +- diagnostic layer стал explainable +- diagnostic layer стал user-readable +- diagnostic layer подготовлен к Telegram Diagnostic Screen +- diagnostic layer подготовлен к Diagnostic Journal Layer +- diagnostic layer подготовлен к Auto-refresh Diagnostic UI + +--- + ### 07.4.5 ⏳ Scalping strategy diff --git a/docs/stages/stage-07_4_4_1_10_2-human_readable_formatter.md b/docs/stages/stage-07_4_4_1_10_2-human_readable_formatter.md new file mode 100644 index 0000000..74e8660 --- /dev/null +++ b/docs/stages/stage-07_4_4_1_10_2-human_readable_formatter.md @@ -0,0 +1,315 @@ +# 07.4.4.1.10.2 — Human-readable formatter + +## Статус + +✅ Этап реализован. + +## Назначение этапа + +Этап **07.4.4.1.10.2 Human-readable formatter** добавляет человекочитаемый слой поверх диагностического snapshot builder из этапа **07.4.4.1.10.1**. + +Если предыдущий этап собирал структурированный diagnostic snapshot в виде технического словаря, то текущий этап превращает этот snapshot в понятный текстовый отчёт, который можно напрямую показывать пользователю в Telegram, писать в журнал или использовать как основу для отдельного diagnostic screen. + +Главная цель этапа — сделать runtime-состояние автоторговли объяснимым: не только хранить значения `market_state`, `momentum_state`, `execution_quality`, `execution_confidence_score`, `adaptive_size_multiplier`, но и отображать их в единой логичной структуре. + +## Что было реализовано + +Создан отдельный formatter-слой: + +```text +app/src/trading/diagnostics/formatter.py +``` + +В файл добавлен класс: + +```python +SemanticDiagnosticFormatter +``` + +Класс получает на вход диагностический snapshot и формирует человекочитаемый отчёт по ключевым runtime-блокам автоторговли. + +Formatter не меняет торговую логику, не влияет на сигналы, не открывает и не закрывает позиции, не пересчитывает market analysis и не изменяет состояние `AutoTradeState`. Это read-only presentation layer. + +## Архитектурная роль + +До этого этапа диагностическая информация существовала в виде набора технических полей: + +- `last_signal` +- `decision_status` +- `market_state` +- `market_trend` +- `market_phase` +- `momentum_state` +- `breakout_reason` +- `execution_quality` +- `execution_confidence_score` +- `adaptive_size_multiplier` +- `runtime_expired_reason` +- `position_side` + +Такая структура удобна для кода, но неудобна для ручной проверки в Telegram. + +Этап **07.4.4.1.10.2** добавил промежуточный уровень: + +```text +AutoTradeState + ↓ +SemanticDiagnosticSnapshotBuilder + ↓ +SemanticDiagnosticFormatter + ↓ +Telegram screen / journal / debug output +``` + +Теперь диагностический snapshot можно не только собрать, но и вывести в читаемом виде. + +## Реализованные диагностические блоки + +Formatter формирует отчёт из отдельных смысловых секций. + +### 1. Runtime + +Блок показывает базовый runtime-контекст автоторговли: + +- статус автоторговли +- торговый инструмент +- стратегия +- признак корректной настройки + +Этот блок нужен, чтобы сразу видеть, в каком режиме находится система: `OFF`, `OBSERVING` или `RUNNING`. + +### 2. Signal + +Блок отображает состояние сигнального слоя: + +- текущий сигнал +- confidence стратегии +- decision status +- подтверждён ли сигнал +- готов ли сигнал к execution +- количество повторов +- прогресс подтверждения +- возраст сигнала +- причина сигнала + +Этот блок помогает понять, почему бот держит `HOLD`, почему BUY / SELL ещё подтверждается, или почему сигнал уже готов к исполнению. + +### 3. Market + +Блок отображает semantic market diagnostics: + +- состояние рынка +- направление тренда +- волатильность +- силу тренда +- качество тренда +- фазу рынка +- направление фазы +- причину блокировки входа +- возраст market analysis + +Именно этот блок делает видимой работу market semantic layer, добавленного на предыдущих этапах. + +Теперь можно увидеть не только короткую UI-строку вроде `📉 Рынок · снижение`, но и полный набор факторов, из которых это состояние собрано. + +### 4. Momentum / Breakout + +Блок отображает momentum и breakout diagnostics: + +- momentum state +- momentum direction +- momentum strength +- процент изменения цены в momentum window +- breakout level +- breakout distance percent +- является ли состояние breakout +- причина классификации + +Этот блок особенно важен после этапа **07.4.4.1.9.6.2 Momentum & Breakout Semantic Engine**, потому что позволяет проверить, видит ли бот импульс, пробой, направление ускорения и силу движения. + +### 5. Execution + +Блок отображает execution diagnostics: + +- execution quality +- semantic execution status +- execution confidence score +- execution confidence level +- spread percent +- snapshot age +- признак runtime degradation +- semantic reason + +Этот блок объясняет, почему execution разрешён, ограничен или заблокирован. + +Он объединяет данные execution quality layer, execution confidence engine и semantic execution state. + +### 6. Adaptive Sizing + +Блок отображает adaptive sizing diagnostics: + +- итоговый multiplier +- effective risk percent +- effective target risk USD +- причина изменения размера + +Этот блок показывает, как execution context влияет на размер будущей позиции. + +Если размер уменьшен, увеличен или заблокирован, formatter делает это видимым. + +### 7. Position + +Блок отображает состояние позиции: + +- сторона позиции +- цена входа +- размер +- unrealized PnL +- realized PnL +- последнее execution-действие + +Этот блок нужен для связи диагностики сигнала с фактической позицией. + +### 8. Runtime Health + +Блок отображает техническое здоровье runtime: + +- есть ли degraded state +- возраст сигнала +- возраст market analysis +- причина runtime expiration +- наличие market data +- наличие momentum data + +Этот блок помогает понять, устарели ли данные, сброшен ли сигнал, доступна ли рыночная аналитика и не работает ли бот на деградированном контексте. + +### 9. Summary + +Финальный блок собирает короткое резюме: + +- market summary +- phase summary +- momentum summary +- execution summary +- position summary +- готовность к execution +- блокировка +- список blockers + +Это верхнеуровневое объяснение текущего состояния автоторговли. + +## Что сделано в части аналитики + +На этом этапе аналитика была не пересчитана, а структурирована для человека. + +Это важное отличие: formatter не добавляет новые торговые правила, но делает уже существующую аналитику наблюдаемой. + +В человекочитаемый отчёт теперь выводятся ключевые аналитические слои: + +- signal layer +- decision layer +- market semantic layer +- market phase layer +- trend strength layer +- trend quality layer +- momentum semantic layer +- breakout semantic layer +- execution quality layer +- execution confidence layer +- adaptive sizing layer +- runtime health layer +- position state layer + +Таким образом, аналитика перестала быть скрытой внутри payload и runtime state. + +Теперь можно вручную проверить: + +- почему бот видит рынок как trend / range / squeeze / high volatility +- почему фаза определена как impulse / pullback / range / squeeze +- есть ли momentum или breakout +- насколько сильный импульс +- где находится breakout level +- почему вход заблокирован +- почему execution confidence низкий или нормальный +- почему adaptive sizing уменьшил или увеличил размер +- есть ли stale snapshot или широкий spread +- почему позиция открыта, не открыта или не переворачивается + +## Почему это важно + +До появления formatter диагностика была доступна только через внутренние поля и payload. + +Это создавало несколько проблем: + +1. В UI Telegram отображалось только несколько коротких строк. +2. Нельзя было быстро понять, какой именно слой заблокировал вход. +3. Momentum и breakout были рассчитаны, но не имели полноценного human-readable вывода. +4. Execution confidence был числом, но без нормальной расшифровки в общем контексте. +5. Adaptive sizing работал, но его причина не была частью единого diagnostic report. +6. Для проверки приходилось смотреть код, payload или журнал. + +Новый formatter решает эти проблемы и готовит систему к отдельному diagnostic screen. + +## Пример будущего использования + +Formatter рассчитан на дальнейшее использование в Telegram Diagnostic Screen: + +```python +snapshot = SemanticDiagnosticSnapshotBuilder().build() +text = SemanticDiagnosticFormatter().format(snapshot) +``` + +После этого `text` можно отправить в Telegram как отдельный экран диагностики. + +## Что этап НЕ делает + +Этап не добавляет новую торговую стратегию. + +Этап не меняет расчёт сигналов. + +Этап не меняет thresholds. + +Этап не меняет execution engine. + +Этап не меняет adaptive sizing. + +Этап не пишет автоматически диагностику в журнал. + +Этап не добавляет Telegram handler. + +Этап только создаёт human-readable presentation layer для уже существующего diagnostic snapshot. + +## Подготовка к следующим этапам + +Этап подготавливает базу для: + +- **07.4.4.1.10.3 Telegram Diagnostic Screen** +- **07.4.4.1.10.4 Diagnostic Journal Layer** +- **07.4.4.1.10.5 Auto-refresh Diagnostic UI** + +После этого этапа можно безопасно строить отдельный экран диагностики, потому что форматтер уже умеет превращать технический snapshot в готовый текст для пользователя. + +## Проверка + +Минимальная проверка: + +```bash +python3 -m compileall app/src/trading/diagnostics +``` + +Ожидаемый результат: + +```text +Listing 'app/src/trading/diagnostics'... +Compiling 'app/src/trading/diagnostics/formatter.py'... +``` + +Если ошибок нет, formatter синтаксически корректен. + +## Итог + +Этап **07.4.4.1.10.2 Human-readable formatter** завершает второй слой диагностической инфраструктуры. + +Теперь система умеет не только собирать semantic diagnostic snapshot, но и превращать его в понятный отчёт. + +Это переводит диагностику автоторговли из raw technical state в explainable runtime representation и подготавливает основу для полноценного Telegram diagnostic screen.