下单、撤单与结果跟踪

本页目录

本文片段放在已创建 CTP 账户并完成同步的 ExApi 生命周期内。symbol 是要交易的合约,limit_price 是自行确定的有效限价,配置步骤见 CTP 账户。

交易操作:下单会向真实期货公司提交委托,请先在适当测试环境充分验证策略。

限价委托#

orders = api.watch_order()
if api.trading_status() != "READY":
    raise RuntimeError("Trading account is not READY")

results = api.insert_order(
    symbol=symbol,
    direction="BUY",
    offset="OPEN",
    volume=1,
    limit_price=limit_price,
)
tracked_ids = set()
for result in results:
    print(result.status, result.order_id, result.message)
    if result.status in {"SUBMITTED", "UNKNOWN"} and result.order_id:
        tracked_ids.add(result.order_id)
参数要求
directionBUY / SELL
offsetOPEN / CLOSE
volume正整数,单位为手
limit_price符合最小变动价位的有效限价

SDK 仅支持普通投机限价委托。最小变动价位可通过 合约详情 的 data["price_tick"] 核对,最终以柜台校验为准;不要直接将未经检查的缺失或过期行情作为限价。

即时提交结果#

TradingResult.status含义正确处理
SUBMITTED已交给交易接口等待订单回报;不等于柜台接受或成交
REJECTED本地拒绝或明确未发送检查 message;下单不会创建订单,order_id 为 None
UNKNOWN提交结果不明保留订单号等待自然回报,不自动重发

返回值为 list[TradingResult],立即可读且不会随回报改变。本地拒绝只写入返回结果,不会创建订单供 watch_order() 查询。

平仓输入 CLOSE 后,SDK 按交易所处理:

  • 上期所、能源中心:按昨仓优先、今仓补足拆分,实际订单的 offset 为 CLOSE_YESTERDAY / CLOSE_TODAY。
  • 其他交易所:发送普通 CLOSE,由柜台和交易所决定冲抵顺序。

拆单不是原子操作:前一子单失败或结果不明时,后续子单不再发送,以拒绝结果说明;各子单独立跟踪,也可能只成交一部分。

跟踪最终状态#

沿用下单前创建的 orders 和本轮结果中的 tracked_ids。下面为本次跟踪设置 60 秒总期限;这是应用示例期限,不是订单失效时间:

import time

deadline = time.time() + 60
while tracked_ids and time.time() < deadline:
    if not api.wait_update(deadline=deadline):
        break
    if api.trading_status() != "READY":
        continue
    snapshot = orders.data()
    for order_id in list(tracked_ids):
        order = snapshot.get(order_id)
        if order is None:
            continue
        print(order_id, order.status, order.volume_traded, order.volume_left,
              order.status_msg, order.cancel_error)
        if order.status in {"FILLED", "CANCELLED", "REJECTED"}:
            tracked_ids.remove(order_id)

if tracked_ids:
    print("跟踪等待结束,以下订单结果仍需核对:", sorted(tracked_ids))

到期只结束本次等待,不代表报单失败、撤单成功或订单被撤销。 对于仍无终态的订单,尤其是 UNKNOWN,保留订单标识,核对账户的订单、成交和持仓;SDK 无法确认时,通过期货公司客户端或人工核实,不能按“没收到回报”重新下单。

订单状态含义
PENDING待回报
ALIVE尚未确认终态
FILLED全部成交
CANCELLED未全成且不再排队,volume_left 仍可大于零
REJECTED提交失败或被拒

撤单#

results = api.cancel_order(order_id)
tracked_ids = {order_id}
for result in results:
    print(result.status, result.order_id, result.message)

传入本地 order_id,不是 order_sys_id。

  • 返回空列表:订单不存在、已结束或已经在撤单处理中;空列表本身不能证明已撤成功。
  • 立即拒绝:订单尚未确认或缺少系统订单号,不缓存撤单意图。
  • 确认结果:查看订单的 status、cancel_pending、cancel_error;撤单 SUBMITTED 不等于已撤成功。

沿用下单前创建的 orders,对新的 tracked_ids 运行上面的有限等待循环,核对原订单;立即拒绝时也应查看 message,原委托不会因此撤销。等待期间仍可能成交,最终以订单终态和 volume_traded 判断实际成交量。部分成交后撤单成功,通常表现为 CANCELLED 且 volume_traded > 0、volume_left > 0;若撤单完成前已全部成交,最终可能为 FILLED。撤单不会撤回已发生的成交。

status_msg、cancel_error 提供后续提示;部分异步失败目前只有“报单被拒绝”“撤单被拒绝”等通用文字,不保证包含详细柜台原因。

断线恢复与程序重启#

  1. 非 READY 时暂停新交易决策,继续通过更新循环推进恢复。
  2. 恢复 READY 后重新读取订单、成交和持仓,核对断线前未结束的委托及实际成交,再决定后续操作。
  3. 结果仍不明确时转人工核实,不自动重发报单或撤单。

订单视图包含同一账户其他客户端的记录。策略应自行保存已提交或结果不明的订单号及业务关联;重启后先与账户快照核对,不能将所有 ALIVE 订单都当作本策略新订单,也不能将本地记录丢失解释为未下单。当前交易日范围和持久化边界见 交易数据。

错误与退出#

下单、撤单的参数或业务拒绝通常通过 TradingResult 报告,不自动重试;账户验证、运行故障和调用方式错误仍可能抛异常。异常应覆盖整个调用与更新循环,见 错误处理。

关闭 ExApi 不会撤销订单。如果策略退出时需要撤单,应在仍能正常交易时自行发起并跟踪结果;认证或连接已失效时,应通过期货公司客户端等渠道处理存量委托。

联系我们

微信扫一扫