import os import pandas as pd import pandas_ta as ta from dotenv import load_dotenv from datetime import datetime, timedelta # Backtesting-Spezialisten from backtesting import Backtest, Strategy from backtesting.lib import crossover # Alpaca API from alpaca.data.historical import StockHistoricalDataClient from alpaca.data.requests import StockBarsRequest from alpaca.data.timeframe import TimeFrame # --- CONFIG --- load_dotenv() API_KEY = os.getenv('ALPACA_API_KEY') SECRET_KEY = os.getenv('ALPACA_SECRET_KEY') # --- KLASSE: DATEN-ENGINE --- class DataEngine: @staticmethod def get_alpaca_data(symbol, days=365): client = StockHistoricalDataClient(API_KEY, SECRET_KEY) start_date = datetime.now() - timedelta(days=days) request = StockBarsRequest( symbol_or_symbols=[symbol], timeframe=TimeFrame.Day, start=start_date ) df = client.get_stock_bars(request).df df = df.reset_index(level=0, drop=True) # Formatierung für Backtesting.py (Spalten müssen groß geschrieben sein) df.columns = [c.capitalize() for c in df.columns] # Zeitzonen entfernen (wichtig für Excel!) df.index = df.index.tz_localize(None) return df # --- KLASSE: STRATEGIE (RSI) --- class MyRsiStrategy(Strategy): # Parameter - diese können später optimiert werden rsi_period = 25 rsi_low = 30 rsi_high = 70 def init(self): # Indikator berechnen (self.I stellt sicher, dass er im Chart erscheint) self.rsi = self.I(ta.rsi, pd.Series(self.data.Close), length=self.rsi_period) def next(self): # KAUFEN: Wenn RSI die untere Grenze von unten nach oben kreuzt if crossover(self.rsi, self.rsi_low): self.buy() # VERKAUFEN: Wenn RSI die obere Grenze von oben nach unten kreuzt elif crossover(self.rsi_high, self.rsi): if self.position: self.position.close() # --- HAUPTPROGRAMM --- def run_backtest(symbol="AAPL", cash=10000, commission=0.002): # 1. Daten laden print(f"Lade Daten für {symbol}...") data = DataEngine.get_alpaca_data(symbol) # 2. Backtest initialisieren # commission=0.002 bedeutet 0.2% Gebühren pro Trade bt = Backtest(data, MyRsiStrategy, cash=cash, commission=commission) # 3. Backtest ausführen stats = bt.run() # --- AUSWERTUNG --- print("\n" + "="*30) print(f"BACKTEST ERGEBNISSE FÜR {symbol}") print("="*30) print(f"Startkapital: {cash}$") print(f"Endkapital: {stats['Equity Final [$]']:.2f}$") print(f"Rendite [%]: {stats['Return [%]']:.2f}%") print(f"Max. Drawdown: {stats['Max. Drawdown [%]']:.2f}%") print(f"Anzahl Trades: {stats['# Trades']}") print(f"Win Rate [%]: {stats['Win Rate [%]']:.2f}%") print("="*30) # 4. EXPORT: Trades nach Excel trades = stats['_trades'] if not trades.empty: # Dauer der Trades berechnen trades['Duration'] = trades['ExitTime'] - trades['EntryTime'] excel_name = f"Backtest_Trades_{symbol}.xlsx" trades.to_excel(excel_name) print(f"✅ Excel-Liste gespeichert: {excel_name}") # 5. EXPORT: Interaktiver HTML Report report_name = f"Backtest_Report_{symbol}.html" bt.plot(filename=report_name, open_browser=False) print(f"✅ Interaktiver Chart gespeichert: {report_name}") if __name__ == "__main__": # Starte den Backtest run_backtest(symbol="AAPL", cash=10000)