Files
Aktienmanager/financial_tools.py
2025-08-10 15:18:12 +02:00

131 lines
5.8 KiB
Python

import pandas as pd
import numpy as np
class FinancialTools:
@staticmethod
def calculate_returns(prices_series, in_percent=True): # <-- NEUER PARAMETER HIER!
"""Berechnet die täglichen Renditen."""
if prices_series.empty:
return pd.Series(dtype='float64')
if isinstance(prices_series, pd.DataFrame):
if 'adj_close' in prices_series.columns:
prices_series = prices_series['adj_close']
elif 'close' in prices_series.columns:
prices_series = prices_series['close']
else:
return pd.Series(dtype='float64')
returns = prices_series.pct_change().dropna()
if in_percent:
return returns * 100 # Für die Anzeige in Prozent
return returns # Für interne Berechnungen (Dezimalwerte)
@staticmethod
def calculate_cumulative_returns(prices_series):
"""Berechnet die kumulativen Renditen."""
if prices_series.empty:
return pd.Series(dtype='float64')
# HIER: Rufe calculate_returns mit in_percent=False auf, um Dezimalwerte zu bekommen
daily_returns_raw = FinancialTools.calculate_returns(prices_series, in_percent=False)
if daily_returns_raw.empty:
return pd.Series(dtype='float64')
return (1 + daily_returns_raw).cumprod() - 1
@staticmethod
def calculate_moving_average(prices_series, window=20):
"""Berechnet den gleitenden Durchschnitt."""
if prices_series.empty:
return pd.Series(dtype='float64')
if isinstance(prices_series, pd.DataFrame):
if 'adj_close' in prices_series.columns:
prices_series = prices_series['adj_close']
elif 'close' in prices_series.columns:
prices_series = prices_series['close']
else:
return pd.Series(dtype='float64')
return prices_series.rolling(window=window).mean()
@staticmethod
def calculate_volatility(prices_series, window=20):
"""Berechnet die rollierende Volatilität (Standardabweichung der Renditen)."""
if prices_series.empty:
return pd.Series(dtype='float64')
# HIER: Rufe calculate_returns mit in_percent=False auf, um Dezimalwerte zu bekommen
daily_returns_for_vol = FinancialTools.calculate_returns(prices_series, in_percent=False)
if daily_returns_for_vol.empty:
return pd.Series(dtype='float64')
# Annualisiere die Volatilität
return daily_returns_for_vol.rolling(window=window).std() * np.sqrt(252)
@staticmethod
def calculate_beta(stock_prices, market_prices, window=60):
"""
Berechnet das rollierende Beta eines Wertpapiers relativ zu einem Marktindex.
stock_prices: Pandas Series der Aktie
market_prices: Pandas Series des Marktindex
"""
if stock_prices.empty or market_prices.empty:
return pd.Series(dtype='float64')
# Sicherstellen, dass es Series sind, falls doch DataFrames übergeben werden
if isinstance(stock_prices, pd.DataFrame):
if 'adj_close' in stock_prices.columns:
stock_prices = stock_prices['adj_close']
elif 'close' in stock_prices.columns:
stock_prices = stock_prices['close']
else:
return pd.Series(dtype='float64')
if isinstance(market_prices, pd.DataFrame):
if 'adj_close' in market_prices.columns:
market_prices = market_prices['adj_close']
elif 'close' in market_prices.columns:
market_prices = market_prices['close']
else:
return pd.Series(dtype='float64')
# HIER: Rufe calculate_returns mit in_percent=False auf, um Dezimalwerte zu bekommen
returns_stock = FinancialTools.calculate_returns(stock_prices, in_percent=False)
returns_market = FinancialTools.calculate_returns(market_prices, in_percent=False)
# Kombiniere die Renditen und richte sie an den Daten aus
combined_returns = pd.concat([returns_stock.rename('stock'), returns_market.rename('market')], axis=1).dropna()
if combined_returns.empty:
return pd.Series(dtype='float64')
# Berechne die rollierende Kovarianz und Varianz
rolling_covariance = combined_returns['stock'].rolling(window=window).cov(combined_returns['market'])
rolling_variance = combined_returns['market'].rolling(window=window).var()
# Berechne Beta
beta = rolling_covariance / rolling_variance
return beta.dropna()
# Beispielnutzung (für Tests) - Muss an die neuen Funktionssignaturen angepasst werden
if __name__ == "__main__":
# Erzeuge fiktive Daten für Tests
dates = pd.to_datetime(pd.date_range(start='2023-01-01', periods=100))
stock_prices_series = pd.Series(np.random.rand(100) * 100 + 50, index=dates) # direkt als Series
market_prices_series = pd.Series(np.random.rand(100) * 10 + 200, index=dates) # direkt als Series
print("Tägliche Renditen (in Prozent):")
print(FinancialTools.calculate_returns(stock_prices_series, in_percent=True).head()) # Für Anzeige
print("\nKumulative Renditen (Dezimal):")
print(FinancialTools.calculate_cumulative_returns(stock_prices_series).head())
print("\nGleitender 20-Tage-Durchschnitt:")
print(FinancialTools.calculate_moving_average(stock_prices_series, window=20).head())
print("\nRollierende 20-Tage-Volatilität (annualisiert, Dezimal):")
print(FinancialTools.calculate_volatility(stock_prices_series, window=20).head())
print("\nRollierendes 60-Tage-Beta (Aktie vs. Markt, Dezimal):")
print(FinancialTools.calculate_beta(stock_prices_series, market_prices_series, window=60).head())