Dlaczego martyngał wygląda w backteście doskonale
Mechanizm, przez który podwajanie pozycji daje idealną krzywą w teście. Plus kod wykrywający ten schemat w cudzym ekspercie, bez dostępu do źródeł.
2 fragmenty kodu z tej strony przeszły przez kompilator MetaEditor build 6090, 2026-08-05.
To nie jest strona o tym, czy martyngał ma sens. To strona o tym, dlaczego raport z testu nie jest w stanie pokazać ryzyka, które ta konstrukcja niesie — i jak to zobaczyć mimo wszystko.
Rozróżnienie jest ważne, bo problem nie leży w strategii, tylko w narzędziu pomiarowym.
Mechanizm
Podwajanie po stracie i siatka zleceń mają wspólną cechę: strata pozostaje niezrealizowana, dopóki cała konstrukcja się nie zamknie. Pozycja, która idzie przeciwko tobie, nie trafia do bilansu — jest tylko obsunięciem kapitału. Gdy cena w końcu wróci, wszystko zamyka się jednocześnie z małym zyskiem.
Krzywa bilansu składa się wtedy wyłącznie z wygranych. Nie dlatego, że nie ma strat, tylko dlatego, że strata jest zapisywana w bilansie dopiero w chwili, gdy przestaje być stratą.
Stąd bierze się wykres, który wygląda jak prosta rosnąca linia — i to jest dokładnie ten wykres, który trafia na zrzuty ekranu.
Dwie różne miary obsunięcia
Tester liczy obie i to jest cała odpowiedź:
| Miara | Co mierzy | Co pokazuje przy martyngale |
|---|---|---|
| obsunięcie bilansu | spadki zamkniętych wyników | znikome |
| obsunięcie kapitału | spadki wraz z pozycjami otwartymi | prawdziwe |
Raport pokazuje obie, ale wykres domyślnie rysuje bilans. Różnica między nimi jest miarą tego, ile ryzyka konstrukcja ukrywa.
double OnTester()
{
double obsuniecieBilansu = TesterStatistics(STAT_BALANCE_DD);
double obsuniecieKapitalu = TesterStatistics(STAT_EQUITY_DD);
if(obsuniecieKapitalu <= 0.0)
return 0.0;
//--- ile razy prawdziwe obsunięcie przekracza to widoczne w bilansie
double ukrycie = obsuniecieKapitalu / MathMax(obsuniecieBilansu, 0.01);
PrintFormat("obsuniecie bilansu %.2f, kapitalu %.2f, stosunek %.1f",
obsuniecieBilansu, obsuniecieKapitalu, ukrycie);
//--- przebieg, w którym kapitał spada wielokrotnie głębiej niż bilans,
//--- nie zasługuje na miejsce w tabeli wyników optymalizacji
if(ukrycie > 5.0)
return 0.0;
return TesterStatistics(STAT_PROFIT) / obsuniecieKapitalu;
}Czego tester nie modeluje
Nawet obsunięcie kapitału nie oddaje pełnego ryzyka, bo tester upraszcza trzy rzeczy, które przy takiej konstrukcji decydują o wszystkim:
Wezwanie do uzupełnienia depozytu. Tester zamyka pozycje przy poziomie stop out, ale robi to w warunkach idealnych: bez opóźnienia, bez poślizgu, po cenie z historii. Na rachunku zamknięcie przymusowe odbywa się w chwili największej zmienności i po najgorszych cenach dnia.
Rozszerzenie spreadu. Przy siatce liczba otwartych pozycji rośnie dokładnie wtedy, gdy rynek się rozjeżdża. Tester nalicza spread z historii albo stały — nie modeluje tego, że przy dziesiątej pozycji koszt wejścia bywa kilkukrotnie wyższy.
Limity brokera. Limit wolumenu, limit liczby pozycji i limit zleceń oczekujących w teście zwykle nie istnieją. Na rachunku siatka zatrzymuje się w połowie i to jest najgorszy możliwy moment.
Rozpoznanie w cudzym ekspercie
Kupiony ekspert nie ma źródeł, ale historia rachunku ma wszystko, czego trzeba. Martyngał zostawia charakterystyczny ślad: wolumen rośnie po stracie.
void SprawdzSchematWolumenu(const ulong magic, const int dniWstecz)
{
if(!HistorySelect(TimeCurrent() - dniWstecz * 24 * 3600, TimeCurrent()))
{
Print("Nie udalo sie wczytac historii.");
return;
}
double poprzedniWolumen = 0.0;
double poprzedniZysk = 0.0;
int podwojen = 0;
int wejsc = 0;
for(int i = 0; i < HistoryDealsTotal(); i++)
{
ulong bilet = HistoryDealGetTicket(i);
if(bilet == 0)
continue;
if(HistoryDealGetInteger(bilet, DEAL_MAGIC) != (long)magic)
continue;
if(HistoryDealGetInteger(bilet, DEAL_ENTRY) != DEAL_ENTRY_IN)
continue;
double wolumen = HistoryDealGetDouble(bilet, DEAL_VOLUME);
wejsc++;
//--- wejscie wiekszym wolumenem tuz po stracie
if(poprzedniZysk < 0.0 && wolumen > poprzedniWolumen * 1.5)
podwojen++;
poprzedniWolumen = wolumen;
poprzedniZysk = HistoryDealGetDouble(bilet, DEAL_PROFIT);
}
PrintFormat("wejsc: %d, w tym po stracie z powiekszonym wolumenem: %d (%.0f%%)",
wejsc, podwojen, wejsc > 0 ? 100.0 * podwojen / wejsc : 0.0);
}Wynik powyżej kilkunastu procent oznacza, że wielkość pozycji zależy od wyniku poprzedniej transakcji, a nie od ryzyka. Nie przesądza to o niczym — przesądza o tym, że raport z bilansu nie opisuje tej strategii.