QuantumLearner commited on
Commit
37fd55b
·
verified ·
1 Parent(s): 510dfb7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -57
app.py CHANGED
@@ -9,21 +9,21 @@ import networkx as nx
9
  # Streamlit app setup
10
  st.set_page_config(layout="wide")
11
 
12
- st.title("Herding Behaviour Analysis in Cryptocurrency Markets")
13
 
14
  st.markdown(
15
  """
16
- This app analyzes herding behavior in cryptocurrency markets by examining price movements and correlations.
17
- You can specify the cryptocurrency pairs, time period, and other parameters for the analysis.
18
  The app includes various analyses such as price reindexing, Kalman Filter estimation of a common factor,
19
- CSSD and CSAD calculations, rolling CSSD and CSAD, and network visualization of correlations.
20
  """
21
  )
22
 
23
  st.sidebar.header("How to use")
24
  st.sidebar.write(
25
  """
26
- 1. Select the cryptocurrency pairs.
27
  2. Choose the time period.
28
  3. Set additional parameters for the analyses.
29
  4. Click 'Run Analysis' to see the results.
@@ -35,6 +35,7 @@ tickers = st.sidebar.text_area("Asset Symbol (Crypto-Pair or Stock Ticker) (comm
35
  start_date = st.sidebar.date_input("Start Date", value=pd.to_datetime("2020-01-01"))
36
  end_date = st.sidebar.date_input("End Date", value=pd.to_datetime("2025-01-01"))
37
  market_index = st.sidebar.text_input("Market Index Ticker", value="BTC-USD")
 
38
  run_button = st.sidebar.button("Run Analysis")
39
 
40
  if run_button:
@@ -42,7 +43,7 @@ if run_button:
42
  if market_index not in tickers:
43
  tickers.append(market_index)
44
 
45
- # Fetching cryptocurrency data
46
  data = yf.download(tickers, start=start_date, end=end_date)['Close']
47
 
48
  # Clean the data by filling or dropping NaN and infinite values
@@ -50,8 +51,8 @@ if run_button:
50
  data = data.replace([np.inf, -np.inf], np.nan).dropna()
51
 
52
  # Reindexing prices to start at 0
53
- st.markdown("#### Cryptocurrency Prices Reindexed to Start at 0")
54
- st.markdown("This analysis reindexes cryptocurrency prices to start at 0, making it easier to compare their relative movements over time.")
55
 
56
  data_reindexed = data.apply(lambda x: x / x.iloc[0])
57
  fig = go.Figure()
@@ -60,7 +61,7 @@ if run_button:
60
  fig.add_trace(go.Scatter(x=data_reindexed.index, y=data_reindexed[ticker], mode='lines', name=ticker))
61
 
62
  fig.update_layout(
63
- title="Cryptocurrency Prices Reindexed to Start at 0",
64
  xaxis_title="Date",
65
  yaxis_title="Reindexed Price",
66
  template="plotly_dark"
@@ -74,8 +75,8 @@ if run_button:
74
  returns = returns.replace([np.inf, -np.inf], np.nan).dropna()
75
 
76
  # Kalman Filter: Estimating a common factor
77
- st.markdown("#### Kalman Filter: Estimated Common Factor and Cryptocurrency Returns")
78
- st.markdown("This analysis uses the Kalman Filter to estimate a common factor influencing all cryptocurrency returns. It compares individual cryptocurrency returns to the estimated common factor.")
79
 
80
  st.markdown("The Kalman Filter operates based on the following state-space model:")
81
 
@@ -89,17 +90,15 @@ if run_button:
89
 
90
  st.markdown("Where:")
91
  st.markdown(r"""
92
- \begin{itemize}
93
- \item \(\mathbf{x}_t\) is the state vector (the common factor we are estimating).
94
- \item \(\mathbf{A}\) is the state transition matrix (set to the identity matrix \(\mathbf{I}\)).
95
- \item \(\mathbf{w}_t\) is the process noise (with covariance \(\mathbf{Q}\)).
96
- \item \(\mathbf{y}_t\) is the observation vector (cryptocurrency returns).
97
- \item \(\mathbf{H}\) is the observation matrix (set to a vector of ones).
98
- \item \(\mathbf{v}_t\) is the observation noise (with covariance \(\mathbf{R}\)).
99
- \end{itemize}
100
  """)
101
 
102
- st.markdown("The Kalman Filter recursively estimates the state vector \(\mathbf{x}_t\) using the observed cryptocurrency returns \(\mathbf{y}_t\). The estimated common factor is then compared to individual cryptocurrency returns.")
103
 
104
  st.markdown("""
105
  The steps to derive the common factor are:
@@ -107,17 +106,15 @@ if run_button:
107
  2. **Prediction:** Use the state equation to predict the state vector at the next time step.
108
  3. **Update:** Use the observation equation and the actual observed returns to update the estimate of the state vector.
109
 
110
- This process repeats for each time step, producing an estimated common factor that influences all cryptocurrency returns.
111
  """)
112
 
113
  st.markdown("""
114
  **How to Interpret the Results:**
115
 
116
- - **Estimated Common Factor:** This represents the underlying factor that influences all the cryptocurrency returns. If the common factor is high, it indicates that most cryptocurrencies are experiencing high returns. Conversely, if the common factor is low, it indicates that most cryptocurrencies are experiencing low returns.
117
- - **Individual Cryptocurrency Returns vs. Common Factor:** By comparing the individual cryptocurrency returns to the estimated common factor, you can identify which cryptocurrencies are moving with the market trend and which are moving independently.
118
- - **Deviation from the Common Factor:** Cryptocurrencies that deviate significantly from the common factor may be influenced by specific news or events, whereas cryptocurrencies that closely follow the common factor are more influenced by market-wide factors.
119
-
120
- By observing these comparisons, you can gain insights into the behavior of individual cryptocurrencies relative to the market and identify potential outliers or trend-followers.
121
  """)
122
 
123
  observations = returns.values
@@ -138,7 +135,7 @@ if run_button:
138
 
139
  fig.add_trace(go.Scatter(x=returns.index, y=state_means[:, 0], mode='lines', name='Estimated Common Factor', line=dict(color='red', width=4)))
140
  fig.update_layout(
141
- title='Kalman Filter: Estimated Common Factor and Cryptocurrency Returns',
142
  xaxis_title='Date',
143
  yaxis_title='Returns',
144
  template='plotly_dark'
@@ -147,39 +144,29 @@ if run_button:
147
 
148
  # CSSD and CSAD calculations
149
  st.markdown("#### CSSD and CSAD Calculations")
150
- st.markdown("This analysis calculates the Cross-Sectional Standard Deviation (CSSD) and Cross-Sectional Absolute Deviation (CSAD) of cryptocurrency returns. These metrics help to identify herding behavior in the market.")
151
 
152
  st.markdown("The formulas for CSSD and CSAD are as follows:")
153
 
154
  st.markdown("**CSSD (Cross-Sectional Standard Deviation):**")
155
  st.latex(r"\text{CSSD}_t = \sqrt{\frac{\sum_{i=1}^{N} (R_{i,t} - \overline{R}_t)^2}{N - 1}}")
156
 
157
- st.markdown("""
158
- Where:
159
- - \(R_{i,t}\) is the return of cryptocurrency \(i\) at time \(t\).
160
- - \(\overline{R}_t\) is the average return of all cryptocurrencies at time \(t\).
161
- - \(N\) is the number of cryptocurrencies.
162
- """)
163
-
164
  st.markdown("**CSAD (Cross-Sectional Absolute Deviation):**")
165
  st.latex(r"\text{CSAD}_t = \frac{\sum_{i=1}^{N} |R_{i,t} - \overline{R}_t|}{N}")
166
 
167
  st.markdown("""
168
  Where:
169
- - \(R_{i,t}\) is the return of cryptocurrency \(i\) at time \(t\).
170
- - \(\overline{R}_t\) is the average return of all cryptocurrencies at time \(t\).
171
- - \(N\) is the number of cryptocurrencies.
172
  """)
173
-
174
- st.markdown("These metrics help to identify herding behavior by measuring the dispersion of individual cryptocurrency returns around the market return.")
175
 
176
  st.markdown("""
177
  **How to Interpret the Results:**
178
 
179
- - **CSSD (Cross-Sectional Standard Deviation):** A higher CSSD indicates greater dispersion of individual cryptocurrency returns around the market return, suggesting less herding behavior. Conversely, a lower CSSD indicates that cryptocurrency returns are more closely clustered around the market return, suggesting more herding behavior.
180
- - **CSAD (Cross-Sectional Absolute Deviation):** A higher CSAD also indicates greater dispersion of individual cryptocurrency returns around the market return, suggesting less herding behavior. A lower CSAD suggests more herding behavior as cryptocurrency returns are more closely clustered around the market return.
181
-
182
- By observing the trends in CSSD and CSAD over time, you can identify periods of increased or decreased herding behavior in the market.
183
  """)
184
 
185
  market_return = returns[market_index]
@@ -235,31 +222,31 @@ if run_button:
235
  )
236
  st.plotly_chart(fig, use_container_width=True)
237
 
238
- # Network visualization of cryptocurrency correlations
239
- st.markdown("#### Network Visualization of Cryptocurrency Correlations")
240
- st.markdown("This analysis visualizes the correlations between cryptocurrencies as a network. Cryptocurrencies are connected by edges if their correlation exceeds a threshold.")
241
  st.markdown("""
242
  **How to Interpret the Results:**
243
 
244
- - **Nodes:** Each node represents a cryptocurrency. The position of the nodes is determined by a spring layout algorithm, which places highly connected nodes closer together.
245
- - **Edges:** An edge (or line) between two nodes indicates that the correlation between the two cryptocurrencies exceeds the specified threshold (0.5 in this case).
246
  - **Edge Thickness:** The thickness of the edge represents the strength of the correlation. Thicker edges indicate higher correlations.
247
- - **Cluster Formation:** Groups of nodes that are densely connected to each other represent clusters of cryptocurrencies that move together. This can indicate sector-specific movements or broader market trends.
248
- - **Isolated Nodes:** Nodes that are not connected to others suggest that those cryptocurrencies do not have strong correlations with the rest of the market within the given threshold.
249
 
250
- By examining this network, you can identify groups of cryptocurrencies that tend to move together, which may reflect sector-specific behavior or broader market dynamics. This can provide insights into the structure of the market and potential areas of risk or opportunity.
251
  """)
252
 
253
  years = data.index.year.unique()
254
 
255
- def plot_network_for_year(data_for_year, year):
256
  corr_matrix = data_for_year.corr()
257
  G = nx.Graph()
258
 
259
  for ticker in tickers:
260
  G.add_node(ticker)
261
 
262
- threshold = 0.5
263
  for i in range(len(tickers)):
264
  for j in range(i+1, len(tickers)):
265
  if abs(corr_matrix.iloc[i, j]) > threshold:
@@ -294,7 +281,7 @@ if run_button:
294
  )
295
 
296
  layout = go.Layout(
297
- title=f'Cryptocurrency Correlation Network for {year}',
298
  showlegend=False,
299
  hovermode='closest',
300
  margin=dict(b=20, l=5, r=5, t=40),
@@ -307,7 +294,7 @@ if run_button:
307
 
308
  for year in years:
309
  data_for_year = data[data.index.year == year]
310
- plot_network_for_year(data_for_year, year)
311
 
312
  hide_streamlit_style = """
313
  <style>
@@ -315,4 +302,4 @@ hide_streamlit_style = """
315
  footer {visibility: hidden;}
316
  </style>
317
  """
318
- st.markdown(hide_streamlit_style, unsafe_allow_html=True)
 
9
  # Streamlit app setup
10
  st.set_page_config(layout="wide")
11
 
12
+ st.title("Herding Behaviour Analysis in Financials Markets")
13
 
14
  st.markdown(
15
  """
16
+ This app analyzes herding behavior in financial markets by examining price movements and correlations.
17
+ You can specify the stock ticker or Asset pairs, time period, and other parameters for the analysis.
18
  The app includes various analyses such as price reindexing, Kalman Filter estimation of a common factor,
19
+ CSSD and CSAD calculations, and network visualization of correlations over time.
20
  """
21
  )
22
 
23
  st.sidebar.header("How to use")
24
  st.sidebar.write(
25
  """
26
+ 1. Select the stock ticker Asset pairs.
27
  2. Choose the time period.
28
  3. Set additional parameters for the analyses.
29
  4. Click 'Run Analysis' to see the results.
 
35
  start_date = st.sidebar.date_input("Start Date", value=pd.to_datetime("2020-01-01"))
36
  end_date = st.sidebar.date_input("End Date", value=pd.to_datetime("2025-01-01"))
37
  market_index = st.sidebar.text_input("Market Index Ticker", value="BTC-USD")
38
+ correlation_threshold = st.sidebar.slider("Correlation Threshold (for Network Analysis)", min_value=0.0, max_value=1.0, value=0.75, step=0.05)
39
  run_button = st.sidebar.button("Run Analysis")
40
 
41
  if run_button:
 
43
  if market_index not in tickers:
44
  tickers.append(market_index)
45
 
46
+ # Fetching Asset data
47
  data = yf.download(tickers, start=start_date, end=end_date)['Close']
48
 
49
  # Clean the data by filling or dropping NaN and infinite values
 
51
  data = data.replace([np.inf, -np.inf], np.nan).dropna()
52
 
53
  # Reindexing prices to start at 0
54
+ st.markdown("#### Asset Prices Reindexed to Start at 0")
55
+ st.markdown("This analysis reindexes asset prices to start at 0, making it easier to compare their relative movements over time.")
56
 
57
  data_reindexed = data.apply(lambda x: x / x.iloc[0])
58
  fig = go.Figure()
 
61
  fig.add_trace(go.Scatter(x=data_reindexed.index, y=data_reindexed[ticker], mode='lines', name=ticker))
62
 
63
  fig.update_layout(
64
+ title="Asset Prices Reindexed to Start at 0",
65
  xaxis_title="Date",
66
  yaxis_title="Reindexed Price",
67
  template="plotly_dark"
 
75
  returns = returns.replace([np.inf, -np.inf], np.nan).dropna()
76
 
77
  # Kalman Filter: Estimating a common factor
78
+ st.markdown("#### Kalman Filter: Estimated Common Factor and Asset Returns")
79
+ st.markdown("This analysis uses the Kalman Filter to estimate a common factor influencing all asset returns. It compares individual asset returns to the estimated common factor.")
80
 
81
  st.markdown("The Kalman Filter operates based on the following state-space model:")
82
 
 
90
 
91
  st.markdown("Where:")
92
  st.markdown(r"""
93
+ - \(xt\) is the state vector (the common factor we are estimating).
94
+ - \(A\) is the state transition matrix (set to the identity matrix \(I\)).
95
+ - \(wt\) is the process noise (with covariance \(Q\)).
96
+ - \(yt\) is the observation vector (asset returns).
97
+ - \(H\) is the observation matrix (set to a vector of ones).
98
+ - \(vt\) is the observation noise (with covariance \(R\)).
 
 
99
  """)
100
 
101
+ st.markdown("The Kalman Filter recursively estimates the state vector \(xt\) using the observed asset returns \( yt \). The estimated common factor is then compared to individual asset returns.")
102
 
103
  st.markdown("""
104
  The steps to derive the common factor are:
 
106
  2. **Prediction:** Use the state equation to predict the state vector at the next time step.
107
  3. **Update:** Use the observation equation and the actual observed returns to update the estimate of the state vector.
108
 
109
+ This process repeats for each time step, producing an estimated common factor that influences all asset returns.
110
  """)
111
 
112
  st.markdown("""
113
  **How to Interpret the Results:**
114
 
115
+ - **Estimated Common Factor:** This represents the underlying factor that influences all the asset returns. If the common factor is high, it indicates that most assets are experiencing high returns. Conversely, if the common factor is low, it indicates that most asset are experiencing low returns.
116
+ - **Individual Asset Returns vs. Common Factor:** By comparing the individual asset returns to the estimated common factor, you can identify which asset are moving with the market trend and which are moving independently.
117
+ - **Deviation from the Common Factor:** Assets that deviate significantly from the common factor may be influenced by specific news or events, whereas assets that closely follow the common factor are more influenced by market-wide factors.
 
 
118
  """)
119
 
120
  observations = returns.values
 
135
 
136
  fig.add_trace(go.Scatter(x=returns.index, y=state_means[:, 0], mode='lines', name='Estimated Common Factor', line=dict(color='red', width=4)))
137
  fig.update_layout(
138
+ title='Kalman Filter: Estimated Common Factor and Asset Returns',
139
  xaxis_title='Date',
140
  yaxis_title='Returns',
141
  template='plotly_dark'
 
144
 
145
  # CSSD and CSAD calculations
146
  st.markdown("#### CSSD and CSAD Calculations")
147
+ st.markdown("This analysis calculates the Cross-Sectional Standard Deviation (CSSD) and Cross-Sectional Absolute Deviation (CSAD) of Asset returns.")
148
 
149
  st.markdown("The formulas for CSSD and CSAD are as follows:")
150
 
151
  st.markdown("**CSSD (Cross-Sectional Standard Deviation):**")
152
  st.latex(r"\text{CSSD}_t = \sqrt{\frac{\sum_{i=1}^{N} (R_{i,t} - \overline{R}_t)^2}{N - 1}}")
153
 
 
 
 
 
 
 
 
154
  st.markdown("**CSAD (Cross-Sectional Absolute Deviation):**")
155
  st.latex(r"\text{CSAD}_t = \frac{\sum_{i=1}^{N} |R_{i,t} - \overline{R}_t|}{N}")
156
 
157
  st.markdown("""
158
  Where:
159
+ - Rit is the return of Asset i at time t.
160
+ - Rt is the average return of all Assets at time t.
161
+ - N is the number of Assets.
162
  """)
163
+
164
+ st.markdown("These metrics help to identify the dispersion of individual asset returns around the market return.")
165
 
166
  st.markdown("""
167
  **How to Interpret the Results:**
168
 
169
+ - **CSSD (Cross-Sectional Standard Deviation) and CSAD (Cross-Sectional Absolute Deviation):** Higher values indicate greater dispersion of asset returns around the market return, suggesting less herding behavior. Lower values indicate more clustering, suggesting more herding behavior.
 
 
 
170
  """)
171
 
172
  market_return = returns[market_index]
 
222
  )
223
  st.plotly_chart(fig, use_container_width=True)
224
 
225
+ # Network visualization of Asset correlations
226
+ st.markdown("#### Network Visualization of Asset Correlations")
227
+ st.markdown("This analysis visualizes the correlations between Assets as a network. Assets are connected by edges if their correlation exceeds a threshold.")
228
  st.markdown("""
229
  **How to Interpret the Results:**
230
 
231
+ - **Nodes:** Each node represents a Asset. The position of the nodes is determined by a spring layout algorithm, which places highly connected nodes closer together.
232
+ - **Edges:** An edge (or line) between two nodes indicates that the correlation between the two Assets exceeds the specified threshold (0.5 in this case).
233
  - **Edge Thickness:** The thickness of the edge represents the strength of the correlation. Thicker edges indicate higher correlations.
234
+ - **Cluster Formation:** Groups of nodes that are densely connected to each other represent clusters of Assets that move together. This can indicate sector-specific movements or broader market trends.
235
+ - **Isolated Nodes:** Nodes that are not connected to others suggest that those Assets do not have strong correlations with the rest of the market within the given threshold.
236
 
237
+ By examining this network, you can identify groups of Assets that tend to move together, which may reflect sector-specific behavior or broader market dynamics. This can provide insights into the structure of the market and potential areas of risk or opportunity.
238
  """)
239
 
240
  years = data.index.year.unique()
241
 
242
+ def plot_network_for_year(data_for_year, year, threshold):
243
  corr_matrix = data_for_year.corr()
244
  G = nx.Graph()
245
 
246
  for ticker in tickers:
247
  G.add_node(ticker)
248
 
249
+ #threshold = 0.5
250
  for i in range(len(tickers)):
251
  for j in range(i+1, len(tickers)):
252
  if abs(corr_matrix.iloc[i, j]) > threshold:
 
281
  )
282
 
283
  layout = go.Layout(
284
+ title=f'Asset Correlation Network for {year}',
285
  showlegend=False,
286
  hovermode='closest',
287
  margin=dict(b=20, l=5, r=5, t=40),
 
294
 
295
  for year in years:
296
  data_for_year = data[data.index.year == year]
297
+ plot_network_for_year(data_for_year, year, correlation_threshold)
298
 
299
  hide_streamlit_style = """
300
  <style>
 
302
  footer {visibility: hidden;}
303
  </style>
304
  """
305
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)