作者:yunjinqi
类别:教程
日期:2022-01-03 22:16:25
阅读:3458 次
消耗积分:0 分
Order Management
下一个有效标识符
也许在成功连接到TWS后收到的最重要的事件是IBApi.EWrapper.nextValidId,它也在调用IBApi.EClient.reqIds方法后触发。顾名思义,nextValidId 事件提供下订单所需的下一个有效标识符。此标识符只不过是序列中的下一个数字。这意味着,如果有单个客户端应用程序向帐户提交订单,则不必在每次需要提交新订单时都获取新的有效标识符。将从 nextValidId 方法接收的最后一个值增加一个就足够了。例如,如果第一个 API 订单的有效标识符为 1,则下一个有效标识符将为 2,依此类推。
但是,如果有多个客户端应用程序连接到一个账户,则必须使用具有新订单的订单 ID,该订单 ID 大于在 openOrder 或 orderStatus 回调中返回给客户端应用程序的所有先前订单 ID。例如,如果客户端设置为主客户端,它将自动接收来自其他客户端的订单的订单状态和交易回调。在这种情况下,就地使用的任何 orderIDOrder 都必须大于这些状态回调中返回的 orderID。或者,如果客户端使用 reqAllOpenOrders 函数,则该客户端下达的后续订单的订单 ID 必须大于由于该函数调用而返回的所有订单的订单 ID。如果客户端应用程序丢失了对序列的跟踪,则始终可以使用IBApi.EClient.reqIds方法。
# The parameter is always ignored.self.reqIds(-1)
上述内容将导致IBApi.EWrapper.nextValidId回调被调用:
class TestWrapper(wrapper.EWrapper):
###
def nextValidId(self, orderId: int):
super().nextValidId(orderId)
logging.debug("setting nextValidOrderId: %d", orderId)
self.nextValidOrderId = orderId print("NextValidId:", orderId)
下一个有效标识符在 TWS 会话之间是持久的。
如有必要,您可以在"API 设置"对话框中重置订单 ID 序列。但请注意,只有在没有活动的 API 订单时,才能重置订单序列 ID。
下订单
订单通过IBApi.EClient.placeOrder方法提交。从下面的代码片段中,请注意保存 nextValidId 的变量是如何自动递增的:
self.simplePlaceOid = self.nextOrderId()self.placeOrder(self.simplePlaceOid, ContractSamples.USStock(),
OrderSamples.LimitOrder("SELL", 1, 50))
正确提交订单后,TWS将立即开始通过IBApi.EWrapper.openOrder和IBApi.EWrapper.orderStatus发送有关订单活动的事件。
执行分配订单的顾问将收到分配订单本身的执行详细信息和佣金。要接收特定子账户的分配详细信息和佣金IBApi.EClient.req可以使用执行。
订单可以发送到TWS,但不能传输到IB服务器,方法是将订单类中的IBApi.Order.Transmit标志设置为**False。**未发送的订单将仅在该TWS会话中可用(不适用于其他用户名),并将在重新启动时清除。此外,它们可以被取消或从 API 传输,但在它们仍处于"未传输"状态时不被查看。
openOrder 回调
IBApi.EWrapper.openOrder方法提供一个IBApi.Order对象,表示系统内的未结订单。此外,IBApi.EWrapper.openOrder返回一个IBApi.OrderState对象,该对象用于返回估计的交易前保证金和佣金信息,以响应调用IBApi.EClient.placeOrder,其IBApi.Order对象的标志为IBApi.Order.WhatIf标志设置为 True。另请参阅:检查保证金变化。
class TestWrapper(wrapper.EWrapper):
###
def openOrder(self, orderId: OrderId, contract: Contract, order: Order,
orderState: OrderState):
super().openOrder(orderId, contract, order, orderState)
print("OpenOrder. PermId: ", order.permId, "ClientId:", order.clientId, " OrderId:", orderId,
"Account:", order.account, "Symbol:", contract.symbol, "SecType:", contract.secType,
"Exchange:", contract.exchange, "Action:", order.action, "OrderType:", order.orderType,
"TotalQty:", decimalMaxString(order.totalQuantity), "CashQty:", order.cashQty,
"LmtPrice:", order.lmtPrice, "AuxPrice:", order.auxPrice, "Status:", orderState.status)
order.contract = contract
self.permId2ord[order.permId] = order
订单状态回调
IBApi.EWrapper.orderStatus方法包含有关订单执行当前状态的所有相关信息(即已成交和挂单金额、成交价格等)。
class TestWrapper(wrapper.EWrapper):
def orderStatus(self, orderId: OrderId, status: str, filled: Decimal,
remaining: Decimal, avgFillPrice: float, permId: int,
parentId: int, lastFillPrice: float, clientId: int,
whyHeld: str, mktCapPrice: float):
super().orderStatus(orderId, status, filled, remaining,
avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice)
print("OrderStatus. Id:", orderId, "Status:", status, "Filled:", decimalMaxString(filled),
"Remaining:", decimalMaxString(remaining), "AvgFillPrice:", avgFillPrice,
"PermId:", permId, "ParentId:", parentId, "LastFillPrice:",
lastFillPrice, "ClientId:", clientId, "WhyHeld:",
whyHeld, "MktCapPrice:", mktCapPrice)
自动订单状态消息(不调用 reqOpenOrders 或 reqAllOpenOrders)
具有提交订单的客户端 ID 的客户将收到订单状态消息,指示订单状态的更改。
具有主客户端 ID(在 TWS/IBG 中设置)的客户端将接收所有客户端的订单状态消息。
客户端 ID 0 将接收其自己的(客户端 ID 0)订单以及从TWS手动提交的订单的订单状态消息。
可能的订单状态
**ApiPending **- 表示订单尚未发送到IB服务器,例如,如果接收证券定义时出现延迟。不常见的接收。
PendingSubmit - 表示订单是从TWS发送的,但尚未收到 目的地已收到订单 的确认。最常见的原因是交易所是休市的。
PendingCancel -表示已发送取消订单的请求,但尚未收到取消订单的确认。
PreSubmitted - 表示模拟订单类型已被 IB 系统接受,并且尚未选择此订单。该命令在IB系统中保持,直到满足提交的标准。此时,订单将传输到指定的订单目的地。
Submitted - 表示您的订单已在订单目的地被接受并且正在运行。
ApiCancelled - 在提交订单后和确认订单之前,API 客户端可以请求取消订单,从而产生此状态。
Cancelled - 表示您的订单已被IB系统确认取消。当IB或目的地拒绝您的订单时,可能会意外发生这种情况。例如,如果您的订单需要接受价格检查,则可能会被取消,如下单注意事项中所述
Filled - 表示订单已完全填充。
Inactive - 表示订单不起作用,可能的原因包括:
此错误可能是拒绝,例如规定大小拒绝。请参阅下订单注意事项
它是无效的或触发了错误。error() 函数应有相应的错误代码。
订单是卖空股票,但订单在股票被定位时被持有。
在交易所关闭时,订单在TWS中手动下单。
由于预防性设置,订单被TWS阻止,并以未传递状态显示在那里
关于IBApi.EWrapper.orderStatus的重要说明:
附加订单
高级订单(如 Bracket Orders or Hedging)涉及将子订单附加到父订单。这可以通过IBApi.Order.ParentId属性轻松完成,方法是将子订单的IBApi.Order.ParentId分配给现有订单的IBApi.Order.OrderId。当一个订单附加到另一个订单时,系统将保持子订单"暂停",直到其父订单完成。一旦父订单完全完成,其子订单将自动变为活动状态。
**重要:**在附加订单并防止意外执行时,最好使用 IBApi.Order.Transmit标志,如Bracket Orders中所示
如果 API 客户端连接到具有相同 TWS 用户名并使用相同的 API 客户端 ID 的 TWS 会话,则可以修改 API 订单。然后,可以使用与未结订单相同的字段调用函数 IBApi.EClient.placeOrder,但要修改的参数除外。这包括IBApi.Order.OrderId,它必须与未结订单的IBApi.Order.OrderId匹配。通常不建议尝试更改订单价格、大小和 tif 以外的订单字段(对于 DAY -> IOC 修改)。要更改其他参数,最好改为取消未结订单,然后创建一个新订单。
要修改或取消从TWS手动下达的单个订单,必须使用客户端ID 0进行连接,然后在尝试修改之前绑定订单。绑定过程为订单分配一个 API 订单 ID;在绑定之前,它将返回到API,API 订单 ID 为 0。API 订单 ID 为 0 的订单无法从 API 修改/取消。函数 reqOpenOrders 绑定当时尚未具有 API 订单 ID 的未结订单,函数 reqAutoOpenOrders 会自动绑定未来的订单。函数 reqAllOpenOrders不绑定订单。
要在连接到 TWS 的不同会话(使用与原始订单不同的用户名登录)时修改 API 订单,必须先以绑定手动 TWS 订单相同的方式绑定具有客户端 ID 0 的订单,然后才能对其进行修改。API 订单 ID 的绑定分配对于每个 TWS 用户都是独立的,因此同一订单可以针对不同的用户具有不同的 API 订单 ID。在 TWS 分配的 API 订单类中返回的 permID 可用于唯一标识帐户中的订单。
目前(从TWS版本970开始),来自API的订单绑定过程取消/重新提交在交易所工作的订单。这可能会影响订单在交易所队列中的位置。计划进行增强,以允许通过修改交换队列优先级进行 API 绑定。
可以使用函数 IBApi::EClient::cancelOrder and IBApi::EClient::reqGlobalCancel从 API 取消订单。cancelOrder 只能用于取消最初由具有相同客户 ID 的客户(或来自 TWS 的客户 ID 为 0)下达的订单。它采用一个参数,即原始订单 ID。
self.cancelorder(self.simplePlaceOid)
IBApi::EClient::reqGlobalCancel将取消所有未结订单,无论它们最初是如何下达的。
self.reqGlobalCancel()
只要订单处于活动状态,就可以使用TWS API检索它。通过TWS API提交的订单将始终绑定到他们提交的客户应用程序(即客户ID),这意味着只有提交客户才能修改所下订单。提供了三种不同的方法,以实现最大的灵活性。活动订单将通过IBApi.EWrapper.openOrder和IBApi.EWrapper.orderStatus方法返回,如openOrder 回调和OrderStatus 回调部分所述
**注意:**无法获得已取消或已完全成交的订单。
API 客户端的订单
IBApi.EClient.reqOpenOrders方法允许获取客户端应用程序提交的所有活动订单,这些客户端应用程序与订单发送到TWS的客户端 ID 完全相同。如果客户端 0 调用 reqOpenOrders,则将导致从 TWS 手动下达的当前未结订单被"绑定",即分配一个订单 ID,以便 API 客户端 0 可以修改或取消它们。在 973.07 之后的 API 版本中,将出现IBApi.EWrapper.orderBound回调,以响应新绑定的订单,指示 permID(唯一账户范围)和 API 订单 ID(特定于 API 客户端)之间的映射。在"全局配置"的 API 设置中,是默认情况下选中的"使用负数绑定自动订单"的设置,该设置将指定如何为手动TWS订单分配API订单ID。
self.reqOpenOrders()
所有提交的订单
要获取通过TWS API创建的订单,无论提交客户端申请如何,请使用IBApi.EClient.reqAllOpenOrders函数。
self.reqAllOpenOrders()
手动提交的订单
最后,IBApi.EClient.reqAutoOpenOrders只能由 ID 为 0 的客户端调用。这将导致来自TWS的未来订单被"绑定",即分配一个订单ID,以便可以通过取消订单或下订单(用于修改)功能通过客户ID 0访问它们。
self.reqAutoOpenOrders(True)
**重要提示:**只有那些与客户端 ID 0 连接的应用程序才能接管手动提交的订单
通过TWS的API设置,可以在一定程度上配置此方法的行为。如下图所示,手动下达的订单可以给出一个否定的订单ID,该ID可以轻松区分手动和API提交的订单。TWS 的工具提示进一步阐述了:
接收订单信息
活动订单将通过The openOrder回调和The orderStatus回调回调提供。当所有订单都发送到客户端应用程序时,您将收到一个IBApi.EWrapper.openOrderEnd事件:
class TestWrapper(wrapper.EWrapper):
###
def openOrder(self, orderId: OrderId, contract: Contract, order: Order,
orderState: OrderState):
super().openOrder(orderId, contract, order, orderState)
print("OpenOrder. PermId: ", order.permId, "ClientId:", order.clientId, " OrderId:", orderId,
"Account:", order.account, "Symbol:", contract.symbol, "SecType:", contract.secType,
"Exchange:", contract.exchange, "Action:", order.action, "OrderType:", order.orderType,
"TotalQty:", decimalMaxString(order.totalQuantity), "CashQty:", order.cashQty,
"LmtPrice:", order.lmtPrice, "AuxPrice:", order.auxPrice, "Status:", orderState.status)
order.contract = contract
self.permId2ord[order.permId] = order ###
def orderStatus(self, orderId: OrderId, status: str, filled: Decimal,
remaining: Decimal, avgFillPrice: float, permId: int,
parentId: int, lastFillPrice: float, clientId: int,
whyHeld: str, mktCapPrice: float):
super().orderStatus(orderId, status, filled, remaining,
avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice)
print("OrderStatus. Id:", orderId, "Status:", status, "Filled:", decimalMaxString(filled),
"Remaining:", decimalMaxString(remaining), "AvgFillPrice:", avgFillPrice,
"PermId:", permId, "ParentId:", parentId, "LastFillPrice:",
lastFillPrice, "ClientId:", clientId, "WhyHeld:",
whyHeld, "MktCapPrice:", mktCapPrice)
###
def openOrderEnd(self):
super().openOrderEnd()
print("OpenOrderEnd")
logging.debug("Received %d openOrders", len(self.permId2ord))
订单绑定通知
当订单由 API 客户端 0 绑定时,将回调到IBApi::EWrapper::orderBound.
这表示 API 订单 ID 和 permID 之间的映射。
******尚未实施
def orderBound(self, orderId: int, apiClientId: int, apiOrderId: int):
super().orderBound(orderId, apiClientId, apiOrderId)
print("OrderBound.", "OrderId:", orderId, "ApiClientId:", apiClientId, "ApiOrderId:", apiOrderId)
当订单全部或部分成交时,IBApi.EWrapper.execDetails和IBApi.EWrapper.commissionReport事件将传递IBApi.Execution和IBApi.CommissionReport对象。这允许获得订单执行和由此产生的佣金的全部信息。
**重要:**要接收所有客户的佣金报告,必须以主客户端 ID 身份连接。
class TestWrapper(wrapper.EWrapper):...
def execDetails(self, reqId: int, contract: Contract, execution: Execution):
super().execDetails(reqId, contract, execution)
print("ExecDetails. ReqId:", reqId, "Symbol:", contract.symbol, "SecType:", contract.secType, "Currency:", contract.currency, execution)...
def commissionReport(self, commissionReport: CommissionReport):
super().commissionReport(commissionReport)
print("CommissionReport.", commissionReport)
请求执行
IBApi.Execution和IBApi.CommissionReport可以通过IBApi.EClient.reqExecutions方法按需请求,该方法接收IBApi.ExecutionFilter对象作为参数,以便仅获取与给定条件匹配的那些执行。可以传递空的 IBApi.ExecutionFilter对象来获取所有以前的执行。
self.reqExecutions(10001, ExecutionFilter())
一旦交付了所有匹配的执行,将触发IBApi.EWrapper.execDetailsEnd事件。
class TestWrapper(wrapper.EWrapper):
def execDetailsEnd(self, reqId: int):
super().execDetailsEnd(reqId)
print("ExecDetailsEnd. ReqId:", reqId)
**重要提示:**仅会传递自午夜以来对该特定帐户执行的执行。较旧的执行通常无法通过带有IB网关的TWS API获得。
除了TWS API的固有限制,即每秒50条消息意味着每秒最多有50个订单被发送到TWS之外,没有其他仅API的限制。然而,盈透证券要求其用户监控其订单效率比(OER),详见IBKB优化订单效率的注意事项一文。
此外,请注意,IB允许每个账户每个合约买卖上最多各有15个有效订单。
对于需要遵守MiFIR报告的EEA投资公司,以及已选择加入丰富和委托交易报告的EEA投资公司,我们在订单类别中添加了四个新的订单属性,并为TWS和IB网关全局配置添加了几个新的预设。
新的订单属性包括:
新的TWS和IB网关订单预设可以在全局配置的订单>MiFIR页面中找到,包括TWS决策者默认值,API决策者默认值和执行交易者/算法预设。
以下选项可用于"公司内部的投资决策"IBApi.Order.Mifid2DecisionMaker和IBApi.Order.Mifid2DecisionAlgo属性:
如果您符合以下条件,则无需报告此字段:
您可以使用"订单"> MiFIR 页面,通过 TWS 全局配置来配置预设以指示这一点。在这种情况下,专有帐户的订单将需要通过TWS下达。
如果您使用TWS API传输订单,并且投资决策由一个人或委托报告公司内的一群人做出,其中一人是主要决策者:
您的TWS API程序可以在每个订单上使用字段IBApi.Order.Mifid2DecisionMaker传输决策者的IB分配的短代码。您可以通过IB账户管理来定义可以成为决策者的人员。要获取IB分配给这些人员的短代码,请联系IB客户服务。
如果您的TWS API程序无法传输上述字段,并且投资决策由可被视为主要投资决策者的单个人做出或批准,则可以预先配置默认投资决策者,该决策机构将用于不存在上述字段的订单。您必须在IB账户管理中定义投资决策者,然后可以使用MiFIR>订单页面在TWS全球配置中配置默认投资决策者。
如果您使用TWS API传输订单,并且投资决策是通过算法做出的:
您的TWS API程序可以在每个订单上使用字段IBApi.Order.Mifid2DecisionAlgo传输决策者分配的IB短代码。您可以通过IB账户管理定义可以成为决策者的算法。要获取IB分配给这些人员的短代码,请联系IB客户服务。
如果您的TWS API程序无法传输上述字段,并且/或投资决策由单个或主要决策者算法做出,您可以预先配置默认的投资决策者算法,该算法将用于未发送上述字段的订单。您必须在IB账户管理中定义投资决策者,然后可以使用MiFIR>订单页面在TWS全球配置中配置默认投资决策者。
只有一个投资决策者,无论是主要人物还是算法,都应在订单上提供,或选择作为默认值。
以下选项可用于"公司内部执行"IBApi.Order.Mifid2ExecutionTrader和IBApi.Order.Mifid2ExecutionAlgo属性:
如果您使用TWS API传输在第三方交易界面中输入的订单,并且您是负责在公司内执行的交易者,则无需其他信息。
如果您的TWS API程序在没有人为干预的情况下自动将订单传送给IB,请联系IB客户服务部,将程序或程序作为算法注册IB。只有主程序或算法需要注册和识别。然后,您可以使用"订单"> MiFIR 页在 TWS 全局配置中配置默认值。
在每个订单上,您的TWS API程序可以使用现场IBApi.Order.Mifid2ExecutionAlgo(用于算法)或IBApi.Order.Mifid2ExecutionTrader(用于该人)在公司内传输算法或负责执行的人员的IB分配的短代码。
欲了解更多信息,或获取IB账户管理中定义的人员或算法的短代码,请联系IB客户服务。
要了解有关 MiFIR 交易报告义务的更多信息,请参阅欧洲经济区投资公司的 MiFIR 丰富和委托交易报告知识库文章。
价格最小变动单位
价格最小变动单位是合约可以交易的价格水平之间的最小差额。一些交易在所有价格水平上都有恒定的价格增量。但是,有些合约在交易的不同交易所有不同的最小变动单位和/或在不同价格水平下有不同的最小变动单位。在 contractDetails 类中,有一个字段"minTick",它指定在任何交易所或价格上遇到的最小变动单位。有关最小变动单位结构的完整信息,请参阅IB合约和证券搜索网站,或API v973.03和TWS 966中的API功能reqMarketRule。
当与合约对象一起使用时,函数 reqContractDetails 会将 contractDetails 对象返回到 contractDetails 函数,该函数具有工具交易的有效交易所的列表。在 contractDetails 对象中还有一个名为 marketRuleIDs 的字段,其中包含"市场规则"列表。市场规则被定义为定义给定价格的最小价格增量的规则。合约详细信息中返回的市场规则列表具有与有效交易所列表相同的市场规则列表。通过这种方式,可以确定特定交易所上合约的市场规则ID。
使用市场规则ID号,可以使用API函数 IBApi::EClient::reqMarketRule:找到相应的规则:
self.reqMarketRule(26)self.reqMarketRule(239)
该规则将返回到函数IBApi::EWrapper::marketRule
def marketRule(self, marketRuleId: int, priceIncrements: ListOfPriceIncrements):
super().marketRule(marketRuleId, priceIncrements)
print("Market Rule ID: ", marketRuleId)
for priceIncrement in priceIncrements:
print("Price Increment.", priceIncrement)
检查保证金变化
从API中,可以检查指定的交易执行如何实时更改账户的账户保证金要求。这是通过创建一个 Order 对象来完成的,该对象将IBApi.Order.WhatIf标志设置为 true。默认情况下,Order 中的 whatif 布尔值具有 false 值,但如果在 Order 对象中设置为 True,则会传递给IBApi.EClient.placeOrder,而不是将订单发送到目的地 IB 服务器,它将接受信用检查,以满足预期的交易后保证金要求。估计的交易后保证金要求将返回到IBApi.OrderState对象。
这相当于在TWS中创建订单单,单击"预览",然后在"保证金率影响"面板中查看信息。
参见:TWS保证金率影响
触发方法
IBApi.Order类中定义的触发方法指定如何触发模拟止损、止损限价和追踪止损以及条件订单。有效值为:
下表指示给定的 secType 是否与买/卖出驱动或最后驱动的触发方法兼容(方法 7 仅用在 iBot alerts)
secType | Bid/Ask-driven (1, 4, 8) | Last-driven (2, 3) | Default behavior | Notes |
---|
STK | yes | yes | Last | The double bid/ask is used for OTC stocks |
CFD | yes | yes | Last |
|
CFD - Index | yes | n/a | n/a | Ex IBUS500 |
OPT | yes | yes | US OPT: Double bid/ask, Other: Last |
|
FOP | yes | yes | Last |
|
WAR | yes | yes | Last |
|
IOPT | yes | yes | Last |
|
FUT | yes | yes | Last |
|
COMBO | yes | yes | Last |
|
CASH | yes | n/a | Bid/ask |
|
CMDTY | yes | n/a | Last |
|
IND | n/a | yes | n/a | For conditions only |
重要提示:
TWS API相关的教程
【TWS API使用教程1】—如何在自己创建的client和TWS之间创建一个连接,并请求当前的时间
【TWS API使用教程2】—如何使用 TWS API在ubuntu和windows上分别设置contract、获取contract详细信息、设置order、下单、获取持仓信息、获取账户信息
【TWS API使用教程3】—如何使用TWS API从盈透证券中设置contract及获取contract的信息?
【TWS API使用教程4】—如何使用TWS API在盈透证券中设置order?
【TWS API使用教程5】—如何使用TWS API在盈透证券中下单(place order)、获取订单信息、获取持仓、获取账户汇总信息?
【TWS API使用教程6】—如何使用TWS API在盈透证券中获取数据?
【TWS API 使用教程7】如何使用TWS API 从盈透证券中筛选满足一定条件的contract?
【TWS API 使用教程8】一个基于TWS API的简单的程序化策略
系统当前共有 404 篇文章