Symulacja Monte Carlo strategii — ryzyko, którego nie widać w backteście

Ostatnio zweryfikowano: · Treść aktualna długoterminowo
Ostrzeżenie · YMYL Ten artykuł ma charakter wyłącznie edukacyjny i nie stanowi rekomendacji inwestycyjnej. Handel na rynku Forex wiąże się z wysokim ryzykiem utraty kapitału — według ESMA 74–89% rachunków detalicznych traci pieniądze.

Pewien znajomy pokazał mi backtest swojej strategii: skuteczność 55 procent, średnia wygrana 100 euro, średnia strata 80 euro, na papierze plus 3 800 euro w skali roku. Brzmiało porządnie, więc poszedł na rachunek rzeczywisty z ryzykiem pięć procent kapitału na transakcję i po sześciu miesiącach zlikwidował konto. Zapytał, gdzie się pomylił. Pomyłka nie tkwiła w strategii, tylko w tym, że jeden backtest to jedna historia, a Monte Carlo pokazałoby mu, że ten sam edge przy takim ryzyku ma 25-procentową szansę zrujnowania rachunku. Pisałem ten tekst właśnie z myślą o tej rozmowie.

Czym właściwie jest symulacja Monte Carlo strategii

Monte Carlo to metoda probabilistyczna nazwana od kasyna w Monako. W tradingu polega na bardzo prostym zabiegu: zamiast oglądać jedną krzywą kapitału, którą wygenerowała historia twoich transakcji, generujesz tysiąc nowych sekwencji o tej samej statystyce, ale w innej kolejności. Każda sekwencja to inna realizacja, każda rysuje inną krzywą konta, a razem dają chmurę możliwości, której pojedynczy backtest strategii nigdy nie pokaże.

Pojedynczy backtest jest jedną realizacją losowego procesu. Wariancja wokół niego potrafi być potężna i nie ma w tym niczego patologicznego — to po prostu sposób, w jaki działa wynik wielokrotnie powtarzanej gry o przewadze. Monte Carlo daje ci wachlarz tej wariancji w liczbach, których można dotknąć.

Na jakie pytania Monte Carlo naprawdę odpowiada

Symulacja zwraca trzy rzeczy, których jeden backtest nie powie ci wprost. Pierwsza to realistyczne obsunięcie kapitału na 95-procentowym poziomie ufności — czyli takie, którego nie przekraczasz w 95 ze 100 symulacji. Druga to prawdopodobieństwo utraty znacznej części konta, na przykład spadku poniżej 50 procent kapitału. Trzecia to zakres możliwych wyników rocznych przy stałej przewadze.

W moim przykładowym scenariuszu (hipotetycznie, na potrzeby ilustracji) strategia o skuteczności 55 procent, średniej wygranej 100 euro, średniej stracie 80 euro i 200 transakcjach w roku ma wartość oczekiwaną około 19 euro na transakcję, czyli na papierze 3 800 euro rocznie. Symulacja 1 000 przebiegów dała medianę bliską 3 750 euro. Najgorsze pięć procent przebiegów kończyło się na około 500 euro zysku, najgorszy procent na stracie 800 euro, a najlepsze pięć procent na 7 500 euro. Ten sam edge — pięciokrotna różnica między scenariuszami.

Jak uruchomić symulację w Excelu

Wersja bez makr wystarczy, żeby zrozumieć swoją strategię. W komórkach od A1 do A5 zapisujesz parametry: skuteczność 0,55, średnią wygraną 100, średnią stratę minus 80, liczbę transakcji 200 i kapitał początkowy 10 000. W komórce B1 wpisujesz =JEŻELI(LOS()<A1; A2; A3) — funkcja losowa Excela zwraca liczbę z przedziału od zera do jedynki, a jeśli trafi poniżej skuteczności, otrzymujesz wygraną, w przeciwnym razie stratę.

W komórce C1 dodajesz kapitał początkowy do wyniku z B1, tworząc pierwszy punkt krzywej kapitału. B2 ma tę samą formułę co B1, a C2 dodaje wartość z C1 do B2. Kopiujesz obie kolumny w dół do wiersza 200. Tak powstaje jedna pełna sekwencja roczna.

