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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +64 -114
app.py CHANGED
@@ -9,33 +9,35 @@ import networkx as nx
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.
30
- """
31
- )
32
-
33
- # User inputs in the sidebar
34
- tickers = st.sidebar.text_area("Asset Symbol (Crypto-Pair or Stock Ticker) (comma-separated)", value="BTC-USD,ETH-USD,BNB-USD,ADA-USD,SOL-USD,DOT-USD,DOGE-USD,AVAX-USD,MATIC-USD,LTC-USD,LUNA1-USD,LINK-USD,ALGO-USD,ATOM-USD,FTT-USD,TRX-USD,ETC-USD,FIL-USD,XMR-USD,XLM-USD").split(",")
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:
@@ -50,9 +52,8 @@ if run_button:
50
  data = data.fillna(method='ffill').dropna()
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()
@@ -74,48 +75,27 @@ if run_button:
74
  # Ensure no inf or NaN values in returns
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
-
83
- st.latex(r"""
84
- \text{State Equation:} \quad \mathbf{x}_t = \mathbf{A} \mathbf{x}_{t-1} + \mathbf{w}_t
85
- """)
86
-
87
- st.latex(r"""
88
- \text{Observation Equation:} \quad \mathbf{y}_t = \mathbf{H} \mathbf{x}_t + \mathbf{v}_t
89
- """)
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:
105
- 1. **Initialization:** Start with an initial estimate of the state vector \(\mathbf{x}_0\) and the initial covariance.
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
121
  initial_state_mean = np.zeros(1)
@@ -142,32 +122,16 @@ if run_button:
142
  )
143
  st.plotly_chart(fig, use_container_width=True)
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]
173
  returns = returns.drop(columns=[market_index])
@@ -183,7 +147,6 @@ if run_button:
183
  cssd = calculate_cssd(returns.values, market_return.values)
184
  csad = calculate_csad(returns.values, market_return.values)
185
 
186
- # Rolling CSSD and CSAD calculations
187
  window_size = 30
188
 
189
  def rolling_csad(stock_returns, market_returns, window):
@@ -222,21 +185,9 @@ if run_button:
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):
@@ -246,7 +197,6 @@ if run_button:
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:
@@ -302,4 +252,4 @@ hide_streamlit_style = """
302
  footer {visibility: hidden;}
303
  </style>
