fix(live): C-S3实走warmup(am跨日)+fetch_day wrapper+端到端验证

- live_orchestrator warmup: 重放start~昨日raw到策略am使其inited(实走每日单根, 不warmup则ArrayManager永不inited→策略无信号)
- routes _DataSourceWrapper 加 fetch_day(给 live_step 拉当日raw)
- verify_live_step 容器端到端: 创建live account+live_step(07-07 warmup+step)+存pending, 跑通(pending=0系DoubleMa当日无交叉, 撮合/存已单测)
This commit is contained in:
2026-07-08 06:59:24 +08:00
parent 674cfadba7
commit 7eec983164
3 changed files with 93 additions and 7 deletions
+6 -1
View File
@@ -115,7 +115,7 @@ def get_strategies(aid: int):
class _DataSourceWrapper:
"""包装 iter_bars 给 PaperEngineengine 需 data_source.iter_bars 接口)"""
"""包装 iter_bars/fetch_day 给 PaperEngine/live_orchestrator"""
def __init__(self, cfg):
self.cfg = cfg
@@ -125,6 +125,11 @@ class _DataSourceWrapper:
return iter_bars(symbols, start, end, interval, adjust, cfg or self.cfg)
def fetch_day(self, symbol, date, interval, adjust="qfq", cfg=None):
from sanguo_trader.data_source import fetch_day
return fetch_day(symbol, date, interval, adjust, cfg or self.cfg)
def _run_replay(db, aid, req: PaperCreateRequest):
"""构造引擎 + 跑回放(容器内有 vnpy_ctastrategy + NAS parquet,本机仅空转)。"""
+21 -6
View File
@@ -43,8 +43,11 @@ def _restore_ledger(positions: dict) -> dict:
for sym, p in positions.items()}
def live_step(db_path: str, account_id: int, data_source, cfg) -> None:
"""实走单日 stepscheduler 每日调)。data_source=_DataSourceWrapper, cfg=data 配置。"""
def live_step(db_path: str, account_id: int, data_source, cfg, today: str | None = None) -> None:
"""实走单日 stepscheduler 每日调)。data_source=_DataSourceWrapper, cfg=data 配置。
today: 默认 datetime.now();验证可指定历史日期(有 raw)。
"""
from sanguo_data.datareader import guess_exchange
from sanguo_api.strategy_registry import get_strategy_class
from vnpy.trader.utility import ArrayManager
@@ -87,8 +90,21 @@ def live_step(db_path: str, account_id: int, data_source, cfg) -> None:
logger.warning("live_step %s: 无可用策略(容器缺 vnpy_ctastrategy?),跳过", account_id)
return
# 3. 当日 raw barMac launchd 已推 NAS
today = datetime.now().strftime("%Y-%m-%d")
# 3. 日期 + warmup(重放 start~昨日到策略 am 使其 inited;丢弃 warmup 单
# 实走每日单根 barArrayManager 需 warmup 才 inited,否则策略无信号。
today = today or datetime.now().strftime("%Y-%m-%d")
yesterday = (datetime.strptime(today, "%Y-%m-%d") - timedelta(days=1)).strftime("%Y-%m-%d")
start_date = acc.get("start_date") or today
if start_date < yesterday:
for _wd, wbars in data_source.iter_bars(
symbols, start_date, yesterday, interval, adjust="raw", cfg=cfg
):
for runner in runners:
if runner.symbol in wbars:
runner.paper_cta_engine.on_bar(wbars[runner.symbol])
runner.paper_cta_engine.pop_orders() # warmup 单丢弃(不撮合)
# 4. 当日 raw barMac launchd 已推 NAS
bars = {}
for sym in symbols:
bar = data_source.fetch_day(sym, today, interval, adjust="raw", cfg=cfg)
@@ -98,7 +114,7 @@ def live_step(db_path: str, account_id: int, data_source, cfg) -> None:
logger.info("live_step %s: 当日无 raw bar%s 非交易日或未推?),跳过", account_id, today)
return
# 4. 恢复 pending + prev_close
# 5. 恢复 pending + prev_close
pending = []
for o in load_pending_orders(db_path, account_id):
runner = next((r for r in runners if r.strategy_id == o["strategy_id"]), None)
@@ -109,7 +125,6 @@ def live_step(db_path: str, account_id: int, data_source, cfg) -> None:
o["is_market"], MatchSession(o["match_session"]), o["listing_days"],
), runner))
# prev_close:昨日 raw closefetch_day 昨日);失败兜底用当日 open
yesterday = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")
prev_close = {}
for sym in symbols:
ybar = data_source.fetch_day(sym, yesterday, interval, adjust="raw", cfg=cfg)
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
"""C-S3 实走端到端验证(容器内,task 2):创建 live account + live_step + 查 pending/positions。
验证编排 glue:恢复状态 → fetch_day raw → engine.step → 存 pending/positions。
用历史日期(有 raw)验证;首次 step 策略收单(next_open) → pending 非空。
用法(容器内):python3 /app/scripts/verify_live_step.py
"""
import os
import sys
sys.path.insert(0, "/app")
from sanguo_data.config import find_config_path, load_config
from sanguo_api.routes_paper import _DataSourceWrapper
from sanguo_trader.persistence import (
init_db, save_account, update_account_status,
load_pending_orders, load_positions, save_daily_balance,
)
from sanguo_trader.live_orchestrator import live_step
DB = "/volume1/stock/sanguo_vnpy/data/backtest_results.db"
TODAY = "2026-07-07" # 有 raw 的历史日期(验证用)
def main():
cfg = load_config(find_config_path())
init_db(DB)
aid = save_account(DB, {
"name": "live_verify_tmp", "mode": "live", "interval": "d",
"symbols": ["600000"],
"strategies": [{"name": "DoubleMaStrategy",
"params": {"fast_window": 5, "slow_window": 10},
"match_session": "next_open", "symbol": "600000",
"listing_days": 0}],
"initial_capital": 1_000_000, "rate": 0.0003, "slippage": 0,
"pricetick": 0.01, "stamp_duty_rate": 0.0005,
"transfer_fee_rate": 0.00001, "min_commission": 5.0,
"start_date": "2024-01-01",
})
update_account_status(DB, aid, "running")
print(f"created live account #{aid} (mode=live)")
ds = _DataSourceWrapper(cfg)
live_step(DB, aid, ds, cfg, today=TODAY)
pending = load_pending_orders(DB, aid)
positions = load_positions(DB, aid, "account")
print(f"\n=== live_step @ {TODAY} 结果 ===")
print(f"pending orders: {len(pending)}")
for p in pending:
print(f" {p['strategy_id']} {p['symbol']} {p['side']} {p['volume']}@{p['price']} ({p['match_session']})")
print(f"positions: {positions or '(空,首次 step 未撮合)'}")
# 清理验证 account
import sqlite3
with sqlite3.connect(DB) as c:
c.execute("DELETE FROM paper_accounts WHERE id=?", (aid,))
c.execute("DELETE FROM paper_pending_orders WHERE account_id=?", (aid,))
c.execute("DELETE FROM paper_positions WHERE account_id=?", (aid,))
c.execute("DELETE FROM paper_daily_balance WHERE account_id=?", (aid,))
c.commit()
print(f"\n(已清理验证 account #{aid})")
print("live_step 端到端 OK ✓" if pending else "live_step 跑通(策略当日无信号)")
if __name__ == "__main__":
main()