Zum Inhalt springen
ghost_69

Programmieren, Charts und Analysen

Empfohlene Beiträge

ghost_69

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:

image.png.c762a61af8e00cb17f051fc7c86170f5.png

 

Alphabet.ipynb

 

Ghost_69 :-*

Diesen Beitrag teilen


Link zum Beitrag
ghost_69
· bearbeitet von ghost_69

Ich möchte für verschiedene Werte eine Art Bewertung machen,

hier mal ein Beispiel:

 

image.png.b9f9a9090f199ea7e058c50d53901f60.png

 

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

ich bin weiter dabei:

image.png.8487e3a892628c76d4a6003dd5ef0a0c.png

 

 

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
· bearbeitet 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
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:

image.png.da5032045d786ae7a90aa09650aca49d.png

 

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
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
· bearbeitet 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.

image.thumb.png.dfb7638b3ce950e07f195b8f06acc739.png

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
· bearbeitet 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
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

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

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))

image.thumb.png.82be26aa54ce5cd82403369f06d941de.png

 

image.png.a6308bf851f2c02986dbd685d5befa90.png

 

Aktienanalyse.html

 

40Werte+HTLM+Zeitstempel.ipynb

 

ganz oben habe ich einen Zeitstemple eingebaut, dann weiß man wann man ist.

image.png.2ae7f510d1c07b3cd799a0440eaa1eaf.png

 

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

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
· bearbeitet 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:

Ausschnitt-20-09-2025.thumb.JPG.642f33f41555f76b7c1bb95fcaec7da8.JPG

 

Ghost_69 :-*

Diesen Beitrag teilen


Link zum Beitrag
ghost_69

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:

image.thumb.png.ce846db61e9a5424002285241e8c65a1.png

 

image.thumb.png.c67dcadecc205ad5034a0c50500c8dba.png

 

Aktienanalyse-24-09-2025.html

 

Ghost_69 :-*

Diesen Beitrag teilen


Link zum Beitrag
ghost_69

Ich habe mal 2 Charts über einander gelegt,

S&P 500 ab 1991 = erster Internetbrowser

S&P 500 ab 2022 = erstes AI Tool

download.thumb.png.b32ddb154aed84565b17c86d873ca69f.png

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

Ich finde das Tool gut, immer wieder andere Zahlen und somit andere Empfehlungen.

image.thumb.png.5dba6a8bc34d2cffe262b135bdab6bb2.png

 

image.thumb.png.54c3d3da5233a5e46abda576b3e788e8.png

 

Aktienanalyse29-09-2025.html

 

Ghost_69 :-*

 

PS: Zu Risiken und Nebenwirkungen fragen sie Ihren Raider 

Diesen Beitrag teilen


Link zum Beitrag
ghost_69

Diesen Beitrag teilen


Link zum Beitrag
ghost_69

Aktienanalyse-22-10-2025.html

 

image.thumb.png.a03a8fe996eea46785041a3f9bd29a4a.png

 

image.thumb.png.88d0f8f8564ed532d926a8d1947ea8ea.png

 

Zu Risken und Nebenwirkungen fragen sie ihren Raider.

 

Ghost_69 :-*

Diesen Beitrag teilen


Link zum Beitrag
ghost_69

Ich habe noch ein paar mehr Werte eingefügt.

 

Verbesserter Score (1).ipynb

 

dann kommt das dabei rum.

 

Aktienanalyse16-11-2025.html

 

image.thumb.png.80d678227ee2fa41c260f9aa45c4671a.png

 

Ghost_69 :-*

 

 

 

 

 

 

Diesen Beitrag teilen


Link zum Beitrag

Erstelle ein Benutzerkonto oder melde dich an, um zu kommentieren

Du musst ein Benutzerkonto haben, um einen Kommentar verfassen zu können

Benutzerkonto erstellen

Neues Benutzerkonto für unsere Community erstellen. Es ist einfach!

Neues Benutzerkonto erstellen

Anmelden

Du hast bereits ein Benutzerkonto? Melde dich hier an.

Jetzt anmelden

×
×
  • Neu erstellen...