Wat is 'Momentum Trading' en hoe meet je dit met code?
Je kent dat gevoel wel: je ziet een aandeel dat als een raket omhoog schiet en je wilt instappen voordat het te laat is. Momentum trading draait precies om die vibe: meeliften op de snelheid van een trend.
In plaats van te gokken op een bodem, spring je op de trein die al vaart maakt en stap je uit voordat hij stopt.
In deze handleiding leer je niet alleen wat momentum is, maar bouw je meteen een werkende Python-check die je kunt koppelen aan je broker API voor risicomanagement en backtesting.
Wat je nodig hebt voordat je start
Je hebt geen kantoorruimte van 40 m² nodig, maar wel een stabiele basis.
Zorg dat je Python 3.10 of nieuwer hebt geïnstalleerd, bijvoorbeeld via Anaconda of pyenv. Voor data en uitvoering kies je een broker met een fatsoenlijke API, zoals Interactive Brokers, Degiro (via hun unofficial API) of Bux Zero (indien beschikbaar).
Voor data kun je Polygon.io, Alpha Vantage of je broker-API zelf gebruiken; een gratis account met 250–500 API-calls per dag is voor testen ruim voldoende. Installeer de volgende packages: pandas, numpy, yfinance (voor demo-data), requests, en eventeel ib_insync voor IBKR. Gebruik een virtuele omgeving: python -m venv momentum_env en activeer die. Plan 1–2 uur voor de eerste setup en reken op een extra uur voor debuggen. Vergeet niet je API-keys veilig op te slaan in environment variables, niet hardcoded in je script.
Tip: begin klein. Test met een enkel aandeel (bijv. ASML) en een dagelijse tijdseenheid. Zo blijft je feedbackloop snel en overzichtelijk.
Stap 1: data ophalen en voorbereiden
Begin met een simpele data-pipeline die koersen ophaalt en schone candles maakt. Gebruik een dagelijkse frequentie voor je eerste test; dat beperkt ruis en houdt het realtime-beheerbaar. Plan: 15 minuten voor data-inrichting.
- Kies je data-bron en authenticatie. Bij IBKR via ib_insync; bij REST-API’s met requests en een API-key.
- Haal minimaal 2 jaar historische data op (bijv. 500+ candles) voor zinvolle backtests.
- Schoon de data: verwijder nulls, zet index op datetime, sorteer oplopend.
- Check tijdzone: UTC of exchange-time, en sluit aan op je broker-tijd.
- Bewaar lokaal als CSV of Parquet voor snelle iteratie.
Veelgemaakte fout: vergeten tijdzones aligneren, waardoor candles uit de pas lopen. Specifieke maatvoering: gebruik een vaste resolutie (bijv. ‘1d’ of ‘1h’) en bewaar open, high, low, close, volume.
Voor een portfolio van 10–20 aandelen is een dataset van 100–200 MB normaal. Voorbeeldcode (yfinance voor demo):
import yfinance as yf
import pandas as pd
ticker = "ASML.AS" # of IBKR symbool
df = yf.download(ticker, start="2022-01-01", interval="1d")
df = df[['Open','High','Low','Close','Volume']].dropna()
df.index = pd.to_datetime(df.index)
df.sort_index(inplace=True)
df.to_parquet("data/asml_daily.parquet") Veelgemaakte fout: onbedoeld forward-looking data gebruiken (bijv. na splitsingen). Los op door corporate actions te filteren of een adjusted close te gebruiken. Check of de data sluit op 16:00 uur (US) of 17:30 uur (EU) voor consistente sluitingstijden.
Stap 2: momentum berekenen met code
Momentum meet je eenvoudig als percentuele verandering over een periode. Kies een momentum-window van 10–20 dagen voor dagdata; voor intraday kun je 60–120 minuten gebruiken. Plan: 20 minuten bouwen en testen.
Veelgemaakte fout: te korte windows (1–3 dagen) die te veel ruis geven en tot whipsaw leiden.
Formule: momentum = (close / close.shift(n)) - 1. Je kunt ook ROC (Rate of Change) gebruiken. In code:
n = 10 # momentum-venster in dagen
df['momentum'] = df['Close'].pct_change(n) Voorbeeld met EMA voor smoothing: een gemiddelde van momentum vermindert ruis. df['ema_mom'] = df['momentum'].ewm(span=5, adjust=False).mean()
Specifieke drempels: een momentum boven +0.05 (5%) is sterk, onder −0.03 (−3%) is zwak.
Pas drempels aan op volatiliteit: in rustige markten lager, in hete markten hoger. Gebruik ATR (Average True Range) om de drempel dynamisch te maken:
df['atr'] = (df['High'] - df['Low']).rolling(14).mean()
df['threshold'] = 0.01 + (df['atr'] / df['Close']) # dynamische drempel Veelgemaakte fout: vergeten dat momentum een gevoelige indicator is voor gaps. Los op door na sluiting te handelen en limit orders te gebruiken, niet market orders.
Stap 3: handelssignalen en risicomanagement
Een signaal is pas een positie waard als het voldoet aan je risico-regels.
Koppel momentum aan eenvoudige filters: richting, volume en spread. Plan: 30 minuten voor signaallogica en backtesting. Veelgemaakte fout: te veel parameters tunen, waardoor je curve-fitted strategieën krijgt.
- Koop als momentum boven drempel én boven nul, en volume boven gemiddelde.
- Verkoop als momentum onder drempel of als er een stop wordt geraakt.
- Position size: max 1–2% risico per trade op basis van ATR-stop.
Logica: Code-voorbeeld voor signaal:
df['vol_avg'] = df['Volume'].rolling(20).mean()
df['signal'] = 0
df.loc[(df['momentum'] > df['threshold']) & (df['momentum'] > 0) & (df['Volume'] > df['vol_avg']), 'signal'] = 1
df.loc[df['momentum'] < -df['threshold'], 'signal'] = -1
Risicomanagement: stop in percentages of ATR. Voor ASML op €750 kan een ATR van €15 een stop van 1 ATR (≈2%) betekenen. Position size berekenen: risico_bedrag = account * 0.01; size = risico_bedrag / (entry - stop). Voor een €10.000-account en 1% risico: risico = €100; bij een stop van €15 is size ≈ 6–7 aandelen.
Gebruik een broker API voor order types: limit orders voor entries, stop-limits voor exits. Veelgemaakte fout: geen slippage meenemen. Analyseer de order flow en tape met een realistische slippage van 0,05–0,10% voor liquid large-caps, tot 0,25% voor small-caps.
Stap 4: backtesten en validatie
Backtesten geeft je vertrouwen voor live-gaan. Gebruik een eenvoudige vectorized backtest of een event-driven engine zoals backtrader of lean (QuantConnect).
Plan: 1–2 uur voor een degelijke backtest. Veelgemaakte fout: look-ahead bias (gebruik van toekomstige data) en geen rekening houden met transactiekosten. Stappen: Code-voorbeeld (vectorized):
- Splits data: 70% train, 30% test. Gebruik time-based splits, niet willekeurig.
- Voeg transactiekosten toe: €2–5 per trade bij brokers als IBKR of DEGIRO, plus spread.
- Simuleer orderuitvoering: vul op de volgende candle open, met slippage.
- Bereken metrics: winst/verlies, winrate, Sharpe-ratio, max drawdown, expectancy.
cost_per_trade = 3.0 # euro
df['returns'] = df['Close'].pct_change()
df['strat_returns'] = df['signal'].shift(1) * df['returns']
df['trade_cost'] = (df['signal'] != df['signal'].shift(1)).astype(int) * cost_per_trade / df['Close']
df['net_returns'] = df['strat_returns'] - df['trade_cost']
cumret = (1 + df['net_returns']).cumprod()
drawdown = cumret / cumret.cummax() - 1
max_dd = drawdown.min()
sharpe = df['net_returns'].mean() / df['net_returns'].std() * (252**0.5) Check of de Sharpe boven 1.0 ligt en max drawdown onder 15% voor een dagstrategie.
Voor intraday verwacht hogere kosten; bij statistische arbitrage via de Z-score is een Sharpe boven 0.8 realistisch.
Gebruik walk-forward analyse: tune parameters op train, test op opeenvolgende vensters.
Stap 5: live testen en koppeling met broker API
Start met paper trading voor minimaal 2 weken. Koppel je script aan de broker API, test bijvoorbeeld eens hoe een grid trading bot werkt, en log elke actie.
Plan: 1 uur voor API-integratie, plus monitoring. Veelgemaakte fout: live-gaan zonder error handling of rate limits te respecteren. Stappen:
- Authenticatie: API-key, secret, en eventueel certificaten voor IBKR.
- Order routing: gebruik limit orders; market orders alleen bij spoed.
- Risico-limieten: max 3 open posities, max 5% totaal risico.
- Logging: log tijd, signaal, prijs, size, en foutmeldingen.
- Monitoring: dashboards met equity curve, drawdown, en API-latency.
Specifieke parameters: API-rate limiet vaak 100–200 calls/minuut; houd hier rekening mee bij polling.
Voor IBKR kun je met ib_insync realtime data ontvangen en orders plaatsen. Voor REST-API’s gebruik je POST /orders met payload voor size, prijs, en type. Veelgemaakte fout: vergeten dat momentum in zijwaartse markten vaak false positives geeft. Los op door een trendfilter toe te voegen (bijv. EMA(200) boven prijs voor longs).
Verificatie-checklist
Voordat je live gaat, loop deze lijst na: Als je alle items afvinkt, ben je klaar voor een eerste live-run met een kleine taille.
- Dataset compleet en tijdzone consistent? Check datetime, sluitingstijden.
- Momentum-window en drempels getuned op train-data? Geen data-lekken.
- Transactiekosten en slippage toegevoegd? Realistische bedragen per trade.
- Risico per trade berekend? 1–2% risico, stop gebaseerd op ATR.
- Backtest metrics oké? Sharpe > 1.0, drawdown < 15%.
- API-integratie getest? Orders, logging, en rate limits.
- Paper trading gedraaid voor 2 weken? Geen grote afwijkingen.
Houd de eerste dagen extra in de gaten en pas drempels en stops bij als de markt verandert.
Momentum trading is een marathon, geen sprint: blijf itereren, blijf meten, en blijf risico’s managen.
