This website uses cookies to collect usage information in order to offer a better browsing experience. By browsing this site or by clicking on the "ACCEPT COOKIES" button you accept our Cookie Policy.

Duration: 13:09

Level: Intermediate

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, and the API maximum message rate are introduced.

Read More

Study Notes:

A common reason to use the Trader Workstation API is to place an order to an Interactive Brokers’ account from a third party or custom software. This might be part of an automated strategy or caused by a manual user interaction in an API client’s graphical user interface.

In this lesson we will discuss the placeOrder function in the API EClient class, describe how it is used for order placement, as well as describing those functions which were used to monitor order stats and execution information.

Essentially, any order type which we place from TWS can also be placed from the API. This includes advanced order types such as IB Algos, bracket orders and conditional orders. Most order attributes from TWS can also be used with the TWS API. In general, order attributes must be set from the API by defining different fields within the API order class when an order is sent. However, there are also some attributes which will be read from the presets in the session of TWS or the IB Gateway to which the API client is connected.

Interactive Brokers offers an array of orders and attributes and provides access to more than 100 exchanges worldwide. This leads to numerable combinations of order types, instruments and exchanges. The best tool to use and check if a particular combination of order type, instrument and attribute is valid is in TWS itself.

Before creating a particularly complex order from the API, it is always recommended to first check if the same order can be created in TWS Then, if the combination isn’t valid, this will be indicated by TWS because either the order type will be greyed out or not displayed for the combination.

For a simple demonstration of invoking the placeOrder function and receiving the associated callbacks for monitoring orders, we will show how to place an order in the paper account for AAPL stock using a simple program.

Before placing any order to a live account, it is recommended to first place the order in the paper account to verify your order is being placed as intended.

Paper accounts are offered to all Interactive Brokers account holders and demo accounts can be accessed even before a live account is opened.  

Here, I’ve created a file called placeOrder.py which demonstrates how to place the AAPL order through the API.

In this file, we will create the test class which drives from both EClient and EWrapper. But instead of overriding the functions as we did previously, we will override functions related in EWrapper for placing and monitoring orders. Namely nextValidId, orderStatus, openOrder and execDetails or execution details.

The callback nextValidID located at the top is used to receive the next valid order ID for the API client to place a new order.

The next valid ID callback is invoked in response to the API client either by calling the function’s reqIds in the EClient class or invoked after the initial connection is completed.

For this lesson, we will continue using AAPL as our contract. And while I could type out my contract object and put it directly into my order request later, this example can show off some benefit of using a combined class for EClient and EWrapper. I can use my returned contractDetails variable from EWrapper.contractDetails, and specify “contractdetails.contract” to use the contract object directly.

We will start the lesson by placing a simple market order. To get started, I will need to start a process similar to our contracts by creating an order object. I will call this “myorder”. Next, we will need to cover a few attributes that will always need to be included in our orders. I will start with myorder.orderId and set this equal to the orderId variable from the nextValidId method.

Next, I will dictate my action, using myorder.action. In this case, I will set the value to BUY, though you may enter SELL here if that is preferred. Then, I will include my order type, and set this equal to “MKT” for market order.

And then we will end by specifying my quantity. To do so, we will enter myorder.totalQuantity and set this equal to 10. And those are all the required values to place a simple order. We will discuss additional flags later, but this is simply the minimum.

Now that we have our contract object, and our order object, we are ready to move on to our order placement. Here we can make a request to EClient’s placeOrder method. To do so, I will type self.placeOrder. Then in parentheses, I will reuse my orderId as my requestId, then I will specify my contract object, then my order object.

That is all that is needed to place an order. Unlike requesting market data or contract details, we technically do not require that any EWrapper method be called. I can look in Trader Workstation and see that this order has been placed.

However, I think we may want to see details on our orders returned to us after we submit them. Let’s first create a limit order to better showcase these fields.

I will keep most of my order object the same as before, with a few key exceptions. First, I will change my action to “SELL” instead of “BUY”.

After that I will move on to Time in Force, or TIF. I will be using “GTC”, though this field has the same options as TWS, such as MOC for market on close. I would note that if no TIF is specified, it will use DAY order by default.

Then, I can change my order type to LMT instead of MKT.

And finally, I will use myorder.lmtPrice to specify my limit value. For AAPL, I will specify 144.80

As we could see from our contract details request, all contracts have a minimum tick value. For AAPL stock, for instance, this is one cent min tick, so orders can’t have prices specified with more than two decimal places or less than one cent. There is more information about finding the minimum increment for different instruments in the API reference guide.

Now that we have the order ID, the contract object and the order object, we can invoke place order. After TWS receives a valid order, it will begin sending back messages to the callback functions, order status, open order and execution details to indicate an order status as well as any changes in the order status, which occur.

Open Orders

The openOrder method will show us details whenever an order is placed. We will see the full order and contract details of a given order after it has been placed. For instance, in this case we would expect to see an AAPL limit order there with a time in force of GTC and an order price of 144.80 USD.

