feat(strategy): channel_test随启随验探针模式(用户拍板2026-08-20:开盘窗口不再是验证瓶颈,随时启动随时验全场景)——on_demand=None自动:LiveEngine进程(supervisor注入SANGUO_LIVE_STRATEGY)→启动/重启后~90s经facade.run_daily注册probe_all打一轮全场景;必须走facade注册而非直接调用:回调才收到B2包装的代理context(实例预算视图),绕过它探针测不到定寸虚拟化;影子柜台24h可验(收盘价撮合),实盘闭市下单被QMT拒亦属验证项(决策层输出已在日志);重启实例=再验一轮;[PROBE-0]实例视图快照(cash=预算切片非全账户=B2生效标志)/[PROBE-1]rotate主调仓定寸=实例视图等权/[PROBE-2]只卖自己(卖出对象全部来自own账本,对照前端账户实况实例分解)/[PROBE-3]T+1当日买立即卖应拒(冷启动空仓跳过,第二轮起有票)/[PROBE-4]swap_one资金复用;回测/单测无env维持四时点旧行为,显式True/False覆盖;+3测试(env下仅注册1个未来~90s的probe_all/显式off保四时点/probe_all全序列下单断言);旧四时点测试补delenv防环境串扰 [vps]
This commit is contained in:
@@ -115,7 +115,8 @@ def test_t1_probe_fires():
|
||||
assert broker.calls == [("otv", "510300.XSHG", 0)]
|
||||
|
||||
|
||||
def test_initialize_registers_intraday_schedules():
|
||||
def test_initialize_registers_intraday_schedules(monkeypatch):
|
||||
monkeypatch.delenv("SANGUO_LIVE_STRATEGY", raising=False) # 防环境串扰翻到随启随验
|
||||
registered: list[tuple[str, str]] = []
|
||||
|
||||
class _RegBroker(_MockBroker):
|
||||
@@ -129,3 +130,65 @@ def test_initialize_registers_intraday_schedules():
|
||||
s.initialize(object())
|
||||
times = {t for _, t in registered}
|
||||
assert {"9:35", "10:45", "13:45", "14:30"} <= times # 四个盘中时点全注册
|
||||
|
||||
|
||||
# ---------------- 随启随验(2026-08-20) ----------------
|
||||
|
||||
def test_initialize_on_demand_registers_single_probe(monkeypatch):
|
||||
"""LiveEngine env 下只注册一个"启动后约90秒"的 probe_all,不再挂固定时点。"""
|
||||
from datetime import datetime
|
||||
|
||||
monkeypatch.setenv("SANGUO_LIVE_STRATEGY", "channel_test")
|
||||
registered: list[tuple[str, str]] = []
|
||||
|
||||
class _RegBroker(_MockBroker):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.run_daily = lambda fn, t: registered.append(
|
||||
(getattr(fn, "__name__", str(fn)), t))
|
||||
|
||||
s = ChannelTestStrategy(provider=None, broker=_RegBroker(),
|
||||
config=ChannelTestConfig())
|
||||
s.initialize(object())
|
||||
assert len(registered) == 1
|
||||
name, t = registered[0]
|
||||
assert name == "probe_all"
|
||||
hh, mm = t.split(":")
|
||||
now = datetime.now()
|
||||
delta = (int(hh) * 60 + int(mm)) - (now.hour * 60 + now.minute)
|
||||
assert 0 <= delta <= 3 # 未来 ~90 秒(±跨分钟容差)
|
||||
|
||||
|
||||
def test_initialize_on_demand_explicit_off_keeps_schedule(monkeypatch):
|
||||
"""on_demand=False 显式覆盖:即使 LiveEngine env 在,也维持四时点旧行为。"""
|
||||
monkeypatch.setenv("SANGUO_LIVE_STRATEGY", "channel_test")
|
||||
registered: list[tuple[str, str]] = []
|
||||
|
||||
class _RegBroker(_MockBroker):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.run_daily = lambda fn, t: registered.append(
|
||||
(getattr(fn, "__name__", str(fn)), t))
|
||||
|
||||
s = ChannelTestStrategy(provider=None, broker=_RegBroker(),
|
||||
config=ChannelTestConfig(on_demand=False))
|
||||
s.initialize(object())
|
||||
assert {"9:35", "10:45", "13:45", "14:30"} <= {t for _, t in registered}
|
||||
|
||||
|
||||
def test_probe_all_runs_sizing_sell_t1_swap_sequence():
|
||||
"""一轮探针打满:等权买入(定寸) + 卖出(只卖自己源=own 持仓) + T+1 + 换仓。"""
|
||||
broker = _MockBroker()
|
||||
s = ChannelTestStrategy(provider=None, broker=broker,
|
||||
config=ChannelTestConfig(hold_n=2, probe_t1=True,
|
||||
intraday_partial=False,
|
||||
intraday_swap=True,
|
||||
on_demand=True))
|
||||
ctx = _Ctx({"510300.XSHG": _Pos(5000), "600519.XSHG": _Pos(5000)}, cash=4000)
|
||||
s.probe_all(ctx)
|
||||
buys = [c for m, c, v in broker.calls if v > 0]
|
||||
sells = [c for m, c, v in broker.calls if v == 0]
|
||||
assert buys # 定寸买入发生(实例视图等权)
|
||||
assert "510300.XSHG" in sells # T+1 探针卖 own 第一只(或 rotate 换仓卖出)
|
||||
swap_buy = [c for m, c, v in broker.calls if m == "ov" and v > 0]
|
||||
assert swap_buy # 资金复用:卖后另买未持有票
|
||||
|
||||
Reference in New Issue
Block a user