JQ87 commited on
Commit
8158647
·
verified ·
1 Parent(s): 798da31

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -66
app.py CHANGED
@@ -15,9 +15,9 @@ def get_base64_image(image_path):
15
  return base64.b64encode(img_file.read()).decode()
16
 
17
  # Logo als Base64 einlesen
18
- image_base64 = get_base64_image("JQ.png")
19
 
20
- # CSS für fixiertes Logo OHNE Hintergrund & kleinerer Text
21
  st.markdown(
22
  f"""
23
  <style>
@@ -29,12 +29,6 @@ st.markdown(
29
  z-index: 1000;
30
  text-align: center;
31
  }}
32
- .small-text {{
33
- font-size: 14px; /* Kleinere Schriftgröße */
34
- margin-top: 30px; /* Abstand nach unten */
35
- text-align: center;
36
- color: gray; /* Dezente graue Farbe */
37
- }}
38
  </style>
39
  <div class="fixed-logo">
40
  <img src="data:image/png;base64,{image_base64}" width="250">
@@ -53,12 +47,49 @@ st.markdown("<br><br><br>", unsafe_allow_html=True)
53
  # Titel der App
54
  st.title("📈 Interaktive Analyse von Aktienindizes")
55
 
56
- # Liste der wichtigsten Aktien-Indizes mit Yahoo Finance Ticker
57
  indices = {
 
 
 
 
 
58
  "S&P 500 (USA)": "^GSPC",
59
  "Nasdaq 100 (USA)": "^NDX",
60
- "Dow Jones (USA)": "^DJI",
61
  "Russell 2000 (USA)": "^RUT",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  }
63
 
64
  # Dropdown für Ticker 1 & Ticker 2
@@ -76,37 +107,72 @@ end_date = st.date_input("Enddatum", default_end_date)
76
  # Farben für die Linien (fixe Farben für Konsistenz)
77
  color_ticker1 = "#1f77b4" # Blau
78
  color_ticker2 = "#ff7f0e" # Orange
 
79
 
80
  # Button zum Laden der Daten
81
  if st.button("GO"):
82
 
83
- # Daten abrufen
84
- data = {}
 
85
  for name, symbol in [(ticker1_name, ticker1), (ticker2_name, ticker2)]:
86
  ticker = yf.Ticker(symbol)
87
  df = ticker.history(start=start_date, end=end_date)
88
- data[name] = df["Close"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
- # In DataFrame umwandeln
91
- df_indices = pd.DataFrame(data)
92
 
93
- # Falls keine Daten geladen wurden, abbrechen
94
- if df_indices.empty:
95
- st.error("❌ Keine Daten für die gewählten Indizes gefunden!")
96
- else:
97
  # --------- 1. INTERAKTIVER CHART: Vergleich mit zwei Achsen ---------
98
  fig1 = go.Figure()
99
-
100
  # Linke Achse (Ticker 1)
101
  fig1.add_trace(go.Scatter(
102
  x=df_indices.index, y=df_indices[ticker1_name], mode='lines',
103
  name=ticker1_name, yaxis='y1', line=dict(color=color_ticker1)))
104
-
105
  # Rechte Achse (Ticker 2)
106
  fig1.add_trace(go.Scatter(
107
  x=df_indices.index, y=df_indices[ticker2_name], mode='lines',
108
  name=ticker2_name, yaxis='y2', line=dict(color=color_ticker2)))
109
-
110
  # Layout mit zwei Achsen definieren
111
  fig1.update_layout(
112
  title=f"Vergleich der Close-Preise: {ticker1_name} vs. {ticker2_name}",
@@ -116,83 +182,72 @@ if st.button("GO"):
116
  legend=dict(x=0, y=1),
117
  hovermode="x"
118
  )
119
-
120
  # Streamlit: Interaktives Chart anzeigen
121
  st.plotly_chart(fig1, use_container_width=True)
122
-
123
  # --------- 2. INTERAKTIVER CHART: Normierter Vergleich ---------
124
  df_normalized = df_indices / df_indices.iloc[0] * 100
125
-
126
  # Rendite berechnen (% Veränderung von Start bis Ende)
127
- start_price_ticker1 = df_indices[ticker1_name].iloc[0]
128
- end_price_ticker1 = df_indices[ticker1_name].iloc[-1]
129
- return_ticker1 = ((end_price_ticker1 - start_price_ticker1) / start_price_ticker1) * 100
130
-
131
- start_price_ticker2 = df_indices[ticker2_name].iloc[0]
132
- end_price_ticker2 = df_indices[ticker2_name].iloc[-1]
133
- return_ticker2 = ((end_price_ticker2 - start_price_ticker2) / start_price_ticker2) * 100
134
-
135
- # Rundung auf 2 Nachkommastellen
136
- return_ticker1 = round(return_ticker1, 2)
137
- return_ticker2 = round(return_ticker2, 2)
138
-
139
  # Namen mit Rendite für die Legende anpassen
140
  legend_ticker1 = f"{ticker1_name} = {return_ticker1}%"
141
  legend_ticker2 = f"{ticker2_name} = {return_ticker2}%"
142
-
143
  # Diagramm 2 mit Renditen in der Legende anzeigen
144
  fig2 = px.line(df_normalized, x=df_normalized.index, y=df_normalized.columns,
145
  title="Normierter Vergleich der Close-Preise",
146
  labels={"value": "Index (Startwert = 100)", "variable": "Index"},
147
  template="plotly_white",
148
  color_discrete_map={ticker1_name: color_ticker1, ticker2_name: color_ticker2})
149
-
150
  # Legenden-Namen ändern
151
  fig2.for_each_trace(lambda t: t.update(name=legend_ticker1 if t.name == ticker1_name else legend_ticker2))
152
-
153
  # Legendenposition anpassen (oben rechts, wie in Chart 1)
154
  fig2.update_layout(legend=dict(x=0, y=1))
155
-
156
-
157
  # Streamlit: Interaktives Chart anzeigen
158
  st.plotly_chart(fig2, use_container_width=True)
159
-
160
- # --------- 3. INTERAKTIVER CHART: Relative Performance (Differenz der normierten Werte) ---------
161
  df_relative_performance = df_normalized[ticker1_name] - df_normalized[ticker2_name]
162
-
163
- # Berechnung der Gesamtrendite der relativen Performance von Start bis Ende
164
- start_relative = df_relative_performance.iloc[0]
165
- end_relative = df_relative_performance.iloc[-1]
166
- relative_performance_change = end_relative - start_relative # Direkte Differenz
167
-
168
- # Rundung auf 2 Nachkommastellen
169
- relative_performance_change = round(relative_performance_change, 2)
170
-
171
  # Legenden-Text mit relativer Performance
172
- legend_relative = f"{ticker1_name} - {ticker2_name} = {relative_performance_change} Punkte"
173
-
174
  # Chart für relative Performance erstellen
175
  fig3 = px.line(x=df_relative_performance.index, y=df_relative_performance,
176
  title=f"Relative Performance: {ticker1_name} vs. {ticker2_name}",
177
- labels={"x": "Datum", "y": "Relative Performance"},
178
  template="plotly_white")
179
-
180
  # Farbe der Linie auf die gleiche wie Index 1 setzen
181
- fig3.update_traces(line=dict(color=color_ticker1), name=legend_relative)
182
-
183
  # Legendenposition anpassen (oben rechts, wie in Chart 1 und 2)
184
  fig3.update_layout(legend=dict(x=0, y=1))
185
-
186
  # Letzten Wert als Text direkt ins Chart einfügen
187
  fig3.add_annotation(
188
- x=df_relative_performance.index[-1], # Letztes Datum
189
- y=df_relative_performance.iloc[-1], # Letzter Wert der Performance
190
- text=f"{df_relative_performance.iloc[-1]:.2f}%", # Formatierte Anzeige
191
  showarrow=True,
192
  arrowhead=2,
193
- font=dict(size=14, color=color_ticker1),
194
- ax=20, ay=-40 # Position der Anzeige leicht anpassen
195
  )
196
-
197
  # Streamlit: Chart anzeigen
198
  st.plotly_chart(fig3, use_container_width=True)
 
 
 
 
 
15
  return base64.b64encode(img_file.read()).decode()
16
 
17
  # Logo als Base64 einlesen
18
+ image_base64 = get_base64_image("JQ.png") # Bild lokal im Space hochgeladen
19
 
20
+ # CSS für fixiertes Logo OHNE Hintergrund
21
  st.markdown(
22
  f"""
23
  <style>
 
29
  z-index: 1000;
30
  text-align: center;
31
  }}
 
 
 
 
 
 
