"""PaperCtaEngine 适配器测试(mock 策略,不依赖 vnpy_ctastrategy,spec §5)。""" import pytest from sanguo_trader.cta_adapter import PaperCtaEngine, _direction_to_side from sanguo_trader.models import MatchSession, OrderSide, PaperOrder class MockStrategy: """模拟 CtaTemplate:on_bar 调 cta_engine.send_order。""" def __init__(self, engine, vt_symbol="600000.SSE"): self.cta_engine = engine self.vt_symbol = vt_symbol def on_bar(self, bar): # 模拟策略:每根 bar 买 100 股 @10.0 self.cta_engine.send_order(self, "LONG", "OPEN", 10.0, 100) def test_send_order_collects_paper_order(): engine = PaperCtaEngine("s1") strat = MockStrategy(engine) engine.set_strategy(strat) engine.on_bar(None) # 触发策略 on_bar → send_order orders = engine.pop_orders() assert len(orders) == 1 assert isinstance(orders[0], PaperOrder) assert orders[0].strategy_id == "s1" assert orders[0].symbol == "600000" assert orders[0].side == OrderSide.BUY assert orders[0].price == 10.0 def test_match_session_propagates(): engine = PaperCtaEngine("s1", match_session="current_close") strat = MockStrategy(engine) engine.set_strategy(strat) engine.on_bar(None) orders = engine.pop_orders() assert orders[0].match_session == MatchSession.CURRENT_CLOSE def test_on_bar_clears_previous_pending(): engine = PaperCtaEngine("s1") engine.pending_orders.append(PaperOrder("s1", "600000", OrderSide.BUY, 10, 100)) strat = MockStrategy(engine) engine.set_strategy(strat) engine.on_bar(None) # 应清空上一根,只留本根 1 单 assert len(engine.pending_orders) == 1 def test_cancel_order_removes_pending(): engine = PaperCtaEngine("s1") strat = MockStrategy(engine) engine.set_strategy(strat) engine.on_bar(None) oids = engine.send_order(strat, "LONG", "OPEN", 11.0, 200) # 第 2 单 assert len(engine.pending_orders) == 2 engine.cancel_order(oids[0]) assert len(engine.pending_orders) == 1 def test_direction_mapping(): assert _direction_to_side("LONG") == OrderSide.BUY assert _direction_to_side("SHORT") == OrderSide.SELL assert _direction_to_side("多") == OrderSide.BUY assert _direction_to_side("空") == OrderSide.SELL