"""Plan gate + insufficient TF fallback tests.""" from datetime import date, timedelta from ashare_dp.domain.wyckoff import DecisionSignal, EngineResult, OHLCVFrame, WyckoffCycle from ashare_dp.wyckoff.cycle import CycleEngine from ashare_dp.wyckoff.decision import DecisionEngine from ashare_dp.wyckoff.features import FeatureEngine from ashare_dp.wyckoff.plan import PlanEngine from ashare_dp.wyckoff.pipeline import analyze_symbol from ashare_dp.wyckoff.phase import PhaseEngine from ashare_dp.wyckoff.event import EventEngine from ashare_dp.wyckoff.signal import SignalEngine def _er(name, payload, confidence=80.0, score=80.0): return EngineResult(name=name, confidence=confidence, score=score, payload=payload) def test_plan_no_entry_on_watch_even_if_spring_event(): plan = PlanEngine() feat = _er("Feature", {"close": 10.0, "atr": 0.3, "swing_low": 9.0, "swing_high": 11.0, "range_high": 11.0}) decision = _er( "Decision", { "decision_signal": DecisionSignal.WATCH.value, "d_event": "Spring", }, confidence=90, score=50, ) out = plan.run(feat, decision) assert out.payload["entry"] is None assert out.payload["stop"] is None def test_plan_entry_on_buy(): plan = PlanEngine() feat = _er("Feature", {"close": 10.0, "atr": 0.3, "swing_low": 9.0, "swing_high": 11.0, "range_high": 11.0}) decision = _er("Decision", {"decision_signal": DecisionSignal.BUY.value, "d_event": "Spring"}) out = plan.run(feat, decision) assert out.payload["entry"] == 10.0 assert out.payload["stop"] is not None def test_feature_insufficient_for_short_monthly(): fe = FeatureEngine() base = date(2024, 1, 1) n = 10 frame = OHLCVFrame( ts_code="000001.SZ", timeframe="1M", trade_dates=[base + timedelta(days=30 * i) for i in range(n)], open=[10.0] * n, high=[11.0] * n, low=[9.0] * n, close=[10.0] * n, volume=[1e6] * n, ) out = fe.run(frame, "1M") assert out.payload["insufficient"] is True cyc = CycleEngine().run(out, "1M") assert cyc.payload["cycle"] == WyckoffCycle.UNKNOWN.value def test_pipeline_does_not_borrow_daily_as_monthly(): """Daily-only data → monthly cycle Unknown, not inferred from daily.""" base = date(2024, 1, 1) n = 120 closes = [100 + i * 0.4 for i in range(n)] daily = OHLCVFrame( ts_code="000001.SZ", timeframe="1d", trade_dates=[base + timedelta(days=i) for i in range(n)], open=closes, high=[c * 1.01 for c in closes], low=[c * 0.99 for c in closes], close=closes, volume=[1e6] * n, ) result = analyze_symbol( daily, None, None, feature_eng=FeatureEngine(), cycle_eng=CycleEngine(), phase_eng=PhaseEngine(), event_eng=EventEngine(), signal_eng=SignalEngine(), decision_eng=DecisionEngine(), plan_eng=PlanEngine(), ) assert result["f_m"].payload.get("insufficient") is True assert result["c_m"].payload["cycle"] == WyckoffCycle.UNKNOWN.value