Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
519 views
in Technique[技术] by (71.8m points)

python 3.x - Streaming Live Websocket stream data and updating plotly graph with dash within a class

Apologies if this is a stupid question, but I'm wondering if it would be possible to create a dash app and stream live data straight into the graph?

I've been working on a trading bot which has a number of elements. I am currently trying to stream data that updates every 2000ms from a websocket and feed that straight into the graph.

I'm relatively new to programming so could use some assistance and criticism where neccesary!

So, as this live graph will ultimately be incorporated as part of the GUI and bot functionality, I am trying to make this priceTicker class encompass both initialising the dash app and also live updating the graph with the websocket stream that is received.

I am able to stream the data without problem and could parse the data into json, or csv or anything really. I am also able to initialise the graph in the dash app, but it isnt updating the graph with new data.

I have looked at a few SO posts around the general area but not found anything that explains it for my case unfortunately - sorry if there is any posts out there that i've missed!

Below is my full code:

from binance.client import Client
from binance.websockets import BinanceSocketManager
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input
import plotly
import plotly.graph_objs as go
from collections import deque
import pandas as pd
import json

class priceTicker:


    def __init__(self, api_key, secret_key):
        self.app = dash.Dash(__name__)
        self.ticker_time = deque(maxlen=200)
        self.last_price = deque(maxlen=200)
        self.app.layout = html.Div(
            [
                dcc.Graph(id = 'live-graph', animate = True),
                dcc.Interval(
                    id = 'graph-update',
                    interval = 2000,
                    n_intervals = 0
                )
            ]
        )

        client = Client(api_key, secret_key)
        socket = BinanceSocketManager(client)
        socket.start_kline_socket('BTCUSDT', self.on_message, '1m')

        socket.start()
    def on_message(self, message):
        app = self.app
        price = {'time':message['E'], 'price':message['k']['c']}
        self.ticker_time.append(message['E'])
        self.last_price.append(message['k']['c'])
        ticker_time = self.ticker_time
        last_price = self.last_price
        #print(self.ticker_time, self.last_price)

        @app.callback(
            Output('live-graph', 'figure'),
            [Input('graph-update', 'n_intervals')])
        def update_graph(ticker_time,last_price):

            data = go.Scatter(
                x = list(ticker_time),
                y = list(last_price),
                name ='Scatter',
                mode = 'lines+markers'
            )


            return {'data': [data],
                    'layout': go.Layout(xaxis=dict(range=[min(ticker_time), max(ticker_time)]),
                    yaxis=dict(range=[min(last_price), max(last_price)]),)}

def Main():
    api_key = ''
    secret_key = ''
    ticker = priceTicker(api_key, secret_key)
    ticker.app.run_server(debug=True, host='127.0.0.1', port=16552)
if __name__ == '__main__':
    #app.run_server(debug=False, host='127.0.0.1', port=10010)
    Main()

I'm not sure where I'm going wrong but it doesn't seem like the call back function is being called. Sorry if i've missed something obvious!

I'm running on 3.7.6 and macos Big Sur

If anyone has any advice would be greatly appreciated.

cheers

question from:https://stackoverflow.com/questions/65908128/streaming-live-websocket-stream-data-and-updating-plotly-graph-with-dash-within

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For anyone that's interested or trying to do a similar thing to me.

I managed to fix the problem by calling the app.callback within init and assigning the callback to a function within the class:

from binance.client import Client
from binance.websockets import BinanceSocketManager
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input
import plotly
import plotly.graph_objs as go
from collections import deque
import pandas as pd
import json

class priceTicker:
    def __init__(self, api_key, secret_key):
        self.ticker_time = deque(maxlen=200)
        self.last_price = deque(maxlen=200)
        client = Client(api_key, secret_key)
        socket = BinanceSocketManager(client)
        socket.start_kline_socket('BTCUSDT', self.on_message, '1m')

        socket.start()
        self.app = dash.Dash()
        self.app.layout = html.Div(
            [
                dcc.Graph(id = 'live-graph', animate = True),
                dcc.Interval(
                    id = 'graph-update',
                    interval = 2000,
                    n_intervals = 0
                )
            ]
        )
        self.app.callback(
            Output('live-graph', 'figure'),
            [Input('graph-update', 'n_intervals')])(self.update_graph)
        #app.run_server(debug=True, host='127.0.0.1', port=16452)
    def on_message(self, message):

        #price = {'time':message['E'], 'price':message['k']['c']}
        self.ticker_time.append(message['E'])
        self.last_price.append(message['k']['c'])
        #print(self.ticker_time, self.last_price)

    def update_graph(self, n):

        data = go.Scatter(
            x = list(self.ticker_time),
            y = list(self.last_price),
            name ='Scatter',
            mode = 'lines+markers'
        )


        return {'data': [data],
                'layout': go.Layout(xaxis=dict(range=[min(self.ticker_time), max(self.ticker_time)]),
                yaxis=dict(range=[min(self.last_price), max(self.last_price)]),)}

def Main():
    api_key = ''
    secret_key = ''
    ticker = priceTicker(api_key, secret_key)
    ticker.app.run_server(debug=True, host='127.0.0.1', port=16452)
if __name__ == '__main__':
    #app.run_server(debug=False, host='127.0.0.1', port=10010)
    Main()

Output is as expected with the app updating the last price every 2 sec.

Cheers


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...