QuantumLearner commited on
Commit
cde486e
·
verified ·
1 Parent(s): 00e5508

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +45 -41
app.py CHANGED
@@ -5,13 +5,10 @@ import plotly.express as px
5
  import os
6
 
7
  # Global API key and default ETF symbols
8
-
9
  API_KEY = os.getenv("FMP_API_KEY")
10
 
11
  ETF_ASSET_SYMBOL = "SPY" # Used for asset composition
12
-
13
- # For sector and country composition, you may adjust this as needed.
14
- ETF_SYMBOL = "QDVE.DE"
15
 
16
  def format_number(n):
17
  """
@@ -33,15 +30,19 @@ def format_number(n):
33
  @st.cache_data(show_spinner=False)
34
  def get_etf_asset_composition(etf_symbol: str) -> pd.DataFrame:
35
  url = f"https://financialmodelingprep.com/api/v3/etf-holder/{etf_symbol}?apikey={API_KEY}"
36
- response = requests.get(url)
37
- response.raise_for_status()
38
- data = response.json()
39
- if not data:
 
 
 
 
 
 
 
 
40
  return pd.DataFrame()
41
- df = pd.DataFrame(data)
42
- df['marketValue'] = pd.to_numeric(df['marketValue'], errors='coerce')
43
- df_sorted = df.sort_values(by="marketValue", ascending=False)
44
- return df_sorted
45
 
46
  def plot_etf_asset_composition(df: pd.DataFrame, etf_symbol: str):
47
  if df.empty:
@@ -76,15 +77,18 @@ def plot_etf_asset_composition(df: pd.DataFrame, etf_symbol: str):
76
  @st.cache_data(show_spinner=False)
77
  def get_etf_sector_composition(etf_symbol: str) -> pd.DataFrame:
78
  url = f"https://financialmodelingprep.com/api/v3/etf-sector-weightings/{etf_symbol}?apikey={API_KEY}"
79
- response = requests.get(url)
80
- response.raise_for_status()
81
- data = response.json()
82
- if not data:
 
 
 
 
 
 
 
83
  return pd.DataFrame()
84
- df = pd.DataFrame(data)
85
- df['weightPercentage'] = df['weightPercentage'].str.rstrip('%').astype(float)
86
- df_sorted = df.sort_values(by="weightPercentage", ascending=False)
87
- return df_sorted
88
 
89
  def plot_etf_sector_composition(df: pd.DataFrame, etf_symbol: str):
90
  if df.empty:
@@ -110,15 +114,18 @@ def plot_etf_sector_composition(df: pd.DataFrame, etf_symbol: str):
110
  @st.cache_data(show_spinner=False)
111
  def get_etf_country_composition(etf_symbol: str) -> pd.DataFrame:
112
  url = f"https://financialmodelingprep.com/api/v3/etf-country-weightings/{etf_symbol}?apikey={API_KEY}"
113
- response = requests.get(url)
114
- response.raise_for_status()
115
- data = response.json()
116
- if not data:
 
 
 
 
 
 
 
117
  return pd.DataFrame()
118
- df = pd.DataFrame(data)
119
- df['weightPercentage'] = df['weightPercentage'].str.rstrip('%').astype(float)
120
- df_sorted = df.sort_values(by="weightPercentage", ascending=False)
121
- return df_sorted
122
 
123
  def plot_etf_country_composition(df: pd.DataFrame, etf_symbol: str):
124
  if df.empty:
@@ -145,13 +152,13 @@ def main():
145
  st.set_page_config(page_title="ETF Asset Composition Dashboard", layout="wide")
146
  st.title("ETF Asset Composition Dashboard")
147
  st.write(
148
- "This dashboard displays the composition of an ETF. "
149
  "Use the side menu to enter the ETF ticker symbol and then click the 'Run ETF Composition' button. "
150
- "The dashboard is divided into three sections: Asset Composition, Sector Composition, and Country Composition. "
151
  "Each section includes a chart and a data table. Hover over the charts for more details."
152
  )
153
 
154
- # Initialize run button session state variable
155
  if "run_etf" not in st.session_state:
156
  st.session_state.run_etf = False
157
 
@@ -166,14 +173,13 @@ def main():
166
  st.session_state.run_etf = True
167
  st.session_state.etf_ticker = etf_ticker
168
 
169
- # Main content: Only show dashboard if run button was pressed
170
  if st.session_state.get("run_etf", False):
171
  # Section 1: ETF Asset Composition
172
  st.header("1. ETF Asset Composition")
173
  st.write(
174
- "This section shows the holdings of the ETF by asset. "
175
- "The bar chart displays each asset's market value, shares held, and weight in the ETF. "
176
- "The data table below shows the raw holdings data."
177
  )
178
  asset_df = get_etf_asset_composition(st.session_state.etf_ticker)
179
  asset_fig = plot_etf_asset_composition(asset_df, st.session_state.etf_ticker)
@@ -185,9 +191,8 @@ def main():
185
  # Section 2: Sector Composition
186
  st.header("2. Sector Composition")
187
  st.write(
188
- "This section displays the ETF's sector weighting. "
189
- "The bar chart visualizes the weight percentage of each sector represented in the ETF. "
190
- "The data table below contains the raw sector weighting data."
191
  )
192
  sector_df = get_etf_sector_composition(st.session_state.etf_ticker)
193
  sector_fig = plot_etf_sector_composition(sector_df, st.session_state.etf_ticker)
@@ -199,8 +204,8 @@ def main():
199
  # Section 3: Country Composition
200
  st.header("3. Country Composition")
201
  st.write(
202
- "This section shows the geographic distribution of the ETF's holdings by country. "
203
- "The bar chart displays the weight percentage by country, and the table below lists the detailed country weighting data."
204
  )
205
  country_df = get_etf_country_composition(st.session_state.etf_ticker)
206
  country_fig = plot_etf_country_composition(country_df, st.session_state.etf_ticker)
@@ -214,7 +219,6 @@ def main():
214
  if __name__ == "__main__":
215
  main()
216
 
217
-
218
  hide_streamlit_style = """