32
  </style>
33
  <div class="fixed-logo">
34
  <img src="data:image/png;base64,{image_base64}" width="250">
 
47
  # Titel der App
48
  st.title("📈 Interaktive Analyse von Aktienindizes")
49
 
 
50
  indices = {
51
+ # 🌎 Globale Indizes
52
+ #"MSCI World": "^MSCI",
53
+ #"MSCI Emerging Markets": "EEM",
54
+
55
+ # 🇺🇸 USA
56
  "S&P 500 (USA)": "^GSPC",
57
  "Nasdaq 100 (USA)": "^NDX",
58
+ "Dow Jones Industrial Average (USA)": "^DJI",
59
  "Russell 2000 (USA)": "^RUT",
60
+
61
+ # 🇪🇺 Europa
62
+ "DAX (Deutschland)": "^GDAXI",
63
+ "MDAX (Deutschland)": "^MDAXI",
64
+ "CAC 40 (Frankreich)": "^FCHI",
65
+ "FTSE 100 (UK)": "^FTSE",
66
+ "EURO STOXX 50": "^STOXX50E",
67
+ "AEX (Niederlande)": "^AEX",
68
+ "IBEX 35 (Spanien)": "^IBEX",
69
+
70
+ # 🇨🇭 Schweiz
71
+ "SMI (Schweiz)": "^SSMI",
72
+
73
+ # 🇨🇳 China
74
+ "Shanghai Composite": "000001.SS",
75
+ "Hang Seng (Hongkong)": "^HSI",
76
+
77
+ # 🇯🇵 Japan
78
+ "Nikkei 225": "^N225",
79
+ "TOPIX": "^TOPX",
80
+
81
+ # 🇮🇳 Indien
82
+ "BSE Sensex": "^BSESN",
83
+ "Nifty 50": "^NSEI",
84
+
85
+ # 🇦🇺 Australien
86
+ "ASX 200": "^AXJO",
87
+
88
+ # 🇨🇦 Kanada
89
+ "TSX Composite": "^GSPTSE",
90
+
91
+ # 🇧🇷 Brasilien
92
+ "Bovespa": "^BVSP"
93
  }
