Close Navigation
Learn more about IBKR accounts

Websockets

Lesson 10 of 11
Duration 9:07
Level Intermediate
Close Navigation

In this lesson, we will focus on how to create a websocket for the client portal API. This will also describe how we can request market data and review live order information using this websocket.

Study Notes:

Hello, and welcome to this lesson on Websockets in the Interactive Brokers Client Portal API. In this lesson, we will be discussing how to build a websocket, and perform typical tasks like requesting market data or requesting live trade information using the Client Portal API.

Websockets documentation

To begin, let’s start by looking at our documentation page referring to our Websocket values. Just like our standard ‘endpoints’, there is a lot more to be done with websockets that what we will be able to show in this video, but our foundation will allow you to move on with any of these other details you might be interested in.

The documentation will show case how to retrieve streaming data, trades information, as well as notification details for alerts. I would also like to highlight the Websocket Playground at the bottom. While we will be building the websocket ourselves in python, as long as your client portal gateway is up and running, you can use this as a great method to test new requests. After hitting the “Connect” button, you can paste in any of the websocket requests above and send them to the websocket to test the functionality. However, I will disconnect from that, and we can start reviewing how this can be done using Python.

Building the Websocket

Before we move into the file, you will likely need to pip install “websocket-client” module. This will be rather unique from our prior programs, so I will be building this from a fresh file. After installing the websocket-client module, we will need to import “websocket”, “time” and the “ssl” modules into our new python file.

Utilizing websockets will require building out a websocket object. I will define the method on_message and set the arguments to “ws” and “message”. All we will do in this method is print the message value. After that, I will define the method on_error. Just like before, I will pass “ws” and “error” as variables. Next, I can define the method “on_close” and only pass the argument “ws”. This will only be printing the phrase “## CLOSED ##” to make sure I showcase that our websocket had closed.

Moving on to a more exciting method, I can define “on_open” and pass the “ws” argument. Inside the method, I will define a few details. I will start by simply printing “Opened connection” to acknowledge that the connection was established. Now, I will add in ‘time.sleep(3)’ to make our program pause for a few seconds to make sure everything is up and running. Now, I want to make a list, conids, and set it equal to the strings ‘265598’ and ‘8314’. This will be to request market data for AAPL and IBM.

Now I want to iterate through my conids with a for loop, ‘for conid in conids:’. In a new indented line, I can write the method ‘ws.send()’. This will reference our websocket object that was passed in our on_open method, and can send a request. Within the send method, I will pass the following, ‘smd+’+i+’+{“fields”:[“31″,”84″,”86”]}’. I would note that the formatting of single and double quotes is mandatory in this scenario. In our case, we must send the field values with their quoted values. It is worth bearing in mind that all fields that are used on the iserver/marketdata/snapshot endpoint can be used here as well. If you are interested in finding out more about this topic, please reference our prior lesson on requesting market data.

Inside our Name-Main idiom, I will define the variable, ‘ws’. I will set this equal to the ‘websocket.WebSocketApp()’ class. We will need to pass everything we have built up so far, as well as a websocket URL. Starting with our URL, I will create a string for “wss://localhost:5000/v1/api/ws”. I’ll assign the argument, ‘on_open’, to our ‘on_open’ method. Note that we are not actually passing the parentheses this time, only the function name. I will do the same with ‘on_message’ = ‘on_message’, ‘on_error’ = ‘on_error’, and finally ‘on_close’ = ‘on_close’.

Finally, I will call our websocket to run with ‘ws.run_forever()’. I will set the sslopt argument equal to ‘{“cert_reqs”:ssl.CERT_NONE}’. Much like verify=False in our other lessons, this will disable our SSL verification.

We can now run our code. I will see my “Opened connection” message, followed by a few authentication details and my account information. Eventually, I will start seeing a few responses beginning with “server_id” which will identify my requests from one another.

The ‘conidex’ and ‘conid’ fields will show my contract identifier. The ‘_updated’ field will return the epoch time of a given return. Moving along, we can see all of my field values being returned here for a given conid. Now we are able to see an ongoing stream of market data for our two contracts as new data is available.

Requesting Live Orders.

Now, let’s move on to a new example using the Live Order Updates request instead. This will be built functionally the same as our market data stream. Because of that, I will simply copy over the file for the moment, and work with that foundation.  I will simply modify my on_open method, and instead of sending out my “smd” requests, I will instead be sending ‘sor+{}’. This will key off of my currently active account, so no additional information is needed.

After running this code, I will see all of my other orders placed today. This will show the same authentication status as before, and we will see our heartbeat messages returned to let us know the websocket is still connected. But let’s see how it functions in real time. I will open my place order request from our prior lesson to submit an order to AAPL. 

Running my place order file, I will see my order_id returned, along with my current order status. If I jump back to my websocket’s console, I can see that my new order was activated, and I can see the same orderId mirrored over in my websocket. I can even see the execution return and a description on how the order filled.

Thank you for watching this lesson on websockets in the Client Portal API. If you find this lesson helpful, please check out our other lessons in the Client Portal API tutorial series.

