QuantumLearner commited on
Commit
76c40a6
·
verified ·
1 Parent(s): e53694f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -46
app.py CHANGED
@@ -7,11 +7,16 @@ import plotly.graph_objs as go
7
  import warnings
8
  import pandas as pd
9
 
10
-
11
  # Function to fetch stock or crypto data
12
  def fetch_data(ticker_name, start_date, end_date):
13
- raw_data = yf.download(ticker_name, start=start_date, end=end_date)
 
 
 
 
14
  adjusted_close = raw_data['Adj Close'].dropna()
 
 
15
  prices = adjusted_close.values
16
  log_returns = np.log(prices[1:] / prices[:-1])
17
  return adjusted_close, log_returns
@@ -70,14 +75,10 @@ with st.expander("Wasserstein Distance Methodology", expanded=False):
70
  A high distance indicates a significant shift in price dynamics, potentially due to a market event or a change in investor behavior.
71
  """)
72
 
73
-
74
  st.sidebar.title("""
75
  Input Parameters
76
  """)
77
 
78
- #st.write(f"Threshold: {threshold}")
79
-
80
- # Sidebar for "How to Use" instructions inside an expander, closed by default
81
  with st.sidebar.expander("How to Use", expanded=False):
82
  st.write("""
83
  **How to use this app:**
@@ -88,55 +89,58 @@ with st.sidebar.expander("How to Use", expanded=False):
88
  5. Click 'Run Analysis' to start.
89
  """)
90
 
91
- # Input parameters inside an expander, open by default
92
  with st.sidebar.expander("Input Parameters", expanded=True):
93
  ticker_name = st.text_input('Enter Stock or Crypto Symbol (e.g., AAPL or BTC-USD)', '^GSPC', help="Enter the ticker symbol for the stock or cryptocurrency you want to analyze.")
94
  start_date_string = st.date_input('Start Date', pd.to_datetime('2020-01-01'), help="Select the start date for the data range.")
95
  end_date_string = st.date_input('End Date', pd.to_datetime(pd.Timestamp.now().date() + pd.Timedelta(days=1)), help="Select the end date for the data range.")
96
 
97
- # Parameters for the selected method inside an expander, open by default
98
  with st.sidebar.expander("Parameters", expanded=True):
99
  window_size = st.slider('Window Size', min_value=5, max_value=50, value=20, help="Set the window size for the sliding window analysis.")
100
  threshold = st.slider('Alert Threshold', min_value=0.02, max_value=0.2, value=0.075, step=0.005, help="Set the threshold for detecting significant changes in price dynamics.")
101
 
102
- # Run Analysis button in the sidebar
103
  if st.sidebar.button('Run Analysis'):
104
- st.write(f"Analyzing {ticker_name} from {start_date_string} to {end_date_string} with window size {window_size} and threshold {threshold}")
105
-
106
- # Fetch data
107
- prices, log_returns = fetch_data(ticker_name, start_date_string, end_date_string)
108
- rips = Rips(maxdim=2)
109
- wasserstein_dists = compute_wasserstein_distances(log_returns, window_size, rips)
110
-
111
- # Plotting with Plotly
112
- dates = prices.index[window_size:-window_size]
113
- valid_indices = ~np.isnan(wasserstein_dists.flatten())
114
- valid_dates = dates[valid_indices]
115
- valid_distances = wasserstein_dists[valid_indices].flatten()
116
-
117
- alert_indices = [i for i, d in enumerate(valid_distances) if d > threshold]
118
- alert_dates = [valid_dates[i] for i in alert_indices]
119
- alert_values = [prices.iloc[i + window_size] for i in alert_indices]
120
-
121
- # Plot price and alerts
122
- fig = go.Figure()
123
- fig.add_trace(go.Scatter(x=valid_dates, y=prices.iloc[window_size:-window_size], mode='lines', name='Price'))
124
- fig.add_trace(go.Scatter(x=alert_dates, y=alert_values, mode='markers', name='Alert', marker=dict(color='red', size=8)))
125
- fig.update_layout(title=f'{ticker_name} Prices Over Time', xaxis_title='Date', yaxis_title='Price')
126
- st.plotly_chart(fig, use_container_width=True)
127
-
128
- # Plot Wasserstein distances
129
- fig = go.Figure()
130
- fig.add_trace(go.Scatter(x=valid_dates, y=valid_distances, mode='lines', name='Wasserstein Distance', line=dict(color='blue', width=2)))
131
- fig.add_hline(y=threshold, line_dash='dash', line_color='red', annotation_text=f'Threshold: {threshold}', annotation_position='bottom right')
132
- fig.update_layout(title='Wasserstein Distances Over Time', xaxis_title='Date', yaxis_title='Wasserstein Distance')
133
- st.plotly_chart(fig, use_container_width=True)
134
-
135
- st.write("""
136
- **Plot Interpretation:**
137
- - The first plot shows the asset price over time with alerts marked in red.
138
- - The second plot displays the Wasserstein distances over time, with the threshold indicated by a dashed red line. Peaks above this line represent significant changes in price dynamics.
139
- """)
 
 
 
 
 
 
140
 
141
  st.markdown(
142
  """
@@ -157,4 +161,4 @@ hide_streamlit_style = """
157
  footer {visibility: hidden;}
158
  </style>
159
  """
160
- st.markdown(hide_streamlit_style, unsafe_allow_html=True)
 
7
  import warnings
