Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streaming Websocket Data #6

Open
vepak opened this issue Jun 27, 2020 · 12 comments
Open

Streaming Websocket Data #6

vepak opened this issue Jun 27, 2020 · 12 comments

Comments

@vepak
Copy link

vepak commented Jun 27, 2020

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)

@areed1192
Copy link
Owner

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.

@vepak
Copy link
Author

vepak commented Jun 29, 2020

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.

@vepak
Copy link
Author

vepak commented Jun 29, 2020

hey, just checking if you have endpoint for websockets in your lib? Thanks!

@benjaminpolk
Copy link

I have the same issue and have tried opening a ticket with IBKR last week. No answers yet.

@sandybradley
Copy link

Same issue. I can connect to the socket and send subscription messages but no response data is received.

@pandaxbacon
Copy link

@sandybradley @benjaminpolk @vepak
I believe that is more like a ssl cert issue. I created a self-signed-cert and managed to receive response
Screenshot 2020-10-20 at 2 39 52 PM

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()

@AlsaAnz
Copy link

AlsaAnz commented Jan 12, 2022

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.

Capture3

@areed1192 areed1192 reopened this Jan 12, 2022
@areed1192
Copy link
Owner

@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.

@GCB-Botmodels
Copy link

GCB-Botmodels commented Mar 23, 2022

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()

@marianputis
Copy link

marianputis commented Jul 19, 2022

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.

@nugzar
Copy link

nugzar commented Dec 30, 2022

Hi. I think I made the code work and I am successfully receiving the streaming prices.

  1. The endpoint should be "wss://localhost:5000/v1/api/ws" instead of "wss://localhost:5000/v1/portal/ws"
  2. 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})
  3. 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"}}
  4. 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()

@farhoodMoslehi
Copy link

This is very helpful, does anyone know how this is done in .NET? something like websocket sharpe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants