Een Python-backtest vraagt een controleerbare keten van data naar toen beschikbare informatie, besluiten, fills en administratie. Bewaar record-ID’s naast tijdstempels. Een snelle equitygrafiek toont niet of een latere publicatie, onvoltooide bar of onmogelijke uitvoeringsprijs is gebruikt.

Kies de omgeving vanuit de onderzoeksvraag

MT5 Strategy Tester ondersteunt multicurrency-EA’s, tests en optimalisatie. Python is een andere manier om eigen data en berekeningen te organiseren, geen noodzakelijke ontsnapping aan een één-paargrens. Vergelijk contract, gegevens en uitvoeringsvereisten met dezelfde bevroren dataset en regels.

Kies de kleinste bruikbare stack en bewaar versies, licentie, gegevensrechten en ondersteunde omgeving. Onderzoek en deployment kunnen aparte kosten hebben. Geen bibliotheeknaam garandeert realistische uitvoering, een vast snelheidsvoordeel of handelskwaliteit.

Bewaar data én betekenis

Leg product, provider, tijdzone, prijszijde, interval en downloadbereik vast. Controleer dubbele ID’s, volgorde en ontbrekende perioden. Een gesloten markt is niet automatisch corrupt; forwardfill kan juist waarnemingen verzinnen. Bewaar origineel en iedere transformatie afzonderlijk. Gaten in backtestdata: CSV-dekking, conflicten en tijdstempels controleren controleert een afgebakend tijdrooster zonder prijzen te herstellen.

MetaTrader 5 copy_rates_range levert onder meer tijd, OHLC, tickvolume, spread en reëel volume. Dat is geen complete historische commissie- of swaptarieftabel. Ontvangst hangt van beschikbare terminalhistorie en instellingen af; gevraagde periode betekent niet volledig teruggegeven. Tijdargumenten en ontvangen tijden gebruiken UTC. Converteer sessies expliciet per datum naar bijvoorbeeld Europe/Amsterdam.

pandas en NumPy ondersteunen gegevensberekeningen. Backtrader organiseert een eventgedreven workflow. Vectorbt verwerkt eveneens order-, signaal- of customorderfunctiemodi en werkt kas- en activatoestand bij. Vectorinvoer betekent niet dat iedere uitvoering onafhankelijk van eerdere toestand is.

Het indexlabel weglaten kan het signaal aan een andere bar koppelen

Labels of alleen arrayposities?Drie fictieve voltooide records met unieke ID’s en willekeurige prijzen. Flag 1 is slechts kandidaat, geen fill of financieel resultaat.REKENVOORBEELDPrijzenA100, B102, C104FlagsC1, A0, B0Series op labelA0, B0, C104Arrays op positie100,0,0
Labels of alleen arrayposities? Drie fictieve voltooide records met unieke ID’s en willekeurige prijzen. Flag 1 is slechts kandidaat, geen fill of financieel resultaat.

Gelijke lengte bewaart geen identiteit. Controleer labels vóór to_numpy en daarna de informatietijd.

Prijzen
A100, B102, C104 – Op volgorde A, B, C.
Flags
C1, A0, B0 – Andere volgorde, zelfde unieke ID’s.
Series op label
A0, B0, C104 – Kandidaat is C.
Arrays op positie
100,0,0 – Teruggeplakt op A, B, C selecteert onjuist A.

Het fictieve bronbestand heeft voltooide prijsrecords A100, B102, C104, in die volgorde. Een afzonderlijke flag-Series staat in volgorde C:1, A:0, B:0. Flag 1 betekent slechts kandidaat voor verder onderzoek, geen order of fillprijs.

pandas koppelt Series op label: prices * flags geeft A0, B0, C104. Beide naar arrays converteren en op positie vermenigvuldigen geeft 100,0,0. Terugplakken op A, B, C selecteert dan onjuist A. De reekslengte klopt nog steeds. Controleer ID’s vóór to_numpy(); juiste koppeling vraagt daarnaast juiste beschikbaarheidstijd.

Bepaal wanneer een record bruikbaar wordt

Een H1-bar met opening 10.00 heeft niet al om 10.00 zijn volledige OHLC. Bij resampling bepaalt closed welke rand in het interval valt en label het weergegeven randlabel. Een ander label maakt de aggregatie niet eerder beschikbaar.

Koppel macrodata op publicatietijd van de toen beschikbare versie, niet alleen de beschreven maand. merge_asof vereist gesorteerde tijdsleutels. backward kiest vroeger of gelijk; nearest kan later kiezen. Geen van beide kent revisies vanzelf. Leg tolerantie en volgorde bij gelijke tijdstempels vast. EA met API offline backtesten: beschikbare versies en null controleren scheidt versie en observatieperiode.

De eigen broncontrole beslist om 10.04 UTC. Er zijn alleen releases 10.00 met 50 en 10.05 met 60. Zonder tolerantie kiest backward 50, vier minuten oud. nearest kiest 60, één minuut dichtbij maar in de toekomst. Met inclusieve backwardtolerantie twee minuten bestaat geen match. Bewaar dat ontbreken; de toekomst invullen verandert de informatieverzameling.

Het aparte gesloten-barmodel heeft eerste twintig High-waarden 100 tot 119, met steeds Open=High−0.5, Low=High−2, Close=High−1. Bar 21 heeft O120/H121/L118/C120.5; bar 22 O120.6/H122/L119/C121. Dit zijn willekeurige niet-marktprijzen, geen FX-trade.

previous_high = bars["high"].shift(1).rolling(20).max()
signal = bars["close"] > previous_high
next_bar_signal = signal.shift(1, fill_value=False)

