feat(trader): PaperCtaEngine 策略适配器(拦截send_order→PaperOrder)

This commit is contained in:
2026-07-07 12:00:14 +08:00
parent b2c5d8fd79
commit f0d8fd2a03
2 changed files with 153 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
"""PaperCtaEngine 适配器测试(mock 策略,不依赖 vnpy_ctastrategyspec §5)。"""
import pytest
from sanguo_trader.cta_adapter import PaperCtaEngine, _direction_to_side
from sanguo_trader.models import MatchSession, OrderSide, PaperOrder
class MockStrategy:
"""模拟 CtaTemplateon_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