304
  """
305
- 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 Financial Markets")
13
+
14
+ st.markdown("This app analyzes herding behavior in financial markets by examining price movements and correlations.")
15
+
16
+ # Sidebar: How to Use (closed by default)
17
+ with st.sidebar.expander("How to Use", expanded=False):
18
+ st.write(
19
+ """
20
+ 1. Select the stock ticker or crypto pairs.
21
+ 2. Choose the time period.
22
+ 3. Set additional parameters for the analyses.
23
+ 4. Click 'Run Analysis' to see the results.
24
+ """
25
+ )
26
+
27
+ # Sidebar: Assets and Dates (open by default)
28
+ with st.sidebar.expander("Assets and Dates", expanded=True):
29
+ tickers = st.text_area("Asset Symbols (Crypto-Pair or Stock Ticker) (comma-separated)",
30
+ value="BTC-USD,ETH-USD,BNB-USD,ADA-USD,SOL-USD,DOT-USD,DOGE-USD,AVAX-USD,MATIC-USD,LTC-USD,LUNA1-USD,LINK-USD,ALGO-USD,ATOM-USD,FTT-USD,TRX-USD,ETC-USD,FIL-USD,XMR-USD,XLM-USD").split(",")
31
+ start_date = st.date_input("Start Date", value=pd.to_datetime("2020-01-01"))
32
+ end_date = st.date_input("End Date", value=pd.to_datetime(pd.Timestamp.now().date() + pd.Timedelta(days=1)))
33
+
34
+ # Sidebar: Market Index and Correlation (open by default)
35
+ with st.sidebar.expander("Market Index and Correlation", expanded=True):
36
+ market_index = st.text_input("Market Index Ticker", value="BTC-USD")
37
+ correlation_threshold = st.slider("Correlation Threshold (for Network Analysis)",
38
+ min_value=0.0, max_value=1.0, value=0.75, step=0.05)
39
+
40
+ # Run Analysis button
41
  run_button = st.sidebar.button("Run Analysis")
42
 
43
  if run_button:
 
52
  data = data.fillna(method='ffill').dropna()
53
  data = data.replace([np.inf, -np.inf], np.nan).dropna()
54
 
55
+ st.markdown("### Asset Prices Reindexed to Start at 0")
56
+ st.markdown("Reindexed asset prices to compare their relative movements over time.")
 
57
 
58
  data_reindexed = data.apply(lambda x: x / x.iloc[0])
59
  fig = go.Figure()
 
75
  # Ensure no inf or NaN values in returns
76
  returns = returns.replace([np.inf, -np.inf], np.nan).dropna()
77
 
78
+ st.markdown("### Kalman Filter: Estimated Common Factor and Asset Returns")
79
+ st.markdown("Using the Kalman Filter to estimate a common factor influencing all asset returns.")
80
+
81
+ # Methodology in expander
82
+ with st.expander("Kalman Filter Methodology", expanded=False):
83
+ st.markdown("The Kalman Filter operates based on the following state-space model:")
84
+ st.latex(r"""
85
+ \text{State Equation:} \quad \mathbf{x}_t = \mathbf{A} \mathbf{x}_{t-1} + \mathbf{w}_t
86
+ """)
87
+ st.latex(r"""
88
+ \text{Observation Equation:} \quad \mathbf{y}_t = \mathbf{H} \mathbf{x}_t + \mathbf{v}_t
89
+ """)
90
+ st.markdown("""
91
+ Where:
92
+ - \(xt\) is the state vector (the common factor we are estimating).
93
+ - \(A\) is the state transition matrix (set to the identity matrix \(I\)).
94
+ - \(wt\) is the process noise (with covariance \(Q\)).
95
+ - \(yt\) is the observation vector (asset returns).
96
+ - \(H\) is the observation matrix (set to a vector of ones).
97
+ - \(vt\) is the observation noise (with covariance \(R\)).
98
+ """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
  observations = returns.values
101
  initial_state_mean = np.zeros(1)
 
122
  )
123
  st.plotly_chart(fig, use_container_width=True)
124
 
125
+ st.markdown("### CSSD and CSAD Calculations")
126
+ st.markdown("Calculating the Cross-Sectional Standard Deviation (CSSD) and Cross-Sectional Absolute Deviation (CSAD) of asset returns.")
 
 
 
 
 
 
127
 
128
+ # Methodology in expander
129
+ with st.expander("CSSD and CSAD Methodology", expanded=False):
130
+ st.markdown("The formulas for CSSD and CSAD are as follows:")
131
+ st.markdown("**CSSD (Cross-Sectional Standard Deviation):**")
132
+ st.latex(r"\text{CSSD}_t = \sqrt{\frac{\sum_{i=1}^{N} (R_{i,t} - \overline{R}_t)^2}{N - 1}}")
133
+ st.markdown("**CSAD (Cross-Sectional Absolute Deviation):**")
134
+ st.latex(r"\text{CSAD}_t = \frac{\sum_{i=1}^{N} |R_{i,t} - \overline{R}_t|}{N}")
 
 
 
 
 
 
 
 
 
 
135
 
136
  market_return = returns[market_index]
137
  returns = returns.drop(columns=[market_index])
 
147
  cssd = calculate_cssd(returns.values, market_return.values)
148
  csad = calculate_csad(returns.values, market_return.values)
149
 
 
150
  window_size = 30
151
 
152
  def rolling_csad(stock_returns, market_returns, window):
 
185
  )
186
  st.plotly_chart(fig, use_container_width=True)
187
 
188
+ st.markdown("### Network Visualization of Asset Correlations")
189
+ st.markdown("Visualizing the correlations between assets as a network. Assets are connected by edges if their correlation exceeds a threshold.")
 
 
 
190
 
 
 
 
 
 
 
 
 
 
191
  years = data.index.year.unique()
192
 
193
  def plot_network_for_year(data_for_year, year, threshold):
 
197
  for ticker in tickers:
198
  G.add_node(ticker)
199
 
 
200
  for i in range(len(tickers)):
201
  for j in range(i+1, len(tickers)):
202
  if abs(corr_matrix.iloc[i, j]) > threshold:
 
252
  footer {visibility: hidden;}
253
  </style>
254
  """
255
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)