playitsmart.nl

Terug naar home

9 mei 2026 · 6 min lezen

Post #1

27 procent rendement in drie maanden. Te mooi om waar te zijn.

De eerste backtest van mijn handelssysteem. Een seconde of tien voelde ik me geweldig. Toen niet meer.

Vanmorgen om kwart over acht zat ik met koffie achter m'n laptop te kijken naar de uitkomst van de eerste backtest van mijn handelssysteem. Drie maanden gesimuleerd, januari tot eind maart 2024. Tien duizend euro startkapitaal.

De cijfers verschenen in de terminal:

Total return: +27.36%
Sharpe ratio: 7.10
Max drawdown: -1.79%
Win rate: 69.2%

Een seconde of tien voelde ik me geweldig. Toen niet meer.

Te goed om waar te zijn

Een Sharpe ratio van 7. Voor wie niet bekend is met de term: dat is een maat voor rendement gedeeld door risico. Boven 1 is goed. Boven 2 is uitzonderlijk. Het beroemdste hedgefund ooit, Renaissance Technologies' Medallion Fund, draaide naar verluidt rond een Sharpe van 2.5 over decennia. Drie keer zo hoog als wat ik nu zag.

Een Sharpe van 7 in drie maanden voor een long-only aandelenstrategie? Dat kan niet. Dat is geen edge, dat is een bug.

Ik typte "+27% Sharpe 7" in de terminal en stuurde het naar Harry, mijn AI sparringpartner. Die schreef het meteen op:

"Dit is exact waarom we eerst smoke testen voor we 4 jaar draaien. Sharpe 7 is bizar hoog. Goed = 1.5. Top quant = 2-3. Een echte strategy die 27% in 3 maanden maakt MOET ergens fluctueren. Een -1.8% drawdown over 63 dagen is te smooth om waar te zijn."

We gingen op zoek. Twee bugs later had ik m'n koffie nog niet op.

Bug één: de "vereenvoudiging" die alles brak

In mijn systeem zit een exit trigger genaamd target_hit. Het idee: koop een aandeel als het ondergewaardeerd is binnen z'n sector, verkoop het als het de sectormediaan bereikt. Klassieke value mean-reversion.

Toen we naar de eerste run keken, zagen we iets vreemds. 90% van alle exits waren target_hit. Negentig procent. En vaak op de dag na entry. BKNG gekocht op 124,93 euro, target_hit op 122,57 een dag later. Dat is niet een target hit, dat is een verlies van 1,9 procent.

Ik vroeg Cursor, mijn andere AI die de code schrijft, om de target_hit functie te laten zien. Daar stond:

def check_target_hit(position, ticker_ev_ebitda, sector_median):
    """Trigger 6: EV/EBITDA reached sector median (coming from below).
    
    Logic: if at entry the ticker was below sector median, 
    and now is at/above, exit.
    For V1 simplification: just check if current >= sector median.
    """
    return ticker_ev_ebitda >= sector_median

Lees de docstring. Hij wist precies hoe het hoorde. "If at entry the ticker was below sector median, and now is at/above, exit." Dat is correct. Maar dan kwam de regel die alles kapotmaakte: "For V1 simplification: just check if current >= sector median."

Cursor schreef goed gedocumenteerde code en sloeg vervolgens de helft van de logica over met een opmerking dat het wel goed kwam. Daardoor ging de trigger niet meer over "aandeel was undervalued en heeft target bereikt", maar over "aandeel zit boven sectormediaan op dit moment". Dat is de helft van de markt, elke dag.

Voor mijn portfolio betekende het: koop een aandeel, kijk of het ergens boven de mediaan zit, verkoop het meteen weer. Een soort algoritmische ADHD.

We hebben Cursor de fix laten schrijven. Vier nieuwe tests, oude tests aangepast, klaar in tien minuten. Maar de echte vraag bleef: hoeveel andere "V1 simplifications" zitten er nog ergens in mijn code?

