#!/usr/bin/env python3

# Renditen_Vergleich.py
"""
Kapitel Finanzdaten: Diskrete vs. logarithmische Renditen.
Zeigt an einem simulierten Kursverlauf, welche Eigenschaft wo gilt -
und warum das arithmetische Mittel diskreter Renditen in die Irre fuehrt.
"""

import numpy as np
import pandas as pd

if __name__ == "__main__":
    kurse = np.array([100.0, 150.0, 100.0, 120.0, 90.0, 135.0])
    tage = [f"t{i}" for i in range(len(kurse))]

    diskret = kurse[1:] / kurse[:-1] - 1.0
    logarithmisch = np.log(kurse[1:] / kurse[:-1])

    print("=" * 74)
    print("  DISKRETE UND LOGARITHMISCHE RENDITEN IM VERGLEICH")
    print("=" * 74)
    tabelle = pd.DataFrame({
        "Periode": [f"{tage[i]} -> {tage[i+1]}" for i in range(len(diskret))],
        "Kurs von": kurse[:-1],
        "Kurs bis": kurse[1:],
        "diskret R": [f"{r*100:+7.2f} %" for r in diskret],
        "log r": [f"{r:+8.4f}" for r in logarithmisch],
    })
    print(tabelle.to_string(index=False))

    # --- Zeitliche Aggregation ------------------------------------------
    gesamt_wahr = kurse[-1] / kurse[0] - 1.0
    summe_log = logarithmisch.sum()
    aus_log_zurueck = np.exp(summe_log) - 1.0
    summe_diskret = diskret.sum()

    print("\n--- Aggregation ueber die Zeit ---")
    print(f"  Tatsaechliche Gesamtrendite:        {gesamt_wahr*100:+8.2f} %")
    print(f"  Summe der Log-Renditen -> exp()-1:  {aus_log_zurueck*100:+8.2f} %  "
          f"{'KORREKT' if abs(aus_log_zurueck - gesamt_wahr) < 1e-9 else 'falsch'}")
    print(f"  Summe der diskreten Renditen:       {summe_diskret*100:+8.2f} %  FALSCH")

    # --- Mittelwerte ------------------------------------------------------
    arithmetisch = diskret.mean()
    geometrisch = np.prod(1 + diskret) ** (1 / len(diskret)) - 1
    aus_log = np.exp(logarithmisch.mean()) - 1

    print("\n--- Welcher Mittelwert ist der richtige? ---")
    print(f"  Arithmetisches Mittel (diskret):    {arithmetisch*100:+8.2f} %  "
          f"-> ueberschaetzt")
    print(f"  Geometrisches Mittel:               {geometrisch*100:+8.2f} %  -> korrekt")
    print(f"  exp(Mittel der Log-Renditen) - 1:   {aus_log*100:+8.2f} %  "
          f"-> identisch zum geometrischen")

    # Probe: Endkapital mit dem jeweiligen Mittelwert hochgerechnet
    n = len(diskret)
    print(f"\n  Probe - Startkapital 100 EUR ueber {n} Perioden:")
    print(f"    tatsaechlich:                     {kurse[-1]:8.2f} EUR")
    print(f"    mit arithm. Mittel hochgerechnet: {100*(1+arithmetisch)**n:8.2f} EUR")
    print(f"    mit geom.  Mittel hochgerechnet:  {100*(1+geometrisch)**n:8.2f} EUR")

    print("\n--- Annualisierung (252 Handelstage) ---")
    print(f"  Volatilitaet aus Log-Renditen: "
          f"{logarithmisch.std(ddof=1)*np.sqrt(252)*100:.2f} % p.a.")
    print("  (Die Wurzel-Zeit-Regel gilt nur bei unabhaengigen Renditen -")
    print("   fuer reale Maerkte ist sie eine Naeherung.)")
    print("=" * 74)
