ghost_69 16. September Ich bin gerade wieder dabei mir ein paar Charts zu basteln und etwas mehr. Code für Python: import numpy as np import matplotlib.pyplot as plt # Annahmen für Kursentwicklung Alphabet (GOOGL) years = np.arange(0, 6) # 0 bis 5 Jahre current_year = 2025 year_labels = [str(current_year + i) for i in years] current_price = 220 # angenommener aktueller Kurs in USD # Szenarioannahmen (% Wachstum pro Jahr) growth_best = 0.20 # Best-Case: +20 % p.a. growth_base = 0.10 # Base-Case: +10 % p.a. growth_worst = -0.05 # Worst-Case: -5 % p.a. # Berechnung der Szenariopfade price_best = current_price * (1 + growth_best) ** years price_base = current_price * (1 + growth_base) ** years price_worst = current_price * (1 + growth_worst) ** years # Mittelwert (vereinfacht als Durchschnitt der drei Szenarien) price_mean = (price_best + price_base + price_worst) / 3 # Plot plt.figure(figsize=(10,6)) # Unsicherheitswolke (Bereich zwischen Worst und Best) plt.fill_between(years, price_worst, price_best, color='skyblue', alpha=0.3, label="Spanne (Worst - Best)") # Szenarienlinien plt.plot(years, price_best, color='green', linestyle='--', label="Best-Case (+20% p.a.)") plt.plot(years, price_base, color='blue', linestyle='-', label="Base-Case (+10% p.a.)") plt.plot(years, price_worst, color='red', linestyle='--', label="Worst-Case (-5% p.a.)") # Mittelwertlinie plt.plot(years, price_mean, color='black', linestyle='-', linewidth=2, label="Mittelwert") # X-Achse mit Jahreszahlen beschriften plt.xticks(years, year_labels) # Chart verschönern plt.title("Alphabet (GOOGL) – Szenario-Entwicklung (2025–2030)", fontsize=14) plt.xlabel("Jahr", fontsize=12) plt.ylabel("Kurs (USD)", fontsize=12) plt.legend() plt.grid(True, alpha=0.3) plt.show() Ergebnis: Alphabet.ipynb Ghost_69 Diesen Beitrag teilen Link zum Beitrag
ghost_69 16. September · bearbeitet 16. September von ghost_69 Ich möchte für verschiedene Werte eine Art Bewertung machen, hier mal ein Beispiel: Der Code dazu: Zitat import yfinance as yf import pandas as pd import numpy as np # Funktion, um sicher einen Float zu extrahieren def safe_float(x): if isinstance(x, pd.Series) or isinstance(x, pd.DataFrame): return float(x.iloc[-1].item()) if isinstance(x, pd.Series) else float(x.iloc[-1].values[-1]) return float(x) # Liste der Aktien aktien = { "GOOGL": "Alphabet Inc.", "AAPL": "Apple Inc.", "MSFT": "Microsoft Corp.", "AMZN": "Amazon.com Inc." } # DataFrame für Ergebnisse ergebnisse = pd.DataFrame(columns=[ "Symbol", "Name", "Golden Cross", "Momentum", "RSI", "Fibonacci", "Volatilität", "Bewertung (P/E)", "Umsatzwachstum", "Gewinnmarge", "Empfehlung" ]) for symbol, name in aktien.items(): # Daten der letzten 6 Monate data = yf.download(symbol, period="6mo", interval="1d", auto_adjust=True) # Momentum berechnen momentum = safe_float(data["Close"].pct_change().tail(1)) # RSI (vereinfacht) delta = data["Close"].diff() gain = delta.where(delta > 0, 0) loss = -delta.where(delta < 0, 0) avg_gain = gain.rolling(window=14).mean() avg_loss = loss.rolling(window=14).mean() rs = avg_gain / avg_loss rsi = safe_float(100 - (100 / (1 + rs))) # Gleitende Durchschnitte ma20 = data["Close"].rolling(window=20).mean() ma50 = data["Close"].rolling(window=50).mean() # Letzte Werte extrahieren als Float ma20_last = ma20.iloc[-1].item() ma50_last = ma50.iloc[-1].item() # Trend erkennen: 20-Tage über 50-Tage → Golden Cross aktiv if not (np.isnan(ma20_last) or np.isnan(ma50_last)): if ma20_last > ma50_last: golden_cross = "Ja" golden_cross_up = True golden_cross_down = False elif ma20_last < ma50_last: golden_cross = "Nein" golden_cross_up = False golden_cross_down = True else: golden_cross = "Nein" golden_cross_up = False golden_cross_down = False else: golden_cross = "Nein" golden_cross_up = False golden_cross_down = False # Volatilität vol = data["Close"].pct_change().rolling(window=20).std() volatility = safe_float(vol) # Fibonacci Level high = data["Close"].max() low = data["Close"].min() fibo_level = safe_float((data["Close"].iloc[-1] - low) / (high - low) * 100) # Beispielwerte für fundamentale Kennzahlen pe = np.random.uniform(15, 40) umsatzwachstum = np.random.uniform(5, 15) gewinnmarge = np.random.uniform(8, 30) # Empfehlung nach deiner Regel if golden_cross_up: empfehlung = "Kaufen" elif golden_cross_down: if rsi > 70: empfehlung = "Halten" else: empfehlung = "Verkaufen" else: empfehlung = "Halten" # Ergebnis speichern ergebnis_zeile = { "Symbol": symbol, "Name": name, "Golden Cross": golden_cross, "Momentum": f"{momentum*100:.2f}%", "RSI": f"{rsi:.1f}", "Fibonacci": f"{fibo_level:.1f}%", "Volatilität": f"{volatility*100:.2f}%", "Bewertung (P/E)": f"{pe:.1f}", "Umsatzwachstum": f"{umsatzwachstum:.0f}%", "Gewinnmarge": f"{gewinnmarge:.0f}%", "Empfehlung": empfehlung } ergebnisse = pd.concat([ergebnisse, pd.DataFrame([ergebnis_zeile])], ignore_index=True) # Ausgabe als saubere Tabelle pd.set_option('display.max_columns', None) # Alle Spalten anzeigen pd.set_option('display.width', 150) # Breite der Anzeige anpassen print(ergebnisse.to_string(index=False)) # Ohne Index ausgeben das ist nur ein Beispiel und hat noch nichts zu sagen. Gibt es eine gute Regel für die Empfehlungen ? Ghost_69 Diesen Beitrag teilen Link zum Beitrag
ghost_69 17. September ich bin weiter dabei: Score-Berechnung 1. Golden Cross (20-Tage-Durchschnitt > 50-Tage-Durchschnitt) → +1 Punkt 2. Fibonacci-Level unter 80 % → +1 Punkt 3. RSI über 50 → +1 Punkt 4. Volatilität < 2 % → +1 Punkt 5. Momentum > 0 → +1 Punkt 6. 200-Tage-Linie: Schlusskurs über 200-Tage-Durchschnitt → +1 Punkt Maximalpunkte: 6 Empfehlung je Score Score Empfehlung 6 = Kaufen 5 = Achtung Nachkauf 4–2 =Halten 1 = Achtung prüfen / Verkauf 0 = Verkaufen Das System bewertet also die Aktie anhand von Trend, Stärke, Volatilität und Momentum, und du bekommst eine übersichtliche Empfehlung. oder hat noch jemand eine andere Idee ? Ghost_69 Diesen Beitrag teilen Link zum Beitrag
stagflation 17. September · bearbeitet 17. September von stagflation Ich finde es schön, dass Du Python verwendest und auch den Source Code postest! Folgenden Code verstehe ich noch nicht: # Volatilität data = yf.download(symbol, period="6mo", interval="1d", auto_adjust=True) vol = data["Close"].pct_change().rolling(window=20).std() Wozu das Rolling Window? Und warum keine Annualisierung? Ich hätte eher etwas erwartet wie: # Volatilität data = yf.download( symbol, period="6mo", interval="1d", auto_adjust=True ) vol = data["Close"].pct_change().std() * sqrt( 250 ) wobei die Multiplikation mit Wurzel 250 die Annualisierung der Standardabweichung aus Tageskursen ist (man geht von 250 Handelstagen im Jahr aus). Manche rechnen auch mit stetigen Renditen: # Volatilität data = yf.download( symbol, period="6mo", interval="1d", auto_adjust=True ) vol = data["Close"].pct_change().apply( lambda x: log(x) ).std() * sqrt( 250 ) Ein Problem könnten schlechte Daten sein (fehlende Zeitbereiche oder Null-Werte, die von Yahoo kommen). Das müsste man vielleicht auch noch abfangen. Diesen Beitrag teilen Link zum Beitrag
ghost_69 18. September vor 16 Stunden von stagflation: Ich finde es schön, dass Du Python verwendest und auch den Source Code postest! Folgenden Code verstehe ich noch nicht: # Volatilität data = yf.download(symbol, period="6mo", interval="1d", auto_adjust=True) vol = data["Close"].pct_change().rolling(window=20).std() Wozu das Rolling Window? Und warum keine Annualisierung? Ich hätte eher etwas erwartet wie: # Volatilität data = yf.download( symbol, period="6mo", interval="1d", auto_adjust=True ) vol = data["Close"].pct_change().std() * sqrt( 250 ) wobei die Multiplikation mit Wurzel 250 die Annualisierung der Standardabweichung aus Tageskursen ist (man geht von 250 Handelstagen im Jahr aus). Manche rechnen auch mit stetigen Renditen: # Volatilität data = yf.download( symbol, period="6mo", interval="1d", auto_adjust=True ) vol = data["Close"].pct_change().apply( lambda x: log(x) ).std() * sqrt( 250 ) Ein Problem könnten schlechte Daten sein (fehlende Zeitbereiche oder Null-Werte, die von Yahoo kommen). Das müsste man vielleicht auch noch abfangen. Danke für Dein Interesse. Rolling Window, ich nehme nicht die gesamte Zeitreihe sondern das gleitende 20-Tage Fenster, das entspricht einem Handelsmonat, ich finde es zeigt die aktuelle Marktstimmung besser als über 6 Monate oder 1 Jahr. Annualisierung über 250 Handelstage, damit rechne ich die Jahresvolatilität, das ist die Klassische Finanzkennzahl. Variante mit stetigen Renditen, ist Mathematisch schöner, aber in der Praxis sind oft ähnliche Werte, nur bei größeren Sprüngen ist es robuster. Da ich hier noch ganz am Anfang stehe, gerne her mit Vorschlägen und Kritik. Das hier habe ich gestern noch gemacht: Zitat import yfinance as yf import pandas as pd import numpy as np import matplotlib.pyplot as plt from io import BytesIO import base64 from IPython.display import display, HTML # --- Sicherer Float-Konverter --- def safe_float(x): if isinstance(x, pd.Series): x = x.dropna() return float(x.iloc[-1]) if not x.empty else np.nan if isinstance(x, pd.DataFrame): x = x.dropna(how='all') if x.empty: return np.nan last_row = x.iloc[-1].dropna() return float(last_row.iloc[-1]) if not last_row.empty else np.nan try: return float(x) except: return np.nan # --- Mini-Chart / Sparkline --- def sparkline(data): fig, ax = plt.subplots(figsize=(2,0.5)) ax.plot(data, color='blue', linewidth=1) ax.axis('off') buf = BytesIO() plt.savefig(buf, format='png', bbox_inches='tight', dpi=100) plt.close(fig) buf.seek(0) img_base64 = base64.b64encode(buf.read()).decode('utf-8') return f'<img src="data:image/png;base64,{img_base64}">' # --- Aktienliste --- aktien = { "GOOGL": "Alphabet Inc.", "AAPL": "Apple Inc.", "MSFT": "Microsoft Corp.", "AMZN": "Amazon.com Inc." } # --- Ergebnis DataFrame --- ergebnisse = pd.DataFrame(columns=[ "Symbol", "Name", "Chart", "Golden Cross", "Momentum", "RSI", "Fibonacci", "Volatilität", "Score", "Empfehlung" ]) for symbol, name in aktien.items(): data = yf.download(symbol, period="6mo", interval="1d", auto_adjust=True) if data.empty: continue # Mini-Chart chart_html = sparkline(data['Close']) # Momentum (14 Tage) momentum_period = 14 momentum = safe_float(data["Close"] - data["Close"].shift(momentum_period)) # RSI (14) delta = data["Close"].diff() gain = delta.where(delta > 0, 0) loss = -delta.where(delta < 0, 0) avg_gain = gain.rolling(14).mean() avg_loss = loss.rolling(14).mean() rs = avg_gain / avg_loss rsi = safe_float(100 - (100 / (1 + rs))) # Gleitende Durchschnitte (Golden Cross) ma20 = data["Close"].rolling(20).mean() ma50 = data["Close"].rolling(50).mean() ma20_last = safe_float(ma20) ma50_last = safe_float(ma50) golden_cross = "Ja" if ma20_last > ma50_last else "Nein" # Volatilität (20 Tage Std.) vol = safe_float(data["Close"].pct_change().rolling(20).std()) # Fibonacci-Level high = safe_float(data["Close"].max()) low = safe_float(data["Close"].min()) close_last = safe_float(data["Close"]) fibo_level = ((close_last - low) / (high - low) * 100) if high != low else np.nan # --- Score Berechnung --- score = 0 if golden_cross == "Ja": score += 1 if not np.isnan(fibo_level) and fibo_level < 70: score += 1 # strenger if not np.isnan(rsi) and rsi > 50: score += 1 if not np.isnan(vol) and vol < 0.02: score += 1 # strenger if not np.isnan(momentum) and momentum > 0.01: score += 1 # nur deutliches Momentum # --- Empfehlung --- if score == 5: empfehlung = "Kaufen" elif score == 4: empfehlung = "Achtung Nachkauf" elif score in [2,3]: empfehlung = "Halten" elif score == 1: empfehlung = "Achtung prüfen/Verkauf" else: empfehlung = "Verkaufen" # Ergebnis speichern ergebnis_zeile = { "Symbol": symbol, "Name": name, "Chart": chart_html, "Golden Cross": golden_cross, "Momentum": f"{momentum:.2f}" if not np.isnan(momentum) else "n/a", "RSI": f"{rsi:.1f}" if not np.isnan(rsi) else "n/a", "Fibonacci": f"{fibo_level:.1f}%" if not np.isnan(fibo_level) else "n/a", "Volatilität": f"{vol*100:.2f}%" if not np.isnan(vol) else "n/a", "Score": score, "Empfehlung": empfehlung } ergebnisse = pd.concat([ergebnisse, pd.DataFrame([ergebnis_zeile])], ignore_index=True) # --- Anzeige in Jupyter --- pd.set_option('display.max_columns', None) pd.set_option('display.width', 200) display(HTML(ergebnisse.to_html(escape=False, index=False))) und dabei kommt das raus: dazwischen hatte ich noch einige andere Ideen und Versuche ist nicht leicht ans Ziel zu kommen. Ich bin übrigens ins Jupyter Lab und dort im Notebook unterwegs, da ich dort auch durch kurze Plots eine Zeile sehen kann und etwas verändern. Ghost_69 Diesen Beitrag teilen Link zum Beitrag
stagflation 18. September vor 3 Stunden von ghost_69: Rolling Window, ich nehme nicht die gesamte Zeitreihe sondern das gleitende 20-Tage Fenster, das entspricht einem Handelsmonat, ich finde es zeigt die aktuelle Marktstimmung besser als über 6 Monate oder 1 Jahr. Ah, okay, Du willst nur die letzten 20 Tage, also etwas wie: vol = data["Close"].tail(21).pct_change().std(). Das kann ich nachvollziehen. Ich war nur von rolling() verwirrt. Diesen Beitrag teilen Link zum Beitrag
ghost_69 18. September · bearbeitet 18. September von ghost_69 ich mache gerade weiter und teste, dabei ist mir ein Fehler aufgefallen, ich muss die meisten Werte doch auf die 200-Tage-Linie und dann brauche die die Kurse von min. 1 Jahr sonst passt die Berechnung nicht oder es kommen falsche Werte. Achja das sind keine Empfehlungen von mir, ich bastle nur etwas herum und das kann auch noch nicht stimmen, ich prüfe und vergleiche. Zitat import yfinance as yf import pandas as pd import numpy as np import matplotlib.pyplot as plt from io import BytesIO import base64 from IPython.display import display, HTML # --- Sicherer Float-Konverter --- def safe_float(x): if isinstance(x, pd.Series): x = x.dropna() return float(x.iloc[-1]) if not x.empty else np.nan if isinstance(x, pd.DataFrame): x = x.dropna(how='all') if x.empty: return np.nan last_row = x.iloc[-1].dropna() return float(last_row.iloc[-1]) if not last_row.empty else np.nan try: return float(x) except: return np.nan # --- Mini-Chart / Sparkline nur Kurs --- def sparkline(data): fig, ax = plt.subplots(figsize=(2,0.5)) ax.plot(data, color='blue', linewidth=1) ax.axis('off') buf = BytesIO() plt.savefig(buf, format='png', bbox_inches='tight', dpi=100) plt.close(fig) buf.seek(0) img_base64 = base64.b64encode(buf.read()).decode('utf-8') return f'<img src="data:image/png;base64,{img_base64}">' # --- Aktienliste (Beispiel mit 40 Werten) --- aktien = [ "AAPL","ABI.BR","ABT","ACN","AMZN","ASML.AS","BBZAD.XC","BC8.DE","CAT","CL", "COLO-B.CO","DHR","DIS","EVD.DE","FIE.DE","GEBN.SW","GILD","GIS","GOOG","HNR1.DE", "KO","MA","MDT","MO","MSFT","NOVO-B.CO","NSRGY","NVDA","NVS","PEP","PG","RKT.L", "ROST","SIX2.DE","TMO","TSM","UL","UNP","V","WKL.AS" ] # --- Ergebnis DataFrame --- ergebnisse = pd.DataFrame(columns=[ "Symbol", "Name", "Chart", "Golden Cross", "Über 200 Tage Linie", "Momentum", "RSI", "Fibonacci", "Volatilität", "Dividende", "P/E", "Umsatzwachstum", "Gewinnmarge", "Score", "Empfehlung" ]) for symbol in aktien: ticker = yf.Ticker(symbol) info = ticker.info name = info.get("shortName", symbol) # 1 Jahr historische Daten data = yf.download(symbol, period="1y", interval="1d", auto_adjust=True) if data.empty: continue # Mini-Chart chart_html = sparkline(data['Close']) # Momentum (14 Tage) momentum_period = 14 momentum = safe_float(data["Close"] - data["Close"].shift(momentum_period)) # RSI (14) delta = data["Close"].diff() gain = delta.where(delta > 0, 0) loss = -delta.where(delta < 0, 0) avg_gain = gain.rolling(14).mean() avg_loss = loss.rolling(14).mean() rs = avg_gain / avg_loss rsi = safe_float(100 - (100 / (1 + rs))) # Gleitende Durchschnitte ma20 = data["Close"].rolling(20).mean() ma50 = data["Close"].rolling(50).mean() ma200 = data["Close"].rolling(200).mean() ma20_last = safe_float(ma20) ma50_last = safe_float(ma50) ma200_last = safe_float(ma200) close_last = safe_float(data["Close"]) golden_cross = "Ja" if ma20_last > ma50_last else "Nein" over_200 = "Ja" if not np.isnan(ma200_last) and close_last > ma200_last else "Nein" # Volatilität (20 Tage) vol = safe_float(data["Close"].pct_change().rolling(20).std()) # Fibonacci-Level high = safe_float(data["Close"].max()) low = safe_float(data["Close"].min()) fibo_level = ((close_last - low) / (high - low) * 100) if high != low else np.nan # Fundamentale Kennzahlen div_yield = safe_float(info.get("dividendYield")) div_percent = f"{div_yield:.2f}%" if not np.isnan(div_yield) else "n/a" pe_ratio = safe_float(info.get("trailingPE")) pe_str = f"{pe_ratio:.2f}" if not np.isnan(pe_ratio) else "n/a" revenue_growth = safe_float(info.get("revenueGrowth")) rev_growth_str = f"{revenue_growth*100:.2f}%" if not np.isnan(revenue_growth) else "n/a" profit_margin = safe_float(info.get("profitMargins")) profit_margin_str = f"{profit_margin*100:.2f}%" if not np.isnan(profit_margin) else "n/a" # --- Score Berechnung --- score = 0 if golden_cross == "Ja": score += 1 if over_200 == "Ja": score += 1 if not np.isnan(fibo_level) and fibo_level < 70: score += 1 if not np.isnan(rsi) and rsi > 50: score += 1 if not np.isnan(vol) and vol < 0.02: score += 1 if not np.isnan(momentum) and momentum > 0.01: score += 1 # --- Empfehlung --- if score == 6: empfehlung = "Kaufen" elif score == 5: empfehlung = "Achtung Nachkauf" elif score in [2,3,4]: empfehlung = "Halten" elif score == 1: empfehlung = "Achtung prüfen/Verkauf" else: empfehlung = "Verkaufen" # Ergebnis speichern ergebnis_zeile = { "Symbol": symbol, "Name": name, "Chart": chart_html, "Golden Cross": golden_cross, "Über 200 Tage Linie": over_200, "Momentum": f"{momentum:.2f}" if not np.isnan(momentum) else "n/a", "RSI": f"{rsi:.1f}" if not np.isnan(rsi) else "n/a", "Fibonacci": f"{fibo_level:.1f}%" if not np.isnan(fibo_level) else "n/a", "Volatilität": f"{vol*100:.2f}%" if not np.isnan(vol) else "n/a", "Dividende": div_percent, "P/E": pe_str, "Umsatzwachstum": rev_growth_str, "Gewinnmarge": profit_margin_str, "Score": score, "Empfehlung": empfehlung } ergebnisse = pd.concat([ergebnisse, pd.DataFrame([ergebnis_zeile])], ignore_index=True) # --- Anzeige in Jupyter --- pd.set_option('display.max_columns', None) pd.set_option('display.width', 300) display(HTML(ergebnisse.to_html(escape=False, index=False))) # --- Legende --- legende = """ <h3>Legende zur Bewertung</h3> <ul> <li><b>Golden Cross:</b> Ja = 20-Tage-Linie über 50-Tage-Linie (bullish), Nein = unterhalb (bearish)</li> <li><b>200 Tage:</b> Ja = Kurs über 200-Tage-Linie (langfristig positiv), Nein = Kurs unter 200-Tage-Linie (langfristig negativ)</li> <li><b>Momentum:</b> Kurs höher als vor 14 Tagen = positiv</li> <li><b>RSI:</b> >50 = positiv, <50 = eher schwach</li> <li><b>Fibonacci:</b> Tiefer Wert = guter Rücksetzer, >70% = eher teuer</li> <li><b>Volatilität:</b> niedrig (<2%) = stabil, hoch = riskanter</li> <li><b>Dividende:</b> aktuelle Dividendenrendite in %</li> <li><b>P/E:</b> Kurs-Gewinn-Verhältnis</li> <li><b>Umsatzwachstum:</b> Veränderung des Umsatzes YoY in %</li> <li><b>Gewinnmarge:</b> Nettogewinn-Marge in %</li> </ul> <h4>Score und Empfehlung</h4> <ul> <li>6 Punkte = Kaufen</li> <li>5 Punkte = Achtung Nachkauf</li> <li>2–4 Punkte = Halten</li> <li>1 Punkt = Achtung prüfen / Verkauf</li> <li>0 Punkte = Verkaufen</li> </ul> """ display(HTML(legende)) dann das ganze noch als PDF: Zitat import pandas as pd from reportlab.lib.pagesizes import A4 from reportlab.pdfgen import canvas from reportlab.lib.utils import ImageReader from io import BytesIO import base64 # --- Hier dein DataFrame 'ergebnisse' laden oder erstellen --- # ergebnisse = ... (dein Aktien-DataFrame) # --- Pfad in Downloads --- pdf_file = r"C:\Users\Ghost\Downloads\Aktienanalyse.pdf" # --- PDF erstellen --- c = canvas.Canvas(pdf_file, pagesize=A4) width, height = A4 margin = 40 y_position = height - margin # Titel c.setFont("Helvetica-Bold", 16) c.drawString(margin, y_position, "Aktienanalyse") y_position -= 30 # Tabellenkopf c.setFont("Helvetica-Bold", 10) columns = ["Symbol", "Name", "Golden Cross", "Über 200 Tage Linie", "Momentum", "RSI", "Fibonacci", "Volatilität", "Dividende", "P/E", "Umsatzwachstum", "Gewinnmarge", "Empfehlung"] for idx, col in enumerate(columns): c.drawString(margin + idx*90, y_position, col) y_position -= 20 c.setFont("Helvetica", 10) # Tabelleninhalt for _, row in ergebnisse.iterrows(): if y_position < 50: c.showPage() y_position = height - margin c.setFont("Helvetica-Bold", 10) for idx, col in enumerate(columns): c.drawString(margin + idx*90, y_position, col) y_position -= 20 c.setFont("Helvetica", 10) for idx, col in enumerate(columns): value = str(row[col]) c.drawString(margin + idx*90, y_position, value) y_position -= 20 # PDF speichern c.save() print(f"PDF erfolgreich erstellt: {pdf_file}") oder als HTML Zitat html_content = ergebnisse.to_html(escape=False, index=False) legende = """ <h3>Legende zur Bewertung</h3> <ul> <li><b>Golden Cross:</b> Ja = 20-Tage-Linie über 50-Tage-Linie (bullish), Nein = unterhalb (bearish)</li> <li><b>200 Tage:</b> Ja = Kurs über 200-Tage-Linie (langfristig positiv), Nein = Kurs unter 200-Tage-Linie (langfristig negativ)</li> <li><b>Momentum:</b> Kurs höher als vor 14 Tagen = positiv</li> <li><b>RSI:</b> >50 = positiv, <50 = eher schwach</li> <li><b>Fibonacci:</b> Tiefer Wert = guter Rücksetzer, >70% = eher teuer</li> <li><b>Volatilität:</b> niedrig (<2%) = stabil, hoch = riskanter</li> <li><b>Dividende:</b> aktuelle Dividendenrendite in %</li> <li><b>P/E:</b> Kurs-Gewinn-Verhältnis</li> <li><b>Umsatzwachstum:</b> Veränderung des Umsatzes YoY in %</li> <li><b>Gewinnmarge:</b> Nettogewinn-Marge in %</li> </ul> """ full_html = f"<html><body>{html_content}<br>{legende}</body></html> 200-Tage-Linie-ok.ipynb Hier auch als HTML: Aktienanalyse.html Ghost_69 Diesen Beitrag teilen Link zum Beitrag
LongtermInvestor 18. September · bearbeitet 18. September von LongtermInvestor Am 17.9.2025 um 17:31 von ghost_69: oder hat noch jemand eine andere Idee ? Dir fehlt die komplette Dimension der fundamentalen Daten. Nur als Beispiel: Earnings Yield, FCF-Yield, Shares Outstanding, Gross Margin... Diesen Beitrag teilen Link zum Beitrag
ghost_69 19. September vor 18 Stunden von LongtermInvestor: Dir fehlt die komplette Dimension der fundamentalen Daten. Nur als Beispiel: Earnings Yield, FCF-Yield, Shares Outstanding, Gross Margin... Danke für Dein Interesse, Earnings Yield ist doch nur der Kehrwert (P/E = 20 ⇒ Earnings Yield = 5%), FCF-Yield, ist wirklich spannend: zeigt, wie viel freier Cashflow pro Marktkapitalisierung generiert wird, Shares Outstanding, die Zahl der Aktien im Umlauf, weiß nicht, eher für Aktienrückkäufe ?, Gross Margin, ich habe doch schon Umsatz und Gewinnmarge. Danke ich mache mal weiter Ghost_69 Diesen Beitrag teilen Link zum Beitrag
LongtermInvestor 19. September Ja, du hast natürlich recht mit PE, EY ist dann obsolet. Bei den Shares Outstandings ist aus Anteilseignersicht, die Veränderung z.B. in den letzen 12 Monaten interessant. Die Gross Margin finde ich interessant um zu beurteilen wie profitabel das Kernprodukt ist. Gerne in Ergänzung zur Net Margin. Return on Invested Capital (ROIC). Diesen Beitrag teilen Link zum Beitrag
ghost_69 19. September so hier mit 2 weiteren Kennzahlen: Zitat import yfinance as yf import pandas as pd import numpy as np import matplotlib.pyplot as plt from io import BytesIO import base64 from IPython.display import display, HTML # --- Sicherer Float-Konverter --- def safe_float(x): if isinstance(x, pd.Series): x = x.dropna() return float(x.iloc[-1]) if not x.empty else np.nan if isinstance(x, pd.DataFrame): x = x.dropna(how='all') if x.empty: return np.nan last_row = x.iloc[-1].dropna() return float(last_row.iloc[-1]) if not last_row.empty else np.nan try: return float(x) except: return np.nan # --- Mini-Chart / Sparkline nur Kurs --- def sparkline(data): fig, ax = plt.subplots(figsize=(2,0.5)) ax.plot(data, color='blue', linewidth=1) ax.axis('off') buf = BytesIO() plt.savefig(buf, format='png', bbox_inches='tight', dpi=100) plt.close(fig) buf.seek(0) img_base64 = base64.b64encode(buf.read()).decode('utf-8') return f'<img src="data:image/png;base64,{img_base64}">' # --- Aktienliste (Beispiel mit 40 Werten) --- aktien = [ "AAPL","ABI.BR","ABT","ACN","AMZN","ASML.AS","BBZAD.XC","BC8.DE","CAT","CL", "COLO-B.CO","DHR","DIS","EVD.DE","FIE.DE","GEBN.SW","GILD","GIS","GOOG","HNR1.DE", "KO","MA","MDT","MO","MSFT","NOVO-B.CO","NSRGY","NVDA","NVS","PEP","PG","RKT.L", "ROST","SIX2.DE","TMO","TSM","UL","UNP","V","WKL.AS" ] # --- Ergebnis DataFrame --- ergebnisse = pd.DataFrame(columns=[ "Symbol", "Name", "Chart", "Golden Cross", "Über 200 Tage Linie", "Momentum", "RSI", "Fibonacci", "Volatilität", "Dividende", "P/E", "Earnings Yield", "FCF-Yield", "Umsatzwachstum", "Gewinnmarge", "Score", "Empfehlung" ]) for symbol in aktien: ticker = yf.Ticker(symbol) info = ticker.info name = info.get("shortName", symbol) # 1 Jahr historische Daten data = yf.download(symbol, period="1y", interval="1d", auto_adjust=True) if data.empty: continue # Mini-Chart chart_html = sparkline(data['Close']) # Momentum (14 Tage) momentum_period = 14 momentum = safe_float(data["Close"] - data["Close"].shift(momentum_period)) # RSI (14) delta = data["Close"].diff() gain = delta.where(delta > 0, 0) loss = -delta.where(delta < 0, 0) avg_gain = gain.rolling(14).mean() avg_loss = loss.rolling(14).mean() rs = avg_gain / avg_loss rsi = safe_float(100 - (100 / (1 + rs))) # Gleitende Durchschnitte ma20 = data["Close"].rolling(20).mean() ma50 = data["Close"].rolling(50).mean() ma200 = data["Close"].rolling(200).mean() ma20_last = safe_float(ma20) ma50_last = safe_float(ma50) ma200_last = safe_float(ma200) close_last = safe_float(data["Close"]) golden_cross = "Ja" if ma20_last > ma50_last else "Nein" over_200 = "Ja" if not np.isnan(ma200_last) and close_last > ma200_last else "Nein" # Volatilität (20 Tage) vol = safe_float(data["Close"].pct_change().rolling(20).std()) # Fibonacci-Level high = safe_float(data["Close"].max()) low = safe_float(data["Close"].min()) fibo_level = ((close_last - low) / (high - low) * 100) if high != low else np.nan # Fundamentale Kennzahlen div_yield = safe_float(info.get("dividendYield")) div_percent = f"{div_yield:.2f}%" if not np.isnan(div_yield) else "n/a" pe_ratio = safe_float(info.get("trailingPE")) pe_str = f"{pe_ratio:.2f}" if not np.isnan(pe_ratio) else "n/a" # Earnings Yield = 1 / P/E earnings_yield = (1/pe_ratio*100) if not np.isnan(pe_ratio) and pe_ratio != 0 else np.nan earnings_yield_str = f"{earnings_yield:.2f}%" if not np.isnan(earnings_yield) else "n/a" # FCF-Yield = Free Cash Flow / Market Cap free_cf = safe_float(info.get("freeCashflow")) market_cap = safe_float(info.get("marketCap")) fcf_yield = (free_cf / market_cap * 100) if market_cap and not np.isnan(market_cap) else np.nan fcf_yield_str = f"{fcf_yield:.2f}%" if not np.isnan(fcf_yield) else "n/a" revenue_growth = safe_float(info.get("revenueGrowth")) rev_growth_str = f"{revenue_growth*100:.2f}%" if not np.isnan(revenue_growth) else "n/a" profit_margin = safe_float(info.get("profitMargins")) profit_margin_str = f"{profit_margin*100:.2f}%" if not np.isnan(profit_margin) else "n/a" # --- Score Berechnung --- score = 0 if golden_cross == "Ja": score += 1 if over_200 == "Ja": score += 1 if not np.isnan(fibo_level) and fibo_level < 70: score += 1 if not np.isnan(rsi) and rsi > 50: score += 1 if not np.isnan(vol) and vol < 0.02: score += 1 if not np.isnan(momentum) and momentum > 0.01: score += 1 # if not np.isnan(earnings_yield) and earnings_yield > 5: score += 1 if not np.isnan(fcf_yield) and fcf_yield > 5: score += 1 # --- Empfehlung --- if score == 7: empfehlung = "Kaufen" elif score == 6: empfehlung = "Achtung Nachkauf" elif score in [2,3,4,5]: empfehlung = "Halten" elif score == 1: empfehlung = "Achtung prüfen/Verkauf" else: empfehlung = "Verkaufen" # Ergebnis speichern ergebnis_zeile = { "Symbol": symbol, "Name": name, "Chart": chart_html, "Golden Cross": golden_cross, "Über 200 Tage Linie": over_200, "Momentum": f"{momentum:.2f}" if not np.isnan(momentum) else "n/a", "RSI": f"{rsi:.1f}" if not np.isnan(rsi) else "n/a", "Fibonacci": f"{fibo_level:.1f}%" if not np.isnan(fibo_level) else "n/a", "Volatilität": f"{vol*100:.2f}%" if not np.isnan(vol) else "n/a", "Dividende": div_percent, "P/E": pe_str, "Earnings Yield": earnings_yield_str, "FCF-Yield": fcf_yield_str, "Umsatzwachstum": rev_growth_str, "Gewinnmarge": profit_margin_str, "Score": score, "Empfehlung": empfehlung } ergebnisse = pd.concat([ergebnisse, pd.DataFrame([ergebnis_zeile])], ignore_index=True) # --- Anzeige in Jupyter --- pd.set_option('display.max_columns', None) pd.set_option('display.width', 300) display(HTML(ergebnisse.to_html(escape=False, index=False))) # --- Legende --- legende = """ <h3>Legende zur Bewertung</h3> <ul> <li><b>Golden Cross:</b> Ja = 20-Tage-Linie über 50-Tage-Linie (bullish), Nein = unterhalb (bearish)</li> <li><b>200 Tage:</b> Ja = Kurs über 200-Tage-Linie (langfristig positiv), Nein = Kurs unter 200-Tage-Linie (langfristig negativ)</li> <li><b>Momentum:</b> Kurs höher als vor 14 Tagen = positiv</li> <li><b>RSI:</b> >50 = positiv, <50 = eher schwach</li> <li><b>Fibonacci:</b> Tiefer Wert = guter Rücksetzer, >70% = eher teuer</li> <li><b>Volatilität:</b> niedrig (<2%) = stabil, hoch = riskanter</li> <li><b>Dividende:</b> aktuelle Dividendenrendite in %</li> <li><b>P/E:</b> Kurs-Gewinn-Verhältnis</li> <li><b>Earnings Yield:</b> 1 / P/E in %</li> <li><b>FCF-Yield:</b> Free Cash Flow / Market Cap in %</li> <li><b>Umsatzwachstum:</b> Veränderung des Umsatzes YoY in %</li> <li><b>Gewinnmarge:</b> Nettogewinn-Marge in %</li> </ul> <h4>Score und Empfehlung</h4> <ul> <li>7 Punkte = Kaufen</li> <li>6 Punkte = Achtung Nachkauf</li> <li>2–5 Punkte = Halten</li> <li>1 Punkt = Achtung prüfen / Verkauf</li> <li>0 Punkte = Verkaufen</li> </ul> """ display(HTML(legende)) Aktienanalyse.html 40Werte+HTLM+Zeitstempel.ipynb ganz oben habe ich einen Zeitstemple eingebaut, dann weiß man wann man ist. Code für das HTML: Zitat from datetime import datetime # Aktuelles Datum und Uhrzeit zeitstempel = datetime.now().strftime("%d.%m.%Y %H:%M:%S") # HTML-Content aus DataFrame html_content = ergebnisse.to_html(escape=False, index=False) # CSS für Schriftart wie in Jupyter style = """ <style> body { font-family: Arial, Helvetica, sans-serif; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ddd; padding: 8px; text-align: center; } th { background-color: #f2f2f2; } </style> """ # Legende mit Score legende = """ <h3>Legende zur Bewertung</h3> <ul> <li><b>Golden Cross:</b> Ja = 20-Tage-Linie über 50-Tage-Linie (bullish), Nein = unterhalb (bearish)</li> <li><b>200 Tage:</b> Ja = Kurs über 200-Tage-Linie (langfristig positiv), Nein = Kurs unter 200-Tage-Linie (langfristig negativ)</li> <li><b>Momentum:</b> Kurs höher als vor 14 Tagen = positiv</li> <li><b>RSI:</b> >50 = positiv, <50 = eher schwach</li> <li><b>Fibonacci:</b> Tiefer Wert = guter Rücksetzer, >70% = eher teuer</li> <li><b>Volatilität:</b> niedrig (<2%) = stabil, hoch = riskanter</li> <li><b>Dividende:</b> aktuelle Dividendenrendite in %</li> <li><b>P/E:</b> Kurs-Gewinn-Verhältnis</li> <li><b>Earnings Yield:</b> 1 / P/E in %, nur Anzeige</li> <li><b>FCF-Yield:</b> Free Cash Flow / Market Cap in %</li> <li><b>Umsatzwachstum:</b> Veränderung des Umsatzes YoY in %</li> <li><b>Gewinnmarge:</b> Nettogewinn-Marge in %</li> </ul> <h4>Score und Empfehlung</h4> <ul> <li>7 Punkte = Kaufen</li> <li>6 Punkte = Achtung Nachkauf</li> <li>2–5 Punkte = Halten</li> <li>1 Punkt = Achtung prüfen / Verkauf</li> <li>0 Punkte = Verkaufen</li> </ul> """ # --- Korrektes full_html mit Zeitstempel --- full_html = f""" <html> <head>{style}</head> <body> <p>Aktualisiert am: {zeitstempel}</p> {html_content}<br> {legende} </body> </html> Ghost_69 Diesen Beitrag teilen Link zum Beitrag
ghost_69 20. September so hier mal meine 40 Werte zum Wochenende, habe schon bemerkt das einige Werte sich gerade so bei 2 Stunden vor US-Börsenschluss sich schnell mal verändern und dann gleich wieder zurück, also geht es doch. Ich teste noch und möchte die Werte auf 100 Stück erhöhen. Aktienanalyse-20-09-2025.html Ghost_69 Diesen Beitrag teilen Link zum Beitrag
ghost_69 20. September · bearbeitet 20. September von ghost_69 Ich habe auf 96 Werte erhöht, 4 möchte ich noch, aktuell fallen mir keine ein, werden auf die Dauer aber sicherlich mehr werden. 96-Aktienanalyse-20-09-2025.html Auszug: Ghost_69 Diesen Beitrag teilen Link zum Beitrag
ghost_69 24. September ich habe den Code noch etwas angepasst: Zitat import yfinance as yf import pandas as pd import numpy as np import matplotlib.pyplot as plt from io import BytesIO import base64 from IPython.display import display, HTML # --- Sicherer Float-Konverter --- def safe_float(x): if isinstance(x, pd.Series): x = x.dropna() return float(x.iloc[-1]) if not x.empty else np.nan if isinstance(x, pd.DataFrame): x = x.dropna(how='all') if x.empty: return np.nan last_row = x.iloc[-1].dropna() return float(last_row.iloc[-1]) if not last_row.empty else np.nan try: return float(x) except: return np.nan # --- Mini-Chart / Sparkline nur Kurs --- def sparkline(data): fig, ax = plt.subplots(figsize=(2,0.5)) ax.plot(data, color='blue', linewidth=1) ax.axis('off') buf = BytesIO() plt.savefig(buf, format='png', bbox_inches='tight', dpi=100) plt.close(fig) buf.seek(0) img_base64 = base64.b64encode(buf.read()).decode('utf-8') return f'<img src="data:image/png;base64,{img_base64}">' # --- Aktienliste (alphabetisch & erweitert) --- aktien = [ "AAPL","ABI.BR","ABT","ACN","ADBE","ALV.DE","AMD","AMZN","ASML.AS","AZO", "BATS.L","BBZAD.XC","BC8.DE","BRK-B","AVGO","CSCO","CAT","CL","COLO-B.CO", "COST","DE","DELL","DB1.DE","DGE.L","DOL.TO","DHR","DIS","ELV","LLY","EFX","FICO", "GEBN.SW","GILD","GIS","GOOG","HNR1.DE","HLI","INTU","JNJ","JPM","KO", "LAB.MC","LIN","LMT","MELI","MA","META","MDT","MO","MCO","MSCI","MSFT", "MTX.DE","MUV2.DE","NEM.DE","NFLX","NEE","NKE","NOVO-B.CO","NSRGY","NVDA", "NVS","ORCL","ORLY","PEP","PG","QCOM","RDC.DE","RHM.DE","ROG.SW","RKLB", "RKT.L","ROST","SPGI","SHOP","SIE.DE","ENR.DE","SIX2.DE","SREN.SW","TJX", "TSLA","TXN","TMO","TSM","UL","UNH","UNP","V","WMT","WKL.AS" ] # --- Ergebnis DataFrame --- ergebnisse = pd.DataFrame(columns=[ "Symbol", "Name", "Chart", "Golden Cross", "Über 200 Tage Linie", "Momentum", "RSI", "Fibonacci", "Volatilität", "Dividende", "P/E", "Earnings Yield", "FCF-Yield", "Umsatzwachstum", "Gewinnmarge", "Score", "Empfehlung" ]) for symbol in aktien: ticker = yf.Ticker(symbol) info = ticker.info name = info.get("shortName", symbol) # 1 Jahr historische Daten data = yf.download(symbol, period="1y", interval="1d", auto_adjust=True) if data.empty: continue # Mini-Chart chart_html = sparkline(data['Close']) # Momentum (14 Tage) momentum_period = 14 momentum = safe_float(data["Close"] - data["Close"].shift(momentum_period)) # RSI (14) delta = data["Close"].diff() gain = delta.where(delta > 0, 0) loss = -delta.where(delta < 0, 0) avg_gain = gain.rolling(14).mean() avg_loss = loss.rolling(14).mean() rs = avg_gain / avg_loss rsi = safe_float(100 - (100 / (1 + rs))) # Gleitende Durchschnitte ma20 = data["Close"].rolling(20).mean() ma50 = data["Close"].rolling(50).mean() ma200 = data["Close"].rolling(200).mean() ma20_last = safe_float(ma20) ma50_last = safe_float(ma50) ma200_last = safe_float(ma200) close_last = safe_float(data["Close"]) golden_cross = "Ja" if ma20_last > ma50_last else "Nein" over_200 = "Ja" if not np.isnan(ma200_last) and close_last > ma200_last else "Nein" # Volatilität (20 Tage) vol = safe_float(data["Close"].pct_change().rolling(20).std()) # Fibonacci-Level high = safe_float(data["Close"].max()) low = safe_float(data["Close"].min()) fibo_level = ((close_last - low) / (high - low) * 100) if high != low else np.nan # Fundamentale Kennzahlen div_yield = safe_float(info.get("dividendYield")) div_percent = f"{div_yield:.2f}%" if not np.isnan(div_yield) else "n/a" pe_ratio = safe_float(info.get("trailingPE")) pe_str = f"{pe_ratio:.2f}" if not np.isnan(pe_ratio) else "n/a" # Earnings Yield = 1 / P/E earnings_yield = (1/pe_ratio*100) if not np.isnan(pe_ratio) and pe_ratio != 0 else np.nan earnings_yield_str = f"{earnings_yield:.2f}%" if not np.isnan(earnings_yield) else "n/a" # FCF-Yield = Free Cash Flow / Market Cap free_cf = safe_float(info.get("freeCashflow")) market_cap = safe_float(info.get("marketCap")) fcf_yield = (free_cf / market_cap * 100) if market_cap and not np.isnan(market_cap) else np.nan fcf_yield_str = f"{fcf_yield:.2f}%" if not np.isnan(fcf_yield) else "n/a" revenue_growth = safe_float(info.get("revenueGrowth")) rev_growth_str = f"{revenue_growth*100:.2f}%" if not np.isnan(revenue_growth) else "n/a" profit_margin = safe_float(info.get("profitMargins")) profit_margin_str = f"{profit_margin*100:.2f}%" if not np.isnan(profit_margin) else "n/a" # --- Score Berechnung --- score = 0 # Wichtig: Golden Cross + über 200 Tage Linie nur zusammen werten if golden_cross == "Ja" and over_200 == "Ja": score += 2 # beide zusammen 2 Punkte # nur einer von beiden = keine Punkte # score += 0 (implizit) # Andere Kriterien if not np.isnan(fibo_level) and fibo_level < 70: score += 1 if not np.isnan(rsi) and rsi > 50: score += 1 if not np.isnan(vol) and vol < 0.02: score += 1 if not np.isnan(momentum) and momentum > 0.01: score += 1 if not np.isnan(fcf_yield) and fcf_yield > 5: score += 1 # --- Empfehlung --- if score >= 7: empfehlung = "Kaufen" elif score == 6: empfehlung = "Achtung Nachkauf" elif score in [2,3,4,5]: empfehlung = "Halten" elif score == 1: empfehlung = "Achtung prüfen/Verkauf" else: empfehlung = "Verkaufen" # Ergebnis speichern ergebnis_zeile = { "Symbol": symbol, "Name": name, "Chart": chart_html, "Golden Cross": golden_cross, "Über 200 Tage Linie": over_200, "Momentum": f"{momentum:.2f}" if not np.isnan(momentum) else "n/a", "RSI": f"{rsi:.1f}" if not np.isnan(rsi) else "n/a", "Fibonacci": f"{fibo_level:.1f}%" if not np.isnan(fibo_level) else "n/a", "Volatilität": f"{vol*100:.2f}%" if not np.isnan(vol) else "n/a", "Dividende": div_percent, "P/E": pe_str, "Earnings Yield": earnings_yield_str, "FCF-Yield": fcf_yield_str, "Umsatzwachstum": rev_growth_str, "Gewinnmarge": profit_margin_str, "Score": score, "Empfehlung": empfehlung } ergebnisse = pd.concat([ergebnisse, pd.DataFrame([ergebnis_zeile])], ignore_index=True) # --- Anzeige in Jupyter --- pd.set_option('display.max_columns', None) pd.set_option('display.width', 300) display(HTML(ergebnisse.to_html(escape=False, index=False))) # --- Legende --- legende = """ <h3>Legende zur Bewertung</h3> <ul> <li><b>Golden Cross:</b> Ja = 20-Tage-Linie über 50-Tage-Linie (bullish), Nein = unterhalb (bearish)</li> <li><b>200 Tage:</b> Ja = Kurs über 200-Tage-Linie (langfristig positiv), Nein = Kurs unter 200-Tage-Linie (langfristig negativ)</li> <li><b>Momentum:</b> Kurs höher als vor 14 Tagen = positiv</li> <li><b>RSI:</b> >50 = positiv, <50 = eher schwach</li> <li><b>Fibonacci:</b> Tiefer Wert = guter Rücksetzer, >70% = eher teuer</li> <li><b>Volatilität:</b> niedrig (<2%) = stabil, hoch = riskanter</li> <li><b>Dividende:</b> aktuelle Dividendenrendite in %</li> <li><b>P/E:</b> Kurs-Gewinn-Verhältnis</li> <li><b>Earnings Yield:</b> 1 / P/E in %</li> <li><b>FCF-Yield:</b> Free Cash Flow / Market Cap in %</li> <li><b>Umsatzwachstum:</b> Veränderung des Umsatzes YoY in %</li> <li><b>Gewinnmarge:</b> Nettogewinn-Marge in %</li> </ul> <h4>Score und Empfehlung</h4> <ul> <li>7 Punkte = Kaufen</li> <li>6 Punkte = Achtung Nachkauf</li> <li>2–5 Punkte = Halten</li> <li>1 Punkt = Achtung prüfen / Verkauf</li> <li>0 Punkte = Verkaufen</li> </ul> """ display(HTML(legende)) sowie die Ausgabe mit Filtern und Suchfeld: Zitat from datetime import datetime # Zeitstempel erstellen timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") timestamp_html = f"<div style='text-align:right; font-size:12px; margin-bottom:5px;'>Analyse erstellt am: {timestamp}</div>" # HTML-Tabelle interaktiv mit DataTables html_content = ergebnisse.to_html(escape=False, index=False, classes="display", table_id="aktien_table") # CSS + JS für DataTables style_js = """ <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css"/> <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script> <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script> <script> $(document).ready(function() { $('#aktien_table').DataTable({ "paging": true, "pageLength": 20, "order": [[15, "desc"]] // Sortierung standardmäßig nach Score }); }); </script> <style> body { font-family: Arial, Helvetica, sans-serif; } table.dataTable { width: 100%; border-collapse: collapse; } th, td { text-align: center; } </style> """ # Legende bleibt gleich full_html = f"<html><head>{style_js}</head><body>{timestamp_html}{html_content}<br>{legende}</body></html> das kommt dabei rum: Aktienanalyse-24-09-2025.html Ghost_69 Diesen Beitrag teilen Link zum Beitrag
ghost_69 25. September Ich habe mal 2 Charts über einander gelegt, S&P 500 ab 1991 = erster Internetbrowser S&P 500 ab 2022 = erstes AI Tool Zitat import pandas as pd import matplotlib.pyplot as plt import numpy as np from matplotlib.patches import Patch # für Legende der Füllung # ----------------------------- # Echte historische Preisindex-Daten 1991–2005 # ----------------------------- price_data = { 1991: 417, 1992: 435, 1993: 466, 1994: 459, 1995: 615, 1996: 740, 1997: 970, 1998: 1229, 1999: 1469, 2000: 1320, 2001: 1148, 2002: 879, 2003: 1112, 2004: 1212, 2005: 1248 } # Historische S&P 500 TR-Daten 2022–2025 (Basis 100 in 2022) hist_tr = pd.DataFrame({ 'year': [2022, 2023, 2024, 2025], 'index_norm2022': [100, 105, 112, 118] }) # ----------------------------- # Mapping Jahre # ----------------------------- map_years_price = list(range(1991, 2006)) # 1991–2005 map_years_sp = list(range(2022, 2022+len(map_years_price))) # 2022–2036 map_labels = [f"{p}/{s}" for p,s in zip(map_years_price, map_years_sp)] # ----------------------------- # Preisindex DataFrame # ----------------------------- price_df_full = pd.DataFrame(list(price_data.items()), columns=['year','price_index']) base_price = price_df_full.loc[price_df_full['year']==1991, 'price_index'].values[0] price_df_full['index_norm'] = price_df_full['price_index']/base_price*100 price_df_full['mapped_label'] = map_labels # ----------------------------- # S&P 500 TR-Daten 2022–2025 # ----------------------------- sp_values = [] for y in map_years_sp: if y in hist_tr['year'].values: sp_values.append(hist_tr.loc[hist_tr['year']==y, 'index_norm2022'].values[0]) else: sp_values.append(np.nan) # ab 2026 keine Werte plot_sp = pd.DataFrame({ 'mapped_label': map_labels, 'sp500_norm2022': sp_values }) # ----------------------------- # Projektionen Best/Base/Worst Case ab 2025 # ----------------------------- last_real = hist_tr['index_norm2022'].iloc[-1] # Internetblase 1995–2005 relativ zu 1994 bubble_future_values = np.array([price_data[y]/price_data[1994] for y in range(1995, 2006)]) # Projektionen auf 2025 skalieren proj_best = last_real * bubble_future_values # grün proj_base = proj_best * 0.9 # gelb proj_worst = proj_best * 0.75 # rot # X-Index für Projektionen (2025–2036 inkl. Übergang) proj_years_idx = list(range(map_labels.index('1994/2025'), len(map_labels))) # inkl. 2025 proj_labels = [map_labels for i in proj_years_idx] # ----------------------------- # Plot # ----------------------------- plt.figure(figsize=(12,6)) # Historische Linie 1991–2005 plt.plot(price_df_full['mapped_label'], price_df_full['index_norm'], marker='o', label='S&P 500 Preisindex 1991–2005') # TR-Daten 2022–2025 plt.plot(plot_sp['mapped_label'], plot_sp['sp500_norm2022'], marker='s', label='S&P 500 TR 2022–2025') # Projektionen Best/Base/Worst Case ab 2025 plt.plot(proj_labels[1:], proj_best[0:len(proj_labels)-1], linestyle='--', color='green', marker='o', label='Best Case') plt.plot(proj_labels[1:], proj_base[0:len(proj_labels)-1], linestyle='--', color='gold', marker='o', label='Base Case') plt.plot(proj_labels[1:], proj_worst[0:len(proj_labels)-1], linestyle='--', color='red', marker='o', label='Worst Case') # Kurzer Übergang von 2025 zu 2026 x_transition = [proj_labels[0], proj_labels[1]] # 2025 → 2026 plt.plot(x_transition, [last_real, proj_best[0]], linestyle='--', color='green') plt.plot(x_transition, [last_real, proj_base[0]], linestyle='--', color='gold') plt.plot(x_transition, [last_real, proj_worst[0]], linestyle='--', color='red') # ----------------------------- # Füllung zwischen Best und Worst Case ab 2025 # ----------------------------- fill_x = proj_labels # ab 2025 fill_y_low = np.concatenate(([last_real], proj_worst[0:len(proj_labels)-1])) fill_y_high = np.concatenate(([last_real], proj_best[0:len(proj_labels)-1])) plt.fill_between(fill_x, fill_y_low, fill_y_high, color='skyblue', alpha=0.3) # ----------------------------- # Legende inkl. Spanne # ----------------------------- span_patch = Patch(facecolor='skyblue', alpha=0.3, label='Projektionsspanne Best–Worst Case') plt.legend(handles=[span_patch] + plt.gca().get_legend_handles_labels()[0], loc='upper left') # Achsen und Layout plt.xticks(rotation=45) plt.title('Mapping: Internetblase (1991–2005) vs. AI Blase (2022–2036)') plt.xlabel('Mapped Jahre (1991–2005 / 2022–2036)') plt.ylabel('Index (Basisjahr = 100)') plt.grid(True) plt.tight_layout() plt.show() sozusagen: Vergangenheit, Gegenwart und mögliche Zukunft in einem Blick, Parallelen zwischen der Dot-com-Blase und der heutigen Marktphase ! Ghost_69 Diesen Beitrag teilen Link zum Beitrag
ghost_69 29. September Ich finde das Tool gut, immer wieder andere Zahlen und somit andere Empfehlungen. Aktienanalyse29-09-2025.html Ghost_69 PS: Zu Risiken und Nebenwirkungen fragen sie Ihren Raider Diesen Beitrag teilen Link zum Beitrag
ghost_69 22. Oktober Aktienanalyse-22-10-2025.html Zu Risken und Nebenwirkungen fragen sie ihren Raider. Ghost_69 Diesen Beitrag teilen Link zum Beitrag
ghost_69 16. November Ich habe noch ein paar mehr Werte eingefügt. Verbesserter Score (1).ipynb dann kommt das dabei rum. Aktienanalyse16-11-2025.html Ghost_69 Diesen Beitrag teilen Link zum Beitrag