跳转到内容

提交订单

place_order_sync() 用来提交订单,并等待 orderStatus() 返回初始订单状态。它对应原始 TWS API 的:

placeOrder(orderId, contract, order)
-> openOrder(orderId, contract, order, orderState)
-> orderStatus(orderId, status, filled, remaining, ...)

同步封装会自动调用 get_next_valid_id() 取得订单 ID,然后把它写入 order.orderId

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

def place_order_sync(self, contract, order, timeout=None):
if timeout is None:
timeout = 5 if order.orderType in ["LMT", "MKT"] else 2
order_id = self.get_next_valid_id()
order.orderId = order_id
if order_id in self.order_status:
del self.order_status[order_id]
self.placeOrder(order_id, contract, order)
return self._wait_for_response(order_id, "order_status", timeout)

参数说明:

参数含义
contract要交易的合约对象
orderibapi.order.Order 订单对象
timeout等待 orderStatus() 的秒数

返回值是一个字典,来自 orderStatus() 回调,例如 statusfilledremainingavgFillPrice

限价单最少要把这些字段写清楚:

字段中文含义示例
action买卖方向"BUY""SELL"
orderType订单类型"LMT"
totalQuantity数量Decimal("1")
lmtPrice限价1.00
tif有效时间"DAY"
transmit是否发送True
whatIf是否只做预检查TrueFalse

实际下单前建议先使用 whatIf=True 做预检查。它会让 TWS 评估保证金变化和订单合法性,但不会形成真实可成交订单。

下面代码只做订单预检查,不提交真实订单。示例价格故意使用很低的限价,避免误以为这是交易建议。

from decimal import Decimal
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 limit_order(action: str, quantity: str, limit_price: float) -> Order:
order = Order()
order.action = action
order.orderType = "LMT"
order.totalQuantity = Decimal(quantity)
order.lmtPrice = limit_price
order.tif = "DAY"
order.whatIf = True
order.transmit = True
return order
app = TWSSyncWrapper(timeout=10)
try:
if not app.connect_and_start("127.0.0.1", 7497, 951):
raise RuntimeError("连接 TWS API 失败")
try:
status = app.place_order_sync(
stock_contract("AAPL"),
limit_order("BUY", "1", 1.00),
timeout=10,
)
print(status)
except ResponseTimeout:
# whatIf 预检查可能只返回 openOrder/orderState,不一定返回 orderStatus。
for order_id, item in app.open_orders.items():
state = item["orderState"]
print(f"ORDER_ID={order_id}")
print(f"ORDER_STATE_STATUS={state.status}")
print(f"INIT_MARGIN_CHANGE={state.initMarginChange}")
print(f"MAINT_MARGIN_CHANGE={state.maintMarginChange}")
print(f"EQUITY_WITH_LOAN_CHANGE={state.equityWithLoanChange}")
finally:
app.disconnect_and_stop()

使用 TWS 模拟账户、127.0.0.1:7497、独立 clientId 检查 whatIf=True 预检查时,可能返回 openOrder 和保证金变化,但不一定返回 orderStatus(),因此同步等待可能超时:

CONNECTED=True
ORDER_STATUS_TIMEOUT=True
OPEN_ORDER_COUNT=1
OPEN_ORDER_ID=1
ORDER_STATE_STATUS=PreSubmitted
INIT_MARGIN_CHANGE=96.21
MAINT_MARGIN_CHANGE=87.46
EQUITY_WITH_LOAN_CHANGE=95.19999999995343
IS_CONNECTED_AFTER_STOP=False

随后重新连接查询开放订单:

CONNECTED=True
OPEN_ORDER_COUNT=0
IS_CONNECTED_AFTER_STOP=False

这说明 whatIf=True 没有留下真实开放订单。它适合做下单前验证,但不适合用 place_order_sync()orderStatus() 作为唯一成功条件。

如果不设置 order.tif,TWS 返回:

ERROR 1 ... 10052 无效的“有效时间”:空白

所以限价单示例里明确写了:

order.tif = "DAY"

新手下单时不要只填方向、数量和价格。订单有效时间、是否发送、是否预检查也要明确。

真实提交订单时,把 whatIf 改成 False

order.whatIf = False
status = app.place_order_sync(contract, order, timeout=10)
print(status["status"])

这会发送订单到 TWS。即使是模拟账户,也建议先在 TWS 界面确认订单预防设置、价格、数量和合约。真实账户不要直接运行从文档复制的下单代码。

place_order_sync() 等待的是 orderStatus()。常见字段如下:

字段中文含义
orderId订单 ID
status订单状态,例如 SubmittedFilledCancelled
filled已成交数量
remaining剩余数量
avgFillPrice平均成交价
permIdIBKR 永久订单 ID
parentId父订单 ID
lastFillPrice最近成交价
clientIdAPI 客户端 ID
whyHeld被挂起原因

订单状态可能重复回调,也可能先收到 openOrder() 再收到 orderStatus()。正式系统要把订单状态当作事件流处理,不要只依赖一次返回。

现象常见原因处理方式
10052 无效的“有效时间”没有设置 order.tif对日内限价单设置 order.tif = "DAY"
what-if 后 ResponseTimeout只返回了 openOrder/orderState,没有返回 orderStatusapp.open_orders 读取预检查结果
订单立即被拒绝合约、价格、权限或订单预防设置不满足要求先用 whatIf=True 和 TWS 界面检查
下错合约Contract 定义不够精确先用 get_contract_details() 确认 conId 和主交易所
价格格式被拒绝不符合 minTick用合约详情里的 minTick 校验限价

IBKR Campus: TWS API Documentation