Spaces:
Sleeping
Sleeping
import pandas as pd | |
import pandas_ta as ta | |
import dash | |
from dash import dcc, html | |
from dash.dependencies import Input, Output, State | |
import plotly.graph_objects as go | |
from plotly.subplots import make_subplots | |
# Load sample data (replace with actual data) | |
data = pd.read_csv('data/brent_futures.csv') | |
data['Date'] = pd.to_datetime(data['Date']) | |
data.sort_values('Date', inplace=True) | |
# Initialize Dash app | |
app = dash.Dash(__name__) | |
# Dash layout | |
app.layout = html.Div([ | |
html.H1("OHLCV Chart with Technical Indicators"), | |
# Dropdown for selecting moving averages and other technical indicators | |
html.Div([ | |
html.Label("Select Moving Averages"), | |
dcc.Dropdown( | |
id='moving-avg-choice', | |
options=[ | |
{'label': 'MA 4', 'value': 'MA_4'}, | |
{'label': 'MA 10', 'value': 'MA_10'}, | |
{'label': 'MA 30', 'value': 'MA_30'} | |
], | |
multi=True, | |
value=['MA_4', 'MA_10'] # Default selected | |
), | |
html.Br(), | |
# Sliders for lengths of technical indicators | |
html.Label("MA 4 Length"), | |
dcc.Slider(id='ma4-length', min=2, max=20, value=4, marks={i: str(i) for i in range(2, 21)}), | |
html.Br(), | |
html.Label("MA 10 Length"), | |
dcc.Slider(id='ma10-length', min=5, max=50, value=10, marks={i: str(i) for i in range(5, 51, 5)}), | |
html.Br(), | |
html.Label("MA 30 Length"), | |
dcc.Slider(id='ma30-length', min=10, max=100, value=30, marks={i: str(i) for i in range(10, 101, 10)}), | |
html.Br(), | |
dcc.Checklist( | |
id='indicator-choice', | |
options=[ | |
{'label': 'Bollinger Bands', 'value': 'BB'}, | |
{'label': 'RSI', 'value': 'RSI'}, | |
{'label': 'MACD', 'value': 'MACD'} | |
], | |
value=['BB', 'RSI'], # Default checked | |
labelStyle={'display': 'inline-block'} | |
) | |
], style={'width': '30%', 'display': 'inline-block', 'padding': '20px'}), | |
# Div for rendering plotly chart | |
html.Div([dcc.Graph(id='technical-chart')], style={'width': '68%', 'display': 'inline-block'}), | |
]) | |
# Callback to update chart based on selected technical analyses and lengths | |
def update_chart(moving_avg_choice, ma4_length, ma10_length, ma30_length, indicators): | |
# Reset calculations for indicators | |
data['MA_4'] = ta.sma(data['Close'], length=ma4_length) if 'MA_4' in moving_avg_choice else None | |
data['MA_10'] = ta.sma(data['Close'], length=ma10_length) if 'MA_10' in moving_avg_choice else None | |
data['MA_30'] = ta.sma(data['Close'], length=ma30_length) if 'MA_30' in moving_avg_choice else None | |
if 'BB' in indicators: | |
bbands = ta.bbands(data['Close'], length=20) | |
data['BB_upper'], data['BB_middle'], data['BB_lower'] = bbands.iloc[:, 2], bbands.iloc[:, 1], bbands.iloc[:, 0] | |
if 'RSI' in indicators: | |
data['RSI'] = ta.rsi(data['Close'], length=8) | |
if 'MACD' in indicators: | |
macd = ta.macd(data['Close'], fast=12, slow=26, signal=9) | |
data['MACD'], data['MACD_Signal'], data['MACD_Hist'] = macd.iloc[:, 0], macd.iloc[:, 1], macd.iloc[:, 2] | |
# Create subplots | |
fig = make_subplots( | |
rows=4 if 'MACD' in indicators else 3, cols=1, | |
shared_xaxes=True, | |
vertical_spacing=0.05, | |
row_heights=[0.6, 0.2, 0.2, 0.2] if 'MACD' in indicators else [0.6, 0.2, 0.2], | |
subplot_titles=('OHLC with Technical Indicators', 'RSI', 'MACD', 'Volume') if 'MACD' in indicators else ('OHLC with Technical Indicators', 'RSI', 'Volume') | |
) | |
# Plot OHLC candlestick | |
fig.add_trace(go.Candlestick(x=data['Date'], open=data['Open'], high=data['High'], low=data['Low'], close=data['Close'], name="OHLC"), row=1, col=1) | |
# Plot Moving Averages | |
if 'MA_4' in moving_avg_choice: | |
fig.add_trace(go.Scatter(x=data['Date'], y=data['MA_4'], mode='lines', name=f'MA {ma4_length}', line=dict(color='blue')), row=1, col=1) | |
if 'MA_10' in moving_avg_choice: | |
fig.add_trace(go.Scatter(x=data['Date'], y=data['MA_10'], mode='lines', name=f'MA {ma10_length}', line=dict(color='orange')), row=1, col=1) | |
if 'MA_30' in moving_avg_choice: | |
fig.add_trace(go.Scatter(x=data['Date'], y=data['MA_30'], mode='lines', name=f'MA {ma30_length}', line=dict(color='green')), row=1, col=1) | |
# Plot Bollinger Bands | |
if 'BB' in indicators: | |
fig.add_trace(go.Scatter(x=data['Date'], y=data['BB_upper'], mode='lines', name='BB Upper', line=dict(color='purple')), row=1, col=1) | |
fig.add_trace(go.Scatter(x=data['Date'], y=data['BB_middle'], mode='lines', name='BB Middle', line=dict(color='gray')), row=1, col=1) | |
fig.add_trace(go.Scatter(x=data['Date'], y=data['BB_lower'], mode='lines', name='BB Lower', line=dict(color='purple')), row=1, col=1) | |
# Plot RSI | |
if 'RSI' in indicators: | |
fig.add_trace(go.Scatter(x=data['Date'], y=data['RSI'], mode='lines', name='RSI', line=dict(color='magenta')), row=2, col=1) | |
# Plot MACD | |
if 'MACD' in indicators: | |
fig.add_trace(go.Scatter(x=data['Date'], y=data['MACD'], mode='lines', name='MACD', line=dict(color='blue')), row=3, col=1) | |
fig.add_trace(go.Scatter(x=data['Date'], y=data['MACD_Signal'], mode='lines', name='MACD Signal', line=dict(color='red')), row=3, col=1) | |
fig.add_trace(go.Bar(x=data['Date'], y=data['MACD_Hist'], name='MACD Hist', marker=dict(color='green')), row=3, col=1) | |
# Plot Volume | |
fig.add_trace(go.Bar(x=data['Date'], y=data['Volume'], name='Volume', marker=dict(color='darkgreen')), row=4 if 'MACD' in indicators else 3, col=1) | |
# Customize layout | |
fig.update_layout( | |
height=1000, | |
showlegend=True, | |
xaxis_rangeslider_visible=False, | |
dragmode='drawline' # Allow drawing lines on the chart | |
) | |
# Enable dynamic range for y-axes | |
fig.update_yaxes(autorange=True) | |
return fig | |
# Run the app | |
if __name__ == '__main__': | |
app.run_server(debug=True) |