In this lesson we discuss how orders can be placed, monitored, modified, and cancelled from the TWS API. To demonstrate the essential components necessary to place an order, a simple Python program is introduced which places an AAPL order to a paper account, and then prints order status messages to the console. Important topics associated with placing and monitoring orders from the API, including the master client ID, the Order Efficiency Ratio (OER), and the API maximum message rate are introduced. Finally, we address a few special cases in which commissions and fees are different for API orders than for orders created directly in an IBKR trading application.
A common reason to use the TWS API is to place orders to IBKR account(s) from third party or custom software. This might be part of an automated strategy, or caused by a manual user action in the API client’s graphical user interface. In this lesson we will discuss the placeOrder function in the API EClient class and describe how it used for order placement, as well as those functions which are used to monitor order status and execution information.
For reference, there is a section of the API reference guide which documents these functions, and has many examples of defining different types of orders.
Essentially any order type which can be placed from TWS can also be placed from the API. This includes advanced order types such as IBAlgos, bracket orders, and conditional orders. Most, but not all, order attributes can also be used with the TWS API. In general, order attributes must be set from the API by defining different fields with the API Order class, however there are also some attributes which will be read from the presets in the TWS or IB Gateway session to which the API client is connected.
Interactive Brokers offers over 60 types of orders and attributes, and provides access to more than a hundred exchanges worldwide. This leads to an immense possible range of combinations of order types, instruments, and exchanges. The best tool to use to check if a particular combination of order type, instrument, and attribute is valid is TWS itself. Before creating a complex order from the API, it is recommended to first check if the order can be created in a TWS Order Ticket. If the combination is invalid, generally this will be indicated by TWS not displaying or greying out the invalid order type and/or attribute in that combination.
For a demonstration of invoking the placeOrder function and receiving the associated callbacks for monitoring orders, we will place an order for the US AAPL stock to a paper account using a simple program.
Before placing any API order to a live account, it is recommended to first place the order in a paper account to verify that it is being placed as intended.
Paper accounts are offered to all IBKR account holders, and demo accounts can be accessed even before a live account is opened.
AAPL Limit Order Example.
Note: It is recommended to try all orders first in a paper trading account.
from ibapi.client import EClient from ibapi.wrapper import EWrapper from ibapi.contract import Contract from ibapi.order import * from threading import Timer class TestApp(EWrapper, EClient): def __init__(self): EClient.__init__(self, self) def error(self, reqId , errorCode, errorString): print("Error: ", reqId, " ", errorCode, " ", errorString) def nextValidId(self, orderId ): self.nextOrderId = orderId self.start() def orderStatus(self, orderId , status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice): print("OrderStatus. Id: ", orderId, ", Status: ", status, ", Filled: ", filled, ", Remaining: ", remaining, ", LastFillPrice: ", lastFillPrice) def openOrder(self, orderId, contract, order, orderState): print("OpenOrder. ID:", orderId, contract.symbol, contract.secType, "@", contract.exchange, ":", order.action, order.orderType, order.totalQuantity, orderState.status) def execDetails(self, reqId, contract, execution): print("ExecDetails. ", reqId, contract.symbol, contract.secType, contract.currency, execution.execId, execution.orderId, execution.shares, execution.lastLiquidity) def start(self): contract = Contract() contract.symbol = "AAPL" contract.secType = "STK" contract.exchange = "SMART" contract.currency = "USD" contract.primaryExchange = "NASDAQ" order = Order() order.action = "BUY" order.totalQuantity = 10 order.orderType = "LMT" order.lmtPrice = 185 self.placeOrder(self.nextOrderId, contract, order) def stop(self): self.done = True self.disconnect() def main(): app = TestApp() app.nextOrderId = 0 app.connect("127.0.0.1", 7497, 9) Timer(3, app.stop).start() app.run() if __name__ == "__main__": main()
The parts of this sample program for order placement will look very familiar if you’ve viewed the previous lessons, which demonstrated the reqContractDetails, reqMktData, and reqHistoricalData functions. In this program we again create a TestApp class which derives from both EClient and EWrapper, but here instead override the functions in EWrapper which are related to placing and monitoring orders, namely nextValidId, orderStatus, openOrder, and execDetails.
The callback nextValidId is used to receive the next valid order ID which could be used by an API client at that particular moment to place a new order. Order IDs larger than this value would also be accepted. The nextValidId callback is invoked in response to the API client calling EClient.reqIds(), and additionally, is invoked immediately after a connection is complete at the beginning of a program. Here we demonstrate how it is best to wait for the nextValidId callback before sending any messages to TWS, in this case with the placeOrder function. After connection, the sample program enters a run loop which just checks a message queue for any inbound messages. When it finds a message for nextValidId, it invokes that overridden callback with the next valid order Id at that moment. The app stores the next valid ID in a local variable, and then calls the start() function to indicate outgoing messages can now be sent.
In the start function here we need to define the objects which are passed as parameters to placeOrder. For the order ID we will use the next valid ID has already been received. The other arguments are the Contract object, which uniquely defines a financial instrument in IBKR’s database, and the Order object which defines how we would like an order placed for that instrument. Included with the sample program Program.py that is distributed with the API download there are two files called ContractSamples.py and OrderSamples.py which have many examples of defining contracts and orders.
To uniquely define the AAPL Nasdaq stock, here we will define the fields symbol, security type, primary exchange, and currency. We will then also define the exchange field as ‘SMART’ to indicate we want to SMART-route the order using IBKR’s proprietary Smart-routing algorithm. The Smart-routing algorithm considers all available exchanges where the security trades. For the Order object we have decided to place a limit order, so in addition to the fields which are almost always defined, or the totalQuantity (which is the size of the order), the action (Buy or Sell) and the order type (LMT for limit in this case), we also need to specify a limit price. Its important to note when defining order prices for stocks that there is minimum increment which can be used. For AAPL stock for instance, this is 1 cent, so orders can’t have prices specified with more than two decimal places. There is more information about finding the minimum increment for different instruments in the API reference guide.
Now that we have the order ID, Contract object, and Order object, we can invoke placeOrder. After TWS receives a valid order, it will begin sending messages back to the callback functions orderStatus, openOrder, and execDetails, to indicate an order’s status and any changes in the order status which occur. For instance in this case we would expect to see for an AAPL LMT order placed during market hours that there will be an orderStatus callback with status ‘Submitted’, an openOrder callback with the order details, and then eventually, possibly an execDetails callback if the order executes. There will typically be multiple orderStatus callbacks. In some cases these can be duplicate orderStatus callbacks which should be filtered out by the API client. In the case of partial fills, there would be a separate execDetails, as well as a orderStatus typically for each partial fill.
In this example, we have a simple timer set before entering the run loop which causes the disconnect() function to be called after 3 seconds to make sure we have a clean disconnection. A production application would probably stay connected for longer periods.
In addition to receiving order status updates about orders an API client has submitted, the API client can also be designed to receive information about orders placed by other means, such as in TWS manually or by other API clients. This can be done in several ways:
- An API client can invoke the function reqAllOpenOrders to receive a snapshot of order status information for all orders in the account at that moment, or,
- The API client can ‘bind’ orders which don’t yet have an API order ID using the function reqOpenOrders, or reqAutoOpenOrders. The function reqOpenOrders is used to bind current orders, whereas the function reqAutoOpenOrders can be used to bind orders which will be placed in the future. A bound order can then be cancelled/modified.
- By using the Master Client ID setting in TWS or IB Gateway configuration. The designated master client will automatically receive order status updates for all open orders.
To modify an open order, an API client would invoke the placeOrder function with the order ID of the open order, and the same contract object and order object as the open order except with the field changed which is to be modified. Generally, this would be the order price or size.
Limitations on API order placement
From the API there is a rate limit of 50 messages per second which can be sent from an API client to TWS or IB Gateway. This limit only applies to outgoing messages, and not to incoming messages sent to the API client in the opposite direction. Functions in EClient such as placeOrder are associated with a single outgoing message, so an API program could send at most 50 orders per second if it is sending no other messages. Additionally, it is important to bear in mind the Order Efficiency Ratio (OER) which tracks the ratio of messages sent, or submissions, modifications, and cancellations, to the number of orders which actually execute. In general, this ratio is expected to be about 20 or less, and it will be tracked by the IBKR servers automatically.
Commissions for API Orders
Executions which result from API orders in general have the same commissions as executions for orders placed by any other means. One exception is for direct (as opposed to Smart-) routed US stock orders. Executions from direct-routed stock orders have a commission of three quarters of a penny per share whereas executions from Smart-routed orders would have a commission of half of a penny per share under the fixed commission structure. Additionally, there can be a fee for cancelling European futures orders from the API. More information is available on the website.
In addition to execution and commission information available in real time to the associated connected API clients, it is also possible to query executions in the account using the reqExecutions() function. For much older execution data, it is possible to gain programmatic access using the Flex Web Service, or by statements in Account Management.
Disclosure: Interactive Brokers
The analysis in this material is provided for information only and is not and should not be construed as an offer to sell or the solicitation of an offer to buy any security. To the extent that this material discusses general market activity, industry or sector trends or other broad-based economic or political conditions, it should not be construed as research or investment advice. To the extent that it includes references to specific securities, commodities, currencies, or other instruments, those references do not constitute a recommendation by IBKR to buy, sell or hold such investments. This material does not and is not intended to take into account the particular financial conditions, investment objectives or requirements of individual customers. Before acting on this material, you should consider whether it is suitable for your particular circumstances and, as necessary, seek professional advice.
Supporting documentation for any claims and statistical information will be provided upon request.
Any stock, options or futures symbols displayed are for illustrative purposes only and are not intended to portray recommendations.
Disclosure: API Examples Discussed
Throughout the lesson, please keep in mind that the examples discussed are purely for technical demonstration purposes, and do not constitute trading advice. Also, it is important to remember that placing trades in a paper account is recommended before any live trading.