Powielając te dwie kolumny w bok 1 000 razy (B–C, D–E, F–G i tak dalej) dostajesz tysiąc niezależnych krzywych. Z wartości końcowych liczysz =PERCENTYL.PRZEDZ.ZAMK(zakres; 0,5) dla mediany, dla 0,05 i 0,01, żeby zobaczyć najgorsze pięć i jeden procent. Klawisz F9 przelicza wszystkie losowe wartości od nowa, więc każde naciśnięcie to świeży tysiąc symulacji. To naprawdę wystarcza.

Jak zrobić to samo w Pythonie z bootstrapem

Python daje dwie rzeczy, których Excel nie da. Po pierwsze — szybkość, więc tysiące symulacji trwają sekundy zamiast minut. Po drugie, i ważniejsze, pozwala na bootstrap: losowanie nie z założonych parametrów, tylko z prawdziwej listy twoich historycznych transakcji.

Importujesz NumPy, ładujesz listę 100 lub więcej rzeczywistych P/L z dziennika i piszesz coś w stylu nowa_sekwencja = np.random.choice(historia, size=200, replace=True). Funkcja np.cumsum zamienia pojedyncze wyniki w krzywą kapitału, a pętla wokół tego daje tysiąc niezależnych przebiegów. Percentyle liczysz przez np.percentile, a Matplotlib pozwala narysować spaghetti plot — wszystkie tysiąc krzywych nałożonych na siebie z wyróżnioną medianą i pasem 5–95 percentyla.

Bootstrap odtwarza realne ogony rozkładu — grube straty, klastrujące się ruchy, kilka rekordowo dobrych transakcji w sezonie zmienności. Założenia parametryczne tego nie zrobią, bo nie zakładają, że twoje transakcje mają taki rozkład, jaki naprawdę mają.

„Reward-to-risk ratios make almost no sense without including position sizing in the equation. Through position sizing, you can achieve almost any objective you'd like." — Van K. Tharp, Trade Your Way to Financial Freedom, McGraw-Hill, 2007

Uczciwe ograniczenia — czego Monte Carlo nie zrobi

Symulacja parametryczna stoi na dwóch założeniach: transakcje są niezależne, a rozkład wyników stacjonarny. W realnym rynku oba te warunki bywają złamane jednocześnie. Straty potrafią się klastrować — gdy zmienia się reżim rynkowy, kilka transakcji z rzędu pójdzie w tę samą stronę i model losujący niezależnie z tej samej dystrybucji tego nie odtworzy.

Drugi problem to to, że symulacja używa tej samej historii, którą jej dasz. Jeśli twoje 100 transakcji obejmuje wyłącznie trend wzrostowy na EUR/USD, Monte Carlo nie powie ci, jak strategia poradzi sobie w długiej konsolidacji ani w nagłym ruchu na 200 pipsów po danych z USA. Stąd warto łączyć symulację z walk-forward analysis, która testuje strategię w kolejnych oknach czasowych i wychwytuje degradację edge'u.

Najczarniejsze obsunięcia w realnym handlu często wyglądają gorzej niż 1-procentowy percentyl z Monte Carlo, a nie lepiej. Wniosek jest jeden: traktuj wynik symulacji jako probabilistyczną podłogę, nie sufit, a kontekst matematyczny tego, dlaczego pojedynczy backtest niedoszacowuje ryzyka, dobrze podsumowuje rozdział o matematyce strat i risk of ruin w kursie MyBank.pl.

