期货
期货:主力换月与排查
期货回测中的主力合约映射与换月:用 get_future_dominant 取得真实主力、避免当日主力信息提前进入信号、先平旧仓再开新仓的分步换月流程;以及期货策略常见问题的排查清单。
一、主力映射
get_future_dominant 返回的表里,underlying_symbol 是品种、date 是映射日期、symbol 是真实主力合约。即使出现 trading_code 列,它也不是平台下单用的带后缀合约代码。
回测可以一次预加载整个区间的主力映射,但每天只能读取在决策时点已经可知的记录。配套示例保守地使用当前交易日之前最近一条映射,避免当天收盘后才确定的主力信息提前进入信号。
二、先平旧仓、再开新仓
需要严格保持「先平后开」时,按以下流程分步换月:
- 盘前确定目标真实合约,并订阅它的行情。
- 若有未完成委托,先等回报,或按策略条件撤单。
- 对旧合约按可平量发平仓单,保存新合约目标。
- 之后的
handle_data再读实际持仓:旧仓确认归零、且没有未完成委托,才开新仓。
旧合约没有有效行情、可平量不足或平仓被拒时,保持「换月未完成」的状态,不能仅因发过平仓请求就开新仓。
两种换月方式的取舍:用组合目标仓位一次调仓,适合能接受多笔委托并行执行的组合;分步换月适合要求严格先平后开的策略。
完整代码见期货示例里的「主力合约换月」。那份示例使用独立账户、只管理一个品种的多头,不要直接挂到已有其他策略持仓的账户上。
三、常见问题
| 现象 | 检查方法 |
|---|---|
| 没有任何交易 | 合约是否在有效回测区间内;是否取得有效行情;信号窗口是否预热完成;是否被未完成委托阻塞 |
| 下单返回非空但没成交 | 查看每张订单的 status、message、filled_quantity,不要以返回列表长度判断成交 |
| 平仓被拒绝 | 检查多空方向、是否为 Python 整数手数、总可平量、今仓可平量,以及是否重复冻结 |
| 夜盘信号查不到 | 映射的键是否用 context.trade_date;DataFrame 的日期类型是否已统一 |
| 查询旧合约资料为空 | 用历史日期和 get_future_detail_all;默认的可交易目录不适合查询已到期合约 |
| 换月后旧仓仍在 | 平仓请求是否实际成交;旧合约行情是否有效;是否存在挂单或冻结 |
| 组合意外清掉其他合约 | 组单字典描述的是整个账户的目标,检查是否漏了应保留的持仓方向 |
| 净值与想象的成交价不一致 | 核对撮合参考价、滑点单位、手续费与保证金倍率,以及是否用了未来信息 |
| 数据字段不存在 | 区分当前 Bar 对象和历史 DataFrame;检查 fields 与实际返回列,不要用默认值掩盖字段错误 |
日志用 print,记录提交订单、成交、拒单、换月和每日汇总即可,避免每根 Bar 无条件打印。可预期的数据缺失显式判空;必需数据为空或字段错误时给出清楚的异常,不要用宽泛的异常捕获把失败变成正常的收益结果。
四、运行前确认
- 合约真实,且在有效区间内;
- 价格单位与最小变动价位正确;
- 手数是正整数;
- 信号没有读取未来数据;
- 反向仓已经处理,平仓用的是可平量;
- 未完成委托有跟踪;
- 组单的目标范围明确;
- 回调里使用的是期货订单对象的字段。
