File size: 6,278 Bytes
ffe3438
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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)