Co zrobić jutro, żeby rzeczywiście to wykorzystać

  1. Zbierz historię co najmniej 100 zamkniętych transakcji z dziennika lub z eksportu z platformy. Mniej niż 100 daje statystykę zbyt szumną, żeby Monte Carlo cokolwiek powiedział o ogonach rozkładu. Jeśli masz mniej, popracuj jeszcze sześć–dwanaście tygodni i wróć do tego ćwiczenia z większą próbą.
  2. Otwórz pusty arkusz Excela i zbuduj prostą wersję parametryczną opisaną powyżej. Wpisz swoją skuteczność, średnią wygraną, średnią stratę i kapitał, powiel kolumny tysiąc razy, naciśnij F9 i przyjrzyj się rozrzutowi wartości końcowych. To zajmie godzinę i pokaże ci, jak szeroki wachlarz wyników kryje się za twoim „średnim rokiem".
  3. Policz percentyl 5-procentowy maksymalnego obsunięcia z tysiąca symulacji. Jeśli pokazuje ci 30 procent kapitału, a twoja realna tolerancja psychologiczna kończy się na 15 procentach, masz problem nie ze strategią, tylko z wielkością pozycji — zmniejsz ryzyko na transakcję o połowę i przelicz ponownie, aż 5-procentowa podłoga zmieści się w twojej granicy bólu.
  4. Po roku rzeczywistego handlu uruchom symulację po raz drugi z nową historią i porównaj rozkład z tym sprzed roku. Jeśli mediana spadła, a ogony się rozszerzyły, twoja przewaga się degraduje — czas zacząć rozmowę o tym, czy strategia wciąż działa, a nie tylko o tym, jak ją pielęgnować.
Jarosław Wasiński
O autorze

Jarosław Wasiński

Redaktor naczelny MyBank.pl · Analityk finansowy i rynkowy

Niezależny analityk i praktyk z ponad 20-letnim doświadczeniem w sektorze finansowym. Twórca i redaktor naczelny portalu MyBank.pl, działającego od 2004 roku. Analiza fundamentalna rynków walutowych i makroekonomicznych od 2007 roku.

Źródła i bibliografia

  1. Bank for International Settlements Minimum capital requirements for market risk (d457) · Bazylejski standard pokazujący, jak instytucje liczą ryzyko rynkowe za pomocą expected shortfall i historycznej symulacji — analog Monte Carlo dla portfela. www.bis.org ↗
  2. Van Tharp Institute About Van K. Tharp · Strona biograficzna potwierdzająca autorstwo książki „Trade Your Way to Financial Freedom" (McGraw-Hill) i jego pracę nad position sizingiem oraz symulacją Monte Carlo dla traderów detalicznych. www.vantharp.com ↗
  3. NumPy Developers numpy.random.choice — Random sampling · Oficjalna dokumentacja funkcji losowania z powtórzeniami; podstawowe narzędzie do bootstrap resampling listy transakcji w Pythonie. numpy.org ↗
  4. Python Software Foundation random — Generate pseudo-random numbers · Oficjalna dokumentacja biblioteki standardowej Pythona z funkcjami random.choices i random.sample, używanymi do prostych symulacji Monte Carlo bez NumPy. docs.python.org ↗

Najczęstsze pytania

Czym jest symulacja Monte Carlo strategii tradingowej?

Monte Carlo to metoda probabilistyczna nazwana od kasyna w Monako. W tradingu polega na tym, że bierzesz listę swoich historycznych transakcji lub statystykę strategii — skuteczność, średnią wygraną, średnią stratę — i zamiast oglądać jedną krzywą kapitału, jaką dała historia, generujesz tysiąc nowych sekwencji w losowej kolejności. Każda z nich ma te same parametry, ale inną kolejność wygranych i strat, więc tworzy inny rysunek konta. Po co: pojedynczy backtest to jedna realizacja. Wariancja wokół niej bywa ogromna. Ta sama strategia o oczekiwanej wartości około 19 euro na transakcję i 200 transakcjach w roku potrafi w symulacjach Monte Carlo dać medianę bliską 3 750 euro rocznie, ale najgorszy percentyl pięcioprocentowy schodzi do 500 euro, a najlepszy pięcioprocentowy wybija do 7 500 euro. Wachlarz jest duży nawet przy tej samej przewadze. Najczęstsze nieporozumienie: „w zeszłym roku strategia dała 5 000 euro, więc w tym dam podobnie". Monte Carlo pokazuje, że realny zakres przy stałej przewadze może obejmować od 1 000 do 10 000 euro i nie ma w tym nic dziwnego — to po prostu wariancja.

Jak zrobić symulację Monte Carlo w Excelu?

