Strategia daje nierealistycznie dobre wyniki poprzez podglądanie przyszłości

Jednym z naszych głównych celów przy tworzeniu języka Pine jest dostarczenie użytkownikom jak największej ilości użytecznych narzędzi. Narzędzia te mogą mieć wiele różnych zastosowań, a przy pewnych manipulacjach, niektóre wskaźniki i typy wykresów pozwalają na wyodrębnienie danych z przyszłych słupków lub transakcji (w stosunku do aktualnie przetwarzanego słupka). Oczywiście nie da się uzyskać takich danych, dlatego strategie zbudowane na takich zasadach mogą dawać nierealistycznie zyskowne wyniki w backtestach, ale w czasie rzeczywistym te transakcje przyniosłyby stratę. Błąd polegający na wykorzystywaniu w strategiach informacji z przyszłości jest nazuwany "look-ahead bias".

Niektórzy użytkownicy TradingView nieświadomie lub w złych zamiarach tworzą pomysły i publikują skrypty przy użyciu tych metod. TradingView nie może usunąć samej funkcji, ponieważ w niektórych przypadkach może być ona przydatna, ale jednocześnie jesteśmy zobowiązani do ostrzegania użytkowników przed takim zachowaniem.

Strategie korzystające ze świec w stylu japońskim

Bardzo częstym powodem takiego zachowania jest backtesting strategii na wykresach w stylu japońskim (Renko, Kagi itp.). Problem występuje dlatego, że silnik testowania strategii traktuje każdy słupek jako 4 transakcje, czyli cena otwarcia, zamknięcia, minimum i maksimum (tak jak w przypadku zwykłego wykresu świecowego). Z tego powodu na wykresie Renko silnik testowania strategii może wejść/wyjść z pozycji po cenie, która w rzeczywistości nie wystąpiła. Jeśli dodatkowo ustawisz Rozmiar Pola na wartość mniejszą niż mintick, możesz sprawdzić, czy kolejna cena będzie wyższa, czy niższa od obecnej i wejść/wyjść z pozycji z wyprzedzeniem, zanim silnik testowania strategii przetworzy rzeczywistą cenę.

//@version=4
strategy("My Strategy", overlay=true)
if close < close[1]
    strategy.entry("ShortEntryId", strategy.short)
strategy.close("ShortEntryId", when = close > close[1])

if close > close[1]
    strategy.entry("LongEntryId", strategy.long)
strategy.close("LongEntryId", when = close < close[1])
Jak widać na powyższym zrzucie ekranu, ta prosta strategia pozwala na zawieranie transakcji po cenach bardzo zbliżonych do maksimum i minimum.

Strategie korzystające z parametru calc_on_order_fills = true

Kiedy w funkcji strategii jest określony parametr calc_on_order_fills = true, silnik backtestingowy wykonuje dodatkową kalkulację wewnątrz słupka po zrealizowaniu zlecenia (w przeciwieństwie do zwykłej sytuacji, kiedy strategia jest obliczana tylko na zamknięciu słupka). Jednocześnie podczas kalkulacji, strategia uzyskuje dostęp do wielu dodatkowych parametrów słupka, na przykład wartości maksimum i minimum. Pozwala to na napisanie strategii, która podczas backtestingu będzie wykazywała doskonałą wydajność:
//@version=4
strategy("CalcOnOrderFillsStrategy", overlay=true, calc_on_order_fills=true)

// a variable is used to prevent double entry on the same bar
var lastTimeEntry = 0

longCondition = close > sma(close, 14)  and lastTimeEntry != time
if longCondition
    strategy.entry("LongEntryId", strategy.long)

strategy.exit("exitId", "LongEntryId", limit=high)
lastTimeEntry := time

Na powyższym zrzucie ekranu widać, że wejście następuje po cenie otwarcia słupka, wyjście po jego cenie maksymalnej. Oznacza to, że podczas kalkulacji, po tym jak zlecenie zostało wykonane, ustawiliśmy limit ceny strategy.exit równy maksymalnemu poziomowi słupka, co oczywiście nie jest możliwe w rzeczywistości. 

Parametr lookahead = barmerge.lookahead_on w funkcji security i wszystkich funkcjach security przed Pine v3

Funkcja security w Pine pozwala na żądanie danych z innych symboli i/lub interwałów. W zależności od implementacji może to pozwolić strategii na otrzymywanie danych z przyszłości: jeśli zażądasz ceny zamknięcia lub maksimum słupka dziennego, to podczas testów na danych historycznych strategia może znać te wartości od razu na początku dnia. 

Przed wersją 3 funkcja security zwracała wartość z wyższego interwału, jeszcze zanim powinna być dostępna. To zachowanie zostało naprawione w wersji 3, ale dla zachowania kompatybilności, parametr lookahead został dodany do funkcji security. Jego wartość jest domyślnie ustawiona na false (tj. podgląd przyszłości jest wyłączony), ale można go włączyć, ustawiając wartość parametru lookahead na barmerge.lookahead_on).

Przykład zyskownej strategii zbudowanej przy użyciu tej funkcji:

//@version=4
strategy("My Strategy", overlay=true)
dayStart = security(syminfo.tickerid, "1D", time, lookahead=barmerge.lookahead_on)
dayHigh = security(syminfo.tickerid, "1D", high, lookahead=barmerge.lookahead_on)
dayLow = security(syminfo.tickerid, "1D", low, lookahead=barmerge.lookahead_on)

// entry at first bar of a day
if time == dayStart
    // distance to daily high is further, so we can earn more
    if abs(open - dayHigh) > abs(open - dayLow)
        strategy.entry("LongEntryId", strategy.long)
        strategy.exit("exitLongId", "LongEntryId", limit=dayHigh)
    else
        strategy.entry("ShortEntryId", strategy.short)
        strategy.exit("exitShortId", "ShortEntryId", limit=dayLow)
        
plot(dayHigh)
plot(dayLow)

Na pierwszym słupku analizujemy, czy cena przesunie się bardziej w górę, czy w dół w stosunku do ceny otwarcia i na tej podstawie otwieramy pozycję długą lub krótką, a następnie wychodzimy odpowiednio po cenie maksimum lub minimum dnia.

Zauważ, że nie we wszystkich przypadkach, w których funkcja security() korzysta z parametru barmerge.lookahead_on, strategia podgląda przyszłość: jeśli na przykład zmienimy kod funkcji security, zamieniając time/high/low odpowiednio na time[1]/high[1]/low[1], otrzymalibyśmy wartości dla już zamkniętych słupków. jest to metoda często używana przez doświadczonych programistów, aby uzyskać dane z funkcji security() bez ryzyka wystąpienia lookahead. 

Aktualnie są to wszystkie znane sposoby, aby strategia mogła podglądać przyszłość. Mamy nadzieję, że ten opis pozwoli Ci stworzyć strategie pozbawione tych wad, a także uniknąć strategii już opublikowanych, których autorzy wykorzystują te cechy w swoich pomysłach.