219
  <style>
220
  #MainMenu {visibility: hidden;}
 
5
  import os
6
 
7
  # Global API key and default ETF symbols
 
8
  API_KEY = os.getenv("FMP_API_KEY")
9
 
10
  ETF_ASSET_SYMBOL = "SPY" # Used for asset composition
11
+ ETF_SYMBOL = "QDVE.DE" # For sector and country composition, you may adjust this as needed.
 
 
12
 
13
  def format_number(n):
14
  """
 
30
  @st.cache_data(show_spinner=False)
31
  def get_etf_asset_composition(etf_symbol: str) -> pd.DataFrame:
32
  url = f"https://financialmodelingprep.com/api/v3/etf-holder/{etf_symbol}?apikey={API_KEY}"
33
+ try:
34
+ response = requests.get(url)
35
+ response.raise_for_status()
36
+ data = response.json()
37
+ if not data:
38
+ return pd.DataFrame()
39
+ df = pd.DataFrame(data)
40
+ df['marketValue'] = pd.to_numeric(df['marketValue'], errors='coerce')
41
+ df_sorted = df.sort_values(by="marketValue", ascending=False)
42
+ return df_sorted
43
+ except:
44
+ # Generic failover, no mention of the source
45
  return pd.DataFrame()
 
 
 
 
46
 
47
  def plot_etf_asset_composition(df: pd.DataFrame, etf_symbol: str):
48
  if df.empty:
 
77
  @st.cache_data(show_spinner=False)
78
  def get_etf_sector_composition(etf_symbol: str) -> pd.DataFrame:
79
  url = f"https://financialmodelingprep.com/api/v3/etf-sector-weightings/{etf_symbol}?apikey={API_KEY}"
80
+ try:
81
+ response = requests.get(url)
82
+ response.raise_for_status()
83
+ data = response.json()
84
+ if not data:
85
+ return pd.DataFrame()
86
+ df = pd.DataFrame(data)
87
+ df['weightPercentage'] = df['weightPercentage'].str.rstrip('%').astype(float)
88
+ df_sorted = df.sort_values(by="weightPercentage", ascending=False)
89
+ return df_sorted
90
+ except:
91
  return pd.DataFrame()
 
 
 
 
92
 
93
  def plot_etf_sector_composition(df: pd.DataFrame, etf_symbol: str):
94
  if df.empty:
 
114
  @st.cache_data(show_spinner=False)
115
  def get_etf_country_composition(etf_symbol: str) -> pd.DataFrame:
116
  url = f"https://financialmodelingprep.com/api/v3/etf-country-weightings/{etf_symbol}?apikey={API_KEY}"
117
+ try:
118
+ response = requests.get(url)
119
+ response.raise_for_status()
120
+ data = response.json()
121
+ if not data:
122
+ return pd.DataFrame()
123
+ df = pd.DataFrame(data)
124
+ df['weightPercentage'] = df['weightPercentage'].str.rstrip('%').astype(float)
125
+ df_sorted = df.sort_values(by="weightPercentage", ascending=False)
126
+ return df_sorted
127
+ except:
128
  return pd.DataFrame()
 
 
 
 
129
 
130
  def plot_etf_country_composition(df: pd.DataFrame, etf_symbol: str):
131
  if df.empty:
 
152
  st.set_page_config(page_title="ETF Asset Composition Dashboard", layout="wide")
153
  st.title("ETF Asset Composition Dashboard")
154
  st.write(
155
+ "Analyze the composition of an ETF. "
156
  "Use the side menu to enter the ETF ticker symbol and then click the 'Run ETF Composition' button. "
157
+ "The analysis is divided into three sections: Asset Composition, Sector Composition, and Country Composition. "
158
  "Each section includes a chart and a data table. Hover over the charts for more details."
159
  )
160
 
161
+ # Initialize run button state
162
  if "run_etf" not in st.session_state:
163
  st.session_state.run_etf = False
164
 
 
173
  st.session_state.run_etf = True
174
  st.session_state.etf_ticker = etf_ticker
175
 
176
+ # Main content
177
  if st.session_state.get("run_etf", False):
178
  # Section 1: ETF Asset Composition
179
  st.header("1. ETF Asset Composition")
180
  st.write(
181
+ "Shows the top holdings by market value. "
182
+ "The bar chart includes each asset's market value, shares held, and weight in the ETF."
 
183
  )
184
  asset_df = get_etf_asset_composition(st.session_state.etf_ticker)
185
  asset_fig = plot_etf_asset_composition(asset_df, st.session_state.etf_ticker)
 
191
  # Section 2: Sector Composition
192
  st.header("2. Sector Composition")
193
  st.write(
194
+ "Displays the ETF's sector weighting. "
195
+ "The bar chart visualizes each sector's percentage in the portfolio."
 
196
  )
197
  sector_df = get_etf_sector_composition(st.session_state.etf_ticker)
198
  sector_fig = plot_etf_sector_composition(sector_df, st.session_state.etf_ticker)
 
204
  # Section 3: Country Composition
205
  st.header("3. Country Composition")
206
  st.write(
207
+ "Shows the geographic distribution of the ETF's holdings by country. "
208
+ "The bar chart displays the weight percentage by country."
209
  )
210
  country_df = get_etf_country_composition(st.session_state.etf_ticker)
211
  country_fig = plot_etf_country_composition(country_df, st.session_state.etf_ticker)
 
219
  if __name__ == "__main__":
220
  main()
221
 
 
222
  hide_streamlit_style = """
223
  <style>
224
  #MainMenu {visibility: hidden;}