Code Snippet – websocket_md.py

import websocket
import time
import ssl

def on_message(ws, message):
    print(message)

def on_error(ws, error):
    print(error)

def on_close(ws):
    print("## CLOSED! ##")

def on_open(ws):
    print("Opened Connection")
    time.sleep(3)
    conids = ["265598", "8314"]

    for conid in conids:
        ws.send('smd+'+conid+'+{"fields":["31","84","86"]}')

if __name__ == "__main__":
    ws = websocket.WebSocketApp(
        url="wss://localhost:5000/v1/api/ws",
        on_open=on_open,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close
    )
    ws.run_forever(sslopt={"cert_reqs":ssl.CERT_NONE})

Code Snippet – websocket_orders.py

import websocket
import time
import ssl

def on_message(ws, message):
    print(message)

def on_error(ws, error):
    print(error)

def on_close(ws):
    print("## CLOSED! ##")

def on_open(ws):
    print("Opened Connection")
    time.sleep(3)
    ws.send('sor+{}')

if __name__ == "__main__":
    ws = websocket.WebSocketApp(
        url="wss://localhost:5000/v1/api/ws",
        on_open=on_open,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close
    )
    ws.run_forever(sslopt={"cert_reqs":ssl.CERT_NONE})

Join The Conversation

If you have a general question, it may already be covered in our FAQs. If you have an account-specific question or concern, please reach out to Client Services.

7 thoughts on “Websockets”

  • Is there a python example how to send the sessionid. i use the websocket with the following url wss://api.ibkr.com/v1/api/ws

  • Is there a way to get market data for an option spread using the smd websockets command? I know that I can get the market data for the individual legs of the spread but the bid and ask of those individual legs never match the bid/ask of the actual spread in TWS. I believe TWS is doing additional calculations to figure out the bid/ask spread and was wondering if there is anyway to get this information through the web sockets api?

    Similar to how you spread orders with multiple conids, is there a way to get the bid/ask market data for a spread using the smd websockets or any other api’s?

    • Hello, thank you for reaching out. Combos and Spreads are supported for websockets. To retrieve data in this fashion, the ‘conid’ parameter of the websocket request should include the full spread details, similar to a spread order from the /iserver/account/{acctId}/orders endpoint. You can read more about the market data websocket and making a combo request here: https://ibkrcampus.com/ibkr-api-page/cpapi/#ws-sub-watchlist-data

      We hope this helps!

  • Hello there!
    I’m trying to understand the Historical Data websocket. After I subscribe to a contract, I receive the following messages:
    {“serverId”:”4379500″,”symbol”:”MARA”,”text”:”MARATHON DIGITAL HOLDINGS IN”,”priceFactor”:100,”startTime”:”20240301-18:21:00″,”high”:”2594/62.18/1″,”low”:”2582/197.09/0″,”timePeriod”:”60s”,”barLength”:60,”mdAvailability”:”S”,”mktDataDelay”:0,”outsideRth”:false,”volumeFactor”:1,”priceDisplayRule”:1,”priceDisplayValue”:”2″,”negativeCapable”:false,”messageVersion”:2,”data”:[{“o”:25.87,”c”:25.92,”h”:25.93,”l”:25.82,”v”:197.09},{“o”:25.93,”c”:25.86,”h”:25.94,”l”:25.86,”v”:62.18}],”points”:1,”travelTime”:96,”topic”:”smh+474219659″,”payload”:”{\n \”period\”: \”1min\”,\n \”bar\”: \”1min\”,\n \”source\”: \”trades\”,\n \”format\”: \”%o/%c/%h/%l/%v\”\n}\n”}
    {“serverId”:”4379500″,”tickNum”:1,”negativeCapable”:false,”data”:[{“o”:25.89,”c”:1.111}],”points”:0,”travelTime”:792,”topic”:”smh+474219659″,”payload”:”{\n \”period\”: \”1min\”,\n \”bar\”: \”1min\”,\n \”source\”: \”trades\”,\n \”format\”: \”%o/%c/%h/%l/%v\”\n}\n”}
    ….
    {“serverId”:”4379500″,”tickNum”:4,”negativeCapable”:false,”data”:[{“o”:0.01}],”points”:0,”travelTime”:5725,”topic”:”smh+474219659″,”payload”:”{\n \”period\”: \”1min\”,\n \”bar\”: \”1min\”,\n \”source\”: \”trades\”,\n \”format\”: \”%o/%c/%h/%l/%v\”\n}\n”}

    My questions are:
    1. In the 1st update, the date 20240301-18:21:00 is delayed a couple of seconds. Is this correct? Can’t I receive more updated bars?
    2. How can I know the time of the next updates?
    3. What close = 1.111 represents in tickNum #1?
    4. And open = 0.01 in tickNum #4?

    Thanks in advance!

Leave a Reply

Your email address will not be published. Required fields are marked *

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.

The views and opinions expressed herein are those of the author and do not necessarily reflect the views of Interactive Brokers, its affiliates, or its employees.

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.

IBKR Campus Newsletters

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.