Entscheidungen von Agenten backtesten
Agentenstrategien mit historischen Daten simulieren, um ihre Leistung zu validieren.
Entscheidungen von Agenten backtesten ist eine kostenlose AI Agents-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Agents-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Agents-Kurs umfasst insgesamt 4 Lektionen.
Warum Entscheidungen von Agenten backtesten?
Sie können nicht wissen, ob Ihr Finanzagent gute Empfehlungen erstellt, ohne ihn anhand historischer Daten zu testen. Beim Backtesting werden vergangene Marktbedingungen durch die Entscheidungslogik des Agenten wiedergegeben. Dabei wird gemessen, wie sich diese Entscheidungen entwickelt hätten.
Backtesting ist das wichtigste Werkzeug, um die Qualität einer Strategie vor dem Einsatz im Live-Betrieb zu validieren.
Die Falle des Look-ahead-Bias
Look-ahead-Bias ist der häufigste und gefährlichste Fehler beim Backtesting: Dabei werden zukünftige Daten verwendet, um eine „vergangene“ Entscheidung zu treffen. Ein Beispiel ist, den Schlusskurs des Tages zu verwenden, um zu entscheiden, ob am Tagesbeginn desselben Tages gekauft werden soll.
Jede historische Entscheidung darf ausschließlich Daten verwenden, die zum simulierten Entscheidungszeitpunkt verfügbar waren.
import pandas as pd
import yfinance as yf
# WRONG — uses today's close to decide today's trade
def bad_signal(history: pd.DataFrame, date: str) -> str:
today_close = history.loc[date, 'Close'] # look-ahead!
if today_close > history['Close'].mean():
return 'BUY'
return 'HOLD'
# CORRECT — uses only data available BEFORE the decision date
def good_signal(history: pd.DataFrame, date: str) -> str:
past_data = history.loc[:date].iloc[:-1] # exclude today
if past_data.empty:
return 'HOLD'
today_open = history.loc[date, 'Open'] # open price known at market open
if today_open > past_data['Close'].mean():
return 'BUY'
return 'HOLD'Die Schleife für die historische Wiedergabe erstellen
Durchlaufen Sie jedes historische Datum. Bei jedem Schritt sieht der Agent nur die bis zu diesem Zeitpunkt verfügbaren Daten. Zeichnen Sie die Entscheidung auf und gehen Sie anschließend zum nächsten Datum weiter, um das Ergebnis zu beobachten.
import yfinance as yf
import pandas as pd
def backtest_simple(ticker: str, start: str, end: str) -> list[dict]:
hist = yf.Ticker(ticker).history(start=start, end=end)
results = []
for i in range(20, len(hist)): # need 20 days of history for signals
window = hist.iloc[:i] # data available on day i
today = hist.iloc[i]
decision = good_signal(window, str(hist.index[i].date()))
results.append({
'date': str(hist.index[i].date()),
'decision': decision,
'open': float(today['Open']),
'close': float(today['Close']),
'next_day_return': None # filled in next iteration
})
return resultsDie Agentenlogik bei jedem Schritt simulieren
Für ein realistischeres Backtesting simulieren Sie an jedem Datum den vollständigen Tool-Aufruf des Agenten – einschließlich Prompt-Erstellung, LLM-Aufruf und Parsen der Entscheidung. So testen Sie das gesamte System und nicht nur die Signallogik.
import openai, json
import yfinance as yf
client = openai.OpenAI(api_key='YOUR_OPENAI_KEY')
def agent_decision_at_date(ticker: str, hist_up_to: pd.DataFrame) -> str:
recent = hist_up_to.tail(20)
closes = recent['Close'].tolist()
returns = [round((closes[i] - closes[i-1]) / closes[i-1], 4)
for i in range(1, len(closes))]
prompt = (
f'Ticker: {ticker}\n'
f'Last 20 closing prices: {closes}\n'
f'Daily returns: {returns}\n'
f'Based on this data, recommend: BUY, SELL, or HOLD.\n'
f'Return JSON: {{"action": "BUY/SELL/HOLD", "reason": "..."}}'
)
resp = client.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'user', 'content': prompt}],
response_format={'type': 'json_object'}
)
return json.loads(resp.choices[0].message.content).get('action', 'HOLD')Die Trefferquote berechnen
Die Trefferquote gibt an, welcher Prozentsatz der BUY-Entscheidungen von einer positiven Rendite am nächsten Tag gefolgt wurde. Eine Trefferquote von über 50 % bedeutet, dass der Agent die Richtung häufiger als zufällig richtig vorhersagt.
def compute_hit_rate(results: list[dict]) -> dict:
buy_decisions = [r for r in results if r['decision'] == 'BUY'
and r.get('next_day_return') is not None]
if not buy_decisions:
return {'hit_rate': None, 'sample_size': 0}
correct = sum(1 for r in buy_decisions if r['next_day_return'] > 0)
return {
'hit_rate': round(correct / len(buy_decisions), 4),
'sample_size': len(buy_decisions),
'correct': correct,
'interpretation': 'above_chance' if correct / len(buy_decisions) > 0.52 else 'at_or_below_chance'
}
if __name__ == '__main__':
results = [
{'decision': 'BUY', 'next_day_return': 0.012},
{'decision': 'BUY', 'next_day_return': -0.004},
{'decision': 'HOLD', 'next_day_return': None},
{'decision': 'BUY', 'next_day_return': 0.007},
]
print('Hit rate:', compute_hit_rate(results))
Rendite im Vergleich zur Benchmark berechnen
Vergleichen Sie die Rendite der Strategie mit der Buy-and-Hold-Benchmark. Wenn der Agent schlechter abschneidet als das bloße Halten des Index, ist seine Komplexität nicht gerechtfertigt.
def compare_to_benchmark(results: list[dict], ticker: str, period: str = '1y') -> dict:
import yfinance as yf
# Strategy return: only invested on BUY days
buy_days = [r for r in results if r['decision'] == 'BUY'
and r.get('next_day_return') is not None]
strategy_return = sum(r['next_day_return'] for r in buy_days)
# Benchmark: buy-and-hold
hist = yf.Ticker(ticker).history(period=period)['Close']
bh_return = float((hist.iloc[-1] - hist.iloc[0]) / hist.iloc[0])
return {
'strategy_return_pct': round(strategy_return * 100, 2),
'benchmark_return_pct': round(bh_return * 100, 2),
'outperformed': strategy_return > bh_return,
'alpha_pct': round((strategy_return - bh_return) * 100, 2)
}Auswirkungen von Transaktionskosten
Ohne die Berücksichtigung von Transaktionskosten (Provisionen, Spread, Slippage) kann eine Strategie profitabel erscheinen, in der Praxis aber tatsächlich Verluste machen. Selbst 0,1 % pro Trade summieren sich über viele Trades erheblich.
COMMISSION_PCT = 0.001 # 0.1% per trade (buy + sell)
SLIPPAGE_PCT = 0.0005 # 0.05% per trade
def returns_after_costs(decisions: list[dict]) -> dict:
total_return = 0.0
total_cost = 0.0
for d in decisions:
if d['decision'] == 'BUY' and d.get('next_day_return') is not None:
gross = d['next_day_return']
cost = COMMISSION_PCT + SLIPPAGE_PCT
net = gross - cost
total_return += net
total_cost += cost
return {
'gross_return_pct': round((total_return + total_cost) * 100, 2),
'net_return_pct': round(total_return * 100, 2),
'total_costs_pct': round(total_cost * 100, 2),
'num_trades': sum(1 for d in decisions if d['decision'] == 'BUY')
}
if __name__ == '__main__':
decisions = [
{'decision': 'BUY', 'next_day_return': 0.012},
{'decision': 'BUY', 'next_day_return': -0.004},
{'decision': 'HOLD', 'next_day_return': None},
]
print('Returns after trading costs:', returns_after_costs(decisions))
Walk-Forward-Validierung
Eine In-Sample-Optimierung (Training in demselben Zeitraum, in dem getestet wird) führt zu Overfitting. Bei der Walk-Forward-Validierung folgt auf ein rollierendes Trainingsfenster jeweils ein neuer Testzeitraum – genau wie beim echten Einsatz.
def walk_forward_test(ticker: str, total_years: int = 3,
train_months: int = 12, test_months: int = 3) -> list[dict]:
import yfinance as yf
from dateutil.relativedelta import relativedelta
from datetime import date
results = []
start = date(date.today().year - total_years, 1, 1)
end = date.today()
window_start = start
while True:
train_end = window_start + relativedelta(months=train_months)
test_end = train_end + relativedelta(months=test_months)
if test_end > end:
break
# In practice: train your signal on window_start->train_end
# then evaluate on train_end->test_end
results.append({
'train_period': f'{window_start} to {train_end}',
'test_period': f'{train_end} to {test_end}'
})
window_start += relativedelta(months=test_months)
return resultsBacktesting-Bericht
Fassen Sie die Ergebnisse des Backtests in einem strukturierten Bericht zusammen: Trefferquote, Gesamtrendite im Vergleich zur Benchmark, Alpha, Sharpe-Ratio, maximaler Drawdown, Anzahl der Trades und Rendite nach Kosten.
def backtest_report(ticker: str, results: list[dict]) -> dict:
hit = compute_hit_rate(results)
benchmark = compare_to_benchmark(results, ticker)
costs = returns_after_costs(results)
return {
'ticker': ticker,
'total_decisions': len(results),
'buy_signals': costs['num_trades'],
'hit_rate': hit.get('hit_rate'),
'strategy_return_gross': f'{costs["gross_return_pct"]}%',
'strategy_return_net': f'{costs["net_return_pct"]}%',
'benchmark_return': f'{benchmark["benchmark_return_pct"]}%',
'alpha': f'{benchmark["alpha_pct"]}%',
'outperformed_benchmark': benchmark['outperformed'],
'transaction_costs': f'{costs["total_costs_pct"]}%'
}Backtesting-Ergebnisse interpretieren
Gute Backtesting-Ergebnisse garantieren keine zukünftige Performance. Schlechte Ergebnisse zeigen jedoch, welche Strategien nicht eingesetzt werden sollten. Wichtige Warnsignale sind: eine Trefferquote unter 50 %, negatives Alpha nach Kosten, eine Sharpe-Ratio unter 0,5 oder ein maximaler Drawdown, der Ihre Risikotoleranz überschreitet.
def interpret_backtest(report: dict) -> list[str]:
warnings = []
hit_rate = report.get('hit_rate')
if hit_rate and hit_rate < 0.50:
warnings.append(f'Hit rate {hit_rate:.1%} is below chance — strategy predicts direction poorly')
alpha_str = report.get('alpha', '0%')
alpha = float(alpha_str.replace('%', '')) / 100
if alpha < 0:
warnings.append(f'Negative alpha {alpha_str}: strategy underperforms buy-and-hold')
if not warnings:
return ['Backtest results look acceptable — proceed with paper trading before live deployment']
return warnings
if __name__ == '__main__':
report = {'hit_rate': 0.45, 'alpha': '-1.2%'}
for warning in interpret_backtest(report):
print('-', warning)
Monte-Carlo-Simulation zur Robustheitsprüfung
Ein einzelner Backtest hängt stark vom gewählten Zeitraum ab. Bei einer Monte-Carlo-Simulation wird die Reihenfolge historischer Renditen zufällig verändert, um zu prüfen, ob die Performance bei unterschiedlichen Abfolgen bestehen bleibt. So lässt sich erkennen, ob die Strategie robust oder nur glücklicherweise erfolgreich ist.
import numpy as np
def monte_carlo_backtest(daily_returns: list[float],
simulations: int = 1000) -> dict:
returns_arr = np.array(daily_returns)
final_returns = []
for _ in range(simulations):
shuffled = np.random.choice(returns_arr, size=len(returns_arr), replace=True)
cumulative = float((1 + shuffled).prod() - 1)
final_returns.append(cumulative)
final_returns = sorted(final_returns)
return {
'median_return': round(float(np.median(final_returns)) * 100, 2),
'percentile_5': round(float(np.percentile(final_returns, 5)) * 100, 2),
'percentile_95': round(float(np.percentile(final_returns, 95)) * 100, 2),
'prob_positive': round(sum(1 for r in final_returns if r > 0) / simulations, 3)
}Was ist Look-ahead-Bias beim Backtesting?
Look-ahead-Bias ist die häufigste Ursache dafür, dass die Performance eines Backtests versehentlich überschätzt wird. Wenn Sie die genaue Definition verstehen, vermeiden Sie es, fehlerhafte Backtests zu erstellen.
Zusammenfassung: Entscheidungen von Agenten backtesten
Fundiertes Backtesting erfordert: das Vermeiden von Look-ahead-Bias (Entscheidungen verwenden ausschließlich vergangene Daten), die Simulation einer realistischen Agentenlogik bei jedem historischen Schritt, die Messung der Trefferquote und des Alphas im Vergleich zur Benchmark, die Berücksichtigung von Transaktionskosten sowie die Validierung mit Walk-Forward-Aufteilungen, um Overfitting zu erkennen.
Häufig gestellte Fragen
Ist die Lektion „Entscheidungen von Agenten backtesten“ kostenlos?
Ja — der vollständige Text von „Entscheidungen von Agenten backtesten“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Agents-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Agents-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Entscheidungen von Agenten backtesten“?
Agentenstrategien mit historischen Daten simulieren, um ihre Leistung zu validieren. Du übst AI Agents mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um AI Agents zu starten?
Keine Vorkenntnisse erforderlich. AI Agents auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Entscheidungen von Agenten backtesten“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser AI Agents-Lektion Code schreiben und ausführen?
Ja. Jede AI Agents-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Integration von Marktdaten-APIs
- Tools für Agenten zur Portfolioanalyse
- Leitplanken für Risiko und Compliance
- Entscheidungen von Agenten backtesten