interactive-broker-python-api
interactive-broker-python-api copied to clipboard
Streaming Websocket Data
Hi Alex, Great lib, thank you for making this. After watching your video series, I'm trying to get continuous market data from IB Websocket API. I could able to connect to Client Portal gateway and also connection to websocket is successful, but I'm not able to subscribe to any quotes. Below is the code I used.
Any guidance on where I might be doing wrong/missing? Thank you.
# -*- coding: utf-8 -*-
import websocket, json
import ssl
web_socket_endpoint = "wss://localhost:5000/v1/portal/ws"
def logout(ws):
print("close")
ws.close()
def on_open(ws):
print("opened")
ws.send("s+md+59392609")
def on_message(ws, message):
print("message recieved")
try:
print(message)
except:
print("JSON Decode Failed")
def on_close(ws):
print("Connection Closed")
def on_error(ws, error):
print("error")
print(error)
try:
websocket.enableTrace(True)
WSCONNECTION = websocket.WebSocketApp(web_socket_endpoint,
on_message = on_message,
on_error = on_error,
on_close = on_close)
WSCONNECTION.on_open = on_open
WSCONNECTION.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
except Exception as e:
print(e)
capture_exception(e)
What does the subscription request look like? Also, what's the error you're getting? Keep in mind that it may be hard to test during the weekend, the API seems to give very different results on the weekend compared to the weekdays.
Hi Alex,
Here is the subscription request:
ws.send("s+md+59392609")
as mentioned here https://interactivebrokers.github.io/cpwebapi/RealtimeSubscription.html s - Subscribe md - Market Data 59392609 - conId
As you mentioned I waited until Monday morning in India when market opens at NSE and tried agin.
I don't see any errors, but I'm not getting any response in on_message function. I've market data subscription for the markets as I'm getting individual ticker details.
Whenever you got some time could you try connecting over websockets?
Thank you, Vamsi.
hey, just checking if you have endpoint for websockets in your lib? Thanks!
I have the same issue and have tried opening a ticket with IBKR last week. No answers yet.
Same issue. I can connect to the socket and send subscription messages but no response data is received.
@sandybradley @benjaminpolk @vepak
I believe that is more like a ssl cert issue. I created a self-signed-cert and managed to receive response

Code snippet:
import asyncio
import pathlib
import ssl
import websockets
import os
ssl_context = ssl.SSLContext(ssl.CERT_REQUIRED)
localhost_pem = pathlib.Path(__file__).with_name("self-signed-cert.pem")
ssl_context.load_verify_locations(localhost_pem)
# To allow https connection
if (not os.environ.get('PYTHONHTTPSVERIFY', '') and getattr(ssl, '_create_unverified_context', None)):
ssl._create_default_https_context = ssl._create_unverified_context
async def receive_messages(websocket):
while True:
try:
response = await websocket.recv()
except websockets.ConnectionClosed:
print(f"Terminated")
break
print(f"< {response}")
async def ib_websocket_connection():
uri = "wss://localhost:5000/v1/api/ws"
async with websockets.connect(
uri, ssl=ssl_context
) as websocket:
# Send market data subscription request
await websocket.send('smd+265598+{"fields":["31","83"]}')
await receive_messages(websocket)
asyncio.get_event_loop().run_until_complete(ib_websocket_connection())
asyncio.get_event_loop().run_forever()
Hello @pandaxbacon @areed1192 , I am getting this exact same data with the "topic : system, hb : 12234567", however, this is really not the data I am looking for. I am more specifically looking for tick data.
I am using the web socket API in javascript and in my case the data comes in as a blob which I then convert to json. Can you please share your thoughts, I have been on this for some time now.
@pandaxbacon Random question, did generating the self-signed certificate alleviate issues when navigating to the login page. I remember it always was warning issues that it wasn't a secure page.
I want get the same response using websocket.WebSocketApp and run_forever. How did should will refactor the code to?
import websocket as ws
import json
import ssl
wss = 'wss://localhost:500/v1/api/ws'
conn = ws.create_connection(wss,sslopt={"cert_reqs":ssl.CERT_NONE})
conn.send('smd+265598+{"fields":["31","83"]}')
conn.recv()
hi, by any chance was someone able to resolve this issue and if yes could you share the code ? i used ws:// connection instead of wss:// (no encryption in transit between client and gateway) but still getting only Unsolicited Message Types. if i sent 'smd+265598+{"fields":["31","83"]}' i receive answer always only once.
Hi. I think I made the code work and I am successfully receiving the streaming prices.
- The endpoint should be "wss://localhost:5000/v1/api/ws" instead of "wss://localhost:5000/v1/portal/ws"
- There is no need in generating other custom certificate. You just need to pass 'sslopt={"cert_reqs": ssl.CERT_NONE}' ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
- Main problem with the making things work is to wait for the time when the server is ready. After initial connection, you need to wait for the server to send following messages: First message: {"topic":"system","success":"yourusername","isFT":false,"isPaper":false} Second message: {"topic":"sts","args":{"authenticated":true, "competing":false, "message":"", "fail":"", "serverName":"yourservername", "serverVersion":"Build 10.20.0d, Dec 5, 2022 6:31:27 PM", "username":"yourusername"}}
- Only after receiving "topic":"sts" with "authenticated":true I am sending smd+270639+{"tempo":1000,"snapshot":true,"fields":["31","70","71","82","84","85","86","87","88","7295","7296","7674","7675","7676","7677","TimestampBase","TimestampDelta","6509"]}
You can see my working code below. Hope it helps.
import json, os, websocket, time, syslog, ssl
from dotenv import load_dotenv
from datetime import datetime
#from lib.tickle import tickle
def subscribe():
start_time = time.time()
def on_message(ws, binarymessage):
message = binarymessage.decode()
syslog.syslog(syslog.LOG_INFO, message)
m = json.loads(message)
print (message)
if ("topic" in m) and (m["topic"] == "sts") and ("args" in m) and ("authenticated" in m["args"]) and (m["args"]["authenticated"] == True):
s = """smd+270639+{"tempo":1000,"snapshot":true,"fields":["31","70","71","82","84","85","86","87","88","7295","7296","7674","7675","7676","7677","TimestampBase","TimestampDelta","6509"]}"""
syslog.syslog(syslog.LOG_INFO, "Sending: {}".format(s))
ws.send(s)
if ((datetime.now().minute == 0) and (time.time() - start_time > 3 * 60)) or (time.time() - start_time > 60 * 60):
syslog.syslog(syslog.LOG_INFO, "Periodical restart of the streamer")
ws.close()
exit()
return
def on_error(ws, error):
syslog.syslog(syslog.LOG_ERR, "received error as {}".format(error))
def on_close(ws, close_status_code, close_msg):
syslog.syslog(syslog.LOG_INFO, "Connection closed {}".format(close_msg))
def on_open(ws):
#response = tickle()
#r = json.loads(response.text)
#print (response.text)
return
def ex_callback(callback, *args):
"""
Monkey patch for WebSocketApp._callback() because it swallows
exceptions.
"""
if callback is not None:
callback(ws, *args)
#websocket.enableTrace(True)
url = "wss://localhost:5000/v1/api/ws"
ws = websocket.WebSocketApp(url,
on_message = on_message,
on_error = on_error,
on_close = on_close,
on_open = on_open
)
ws._callback = ex_callback
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
if __name__ == "__main__":
subscribe()
This is very helpful, does anyone know how this is done in .NET? something like websocket sharpe