import pandas as pd import plotly.graph_objects as go import pygwalker as pyg import streamlit as st import streamlit.components.v1 as components import yfinance as yf from plotly.subplots import make_subplots from scipy.stats import norm from utils.helper import * # Streamlit app layout st.set_page_config(layout="wide") st.title("📊 Technical Trading Strategy Simulation 💹") # Sidebar inputs ticker = st.sidebar.text_input("Enter Stock Ticker", "AAPL").upper() start_date = st.sidebar.date_input("Start Date", pd.to_datetime("2020-01-01")) end_date = st.sidebar.date_input("End Date", pd.to_datetime("today")) # Add sidebar slider for selecting two integers st.sidebar.success("Please select your own parameters.") # Expander with st.expander("Expand to fine tune the windows:"): short_window = st.sidebar.slider( "Select short window size", min_value=2, max_value=200, value=20 ) long_window = st.sidebar.slider( "Select long window size", min_value=2, max_value=250, value=95 ) signal_window = st.sidebar.slider( "Select signal window size", min_value=2, max_value=250, value=9 ) values = st.sidebar.slider( "Select a range of values", min_value=-100, max_value=100, value=(-10, 10), step=1 ) option = st.sidebar.selectbox( "How would you like rescale data?", ("Original", "Normalization", "Percentile") ) st.sidebar.markdown( f""" ## URL of the app: [here](https://huggingface.co/spaces/eagle0504/technical-trader). """ ) # Add submit button in the sidebar submit_button = st.sidebar.button("Submit") # Update to execute changes only when the submit button is clicked if submit_button: with st.spinner("Wait for it..."): # Message if option == "Original": st.success( "We use the stock price (within the range selected) to create the MACD and Signal Line (which numerically vary based on price data)." ) elif option == "Normalization": st.success( "We use the stock price (within the range selected) to create the MACD and Signal Line (which numerically vary based on price data). Next, we normalize the MACD/Signal Line so that fall in a consistent range, i.e. approximately from -2 to 2." ) else: st.success( "We use the stock price (within the range selected) to create the MACD and Signal Line (which numerically vary based on price data). Next, we normalize the MACD/Signal Line so that fall in a consistent range, i.e. approximately from -2 to 2. Last, we use the normalized data to create probabilities from -100% to +100%. The probability means statistically what is believed to reverse the current direction." ) # Download stock data data = yf.download(ticker, start=start_date, end=end_date) if not data.empty: if option == "Normalization": data = calculate_normalized_macd( data, short_window, long_window, signal_window ) some_warning_message = "normalized data" elif option == "Percentile": data = calculate_percentile_macd( data, short_window, long_window, signal_window ) some_warning_message = "percentile data (numbers in %)" else: data = calculate_macd(data, short_window, long_window, signal_window) some_warning_message = "original data" data = find_crossovers(data, values[0], values[1]) # Plotting fig = create_fig(data, ticker) st.plotly_chart(fig, use_container_width=True) st.warning(f"In the above graph, we use {some_warning_message}.") else: st.write("No data available for the given ticker.") # New section to get and display fundamentals data under an expander with st.expander("View Fundamentals Data"): a, b, c = get_fundamentals(ticker) fundamentals_data = pd.concat([a, b, c], axis=0) fundamentals_data_t = fundamentals_data.transpose() fundamentals_data_t["date"] = fundamentals_data_t.index fundamentals_data_t.reset_index(drop=True, inplace=True) if not fundamentals_data.empty: # Generate a table (crude way) # st.table(fundamentals_data) # Generate the HTML using Pygwalker (user-friendly and flexible) pyg_html = pyg.walk(fundamentals_data_t, return_html=True) # Embed the HTML into the Streamlit app components.html(pyg_html, height=1000, scrolling=True) else: st.write("No fundamentals data available for the given ticker.")