import pandas as pd import pandas_ta as ta import streamlit as st import plotly.graph_objects as go from plotly.subplots import make_subplots from modules.technical import TechnicalAnalysis st.set_page_config(page_title="Technical Analysis", layout="wide") # Load sample data (replace this with actual data) data = pd.read_csv('data/brent_futures.csv') data['Date'] = pd.to_datetime(data['Date']) data.sort_values('Date', inplace=True) # crudeData = TechnicalAnalysis('data/brent_futures.csv') # Streamlit sidebar for user input st.sidebar.title("Technical Analysis Settings") # Allow user to choose which technical indicators to display using multiselect indicators = st.sidebar.multiselect("Select Technical Indicators", ['Simple Moving Average', 'Bollinger Bands', 'RSI', 'MACD', 'Stochastic Oscillator', 'ADX'], default=['Simple Moving Average']) # Set lengths for technical indicators with st.sidebar.expander("Simple Moving Average"): sma_length = st.number_input('Simple Moving Average Length', min_value=5, max_value=300, value=5, step=1) with st.sidebar.expander("Bollinger Bands"): bb_length = st.number_input('Bollinger Bands Length', min_value=5, max_value=300, value=20, step=1) with st.sidebar.expander("RSI"): rsi_length = st.number_input('RSI Length', min_value=1, max_value=300, value=5, step=1) with st.sidebar.expander("MACD"): macd_fast_length = st.number_input("MACD Fast Length", min_value=5, max_value=300, value=12) macd_slow_length = st.number_input("MACD Slow Length", min_value=10, max_value=300, value=26) macd_signal_length = st.number_input("MACD Signal Length", min_value=5, max_value=300, value=9) with st.sidebar.expander("Stochastic Oscillator"): stocho_fast_length = st.number_input("Stochastic Oscillator Length", min_value=5, max_value=300, value=14) stocho_slow_length = st.number_input("Stochastic Oscillator Length", min_value=5, max_value=300, value=28) with st.sidebar.expander("ADX"): adx_length = st.number_input("ADX Length", min_value=5, max_value=50, value=14) # Initialize indicator choices moving_avg_choice = 'Simple Moving Average' in indicators bb_choice = 'Bollinger Bands' in indicators rsi_choice = 'RSI' in indicators macd_choice = 'MACD' in indicators stocho_choice = 'Stochastic Oscillator' in indicators adx_choice = 'ADX' in indicators # Calculate indicators based on user input if moving_avg_choice: data['SMA'] = ta.sma(data['Close'], length=sma_length) if bb_choice: bbands = ta.bbands(data['Close'], length=bb_length) data['BB_upper'], data['BB_middle'], data['BB_lower'] = bbands.iloc[:, 2], bbands.iloc[:, 1], bbands.iloc[:, 0] if rsi_choice: data['RSI'] = ta.rsi(data['Close'], length=rsi_length) if macd_choice: macd = ta.macd(data['Close'], fast=macd_fast_length, slow=macd_slow_length, signal=macd_signal_length) data['MACD'], data['MACD_Signal'], data['MACD_Hist'] = macd.iloc[:, 0], macd.iloc[:, 1], macd.iloc[:, 2] if stocho_choice: stoch = ta.stoch(data['High'], data['Low'], data['Close'], k=stocho_fast_length, d=stocho_slow_length) data['Stochastic_k'] = stoch.iloc[:, 0] data['Stochastic_d'] = stoch.iloc[:, 1] if adx_choice: adx = ta.adx(data['High'], data['Low'], data['Close'], length=adx_length) data['ADX'], data['ADX_DMP'], data['ADX_DMN'] = adx.iloc[:, 0], adx.iloc[:, 1], adx.iloc[:, 2] # Dynamically calculate the number of rows based on selected options rows = 1 # OHLC is mandatory if rsi_choice: rows += 1 if macd_choice: rows += 1 if stocho_choice: rows += 1 if adx_choice: rows += 1 row_heights = [0.6] + [0.2] * (rows - 1) # Create a subplot figure subplot_titles = ['OHLC with Technical Indicators'] if rsi_choice: subplot_titles.append('RSI') if macd_choice: subplot_titles.append('MACD') if stocho_choice: subplot_titles.append('Stochastic Oscillator') if adx_choice: subplot_titles.append('ADX') subplot_titles.append('Volume') fig = make_subplots( rows=rows + 1, cols=1, # Extra row for Volume shared_xaxes=True, vertical_spacing=0.05, row_heights=row_heights + [0.2], subplot_titles=subplot_titles ) # 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 moving_avg_choice: fig.add_trace(go.Scatter(x=data['Date'], y=data['SMA'], mode='lines', name=f'SMA {sma_length}', line=dict(color='blue')), row=1, col=1) # Plot Bollinger Bands if bb_choice: 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_choice: fig.add_trace(go.Scatter(x=data['Date'], y=data['RSI'], mode='lines', name=f'RSI {rsi_length}', line=dict(color='magenta')), row=2, col=1) # Plot MACD if macd_choice: macd_row = 2 if not rsi_choice else 3 fig.add_trace(go.Scatter(x=data['Date'], y=data['MACD'], mode='lines', name='MACD', line=dict(color='blue')), row=macd_row, col=1) fig.add_trace(go.Scatter(x=data['Date'], y=data['MACD_Signal'], mode='lines', name='MACD Signal', line=dict(color='red')), row=macd_row, col=1) fig.add_trace(go.Bar(x=data['Date'], y=data['MACD_Hist'], name='MACD Hist', marker=dict(color='green')), row=macd_row, col=1) # Plot Stochastic Oscillator if stocho_choice: stocho_row = 2 if not rsi_choice and not macd_choice else (3 if (not rsi_choice) or (not macd_choice) else 4) fig.add_trace(go.Scatter(x=data['Date'], y=data['Stochastic_k'], mode='lines', name='Stochastic K', line=dict(color='blue')), row=stocho_row, col=1) fig.add_trace(go.Scatter(x=data['Date'], y=data['Stochastic_d'], mode='lines', name='Stochastic D', line=dict(color='red')), row=stocho_row, col=1) # Plot ADX if adx_choice: adx_row = 2 if not rsi_choice and not macd_choice and not stocho_choice else ( 3 if (not macd_choice and not stocho_choice) or (not macd_choice and not rsi_choice) or (not stocho_choice and not rsi_choice) else ( 4 if (not stocho_choice) or (not macd_choice) or (not rsi_choice) else 5)) fig.add_trace(go.Scatter(x=data['Date'], y=data['ADX'], mode='lines', name='ADX', line=dict(color='darkgreen')), row=adx_row, col=1) fig.add_trace(go.Scatter(x=data['Date'], y=data['ADX_DMP'], mode='lines', name='ADX DMP', line=dict(color='lightgreen')), row=adx_row, col=1) fig.add_trace(go.Scatter(x=data['Date'], y=data['ADX_DMN'], mode='lines', name='ADX DMN', line=dict(color='orange')), row=adx_row, col=1) # Plot Volume fig.add_trace(go.Bar(x=data['Date'], y=data['Volume'], name='Volume', marker=dict(color='darkgreen')), row=rows + 1, col=1) # Customize layout fig.update_layout( title='Brent Crude Oil Futures', height=700, showlegend=True, dragmode='pan', xaxis_rangeslider_visible=False, # Hide default range slider ) config = {'scrollZoom': True} # Enable dynamic range for y-axes fig.update_yaxes(autorange=True) # Show the plot in Streamlit st.plotly_chart(fig, config=config) st.subheader('Technical Analysis Data') st.dataframe(data) st.markdown(""" ## Notes for improvements - Add interactive elements to allow users to customize the technical indicators - Add features such as backtesting, alerts, and notifications, line annotations, etc. """) # ta = TechnicalAnalysis('data/brent_futures.csv') # # Allow user to input settings # length_ma = st.number_input("Moving Average Length", min_value=2, value=20) # rsi_button = st.checkbox("Show RSI", value=False) # bb_button = st.checkbox("Show Bollinger Bands", value=False) # macd_button = st.checkbox("Show MACD", value=False) # # Calculate moving average # ta.moving_average(length=length_ma) # # Conditionally calculate and show indicators # if rsi_button: # ta.rsi() # if bb_button: # ta.bollinger_bands() # if macd_button: # ta.macd() # # Fetch the updated data # data = ta.get_data() # # Plot data using Plotly # fig = go.Figure() # # Add candlestick # fig.add_trace(go.Candlestick(x=data.index, open=data['Open'], high=data['High'], low=data['Low'], close=data['Close'], name='Candlestick')) # # Add moving average # fig.add_trace(go.Scatter(x=data.index, y=data[f'MA_{length_ma}'], mode='lines', name=f'MA {length_ma}')) # # Add indicators if toggled # if rsi_button: # fig.add_trace(go.Scatter(x=data.index, y=data[f'RSI_14'], mode='lines', name='RSI')) # if bb_button: # fig.add_trace(go.Scatter(x=data.index, y=data['BB_upper'], mode='lines', name='BB Upper')) # fig.add_trace(go.Scatter(x=data.index, y=data['BB_middle'], mode='lines', name='BB Middle')) # fig.add_trace(go.Scatter(x=data.index, y=data['BB_lower'], mode='lines', name='BB Lower')) # if macd_button: # fig.add_trace(go.Scatter(x=data.index, y=data['MACD'], mode='lines', name='MACD')) # fig.add_trace(go.Scatter(x=data.index, y=data['MACD_Signal'], mode='lines', name='MACD Signal')) # # Display the chart # st.plotly_chart(fig)