Spaces:
Runtime error
Runtime error
| import yfinance as yf | |
| import pandas as pd | |
| import numpy as np | |
| import plotly.graph_objects as go | |
| from plotly.subplots import make_subplots | |
| import streamlit as st | |
| from datetime import datetime, timedelta | |
| # Helper function to fetch stock data | |
| def fetch_stock_data(ticker: str, start_date: str, end_date: str) -> pd.DataFrame: | |
| """Fetch stock data from Yahoo Finance.""" | |
| data = yf.download(ticker, start=start_date, end=end_date, auto_adjust=False) | |
| if isinstance(data.columns, pd.MultiIndex): | |
| data.columns = data.columns.get_level_values(0) | |
| return data | |
| # Function to estimate probability and plot | |
| def estimate_probability(data, n_days, initial_price, up_target, down_target): | |
| # Calculate the thresholds for price change | |
| up_threshold = round(abs((up_target - initial_price) / initial_price), 3) | |
| down_threshold = round(abs((down_target - initial_price) / initial_price), 3) | |
| # Calculate the n-day percentage change | |
| data[f'{n_days}d_pct_change'] = data['Adj Close'].pct_change(n_days) | |
| # Calculate the frequency of the threshold price change | |
| total_periods = len(data.dropna(subset=[f'{n_days}d_pct_change'])) | |
| down_periods = len(data[data[f'{n_days}d_pct_change'] <= -down_threshold]) | |
| up_periods = len(data[data[f'{n_days}d_pct_change'] >= up_threshold]) | |
| down_frequency = down_periods / total_periods if total_periods > 0 else 0 | |
| up_frequency = up_periods / total_periods if total_periods > 0 else 0 | |
| # Plotting | |
| fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1, | |
| subplot_titles=(f'Distribution of {n_days}-day percentage changes', f'Price for {ticker}'), | |
| specs=[[{"secondary_y": False}], [{"secondary_y": False}]]) | |
| fig.add_trace(go.Histogram(x=data[f'{n_days}d_pct_change'], nbinsx=100, name='Percentage Change'), row=1, col=1) | |
| fig.add_vline(x=-down_threshold, line=dict(color='red', dash='dash'), annotation_text=f"{down_threshold * 100:.2f}% decrease frequency: {down_frequency * 100:.2f}%", annotation_position="bottom left", row=1, col=1) | |
| fig.add_vline(x=up_threshold, line=dict(color='blue', dash='dash'), annotation_text=f"{up_threshold * 100:.2f}% increase frequency: {up_frequency * 100:.2f}%", annotation_position="top right", row=1, col=1) | |
| fig.add_trace(go.Scatter(x=data.index, y=data['Adj Close'], mode='lines', name='Adjusted Close Price'), row=2, col=1) | |
| up_instances = data[data[f'{n_days}d_pct_change'] >= up_threshold] | |
| down_instances = data[data[f'{n_days}d_pct_change'] <= -down_threshold] | |
| fig.add_trace(go.Scatter(x=up_instances.index, y=up_instances['Adj Close'], mode='markers', marker=dict(color='blue', symbol='triangle-up', size=10), name=f"{up_threshold * 100:.2f}% increase"), row=2, col=1) | |
| fig.add_trace(go.Scatter(x=down_instances.index, y=down_instances['Adj Close'], mode='markers', marker=dict(color='red', symbol='triangle-down', size=10), name=f"{down_threshold * 100:.2f}% decrease"), row=2, col=1) | |
| fig.update_layout(title_text=f"Probability Estimation and Price for {ticker}", xaxis_title='Date', yaxis_title='Adjusted Close Price') | |
| return fig, up_frequency, down_frequency | |
| # Streamlit app | |
| st.set_page_config(page_title="Price Movements Probability Analysis", layout="wide") | |
| st.title('Price Probability Analysis') | |
| # Sidebar for method selection | |
| st.sidebar.title("Input Parameters") | |
| with st.sidebar.expander("How to Use", expanded=False): | |
| st.markdown(""" | |
| ### How to Use | |
| 1. **Enter Ticker**: Input the stock symbol or crypto pair you want to analyze. | |
| 2. **Select Date Range**: Choose the start and end dates for the historical data. | |
| 3. **Set Parameters**: | |
| - **Number of Days**: Define the period for percentage change calculation. | |
| - **Initial Price**: The starting price for your analysis. | |
| - **Up Target**: The target price for an upward move. | |
| - **Down Target**: The target price for a downward move. | |
| 4. **Run Analysis**: Click the 'Run Analysis' button to generate the results. | |
| """) | |
| with st.sidebar.expander("Ticker and Date Settings", expanded=True): | |
| ticker = st.text_input('Enter Ticker (Stock or Crypto Pair)', 'SAP.DE', help="Enter a stock ticker (e.g., AAPL) or a crypto pair (e.g., BTC-USD)") | |
| start_date = st.date_input('Start Date', pd.to_datetime('2020-01-01'), help="Select the start date for the data") | |
| end_date = st.date_input('End Date', datetime.now().date() + timedelta(days=1), help="Select the end date for the data") | |
| with st.sidebar.expander("Parameter Settings", expanded=True): | |
| # Fetch data to set default values only if Run Analysis is clicked | |
| n_days = st.slider('Number of Days', min_value=1, max_value=100, value=30, step=1, help="Number of days for percentage change calculation") | |
| initial_price = st.number_input('Initial Price', value=0.0, help="Starting price for analysis (defaults to latest price if 0)") | |
| up_target = st.number_input('Up Target', value=0.0, help="Target price for upward move (defaults to 10% above initial if 0)") | |
| down_target = st.number_input('Down Target', value=0.0, help="Target price for downward move (defaults to 10% below initial if 0)") | |
| # Main content area | |
| st.markdown(""" | |
| This app estimates the probability of a stock or cryptocurrency reaching certain price targets within a specified number of days based on historical data. | |
| - **Distribution of Percentage Changes**: The histogram shows the distribution of percentage changes over the selected number of days. | |
| - **Price Targets**: The vertical lines indicate the price targets for upward and downward moves. The frequencies of reaching these targets are annotated. | |
| - **Price Plot**: The line chart shows the historical adjusted close prices with markers indicating instances where the price targets were met. | |
| """) | |
| # Run button | |
| run_button = st.sidebar.button('Run Analysis') | |
| # Fetch data and display results | |
| if run_button: | |
| data = fetch_stock_data(ticker, start_date, end_date) | |
| if data.empty: | |
| st.error(f"No data returned for {ticker} from {start_date} to {end_date}") | |
| else: | |
| st.session_state.data = data | |
| data = st.session_state.data | |
| if initial_price <= 0: | |
| initial_price = data['Adj Close'].iloc[-1] | |
| if up_target <= 0: | |
| up_target = initial_price * 1.1 | |
| if down_target <= 0: | |
| down_target = initial_price * 0.9 | |
| fig, up_frequency, down_frequency = estimate_probability(data, n_days, initial_price, up_target, down_target) | |
| st.plotly_chart(fig) | |
| st.markdown(f""" | |
| ### Results | |
| **Probability of Reaching Targets:** | |
| - Probability of reaching the up target ({up_target:.2f}) in {n_days} days: **{up_frequency * 100:.2f}%** | |
| - Probability of reaching the down target ({down_target:.2f}) in {n_days} days: **{down_frequency * 100:.2f}%** | |
| This analysis helps in understanding the historical likelihood of the price reaching certain targets within a specified number of days. | |
| """) | |
| hide_streamlit_style = """ | |
| <style> | |
| #MainMenu {visibility: hidden;} | |
| footer {visibility: hidden;} | |
| </style> | |
| """ | |
| st.markdown(hide_streamlit_style, unsafe_allow_html=True) |