跳转到内容

未完成订单

get_open_orders() 用来查询还没有结束的订单,也就是仍然处于活动状态、还能被成交、修改或取消的订单。

它对应原始 TWS API 的这一组调用和回调:

reqOpenOrders()
-> openOrder(orderId, contract, order, orderState)
-> openOrderEnd()

注意:未完成订单不是历史订单。已经完全成交、已经取消、已经失效的订单,不会通过 reqOpenOrders() 当作开放订单返回。要查成交记录,需要看后面的“成交”章节。

本地官方源码中的同步封装如下:

def get_open_orders(self, timeout=3):
# 清空上一次缓存的开放订单,避免新旧结果混在一起。
self.open_orders = {}
self.reqOpenOrders()
return self._wait_for_response(0, "open_orders", timeout)

源码里的 openOrder() 回调会把每一条订单整理成字典:

def openOrder(self, orderId, contract, order, orderState):
open_order_data = {
"orderId": orderId,
"contract": contract,
"order": order,
"orderState": orderState,
}
self.open_orders[orderId] = open_order_data

当 TWS 把开放订单都发完后,会触发 openOrderEnd()。同步封装就是等这个结束信号,再把 self.open_orders 返回给调用方。

返回结构可以理解成:

字段中文含义
orderIdAPI 客户端可识别的订单 ID
contract合约对象,例如股票代码、证券类型、交易所、币种
order订单对象,例如买卖方向、订单类型、数量、限价、有效期
orderState订单状态对象,例如 PreSubmittedSubmittedPendingCancel

下面的示例会在模拟账户中提交一笔极低价格的 AAPL 限价买单,使它保持未成交;随后调用 get_open_orders() 查询未完成订单,最后立刻撤单并确认列表清空。

这个价格只是为了演示开放订单查询流程,不是交易建议。

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_OPEN_ORDERS_TEST"
return order
app = TWSSyncWrapper(timeout=12)
try:
if not app.connect_and_start("127.0.0.1", 7497, 955):
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"PLACE_STATUS={place_status['status']}")
open_orders = app.get_open_orders(timeout=8)
print(f"OPEN_ORDER_COUNT={len(open_orders)}")
for order_id, item in open_orders.items():
contract = item["contract"]
order = item["order"]
order_state = item["orderState"]
print(f"SYMBOL={contract.symbol}")
print(f"SEC_TYPE={contract.secType}")
print(f"EXCHANGE={contract.exchange}")
print(f"ACTION={order.action}")
print(f"ORDER_TYPE={order.orderType}")
print(f"TOTAL_QUANTITY={order.totalQuantity}")
print(f"LMT_PRICE={order.lmtPrice}")
print(f"TIF={order.tif}")
print(f"ORDER_REF={order.orderRef}")
print(f"STATE_STATUS={order_state.status}")
cancel_status = app.cancel_order_sync(order_id, timeout=12)
print(f"CANCEL_STATUS={cancel_status['status']}")
time.sleep(2)
open_orders_after_cancel = app.get_open_orders(timeout=8)
print(f"OPEN_ORDER_COUNT_AFTER_CANCEL={len(open_orders_after_cancel)}")
except ResponseTimeout:
print("等待 TWS 返回开放订单或订单状态时超时,请到 TWS 订单窗口确认订单状态。")
finally:
app.disconnect_and_stop()
print(f"IS_CONNECTED_AFTER_STOP={app.isConnected()}")

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

CONNECTED=True
PLACE_STATUS=PreSubmitted
PLACE_FILLED=0
PLACE_REMAINING=1
OPEN_ORDER_COUNT=1
ORDER_ID=1
SYMBOL=AAPL
SEC_TYPE=STK
EXCHANGE=SMART
ACTION=BUY
ORDER_TYPE=LMT
TOTAL_QUANTITY=1
LMT_PRICE=1.0
TIF=DAY
ORDER_REF=DOC_OPEN_ORDERS_TEST
STATE_STATUS=PreSubmitted
CANCEL_STATUS=PendingCancel
OPEN_ORDER_COUNT_AFTER_CANCEL=0
IS_CONNECTED_AFTER_STOP=False

这说明 get_open_orders() 读取到了刚提交的未完成订单;撤单后再次查询,开放订单数量变为 0。

连接日志里可能还会看到 210421062158 这类市场数据场连接正常的提示,或者撤单后的 202 提示。这些是 TWS 的状态和撤单通知,不代表开放订单查询失败。

官方文档把开放订单查询分成三类:

方法中文含义适合场景
reqOpenOrders()查询这个客户端可以看到的开放订单普通策略程序最常用
reqAllOpenOrders()查询所有 API 客户端提交的开放订单多个 API 程序同时连接同一个 TWS 时使用
reqAutoOpenOrders(True)clientId=0 绑定之后的 TWS 手工订单需要 API 接管手工订单时使用

get_open_orders() 封装的是 reqOpenOrders(),它最适合新手和普通策略系统:谁提交订单,谁查询和管理订单,边界清楚。

TWS API 里,订单不是只按账户归属,还和 API 客户端有关。

情况结果
clientId=955 提交订单,再用同一个连接查询通常可以看到这笔订单
用另一个普通 clientId 查询不一定能看到或管理这笔订单
reqAllOpenOrders() 查询可以查看所有 API 客户端提交的开放订单
clientId=0 并启用自动绑定可以绑定部分 TWS 手工订单,随后 API 才能管理

如果你的系统只做自动策略,建议每个策略使用固定的 clientId,并把 orderIdpermIdorderRef 记录到自己的日志或数据库。这样程序重启后,才能把 TWS 返回的订单和本地策略订单对应起来。

开放订单查询常常会同时涉及 openOrder()orderStatus(),两者含义不同:

回调主要内容适合用来做什么
openOrder()合约、订单参数、订单状态对象恢复订单列表、展示订单详情
orderStatus()成交数量、剩余数量、平均成交价、状态变化监听订单生命周期
openOrderEnd()本轮开放订单发送结束判断这次查询已经收齐

只看 openOrder() 不够,因为它更像“订单详情快照”;真正判断是否成交、剩余多少、是否取消,仍然要结合 orderStatus()

字段示例中文解释
contract.symbolAAPL合约代码
contract.secTypeSTK证券类型,STK 表示股票
contract.exchangeSMART路由或交易所
order.actionBUY买入或卖出
order.orderTypeLMT订单类型,LMT 表示限价单
order.totalQuantity1委托数量
order.lmtPrice1.0限价单价格
order.tifDAY有效期,DAY 表示当日有效
order.orderRefDOC_OPEN_ORDERS_TEST自定义订单标记,方便日志追踪
orderState.statusPreSubmittedTWS 看到的订单状态
现象常见原因处理方式
返回 0 条开放订单没有活动订单,或订单已经成交/取消到 TWS 订单窗口确认;需要历史成交时用成交查询
刚撤单后还能看到订单状态可能还在 PendingCancel等待几秒后重新查询,或继续监听 orderStatus()
看不到手工订单普通 clientId 不会自动接管 TWS 手工订单了解 clientId=0reqAutoOpenOrders(True) 和订单绑定后再使用
多个程序看到的订单不一致clientId 不同,订单可见范围不同为每个策略固定 clientId,必要时使用 reqAllOpenOrders()
查询超时TWS 没有在超时时间内返回 openOrderEnd()检查 TWS 是否在线、API 连接是否正常、是否有弹窗阻塞

IBKR Campus: TWS API Documentation