复盘里写着“买入2手”,这次是在增加多仓,还是在结束空仓?对普通单腿期货,同样是买入,开仓和平仓代表两种不同的交易含义。TqSdk的成交记录同时保留买卖方向与开平标志,读懂这两项,才能说明已经发生的成交做了什么。
方向说明买卖,开平说明成交性质
Trade对象的direction表示买卖方向,BUY是买入,SELL是卖出;offset表示开平,OPEN、CLOSE、CLOSETODAY分别表示开仓、平仓和平今。普通单腿期货的成交可以这样读:
| 买卖方向 | 开平标志 | 成交含义 |
|---|---|---|
| BUY | OPEN | 买入开多 |
| BUY | CLOSE或CLOSETODAY | 买入平空 |
| SELL | OPEN | 卖出开空 |
| SELL | CLOSE或CLOSETODAY | 卖出平多 |
假设一条记录是BUY、CLOSETODAY、2手,它表示买入平今空仓2手。CLOSE和CLOSETODAY都属于平仓,但平今的信息仍要保留在明细里。字段尚未齐全或组合无法解释时,保留原值待核,不猜成开仓。
从账户成交中取得开平字段
复盘某个合约当前交易日、跨不同委托的成交,可以使用api.get_trade()的账户成交集合。若只关心一笔委托的成交,官方更建议查看该Order的trade_records。
下面是接在已有TqSdk程序中的局部代码。api是原程序创建的接口实例,selected_account是选定的账户实例,多账户时须明确传入。不填trade_id,得到的是该账户当前交易日成交集合的引用。
# 指定账户,避免混入其他账户的成交。trades=api.get_trade(account=selected_account)trades按成交ID访问,每个值是一个Trade对象;给get_trade传入具体成交ID,返回的则是那一条成交的引用。接口没有symbol过滤参数,目标合约要用exchange_id和instrument_id共同识别,不能只按品种简称筛选。
查看这份集合之前,原程序需要通过wait_update()推进更新,并确认该账户的初始成交数据已经同步。一次更新返回不代表所有资料到齐,未确认同步时的空集合也不能说明“今天没有成交”。
下面的遍历放在初始同步已确认的位置。target_exchange与target_instrument由原程序提供,分别是目标交易所标识和交易所内的具体合约代码。
# 初始成交已同步,按交易所和具体合约筛选。fortrade_id,tradeintrades.items():if(trade.exchange_id!=target_exchangeortrade.instrument_id!=target_instrument):continueprint(trade_id,trade.order_id,trade.exchange_id,trade.instrument_id,trade.direction,trade.offset,trade.volume)输出依次保留成交号、所属委托号、合约身份、方向、开平和本条成交手数。对照前面的表格,BUY配OPEN是开多,BUY配平仓标志是平空。这段读取只展示已有成交,不发出交易指令。
成交条数不等于成交手数
volume是本条成交的手数。假设同一个委托号下有两个不同成交号,手数分别为1和2,合计就是3手,而不是两条记录等于2手。仅凭这两条成交,也不能判断原委托还有多少未完成。
再次遍历时,展示的仍是当前集合,不只是新增成交。若把每次刷新的输出都追加相加,就会重复计算;长期归档还需保留账户、交易日和成交身份,另行处理重复记录。
get_trade读取当前交易日的成交,不提供任意历史区间的完整归档。交易日不能按本地自然日零点直接划分,跨日复盘需要另外保存并核对的历史资料。成交性质和手数说明了发生什么,盈亏配对、策略好坏则需要更完整的分析。
用TqSdk让复盘说清“这笔成交做了什么”
我推荐用TqSdk把这些成交字段接入已有复盘视图。方向与开平说明成交性质,手数说明数量,成交号和委托号把逐笔成交与原委托联系起来。复盘“买入2手”时,便有依据区分开多与平空,并对照自己的交易意图,而不只剩下一列买卖方向。