It is important to note that openOrder also returns the orderState object. orderState will include values such as commission, initial margin, and maintenance margin. Just like we did with contractDetails before, we can review the order_state.py file in the source code to see what other flags can be requested specifically.

Now, in addition to the openOrder function, we will also want to include the orderStatus method. While openOrder provides information on an order once it is placed, orderStatus provides information on the order thereafter. After every submission of an order, as soon as the order is valid usually you would see an order status callback which would be either pre-submitted, submitted or filled. Sometimes there will be duplicates which might need to be filtered out by the API client.

Order Executions

If the order executes there will always be execDetails or execution details for every partial fill. This can be thought of as the summary of the order. We can review the orderId, the executionId, information on the contract, information on the average price, and so on.

So, if there is more than one fill for a particular order you would see multiple callbacks for exec details. The callback would have information such as the order ID, which would be different than the API order ID. This is an order ID which is unique in the account and generated by TWS.

You would see the number of shares which have executed. You would also see a last liquidity flag which would tell us if this execution either added or removed liquidity from the market.

I will go ahead and run the script and that should immediately place the order for AAPL stock. A sell order for ten shares at the limit price of 144.00.

When we scroll down to the bottom, we can see that we receive an immediate execution. That’s because the current price of AAPL is at about 144.75 and this is during market hours, so the order immediately became active.

Before that occurred, the callback we received was open order. Open order callback let us know the details of the order.

The next orderStatus we receive will be a filled status because the order filled pretty much immediately, at least in the paper trading simulation engine and that tells us how many shares filled, how many are remaining, and also the fill price.

We also received execution details more or less simultaneously with that order status so there’s information like the exact execution details ID as well as the same information about the number of shares which filled and the filled price.

Modify Orders

Now let’s say we want to modify an order. Because we included the EWrapper callbacks for our order, we can receive our order ID, and easily modify this order whenever we need. We can simply return to our order object with our problematic orderId, change our orderId from nextValidId’s orderId, and use it here. Now, any changes applied to this order submission will modify our original order.

While I may be using a very simple example here with very human error, I would like to emphasize that this process can all be done programmatically for on-the-fly adjustments to your orders to coincide with the market, or other more complex examples.

Let’s go ahead and walk through this process. Let’s say I placed an order for $1490.00 instead of my $149.00 example. Just a simple typo with very big repercussions all because I missed the decimal place. Because I have the orderId from that request in my callback from before, I can modify this order. I can change my order to use orderId 15 again, then put in the correct price. Now, if I go ahead and put $149.00 in my limit price value and then resubmit the order, I can run my code again, and we can see that this order updated. And if you had any doubts, we can return to Trader Workstation and see that this order has updated there as well.

These are just some order types that Interactive Brokers offers through the Trader Workstation, and you are welcome to explore our wide array of available offerings notated in our documentation.

This concludes our video on Basic Orders and Order Modification in the TWS API. Thank you for watching, and we look forward to having you join us for more TWS Python API lessons.

TWS API Online Documentation

Available Order Types & Algos using TWS API

Retrieving current active Orders

Order Management

Minimum Price Increment

Checking Margin Changes

Order Efficiency Ratio (OER)

Place Order

from ibapi.client import *
from ibapi.wrapper import *

class TestApp(EClient, EWrapper):
    def __init__(self):
        EClient.__init__(self, self)

    def nextValidId(self, orderId: OrderId):
        
        mycontract = Contract()
        mycontract.symbol = "AAPL"
        mycontract.secType = "STK"    
        mycontract.exchange = "SMART"
        mycontract.currency = "USD"

        self.reqContractDetails(orderId, mycontract)
        
    def contractDetails(self, reqId: int, contractDetails: ContractDetails):
        print(contractDetails.contract)

        myorder = Order()
        myorder.orderId = reqId
        myorder.action = "SELL"
        myorder.tif = "GTC"
        myorder.orderType = "LMT"
        myorder.lmtPrice = 144.80
        myorder.totalQuantity = 10

        self.placeOrder(myorder.orderId, contractDetails.contract, myorder)


    def openOrder(self, orderId: OrderId, contract: Contract, order: Order, orderState: OrderState):
        print(f"openOrder. orderId: {orderId}, contract: {contract}, order: {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):
        print(f"orderId: {orderId}, status: {status}, filled: {filled}, remaining: {remaining}, avgFillPrice: {avgFillPrice}, permId: {permId}, parentId: {parentId}, lastFillPrice: {lastFillPrice}, clientId: {clientId}, whyHeld: {whyHeld}, mktCapPrice: {mktCapPrice}")

    def execDetails(self, reqId: int, contract: Contract, execution: Execution):
        print(f"reqId: {reqId}, contract: {contract}, execution: {execution}")


app = TestApp()
app.connect("127.0.0.1", 7497, 100)
app.run()


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.

trading top
Translate »