"""Phase Engine — Phase A–E via Rule Registry.""" from __future__ import annotations from crypto_wyckoff.domain_models import EngineResult, WyckoffPhase from crypto_wyckoff.rules.registry import rule_registry class PhaseEngine: name = "Phase" version = "1.0.0" def run(self, cycle: EngineResult, feature: EngineResult, timeframe: str) -> EngineResult: if feature.payload.get("insufficient") or cycle.payload.get("cycle") == "Unknown": return EngineResult( name=self.name, version=self.version, confidence=20.0, score=30.0, reasons=["数据/周期不足,Phase=None"], warnings=["insufficient_features"], payload={ "phase": WyckoffPhase.NONE.value, "timeframe": timeframe, "cycle": cycle.payload.get("cycle"), "structure_score": 30.0, }, ) context = { "features": feature.payload, "cycle": cycle.payload, "timeframe": timeframe, } hits = [] for rule in rule_registry.by_category("phase", timeframe): hit = rule.evaluate(context) if hit and hit.phase: hits.append(hit) if not hits: return EngineResult( name=self.name, version=self.version, confidence=40.0, score=cycle.score * 0.5, reasons=["未识别明确 Phase"], payload={ "phase": WyckoffPhase.NONE.value, "timeframe": timeframe, "cycle": cycle.payload.get("cycle"), "structure_score": cycle.score * 0.5, }, ) best = max(hits, key=lambda h: h.confidence) structure_score = best.score # Phase D/E stronger structure if best.phase in (WyckoffPhase.D.value, WyckoffPhase.E.value): structure_score = max(structure_score, 80.0) elif best.phase == WyckoffPhase.C.value: structure_score = max(structure_score, 72.0) return EngineResult( name=self.name, version=self.version, confidence=best.confidence, score=structure_score, reasons=best.reasons, metrics=best.metrics, payload={ "phase": best.phase, "timeframe": timeframe, "cycle": cycle.payload.get("cycle"), "rule_id": best.rule_id, "structure_score": structure_score, }, )