112 lines
3.3 KiB
Python
112 lines
3.3 KiB
Python
import dash_bootstrap_components as dbc
|
|
|
|
from dash import Dash, dcc, html, Input, Output
|
|
from dash_ag_grid import AgGrid
|
|
from dash_bootstrap_templates import load_figure_template
|
|
from datetime import datetime
|
|
from flask_caching import Cache
|
|
from pandas import DataFrame, Series
|
|
|
|
from plotting import CandlestickChart, figure_with_subplots
|
|
|
|
from daily_data import get_daily_data
|
|
from signals import calculate_signals
|
|
from stylesheets import grid_stylesheet, theme_stylesheet
|
|
|
|
app = Dash(__name__, external_stylesheets = [theme_stylesheet, grid_stylesheet])
|
|
app.title = 'Swing Trading Dashboard'
|
|
|
|
cache = Cache(app.server, config = {
|
|
'CACHE_TYPE': 'SimpleCache',
|
|
'CACHE_DEFAULT_TIMEOUT': 60 # Seconds.
|
|
})
|
|
|
|
load_figure_template('lux_dark')
|
|
|
|
def load_chart(data: DataFrame) -> dict:
|
|
chart_data = data.tail(180)
|
|
candlestick_chart = CandlestickChart(
|
|
x = chart_data['Date'],
|
|
opens = chart_data['Open'],
|
|
highs = chart_data['High'],
|
|
lows = chart_data['Low'],
|
|
closes = chart_data['Close']
|
|
)
|
|
|
|
return figure_with_subplots([[candlestick_chart]])
|
|
|
|
@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(
|
|
[
|
|
dcc.Interval(
|
|
id = 'refresh-interval',
|
|
interval = 60 * 1000, # Milliseconds.
|
|
n_intervals = 0
|
|
),
|
|
dcc.Graph(
|
|
id = 'candlestick-chart',
|
|
config = {'displayModeBar': False},
|
|
figure = figure_with_subplots([[CandlestickChart(
|
|
x = Series(datetime.today()),
|
|
opens = Series(),
|
|
highs = Series(),
|
|
lows = Series(),
|
|
closes = Series(),
|
|
title = ''
|
|
)]])
|
|
),
|
|
html.Div(
|
|
AgGrid(
|
|
id = 'signal-table',
|
|
columnDefs = [{'field': 'Strategy', 'flex': 3}],
|
|
rowData = [],
|
|
defaultColDef = {'flex': 1, 'sortable': False, 'resizable': False},
|
|
dashGridOptions = {
|
|
'domLayout': 'autoHeight',
|
|
'pagination': True,
|
|
'paginationPageSizeSelector': False,
|
|
'paginationPageSize': 10,
|
|
},
|
|
style = {'height': None}
|
|
),
|
|
className = 'dbc dbc-ag-grid'
|
|
)
|
|
],
|
|
style = {'maxWidth': '1200px', 'margin': '0 auto'},
|
|
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__':
|
|
app.run_server(debug = False) |