Najprostsza wersja nie wymaga makr ani VBA. W komórkach A1–A5 wpisujesz parametry: skuteczność strategii (na przykład 0,55), średnią wygraną (na przykład 100), średnią stratę (na przykład minus 80), liczbę transakcji w sekwencji (na przykład 200) oraz kapitał początkowy (na przykład 10 000). W komórce B1 wpisujesz formułę =JEŻELI(LOS()<A1; A2; A3), która symuluje jedną transakcję — funkcja losowa Excela zwraca liczbę z przedziału od zera do jedynki i jeśli trafi poniżej skuteczności, otrzymujesz wygraną, w przeciwnym razie stratę. W komórce C1 dodajesz kapitał początkowy do wyniku z B1. Formuły z B2 i C2 budujesz analogicznie, ale C2 odwołuje się do C1. Kopiujesz w dół do wiersza 200. Tak powstaje jedna pełna sekwencja roczna. Powielając te dwie kolumny w bok 1 000 razy dostajesz 1 000 niezależnych krzywych kapitału. Z wartości końcowych liczysz =PERCENTYL.PRZEDZ.ZAMK(zakres; 0,5) dla mediany oraz dla 0,05 i 0,01, żeby zobaczyć najgorsze pięć i jeden procent. Klawisz F9 przelicza wszystkie losowe wartości od nowa, więc każde naciśnięcie daje świeży tysiąc symulacji. Excel obsługuje to spokojnie i to wystarczy do zrozumienia własnej strategii.

Jak zaimplementować Monte Carlo w Pythonie?

Python potrafi to samo szybciej i pozwala na bootstrap z prawdziwej historii transakcji, a nie tylko z parametrów. Importujesz NumPy, definiujesz parametry strategii i piszesz funkcję, która generuje jedną sekwencję wyników — losowa tablica wartości od zera do jedynki porównywana z hit rate daje wektor zer i jedynek, a funkcja np.where zamienia ten wektor na średnie wygrane i straty. Funkcja np.cumsum zamienia listę pojedynczych P/L na krzywą kapitału. Uruchamiasz tę funkcję w pętli tysiąc razy, zbierasz wartości końcowe i liczysz percentyle za pomocą np.percentile. Mając listę 100 lub więcej rzeczywistych transakcji, używasz np.random.choice(historia, size=200, replace=True), żeby zrobić bootstrap — losujesz nowy ciąg 200 transakcji z powtórzeniami z własnej historii, dzięki czemu zachowujesz prawdziwe ogony rozkładu, których założenia parametryczne nie odtwarzają. Biblioteka Matplotlib pozwala narysować spaghetti plot, czyli wszystkie 1 000 krzywych nałożonych na siebie z wyróżnioną medianą i pasem 5–95 percentyla — pojedynczy obrazek mówi więcej o ryzyku strategii niż dziesięć tabel.

Jakie są ograniczenia Monte Carlo w tradingu?

Monte Carlo nie jest wróżbą i warto to powiedzieć wprost. Podstawowe założenie symulacji parametrycznej to niezależność transakcji oraz stacjonarność rozkładu wyników. W realnym rynku oba te warunki bywają złamane jednocześnie. Straty na rynku potrafią się klastrować — gdy zmienia się reżim rynkowy, kilka transakcji z rzędu może pójść w jedną stronę, czego model losujący niezależnie z tej samej dystrybucji nie odtwarza. Dlatego najczarniejsze drawdowny w realu często wyglądają gorzej niż 1-procentowy percentyl z Monte Carlo, a nie lepiej. Drugi problem to to, że symulacja używa tej samej statystyki, którą wyciągnąłeś z historii. Jeśli historia obejmuje wyłącznie trend wzrostowy na EUR/USD, Monte Carlo nie powie ci nic o zachowaniu strategii w fazie konsolidacji. Co z tego wynika praktycznie: traktuj wynik Monte Carlo jako probabilistyczną podłogę, a nie sufit. Jeśli najgorszy pięcioprocentowy scenariusz mówi o 30-procentowym obsunięciu, zakładaj, że w boju zobaczysz głębsze. Dobieraj wielkość pozycji do tej probabilistycznej podłogi, a nie do uśrednionego oczekiwanego wyniku — wtedy realna porażka cię nie wybije.

Pogłębij temat · pełny przewodnik