import streamlit as st import yfinance as yf import pandas as pd import plotly.graph_objs as go from st_pages import show_pages_from_config, add_page_title # Load pages from the TOML configuration file show_pages_from_config(".streamlit/pages_sections.toml") add_page_title("BBMA Oma Ally", "🌐") # Optionally add a title and icon to the current page # Define ticker symbols for various stock exchanges stock_exchanges = { "Kuala Lumpur Stock Exchange (KLSE)": { "CIMB Group Holdings Bhd - CIMB": "1023.KL", "RHB Bank Bhd - RHBBANK": "1066.KL", "Hong Leong Financial Group Bhd - HLFG": "1082.KL", "Malayan Banking Bhd - MAYBANK": "1155.KL", "Public Bank Bhd - PBBANK": "1295.KL", "IOI Corporation Bhd - IOICORP": "1961.KL", "Kuala Lumpur Kepong Bhd - KLK": "2445.KL", "Genting Bhd - GENTING": "3182.KL", "MISC Bhd - MISC": "3816.KL", "PPB Group Bhd - PPB": "4065.KL", "Sime Darby Bhd - SIME": "4197.KL", "Telekom Malaysia Bhd - TM": "4863.KL", "Tenaga Nasional Bhd - TENAGA": "5278.KL", "Top Glove Corporation Bhd - TOPGLOV": "7113.KL", "AirAsia X Bhd - AAX": "5238.KL", "Ramssol Group Bhd - RAMSSOL": "0236.KL", "Uzma Bhd - UZMA": "7250.KL", "WZ Satu Bhd - WZSATU": "7245.KL", "Systech Bhd - SYSTECH": "0050.KL", "Yong Tai Bhd - YONGTAI": "7066.KL", }, "Euronext": { "LVMH Moet Hennessy Louis Vuitton SE - LVMH": "MC.PA", "TotalEnergies SE - TotalEnergies": "TTE.PA", "Sanofi SA - Sanofi": "SAN.PA", "Air Liquide SA - Air Liquide": "AI.PA", "Schneider Electric SE - Schneider Electric": "SU.PA", "Kering SA - Kering": "KER.PA", "BNP Paribas SA - BNP Paribas": "BNP.PA", "Hermès International SCA - Hermès": "RMS.PA", "L'Oréal SA - L'Oréal": "OR.PA", "AXA SA - AXA": "CS.PA", "Vinci SA - Vinci": "DG.PA", "Dassault Systèmes SE - Dassault Systèmes": "DSY.PA", "Engie SA - Engie": "ENGI.PA", "Société Générale SA - Société Générale": "GLE.PA", "Pernod Ricard SA - Pernod Ricard": "RI.PA", "Safran SA - Safran": "SAF.PA", "ArcelorMittal SA - ArcelorMittal": "MT.AS", "Saint-Gobain SA - Saint-Gobain": "SGO.PA", "Capgemini SE - Capgemini": "CAP.PA", "Danone SA - Danone": "BN.PA", }, "London Stock Exchange (LSE)": { "HSBC Holdings plc - HSBC": "HSBA.L", "Royal Dutch Shell plc - Shell": "RDSA.L", "BP plc - BP": "BP.L", "GlaxoSmithKline plc - GlaxoSmithKline": "GSK.L", "AstraZeneca plc - AstraZeneca": "AZN.L", "Unilever plc - Unilever": "ULVR.L", "British American Tobacco plc - British American Tobacco": "BATS.L", "Diageo plc - Diageo": "DGE.L", "Barclays plc - Barclays": "BARC.L", "Lloyds Banking Group plc - Lloyds": "LLOY.L", "Vodafone Group plc - Vodafone": "VOD.L", "Rio Tinto plc - Rio Tinto": "RIO.L", "Reckitt Benckiser Group plc - Reckitt Benckiser": "RKT.L", "Tesco plc - Tesco": "TSCO.L", "Glencore plc - Glencore": "GLEN.L", "National Grid plc - National Grid": "NG.L", "BT Group plc - BT Group": "BT-A.L", "Aviva plc - Aviva": "AV.L", "Imperial Brands plc - Imperial Brands": "IMB.L", "Rolls-Royce Holdings plc - Rolls-Royce": "RR.L", }, "NYSE": { "Berkshire Hathaway Inc. (Class B) - BRK-B": "BRK-B", "Johnson & Johnson - JNJ": "JNJ", "JPMorgan Chase & Co. - JPM": "JPM", "Procter & Gamble Co. - PG": "PG", "Visa Inc. (Class A) - V": "V", "Walmart Inc. - WMT": "WMT", "Mastercard Incorporated (Class A) - MA": "MA", "The Home Depot, Inc. - HD": "HD", "Bank of America Corporation - BAC": "BAC", "Walt Disney Company (The) - DIS": "DIS", "Pfizer Inc. - PFE": "PFE", "Chevron Corporation - CVX": "CVX", "Coca-Cola Company (The) - KO": "KO", "Exxon Mobil Corporation - XOM": "XOM", "AbbVie Inc. - ABBV": "ABBV", "Merck & Co., Inc. - MRK": "MRK", "AT&T Inc. - T": "T", "Verizon Communications Inc. - VZ": "VZ", "Morgan Stanley - MS": "MS", "Goldman Sachs Group, Inc. (The) - GS": "GS", }, "NASDAQ": { "Apple Inc. - AAPL": "AAPL", "Microsoft Corporation - MSFT": "MSFT", "Amazon.com, Inc. - AMZN": "AMZN", "Tesla, Inc. - TSLA": "TSLA", "Alphabet Inc. (Class A) - GOOGL": "GOOGL", "Alphabet Inc. (Class C) - GOOG": "GOOG", "NVIDIA Corporation - NVDA": "NVDA", "Meta Platforms, Inc. - META": "META", "Netflix, Inc. - NFLX": "NFLX", "Intel Corporation - INTC": "INTC", "Adobe Inc. - ADBE": "ADBE", "Cisco Systems, Inc. - CSCO": "CSCO", "PepsiCo, Inc. - PEP": "PEP", "Comcast Corporation - CMCSA": "CMCSA", "Advanced Micro Devices, Inc. - AMD": "AMD", "Broadcom Inc. - AVGO": "AVGO", "Charter Communications, Inc. - CHTR": "CHTR", "PayPal Holdings, Inc. - PYPL": "PYPL", "Starbucks Corporation - SBUX": "SBUX", "Booking Holdings Inc. - BKNG": "BKNG", }, } def fetch_data(ticker, start_date, end_date): data = yf.download(ticker, start=start_date, end=end_date) return data def fetch_weekly_data(ticker, start_date, end_date): data = yf.download(ticker, start=start_date, end=end_date, interval='1wk') return data def calculate_indicators(data): # Bollinger Bands data['Middle Band'] = data['Close'].rolling(window=20).mean() data['Upper Band'] = data['Middle Band'] + 1.96 * data['Close'].rolling(window=20).std() data['Lower Band'] = data['Middle Band'] - 1.96 * data['Close'].rolling(window=20).std() # Moving Averages data['MA5'] = data['Close'].rolling(window=5).mean() data['MA10'] = data['Close'].rolling(window=10).mean() return data def identify_signals(data): # Calculate Buy and Sell signals on daily data data['Buy Signal'] = ((data['Close'] < data['Lower Band']) & (data['Close'].shift(1) > data['Lower Band'])) | \ ((data['Close'] > data['MA5']) & (data['Close'].shift(1) < data['MA5'])) data['Sell Signal'] = ((data['Close'] > data['Upper Band']) & (data['Close'].shift(1) < data['Upper Band'])) | \ ((data['Close'] < data['MA5']) & (data['Close'].shift(1) > data['MA5'])) # Filter signals by volume avg_volume = data['Volume'].rolling(window=20).mean() data['Buy Signal'] = data['Buy Signal'] & (data['Volume'] > avg_volume) data['Sell Signal'] = data['Sell Signal'] & (data['Volume'] > avg_volume) return data def identify_weekly_signals(weekly_data): weekly_data['Buy Signal'] = ((weekly_data['Close'] < weekly_data['Lower Band']) & (weekly_data['Close'].shift(1) > weekly_data['Lower Band'])) | \ ((weekly_data['Close'] > weekly_data['MA5']) & (weekly_data['Close'].shift(1) < weekly_data['MA5'])) weekly_data['Sell Signal'] = ((weekly_data['Close'] > weekly_data['Upper Band']) & (weekly_data['Close'].shift(1) < weekly_data['Upper Band'])) | \ ((weekly_data['Close'] < weekly_data['MA5']) & (weekly_data['Close'].shift(1) > weekly_data['MA5'])) return weekly_data def confirm_signals_with_weekly(data, weekly_data): weekly_data = calculate_indicators(weekly_data) weekly_data = identify_weekly_signals(weekly_data) data['Weekly Buy Signal'] = weekly_data['Buy Signal'].reindex(data.index, method='ffill') data['Weekly Sell Signal'] = weekly_data['Sell Signal'].reindex(data.index, method='ffill') data['Buy Signal'] = data['Buy Signal'] & data['Weekly Buy Signal'] data['Sell Signal'] = data['Sell Signal'] & data['Weekly Sell Signal'] return data def plot_data(data): fig = go.Figure() # Adding Close price trace fig.add_trace(go.Scatter(x=data.index, y=data['Close'], name='Close Price', line=dict(color='blue', width=2))) # Adding Bollinger Bands traces fig.add_trace(go.Scatter(x=data.index, y=data['Upper Band'], name='Upper Bollinger Band', line=dict(color='red', dash='dash'))) fig.add_trace(go.Scatter(x=data.index, y=data['Middle Band'], name='Middle Bollinger Band', line=dict(color='white', dash='dash'))) fig.add_trace(go.Scatter(x=data.index, y=data['Lower Band'], name='Lower Bollinger Band', line=dict(color='red', dash='dash'))) # Adding Moving Averages traces fig.add_trace(go.Scatter(x=data.index, y=data['MA5'], name='5-Day MA', line=dict(color='green', dash='dot'))) fig.add_trace(go.Scatter(x=data.index, y=data['MA10'], name='10-Day MA', line=dict(color='orange', dash='dot'))) # Adding Buy and Sell signals buys = data[data['Buy Signal']] sells = data[data['Sell Signal']] fig.add_trace(go.Scatter(x=buys.index, y=buys['Close'], mode='markers', name='Buy Signal', marker=dict(symbol='triangle-up', size=10, color='green'))) fig.add_trace(go.Scatter(x=sells.index, y=sells['Close'], mode='markers', name='Sell Signal', marker=dict(symbol='triangle-down', size=10, color='red'))) # Layout updates fig.update_layout(title='Stock Price and Trading Signals', xaxis_title='Date', yaxis_title='Price', template='plotly_dark') fig.update_xaxes(rangeslider_visible=True) return fig def main(): st.title("OMA Ally BBMA Trading Strategy Visualization") # Sidebar with dropdown menu for stock tickers st.sidebar.title("Select Ticker Symbol") exchange = st.sidebar.selectbox("Select Stock Exchange", list(stock_exchanges.keys())) ticker_symbols = stock_exchanges[exchange] ticker = st.sidebar.selectbox("Select Ticker Symbol", list(ticker_symbols.keys())) ticker_symbol = ticker_symbols[ticker] start_date = st.date_input("Select the start date") end_date = st.date_input("Select the end date") if st.button("Analyze"): data = fetch_data(ticker_symbol, start_date, end_date) weekly_data = fetch_weekly_data(ticker_symbol, start_date, end_date) data = calculate_indicators(data) data = identify_signals(data) data = confirm_signals_with_weekly(data, weekly_data) fig = plot_data(data) st.plotly_chart(fig, use_container_width=True) if __name__ == "__main__": main()