期货
期货:开平仓与订单
期货回测的下单写法:buy_open、sell_open、sell_close、buy_close 四种开平操作与平今参数,target_future_group_order 组合目标仓位,市价、限价 IOC 与 GFD,撮合参考价与滑点;查询与撤单、订单字段与状态、账户资金,以及多空、今昨与可平持仓。
一、四种开平操作
| 操作 | 方法 | side |
effect |
|---|---|---|---|
| 开多 | buy_open |
0 买 |
0 开仓 |
| 开空 | sell_open |
1 卖 |
0 开仓 |
| 平多 | sell_close |
1 卖 |
1 平仓 |
| 平空 | buy_close |
0 买 |
1 平仓 |
四个方法的前三个位置参数都是 account_id, id_or_ins, amount,其余参数建议按名称传。
| 参数 | 类型、默认值 | 说明 |
|---|---|---|
account_id |
字符串,必填 | 期货账户 |
id_or_ins |
字符串,必填 | 带交易所后缀的真实合约 |
amount |
Python int,必填 |
正整数手数;平仓不超过对应可平量 |
style |
默认 None |
默认市价;也可传 LimitOrderStyle(...) |
remark |
字符串,默认 None |
订单备注 |
close_today |
布尔值,默认 False,仅平仓 |
False 先平昨仓、不足再平今仓;True 指定平今,数量不能超过今仓可平量 |
close_local |
布尔值,默认 True,仅平仓 |
保留接口默认的仓位口径;普通回测按当前账户可平持仓执行,无须修改 |
retry_num |
整数,默认 None |
使用追单功能时的追单次数标记;普通委托省略 |
平仓接口中,close_today、close_local 位于 style 之后、retry_num 之前。指定平今时写 close_today=True,不要靠位置参数猜顺序。close_local 不是绕过可平仓位校验的开关。
这些方法通常返回 list[Order];格式、数量等检查失败时可能返回空列表或空值,拒单也可能返回一个 status=-1 的订单对象。
列表非空不等于成交成功,要继续看每张订单的状态、成交数量和 message。
下面的函数把某合约的今仓全部平掉:
from panda_backtest.api.api import buy_close, sell_close
def close_today_positions(context, symbol):
position = context.future_account_dict[context.account].positions[symbol]
long_amount = int(position.closable_today_buy_quantity)
short_amount = int(position.closable_today_sell_quantity)
if long_amount > 0:
sell_close(context.account, symbol, long_amount, close_today=True)
if short_amount > 0:
buy_close(context.account, symbol, short_amount, close_today=True)
从 DataFrame、NumPy 或持仓字段得到的手数,先检查是有效的整数数量,再转成 int;不要直接传 numpy.int64,也不要用 int 静默截断一个本来不是整数的下单意图。
二、组合目标仓位
target_future_group_order(account, long_symbol_dict, short_symbol_dict) 接受两个 {真实合约: 非负整数目标手数} 字典,返回 None。多头和空头分别计算;目标手数是调仓后的持仓数量,不是本次买卖数量。
from panda_backtest.api.api import target_future_group_order
def set_portfolio_target(context):
target_future_group_order(
context.account,
{"A2501.DCE": 2},
{"M2501.DCE": 1},
)
上例表示整个期货账户的目标是豆一多头 2 手、豆粕空头 1 手;不在目标字典中的现有持仓方向也会尝试平掉。两个字典都为空表示目标空仓,所以数据查询失败时,不要把空字典当作有效目标提交。
组单适合单一策略专属的账户。它会提交多笔委托,任何一笔都可能拒绝、部分成交或撤单,不是保证同时成功的交易;再次调整前先检查未完成委托,提交后核对实际持仓。主力切换时,把目标字典里的旧合约换成新合约,会产生「平旧、开新」的并行调仓;要求旧仓确认全部平掉后才开新仓的,用分步换月。
三、市价、限价与撮合价格
| 写法 | 含义 |
|---|---|
省略 style 或 style=MarketOrderStyle() |
市价单,IOC |
LimitOrderStyle(price) |
限价 IOC,未成交部分立即撤销 |
LimitOrderStyle(price, time_condition=TimeConditionType.GFD) |
限价当日有效,未成交部分保留到后续行情撮合,或撤单、日终为止 |
price 用品种报价单位,并对齐该合约的最小变动价位。不同品种的最小变动价位不同,不要把示例里的价差原样用到别的合约上。
回测 matching_type 对应的撮合参考价:
| 取值 | 参考价 |
|---|---|
0 |
当前 Bar 收盘价(日线示例用这个) |
1 |
当前 Bar 开盘价 |
2 |
买一卖一中间价 |
3 |
买单取卖一、卖单取买一 |
2、3 需要有效的盘口数据。期货滑点按最小变动价位的整数倍加在买价上、从卖价中减去。
限价单按所选参考价判断能否成交,同时受成交量等条件约束;不能理解为「当根最高 / 最低价触及限价就一定成交」。计算信号时还要注意时间顺序:用本根的收盘信息、却假设在本根开盘成交,会引入未来信息。
四、查询与撤单
| 方法 | 参数 | 返回与用法 |
|---|---|---|
get_open_future_orders |
account_id, symbol=None |
未完成订单列表;无订单返回 [],不传合约时查该账户全部 |
cancel_future_order |
account_id, order_id |
发起撤单;没有可用于确认成功的返回值,看回调和后续查询 |
auto_retry_cancel_future_order |
order, max_retry=15 |
在撤单回调里对未成交量按原方向重新提交市价单;返回新订单列表或空值 |
挂单查询包含待报、已报以及仍在队列中的部分成交 / 未成交订单。IOC 也有报单和处理过程,「IOC 不留长期挂单」不等于「永远不需要检查在途状态」。
查询范围是账户和合约,不是策略私有的登记表。记录本策略返回的订单号后再撤单,避免误撤其他委托。只有继续追单仍符合当前信号和风险条件时才用自动追单,它会产生新的市价委托。
五、订单字段
| 字段 | 类型、单位 | 含义 |
|---|---|---|
order_id |
字符串 | 订单号,用于撤单和关联回报 |
account |
字符串 | 账户 |
order_book_id |
字符串 | 合约代码 |
side / effect |
整数 | 买卖方向和开平方向,见上文 |
price |
数值,报价单位 | 委托限价;市价单不以此表示最终成交价 |
price_type |
整数 | 1 市价,2 限价 |
quantity |
数值,手 | 订单数量字段;部分成交过程中不能用来反推原始委托量,需要时自己保存 |
filled_quantity |
数值,手 | 累计成交数量 |
unfilled_quantity |
数值,手 | 未成交数量 |
cur_filled_quantity |
数值,手 | 本次成交数量 |
avg_price |
数值,报价单位 | 订单成交价格字段;多次成交的成本结合成交回报自行记录 |
transaction_cost |
数值,元 | 订单费用 |
status |
整数 | 订单状态,见下表 |
message |
字符串 | 拒单、撤单或其他说明 |
remark |
自定义备注 | 下单时传入的备注 |
trade_date |
日期值 | 订单所属交易日 |
六、订单状态
| 状态 | 含义 | 后续处理 |
|---|---|---|
0 |
待报 | 继续等待 |
1 |
已报未成交 | 继续等待或撤单 |
2 |
全部成交 | 按实际持仓推进策略 |
3 |
已撤单 | 核对已成交部分,未成交部分结束 |
4 |
部分成交,仍在队列 | 保留未完成登记 |
5 |
部分成交,不在队列 | 核对已成交部分和剩余目标 |
6 |
未成交,仍在队列 | 继续等待或撤单 |
7 |
未成交,不在队列 | 核对终结原因 |
8 / 9 |
未触发 / 已触发 | 结合所用委托类型处理,不当作全部成交 |
-1 |
拒单 | 阅读 message,检查参数、资金、持仓和行情 |
七、账户资金
account = context.future_account_dict[context.account],以下金额单位均为元:
| 字段 | 含义 |
|---|---|
total_value |
账户总权益 |
cash |
可用资金 |
frozen_cash |
冻结资金 |
margin |
已占用保证金 |
buy_margin / sell_margin |
多头 / 空头保证金 |
daily_pnl |
当日盈亏,包含权益变动和当日出入金调整 |
holding_pnl / realized_pnl |
持仓盈亏 / 平仓盈亏 |
add_profit |
累计盈亏,已调整累计出入金 |
transaction_cost |
累计手续费 |
deposit / withdraw |
累计入金 / 出金 |
today_deposit / today_withdraw |
当日入金 / 出金 |
positions |
期货持仓容器 |
add_profit、daily_pnl 都是金额,不是收益率。可用资金也不是总权益,开仓时还要预留保证金和手续费。
八、多空、今昨与可平持仓
position = account.positions[symbol] 获取指定合约,未持有时也能得到数量为 0 的对象。遍历当前持仓优先用 positions.keys()(只返回实际有持仓的合约);positions.get(symbol) 未持仓时返回 None;items()、values() 可能带出零仓位条目。
| 多头字段 | 空头字段 | 类型、单位及含义 |
|---|---|---|
buy_quantity |
sell_quantity |
手;该方向总持仓 |
buy_today_quantity |
sell_today_quantity |
手;该方向今仓 |
closable_buy_quantity |
closable_sell_quantity |
手;扣除冻结后的总可平量 |
closable_today_buy_quantity |
closable_today_sell_quantity |
手;扣除冻结后的今仓可平量 |
buy_avg_open_price |
sell_avg_open_price |
报价单位;开仓均价 |
buy_avg_holding_price |
sell_avg_holding_price |
报价单位;持仓成本价,可能受结算影响 |
buy_margin |
sell_margin |
元;该方向占用保证金 |
buy_daily_pnl |
sell_daily_pnl |
元;该方向当日盈亏 |
- 昨仓数量 = 总持仓 − 今仓;昨仓可平量 = 总可平量 − 今仓可平量。
- 平仓取可平量,不能把全部持仓量直接当可平量。总持仓大于 0 而可平量为 0,可能是存在冻结,不要重复发平仓单。
- 同一合约可以同时有多头和空头,不能用单个数量或净持仓代替两侧仓位。平多用
sell_close,平空用buy_close。
