07.4.4.1.10.3 — Telegram Diagnostic Screen

This commit is contained in:
2026-05-16 09:23:37 +03:00
parent 8e1c09ad66
commit 2c75f95b46
16 changed files with 2902 additions and 243 deletions

View File

@@ -110,6 +110,9 @@ class TrendStrategy:
if len(prices) > self._window_size:
prices.pop(0)
market_phase = self._normalized_market_phase(market)
market_phase_direction = self._normalized_market_phase_direction(market)
base_payload = {
"strategy": self.name,
"symbol": symbol,
@@ -125,8 +128,8 @@ class TrendStrategy:
"market_analysis": market.payload,
"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": market_phase,
"market_phase_direction": market_phase_direction,
"market_phase_change_percent": market.phase_change_percent,
"market_phase_direction_consistency": market.payload.get("market_phase_direction_consistency"),
"market_phase_reason": market.phase_reason,
@@ -305,7 +308,10 @@ class TrendStrategy:
momentum_direction = getattr(market, "momentum_direction", TrendDirection.UNKNOWN)
momentum_strength = float(getattr(market, "momentum_strength", 0.0) or 0.0)
if momentum_state == MomentumState.BREAKOUT_UP:
if (
momentum_state == MomentumState.BREAKOUT_UP
and market.state == MarketState.TREND_UP
):
return SignalResult(
signal=SignalType.BUY,
reason="BREAKOUT_UP подтверждён momentum/breakout semantic layer.",
@@ -319,7 +325,10 @@ class TrendStrategy:
},
)
if momentum_state == MomentumState.BREAKOUT_DOWN:
if (
momentum_state == MomentumState.BREAKOUT_DOWN
and market.state == MarketState.TREND_DOWN
):
return SignalResult(
signal=SignalType.SELL,
reason="BREAKOUT_DOWN подтверждён momentum/breakout semantic layer.",
@@ -333,6 +342,37 @@ class TrendStrategy:
},
)
if (
momentum_state == MomentumState.BREAKOUT_DOWN
and market.state == MarketState.TREND_UP
):
return SignalResult(
signal=SignalType.HOLD,
reason="Пробой вниз против TREND_UP считается коррекцией, вход в SHORT запрещён.",
confidence=0.0,
payload={
**base_payload,
"entry_block_reason": "COUNTER_TREND_BREAKOUT",
"entry_block_message": "пробой против тренда",
"expected_direction": "BUY",
},
)
if (
momentum_state == MomentumState.BREAKOUT_UP
and market.state == MarketState.TREND_DOWN
):
return SignalResult(
signal=SignalType.HOLD,
reason="Пробой вверх против TREND_DOWN считается откатом, вход в LONG запрещён.",
confidence=0.0,
payload={
**base_payload,
"entry_block_reason": "COUNTER_TREND_BREAKOUT",
"entry_block_message": "пробой против тренда",
"expected_direction": "SELL",
},
)
return None
def _calculate_breakout_confidence(self, momentum_strength: float) -> float:
@@ -384,6 +424,31 @@ class TrendStrategy:
return down_moves / total_moves
def _normalized_market_phase(self, market) -> str:
phase = market.market_phase.value
momentum_state = market.momentum_state.value
active_momentum_states = {
"MOMENTUM_UP",
"MOMENTUM_DOWN",
"BREAKOUT_UP",
"BREAKOUT_DOWN",
}
if phase == "IMPULSE" and momentum_state not in active_momentum_states:
return "UNKNOWN"
return phase
def _normalized_market_phase_direction(self, market) -> str:
phase = self._normalized_market_phase(market)
if phase == "UNKNOWN":
return "UNKNOWN"
return market.phase_direction.value
def _calculate_confidence(
self,
change_percent: float,