跳转到内容

取消订单

cancel_order_sync() 用来取消一个已经提交到 TWS 的 API 订单,并等待该订单的下一次 orderStatus() 回调。它对应原始 TWS API 的:

cancelOrder(orderId, orderCancel)
-> orderStatus(orderId, status, filled, remaining, ...)

取消订单必须知道 orderId。最稳妥的方式是:程序提交订单后保存 place_order_sync() 返回的 orderId,随后用同一个 clientId 连接去取消它。

本地官方源码中的定义如下:

def cancel_order_sync(self, order_id, orderCancel=None, timeout=3):
if orderCancel is None:
orderCancel = OrderCancel()
self.cancelOrder(order_id, orderCancel)
return self._wait_for_response(order_id, "order_status", timeout)

参数说明:

参数含义
order_id要取消的订单 ID
orderCancel可选的 OrderCancel 对象;普通取消可以不传
timeout等待 orderStatus() 的秒数

返回值是 orderStatus() 字典。常见取消相关状态包括 PendingCancelCancelledInactive

下面示例会在模拟账户里提交 1 股 AAPL 的极低价限价买单,然后立即取消。这个价格只是为了让订单保持未成交,便于演示取消流程,不是交易建议。

from decimal import Decimal
import time
from ibapi.contract import Contract
from ibapi.order import Order
from ibapi.sync_wrapper import TWSSyncWrapper, ResponseTimeout
def stock_contract(symbol: str, currency: str = "USD") -> Contract:
contract = Contract()
contract.symbol = symbol
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = currency
return contract
def low_price_limit_buy() -> Order:
order = Order()
order.action = "BUY"
order.orderType = "LMT"
order.totalQuantity = Decimal("1")
order.lmtPrice = 1.00
order.tif = "DAY"
order.transmit = True
order.whatIf = False
order.orderRef = "DOC_CANCEL_TEST"
return order
app = TWSSyncWrapper(timeout=12)
try:
if not app.connect_and_start("127.0.0.1", 7497, 953):
raise RuntimeError("连接 TWS API 失败")
place_status = app.place_order_sync(
stock_contract("AAPL"),
low_price_limit_buy(),
timeout=12,
)
order_id = place_status["orderId"]
print(f"ORDER_ID={order_id}")
print(f"PLACE_STATUS={place_status['status']}")
cancel_status = app.cancel_order_sync(order_id, timeout=12)
print(f"CANCEL_STATUS={cancel_status['status']}")
# 取消状态可能先返回 PendingCancel,再过一小段时间才从开放订单列表消失。
time.sleep(2)
open_orders = app.get_open_orders(timeout=8)
print(f"OPEN_ORDER_COUNT_AFTER_CANCEL={len(open_orders)}")
except ResponseTimeout:
print("等待订单状态超时,请到 TWS 订单窗口确认订单是否仍存在")
finally:
app.disconnect_and_stop()

使用 TWS 模拟账户、127.0.0.1:7497、独立 clientId 检查撤单流程时,输出类似:

CONNECTED=True
PLACE_STATUS_RECEIVED=True
ORDER_ID=1
PLACE_STATUS=PreSubmitted
PLACE_FILLED=0
PLACE_REMAINING=1
CANCEL_STATUS_RECEIVED=True
CANCEL_STATUS=PendingCancel
CANCEL_FILLED=0
CANCEL_REMAINING=1
OPEN_ORDER_COUNT_AFTER_CANCEL=1
IS_CONNECTED_AFTER_STOP=False

立刻查询开放订单时仍有 1 个订单,因为 TWS 已收到取消请求,但状态还在 PendingCancel。等待 2 秒后重新连接查询:

CONNECTED=True
OPEN_ORDER_COUNT=0
IS_CONNECTED_AFTER_STOP=False

这说明订单已经从开放订单列表中消失。写交易系统时,不要把 PendingCancel 当作最终完成状态;更稳妥的做法是继续监听 Cancelled,或再次查询开放订单确认。

状态中文含义是否最终状态
PendingCancel取消请求已发出,等待交易所或 TWS 确认
Cancelled订单已取消
Inactive订单不可用或被拒绝通常需要检查原因

实际回调顺序不是固定的。可能先收到 PendingCancel,稍后收到 Cancelled;也可能因为订单已经成交、被拒绝或不存在而收到其他错误或状态。

用 API 提交的订单通常应由同一个 API 客户端管理。示例里提交和撤单都使用同一个连接对象:

place_status = app.place_order_sync(contract, order, timeout=12)
order_id = place_status["orderId"]
cancel_status = app.cancel_order_sync(order_id, timeout=12)

如果程序重启,至少要保存这些信息:

信息用途
orderId撤单和本地订单状态匹配
clientId区分哪个 API 客户端提交的订单
permIdIBKR 永久订单 ID,适合跨会话追踪
orderRef你自己的策略或系统订单标记

如果要接管 TWS 手动订单或其他客户端订单,需要先理解订单绑定、主客户端 ID 和开放订单请求,不建议新手直接做。

TWS API 还有全局取消接口 reqGlobalCancel()。它会请求取消所有开放订单,不只影响这个脚本提交的订单。教学、调试和普通策略开发都不应该用它做默认撤单方式。

普通策略应优先使用:

app.cancel_order_sync(order_id, timeout=12)

只有在非常明确的紧急风控场景中,才考虑全局取消,并且要在界面、日志和权限上做额外保护。

现象常见原因处理方式
取消后仍看到开放订单状态还在 PendingCancel等待一小段时间,再查开放订单或继续监听状态
ResponseTimeout没有在超时时间内收到新的 orderStatus()到 TWS 订单窗口确认,并用 get_open_orders() 再查一次
提示找不到订单orderId 错误,或订单不是这个客户端可管理的订单保存提交时返回的 orderId,并确认 clientId
订单已成交无法取消市价单或可成交限价单已经成交撤单前先检查 filledremaining
不确定是否取消成功只看到了 PendingCancelCancelled 回调或开放订单列表消失作为更强确认

IBKR Campus: TWS API Documentation