94
 
95
  # Dropdown für Ticker 1 & Ticker 2
 
107
  # Farben für die Linien (fixe Farben für Konsistenz)
108
  color_ticker1 = "#1f77b4" # Blau
109
  color_ticker2 = "#ff7f0e" # Orange
110
+ color_ticker3 = "#e377c2" # Pink
111
 
112
  # Button zum Laden der Daten
113
  if st.button("GO"):
114
 
115
+ # Daten abrufen (Erst `Adj Close`, falls nicht verfügbar `Close`)
116
+ data_dict = {}
117
+
118
  for name, symbol in [(ticker1_name, ticker1), (ticker2_name, ticker2)]:
119
  ticker = yf.Ticker(symbol)
120
  df = ticker.history(start=start_date, end=end_date)
121
+
122
+ # 🕒 Datum als Index setzen & Uhrzeit entfernen
123
+ df.index = pd.to_datetime(df.index).date # Konvertiert Timestamp zu Date ohne Uhrzeit
124
+
125
+ # Prüfe, ob `Adj Close` existiert, falls nicht, nutze `Close`
126
+ if "Adj Close" in df.columns and not df["Adj Close"].isna().all():
127
+ selected_data = df["Adj Close"]
128
+ elif "Close" in df.columns and not df["Close"].isna().all():
129
+ selected_data = df["Close"]
130
+ else:
131
+ st.warning(f"⚠️ Keine gültigen Daten für {name} ({symbol}) gefunden!")
132
+ continue # Falls keine Daten vorhanden sind, überspringen
133
+
134
+ # 🔹 Doppelte Einträge pro Tag entfernen → den letzten Wert behalten
135
+ selected_data = selected_data[~selected_data.index.duplicated(keep="last")]
136
+
137
+ # Spaltennamen für spätere Zusammenführung setzen
138
+ selected_data.name = name # Name des Index setzen
139
+
140
+ # Speichere bereinigte Daten für den Index
141
+ data_dict[name] = selected_data
142
+
143
+ # Sicherstellen, dass beide DataFrames existieren
144
+ if ticker1_name in data_dict and ticker2_name in data_dict:
145
+ df1 = data_dict[ticker1_name].to_frame()
146
+ df2 = data_dict[ticker2_name].to_frame()
147
+
148
+ # 🔹 Beide DataFrames über gemeinsamen `Index (Datum)` zusammenführen
149
+ df_indices = pd.merge(df1, df2, left_index=True, right_index=True, how="outer")
150
+
151
+ # Fehlende Werte mit vorherigem Wert füllen
152
+ df_indices.ffill(inplace=True)
153
+
154
+ # Falls noch NaN-Werte übrig sind, entfernen
155
+ df_indices.dropna(inplace=True)
156
+
157
+ # Falls keine Daten geladen wurden, abbrechen
158
+ if df_indices.empty:
159
+ st.error("❌ Keine gemeinsamen Daten für die gewählten Indizes gefunden!")
160
+ st.stop()
161
 
 
 
162
 
 
 
 
 
163
  # --------- 1. INTERAKTIVER CHART: Vergleich mit zwei Achsen ---------
164
  fig1 = go.Figure()
165
+
166
  # Linke Achse (Ticker 1)
167
  fig1.add_trace(go.Scatter(
168
  x=df_indices.index, y=df_indices[ticker1_name], mode='lines',
169
  name=ticker1_name, yaxis='y1', line=dict(color=color_ticker1)))
