File size: 7,216 Bytes
0d45d74
 
 
 
 
 
5a4149f
0d45d74
c77be48
0d45d74
c77be48
382ea28
 
 
 
0d45d74
 
 
 
 
 
 
 
 
 
 
382ea28
0d45d74
 
382ea28
 
0d45d74
 
 
5a4149f
0d45d74
 
 
 
 
 
 
 
 
 
 
 
5a4149f
0d45d74
 
 
 
c1ca84f
5a4149f
0d45d74
928b15d
86fea3a
24b5931
86fea3a
e2af605
 
 
 
 
 
 
 
 
 
 
 
5a4149f
e2af605
382ea28
e2af605
5a4149f
 
382ea28
5a4149f
382ea28
 
 
5a4149f
 
928b15d
5a4149f
928b15d
 
5a4149f
928b15d
0d45d74
382ea28
 
 
0d45d74
 
382ea28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67bb0d5
 
 
 
 
 
 
5a4149f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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)