Op bar 21 is de vorige twintigbarstop 119, dus 120,5>119 waar. De huidige High meenemen maakt drempel 121 en conditie onwaar. De laatste coderegel plaatst het waargenomen signaal op bar 22, maar levert geen fillprijs, orderacceptatie, hoeveelheid of exit. Gebruik alleen voltooide invoer en definieer die overige fasen apart.

Signaal, fill en kosten afzonderlijk modelleren

Backtrader beschrijft voor zijn gewone Market-model een order na huidige barverwerking op de opening van de volgende beschikbare bar. Andere instellingen of modellen kunnen timing wijzigen. Als stop en target binnen dezelfde OHLC-bar vallen, bepaalt OHLC alleen hun waarnemingsvolgorde niet.

Het fictieve een-trademodel koopt 10.000 EUR op toegewezen EUR/USD-Ask 1,1002 bij Bid 1,1000. Later sluit het alles op Bid 1,1012 bij Ask 1,1014. Pip 0,0001 geeft tienpipsfillverschil, USD 10. Commissie USD 1 per zijde geeft netto USD 8; financiering en extra slippage zijn hier nul aangenomen.

Nogmaals twee entryspreadpips aftrekken maakt USD 6 en telt een al opgenomen prijsverschil dubbel. Definieer echte financiering, conversie, contractgrootte, marge en geweigerde orders voor het onderzochte product. Een willekeurig slippagemodel vraagt verdeling, seed en bibliotheekversie.

Nieuw afzonderlijk EUR-tegenvoorbeeld: een zelfgemaakt allocatiemodel begint met EUR 1.000 beschikbaar voor twee gelijktijdige orders. A reserveert exact EUR 700 marge; B EUR 400. Geen andere blootstelling, kosten of waardeverandering tijdens de allocatie. Beide volledig uitvoeren vraagt EUR 1.100 en is onmogelijk onder deze modelgrens.

Met “alles of niets” per order wordt bij A-eerst B geweigerd; bij B-eerst A. Ken alleen ter illustratie aan een uitgevoerde A EUR 70 en aan uitgevoerde B EUR 40 later nettoresultaat toe. Dan zijn de twee scenariototalen 70 of 40, niet de onafhankelijk opgetelde 110. Margeregels en latere uitkomsten zijn toegewezen, geen actuele brokerformule of voorspelling. Een gedeelde rekening heeft gedeelde beperkingen; onafhankelijke equitycurves optellen kan onfinancierbare orders verbergen.

Een grootboek maakt de uitkomst herleidbaar

Het afzonderlijke gelijk-R-model heeft precies veertig winsten+2R en zestig verliezen−1R:80R positief,60R verlies, netto 20R, PF80/60≈1,33, gemiddelde 0,2R. Kosten 0,1R op iedere trade geven veertigmaal+1,9R en zestigmaal−1,1R:76R positief,66R verlies, netto 10R, PF76/66≈1,15 en gemiddelde 0,1R. R heeft overal hetzelfde geldbedrag; dit is rekenwerk, geen echte backtest.

De eigen herinstapcase heeft vijf condities waar, waar, waar, onwaar, waar. Beide procedures openen op bar 1; de stop sluit op bar 2 vóór instapbeoordeling. Er zijn geen verdere exits. “Flat en waar” opent direct weer op bar 2. “Eerst een nieuwe onwaar afwachten” blijft wachten op 2 en 3, activeert weer op 4 en opent op 5.

Beide tellen twee instappen maar op andere momenten. Dit is een eigen gekozen toestandsmachine, geen standaardclaim over een bibliotheek. Bewaar instap-ID’s en toestandovergangen, niet alleen tradeaantal. Houd open-equity en gesloten resultaten apart, beginvermogen als piekreferentie en externe stromen buiten tradingrendement.

Selectie en onbekende evaluatie niet verwarren

Leg trainings- en testvensters chronologisch vast vóór voorkeursregels worden gekozen. Bewaar alle instrumenten, parameters, filters, splits en verworpen versies. Weinig zichtbare parameters betekent niet weinig onderzochte hypotheses. Bailey en mede-auteurs bespreken backtestoverfitting; uit onze fictieve cases wordt geen PBO berekend.

Het andere toegewezen honderd-trademodel heeft 75 winsten+0,2R en 25 verliezen−1R. Winrate 75%, winstsommen 15R/verliessom 25R, netto−10R en PF0,6 vóór kosten. Geen hitrate- of PF-drempel diagnosticeert alleen een bug. Controleer informatietijd, afhankelijkheid, uitvoering en sensitiviteit vóór een oorzaak wordt ingevuld.

Een offline onderzoek zonder echte order starten

  1. Maak een geïsoleerd project en bewaar ongewijzigde data met ID’s, bron, UTC, prijszijde en versie. Voor dit leren zijn geen live credentials nodig.
  2. Werk enkele volledig opgegeven records door: wanneer is het signaal bekend, welk volgend event mag uitvoeren en wat bij ontbreken of revisie?
  3. Definieer toevoegen, omkeren, herinstappen of opnieuw activeren expliciet. Controleer verwachte entry-ID’s.
  4. Sluit iedere fill en kostenregel aan en leid rapportmaten uit het grootboek af. Bewaar geen Sharpe of drawdown die niet uit gedateerde reeksen volgt.
  5. Vergelijk dezelfde bevroren regels onder beschreven alternatieve uitvoering en bewaar proeven, vensters en beperkingen. Een vaste daling in prestatie identificeert haar oorzaak niet.