170
+
171
  # Rechte Achse (Ticker 2)
172
  fig1.add_trace(go.Scatter(
173
  x=df_indices.index, y=df_indices[ticker2_name], mode='lines',
174
  name=ticker2_name, yaxis='y2', line=dict(color=color_ticker2)))
175
+
176
  # Layout mit zwei Achsen definieren
177
  fig1.update_layout(
178
  title=f"Vergleich der Close-Preise: {ticker1_name} vs. {ticker2_name}",
 
182
  legend=dict(x=0, y=1),
183
  hovermode="x"
184
  )
185
+
186
  # Streamlit: Interaktives Chart anzeigen
187
  st.plotly_chart(fig1, use_container_width=True)
188
+
189
  # --------- 2. INTERAKTIVER CHART: Normierter Vergleich ---------
190
  df_normalized = df_indices / df_indices.iloc[0] * 100
191
+
192
  # Rendite berechnen (% Veränderung von Start bis Ende)
193
+ return_ticker1 = round(((df_indices[ticker1_name].iloc[-1] - df_indices[ticker1_name].iloc[0]) / df_indices[ticker1_name].iloc[0]) * 100, 2)
194
+ return_ticker2 = round(((df_indices[ticker2_name].iloc[-1] - df_indices[ticker2_name].iloc[0]) / df_indices[ticker2_name].iloc[0]) * 100, 2)
195
+
 
 
 
 
 
 
 
 
 
196
  # Namen mit Rendite für die Legende anpassen
197
  legend_ticker1 = f"{ticker1_name} = {return_ticker1}%"
198
  legend_ticker2 = f"{ticker2_name} = {return_ticker2}%"
199
+
200
  # Diagramm 2 mit Renditen in der Legende anzeigen
201
  fig2 = px.line(df_normalized, x=df_normalized.index, y=df_normalized.columns,
202
  title="Normierter Vergleich der Close-Preise",
203
  labels={"value": "Index (Startwert = 100)", "variable": "Index"},
204
  template="plotly_white",
205
  color_discrete_map={ticker1_name: color_ticker1, ticker2_name: color_ticker2})
206
+
207
  # Legenden-Namen ändern
208
  fig2.for_each_trace(lambda t: t.update(name=legend_ticker1 if t.name == ticker1_name else legend_ticker2))
209
+
210
  # Legendenposition anpassen (oben rechts, wie in Chart 1)
211
  fig2.update_layout(legend=dict(x=0, y=1))
212
+
 
213
  # Streamlit: Interaktives Chart anzeigen
214
  st.plotly_chart(fig2, use_container_width=True)
215
+
216
+ # --------- 3. INTERAKTIVER CHART: Relative Performance (Differenz der normierten Werte) ---------
217
  df_relative_performance = df_normalized[ticker1_name] - df_normalized[ticker2_name]
218
+
219
+ # Letzter Wert der relativen Performance berechnen
220
+ relative_performance_change = round(df_relative_performance.iloc[-1], 2)
221
+
 
 
 
 
 
222
  # Legenden-Text mit relativer Performance
223
+ legend_relative = f"{ticker1_name} - {ticker2_name} = {relative_performance_change}%"
224
+
225
  # Chart für relative Performance erstellen
226
  fig3 = px.line(x=df_relative_performance.index, y=df_relative_performance,
227
  title=f"Relative Performance: {ticker1_name} vs. {ticker2_name}",
228
+ labels={"x": "Datum", "y": "Relative Performance (%)"},
229
  template="plotly_white")
230
+
231
  # Farbe der Linie auf die gleiche wie Index 1 setzen
232
+ fig3.update_traces(line=dict(color=color_ticker3), name=legend_relative)
233
+
234
  # Legendenposition anpassen (oben rechts, wie in Chart 1 und 2)
235
  fig3.update_layout(legend=dict(x=0, y=1))
236
+
237
  # Letzten Wert als Text direkt ins Chart einfügen
238
  fig3.add_annotation(
239
+ x=df_relative_performance.index[-1],
240
+ y=df_relative_performance.iloc[-1],
241
+ text=f"{df_relative_performance.iloc[-1]:.2f}%",
242
  showarrow=True,
243
  arrowhead=2,
244
+ font=dict(size=14, color=color_ticker3),
245
+ ax=20, ay=-40
246
  )
247
+
248
  # Streamlit: Chart anzeigen
249
  st.plotly_chart(fig3, use_container_width=True)
250
+
251
+ # Daten-Check: DataFrame anzeigen
252
+ #st.subheader("📊 Rohdaten der ausgewählten Indizes")
253
+ #st.dataframe(df_indices)