Add support for live intraday data / signals and support caching requests for them server-side
This commit is contained in:
parent
cef85d06df
commit
f088539163
70
dashboard.py
70
dashboard.py
@ -1,9 +1,10 @@
|
|||||||
import dash_bootstrap_components as dbc
|
import dash_bootstrap_components as dbc
|
||||||
|
|
||||||
from dash import Dash, dcc, html
|
from dash import Dash, dcc, html, Input, Output
|
||||||
from dash_ag_grid import AgGrid
|
from dash_ag_grid import AgGrid
|
||||||
from dash_bootstrap_templates import load_figure_template
|
from dash_bootstrap_templates import load_figure_template
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from flask_caching import Cache
|
||||||
from pandas import DataFrame, Series
|
from pandas import DataFrame, Series
|
||||||
from typing import Callable, List, Dict
|
from typing import Callable, List, Dict
|
||||||
|
|
||||||
@ -26,6 +27,11 @@ from stylesheets import grid_stylesheet, theme_stylesheet
|
|||||||
app = Dash(__name__, external_stylesheets = [theme_stylesheet, grid_stylesheet])
|
app = Dash(__name__, external_stylesheets = [theme_stylesheet, grid_stylesheet])
|
||||||
app.title = 'Swing Trading Dashboard'
|
app.title = 'Swing Trading Dashboard'
|
||||||
|
|
||||||
|
cache = Cache(app.server, config = {
|
||||||
|
'CACHE_TYPE': 'SimpleCache',
|
||||||
|
'CACHE_DEFAULT_TIMEOUT': 60 # Seconds.
|
||||||
|
})
|
||||||
|
|
||||||
load_figure_template('lux_dark')
|
load_figure_template('lux_dark')
|
||||||
|
|
||||||
SignalFunction = Callable[[DataFrame], Series]
|
SignalFunction = Callable[[DataFrame], Series]
|
||||||
@ -44,9 +50,7 @@ signal_functions: List[Dict[str, SignalFunction]] = [
|
|||||||
{'strategy': 'VIX RSI', 'function': vix_rsi.signals}
|
{'strategy': 'VIX RSI', 'function': vix_rsi.signals}
|
||||||
]
|
]
|
||||||
|
|
||||||
data = get_daily_data('SPY')
|
def calculate_signals(data: DataFrame, days: int = 12) -> DataFrame:
|
||||||
|
|
||||||
def calculate_signals(days: int = 12) -> DataFrame:
|
|
||||||
signal_data = []
|
signal_data = []
|
||||||
|
|
||||||
for signal_info in signal_functions:
|
for signal_info in signal_functions:
|
||||||
@ -61,7 +65,7 @@ def calculate_signals(days: int = 12) -> DataFrame:
|
|||||||
|
|
||||||
return DataFrame(signal_data)
|
return DataFrame(signal_data)
|
||||||
|
|
||||||
def load_chart() -> dict:
|
def load_chart(data: DataFrame) -> dict:
|
||||||
chart_data = data.tail(180)
|
chart_data = data.tail(180)
|
||||||
candlestick_chart = CandlestickChart(
|
candlestick_chart = CandlestickChart(
|
||||||
x = chart_data['Date'],
|
x = chart_data['Date'],
|
||||||
@ -73,22 +77,45 @@ def load_chart() -> dict:
|
|||||||
|
|
||||||
return figure_with_subplots([[candlestick_chart]])
|
return figure_with_subplots([[candlestick_chart]])
|
||||||
|
|
||||||
signal_data = calculate_signals()
|
@cache.cached(timeout = 60, key_prefix = 'get_daily_data')
|
||||||
|
def get_cached_data():
|
||||||
|
return get_daily_data('SPY')
|
||||||
|
|
||||||
|
@cache.cached(timeout = 60, key_prefix = 'calculate_signals')
|
||||||
|
def get_cached_signals():
|
||||||
|
data = get_cached_data()
|
||||||
|
return calculate_signals(data)
|
||||||
|
|
||||||
|
@cache.cached(timeout = 60, key_prefix = 'load_chart')
|
||||||
|
def get_cached_chart():
|
||||||
|
data = get_cached_data()
|
||||||
|
return load_chart(data)
|
||||||
|
|
||||||
app.layout = dbc.Container(
|
app.layout = dbc.Container(
|
||||||
[
|
[
|
||||||
|
dcc.Interval(
|
||||||
|
id = 'refresh-interval',
|
||||||
|
interval = 60 * 1000, # Milliseconds.
|
||||||
|
n_intervals = 0
|
||||||
|
),
|
||||||
dcc.Graph(
|
dcc.Graph(
|
||||||
id = 'candlestick-chart',
|
id = 'candlestick-chart',
|
||||||
config = {'displayModeBar': False},
|
config = {'displayModeBar': False},
|
||||||
figure = load_chart(),
|
figure = figure_with_subplots([[CandlestickChart(
|
||||||
|
x = Series(datetime.today()),
|
||||||
|
opens = Series(),
|
||||||
|
highs = Series(),
|
||||||
|
lows = Series(),
|
||||||
|
closes = Series(),
|
||||||
|
title = ''
|
||||||
|
)]])
|
||||||
|
|
||||||
),
|
),
|
||||||
html.Div(
|
html.Div(
|
||||||
AgGrid(
|
AgGrid(
|
||||||
columnDefs = [
|
id = 'signal-table',
|
||||||
{'field': col, 'flex': 3} if col == 'Strategy' else {'field': col, 'flex': 1, 'cellRenderer': 'SignalRenderer'}
|
columnDefs = [{'field': 'Strategy', 'flex': 3}],
|
||||||
for col in signal_data.columns
|
rowData = [],
|
||||||
],
|
|
||||||
rowData = signal_data.to_dict(orient = 'records'),
|
|
||||||
defaultColDef = {'flex': 1, 'sortable': False, 'resizable': False},
|
defaultColDef = {'flex': 1, 'sortable': False, 'resizable': False},
|
||||||
dashGridOptions = {'domLayout': 'autoHeight'},
|
dashGridOptions = {'domLayout': 'autoHeight'},
|
||||||
style = {'height': None}
|
style = {'height': None}
|
||||||
@ -100,5 +127,24 @@ app.layout = dbc.Container(
|
|||||||
fluid = True
|
fluid = True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.callback(
|
||||||
|
[
|
||||||
|
Output('candlestick-chart', 'figure'),
|
||||||
|
Output('signal-table', 'columnDefs'),
|
||||||
|
Output('signal-table', 'rowData')
|
||||||
|
],
|
||||||
|
Input('refresh-interval', 'n_intervals')
|
||||||
|
)
|
||||||
|
def update_dashboard(_):
|
||||||
|
signal_data = get_cached_signals()
|
||||||
|
chart_figure = get_cached_chart()
|
||||||
|
|
||||||
|
column_defs = [
|
||||||
|
{'field': col, 'flex': 3} if col == 'Strategy' else {'field': col, 'flex': 1, 'cellRenderer': 'SignalRenderer'}
|
||||||
|
for col in signal_data.columns
|
||||||
|
]
|
||||||
|
|
||||||
|
return chart_figure, column_defs, signal_data.to_dict(orient = 'records')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run_server(debug = False)
|
app.run_server(debug = False)
|
Loading…
Reference in New Issue
Block a user