Bug twee: praten over wat je nog niet weet

Na de target_hit fix draaide ik dezelfde drie maanden opnieuw.

Total return: +27.36%
Sharpe ratio: 7.10

Ja, hoger zelfs. Sharpe nu 7.10. Geen verandering, want bug één was niet de bron van de te-mooie cijfers. Dat is bug twee.

Hier wordt het subtiel.

Mijn systeem berekent elke handelsdag scores voor 462 aandelen. Die scores zijn gebaseerd op de slotkoersen van die dag. Vervolgens beslist het: koop deze, verkoop die. En in mijn backtest gebeurde de aankoop ook op die slotkoers.

Dat klinkt logisch. Het is niet logisch.

In de echte wereld komt om half tien 's avonds de slotkoers binnen, daarna draait mijn backend de scores. Tegen elven weet ik welke aandelen morgen interessant zijn. Maar morgen is morgen. Ik kan vandaag's slotkoers niet meer kopen, die is geweest.

In de backtest deed ik dat wel. Het systeem keek naar de slotkoers, berekende dat die hoog scoorde, en kocht alsof het diezelfde slotkoers nog kon krijgen. Dat is look-ahead bias: een systeem dat informatie gebruikt die op het moment van handelen nog niet beschikbaar was.

Wat is het effect? Stel je voor dat NVIDIA op een woensdag onverwacht goede kwartaalcijfers presenteerde, na sluiting van de markt. Dat nieuws zit in de slotkoers van donderdag. Mijn systeem zag donderdagavond een mooie score voor NVIDIA en "kocht" die diezelfde donderdag, op slotkoers. Maar in werkelijkheid had ik pas vrijdagochtend kunnen kopen, en dan weet de markt het ook al. NVIDIA zou waarschijnlijk drie procent hoger openen.

Over zestig handelsdagen, met veertien posities, opgeteld: het verschil tussen optimistische backtest en werkelijkheid loopt al snel op tot dertig procentpunt rendement. Dat is precies wat ik zag.

Het patroon

Beide bugs hebben iets gemeen. Het zijn niet domme fouten in de zin van "syntax error" of "verkeerd nummer". Het zijn logica fouten in een systeem dat verder werkt zoals het hoort. Tests groen. Code netjes. Output plausibel ogend.

Een test kan controleren: "als je de check_target_hit functie aanroept met deze parameters, krijg je deze output". Maar een test kan niet controleren: "is dit conceptueel wat we willen testen?". Dat moet een mens zien. Of beter: meerdere mensen, met meerdere perspectieven.

Bij mijn project werkt dat zo: ik denk en ontwerp, Harry reviewt en stelt prompts op, Cursor bouwt de code. Drie ogenparen op elke beslissing. Vandaag werkte het. Cursor schreef de bug, Harry zag de cijfers en zei "dit klopt niet", ik checkte de code. Tien minuten later was bug één gefixt. Een uur later bug twee.

Wat nieuw voor me is: ik vertrouw Cursor om code te schrijven, maar ik kan hem niet vertrouwen om logisch correct te zijn. Hij is geweldig in mechanica. Het werkt. Maar of het ook klopt, dat is een andere vraag.

Wat nu

Na de twee fixes draaide ik een sanity check. Niet de bull market van Q1 2024, maar Q3 2022, toen de markt ongeveer 16 procent zakte. Als mijn strategie zonder bias is, zou hij in die periode rond nul moeten uitkomen. Niet positief, niet zwaar negatief. Gewoon: defensief gedrag in een dalende markt.

Resultaat: +0,04 procent. Vlak. Geen verlies, geen winst. Precies wat een gezond systeem in een crashende markt hoort te doen.

Volgende keer dat je een backtest ziet met Sharpe 7 en een drawdown van anderhalf procent, weet je het: ergens, in een van de honderden regels code, staat iemand zichzelf voor de gek te houden. Soms ben jij het. Soms is het je AI.

In dit geval waren we het allebei.

Wekelijks volgen?