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