8
  import pandas as pd
9
 
 
10
  # Function to fetch stock or crypto data
11
  def fetch_data(ticker_name, start_date, end_date):
12
+ raw_data = yf.download(ticker_name, start=start_date, end=end_date, auto_adjust=False) # Unadjusted prices
13
+ if isinstance(raw_data.columns, pd.MultiIndex): # Flatten multi-index
14
+ raw_data.columns = raw_data.columns.get_level_values(0)
15
+ if raw_data.empty:
16
+ raise ValueError(f"No data found for {ticker_name} from {start_date} to {end_date}")
17
  adjusted_close = raw_data['Adj Close'].dropna()
18
+ if len(adjusted_close) < 2: # Need at least 2 points for log returns
19
+ raise ValueError(f"Insufficient data points for {ticker_name}")
20
  prices = adjusted_close.values
21
  log_returns = np.log(prices[1:] / prices[:-1])
22
  return adjusted_close, log_returns
 
75
  A high distance indicates a significant shift in price dynamics, potentially due to a market event or a change in investor behavior.
76
  """)
77
 
 
78
  st.sidebar.title("""
79
  Input Parameters
80
  """)
81
 
 
 
 
82
  with st.sidebar.expander("How to Use", expanded=False):
83
  st.write("""
84
  **How to use this app:**
 
89
  5. Click 'Run Analysis' to start.
90
  """)
91
 
 
92
  with st.sidebar.expander("Input Parameters", expanded=True):
93
  ticker_name = st.text_input('Enter Stock or Crypto Symbol (e.g., AAPL or BTC-USD)', '^GSPC', help="Enter the ticker symbol for the stock or cryptocurrency you want to analyze.")
94
  start_date_string = st.date_input('Start Date', pd.to_datetime('2020-01-01'), help="Select the start date for the data range.")
95
  end_date_string = st.date_input('End Date', pd.to_datetime(pd.Timestamp.now().date() + pd.Timedelta(days=1)), help="Select the end date for the data range.")
96
 
 
97
  with st.sidebar.expander("Parameters", expanded=True):
98
  window_size = st.slider('Window Size', min_value=5, max_value=50, value=20, help="Set the window size for the sliding window analysis.")
99
  threshold = st.slider('Alert Threshold', min_value=0.02, max_value=0.2, value=0.075, step=0.005, help="Set the threshold for detecting significant changes in price dynamics.")
100
 
 
101
  if st.sidebar.button('Run Analysis'):
102
+ try:
103
+ st.write(f"Analyzing {ticker_name} from {start_date_string} to {end_date_string} with window size {window_size} and threshold {threshold}")
104
+
105
+ # Fetch data
106
+ prices, log_returns = fetch_data(ticker_name, start_date_string, end_date_string)
107
+ if len(log_returns) < 2 * window_size:
108
+ raise ValueError(f"Insufficient data: Need at least {2 * window_size} log returns, got {len(log_returns)}")
109
+
110
+ rips = Rips(maxdim=2)
111
+ wasserstein_dists = compute_wasserstein_distances(log_returns, window_size, rips)
112
+
113
+ # Plotting with Plotly
114
+ dates = prices.index[window_size:-window_size]
115
+ valid_indices = ~np.isnan(wasserstein_dists.flatten())
116
+ valid_dates = dates[valid_indices]
117
+ valid_distances = wasserstein_dists[valid_indices].flatten()
118
+
119
+ alert_indices = [i for i, d in enumerate(valid_distances) if d > threshold]
120
+ alert_dates = [valid_dates[i] for i in alert_indices]
121
+ alert_values = [prices.iloc[i + window_size] for i in alert_indices]
122
+
123
+ # Plot price and alerts
124
+ fig = go.Figure()
125
+ fig.add_trace(go.Scatter(x=valid_dates, y=prices.iloc[window_size:-window_size], mode='lines', name='Price'))
126
+ fig.add_trace(go.Scatter(x=alert_dates, y=alert_values, mode='markers', name='Alert', marker=dict(color='red', size=8)))
127
+ fig.update_layout(title=f'{ticker_name} Prices Over Time', xaxis_title='Date', yaxis_title='Price')
128
+ st.plotly_chart(fig, use_container_width=True)
129
+
130
+ # Plot Wasserstein distances
131
+ fig = go.Figure()
132
+ fig.add_trace(go.Scatter(x=valid_dates, y=valid_distances, mode='lines', name='Wasserstein Distance', line=dict(color='blue', width=2)))
133
+ fig.add_hline(y=threshold, line_dash='dash', line_color='red', annotation_text=f'Threshold: {threshold}', annotation_position='bottom right')
134
+ fig.update_layout(title='Wasserstein Distances Over Time', xaxis_title='Date', yaxis_title='Wasserstein Distance')
135
+ st.plotly_chart(fig, use_container_width=True)
136
+
137
+ st.write("""
138
+ **Plot Interpretation:**
139
+ - The first plot shows the asset price over time with alerts marked in red.
140
+ - The second plot displays the Wasserstein distances over time, with the threshold indicated by a dashed red line. Peaks above this line represent significant changes in price dynamics.
141
+ """)
142
+ except Exception as e:
143
+ st.error(f"Error: {str(e)}. Check ticker symbol, date range, or window size.")
144
 
145
  st.markdown(
146
  """
 
161
  footer {visibility: hidden;}
162
  </style>
163
  """
164
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)