Space8 / app.py
QuantumLearner's picture
Update app.py
382ea28 verified
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)