Maximum Drawdown (MDD) detecteren in een Pandas DataFrame
Je hebt een backtest lopen draaien in Python, je bot draait soepel op de API van een broker zoals Interactive Brokers of Alpaca, en de resultaten zien er veelbelovend uit.
Maar dan check je de equity curve en je ziet een diepe val. De bot maakt misschien nog steeds winst op lange termijn, maar die ene week in augustus waarbij de markt instortte, had je bijna je hele account leeggetrokken. Dat gat in je equity curve is je Maximum Drawdown (MDD). Het is het pijnlijkste getal in trading, maar ook het meest leerzame.
In deze gids gaan we aan tafel zitten en bouwen we een simpele, krachtige MDD-detector in een Pandas DataFrame. Geen ingewikkelde theorie, gewoon code die je morgen nog kunt gebruiken.
Wat is Maximum Drawdown eigenlijk?
Maximum Drawdown is de grootste procentuele daling vanaf een piek naar een dieptepunt in je equity curve. Stel je voor: je start met €10.000.
Je bot draait goed en het account groeit naar €15.000. Dan komt er een slechte periode, misschien door een onverwachte news event, en het zakt terug naar €11.000. Die daling van €15.000 naar €11.000 is een drawdown van €4.000, oftewel 26,7%.
De grootste van dit soort dalingen in je hele dataset is de MDD.
Waarom is dit zo belangrijk voor algoritmische trading? Omdat winst en verlies twee kanten van dezelfde medaille zijn, maar pijn en psychologie alleen aan de verlieskant zitten. Een bot die 20% rendement maakt met een MDD van 5% voelt geweldig. Een bot die 40% rendement maakt met een MDD van 35% voelt onhoudbaar.
Je stopt veel te snel met een bot die diep wegzakt, zelfs als die op lange termijn winstgevend is. Door MDD te meten, weet je of je risicomanagement op orde is en of je broker-setup (denk aan hefboom en spread) je strategie aankan.
De basis: je data voorbereiden in Pandas
Voordat we MDD kunnen berekenen, heb je een Pandas DataFrame nodig met je equity curve. Meestal komt deze data uit je backtesting engine (zoals Backtrader, Zipline of een eigen script) of uit de API van je broker.
De DataFrame heeft minimaal twee kolommen nodig: een datum (index) en het account saldo. Zorg dat je data schoon is, zonder gaten of dubbele waardes. Als je met kleine tijdframes werkt (bijvoorbeeld 1-minuut candles van Binance), zorg dan dat je de resample doet naar een logische frequentie, zoals dagelijks, om ruis te filteren.
import pandas as pd
data = {
'date': pd.date_range(start='2023-01-01', periods=100, freq='D'),
'equity': [10000] * 100
}
# Simuleer een piek en een daling
data['equity'][20:40] = [10000 + i*50 for i in range(20)] # stijgt naar 11000
data['equity'][40:60] = [11000 - i*30 for i in range(20)] # daalt naar 10400
data['equity'][60:] = [10400 + i*20 for i in range(40)] # herstelt
df = pd.DataFrame(data)
df.set_index('date', inplace=True)
Stel je DataFrame ziet er zo uit: Deze simuleerde equity curve is een perfect testobject.
Je ziet een stijging, een daling en een herstel. In de echte wereld heb je waarschijnlijk een JSON-bestand van je broker API of een CSV uit je backtester. Het principe blijft hetzelfde: we willen de pieken en dalen in deze lijn vinden.
MDD berekenen: stap voor stap met code
De logica achter MDD is simpel: we volgen de hoogste punt tot nu toe (de running peak) en vergelijken die met het huidige equity niveau. Het verschil tussen die twee is de drawdown op dat moment.
De grootste van die verschillen is je Maximum Drawdown. We doen dit in één loop door je DataFrame, wat in Python super snel gaat. Deze code is een kant-en-klare functie die je zo in je script kunt plakken.
def calculate_mdd(df, equity_col='equity'):
# Maak een kopie om de data niet te verpesten
eq = df[equity_col].copy()
# Bereken de running peak (het hoogste punt tot nu toe)
running_peak = eq.cummax()
# Bereken de drawdown op elk moment: (huidig - peak) / peak
drawdown = (eq - running_peak) / running_peak
# De MDD is de laagste (meest negatieve) waarde
mdd = drawdown.min()
# Bonus: vind de periode waarin de MDD plaatsvond
mdd_date = drawdown.idxmin()
return mdd, mdd_date, drawdown
# Pas toe op onze voorbeeld-data
mdd_value, mdd_date, drawdown_series = calculate_mdd(df)
print(f"Maximum Drawdown: {mdd_value:.2%}")
print(f"Datum van dieptepunt: {mdd_date.strftime('%Y-%m-%d')}")
We gebruiken alleen Pandas, geen extra libraries nodig. Als je dit draait, krijg je een output zoals "Maximum Drawdown: -5.45%" en de datum waarop dit gebeurde.
De drawdown_series is een nieuwe lijn die je kunt toevoegen aan je DataFrame voor visualisatie. Dit is de kern van MDD-detectie: het is geen magie, maar een simpele vergelijking tussen huidig saldo en het hoogste saldo ooit. Waarom werkt dit zo goed?
Omdat het geen assumpties maakt over je strategie. Of je nu een trend-following bot draait op futures via Interactive Brokers of een mean-reversion bot op aandelen via Alpaca, de equity curve liegt nooit. Deze methode vangt de impact van hefboom, spreads en slippage op één plek: je account saldo.
Praktische toepassing en risicomanagement
Ken je MDD, dan kun je je risicomanagement aanpassen. Stel je MDD is 15% op een account van €25.000.
Dat betekent een verlies van €3.750 in de ergste periode. Vraag je af: kan ik dat verlies mentaal aan? En financieel? Als je bot op de Binance API draait met 10x hefboom, kan een kleine marktbeweging je MDD verdubbelen.
Test daarom altijd je MDD op verschillende hefboomniveaus. Een handige truc is om je position sizing te koppelen aan je MDD.
Als je MDD historisch 10% is, en je wilt nooit meer dan 2% van je account riskeren per trade, dan moet je je inleg per trade verlagen. Gebruik een eenvoudige formule: inleg = (account saldo * 2%) / MDD. Op een €10.000 account met 10% MDD is dat €200 / 0.10 = €2.000 maximaal risico per trade.
Pas dit toe in je bot-logica, bijvoorbeeld door je stop-loss en take-profit levels dynamisch te berekenen. Verder is het slim om MDD te monitoren na elke backtest of live sessie.
Als je broker API (zoals die van DEGIRO of Plus500) latency heeft, kan je MDD groter uitvallen dan in de backtest.
Draai wekelijks een check: vergelijk je live MDD met je backtest MDD. Als het verschil meer dan 2-3% is, kijk dan naar je orderuitvoering of je risicoregels.
Variatie: rolling MDD voor dynamisch inzicht
De standaard MDD over je hele dataset is nuttig, maar soms wil je weten hoe je bot presteert in specifieke marktperiodes.
Daarom gebruiken we een rolling MDD: je berekent de MDD over een venster van bijvoorbeeld 30 dagen. Dit laat zien of je risico toeneemt tijdens volatiele markten, zoals rondom FOMC-meetings of earnings seasons. De code hiervoor bouwt voort op de vorige functie.
def rolling_mdd(df, window=30, equity_col='equity'):
eq = df[equity_col].rolling(window=window).apply(lambda x: (x.cummax() - x).max() / x.cummax().max(), raw=False)
return eq.dropna()
# Pas toe op de voorbeeld-data
rolling_mdd_series = rolling_mdd(df, window=30)
print(rolling_mdd_series.head())
We passen een rolling window toe op de equity data en berekenen per venster de MDD. Dit geeft een lijst van MDD-waardes die je kunt plotten of analyseren.
Deze rolling MDD is ideaal voor risicomanagement in live trading. Stel je draait een bot op de API van Kraken met een 1-uur timeframe.
Je kunt een rolling MDD van 7 dagen gebruiken om je stop-loss aan te passen als de markt omslaat. Als de rolling MDD plotseling stijgt naar 8%, verlaag dan je hefboom of zet de bot tijdelijk op pauze. Dit voorkomt grote klappen tijdens een flash crash. Een andere variant is de geannualiseerde MDD, die je MDD deelt door het aantal jaar in je dataset.
Handig als je rendementsdoelen stelt, zoals "max 10% jaarlijkse MDD". Dit helpt bij het vergelijken van strategieën op verschillende tijdschalen, van daytraden op aandelen tot swingtraden op crypto.
Praktische tips voor je trading setup
Begin klein: laad eerst je data in een OHLCV dataframe en test je MDD-code op een simpele CSV van een oude backtest.
Gebruik een broker zoals Interactive Brokers voor futures of Alpaca voor aandelen, en haal je historische data via hun API. Als je crypto-trade op Binance, download dan je trade history via de API en laad die in Pandas voor financiële data. Dit geeft je direct inzicht in echte MDD, inclusief fees en slippage.
Combineer MDD met andere metrics. Voeg Sharpe ratio en gewogen voortschrijdende gemiddelden toe aan je DataFrame.
Een bot met lage MDD maar lage Sharpe is misschien te conservatief.
Gebruik libraries als matplotlib of Plotly om je equity curve en MDD te visualiseren: een groene lijn voor equity, een rode voor drawdown. Zo zie je direct waar de pijn zit. Test je bot op meerdere brokers en assets. Een MDD van 5% op EUR/USD via Interactive Brokers kan 8% worden op crypto via Binance door hogere volatiliteit.
Pas je risicomanagement aan: verminder hefboom, gebruik trailing stops, of diversifieer over meerdere paren. En onthoud: geen enkele bot is perfect.
Gebruik MDD als een kompas, niet als een keiharde limiet. Tot slot, als je live gaat, zet dan een alert op je MDD. Bijvoorbeeld: als je equity onder de running peak met meer dan 10% zakt, stop dan de bot en herzie je strategie.
Dit soort discipline maakt het verschil tussen een hobby-trader en een professionele algoritmische belegger.
Veel succes met coderen, en onthoud: elke drawdown is een leerles voor je volgende trade.
