Backtesting i forward testing — metodologia i pułapki testowania
Testowanie strategii pozwala sprawdzić, jak jej reguły działają na danych i na ile wynik zależy od przyjętych założeń. Backtest wykorzystuje dane historyczne, a forward test polega na obserwacji działania strategii na bieżąco napływających danych. Obie metody wymagają uwzględnienia kosztów, sposobu realizacji zleceń i ograniczeń dostępnej próby. W tej lekcji pokazujemy, jak przygotować test, oddzielić dane służące do opracowania strategii od danych przeznaczonych do jej oceny oraz rozpoznać błędy, które mogą zawyżać wyniki. Znajdziesz tu kartę testu, przykłady obliczeń i wskazówki dotyczące porównania wyników historycznych z późniejszymi obserwacjami. Pomogą Ci ocenić, co wynika z zebranych danych, a czego nie można jeszcze na ich podstawie stwierdzić.
- Backtest odpowiada na pytanie „czy strategia mogła zarabiać w przeszłości", forward test odpowiada na pytanie „czy zarabia teraz". To dwa różne testy z dwoma różnymi pułapkami — żaden nie zastąpi drugiego
- Sześć pułapek metodologicznych: look-ahead bias, survivorship, curve fitting, overfitting, niedomodelowane koszty i data snooping — plus osiem typowych błędów wdrożenia w sekcji 9. Każda potrafi sama zamienić tracący system w pozornego zwycięzcę
- Walk-forward analysis to szeroko opisana metoda walidacji: in-sample (np. 70% danych) do kalibracji, out-of-sample (30%) do walidacji, okno przesuwane krokiem. Sam podział jest założeniem scenariusza, nie normą. Bez tego optymalizujesz na szumie historycznym
- Liczba transakcji sama nie jest dowodem — rozstrzyga szerokość przedziału względem progu decyzji. Dla WR 60% i prób niezależnych (Clopper–Pearson, 95%): N = 30 daje ±18 pp, N = 200 daje ±7 pp, N = 500 daje ±4 pp. Przy seriach i wspólnych zdarzeniach przedział jest szerszy
- Forward na danych napływających sprawdza co innego niż backtest: rozjazd sygnałów, koszty egzekucji, awarie alertów i błędy człowieka pod realnym ryzykiem. Długości etapów używane w tym artykule (30 dni demo, 90 dni mikrokonta) to założenie scenariusza — nie norma rynkowa i nie walidacja statystyczna
Zapisz hipotezę, reguły, próbę i wyniki w dodatku N: protokole testowania strategii. Formularz uzupełnia metodę z tego rozdziału; umożliwia zapis lokalny, eksport i wydruk.
1. Backtest vs forward test — różne pytania, różne odpowiedzi
Większość początkujących robi jeden błąd: po dobrym backteście uznaje, że strategia jest gotowa. Nie jest. Backtest sprawdza historię, forward sprawdza wykonanie tu i teraz. W praktyce to są dwa różne filtry: backtest łapie statystykę, forward łapie realną egzekucję, opóźnienia, poślizg i to, czy trader faktycznie klika zgodnie z regułami. Pomylenie ról oznacza, że jeden test próbujesz zastąpić drugim — i tracisz informację, którą tylko ten drugi potrafiłby ci dać.
Backtest — pytanie historyczne
Backtest pyta: „Gdyby strategia działała przez ostatnie 3–10 lat, jak by się zachowała?". Odpowiedź jest tak dobra, jak jakość danych i jakość modelu kosztów. Backtest jest retrospektywny — patrzy w przeszłość, więc:
- Jest szybki — możesz przetestować 5 lat danych w 10 minut
- Daje dużą próbę — kilkaset, kilka tysięcy transakcji
- Pozwala porównać warianty parametrów — ale to jednocześnie jego największa pułapka (overfitting)
- Jest wrażliwy na jakość danych — błędne ticki, brakujące świece, wadliwy model kosztów = wynik bezwartościowy
Backtest nie odpowiada na pytanie, czy strategia działa teraz. Reżim rynkowy z 2018–2022 może nie istnieć w 2024–2026. Strategia, która świetnie zarabiała na trendach JPY z lat 2012–2015, nie zarabia w środowisku QE plus interwencji BOJ.
Forward test — pytanie prospektywne
Forward test pyta: „Czy strategia zarabia teraz, w obecnym reżimie, na realnych warunkach egzekucji?". Jest prospektywny — patrzy w przyszłość, dane spływają w czasie rzeczywistym, więc:
- Jest powolny — żeby zebrać 100 transakcji przy 5 trade'ach tygodniowo, potrzebujesz 5 miesięcy
- Daje mniejszą próbę — większość forward testów detalu kończy się na 30–80 transakcjach
- Eliminuje look-ahead bias z definicji — danych z przyszłości fizycznie nie ma
- Mierzy realne warunki egzekucji — spread w stresie, slippage, requote, opóźnienia mostka
- Mierzy poślizg ludzki — fat-finger, paraliż decyzyjny, manualne interwencje na otwartej pozycji w warunkach stresu rynkowego
Forward test nie odpowiada na pytanie, czy strategia ma długoterminową przewagę — próba jest za mała. Odpowiada na pytanie, czy nie ma fundamentalnej dziury między backtestem a realem.
Trzy tryby testu: manualny, replay i automatyczny
„Backtest" to w praktyce trzy różne czynności o różnej mocy dowodowej — i warto je rozdzielić, zanim zacznie się spór o wynik:
- Test manualny. Przewijasz wykres i zapisujesz decyzje. Wykazuje, czy reguły są w ogóle wykonalne i gdzie leżą przypadki graniczne. Nie wykazuje statystyki: widzisz świece, których w danym momencie by nie było, a tempo przewijania i pamięć o tym, co stało się dalej, skażają próbę.
- Replay — odtwarzanie świeca po świecy. Narzędzie odtwarza historię z zasłoniętą przyszłością (bar replay w TradingView, tryb wizualny testera MT4/MT5, osobne aplikacje do replayu). Wykazuje powtarzalność oceny uznaniowej i realny czas reakcji, bo kolejnej świecy fizycznie nie widzisz. Nadal nie mierzy kosztów wykonania i nadal zależy od twojej uczciwości — cofnięcie się o dziesięć świec unieważnia próbę.
- Test automatyczny. Kod na danych historycznych. Jedyny tryb, który daje dużą próbę i powtarzalność co do świecy, ale wprowadza wszystkie pułapki z sekcji 2: look-ahead, model wykonania, koszty, strojenie.
Kolejność ma znaczenie. Replay przed kodem pokazuje, których reguł nie da się zapisać jednoznacznie — a reguły niejednoznacznej nie naprawi żaden tester, tylko powtórzy twoją uznaniowość z ładnym wykresem equity. Specyfikację i wersję strategii zamrażasz przed testem (15.3), nie po obejrzeniu wyniku.
Czego nie wykryje backtest, czego nie wykryje forward
| Klasa błędu | Wykrywa backtest? | Wykrywa forward? |
|---|---|---|
| Look-ahead bias (dane z przyszłości w decyzji) | Nie — to jest źródło iluzji | Tak — dane z przyszłości fizycznie niedostępne |
| Curve fitting parametrów | Częściowo — tylko walk-forward | Częściowo — ujawnia się dopiero po wystarczającym N lub zmianie reżimu (krótki forward sam może trafić w korzystną wariancję) |
| Niedomodelowane koszty (slippage, requote) | Częściowo — zależy od jakości modelu | Tak — koszty realne są mierzone bezpośrednio |
| Zmiana reżimu rynkowego od czasu danych historycznych | Nie — operuje na starych danych | Tak — operuje na obecnym reżimie |
| Niewykonalność reguł przez tradera (dyscyplina) | Nie — backtest zakłada idealne wykonanie | Tak — realny człowiek przy klawiaturze |
| Precyzja pomiaru edge'u (wąski przedział wokół expectancy) | Tak — backtest dostarcza dużej próby | Nie — forward przy 5 transakcjach tygodniowo daje około 130 obserwacji w pół roku (26 × 5), a przedział przy takim n jest szeroki |
| Drawdown w długim horyzoncie (3+ lata, kilka cykli) | Tak — backtest na 5 lat to kilka cykli | Nie — forward to zwykle 1 cykl rynkowy |
Bez backtestu nie masz próby. Bez forwardu nie wiesz, czy twój backtest nie był fikcją kosztową albo efektem repaintującego wskaźnika. W praktyce traderzy pomijają forward test częściej niż backtest — bo forward to 90 dni czekania, a backtest daje wyniki w 10 minut. To jest dokładnie ten moment, w którym tracą kapitał, który backtest „zaoszczędził".
Reconciliation backtest vs forward — procedura kontrolna
Najmocniejszy detektor look-ahead bias i błędów feedu danych: porównanie sygnał po sygnale. Eksport z backtestu i z forwardu w jednolitym formacie CSV:
timestamp_utc, broker_server_time, pair, setup_id, direction, entry_rule_hash,
entry_price, sl_price, tp_price, trigger_bar_close, source
Pierwsze 30–60 dni forwardu generuje sygnały na realnych świecach. W tym samym oknie odpalasz backtest na archiwalnych danych z tych dni. Porównujesz oba pliki: rozjazd > 5–10% sygnałów = alarm. Możliwe przyczyny: look-ahead w indykatorze, repaint, inny feed danych, błąd w kodzie strategii (np. dostęp do Close[0] intrabar). Strategia, która produkuje 50 sygnałów w backteście i 12 w forwardzie na tych samych dniach, ma fundamentalną dziurę i nie idzie dalej, dopóki diagnoza nie jest jednoznaczna.
timestamp_utc, jak i broker_server_time. Część brokerów MT4/MT5 używa czasu serwera GMT+2/GMT+3 z przesunięciem DST (zwykle dopasowanym do New York close, czyli 5 PM ET). Jeśli porównasz sygnały bez normalizacji czasu, wykryjesz „look-ahead", którego nie ma — bo testujesz inne świece niż te, na których działa twój EA. Zawsze najpierw normalizuj do UTC, potem porównuj. Przy okazji policz dwie rzeczy, które trafiają do karty testu: ile świec w twoim zakresie w ogóle nie ma (przerwy w feedzie, dni świąteczne, luki dostawcy) i ile timestampów się dubluje. Obie potrafią zmienić wynik bez żadnego śladu w raporcie testera.Karta testu — dwanaście pól wypełnianych przed oceną wyniku
Wynik testu bez karty jest nieodtwarzalny: za pół roku nie wiesz, na jakich danych, z jakim modelem wykonania i po ilu próbach powstał. Karta ma dwanaście pól, a pierwsze dziewięć wypełniasz przed uruchomieniem testu. To jest cały mechanizm — reszta artykułu tylko tłumaczy, dlaczego każde z tych pól potrafi odwrócić wniosek.
| Pole | Co zapisujesz | Przykład wypełnienia (dane syntetyczne) |
|---|---|---|
| 1. Pytanie | jedno zdanie, na które test ma odpowiedzieć | „Czy wybicie zakresu godziny przed otwarciem Londynu na EUR/USD ma dodatnią expectancy po kosztach?" |
| 2. Wersja strategii i kodu | identyfikator wersji i hash zamrożonej specyfikacji | lonbreak v1.3, hash a91f…, zamrożone przed pierwszym uruchomieniem OOS |
| 3. Dane i okresy | dostawca, instrument, rozdzielczość, bid/ask/mid, strefa czasu, zakres, czyszczenie | Dukascopy, EUR/USD, ticki bid+ask, UTC, 2018-01 → 2024-12; usunięto duplikaty timestampów, opisano 4 dni bez danych i 11 luk dłuższych niż 30 minut |
| 4. Podział | IS / walidacja / OOS, chronologicznie, z datami granic; czy „forward" to holdout czy dane napływające | IS 2018-01 → 2021-12, walidacja 2022-01 → 2023-06, OOS 2023-07 → 2024-12 (nietknięty do końca); forward na danych napływających od 2026-05-04 |
| 5. Model wykonania | moment sygnału, fill, opóźnienie, częściowe wykonania, luki, rozstrzyganie niejednoznacznych świec | sygnał na zamknięciu M15, fill po ask, opóźnienie 300 ms, świeca z SL i TP liczona jako SL, luka otwarcia rozliczana po pierwszej dostępnej cenie |
| 6. Koszty | spread, slippage, prowizja, swap — z modelem każdego i kontrolą, czy któryś nie jest liczony dwa razy | spread z ticków, slippage 0,1 × ATR(14) M5 dwustronnie, prowizja 0,6 pipsa RT, swap z tabeli brokera; spread siedzi w cenach filli i nie jest odejmowany drugi raz |
| 7. Warianty i liczba prób | ile kombinacji parametrów i wersji reguł sprawdzono łącznie, licząc odrzucone | 96 kombinacji parametrów + 4 warianty reguły wyjścia = 100 prób; rejestr w 02_IS/prob_log.csv |
| 8. Metryki | lista policzonych metryk z definicją i mianownikiem | expectancy w R (R0 = ryzyko planowane przed wejściem), profit factor, max DD z bieżącego maksimum equity, liczba transakcji |
| 9. Kryteria oceny ustalone wcześniej | co uznasz za wynik pozytywny, negatywny i nierozstrzygnięty — zapisane przed testem | „kontynuuję, jeśli dolna granica 95% przedziału expectancy na OOS jest powyżej zera; wracam do projektowania, jeśli górna jest poniżej zera; w pozostałych przypadkach wynik nierozstrzygnięty" |
| 10. Wyniki | liczby z przedziałami, nie same punkty | OOS n = 214, E +0,12R, przedział 95% (−0,07R; +0,31R) — obejmuje zero |
| 11. Ograniczenia | czego test nie mierzy i co mogło go skazić | jeden broker, jedna para, brak danych o głębokości arkusza, okres bez kryzysu płynności, 100 prób bez korekty na wielokrotne testowanie |
| 12. Pliki do odtworzenia | ścieżki i hashe wszystkiego, co potrzebne do powtórzenia testu | 01_data/eurusd_2018_2024.csv (sha256), lonbreak_v1_3.mq5, koszty.json, prob_log.csv, notatnik bootstrapu |
Pole 9 znika najczęściej. Kryterium dopisane po zobaczeniu wyniku nie jest kryterium, tylko opisem wyniku — i właśnie dlatego wypełnia się je przed uruchomieniem testu, na piśmie. Drugie w kolejności zanikania jest pole 7: bez liczby prób nie da się ocenić, czy „najlepszy wariant" jest przewagą, czy po prostu najwyższą wartością ze stu losowań (sekcja 2, pułapka 6). Pole 11 jest jedynym, w którym wolno napisać „nie wiem" — i najczęściej to właśnie ono decyduje, czy test wolno komukolwiek pokazać.
2. Pułapki testowania — look-ahead, survivorship, curve fit, overfitting
Te pułapki są metodologiczne, nie poznawcze. Oznacza to, że nie chodzi o to, że tester jest naiwny lub leniwy — chodzi o to, że narzędzia testowe (MT4 Strategy Tester, MT5, własne skrypty) same wpuszczają błędy, jeśli tester nie wie, czego szukać. Pułapki poznawcze (confirmation bias, hindsight) opisujemy w dziale 10; tu skupiamy się na technicznych dziurach metody.
Pułapka 1: Look-ahead bias
Strategia w trakcie świecy używa danych, które stałyby się znane dopiero po jej zamknięciu. Najczęstsze warianty:
- Decyzja w trakcie świecy na podstawie close. Strategia oblicza SMA-20 z 20 ostatnich świec łącznie z bieżącą i wchodzi „gdy świeca M5 zamknie się powyżej". W realu: w sekundzie 240 świecy M5 nie wiesz jeszcze, jak się zamknie. W teście błąd pojawia się wtedy, gdy kod czyta
Close[0]w trakcie świecy, a tester ocenia ten odczyt na świecy już zamkniętej — wynik wygląda jak decyzja podjęta w chwili t, a zapadła z wiedzą z t + 1. [DO WERYFIKACJI PROCEDURA: MT4 → tester → tryb „Open prices only" → co zwracaClose[0]w chwili wywołania] - Indykator z look-back rounding. ZigZag, Fractals, Andrews Pitchfork, niektóre warianty Donchiana — odświeżają się retrospektywnie. Świeca, która 10 dni temu była zaznaczona jako swing high, może dziś nie być nim, gdy zaszły nowe dane. Tester widzi w danych „swing high" w t = -10 i zakłada, że trader też go widział — nie widział, bo wtedy nie był on jeszcze swing highem
- Dane fundamentalne z opóźnieniem publikacji. CPI za marzec publikowany jest dopiero w kwietniu, ale w bazie danych ma datę „marzec" [DO WERYFIKACJI PROCEDURA: kalendarz publikacji twojego dostawcy danych makro → data publikacji odczytu za dany miesiąc]. Strategia, która używa „CPI z marca w decyzjach z 1 kwietnia", używa danych, których wtedy nie było
Detekcja: uruchom strategię na realtime data feed (forward test) i porównaj wygenerowane sygnały z tymi, które backtest wskazałby na tych samych świecach (procedura reconciliation z sekcji 1). Jeśli backtest generuje więcej sygnałów lub generuje je w innych miejscach, masz rozjazd do zdiagnozowania — look-ahead jest tylko jedną z możliwych przyczyn, obok repaintu wskaźnika, innego feedu danych, nieznormalizowanej strefy czasu i nieudanych wejść w realu (requote, odrzucenie zlecenia, brak płynności). Kolejność diagnozy: najpierw czas i feed, potem wykonanie, dopiero na końcu kod strategii — odwrotna kolejność kończy się przepisywaniem działającego indykatora.
Lista konstrukcji wymagających testu antyrepaint w MT4/MT5:
- ZigZag, Fractals, Andrews Pitchfork — z definicji odświeżają się retrospektywnie, wpisane w architekturę narzędzia
- Heikin-Ashi, SuperTrend, Hull MA i customowe kanały nie są z definicji oszustwem — ale każda implementacja z MQL Market albo TradingView musi przejść test antyrepaint przed użyciem w backteście. Problemem nie jest nazwa wskaźnika, tylko to, czy jego sygnał na zamkniętej świecy pozostaje niezmienny po dopłynięciu kolejnych świec
- Custom indicators z MQL Market bez kodu źródłowego — czarna skrzynka, której nie można zwalidować, automatyczne odrzucenie
iCustom()bez kontroli bufora — czytanie wartości z bufora wskaźnika, który mógł zostać przeliczony- Decyzje intrabar na
Close[0]w MT4 — w realuClose[0]w trakcie świecy to bieżąca cena bid, nie cena zamknięcia, której nie ma jeszcze w naturze - Wskaźnik z wyższego interwału użyty na niższym — wartość z H4 wzięta do decyzji na M15 przed zamknięciem świecy H4 jest wartością nieostateczną i zmienia się w trakcie. W Pine
request.security()domyślnie nie zagląda w przyszłość, ale sama niezamknięta świeca wyższego interwału wystarczy, żeby sygnał „migotał"; odwołuj się do wartości z zamkniętej świecy (indeks[1]) i sprawdź to samo w swoim kodzie MQL - Dane makro z datą okresu zamiast datą publikacji — CPI „za marzec" w bazie z datą pierwszego dnia miesiąca odniesienia zamiast faktycznej daty publikacji
Test antyrepaint (do wykonania w MT4): uruchom indykator na żywo, zapisz wartość dla bary t = -10 (np. wartość ZigZag 10 świec wstecz). Poczekaj 5 nowych świec — na M1 to około pięciu minut, na H1 pięć godzin, więc czas testu wyznacza twój interwał, a nie zegarek. Sprawdź wartość bary t = -15 (ta sama świeca, teraz przesunięta o 5). Jeśli wartość się zmieniła, wskaźnik przelicza się wstecz i backtest na nim mierzy co innego niż sygnał dostępny w chwili decyzji. Uwaga w drugą stronę: brak zmiany na jednej świecy niczego nie certyfikuje — wskaźnik może przeliczać się tylko w niektórych układach, więc powtórz test na kilkunastu świecach i w różnych reżimach zmienności, zanim uznasz wskaźnik za czysty. Kosztuje to kilka minut obserwacji i oszczędza miesiące pracy nad strategią opartą na fałszywym sygnale.
Close[0] w trakcie świecy. Repaintujący kod „wiedział" o odwróceniu trendu, zanim to nastąpiło. Sam koncept Heikin-Ashi nie jest patologiczny — patologiczna była ta konkretna implementacja, której nie zwalidowano testem antyrepaint przed backtestem. Test antyrepaint wykryłby tę wadę na kilku świecach obserwacji, przed backtestem; procedura reconciliation zatrzymałaby wdrożenie po pierwszych kilku sygnałach z rozjazdem przekraczającym 50%. Dwanaście setupów to za mało, żeby cokolwiek policzyć — ale nie za mało, żeby zauważyć, że sygnały testu i realu nie są tymi samymi sygnałami.Pułapka 2: Survivorship bias
Testujesz strategię na koszyku par walutowych z 2024 r. — EUR/USD, USD/TRY, GBP/JPY, USD/RUB itp. Backtest pokazuje świetne wyniki na USD/RUB w 2018 r. Problem: USD/RUB jako para handlowalna w retail praktycznie zniknął po 2022 r. Strategia, która „działa" głównie na danych historycznych USD/RUB, ma dziś ograniczoną wartość operacyjną — bo dostępność handlu, płynność i warunki egzekucji po 2022 r. są zupełnie inne.
Drugi wariant: testujesz EA z marketplace'u, który ma 5 gwiazdek i 200 pozytywnych opinii. Survivorship bias: setki EA z 1 gwiazdką, które przegrały konta swoich klientów, zniknęły z marketplace'u. Widzisz tylko tych, którzy przeżyli pierwsze 3 miesiące — ale kupujesz strategię, która ma średnio taką samą szansę przeżycia jak każda inna na starcie.
Detekcja: koszyk instrumentów odtwarzasz na moment decyzji — do testu na oknie 2018–2020 wchodzą pary, które w 2018 r. były u twojego brokera dostępne do handlu, także te, które później zniknęły. Zawężenie historii do listy par aktywnych dziś survivorship nie usuwa — zamienia go na selekcję przyszłą: wybierasz instrumenty na podstawie tego, że dotrwały do dzisiaj, czyli na podstawie informacji, której w chwili decyzji nie było. To ten sam mechanizm co look-ahead, tylko na poziomie uniwersum, a nie pojedynczej świecy. Dzisiejsza wykonalność jest osobnym pytaniem i osobnym zapisem w polu „ograniczenia": ile instrumentów z koszyka historycznego jest dziś jeszcze handlowalnych u twojego brokera i jaka część wyniku pochodziła z tych, których już nie ma. W ocenie EA z marketplace'u sprawdzaj datę publikacji produktu i pamiętaj, że ranking, który widzisz, przeszedł dokładnie przez ten sam filtr przetrwania.
Pułapka 3: Curve fitting (dopasowanie do krzywej)
Testujesz strategię z parametrami SMA-20 vs SMA-22 vs SMA-25 vs SMA-30, RSI(11) vs RSI(14) vs RSI(17), próg ATR od 0,8 do 1,5 z krokiem 0,1. Łącznie 4 × 3 × 8 = 96 kombinacji. Z czystego przypadku jakaś kombinacja wygeneruje świetne wyniki w backteście — to jest matematyka, nie talent strategii.
Klasyczny przykład: trader testuje 96 kombinacji parametrów, wybiera najlepszą (SMA-22, RSI-14, ATR 1,1), backtest pokazuje +180% w 3 lata. Forward test 60 dni: −8%. Co się stało? Strategia była dopasowana do szumu historycznego, nie do edge'u. Każda kombinacja parametrów to 96-elementowa loteria, w której pojedyncza wygrana w backteście nie świadczy o przewadze — świadczy o tym, że losowałeś 96 razy.
Detekcja: wykres heatmapy parametrów. Jeśli optymalne parametry to izolowany szczyt otoczony słabymi wynikami, cały rezultat wisi na jednej komórce i jest to przesłanka curve fittingu. Plateau — wiele kombinacji okolicznych daje podobnie dobre wyniki — mówi natomiast tylko tyle, że wynik nie wisi na jednym ustawieniu. Plateau nie dowodzi dodatniej expectancy. Cała heatmapa liczona jest na tych samych danych, na których stroiłeś, więc gładkie plateau na przeoptymalizowanym zbiorze bywa równie dobrze artefaktem tego zbioru — może też powstać z samej bezwładności parametru, gdy zmiana o jeden krok w ogóle nie zmienia zbioru transakcji. Przewagę rozstrzyga dopiero niezależna walidacja: OOS uruchomiony raz, walk-forward na kolejnych oknach i porównanie z wariantem bazowym (sekcja 3) — każde z liczbą transakcji i przedziałem wokół expectancy, nie z samą średnią.
Pułapka 4: Overfitting (przeuczenie)
Curve fitting to overfitting na poziomie parametrów. Pełen overfitting to dodawanie reguł i filtrów do strategii w odpowiedzi na konkretne stratne trade'y w backteście. „Dodaję filtr: nie wchodzę we wtorki po 14:00 PL" — bo dwa stratne trade'y w backteście były we wtorki po 14:00. Z perspektywy backtestu wynik się poprawia. Z perspektywy realu ten filtr nie ma sensu — to dopasowanie do dwóch instancji szumu.
Nie wolno dodawać filtra tylko dlatego, że trzy stratne transakcje w historii były w piątek. Filtr musi istnieć przed testem i mieć logiczny powód poza tym, że poprawia equity curve. Reguły dodawane ex post w odpowiedzi na konkretne stratne trade'y są overfittingiem na szumie.
Zasada robocza: jeśli optymalizujesz więcej niż 4 niezależne parametry na próbie mniejszej niż 200 trade'ów, overfitting jest bazowym założeniem audytowym — traktujesz strategię jako przeuczoną, dopóki OOS, walk-forward i stabilna heatmapa nie udowodnią inaczej. Krąży przy tym heurystyka „liczba optymalizowanych parametrów × 30 ≤ liczba transakcji w próbie" — cztery parametry to 120 transakcji, osiem to 240. [PRÓG ILUSTRACYJNY — NIE NORMA RYNKOWA] Nie ma ona podstawy w literaturze i nie zastępuje rachunku; traktuj ją najwyżej jako sygnał ostrzegawczy. Właściwym testem jest to, czy przedział wokół expectancy najlepszego wariantu w ogóle odróżnia go od wariantów sąsiednich i od wariantu bazowego (sekcja 3) — jeśli nie odróżnia, „najlepszy" znaczy tylko „najwyższy w tej loterii".
Pułapka 5: Niedomodelowane koszty
MT4 Strategy Tester domyślnie używa fixed spreadu (np. 1,0 pipsa na EUR/USD przez całe 5 lat). Realność: spread na EUR/USD potrafi rosnąć z ułamka pipsa w pełnej płynności LON+NY do kilku pipsów w godzinach rolloveru i kilkunastu w pierwszej minucie po publikacjach makro (rzędy wielkości u typowego brokera detalicznego — własną historię spreadu sprawdź w danych swojego rachunku, bo różnice między brokerami są duże). Strategia, która działa intraday w godzinach 21:00–06:00 (rollover, niska płynność), w fixed spread teście pokazuje zysk; w realnym środowisku z variable spreadem traci.
Drugi wymiar: slippage. Backtest zakłada egzekucję dokładnie po cenie z bazy danych. Real: slippage 0,2–0,5 pipsa w normalnych warunkach, 1–3 pipsy na breakoutach, 5–15 pipsów po publikacjach. Strategia z expectancy +0,3R brutto może mieć w realu +0,1R netto — i nie wiesz tego z backtestu, jeśli nie modelowałeś slippage'u.
Trzeci: swap (cost of carry). Strategia swing trzymająca pozycje 3–8 dni płaci swap codziennie. Long EUR/USD ma zwykle ujemny swap (płacisz różnicę stóp). Przykład rachunku [PRÓG ILUSTRACYJNY — NIE NORMA RYNKOWA]: swap 3 pipsy za noc przy stopie oddalonym o 20 pipsów to 0,15R za noc; strategia z expectancy +0,4R, trzymająca pozycję pięć nocy, oddaje 5 × 0,15R = 0,75R — więcej niż jej brutto edge. Przelicz to u siebie, bo wynik zależy głównie od odległości stopa: koszt w R za noc = swap w pipsach ÷ odległość SL w pipsach. Ten sam swap przy SL 60 pipsów to już 0,05R za noc.
Czwarty: prowizja. Konta ECN (zwykle wymagane dla strategii skalpujących) mają komisję 5–7 USD per lot per RT. Przy 0,1 lota i 200 trade'ach miesięcznie: 200 × 0,1 × 6 = 120 USD komisji miesięcznie, czyli 12% od kapitału 1000 USD. Backtest bez modelowania prowizji jest bezwartościowy dla skalperów.
Pułapka 6: Data snooping (przeszukiwanie danych)
Bardziej subtelna wersja curve fittingu. Tester przegląda 30 strategii, odrzuca 28, które nie działają, publikuje 2, które działają w backteście. Z czystego przypadku przy 30 testach jakieś 2–3 strategie wyjdą dobrze. Tester nie kłamie — jego backtest tych 2 strategii jest poprawny. Ale prawdopodobieństwo, że któraś działa w realu, jest niemal zerowe — bo prawdopodobnie wybrał statystyczne anomalie z 30 prób.
Akademicka korekta: Bonferroni[2] — przy 30 testach próg p-value powinien wynosić 0,05/30 = 0,00167 zamiast 0,05. Korekta jest konserwatywna i istnieją metody mniej brutalne (kontrola odsetka fałszywych odkryć, deflated Sharpe ratio[3]), ale wszystkie wymagają jednego: żebyś znał liczbę prób. Detal o tym nie myśli, bo nie liczy, ile strategii odrzucił przed tą jedną — dlatego pole 7 karty testu jest w niej polem obowiązkowym.
Detekcja: prowadź dziennik wszystkich testowanych strategii z wynikami. Jeśli z 30 testowanych 2 wyszły dobrze, traktuj te 2 z większym sceptycyzmem niż gdyby były 1. lub 2. testem.
Przykład błędu do przerobienia: stop i target w tej samej świecy
To najczęstsza pojedyncza przyczyna zawyżonego backtestu i najłatwiejsza do przeoczenia, bo nie wygląda na błąd — wygląda na wynik.
Zapis błędny. Świeca H1: open 1,0850, high 1,0885, low 1,0815, close 1,0870. Pozycja long otwarta na 1,0850, SL 1,0820 (30 pipsów), TP 1,0880 (30 pipsów, 1R). Świeca dotknęła obu poziomów: low 1,0815 leży poniżej SL, high 1,0885 powyżej TP. Tester bez zdefiniowanej reguły rozstrzygania stosuje domyślną kolejność „najpierw sprawdź TP" i zapisuje +1R. Na dwustu transakcjach takich świec bywa kilkanaście — i to one robią różnicę między wynikiem dodatnim a ujemnym.
Poprawiony model wykonania. Z danych OHLC nie da się odtworzyć kolejności zdarzeń wewnątrz świecy. Nie ma tu rozwiązania „prawdziwego", jest tylko rozwiązanie jawne:
- zasada domyślna: świeca, która dotknęła obu poziomów, liczy się jako trafienie stopa. To założenie pesymistyczne, a nie „realistyczne" — i tak trzeba je nazwać w polu 5 karty testu;
- zejdź na niższy interwał (M1) albo na ticki, ale tylko dla tych świec, i sprawdź faktyczną kolejność. To jedyne rozstrzygnięcie, które nie jest założeniem;
- policz wynik w obu skrajnych wariantach (wszystkie takie świece jako SL / wszystkie jako TP) i podaj obie liczby jako widełki. Jeśli widełki obejmują zero, test nie rozstrzyga i nie wolno raportować górnego końca jako wyniku;
- zapisz liczbę takich świec w polu „ograniczenia". Sam ich odsetek jest diagnozą: strategia, w której SL i TP leżą bliżej siebie niż typowy zasięg świecy interwału decyzyjnego, jest na danych OHLC po prostu niemierzalna.
Ograniczenie danych. [PRZYKŁAD ILUSTRACYJNY — NIE WYNIK HISTORYCZNY] Wynik syntetyczny, żeby pokazać skalę: test na 200 transakcjach, w którym 14 świec zawiera oba poziomy. Wariant „zawsze TP" daje E +0,18R. Wariant „zawsze SL" daje E +0,04R (14 transakcji zmienia się o 2R każda, czyli 28R na 200 = 0,14R różnicy w expectancy). Sprawdzenie tych 14 świec na tickach: 9 razy pierwszy był stop, 5 razy target — E +0,09R. Różnica między wariantem najbardziej optymistycznym a rozstrzygnięciem tickowym to 0,09R na transakcję, czyli więcej niż cały modelowany koszt wykonania w typowej strategii intraday. Dane H1 i dzienne bez zejścia na niższy interwał tego nie rozstrzygają — i to zdanie ma stać w raporcie zamiast wariantu, który lepiej wygląda.
3. Walk-forward analysis — jak walidować z małą próbką
Walk-forward analysis (WFA) to szeroko opisana metoda walidacji — jej systematyczny wykład dał Robert Pardo w The Evaluation and Optimization of Trading Strategies[1]. Idea: zamiast optymalizować parametry na całych danych historycznych, dzielimy je na okno in-sample (IS) i out-of-sample (OOS), optymalizujemy na IS, walidujemy na OOS, a następnie przesuwamy okno do przodu i powtarzamy.
Podział chronologiczny: IS, walidacja, OOS
Najprostsza wersja:
- Dane łączne: 5 lat (2020-01-01 do 2024-12-31)
- In-sample: 70% = 3,5 roku (2020-01-01 do 2023-06-30) — kalibrujesz parametry tutaj
- Out-of-sample: 30% = 1,5 roku (2023-07-01 do 2024-12-31) — testujesz raz na tych danych z parametrami z IS
Podział 70/30 jest założeniem scenariusza, nie normą — proporcja zależy od tego, ile transakcji generuje strategia i ile różnych reżimów chcesz mieć po obu stronach granicy. Ważniejsze od proporcji są dwie rzeczy. Po pierwsze, podział musi być chronologiczny: OOS zawsze po IS, nigdy losowo wymieszany, bo przemieszanie dat wpuszcza informację z przyszłości tylnymi drzwiami. Po drugie, ról jest trzy, nie dwie:
- In-sample — tu wolno szukać, optymalizować i odrzucać warianty. To jest miejsce na strojenie i nikt tego nie ukrywa.
- Walidacja — osobne okno, na którym wybierasz jeden wariant spośród kilku, które przeszły IS. Ten wybór też jest strojeniem, więc walidacja przestaje być niezależna w chwili pierwszego użycia.
- Out-of-sample — uruchamiany raz, po zamrożeniu wszystkiego. OOS użyty do wyboru filtra przestaje być OOS i trzeba go tak nazwać w karcie testu, w polu „ograniczenia".
Bez środkowego okna wybór wariantu odbywa się na OOS i cała niezależność znika przy pierwszym „sprawdźmy jeszcze ten jeden filtr".
Reguła żelazna: parametrów nie wolno dotykać po teście OOS. Jeśli OOS daje słabe wyniki i wracasz do IS żeby „doszlifować", po czym retestujesz OOS — właśnie zmieniłeś OOS w drugi IS, czyli zoptymalizowałeś na całym zbiorze danych. Pełen overfitting.
Walk-forward kroczący — wersja zaawansowana
Pojedynczy podział 70/30 ma wadę — jeden konkretny okres OOS może być niereprezentatywny (akurat trafił w wyjątkowo trudny lub łatwy reżim). Walk-forward kroczący naprawia to przesuwając okno:
| Krok | In-sample (kalibracja) | Out-of-sample (test) |
|---|---|---|
| 1 | 2020-01 do 2022-12 (3 lata) | 2023-01 do 2023-06 (6 miesięcy) |
| 2 | 2020-07 do 2023-06 (3 lata) | 2023-07 do 2023-12 (6 miesięcy) |
| 3 | 2021-01 do 2023-12 (3 lata) | 2024-01 do 2024-06 (6 miesięcy) |
| 4 | 2021-07 do 2024-06 (3 lata) | 2024-07 do 2024-12 (6 miesięcy) |
Każdy krok ma własne IS i OOS. Sumarycznie testujesz strategię na 4 oknach OOS rozłącznych w czasie, pokrywających 2 lata. Rozłączność dat to jednak nie to samo co niezależność statystyczna: okna sąsiadują ze sobą, kolejne IS-y w dużej części się pokrywają, a jeden długi reżim rynkowy potrafi objąć dwa okna naraz. Odczyt: jeśli strategia daje dodatni wynik w 3–4 z 4 okien, masz kandydata na przewagę odporną na zmianę próbki (robust edge) — pod warunkiem, że przy każdym oknie podajesz liczbę transakcji i przedział wokół expectancy po kosztach, a nie samą średnią. Sam licznik dodatnich okien nie jest wynikiem testu: przy czterech oknach i strategii bez żadnej przewagi rezultat „co najmniej trzy dodatnie" pojawia się w około 31% przypadków (rzut monetą, okna niezależne), a zależność między oknami ten odsetek jeszcze podnosi. Jeśli działa w 1–2, strategia jest co najwyżej reżimowo wrażliwa. Jeśli działa w 0–1, wynik nie odróżnia się od szumu i nie ma czego wdrażać.
Walk-forward dla swing tradera z małą próbką
Swing trader z 5–10 trade'ami miesięcznie ma w 5 latach 300–600 trade'ów. Przy podziale 70/30 OOS ma 90–180 trade'ów — przy WR rzędu 60% i próbach niezależnych przedział wokół WR ma wtedy półszerokość mniej więcej 7–11 pp (Clopper–Pearson, 95%), czyli wystarcza do wypowiedzi o kierunku, nie o wielkości przewagi. Day trader z 50–100 trade'ami miesięcznie ma 3000–6000 trade'ów w 5 lat — przy takiej próbie przedziały są wąskie i wąskim gardłem przestaje być liczba transakcji, a staje się model kosztów.
Position trader z 1–2 trade'ami miesięcznie ma 60–120 trade'ów w 5 lat. Przy 70/30 OOS ma 18–36 trade'ów — przedział wokół expectancy jest wtedy tak szeroki, że obejmuje i wyraźną przewagę, i wyraźną stratę, więc test nie rozstrzyga w żadną stronę. Rozwiązania:
- Dłuższy zakres danych (10–15 lat zamiast 5) — daje 120–360 trade'ów łącznie, OOS 36–108
- Multi-asset — testowanie na 6–10 par walutowych jednocześnie zwielokrotnia próbę
- Block bootstrap (Monte Carlo na blokach trade'ów) — pokazuje rozrzut wyniku przy innej kolejności tych samych transakcji, z zachowaniem korelacji czasowych. Nie dodaje ani jednej nowej obserwacji i nie zwęża przedziału wokół expectancy — patrz sekcja 4
Wariant bazowy — z czym w ogóle porównujesz wynik
Wynik strategii bez punktu odniesienia nie mówi nic. Zanim ocenisz „+0,25R na transakcję", policz to samo dla wariantu bazowego na tych samych danych, z tym samym modelem wykonania i tymi samymi kosztami:
- Sam trigger bez filtrów. Jeśli komplet czterech filtrów daje ten sam wynik co goły sygnał wejścia, filtry są dekoracją — i czterema dodatkowymi stopniami swobody, za które płacisz w pułapce 3 i 4.
- Wejście losowe o tej samej częstości, kierunku i tym samym SL/TP. Kilkaset losowań daje rozkład, a nie jedną liczbę; jeśli wynik strategii mieści się w środku tego rozkładu, „przewaga" jest wariancją. Losowanie z ustalonym ziarnem, żeby dało się je powtórzyć.
- Trzymanie kierunku przez cały okres. Dla strategii swing na jednej parze bywa brutalnie skuteczne i pokazuje, ile z wyniku pochodzi z samego dryfu kursu, a nie z reguł.
- Ta sama strategia z odwróconym sygnałem. Jeśli odwrócenie też wychodzi na plus, wynikiem rządzi coś innego niż kierunek — najczęściej asymetria SL/TP albo błąd w modelu kosztów.
Do karty testu wpisujesz wynik strategii i wariantu bazowego, w polu 10. Analiza wrażliwości jest tym samym pytaniem w mikroskali: co dzieje się z wynikiem, gdy przesuniesz każdy parametr o jeden krok w obie strony. Wynik, który znika przy przesunięciu progu ATR z 1,1 na 1,0, nie jest przewagą — jest jedną komórką heatmapy.
Zamrożenie OOS — folder structure i hash konfiguracji
Najczęstsze samosabotowanie WFA: trader testuje OOS, widzi słaby wynik, „dostosowuje" parametry na IS i retestuje OOS. To nie jest walk-forward — to optymalizacja na całym zbiorze danych. Praktyka, która eliminuje ten błąd na poziomie procesu:
- Folder projektu ma trzy katalogi:
01_raw_data,02_IS_optimization,03_OOS_locked - Po pierwszym uruchomieniu OOS zapisujesz hash konfiguracji strategii (parametry, kod, model kosztów, zakres dat) w pliku
03_OOS_locked/run_001.lock - Każda kolejna zmiana parametrów wymaga nowego pliku
run_002.locki oznacza poprzedni test jakotainted(skażony) - Liczba czystych uruchomień na tym samym oknie OOS = 1. Kolejne uruchomienie po zmianie parametrów oznacza, że to okno przestaje być dziewiczym OOS — staje się drugim IS. Walk-forward windows planujesz z góry, każde traktujesz jako osobne OOS
Co zrobić, gdy OOS wypada słabo
Po słabym OOS nie wolno dopisywać filtra, bo boli wynik. To najprostszy sposób, żeby zamienić walidację w dekorowanie trupa. Sekwencja decyzyjna:
- Zaakceptuj wynik — strategia w obecnej formie nie ma walidacji
- Wróć do koncepcji — przejrzyj sekcje 1–3 artykułu 15.3 (Budowanie strategii): hipotezę, cykl budowy strategii i edge. Sprawdź, czy hipoteza nadal jest sensowna w obecnym reżimie
- Jeśli koncepcja stoi — może to być reżimowa wrażliwość. Testuj walk-forward kroczący na 4–6 oknach. Jeśli strategia działa w 2 z 6 okien w trendzie i nie działa w 4 oknach konsolidacji — masz strategię trend-following, której nie ma w obecnym reżimie. Trzymasz ją w playbooku, włączasz, gdy wraca trend. Warunek dodatkowy: przy każdym z „działających" okien podaj liczbę transakcji i przedział wokół expectancy po kosztach, nie samą średnią. Trzy z czterech okien po osiem transakcji dają przedziały tak szerokie, że mieszczą i wyraźną przewagę, i wyraźną stratę — to nie jest dowód, to wynik nierozstrzygnięty
- Jeśli koncepcja upada — strategia ginie, idziesz do następnego pomysłu
4. Monte Carlo na backteście — dlaczego jeden backtest to za mało
Backtest pokazuje jedną realizację historii. Strategia z 100 trade'ami w backteście miała 100 konkretnych okazji wejścia w 5 lat — gdyby historia toczyła się minimalnie inaczej, miałaby 95 lub 110, w innych miejscach, z innymi wynikami. Pojedynczy backtest jest jak pojedynczy rzut kostką — mówi ci coś, ale nie wszystko o rozkładzie wyników.
Monte Carlo na backteście symuluje, jak strategia mogłaby zachować się w alternatywnych historiach. Daje rozkład zamiast pojedynczej wartości — i ten rozkład pokazuje, jak duże jest realne ryzyko, którego pojedynczy backtest nie pokazuje.
Dwie podstawowe metody
Bootstrap trade'ów (sequence randomization): bierzesz listę 200 wyników trade'ów (np. +1,5R, −1R, +2,2R, −1R, +0,8R, ...) i losujesz z powtórzeniami 200 trade'ów do nowej historii. Powtarzasz 1000 razy. Dostajesz 1000 alternatywnych equity curve.
Block bootstrap: ten sam pomysł, ale losujesz bloki kolejnych trade'ów (np. po 10 trade'ów na raz). Zachowuje korelacje czasowe (volatility clustering — strata zwykle ciągnie za sobą stratę). Dla strategii FX block bootstrap jest realniejszy niż naiwny bootstrap pojedynczych transakcji, ale długość bloku jest parametrem, nie stałą — sprawdź wynik dla 5, 10 i 20.
Co liczysz z 1000 alternatywnych historii
- Mediana zwrotu rocznego — środek rozkładu, lepsze niż wartość z pojedynczego backtestu
- Percentyl 5% — w 5% scenariuszy zwrot będzie tak słaby lub gorszy. To twój worst-realistic-case
- Maksymalny drawdown w percentylu 95% — w 5% scenariuszy DD będzie tak duży lub większy. Czy psychologicznie i kapitałowo wytrzymasz?
- Probability of ruin — w ilu % scenariuszy konto spadło poniżej progu (np. −30%)
Praktyczny przykład [PRZYKŁAD ILUSTRACYJNY — NIE WYNIK HISTORYCZNY]: backtest pokazuje +45% rocznie, max DD −12%. Monte Carlo bootstrap na danych syntetycznych (1000 symulacji): mediana +38%, 5. percentyl +8%, 95. percentyl max DD −22%, odsetek scenariuszy z obsunięciem głębszym niż 30% = 4%. Interpretacja: rozkład jest dodatni, ale w 1 na 25 scenariuszy obsunięcie przekracza 30% — czy wytrzymasz to emocjonalnie i kapitałowo? Jedno zastrzeżenie do wszystkich takich liczb: drawdown wyrażony w procentach kapitału już zakłada konkretny sizing, więc nie jest właściwością samej strategii[4].
Metryki wyniku — definicje bierzesz z jednego miejsca
Zanim wejdziesz w kod, ustal definicje: expectancy w R, profit factor, max DD i czas jego trwania, recovery factor, SQN. Wzory, mianowniki i tabele progów stoją w artykule 15.9 (Dziennik transakcji i metryki) — tutaj potrzebne są tylko trzy uwagi, bo każda z nich zmienia wynik testu:
- Max DD liczysz z bieżącego maksimum equity, nie z globalnego. Poprawnie:
H_t = max(equity do chwili t),D_t = (H_t − E_t) / H_t,maxDD = max(D_t). Różnica nie jest kosmetyczna: dla przebiegu 100 → 80 → 120 → 110 wzór z globalnym minimum i globalnym maksimum daje 33,3%, a rzeczywiste największe obsunięcie to 20,0% (spadek ze 100 na 80). Kod niżej liczy to poprawnie, przeznp.maximum.accumulate— i tekst ma się zgadzać z kodem, nie odwrotnie. - Podaj, na czym i jak często mierzysz. Equity (z otwartymi pozycjami) czy balance (tylko zamknięte)? Próbkowanie tickowe, po zamknięciu transakcji czy dzienne? „Max DD 12%" bez tych dwóch informacji nie jest porównywalne z żadną inną liczbą — ani z twoim limitem z planu.
- SQN = √N × mean(R) / std(R) rośnie z pierwiastkiem z liczby transakcji, więc porównuj go wyłącznie przy tym samym N; definicja, sufit próby i skala interpretacyjna — w 15.9.
Skrypt Pythona — block bootstrap dla strategii Forex
Jak odpalić bez środowiska programistycznego: wejdź na colab.research.google.com (darmowe, wymaga konta Google), kliknij „New Notebook", wklej poniższy kod do jednej komórki i uruchom ją. W tej postaci kod liczy na wpisanej w niego próbce syntetycznej — po to, żeby dało się go odpalić bez żadnych własnych danych i zobaczyć format wyniku. Żeby policzyć na własnych transakcjach, odkomentuj linię z pd.read_csv i wskaż plik CSV z jedną kolumną liczb w R per trade (nagłówek R). Notebook zapisuje się na Google Drive, można wracać do niego z dowolnego komputera.
import numpy as np
import pandas as pd
def block_bootstrap_strategy(trades_R, n_simulations=1000, block_size=10,
risk_per_trade=0.01, seed=42):
"""
Block bootstrap na liście wyników transakcji wyrażonych w R.
trades_R: np.array, np. [-1.0, 3.1, -1.0, 7.2, ...] — wyniki w R
n_simulations: liczba alternatywnych historii
block_size: dlugosc bloku zachowujaca volatility clustering
(parametr do sprawdzenia: 5 / 10 / 20)
risk_per_trade: zalozenie scenariusza o sizingu — WSZYSTKIE wyniki
procentowe i drawdowny sa jego funkcja
seed: ziarno generatora; bez niego wyniku nie da sie powtorzyc
Zwraca: dict z metrykami. Uwaga: 'median_return' to zwrot z len(trades_R)
transakcji, a NIE zwrot roczny — okres zalezy od czestosci sygnalow.
"""
rng = np.random.default_rng(seed)
n_trades = len(trades_R)
block_size = min(block_size, n_trades) # ochrona przed block_size > liczba trade'ow
n_blocks = int(np.ceil(n_trades / block_size)) # zaokraglamy w gore zamiast obcinac konca
final_returns = []
max_drawdowns = []
ruin_count = 0
for sim in range(n_simulations):
# losowanie bloków startowych z powtorzeniami
block_starts = rng.integers(0, n_trades - block_size + 1, n_blocks)
# przycinamy do dlugosci oryginalu, zeby zachowac N=n_trades w symulacji
sim_trades = np.concatenate([trades_R[s:s + block_size] for s in block_starts])[:n_trades]
# konstrukcja equity curve (multiplicative compounding)
equity = 1.0
equity_curve = [1.0]
for r in sim_trades:
equity *= (1.0 + r * risk_per_trade)
equity_curve.append(equity)
equity_curve = np.array(equity_curve)
peak = np.maximum.accumulate(equity_curve)
drawdown = (equity_curve - peak) / peak
final_returns.append(equity - 1.0)
max_drawdowns.append(drawdown.min()) # ujemna wartosc
if drawdown.min() < -0.30:
ruin_count += 1
return {
# zwrot z n_trades transakcji przy przyjetym risk_per_trade, nie roczny
'median_return': np.median(final_returns),
'p05_return': np.percentile(final_returns, 5),
'p95_return': np.percentile(final_returns, 95),
'p95_max_dd': np.percentile(max_drawdowns, 5), # 5. percentyl od dolu
'ruin_probability': ruin_count / n_simulations,
'mean_return': np.mean(final_returns),
}
# wlasne dane: CSV z jedna kolumna liczb w R (naglowek 'R'), po jednej na transakcje
# trades = pd.read_csv('moje_wyniki.csv')['R'].to_numpy(dtype=float)
# przykladowe uzycie — probka SYNTETYCZNA, nie wynik zadnej strategii
# 20 transakcji: 6 wygranych (WR 30%), suma +2,0R, E +0,10R, std 2,04
# cala expectancy tej probki wisi na jednej transakcji +7,2R — i o to chodzi
trades = np.array([-1.0, -1.0, 3.1, -1.0, -1.0, -1.0, 0.9, -1.0, 7.2, -1.0,
-1.0, -0.6, 1.4, -1.0, -1.0, -1.0, 2.3, -1.0, -1.0, 0.7])
trades = np.tile(trades, 10) # 200 transakcji
for risk in (0.01, 0.02):
r = block_bootstrap_strategy(trades, n_simulations=2000,
block_size=10, risk_per_trade=risk, seed=42)
print(f"--- sizing {risk*100:.0f}% na transakcje ---")
print(f"Mediana zwrotu z 200 transakcji: {r['median_return']*100:.1f}%")
print(f"5. percentyl zwrotu: {r['p05_return']*100:.1f}%")
print(f"95. percentyl max DD: {r['p95_max_dd']*100:.1f}%")
print(f"Odsetek scenariuszy z DD > 30%: {r['ruin_probability']*100:.2f}%")
Wynik pokazuje prostą rzecz: czy strategia ma zapas na gorszą kolejność transakcji, czy przewraca się, gdy pierwsze kilkadziesiąt ułoży się gorzej niż w backteście. Na próbce z przykładu (ziarno 42, sizing 1%) mediana zwrotu z 200 transakcji wychodzi rzędu +20%, 5. percentyl lekko ujemny, a 95. percentyl obsunięcia w okolicach −17% — mimo dodatniej expectancy, bo cała ta expectancy wisi na jednej transakcji +7,2R i historie, w których blok z nią nie wypadł, kończą się pod kreską. Ta sama próbka przy risk_per_trade = 0.02 daje 95. percentyl obsunięcia głębszy niż −30% i kilkanaście procent scenariuszy przekraczających próg ruiny. Dokładne liczby zależą od wersji generatora losowego, ale kierunek nie: drawdown w procentach jest funkcją sizingu, nie samej strategii.
Progi wpisujesz do karty testu (pole 9) przed uruchomieniem symulacji [PRÓG ILUSTRACYJNY — NIE NORMA RYNKOWA]: mediana zwrotu i 5. percentyl oba dodatnie, |max DD| w 95. percentylu poniżej limitu obsunięcia z twojego planu, odsetek scenariuszy z obsunięciem głębszym niż 30% poniżej 1%. Wynik odwrotny — 5. percentyl ujemny, |max DD| powyżej 30% w 5% scenariuszy — jest odpowiedzią „nie w tej skali", a nie zaproszeniem do przesunięcia progu po fakcie.
Ograniczenie metody, o którym łatwo zapomnieć: przetasowanie istniejących wyników nie stworzy straty większej niż najgorsza w próbce. Monte Carlo na bootstrapie mierzy wrażliwość na kolejność i na wariancję próbkowania — nie mierzy ryzyka zdarzenia, którego w danych nie było.
Ten sam procent, inna kwota
Symulacja mówi w procentach, a decyzję podejmujesz w złotówkach: 15% obsunięcia na rachunku 5 000 PLN to 750 PLN, na 50 000 PLN — 7 500 PLN, i są to dwie różne decyzje operacyjne przy identycznym wyniku symulacji. Akceptowalny drawdown i wielkość pozycji dla danej klasy kapitału to jednak temat skalowania: tabela liczb stoi w artykule 15.11, a limity dzienne, tygodniowe i miesięczne w planie (15.2). Dla samego testu wystarczy jedna konsekwencja: percentyl obsunięcia z symulacji porównujesz z limitem zapisanym w planie przed testem, a nie z tym, co jesteś skłonny zaakceptować po zobaczeniu wyniku.
Dlaczego block bootstrap, nie naiwny
Volatility clustering to zgrupowanie zmienności, nie znaków wyników: z tego, że po dużym ruchu przychodzi kolejny duży ruch, nie wynika jeszcze, że po stratnej transakcji rośnie prawdopodobieństwo kolejnej straty. Zależność znaków wyników jest hipotezą o twojej strategii — sprawdzasz ją na własnych danych, a nie zakładasz jako właściwość rynku. Jeśli jednak twoje wyniki są seryjne (jeden reżim, skorelowane pary, wspólne zdarzenie makro), naiwny bootstrap (losowanie pojedynczych trade'ów) zakłada niezależność i przez to zaniża seryjność strat oraz max DD. Block bootstrap zachowuje seryjność i daje realniejszy rozkład max DD. Długość bloku to parametr do sprawdzenia, nie liczba do przepisania: policz wynik dla 5, 10 i 20 transakcji w bloku. Jeśli 95. percentyl obsunięcia wyraźnie rośnie razem z długością bloku, zależność serii w twoich danych jest istotna i naiwny bootstrap zaniża ryzyko; jeśli wynik prawie się nie zmienia, założenie niezależności jest w twoim przypadku nieszkodliwe.
5. Forward testing — demo, paper trade, mikrokonto
Forward test ma trzy etapy o rosnącej realności i rosnącym koszcie błędu. Skrócenie walidacji nie usuwa ryzyka — przenosi je na konto live. Różnica jest taka, że błąd w demo kosztuje wieczór, a błąd na live kosztuje kapitał.
Dwa różne „forwardy": holdout w testerze i dane napływające
Słowo „forward" oznacza w praktyce dwie różne rzeczy, a mylenie ich jest jednym z częstszych błędów w raporcie z testu:
- Forward historyczny (holdout w testerze). Tester sam odcina końcówkę zakresu, optymalizuje na części wcześniejszej i sprawdza parametry na odciętej. MT5 ma to natywnie — w ustawieniach testera pole Forward z podziałem 1/2, 1/3, 1/4 zakresu albo datą własną[6]. To wciąż są dane historyczne: mierzą odporność parametrów na inne okno, a nie warunki wykonania. Nazwanie tego w raporcie „forward testem" sugeruje coś, czego nie zrobiono.
- Forward na danych napływających. Strategia działa na świecach, których w chwili zamrożenia wersji jeszcze nie było. Tylko ten wariant mierzy realny spread, poślizg, requote'y, opóźnienia i twój własny błąd wykonania. Z definicji nie ma tu look-ahead — danych z przyszłości fizycznie nie ma.
W karcie testu (pole 4) zapisujesz, który to był, razem z datą zamrożenia wersji. Bez tej daty nie da się później odróżnić „strategia zadziałała na nowych danych" od „strategia zadziałała na danych, które już wtedy leżały na dysku".
Etap 1: demo na danych napływających
Konto demo brokera, ten sam strumień danych co konto live, identyczne warunki egzekucji w teorii. Zalety:
- Brak ryzyka kapitałowego — błędy wykonania i błędy strategii nie kosztują pieniędzy
- Pełna iteracja — możesz po 10 trade'ach wrócić do strategii i poprawić ją bez utraty kapitału
- Test integracji narzędzi — czy alerty działają, czy EA się uruchamia, czy reguły są poprawnie zakodowane
Wady:
- Slippage demo zwykle lepszy niż real — broker chce, żebyś założył live, więc demo egzekuje korzystniej
- Brak ryzyka uderzenia w margin — demo nie wyzwala instynktu przetrwania, który w realu powoduje hesytację przy wejściu i ręczne manipulowanie Stop Lossem
- Brak ryzyka requote — w realnym trybie ECN albo STP requote zdarza się przy publikacjach
30 dni demo ma odpowiedzieć na brutalne pytania: czy alert odpala się wtedy, kiedy trzeba, czy EA nie gubi sygnałów, czy broker pokazuje inny spread niż w testerze, czy trader nie poprawia reguł ręcznie. Długości używane w tym artykule — 30 dni i 30 transakcji — to [PRÓG ILUSTRACYJNY — NIE NORMA RYNKOWA] założenie scenariusza dobrane pod strategię generującą kilka sygnałów tygodniowo; przy jednym sygnale na dwa tygodnie ten sam cel wymaga kilku miesięcy. To nie jest próba statystyczna, tylko sanity check infrastruktury — i tak trzeba go opisać w karcie testu, żeby nikt (łącznie z tobą za pół roku) nie wziął go za walidację.
Zapis wyników forwardu. Eksport z platformy do dziennika ustaw od pierwszego dnia — ręczne przepisywanie transakcji po miesiącu kończy się brakami, a forward bez kompletnego zapisu nie da się uzgodnić z backtestem i cały etap idzie na marne. Wybór narzędzia, komplet kolumn dziennika i procedura uzgodnienia z raportem brokera należą do artykułu 15.9. Dla forward testu istotne jest jedno: zapis musi obejmować godzinę sygnału, godzinę i cenę fillu, poślizg oraz koszt rzeczywisty per transakcja — czyli dokładnie te pola, których backtest nie zna, a R-multiple liczony bez nich nie da się porównać z R z testu.
Etap 2: Paper trade na realtime data feed (opcjonalny, 30–60 dni)
Wariant pomiędzy demo a mikrokontem: zapisujesz każdy sygnał, kalkulujesz hipotetyczny wynik z realistic spreads/slippage, ale nie otwierasz pozycji w MT. Zalety: brak konkurencji platformy demo (która dziwnie egzekuje przy wysokim wolumenie), pełna kontrola nad modelem kosztów. Wady: brak realnego sygnału egzekucyjnego, więc nie wiesz, czy w praktyce kliknąłbyś.
Etap 3: mikrokonto live
Konto live z minimalną wielkością pozycji (0,01–0,05 lota, kapitał rzędu 1 000–2 000 PLN). Cel: sprawdzić strategię w warunkach realnego ryzyka, nie testować dochodu.
Co mierzy mikrokonto, czego nie mierzy demo:
- Realne warunki egzekucji — twój broker w trybie live może mieć szerszy spread, większy slippage, requote'y, opóźnienia mostka. Demo tego nie pokaże
- Twój poziom operacyjnego compliance — mikrokonto bezwzględnie weryfikuje współczynnik błędu ludzkiego: ręczne zamknięcia w trakcie drawdownu, „przesunięcie SL o 5 pipsów", ignorowanie sygnału przeciw aktualnej tezie. Mierzysz to jako error rate w dzienniku — odsetek sygnałów wykonanych niezgodnie z regułą
- Swap rzeczywisty — niektóre brokery mają inne tabele swapów dla demo i live
- Działanie integracji — czy twój EA, alerty, automatyzacje działają na live tak samo jak na demo
Długość etapu użyta w tym artykule — 90 dni i 60–100 transakcji — jest [PRÓG ILUSTRACYJNY — NIE NORMA RYNKOWA] założeniem scenariusza, nie normą rynkową. Wynik pozytywny: przedziały wokół expectancy z backtestu i z tego etapu zachodzą na siebie, czyli różnica między nimi obejmuje zero. To jest inne pytanie niż „czy nowa średnia wpadła w stary przedział": przedział ufności opisuje niepewność tej jednej, historycznej średniej, a nie zakres, w którym ma wylądować średnia z nowej, krótszej próby — ta ma własną, znacznie większą niepewność i porównujesz dwie próby z niepewnością obu. Do tego: brak nieoczekiwanych zachowań egzekucyjnych, obsunięcie nieprzekraczające percentyla z symulacji, a liczba wykonań niezgodnych z regułą policzona i mała. Wszystkie cztery warunki zapisujesz przed startem etapu, nie po jego zakończeniu.
Sekwencja przejść — kryteria
Wszystkie długości etapów i liczby transakcji w tabeli są [PRÓG ILUSTRACYJNY — NIE NORMA RYNKOWA] założeniem scenariusza z tego artykułu; progi decyzji bierzesz z karty testu (pole 9), nie z tej tabeli.
| Z etapu | Do etapu | Kryteria przejścia |
|---|---|---|
| Backtest | Demo | WFA OOS pozytywne, Monte Carlo: 5. percentyl > 0, odsetek scenariuszy z ruiną poniżej progu zapisanego w karcie testu (pole 9), model kosztów realistyczny |
| Demo | Mikrokonto | 30+ dni, 30+ trade'ów, przedziały wokół expectancy z demo i z backtestu zachodzą na siebie (a nie: „średnia mieści się w ±0,15R"), brak nieoczekiwanych dziur |
| Mikrokonto | Skala z planu (15.2) | 90+ dni, 60+ transakcji, przedziały wokół expectancy z mikrokonta i z backtestu zachodzą na siebie, obsunięcie nieprzekraczające percentyla z symulacji, liczba wykonań niezgodnych z regułą policzona i mała |
W tabeli brakuje wiersza, który w praktyce jest najczęstszy: „nie wdrażam". Niespełnione kryterium przejścia nie jest zaproszeniem do obniżenia kryterium — jest wynikiem testu i tak trafia do karty. Czas łączny od backtestu do pełnej skali przy założeniach z tego artykułu: 4–8 tygodni backtestu + 30 dni demo + 90 dni mikrokonta, czyli 148–176 dni, w zaokrągleniu 5–6 miesięcy. Próby skrócenia tej sekwencji w praktyce kończą się stratą pierwszego istotnego drawdownu na live, zanim trader zrozumie, gdzie był błąd — bo eliminacja etapów walidacji to nie oszczędność czasu, tylko transfer ryzyka z demo na konto z prawdziwymi pieniędzmi.
Wykonalność operacyjna — warunek, którego backtest nie sprawdza
Strategia generująca sygnały o 14:30 czasu polskiego dla kogoś, kto do 17:00 siedzi na spotkaniach, jest operacyjnie niewykonalna niezależnie od tego, jak dobry ma backtest — a forward test pokaże to bezlitośnie, jako serię sygnałów bez wejścia. Warianty workflow dla pracującego na etacie (okna decyzyjne, automatyzacja alertów, przejście na wyższy interwał) opisuje artykuł 15.5, a architekturę VPS, watchdoga i autostartu — 15.3, sekcja 4. Dla testu istotny jest jeden wniosek: sygnały, których fizycznie nie mogłeś wykonać, zapisujesz w signal inventory (sekcja 8) i traktujesz jako brak wykonania, zamiast udawać, że test i real widziały te same okazje.
6. Ile obserwacji wystarczy — N, p-value, przedział ufności
Detal patrzy na backtest z 30 trade'ami, widzi WR 60% i myśli „strategia ma WR 60%". Statystyka mówi co innego: przy próbie 30 transakcji i obserwowanym WR 60% przedział, w którym z 95-procentową pewnością leży rzeczywiste WR, wynosi 41–77% (metoda Clopper–Pearson, założenie: próby niezależne). Innymi słowy — nie zmierzyłeś WR, zmierzyłeś przedział, i to bardzo szeroki.
Centralne Twierdzenie Graniczne, grube ogony i brak magicznej liczby
Klasyczny statystyczny minimalny próg N = 30 (Centralne Twierdzenie Graniczne) działa dla rozkładów bez grubych ogonów. Rynki finansowe mają wyraźnie grube ogony — pojedyncze trade'y +5R lub −3R (gap, news shock, flash crash) zaburzają średnią i odchylenie. Skutek jest taki, że przybliżenie normalne schodzi się wolniej, a sama liczba transakcji nie mówi, jak precyzyjny jest pomiar. Nie istnieje jedna magiczna liczba transakcji. Adekwatność próby zależy od rozrzutu wyników w R, od zależności między transakcjami (serie w jednym reżimie, kilka pozycji na skorelowanych parach, wspólna publikacja makro), od rzadkości sygnału, od liczby sprawdzonych wariantów i od tego, jak precyzyjnej odpowiedzi w ogóle potrzebujesz. Liczbę obserwacji podajesz więc zawsze — ale razem z przedziałem, metodą i założeniem o niezależności, nigdy jako samodzielny werdykt. I nie utożsamiaj liczby transakcji z liczbą niezależnych prób: trzydzieści wejść w jednym tygodniowym trendzie to nie trzydzieści niezależnych obserwacji.
Przedział ufności WR vs próba
| Liczba trade'ów (N) | WR z próby | 95% przedział ufności | Czy odróżnisz edge od szumu? |
|---|---|---|---|
| 30 | 60% | 41–77% (±18 pp) | Nie — przedział obejmuje WR poniżej progu rentowności, który przy payoffie 1:1 i bez kosztów wynosi 50% |
| 50 | 60% | 45–74% (±14 pp) | Nie — dolna granica wciąż poniżej 50% |
| 100 | 60% | 50–70% (±10 pp) | Ledwie — dolna granica dotyka 50%, decyzja odroczona |
| 200 | 60% | 53–67% (±7 pp) | Przedział nie obejmuje 50% — warunek konieczny, nie dowód przewagi |
| 500 | 60% | 56–64% (±4 pp) | Węższy przedział, ten sam warunek — o zyskowności decyduje rozkład R, nie WR |
| 1000 | 60% | 57–63% (±3 pp) | Precyzja pomiaru WR przestaje być wąskim gardłem |
Metoda: przedziały Clopper–Pearson (dokładne, 95%) dla obserwowanego WR 60%, przy założeniu prób niezależnych. Jeśli transakcje są zależne — serie w jednym reżimie, kilka pozycji na skorelowanych parach, wspólne zdarzenie makro — rzeczywisty przedział jest szerszy niż w tabeli, a liczba transakcji przecenia liczbę niezależnych obserwacji. Trzecia kolumna liczona jest dla całkowitej liczby wygranych: przy n = 30 i WR 60% to dokładnie 18 wygranych, bo ułamek liczby transakcji nie jest liczbą wygranych. Czwarta kolumna odnosi przedział do progu 50%, a ten jest progiem rentowności wyłącznie w modelu dwóch stałych wyników o payoffie 1:1 i bez kosztów. Przy innym payoffie próg rentowności to 1/(1 + avgWin/|avgLoss|) — dla 2R do 1R jest to 33%, dla 0,5R do 1R aż 67% — a po doliczeniu kosztów jeszcze wyżej.
Wniosek operacyjny nie brzmi „N = 200 wystarczy". Brzmi tak: sama liczba transakcji niczego nie rozstrzyga — rozstrzyga szerokość przedziału względem progu twojej decyzji. Jeśli progiem jest „WR powyżej 50%", to przy n = 100 przedział 50–70% dotyka progu i decyzja jest odroczona: zbierasz dane dalej, ewentualnie przy zmniejszonej skali. Przy n = 200 przedział progu nie obejmuje i masz warunek konieczny — nadal nie dowód przewagi, bo WR bez rozkładu R nie mówi nic o zyskowności. Ta sama logika działa w drugą stronę: przedział obejmujący próg jest powodem, żeby poczekać, a nie żeby wyłączyć strategię.
Test statystyczny — czy WR jest istotnie wyższe niż 50%
Pełna statystyka: binomial test. Hipoteza zerowa: WR = 50%. Nie jest to to samo co „strategia bez edge'u" — test dwumianowy patrzy wyłącznie na znaki wyników, a o przewadze decyduje WR razem z payoffem zrealizowanym i kosztami; strategia z WR 40% i payoffem 3:1 ma przewagę, a z WR 70% i payoffem 1:2 jej nie ma. Hipoteza alternatywna: WR > 50%. Z próby liczysz p-value — prawdopodobieństwo, że obserwowane wyniki pojawiłyby się przy hipotezie zerowej.
- p < 0,01 — wynik trudny do wyjaśnienia samym przypadkiem, przy tej jednej hipotezie
- p 0,01–0,05 — słabsza przesłanka; jeśli sprawdziłeś kilkanaście wariantów, ten próg trzeba podzielić przez ich liczbę (sekcja 2, pułapka 6)
- p 0,05–0,10 — wynik nierozstrzygnięty
- p > 0,10 — dane nie odróżniają strategii od losowego szumu
Dwa zastrzeżenia, bez których ta lista szkodzi. Po pierwsze, p-value nie jest prawdopodobieństwem, że strategia ma przewagę, i nie mówi nic o jej wielkości — mówi tylko, jak często taki wynik pojawiłby się przy hipotezie zerowej. Po drugie, liczy się przy założeniu jednej, ustalonej z góry hipotezy; przy trzydziestu sprawdzonych wariantach niskie p-value najlepszego z nich jest spodziewane, a nie zaskakujące.
W Pythonie (SciPy ≥ 1.7): from scipy.stats import binomtest; binomtest(wins, n_trades, 0.5, alternative='greater').pvalue. binomtest jest dostępny od SciPy 1.7.0; starsza funkcja binom_test została oznaczona jako przestarzała w 1.10.0 i usunięta w 1.12.0 [STAN NA DZIEŃ: 2026-09-06] — w nowych skryptach używaj binomtest ze zwracanym obiektem wynikowym.
Przykład: 60 wygranych z 100 trade'ów. binomtest(60, 100, 0.5, alternative='greater').pvalue = 0,028. Akceptowalne (p < 0,05). Ale 18 wygranych z 30: binomtest(18, 30, 0.5, alternative='greater').pvalue = 0,18 — brak dowodu, mimo „WR 60%".
Edge w R, nie tylko w WR
WR to tylko połowa obrazu. Strategia z WR 40% i avg win 3R, avg loss 1R ma expectancy +0,6R — bardzo dobra. Strategia z WR 70% i avg win 0,5R, avg loss 1R ma expectancy +0,05R — marginalna.
Pełna statystyka edge'u: t-test na średniej R per trade. Hipoteza zerowa: średnia R = 0. Liczysz t = (mean_R − 0) / (std_R / sqrt(N)).
Próbka 30 z mean +0,3R, std 1,5R: t = 0,3 / (1,5 / sqrt(30)) = 1,1 — p-value 0,14 (brak dowodu). Ta sama mean i std przy N = 200: t = 0,3 / (1,5 / sqrt(200)) = 2,83 — p-value 0,003 (silny dowód).
Zwróć uwagę, co się właśnie stało: ta sama średnia i to samo odchylenie dały zupełnie inny wniosek przy różnym n. To jest cała treść „progu statystycznego" — nie ma liczby, po której wynik staje się pewny, jest tylko przedział, który albo obejmuje próg twojej decyzji, albo go nie obejmuje. W karcie testu zapisujesz jedno i drugie: liczbę obserwacji oraz przedział, nigdy samą średnią.
Pełna metryka edge'u w R — operacyjny wzór
Przykład numeryczny: WR 54%, avgWin 1,8R, avgLoss 1R → E = 0,54 × 1,8 − 0,46 × 1,0 = 0,97 − 0,46 = +0,51R. Uwaga na mianowniki: avgWin i avgLoss to średnie zrealizowane, a nie planowany stosunek R:R. Planowany payoff 1:1,8 i zrealizowany avgWin 1,8R to dwie różne liczby, a różnica między nimi to właśnie koszty wykonania i wyjścia przed celem. Jeśli expectancy brutto jest niska, a model kosztów dodaje 0,2–0,3R, wynik netto potrafi być ujemny mimo dodatniego wyniku testu — dlatego koszty wchodzą do rachunku przed oceną, nie po niej.
SQN — jedna uwaga, definicja w artykule 15.9
SQN (System Quality Number) łączy expectancy, rozrzut wyników i wielkość próby: SQN = √N × mean(R) / std(R)[5]. Dla testu istotna jest jedna własność: SQN rośnie z pierwiastkiem z liczby transakcji, więc dwa backtesty o różnym n są nieporównywalne, a „wysoki SQN" bywa po prostu długim testem. Definicja, ograniczenie próby przyjmowanej do wzoru, skala interpretacyjna autora metody i jej ograniczenia stoją w artykule 15.9. Trzy rzeczy, których SQN nie robi: nie mówi, czy przewaga jest realna, nie zastępuje OOS ani modelu kosztów i nie jest decyzją o alokacji kapitału.
binomtest(27, 47, 0.5, alternative='greater').pvalue = 0,19, więc dane nie odróżniają tego wyniku od rzutu monetą. Przedział 95% dla WR przy n = 47 i k = 27: 42–72% — obejmuje wartości, przy których strategia jest stratna. Co istotniejsze: w arkuszu nie było kolumn avgWin i avgLoss w R, więc sam WR i tak nie wystarczał do policzenia expectancy. Po doliczeniu R: avgWin 0,7R, avgLoss 1,2R → E = 0,574 × 0,7 − 0,426 × 1,2 = 0,402 − 0,511 = −0,11R. Ten sam rachunek na liczbach całkowitych: 27 × 0,7 − 20 × 1,2 = 18,9 − 24 = −5,1R na 47 transakcji, czyli −0,109R średnio. Suma R nie jest procentem rachunku: przelicza ją dopiero przyjęty sizing, a przy 1% kapitału na każdą transakcję wychodzi około −5,1% bez składania i −5,2% po złożeniu — w obu wariantach strata, a nie zysk. Jeśli arkusz pokazywał dodatni wynik procentowy, znaczy to tyle, że ryzyko na transakcję zmieniało się między transakcjami, więc każda ważyła w procentach inaczej. Sama expectancy w R pozostaje przy zmiennym ryzyku w pełni policzalna — pod jednym warunkiem: każda transakcja ma własne R₀ ustalone przed wejściem i wynik dzielisz przez to R₀ (Ri = P/L nettoi ÷ R₀i), a nie przez średnią wielkość pozycji policzoną po fakcie. Nie da się natomiast przejść z sumy R na procent rachunku bez kolumny z wielkością pozycji — i to właśnie tej kolumny w arkuszu brakowało. Osiem miesięcy pracy na metrykach, z których bez niej nic nie wynika.
7. Model wykonania i kosztów: spread, slippage, swap, prowizja, częściowe wykonania
Niedomodelowanie kosztów to pułapka, która sama jedna potrafi zamienić strategię stratną w zwycięską na backteście. Pełen model kosztów ma cztery składowe i każdą trzeba modelować osobno.
Spread: fixed vs variable
| Model | Charakterystyka | Kiedy używać |
|---|---|---|
| Fixed spread (np. 1,0 pipsa stałe) | MT4 default, prosty, zawyża wyniki w godzinach niskiej płynności | Tylko jako pierwszy szybki sanity check, nigdy do walidacji |
| Average spread (z historii brokera) | Średnia z 6–12 miesięcy, pojedyncza wartość | Dla strategii intraday w godzinach wysokiej płynności (LON, NY) |
| Time-of-day variable | Spread zależny od godziny (LON open: 0,3 pipsa, rollover: 4 pipsy) | Standard dla strategii intraday i swing |
| Tick-by-tick variable (Tick Data Suite, Dukascopy) | Realny spread z każdej sekundy historii, z book depth | Strategie skalpujące, news trading, profesjonalna walidacja |
Tick Data Suite (TDS) z danymi tickowymi Dukascopy to najczęściej używany zestaw do backtestu tickowego w MT4. TDS pozwala MT4 używać 99% modelu jakości z prawdziwymi tickami i variable spread. Cena i model licencji u dostawcy zmieniały się — obecnie strona kieruje na inną domenę i mówi o subskrypcji, więc sprawdź aktualne warunki przed zakupem [STAN NA DZIEŃ: 2026-09-06]. Czy zakup się opłaca, zależy od tego, ile strategii faktycznie testujesz i ile z nich jest wrażliwych na spread: dla skalpingu i news-tradingu różnica między testem na stałym i na zmiennym spreadzie potrafi odwrócić znak wyniku, dla strategii swing ze stopem rzędu stu pipsów bywa nieistotna. Policz to na własnym planie testów, zamiast przyjmować z góry, że narzędzie się zwróci.
Slippage — model statyczny vs dynamiczny
Slippage to różnica między ceną w backteście a realną ceną egzekucji. Modelowanie:
- Statyczny: stała wartość (np. 0,5 pipsa per entry/exit). Prosty, niedoszacowuje slippage'u w stresie
- Dynamiczny w funkcji ATR: slippage = 0,1 × ATR(14) M5. Większy slippage przy większej zmienności
- Dynamiczny w funkcji book depth (jeśli dostępny): slippage = funkcja wolumenu zlecenia / głębokości arkusza. Najrealniejszy, ale wymaga danych book depth
Reguła robocza dla detalu [PRÓG ILUSTRACYJNY — NIE NORMA RYNKOWA]: poślizg ułamka pipsa w normalnych warunkach, kilka pipsów na wybiciach z wolumenu, kilkanaście po publikacjach makro — modeluj w trzech reżimach. Te rzędy wielkości są punktem startowym, nie pomiarem: zmierz to u siebie na forwardzie jako cena fillu − cena zlecenia, ze znakiem kierunku (dla pozycji krótkiej dodatni poślizg wejścia oznacza gorsze wejście). Po kilkudziesięciu transakcjach masz własną tabelę zamiast cudzej.
Swap (cost of carry)
Pozycje trzymane przez noc płacą lub otrzymują swap. W MT4 wartości są najczęściej podawane w punktach na lot za noc, ale platforma zna też inne tryby naliczania — m.in. w walucie bazowej lub depozytowej oraz procentowy — więc liczba z okna „Specyfikacja" nie zawsze jest liczbą punktów [DO WERYFIKACJI PROCEDURA: specyfikacja symbolu u twojego brokera → tryb naliczania swapu]. Trzy regiony do uwzględnienia:
- Direction-dependent: long EUR/USD ma zwykle ujemny swap (pożyczasz USD wyżej oprocentowane), short EUR/USD ma dodatni
- Potrójny swap: u większości brokerów FX naliczany jest w środę (rozliczenie T+2 przenosi weekend na środową noc). To konwencja rynkowa, nie własność platformy — sprawdź dzień i mnożnik w specyfikacji symbolu u swojego brokera. Strategie swing trzymające pozycje przez ten dzień muszą to modelować
- Wartość bezwzględna zależy od różnicy stóp — w okresach dużych różnic stóp między walutami pary swap potrafi być istotnym składnikiem kosztu, od kilku do kilkunastu pipsów dziennie w niekorzystnym kierunku. Nie przepisuj liczby z artykułu: pobierz aktualną tabelę swapów u swojego brokera [STAN NA DZIEŃ: 2026-09-06] i wstaw ją do modelu kosztów
Praktyka: dla strategii swing z trzymaniem 3–8 dni swap potrafi zjeść istotną część expectancy brutto — policz to na własnej tabeli, konwersją koszt w R za noc = swap w pipsach ÷ odległość SL w pipsach, i pomnóż przez typową liczbę nocy. Backtest bez swapu jest dla swing tradera bezwartościowy.
Prowizja
Konta ECN i STP zwykle mają komisję per RT (round turn — wejście + wyjście). Typowe wartości: 5–7 USD per lot RT na EUR/USD, 6–10 USD na minor pairs, 8–15 USD na exotics. Modelowanie:
Prowizja w pipsach = komisja RT w walucie kwotowanej ÷ wartość pipsa jednego lota w tej samej walucie. Dla EUR/USD: 6 USD ÷ 10 USD/pips na lot = 0,6 pipsa per RT. Jeśli rachunek prowadzisz w złotych, przelicz na PLN obie strony ułamka albo żadnej — wmieszanie kursu USD/PLN tylko do licznika jest najczęstszym błędem w tym miejscu i zawyża lub zaniża koszt o cały kurs walutowy.
Strategia skalpująca z 200 trade'ami miesięcznie i 0,1 lota: 200 × 0,1 × 6 = 120 USD komisji miesięcznie. Na kapitale 1 000 USD to 12% kapitału miesięcznie obrotowych kosztów prowizji, czyli 144% kapitału rocznie przy zachowanym wolumenie obrotu. Tak — strategia skalpująca z mikro lotami na małym kapitale nie ma sensu kosztowego, bo prowizja zjada wielokrotność oczekiwanego zwrotu. Próg sensowności: kapitał na tyle duży, żeby roczne koszty prowizji nie przekraczały 20–30% oczekiwanego zwrotu netto z edge'u.
Tick Data Suite — jak uruchomić backtest klasy profesjonalnej w MT4
TDS jest praktycznym rozwiązaniem dla backtestu strategii skalpujących i news-tradingowych w MT4. Konfiguracja mieści się w weekend:
- Zakup: tickdatasuite.com — adres przekierowuje dziś na inną domenę, a dostawca opisuje licencję jako subskrypcję; sprawdź aktualny model i cenę przed zakupem [STAN NA DZIEŃ: 2026-09-06]
- Źródło danych: Dukascopy historical data (darmowe, tickdata bid/ask na poziomie milisekundy). Dostępność historii zależy od instrumentu — główne pary mają zwykle najdłuższą historię, egzotyki i CFD krótszą. Przed testem sprawdź ciągłość danych dla konkretnej pary i zakresu
- Setup: 2–3 godziny pierwszego konfigurowania — pobranie danych dla wybranych par, podpięcie do MT4 Strategy Tester, wybór modelu „Every tick"
- Po setupie: backtest na realnych tickach z variable spread per godzina, modelowaniem kosztów per broker, jakość modelu w MT4 99% zamiast domyślnych ~25–60%
Do czego to realnie służy: dla strategii skalpującej lub news-tradingowej test tickowy z realnym zmiennym spreadem potrafi pokazać stratę tam, gdzie test na stałym spreadzie pokazywał zysk. Czy koszt narzędzia się zwraca, wynika z twojego planu testów i z liczby strategii, które na nim sprawdzisz — nie z samego faktu jego zakupu.
Model wykonania: opóźnienie, luki, częściowe wykonania
Koszty to dopiero połowa realizmu testu. Druga połowa to model wykonania — zbiór założeń o tym, co dokładnie działo się między sygnałem a fillem. Każde z nich trzeba zapisać w karcie testu (pole 5), bo każde da się ustawić „korzystnie", a wtedy wynik jest fikcją bez jednego fałszywego zdania w raporcie:
- Moment sygnału i opóźnienie. Sygnał zapada na zamknięciu świecy, a zlecenie wychodzi później: obliczenie, wysłanie, potwierdzenie. W testach domyślnie zero, w realu setki milisekund, a przy klikaniu ręcznym — sekundy. Dla strategii wybiciowej ta różnica potrafi być połową całego kosztu.
- Luki. Zlecenie stop złożone wewnątrz luki nie realizuje się po cenie stopa, tylko po pierwszej dostępnej po drugiej stronie. Tester, który zawsze wypełnia po cenie zlecenia, systematycznie zawyża wynik strategii trzymających pozycje przez weekend i przez publikacje — i to właśnie tam pojawiają się transakcje gorsze niż −1R.
- Częściowe wykonania. Przy większym wolumenie, w cienkiej płynności albo na rachunku ECN zlecenie może wypełnić się w kilku transzach po różnych cenach. Konsekwencje dla testu są trzy. Po pierwsze, ceną wejścia jest średnia ważona transz, a nie pierwsza z nich. Po drugie, jeśli wypełniła się tylko część zlecenia, realne ryzyko jest mniejsze niż planowane — ale mianownik R0 zostaje ten z planu, a różnicę zapisujesz jako niewykonanie, nie jako lepszy wynik. Po trzecie, częściowe wyjścia z jednej decyzji to nadal jedna transakcja w statystyce; liczenie każdej transzy osobno sztucznie podnosi win rate, bo transze zamykane wcześniej są z definicji częściej dodatnie.
- Requote i odrzucenie zlecenia. Sygnał, który w teście zawsze wchodzi, w realu czasem nie wchodzi wcale. Odsetek nieudanych wejść mierzysz na forwardzie i wpisujesz do reconciliation — to on tłumaczy, dlaczego test miał 50 sygnałów, a forward 41, zanim zaczniesz szukać look-ahead tam, gdzie go nie ma.
Reguła kontrolna: każde założenie modelu wykonania przesuń raz w stronę pesymistyczną — większe opóźnienie, większy poślizg, niejednoznaczna świeca rozstrzygana na niekorzyść — i sprawdź, czy wynik przeżywa. Jeśli przewaga znika przy realistycznym pesymizmie, nie była przewagą, tylko marginesem modelu. Backtest, który zawsze wypełnia całość zlecenia natychmiast i po cenie z bazy, jest w tym punkcie optymistyczny i trzeba to napisać wprost w polu „ograniczenia". Diagnostykę wejść i wyjść przez MAE/MFE — definicje, tabelę scenariuszy i wykres rozrzutu — prowadzi artykuł 15.9.
Łączny model kosztów dla MT4 z TDS
# Pseudokod modelu kosztow do skryptu walidacji backtestu.
# Jednostka WSZYSTKICH skladnikow: pipsy danej pary. ATR podajesz juz przeliczony
# na pipsy (atr_pips), nie w jednostkach ceny — inaczej dodajesz do siebie
# liczby o zupelnie roznych rzedach wielkosci i wynik nie znaczy nic.
def total_cost_per_trade(pair, hour_utc, atr_pips, direction, hold_nights,
spread_in_fills=False):
"""
Zwraca laczny koszt trade'u w pipsach; wartosc dodatnia = koszt.
direction: 'long' albo 'short' — swap ma przeciwny znak dla kazdej strony
spread_in_fills: True, gdy backtest wypelnia zlecenia po bid/ask, czyli spread
siedzi juz w cenach filli. Wtedy NIE wolno dodac go drugi raz.
"""
# 1. Spread (variable po godzinie) — pomijany, gdy jest juz w cenach filli
spread_table = {
'EURUSD': {'low_liquidity': 1.5, 'normal': 0.7, 'peak': 0.3},
'GBPJPY': {'low_liquidity': 4.0, 'normal': 2.0, 'peak': 1.2},
# ...
}
if 22 <= hour_utc or hour_utc <= 6:
regime = 'low_liquidity'
elif 8 <= hour_utc <= 16:
regime = 'peak'
else:
regime = 'normal'
spread = 0.0 if spread_in_fills else spread_table[pair][regime]
# 2. Slippage (dynamiczny w ATR wyrazonym w PIPSACH, dwustronny)
slippage = 2 * 0.1 * atr_pips # entry + exit
# 3. Prowizja (EUR/USD = 0,6 pipsa RT)
commission_pips = {'EURUSD': 0.6, 'GBPJPY': 0.8}.get(pair, 0.7)
# 4. Swap — konwencja: liczba DODATNIA = koszt w pipsach za jedna noc.
# Tabela trzyma koszt strony LONG; short ma znak przeciwny i bywa przychodem.
# Liczby bierzesz z tabeli swapow swojego brokera, nie z artykulu.
swap_cost_long = {'EURUSD': 0.3, 'GBPJPY': 0.5}.get(pair, 0.4)
swap_per_night = swap_cost_long if direction == 'long' else -swap_cost_long
# Potrojne naliczenie w dniu rolowania weekendu (u wiekszosci brokerow sroda)
# doliczasz osobno, wedlug kalendarza pozycji — hold_nights samo tego nie widzi.
swap_total = swap_per_night * hold_nights
return spread + slippage + commission_pips + swap_total
Przy walidacji: jeśli twoja strategia ma brutto expectancy +0,4R, a model kosztów dodaje 0,2R kosztów per trade — netto +0,2R. Jeśli model dodaje 0,5R kosztów — strategia jest stratna i nie poszłaby na live. Jeśli twój backtest nie modeluje kosztów — nie wiesz, w którym wariancie jesteś.
8. Cherry picking i selekcja sygnałów — najczęstszy grzech testera
Cherry picking metodologiczny to proces, w którym tester (świadomie lub nie) odrzuca część sygnałów strategii, zostawia te „dobre" i raportuje wyniki. Wynik: backtest pozornie stratnej strategii pokazuje zysk, bo statystycznie najgorsze sygnały zostały usunięte.
Trzy warianty cherry pickingu
Wariant 1: „Pomijam sygnały, które nie wyglądają dobrze". Strategia generuje sygnał, ale tester ręcznie ocenia kontekst — „ten sygnał jest w niewłaściwej fazie, pominę go". W backteście liczysz tylko sygnały, które „wyglądały dobrze". Problem: ocena „czy wygląda dobrze" w retrospektywie jest skażona — wiesz, jak skończyła się świeca po sygnale, więc twój filtr „nie wygląda dobrze" przypadkiem pokrywa się ze stratnymi instancjami.
Wariant 2: „Filtruję ex post na podstawie wyników". Tester widzi w backteście, że stratne trade'y są często we wtorki rano. Dodaje filtr „nie handluję wtorkami rano", retestuje strategię — wynik się poprawia. Filtr nie ma niezależnej hipotezy, dodał go po obejrzeniu wyników. W realu wtorki rano nie są systematycznie gorsze — strategia traci ten sztuczny edge.
Wariant 3: „Backtest na 'czystych' okresach". Tester odrzuca z backtestu okresy „anomaliczne" — np. marzec 2020 (COVID), październik 2008 (Lehman), grudzień 2018 (taper tantrum). Backtest na „normalnych" okresach pokazuje świetne wyniki. Problem: realne handlowanie obejmuje też anomalie. Strategia, która działa tylko poza nimi, w realu w którymś momencie spotka anomalię i zwraca cały zarobek.
Detekcja cherry pickingu
- Liczba zerwanych sygnałów — ile sygnałów strategia wygenerowała vs ile zostało wziętych. Jeśli > 10% sygnałów odrzucono, podejrzanie. Jeśli > 30%, niemal pewny cherry picking
- Powód odrzucenia — czy zdefiniowany przed testem (filtr w kodzie) czy ad hoc (ocena w trakcie)? Tylko pierwsze jest legalne
- Test na pełnych danych — uruchom strategię bez ręcznych odrzuceń, na pełnym zakresie danych włącznie z anomaliami. Porównaj wyniki. Jeśli „pełne" wyniki są dramatycznie gorsze — masz cherry picking
Arkusz „signal inventory" — twardy mechanizm kontrolny
Każdy sygnał strategii dostaje status w jednoznacznym arkuszu, prowadzonym automatycznie z logów lub półautomatycznie z dziennika:
| Status sygnału | Definicja | Akceptowalna częstotliwość |
|---|---|---|
taken | Sygnał wykonany zgodnie z regułą strategii | Cel: > 90% |
skipped_by_rule | Sygnał odfiltrowany przez kod / regułę zdefiniowaną przed testem (np. filtr news, korelacja, godzina) | Bez limitu — to jest legalne |
skipped_manual | Trader ręcznie pominął sygnał („nie podobał mi się układ") | < 10% — powyżej tego backtest jest skażony |
invalid_data | Sygnał wystąpił w warunkach awarii feedu, brokera lub infrastruktury | < 5% — powyżej tego problem operacyjny |
Reguła operacyjna: jeśli skipped_manual przekracza 10% sygnałów, backtest jest skażony cherry pickingiem i nie idzie do walidacji statystycznej. Wracasz do reguł i albo (a) formalizujesz powód pomijania jako filtr w kodzie, albo (b) przyjmujesz, że strategia wymaga dyscypliny, której nie masz, i wracasz do tablicy.
Cherry picking na marketplace'ie EA
9. Najczęstsze błędy w testowaniu
Błąd 1: Optymalizacja parametrów na całym zbiorze
Tester używa MT4 Optimization Mode, testuje 200 kombinacji parametrów na całych 5 latach danych, wybiera tę, która daje +180%. Brak walk-forwardu, brak OOS. To jest klasyczny curve fitting: przy 200 próbach najwyższy wynik jest spodziewany nawet przy zerowej przewadze, więc forward test nie ma czego po tym backteście odziedziczyć. Naprawa: podziel dane chronologicznie — proporcję zapisujesz w karcie testu (pole 4), bo 70/30 jest założeniem scenariusza, nie normą — optymalizuj wyłącznie na IS, walidacja jednorazowa na OOS, a liczbę sprawdzonych kombinacji wpisz do pola 7.
Błąd 2: Zbyt mała próba historyczna
Backtest na 6 miesiącach z 24 transakcjami nie jest backtestem — to anegdota, w której przedział wokół expectancy jest szerszy niż sama expectancy. Reżim rynkowy z pół roku bywa całkowicie niereprezentatywny. Praktyczne minimum dotyczy zakresu, nie liczby: dane muszą obejmować więcej niż jeden reżim, czyli w praktyce kilka lat. Liczbę transakcji oceniasz przedziałem, a nie progiem — [PRÓG ILUSTRACYJNY — NIE NORMA RYNKOWA] liczby 200 i 500, którymi posługuje się ten artykuł, są założeniami scenariusza dla WR w okolicach 60% i prób niezależnych, a nie normą rynkową.
Błąd 3: Backtest tylko na bid (lub tylko na ask)
Niektóre platformy backtestowe domyślnie używają tylko bid (cena sprzedaży). Trade long otwarty na bid, zamknięty na bid = brak modelowania spreadu. Każdy trade „dostaje" cały spread jako zysk, którego w realu nie ma: long powinien wejść po ask i wyjść po bid, a wchodzi i wychodzi po bid. Naprawa: w MT4 ustaw model „Every tick" z TDS, w MT5 użyj trybu „Every tick based on real ticks"[6]. W karcie testu (pole 3) zapisz wprost, czy dane były bid, ask, mid, czy pełne bid+ask — bo z samego raportu testera tego nie widać.
Błąd 4: Ignorowanie zmiany reżimu rynkowego
Strategia testowana na 2020–2023 (post-COVID, niskie stopy, QE) nie zachowuje się tak samo w 2024–2026 (wysokie stopy, QT, polityczne zaburzenia). Naprawa: walk-forward kroczący identyfikuje, w których reżimach strategia działa, w których nie. Strategia, która działa tylko w jednym reżimie, jest reżimowo wrażliwa — nie błędna, ale wymaga wyłączania w innych reżimach.
Błąd 5: Brak testowania na różnych parach
Tester optymalizuje strategię na EUR/USD, działa świetnie. Wniosek: „strategia działa". Ale nie wiesz, czy strategia jest specyficzna dla EUR/USD (mikrostruktura, profil zmienności) czy uniwersalna. Test na 5–8 parach pokazuje, na ilu działa. Strategia działająca tylko na jednej parze = silnie podejrzana o curve fitting do mikrostruktury tej pary.
Błąd 6: Mylenie returns z risk-adjusted returns
Strategia A: +35% rocznie, max DD 22%. Strategia B: +25% rocznie, max DD 8%. Detal patrzy na sam zwrot i wybiera A. Porównanie skorygowane o ryzyko wygląda inaczej:
- Calmar A: 35 / 22 = 1,6
- Calmar B: 25 / 8 = 3,1
Strategia B daje większą stabilność zwrotu na jednostkę obsunięcia. Sharpe'a z tych dwóch liczb nie da się policzyć — potrzebuje serii stóp zwrotu o określonej częstotliwości, stopy odniesienia i okresu: Sharpe = (średnia stopa okresowa − stopa wolna od ryzyka) / odchylenie stóp okresowych × √liczba okresów w roku. Roczny zwrot podzielony przez miesięczne odchylenie nie jest Sharpe'em, tylko liczbą bez jednostki, a dopisanie „np. 1,1" to zmyślenie wyniku. Brak podstaw do policzenia metryki oznacza brak wyniku, a nie wynik „mniej więcej taki". Definicje Sharpe'a, Sortino i Calmara, wraz z tym, czego każda z nich nie mierzy — w artykule 15.9.
Błąd 7: Brak pomiaru po wdrożeniu
Strategia przechodzi backtest, demo, mikrokonto, wchodzi na skalę z planu — i przestaje być mierzona. Test nie kończy się wdrożeniem: expectancy i obsunięcie z realnego handlu porównujesz z przedziałem i percentylami zapisanymi w karcie testu, bo tylko to pozwala odróżnić normalną wariancję od faktycznego rozjazdu. Rytm przeglądu oraz kryteria utrzymania, obserwacji, redukcji i wyłączenia strategii opisuje artykuł 15.10 (Audyt strategii). Z 15.4 zabierasz do niego tylko materiał porównawczy: metryki z definicjami, przedziały i percentyl obsunięcia z Monte Carlo.
Błąd 8: Intervention bias po wdrożeniu
Trader co tydzień zmienia parametry albo dodaje filtry po serii 5–10 strat — czyli zmienia strategię szybciej, niż dane są w stanie cokolwiek o niej powiedzieć. Rachunek na serii pokazuje, skąd bierze się to złudzenie. Przy WR 52% prawdopodobieństwo, że pięć konkretnych, wskazanych z góry transakcji okaże się stratami, wynosi 0,485 = 2,5%. Ale prawdopodobieństwo, że w ciągu stu transakcji pojawi się gdziekolwiek co najmniej jedna taka seria, to około 75% (rachunek dokładny dla prób niezależnych; wzór „1 − (1 − qk)N−k+1" traktuje nakładające się okna jako niezależne i zawyża wynik). To są dwie zupełnie różne wielkości i ich mylenie stoi za większością diagnoz „strategia przestała działać" postawionych po piątej stracie. Zamiast progu „ile transakcji" zapisz w karcie testu warunek merytoryczny: interweniuję, gdy przedział wokół expectancy przestaje obejmować próg decyzji — a nie, gdy wynik ostatniego tygodnia jest brzydki.
Zanim ruszysz regułę — kolejność sprawdzania
Najczęstszy błąd po wdrożeniu: trader miesza błąd systemu z błędem wykonania i naprawia nie to, co trzeba. Kolejność bramek jest odwrotna do intuicyjnej, bo najpierw trzeba ustalić, czy wynik w ogóle mówi coś o strategii:
- Dane i wykonanie. Czy dziennik zgadza się z raportem brokera, czy wersja strategii jest ta sama co w karcie testu, ile sygnałów wykonano niezgodnie z regułą. Wynik z okresu z naruszeniami reguł albo z nieuzgodnionymi kosztami nie mówi nic o strategii — ani dobrego, ani złego.
- Koszty. Czy realny spread, poślizg i prowizja mieszczą się w modelu z karty testu. Spadek expectancy o 0,15R przy koszcie wyższym o 0,15R nie jest problemem strategii, tylko problemem modelu kosztów.
- Reżim. Czy warunki, w których strategia z założenia działa, w ogóle w tym okresie wystąpiły.
- Przewaga. Dopiero tutaj — i wyłącznie z przedziałem wokół expectancy, nie z samą średnią z ostatnich kilkunastu transakcji.
Pełna tabela decyzyjna „kiedy poprawiać system, a kiedy siebie", progi degradacji setupu i tryb przeglądu należą do audytu strategii — artykuł 15.10. W 15.4 kończy się to jedną regułą: dopóki nie przeszedłeś bramek 1–3, nie masz podstaw, żeby dotknąć reguł. A każda zmiana reguł jest nową wersją strategii, którą trzeba sprawdzić od początku pętli — nie doklejeniem poprawki do starego testu.
10. Checklista — czy strategia jest gotowa do live
Łącznie 20 punktów w pięciu kategoriach: walidacja statystyczna (5), pułapki metodologiczne (6), model kosztów (4), forward test (3) i dyscyplina operacyjna (2). Bramki są dwie, bo punkt 17 sam w sobie wymaga już handlu realnym kapitałem i nie może warunkować wejścia na mikrokonto: bramka do mikrokonta to punkty 1–16 oraz 19, bramka do skali z planu to komplet 1–20. Punktacja nie kompensuje — brak choćby jednego warunku z danej bramki zatrzymuje przejście niezależnie od sumy punktów. Wszystkie liczby w checkliście (długości etapów, liczby transakcji, progi) są założeniami scenariusza z tego artykułu, nie normą rynkową.
Walidacja statystyczna (5 punktów)
- Backtest pokrywa minimum 3 lata danych (optymalnie 5–10 lat)
- Liczba transakcji podana razem z przedziałem wokół expectancy i WR, z nazwaną metodą; przedział nie obejmuje progu decyzji zapisanego w karcie testu
- Walk-forward: przedziały wokół expectancy z IS i z OOS zachodzą na siebie — porównujesz dwie próby z niepewnością obu, a nie nową średnią z historycznym przedziałem ufności — a wynik jest porównany z wariantem bazowym na tych samych danych
- Monte Carlo bootstrap z podanym ziarnem i długością bloku: 5. percentyl zwrotu dodatni, odsetek scenariuszy z obsunięciem głębszym niż limit z planu poniżej progu ustalonego przed testem
- Test statystyczny policzony i zinterpretowany z uwzględnieniem liczby sprawdzonych wariantów (pole 7 karty testu)
Pułapki metodologiczne (6 punktów)
- Brak look-ahead bias — strategia używa tylko danych z chwili t lub wcześniejszych; rozstrzygnięcie świecy zawierającej i SL, i TP zapisane w modelu wykonania
- Brak survivorship bias — koszyk instrumentów odtworzony na moment decyzji, razem z tymi, które później zniknęły; zawężenie do par aktywnych dziś jest selekcją przyszłą, nie naprawą. Dzisiejsza wykonalność zapisana osobno w polu „ograniczenia"
- Brak curve fittingu — heatmapa parametrów pokazuje plateau, nie izolowany szczyt (plateau jest przesłanką przeciw dopasowaniu do jednej komórki, nie dowodem przewagi — tę rozstrzyga punkt 3)
- Brak overfittingu — wszystkie reguły i filtry mają uzasadnienie ex ante
- Brak cherry pickingu — zerwane sygnały < 10%, powody zdefiniowane przed testem
- Rejestr prób prowadzony — znasz liczbę sprawdzonych strategii, wariantów i filtrów, łącznie z odrzuconymi, i uwzględniłeś ją w interpretacji wyniku
Model kosztów (4 punkty)
- Spread modelowany jako variable (time-of-day lub tick-by-tick), nie fixed
- Slippage modelowany dynamicznie (statyczny lub ATR-based, w trzech reżimach)
- Swap modelowany dla strategii swing (per direction, triple Wednesday)
- Prowizja modelowana dla strategii skalpujących (komisja per RT)
Forward test (3 punkty)
- Demo 30+ dni, 30+ trade'ów, przedziały wokół expectancy z demo i z backtestu zachodzą na siebie — porównanie dwóch prób z niepewnością obu, nie stała tolerancja zamiast metody
- Mikrokonto live 90+ dni, 60+ trade'ów, ten sam warunek nakładania się przedziałów, policzony na wynikach netto po realnych kosztach wykonania
- Drawdown w trakcie forwardu nie przekracza 95. percentyla z Monte Carlo
Dyscyplina operacyjna (2 punkty)
- Egzekucja mierzona na jednym mianowniku — wszystkich sygnałach wygenerowanych przez strategię w okresie. Z tego mianownika liczysz osobno odsetek wykonań niezgodnych z regułą (
error ratez dziennika) i odsetek pominiętych ręcznie (skipped_manualz signal inventory, próg 10% z sekcji 8). W karcie testu zapisujesz obie liczby, a nie jedną „zgodność" składaną z liczników o różnych mianownikach - Plan pomiaru po wdrożeniu zdefiniowany — co porównujesz (expectancy z przedziałem, obsunięcie vs percentyl Monte Carlo), w jakim rytmie i wg kolejności bramek z sekcji 9; decyzje z tego pomiaru podejmujesz wg 15.10
Artefakty wymagane przed live (lista do archiwizacji)
Strategia idąca na skalę z planu musi zostawić ślad audytowy. Bez tego po 6 miesiącach nie odtworzysz, dlaczego coś działało albo gdzie pojawił się błąd:
- Karta testu — dwanaście pól z sekcji 1, wypełnionych w kolejności: 1–9 przed uruchomieniem testu, 10–12 po
- Plik danych historycznych użytych do backtestu (z hash'em, żeby wykluczyć podmianę)
- Konfiguracja strategii — pełen kod EA / skryptu / opis reguł, wraz z parametrami zamrożonymi po OOS
- Raport IS/OOS — equity curve, expectancy z przedziałem, profit factor, max DD per okno walk-forwardu, plus wynik wariantu bazowego na tych samych danych
- Raport Monte Carlo — 1000+ symulacji, percentyle zwrotu i drawdownu, ruin probability
- Model kosztów — tabela spreadów per godzina, slippage per reżim, swap per direction, prowizja
- Eksport forward demo — log wszystkich sygnałów z 30 dni, status (taken / skipped), reconciliation z backtestem
- Dziennik mikrolive — 90 dni, każdy trade z R-multiple, MAE_R, MFE_R, kosztem rzeczywistym, screenem przed/po
- Lista odrzuconych sygnałów — signal inventory z powodami, weryfikacja error rate
- Screen ustawień brokera — typ konta, dźwignia, minimalny lot, koszty (na potrzeby reklamacji jakości egzekucji)
- Backup EA / skryptów / templates — wszystkie pliki MT4/MT5 w wersji zamrożonej na czas live
Folder projektu na dysku zewnętrznym lub w chmurze, struktura strategy_X/2026-Q2/{01_data, 02_IS, 03_OOS_locked, 04_montecarlo, 05_demo, 06_mikrolive, 07_artefacts}. Bez tego setupu masz strategię, której nie potrafisz zwalidować retrospektywnie po pierwszej gorszej serii.
Komplet 1–16 i 19 — możesz uruchomić mikrokonto. Komplet 1–20 — możesz przejść na skalę z planu. Brak choćby jednego warunku z bramki oznacza powrót do brakującego etapu, a nie obniżenie progu: każdy pominięty punkt to niewykryte ryzyko przeniesione na rachunek z prawdziwymi pieniędzmi.
FAQ — Najczęściej zadawane pytania
Ile czasu zajmuje pełna walidacja strategii od backtestu do live?
Czy MT4 Strategy Tester jest wystarczający do walidacji?
Co zrobić, jeśli moja strategia ma tylko 50 trade'ów w backteście?
Czy mogę pominąć demo, jeśli mam dobry backtest?
Co to są realistyczne wyniki dla strategii detalu?
Jak rozróżnić zmianę reżimu rynkowego od umierania strategii?
Czy używać forward testu bez backtestu?
Czy strategia może mieć dobry backtest, dobry walk-forward, dobry forward test, a w pełnym sizingu zaliczyć margin call?
Czy mogę kupić gotową strategię (EA) zamiast budować własną?
Źródła i bibliografia
- Pardo R., The Evaluation and Optimization of Trading Strategies, Wiley, 2008. Metodologia walk-forward analysis, oceny i optymalizacji systemów transakcyjnych, z naciskiem na unikanie nadmiernej optymalizacji.
- Aronson D., Evidence-Based Technical Analysis, Wiley, 2007. Statystyczne podstawy walidacji reguł technicznych, testy istotności i korekta Bonferroniego przy wielokrotnym testowaniu.
- López de Prado M., Advances in Financial Machine Learning, Wiley, 2018. Metody kontroli wielokrotnego testowania w badaniach strategii, m.in. deflated Sharpe ratio i walidacja krzyżowa z oczyszczaniem próby.
- Bandy H.B., Quantitative Technical Analysis, Blue Owl Press, 2015. Bootstrap i symulacje Monte Carlo dla systemów transakcyjnych, rozkład drawdownu i zależność wyników od przyjętej wielkości pozycji.
- Tharp V.K., Definitive Guide to Position Sizing, IITM, 2008. Definicja R-multiple i wzór SQN (System Quality Number) łączący expectancy, odchylenie wyników i wielkość próby.
- MetaQuotes, dokumentacja MQL5 — testowanie strategii (mql5.com/en/docs/runtime/testing), otwarte 2026-09-06. Tryby generowania ticków (w tym „Every tick based on real ticks") oraz natywny tryb Forward z podziałem 1/2, 1/3, 1/4 zakresu albo datą własną.
Twój postęp w kursie
Oznacz lekcję po zapoznaniu się z materiałem. Samo otwarcie lub przewinięcie strony nie oznacza ukończenia; oznaczenie nie jest wynikiem egzaminu.