feat(paper): 组合策略接入模拟盘实走(E1+E2): paper_accounts加strategy_type列(含迁移); portfolio_paper每晚20:30全量重放→当日成交/末日持仓/净值落paper表(幂等,回测引擎为单一真相源); run_live_step按类型分流; create支持portfolio(仅live); 前端新建模拟盘策略类型选择+组合字段(策略/池/上限/基准) [vps]
CI/CD / test (push) Successful in 11s
CI/CD / nas-deploy (push) Failing after 11s
CI/CD / nas-verify (push) Has been skipped

This commit is contained in:
2026-08-13 18:32:09 +08:00
parent 3e7d40ad5f
commit d030cfc91f
7 changed files with 434 additions and 19 deletions
+20
View File
@@ -53,6 +53,12 @@ class PaperCreateRequest(BaseModel):
min_commission: float = 5.0
start: str
end: str
# 组合策略实走(E1):strategy_type=portfolio 时 mode 必须 live
# strategies[0].name=组合策略名,pool/max_pool/benchmark 进 params
strategy_type: str = "cta"
pool: str = "hs300_subset"
max_pool: int = 30
benchmark: str = "000300.XSHG"
@router.post("/paper/create", dependencies=[Depends(verify_token)])
@@ -62,6 +68,20 @@ def create_paper(req: PaperCreateRequest):
db = _db_path["path"] or ":memory:"
init_db(db)
if req.strategy_type == "portfolio":
if req.mode != "live":
raise HTTPException(400, "组合策略模拟盘仅支持实走(live)模式;历史回放请用「组合回测」")
payload = req.model_dump()
payload["symbols"] = [req.pool]
payload["strategies"] = [{
"name": (req.strategies[0].name if req.strategies else "all_weather"),
"params": {"max_pool": req.max_pool, "benchmark": req.benchmark},
}]
aid = save_account(db, payload)
from sanguo_trader.persistence import update_account_status
update_account_status(db, aid, "running")
return {"account_id": aid, "status": "running"}
aid = save_account(db, req.model_dump())
status = "created"
if req.mode == "replay": # 回放后台线程跑,create 立即返回(避免阻塞 worker 502)