poc / dash_app.py
ryanrahmadifa
Updated technical anlysis
ffe3438
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
@app.callback(
Output('technical-chart', 'figure'),
Input('moving-avg-choice', 'value'),
Input('ma4-length', 'value'),
Input('ma10-length', 'value'),
Input('ma30-length', 'value'),
Input('indicator-choice', 'value')
)
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)