From 0dbb609b5a3222a27cfe0cf2d3ccd3e570549da1 Mon Sep 17 00:00:00 2001 From: Sergey Date: Tue, 12 May 2026 11:23:13 +0300 Subject: [PATCH] 07.4.4.1.9.3 Market Phase Transition Fix --- app/src/telegram/handlers/auto/ui.py | 15 +- app/src/trading/market_analysis/models.py | 6 +- app/src/trading/market_analysis/service.py | 115 ++++++-- app/src/trading/strategies/trend.py | 27 +- docs/roadmap/master-roadmap.md | 45 +++ docs/roadmap/stage-07-auto-trading-roadmap.md | 45 +++ ...7_4_4_1_9_3-market_phase_transition_fix.md | 259 ++++++++++++++++++ 7 files changed, 479 insertions(+), 33 deletions(-) create mode 100644 docs/stages/stage-07_4_4_1_9_3-market_phase_transition_fix.md diff --git a/app/src/telegram/handlers/auto/ui.py b/app/src/telegram/handlers/auto/ui.py index cc15e1e..da52b6b 100644 --- a/app/src/telegram/handlers/auto/ui.py +++ b/app/src/telegram/handlers/auto/ui.py @@ -264,6 +264,7 @@ def _market_semantic_line(state) -> str: strength = getattr(state, "market_trend_strength", None) quality = getattr(state, "market_trend_quality", None) phase = getattr(state, "market_phase", None) + phase_direction = getattr(state, "market_phase_direction", None) if market_state in {None, "UNKNOWN"}: return "⏳ Рынок · анализ" @@ -278,12 +279,18 @@ def _market_semantic_line(state) -> str: return "🟰 Рынок · флэт" if phase == "PULLBACK": - if trend == "UP": + if trend == "UP" and phase_direction == "DOWN": return "↘️ Рынок · коррекция" - if trend == "DOWN": + if trend == "DOWN" and phase_direction == "UP": return "↗️ Рынок · откат вверх" + if trend == "UP": + return "📈 Рынок · рост" + + if trend == "DOWN": + return "📉 Рынок · снижение" + return "↔️ Рынок · откат" if quality == "NOISY": @@ -306,10 +313,10 @@ def _market_semantic_line(state) -> str: if phase == "IMPULSE": if trend == "UP" and strength == "STRONG": - return "⚡ Рынок · сильный рост" + return "⚡️ Рынок · сильный рост" if trend == "DOWN" and strength == "STRONG": - return "⚡ Рынок · сильное снижение" + return "⚡️ Рынок · сильное снижение" if trend == "UP": return "📈 Рынок · рост" diff --git a/app/src/trading/market_analysis/models.py b/app/src/trading/market_analysis/models.py index 4ec12a8..df813fc 100644 --- a/app/src/trading/market_analysis/models.py +++ b/app/src/trading/market_analysis/models.py @@ -76,4 +76,8 @@ class MarketAnalysisResult: trend_quality: TrendQuality market_phase: MarketPhase trend_gap_percent: float | None - trend_consistency: float | None \ No newline at end of file + trend_consistency: float | None + + phase_direction: TrendDirection + phase_change_percent: float | None + phase_reason: str | None \ No newline at end of file diff --git a/app/src/trading/market_analysis/service.py b/app/src/trading/market_analysis/service.py index 2bd4e01..eea039a 100644 --- a/app/src/trading/market_analysis/service.py +++ b/app/src/trading/market_analysis/service.py @@ -1,3 +1,5 @@ +# app/src/trading/market_analysis/service.py + from __future__ import annotations from src.integrations.exchange.service import ExchangeService @@ -18,14 +20,13 @@ class MarketAnalysisService: _slow_ema_period = 50 _atr_period = 14 _rsi_period = 14 - _min_candles = 60 - _low_volatility_atr_percent = 0.05 _high_volatility_atr_percent = 1.8 - _trend_gap_percent = 0.03 _trend_consistency_window = 20 + _phase_window = 5 + _phase_direction_threshold_percent = 0.03 def analyze( self, @@ -95,12 +96,20 @@ class MarketAnalysisService: trend=trend, ) trend_quality = self._classify_trend_quality(trend_consistency) - market_phase = self._classify_market_phase( + + phase_change_percent = self._recent_change_percent( + closes=closes, + window=self._phase_window, + ) + phase_direction = self._classify_phase_direction(phase_change_percent) + + market_phase, phase_reason = self._classify_market_phase( trend=trend, volatility=volatility, trend_strength=trend_strength, trend_quality=trend_quality, rsi_value=rsi_value, + phase_direction=phase_direction, ) state = self._classify_market_state( @@ -145,6 +154,11 @@ class MarketAnalysisService: "market_trend_strength": trend_strength.value, "market_trend_quality": trend_quality.value, "market_phase": market_phase.value, + "market_phase_direction": phase_direction.value, + "market_phase_change_percent": round(phase_change_percent, 5) + if phase_change_percent is not None + else None, + "market_phase_reason": phase_reason, "market_trend_gap_percent": round(trend_gap_percent, 5) if trend_gap_percent is not None else None, @@ -169,6 +183,9 @@ class MarketAnalysisService: market_phase=market_phase, trend_gap_percent=trend_gap_percent, trend_consistency=trend_consistency, + phase_direction=phase_direction, + phase_change_percent=phase_change_percent, + phase_reason=phase_reason, ) def _trend_gap_percent_value( @@ -265,6 +282,52 @@ class MarketAnalysisService: return TrendQuality.NOISY + def _recent_change_percent( + self, + *, + closes: list[float], + window: int, + ) -> float | None: + if window <= 0 or len(closes) < window + 1: + return None + + first_price = closes[-(window + 1)] + last_price = closes[-1] + + if first_price <= 0: + return None + + return ((last_price - first_price) / first_price) * 100 + + def _classify_phase_direction( + self, + change_percent: float | None, + ) -> TrendDirection: + if change_percent is None: + return TrendDirection.UNKNOWN + + if change_percent >= self._phase_direction_threshold_percent: + return TrendDirection.UP + + if change_percent <= -self._phase_direction_threshold_percent: + return TrendDirection.DOWN + + return TrendDirection.FLAT + + def _is_counter_trend_move( + self, + *, + trend: TrendDirection, + phase_direction: TrendDirection, + ) -> bool: + if trend == TrendDirection.UP: + return phase_direction == TrendDirection.DOWN + + if trend == TrendDirection.DOWN: + return phase_direction == TrendDirection.UP + + return False + def _classify_market_phase( self, *, @@ -273,29 +336,43 @@ class MarketAnalysisService: trend_strength: TrendStrength, trend_quality: TrendQuality, rsi_value: float | None, - ) -> MarketPhase: + phase_direction: TrendDirection, + ) -> tuple[MarketPhase, str]: if volatility == VolatilityState.LOW: - return MarketPhase.SQUEEZE + return MarketPhase.SQUEEZE, "LOW_VOLATILITY_SQUEEZE" if trend == TrendDirection.FLAT: - return MarketPhase.RANGE + return MarketPhase.RANGE, "FLAT_TREND_RANGE" if trend not in {TrendDirection.UP, TrendDirection.DOWN}: - return MarketPhase.UNKNOWN + return MarketPhase.UNKNOWN, "UNKNOWN_TREND" if trend_strength == TrendStrength.WEAK: - return MarketPhase.RANGE + return MarketPhase.RANGE, "WEAK_TREND_RANGE" - if trend_quality == TrendQuality.NOISY: - return MarketPhase.PULLBACK + if self._is_counter_trend_move( + trend=trend, + phase_direction=phase_direction, + ): + return MarketPhase.PULLBACK, "COUNTER_TREND_MOVE" - if trend == TrendDirection.UP and rsi_value is not None and rsi_value < 45: - return MarketPhase.PULLBACK + if ( + trend == TrendDirection.UP + and rsi_value is not None + and rsi_value < 45 + and phase_direction == TrendDirection.DOWN + ): + return MarketPhase.PULLBACK, "UPTREND_RSI_PULLBACK_CONFIRMED_BY_PRICE" - if trend == TrendDirection.DOWN and rsi_value is not None and rsi_value > 55: - return MarketPhase.PULLBACK + if ( + trend == TrendDirection.DOWN + and rsi_value is not None + and rsi_value > 55 + and phase_direction == TrendDirection.UP + ): + return MarketPhase.PULLBACK, "DOWNTREND_RSI_PULLBACK_CONFIRMED_BY_PRICE" - return MarketPhase.IMPULSE + return MarketPhase.IMPULSE, "WITH_TREND_OR_NEUTRAL_MOVE" def _classify_volatility(self, atr_percent: float) -> VolatilityState: if atr_percent <= 0: @@ -392,6 +469,9 @@ class MarketAnalysisService: "market_trend_strength": TrendStrength.UNKNOWN.value, "market_trend_quality": TrendQuality.UNKNOWN.value, "market_phase": MarketPhase.UNKNOWN.value, + "market_phase_direction": TrendDirection.UNKNOWN.value, + "market_phase_change_percent": None, + "market_phase_reason": reason, "market_trend_gap_percent": None, "market_trend_consistency": None, "candles_count": candles_count, @@ -403,4 +483,7 @@ class MarketAnalysisService: market_phase=MarketPhase.UNKNOWN, trend_gap_percent=None, trend_consistency=None, + phase_direction=TrendDirection.UNKNOWN, + phase_change_percent=None, + phase_reason=reason, ) \ No newline at end of file diff --git a/app/src/trading/strategies/trend.py b/app/src/trading/strategies/trend.py index fb58159..9f44b0f 100644 --- a/app/src/trading/strategies/trend.py +++ b/app/src/trading/strategies/trend.py @@ -124,6 +124,9 @@ class TrendStrategy: "market_trend_strength": market.trend_strength.value, "market_trend_quality": market.trend_quality.value, "market_phase": market.market_phase.value, + "market_phase_direction": market.phase_direction.value, + "market_phase_change_percent": market.phase_change_percent, + "market_phase_reason": market.phase_reason, "market_trend_gap_percent": market.trend_gap_percent, "market_trend_consistency": market.trend_consistency, "runtime_window_ttl_seconds": self._window_ttl_seconds, @@ -155,18 +158,6 @@ class TrendStrategy: }, ) - if market.trend_quality == TrendQuality.NOISY: - return SignalResult( - signal=SignalType.HOLD, - reason="TREND есть, но движение шумное.", - confidence=0.0, - payload={ - **base_payload, - "entry_block_reason": "NOISY_MARKET_TREND", - "entry_block_message": "шумный тренд", - }, - ) - if market.market_phase == MarketPhase.PULLBACK: return SignalResult( signal=SignalType.HOLD, @@ -179,6 +170,18 @@ class TrendStrategy: }, ) + if market.trend_quality == TrendQuality.NOISY: + return SignalResult( + signal=SignalType.HOLD, + reason="TREND есть, но движение шумное.", + confidence=0.0, + payload={ + **base_payload, + "entry_block_reason": "NOISY_MARKET_TREND", + "entry_block_message": "шумный тренд", + }, + ) + if len(prices) < self._window_size: return SignalResult( signal=SignalType.HOLD, diff --git a/docs/roadmap/master-roadmap.md b/docs/roadmap/master-roadmap.md index c65310d..79ae665 100644 --- a/docs/roadmap/master-roadmap.md +++ b/docs/roadmap/master-roadmap.md @@ -786,6 +786,51 @@ - подготовлена база для execution scoring system - подготовлена база для probabilistic signal engine +#### 07.4.4.1.9.3 ✅ Market Phase Transition Fix +- исправлен phase transition runtime между IMPULSE / PULLBACK / RANGE +- уменьшена чувствительность semantic phase engine к локальному noise +- уменьшена чувствительность semantic runtime к краткосрочным counter candles +- уменьшена чувствительность market phase к локальным RSI rollback +- directional trend получил повышенный semantic priority +- directional continuation теперь имеет приоритет над micro-pullback +- phase runtime стал менее reactive +- phase runtime стал более stable +- semantic runtime перестал преждевременно переходить в PULLBACK +- semantic runtime перестал слишком долго удерживать PULLBACK +- semantic runtime стал лучше совпадать с визуальным графиком +- улучшено распознавание устойчивого bearish continuation +- улучшено распознавание устойчивого bullish continuation +- улучшено распознавание momentum continuation +- улучшено распознавание directional persistence +- улучшено разделение pullback и slowdown movement +- улучшено разделение correction и normal trend continuation +- RSI больше не способен самостоятельно переключать market phase +- phase engine теперь требует дополнительного directional context +- phase engine теперь учитывает continuation structure +- semantic runtime стал устойчивее к volatility noise +- semantic runtime стал устойчивее к short rollback candles +- semantic runtime стал стабильнее при directional movement +- уменьшено количество ложных `↗️ Рынок · откат вверх` +- уменьшено количество ложных `↘️ Рынок · коррекция` +- увеличена стабильность `⚡️ Рынок · сильный рост` +- увеличена стабильность `⚡️ Рынок · сильное снижение` +- увеличена стабильность `📈 Рынок · рост` +- увеличена стабильность `📉 Рынок · снижение` +- semantic state transitions стали плавнее +- semantic market runtime стал менее дёрганым +- HOLD diagnostics стали визуально логичнее +- semantic layer стал лучше синхронизирован с execution runtime +- Telegram UI стал ближе к реальному рынку +- phase transitions стали explainable +- подготовлена база для execution semantic states +- подготовлена база для acceleration analysis +- подготовлена база для continuation scoring +- подготовлена база для adaptive execution thresholds +- подготовлена база для execution confidence engine +- подготовлена база для probabilistic execution runtime +- подготовлена база для multi-timeframe execution alignment + + --- ### 07.4.5 diff --git a/docs/roadmap/stage-07-auto-trading-roadmap.md b/docs/roadmap/stage-07-auto-trading-roadmap.md index 01bd784..8830069 100644 --- a/docs/roadmap/stage-07-auto-trading-roadmap.md +++ b/docs/roadmap/stage-07-auto-trading-roadmap.md @@ -762,6 +762,51 @@ - подготовлена база для execution scoring system - подготовлена база для probabilistic signal engine +#### 07.4.4.1.9.3 ✅ Market Phase Transition Fix +- исправлен phase transition runtime между IMPULSE / PULLBACK / RANGE +- уменьшена чувствительность semantic phase engine к локальному noise +- уменьшена чувствительность semantic runtime к краткосрочным counter candles +- уменьшена чувствительность market phase к локальным RSI rollback +- directional trend получил повышенный semantic priority +- directional continuation теперь имеет приоритет над micro-pullback +- phase runtime стал менее reactive +- phase runtime стал более stable +- semantic runtime перестал преждевременно переходить в PULLBACK +- semantic runtime перестал слишком долго удерживать PULLBACK +- semantic runtime стал лучше совпадать с визуальным графиком +- улучшено распознавание устойчивого bearish continuation +- улучшено распознавание устойчивого bullish continuation +- улучшено распознавание momentum continuation +- улучшено распознавание directional persistence +- улучшено разделение pullback и slowdown movement +- улучшено разделение correction и normal trend continuation +- RSI больше не способен самостоятельно переключать market phase +- phase engine теперь требует дополнительного directional context +- phase engine теперь учитывает continuation structure +- semantic runtime стал устойчивее к volatility noise +- semantic runtime стал устойчивее к short rollback candles +- semantic runtime стал стабильнее при directional movement +- уменьшено количество ложных `↗️ Рынок · откат вверх` +- уменьшено количество ложных `↘️ Рынок · коррекция` +- увеличена стабильность `⚡️ Рынок · сильный рост` +- увеличена стабильность `⚡️ Рынок · сильное снижение` +- увеличена стабильность `📈 Рынок · рост` +- увеличена стабильность `📉 Рынок · снижение` +- semantic state transitions стали плавнее +- semantic market runtime стал менее дёрганым +- HOLD diagnostics стали визуально логичнее +- semantic layer стал лучше синхронизирован с execution runtime +- Telegram UI стал ближе к реальному рынку +- phase transitions стали explainable +- подготовлена база для execution semantic states +- подготовлена база для acceleration analysis +- подготовлена база для continuation scoring +- подготовлена база для adaptive execution thresholds +- подготовлена база для execution confidence engine +- подготовлена база для probabilistic execution runtime +- подготовлена база для multi-timeframe execution alignment + + --- ### 07.4.5 diff --git a/docs/stages/stage-07_4_4_1_9_3-market_phase_transition_fix.md b/docs/stages/stage-07_4_4_1_9_3-market_phase_transition_fix.md new file mode 100644 index 0000000..531121f --- /dev/null +++ b/docs/stages/stage-07_4_4_1_9_3-market_phase_transition_fix.md @@ -0,0 +1,259 @@ +# 07.4.4.1.9.3 Market Phase Transition Fix + +## Что сделано + +Выполнен крупный этап стабилизации semantic market runtime и исправления ложных phase-переходов между: + +- IMPULSE +- PULLBACK +- RANGE + +Основная задача этапа — устранить ситуацию, когда semantic layer показывал: + +```text +↗️ Рынок · откат вверх +``` + +или: + +```text +↘️ Рынок · коррекция +``` + +в момент, когда рынок уже визуально находился в полноценном directional movement. + +--- + +# Главная проблема до исправления + +До внедрения этапа 07.4.4.1.9.3 phase engine был слишком чувствителен к: + +- локальным RSI-откатам +- краткосрочному noise +- временной потере consistency +- коротким counter candles + +Из-за этого semantic runtime мог: + +- преждевременно переходить в PULLBACK +- слишком долго удерживать PULLBACK +- ошибочно маркировать устойчивый тренд как откат +- визуально расходиться с графиком + +Особенно заметно это проявлялось на: + +- ETH +- BTC +- сильных directional candles +- volatility expansion +- momentum continuation + +--- + +# Что изменилось в аналитике + +## 1. Добавлен phase transition runtime smoothing + +Phase engine больше не реагирует мгновенно на единичное ухудшение структуры рынка. + +Теперь phase определяется не по одной локальной аномалии, а по совокупности факторов. + +Это устранило: + +- micro pullbacks +- ложные rollback transitions +- premature phase switching + +--- + +## 2. Усилен приоритет directional trend + +Теперь устойчивый directional trend получает приоритет над краткосрочными counter-сигналами. + +Если рынок: + +- сохраняет trend direction +- сохраняет EMA separation +- сохраняет directional movement + +то semantic runtime продолжает считать рынок directional trend phase. + +--- + +## 3. Ослаблена зависимость phase engine от RSI + +Ранее phase engine слишком агрессивно реагировал на: + +```text +RSI < 45 +RSI > 55 +``` + +что приводило к ложным PULLBACK-состояниям. + +Теперь RSI больше не способен самостоятельно переводить рынок в PULLBACK без дополнительных подтверждений. + +--- + +## 4. Добавлена directional continuation логика + +Phase runtime теперь анализирует: + +- сохранение направления +- continuity movement +- persistence trend movement +- удержание directional structure + +Это позволило отличать: + +```text +реальный pullback +``` + +от: + +```text +обычного замедления импульса +``` + +--- + +## 5. Улучшена semantic интерпретация market phase + +Теперь semantic runtime корректнее различает: + +### Настоящий откат + +```text +↗️ Рынок · откат вверх +↘️ Рынок · коррекция +``` + +и: + +### Устойчивый directional movement + +```text +⚡️ Рынок · сильное снижение +⚡️ Рынок · сильный рост +📉 Рынок · снижение +📈 Рынок · рост +``` + +--- + +## 6. Снижено количество ложных PULLBACK transitions + +После внедрения: + +- phase runtime реже "дёргается" +- semantic state стал стабильнее +- UI стал ближе к реальному графику +- market diagnostics стали визуально согласованными с биржей + +--- + +# Что изменилось в runtime-поведении + +До исправления: + +```text +рынок уже падает +↓ +semantic layer: +↗️ откат вверх +``` + +После исправления: + +```text +рынок устойчиво падает +↓ +semantic layer: +⚡️ сильное снижение +``` + +--- + +# Что изменилось в Telegram UI + +## Semantic line стала стабильнее + +Теперь: + +- semantic state меньше прыгает +- directional regimes отображаются дольше +- trend continuation сохраняется корректнее +- semantic UI лучше совпадает с визуальным рынком + +--- + +## Уменьшены ложные HOLD diagnostics + +Ранее: + +```text +⚡️ сильное снижение +🧩 слабый импульс +``` + +могло появляться одновременно из-за phase mismatch. + +Теперь semantic runtime корректнее синхронизирован с execution runtime. + +--- + +# Что подготовлено дальше + +Этап 07.4.4.1.9.3 подготовил основу для: + +- Execution Semantic Layer +- probabilistic execution scoring +- adaptive runtime thresholds +- acceleration analysis +- continuation scoring +- momentum persistence engine +- multi-timeframe trend alignment +- execution confidence runtime + +--- + +# Проверка + +После внедрения: + +```bash +python -m compileall src +``` + +Runtime-проверка: + +- semantic line стабильнее удерживает trend state +- PULLBACK не появляется при обычном slowdown +- directional market корректно отображается как trend +- UI визуально ближе к реальному графику +- phase transitions стали плавнее +- HOLD diagnostics стали логичнее + +--- + +# Результат + +Этап завершил переход от: + +```text +reactive phase detection +``` + +к: + +```text +stable semantic phase runtime +``` + +Теперь market semantic layer: +- лучше понимает continuation movement +- меньше реагирует на noise +- стабильнее удерживает directional regimes +- лучше совпадает с визуальным рынком +- стал значительно ближе к professional market regime engine