De invloed van 'Transaction Costs' op je optimale parameters
Je hebt een strategie die in de backtest glorieus presteert. Blauwe koeien overal, de equity curve schiet omhoog als een raket.
Je zet 'm live en... poef. De winst verdwijnt als sneeuw voor de zon. Wat is er misgegaan?
Waarschijnlijk heb je de boosdoener genegeerd: transaction costs. Dit zijn de stille moordenaars van elke algoritmische trading bot.
Ze eten je winst op, hapje voor hapje, tot er niets meer over is.
Laten we het hier eens rustig over hebben, alsof we aan de keukentafel zitten met een bak koffie.
Waarom je kosten negeert en je bot faalt
Stel je voor, je bent een supermarkt. Je verkookt een blikje frisdrank voor €1,05.
Je inkoopt voor €1,00. Mooie marge, denk je. Maar dan komt de bezorger langs die €0,05 vraagt voor elke doos die hij levert. En de bank die €0,02 rekent per transactie. En de belasting.
Opeens houd je niets meer over. Zo werkt het ook met je trading bot.
In een backtest met Interactive Brokers of een andere broker, zie je vaak de werkelijke kosten niet.
Je ziet alleen de marktprijs. De realiteit is hard. Elke trade die je bot maakt, kost geld.
Een klein beetje hier, een klein beetje daar. Als je bot 1000 trades per dag maakt - wat bij HFT-strategieën normaal is - worden die kleine beetjes een enorme berg.
Je optimale parameters, zoals een stop-loss van 0,5% of een winstdoel van 1,2%, werken ineens niet meer. Die parameters zijn gebaseerd op een perfecte wereld zonder wrijving. De kunst is om die wrijving te begrijpen en je bot erop aan te passen.
De drie musketiers van de kosten: Commissie, Spread en Slippage
Transaction costs bestaan niet uit één ding, maar uit drie. De eerste is de makkelijkste: commissie.
Dit is wat je broker rekent per transactie. Bijvoorbeeld Interactive Brokers (IBKR) rekent voor aandelen in de VS ongeveer $0,005 per aandeel, met een minimum van $1 per order. Bij crypto exchanges zoals Binance of Kraken betaal je een 'taker' of 'maker' fee, vaak rond de 0,04% tot 0,1%.
Als je een bot draait met lage winstmarges, is dit direct je winst die verdwijnt. De tweede musketier is de spread.
Dit is het verschil tussen de bied- en de laatprijs. In een rustige markt is de spread klein, bijvoorbeeld 0,01% op de S&P 500.
Maar als de markt volatiel is, of als je handelt in een illiquide small-cap aandeel, kan de spread oplopen tot 1% of meer. Je bot koopt direct boven de marktprijs en verkoopt direct eronder. Zonder een prijsbeweging ben je al 1% in de min. De derde en meest vervelende is slippage.
Dit gebeurt als je een marktorder plaatst, maar de uitvoeringsprijs slechter is dan je had verwacht. Je denkt dat je koopt op $100,00, maar door een snelle beweging of weinig liquiditeit krijg je de order gevuld op $100,10.
Een rekenvoorbeeld dat pijn doet
Dit is typisch 0,1% tot 0,5% op normale aandelen, maar in een flash crash of bij een slechte API-verbinding kan dit oplopen tot percentages die je strategie direct naar de filistijnen helpen. Laten we het concreet maken. Je strategie haalt in een schone backtest 10% winst per jaar.
Je bot maakt 500 trades per jaar. Je broker rekent $0,01 commissie per aandeel (bijv. via Tastyworks).
De gemiddelde spread is 0,05% en de slippage is 0,02%. Een trade kost je dus ongeveer: $0,01 commissie + 0,07% van je kapitaal. Als je met $10.000 handelt, is 0,07% ongeveer $7 per trade.
500 trades x $7 = $3500 aan kosten. Je winst was $1000.
Je verliest dus $2500 per jaar. Je strategie is in één klap veranderd van een winstgevende machine in een verliesgevende ramp. Dit is wat er gebeurt als je de 'optimale parameters' uit een backtest zonder kosten live zet. De winstgevende zone wordt simpelweg kleiner.
Hoe kosten je optimale parameters verneuken
Stel, je gebruikt een Python script met Pandas en Backtrader. Je hebt een moving average crossover strategie.
Je optimaliseert de parameters: de snelle MA op 50 perioden, de langzame op 200. In de backtest levert dit 15% op. Je zet de stop-loss op 1% en het winstdoel op 2%. Vergeet niet het belang van out-of-sample testen na deze optimalisatie, want dit is de 'sweet spot' volgens je optimizer.
Als je nu de transaction costs toevoegt (laten we zeggen 0,1% per trade round-trip), verandert het plaatje drastisch. Je winstdoel van 2% wordt nu 1,9% (na kosten).
Je stop-loss van 1% voelt nu aan alsof hij al triggerd op 1,1%.
Je strategie haalt de winstdoelen niet meer of stopt te vroeg. De optimizer zal je nu vertellen dat een winstdoel van 3% en een stop-loss van 1,5% beter is. Door walk-forward optimalisatie toe te passen, voorkom je dat je enkel op historische data vertrouwt. Minder trades, maar wel winstgevend.
Hetzelfde geldt voor de instellingen van je bot. Een 'tight' stop-loss werkt geweldig zonder kosten.
Met kosten word je eruit getrapt door de spread en slippage. Je bot wordt een 'whipsaw' machine die constant in en uit gaat, terwijl hij alleen maar kosten maakt. De optimale parameter voor de stop-loss moet dus 'ruimer' zijn om de kosten te dekken.
Modellen en prijsindicaties: Wat kost het echt?
Hoe bereken je dit nu in je backtest? De meeste Python libraries (Backtrader, Zipline, Lean) hebben ingebouwde opties voor commissies.
Je kunt hier specificeren wat je brokerrekent. Bijvoorbeeld: commission=0.005 per share.
Voor crypto is dit vaak percentage=0.001 (0,1%). Voor slippage en spread is het lastiger. Je kunt geen vaste waarde nemen. Je moet een model gebruiken.
Een simpel model is: slippage = 0.0005 * price (0,05%). Een beter model houdt rekening met de volatiliteit.
In een rustige markt is de slippage laag, in een hectische markt hoog. Je kunt dit doen door de 'true range' te gebruiken. Prijsindicaties per broker (ongeveer):
- Interactive Brokers (Aandelen US): Commissie $0,005 per aandeel (min $1). Spread vaak verwaarloosbaar, tenzij small caps.
- Trading212 / DEGIRO (Retail): Vaak 'free', maar de spread is de verborgen kost. Soms 0,5% op exotische producten.
- Crypto (Binance/Kraken): Fees 0,04% - 0,1%. Slippage hangt af van de liquidity van het paar. BTC/USD is laag, een meme coin is extreem hoog.
- Futures (CME via AMP): Commissie per contract (bijv. $0,75 per future). Spread is minimaal, slippage hangt af van de tick size.
Als je een high-frequency strategie draait op crypto, let dan op de 'taker' fee. Je moet weten of je 'maker' (liquidity toevoegen) of 'taker' (liquidity wegnemen) bent.
Je bot moet dit weten, anders klopt de berekening voor geen meter.
Het gevaar van overdrijven
API's van exchanges geven deze data door, maar je moet ze wel correct interpreteren in je risicomanagement script. Pas op dat je niet te pessimistisch bent. Sommige traders zetten slippage op 1% om 'realistisch' te zijn.
Dan gooi je een goede strategie direct weg. Wees realistisch. Meet het. Als je een API gebruikt, log dan de daadwerkelijke uitvoeringsprijs versus de prijs op het moment van de order. Dat is de enige manier om accurate data te krijgen voor je volgende backtest, en om te voorkomen dat je in de valkuil van over-optimization trapt.
Praktische tips: Fix je parameters nu
Het goede nieuws: dit is oplosbaar. Je bent niet de eerste die hier tegenaan loopt.
- Meet het eerst: Draai je bot live op een demo-account of met een heel klein bedrag (bijv. €100). Log elke trade. Wat was de verwachte prijs? Wat was de werkelijke prijs? Het verschil is je echte slippage + spread. Pas dit getal aan in je backtest.
- Voeg het toe aan de optimizer: Stop met optimaliseren op 'Winst'. Optimaliseer op 'Winst na kosten' (Net Profit). De meeste Python backtesters laten je een eigen 'return' functie schrijven. Doe dit. Trek direct de commissies en een schatting van slippage af van je daily returns.
- Filter je trades: Kijk naar je winstgevende trades. Als je een winstdoel van 0,5% hebt en je kosten zijn 0,2%, moet je 40% van je winst inleveren. Verhoog je winstdoel naar 1% of 1,5%. Je doet minder trades, maar de trades die je doet, leveren netto meer op.
- Gebruik Limit Orders: Waar mogelijk, gebruik limit orders in plaats van market orders. Dit voorkomt slippage. Je loopt wel het risico dat de order niet wordt uitgevoerd, maar dat is vaak beter dan een dure executie. Pas je 'filled or killed' settings aan in je broker API.
- Check de API limits: Sommige brokers rekenen extra kosten als je te veel API calls maakt (rate limits). Zorg dat je bot efficient codeert. Geen oneindige loops die de koers elke seconde opvragen als je maar elke minuut een trade hoeft te doen.
Hier is een stappenplan om je bot weer scherp te krijgen, zonder dat je meteen je spaargeld verliest. Uiteindelijk draait het allemaal om realisme. Een trading bot is geen magische geldprinter. Het is een systeem dat probeert een klein randje te vinden op de markt.
Zonder rekening te houden met transaction costs, ben je die randjes aan het wegsnijden voordat je ze kunt pakken. Pas je parameters aan, wees streng voor je kosten, en je zult zien dat je winstgevendheid stijgt, ook al is het aantal trades misschien lager. Veel succes met het tunen van je bot!
