Część 6: Nasz prosty robot inwestycyjny otwiera pozycję przy każdej zmianie notowań, więc trzeba ograniczyć jego aktywność. W tym celu napiszemy specjalną funkcję, kontrolującą liczbę świec na wykresie.

Napisany przez nas robot otwiera pozycję długą, gdy na wykresie pojawi się sekwencja trzech wzrostowych świec, i krótką, gdy pojawi się sekwencja trzech świec spadkowych.

Aktualizacja: 06.02.2017 14:31 Publikacja: 31.10.2016 13:04

Część 6: Nasz prosty robot inwestycyjny otwiera pozycję przy każdej zmianie notowań, więc trzeba ograniczyć jego aktywność. W tym celu napiszemy specjalną funkcję, kontrolującą liczbę świec na wykresie.

Foto: Archiwum

Sprawdzając jego działanie na rachunku demo, zauważyliśmy, że zawiera on transakcje zbyt często, a jedynym ograniczeniem jest dla niego wielkość dostępnych na rachunku wolnych środków. Dlaczego tak się dzieje i jak rozwiązać ten problem?

Problem funkcji OnTick()

Zanim przejdziemy do sedna tematu, chcieliśmy zaznaczyć, że tym tekstem wkraczamy na nieco bardziej zaawansowany poziom programowania, do którego zrozumienia potrzebna jest przynajmniej uważna lektura poprzednich materiałów tego dodatku. Ponadto chcieliśmy nadmienić, że wszystkie zaproponowane tutaj rozwiązania dotyczące kodowania poszczególnych elementów robota nie są ani najbardziej efektywne, ani ostateczne. Z programowaniem jest bowiem jak z matematyką – do rozwiązania problemu można dojść na wiele sposobów, a wybór sposobu zależy od preferencji i umiejętności.

Przejdźmy teraz do tytułowego problemu. W poprzednim materiale wspominaliśmy, że instrukcje dla robota umieszczone są wewnątrz funkcji specjalnej „OnTick()", która jest wywoływana za każdym razem, gdy kurs danego aktywa (w przypadku naszego robota jest to para walutowa EUR/USD) wykona minimalny ruch, wynikający z zawarcia jakiejś transakcji na rynku. Tym samym nasz robot z każdym takim tickiem sprawdza, czy warunki otwarcia pozycji są spełnione. Przykładowo – jeśli uruchomiliśmy go na wykresie minutowym, na którym właśnie budowana jest kolejna świeca, a trzy poprzednie były wzrostowe, to z każdym tickiem robot otwierał będzie długą pozycję (dopóki nie zabraknie mu środków na rachunku). Z każdym nowym tickiem robot dostaje bowiem informację, że na wykresie są trzy białe świece.

Ten przykład dobrze ilustruje to, jak istotnym elementem programowania jest przewidywanie różnych możliwych scenariuszy. Musimy pamiętać, że robot będzie działał tak, jak go „nauczymy", sam z siebie nic nie wymyśli, a już na pewno się nie domyśli, że gdzieś popełniamy błąd. Instrukcje muszą więc bardzo precyzyjnie wyjaśniać to, w jaki sposób ma działać nasza strategia. Pamiętajmy, że podczas kompilacji kodu program sprawdza tylko poprawność składni, nie jest natomiast w stanie wychwycić błędów w konstrukcji samej strategii (przykładowo – program nie zwróci błędu, jeśli warunki kupna i sprzedaży ustawiliśmy na odwrót).

Aby rozwiązać problem nadmiernej aktywności naszego robota, musimy zakodować mu kolejny warunek – by kryteria otwarcia pozycji sprawdzał tylko wtedy, gdy na wykresie pojawi się nowa świeca. W tym celu musimy zbudować funkcję logiczną, która zwróci „true", gdy na wykresie pojawi się nowa świeca, i „false", gdy takowa się nie pojawi. Jak to zrobić?

Zmienna statyczna

Sposobów dodania takiego warunku jest dużo. My wybraliśmy propozycję amerykańskiego vlogera Jim'a Dandy'ego(https://www.youtube.com/channel/UC6NkmY-LH2p8tJdpLJ2M7iA) zaprezentowaną w odcinku 11. Kod funkcji logicznej „IsNewCandle()" widoczny jest na obrazku powyżej.

Logika tej funkcji polega w skrócie na tym, że sprawdza ona, czy na analizowanym wykresie pojawiła się nowa świeca czy nie. W tym celu z każdym tickiem będzie ona porównywać aktualną liczbą świec do tej sprzed ticku i jeśli liczby będą sobie równe, to zwróci „false" (bo nie pojawiła się nowa świeca), a jeśli będą różne, to zwróci „true".

Teraz wyjaśnijmy znaczenie poszczególnych elementów kodu funkcji. Nowością jest polecenie „Bars", czyli tzw. zmienna predefiniowana, która przechowuje liczbę świec, które dostępne są na otwartym przez nas wykresie, na którym uruchomiliśmy robota. Innymi zmiennymi predefiniowanymi, które wykorzystywaliśmy już podczas tworzenia naszego robota (przy wpisywaniu parametrów funkcji „OrderSend()"), są „Bid" i „Ask", przechowujące odpowiednie ceny danego instrumentu.

Ponadto w kodzie funkcji „IsNewCandle()" zainicjowana została lokalna zmienna statyczna przechowująca wartości całkowite „BarsOnChart". Zmiennej tej przypisaliśmy na początek wartość 0. To właśnie ta zmienna będzie porównywana ze zmienną „Bars", by ustalić, czy mamy na wykresie nową świecę. Jak to działa? Najpierw program przypisze zmiennej „BarsOnChart" wartość 0, a następnie za pomocą instrukcji warunkowej „If" sprawdzi, czy aktualna liczba świec na wykresie przechowywana w zmiennej „Bars" równa jest wartości zmiennej „BarsOnChart". W pierwszym wywołaniu wartości będą różne (na wykresie jest więcej niż 0 świec), więc funkcja zwróci wartość „true", a robot będzie miał zielone światło, by sprawdzić warunki transakcyjne. Jak widzimy w kodzie, przed instrukcją „return(true)" mamy instrukcję przypisania – zmiennej „BarsOnChart" przypisujemy wartość zmiennej „Bars". Nasza zmienna zostanie więc zaktualizowana – zamiast wartości 0 będzie przechowywać aktualną liczbę świec na wykresie. Ponieważ „BarsOnChart" jest zmienną statystyczną, to przy kolejnym ticku i wywołaniu funkcji „IsNewCandle()" zmienna nie będzie mieć już wartości zero, ale zapamięta liczbę świec sprzed ostatniego ticku. Dzięki temu, dopóki na wykresie nie pojawi się nowa świeca, dopóty wartości przechowywane w zmiennych „Bars" i „BarsOnChart" będą sobie równe, a funkcja będzie zwracać „false" i robot nie będzie z każdym tickiem sprawdzał warunków transakcyjnych. Gdy natomiast liczba „Bars" się zmieni, to funkcja zwróci „true" i po raz kolejny zaktualizuje wartość „BarsOnChart". Do zrozumienia logiki działania tej funkcji potrzeba trochę cierpliwości, więc zachęcamy do skopiowania kodu i sprawdzenia na własnym rachunku, jak działa robot bez funkcji „IsNewCandle()" i wraz z nią (na drugim obrazku jest pokazany cały kod robota). Ponadto zachęcamy do oglądania podlinkowanego vloga.

Na koniec chcieliśmy zwrócić uwagę na jedną rzecz. Otóż funkcja „IsNewCandle()" jest konstrukcją uniwersalną i można ją śmiało skopiować do innego kodu. Jeśli więc ktoś ma problem z zawieraniem transakcji przy każdym ticku, to opisana tutaj propozycja funkcji może się okazać pomocna. Warto też zwrócić uwagę na konstrukcję całego kodu robota – funkcję „IsNewCandle()" stworzyliśmy pod funkcją specjalną „OnTick()", zgodnie z zasadą, że nasze własne „twory" budujemy w przestrzeni globalnej. Aby ją wykorzystać, wystarczy tylko wywołanie jej nagłówka wewnątrz funkcji „OnTick()".

Budowany przez nas robot staje się coraz bardziej przystosowany do warunków rynkowych. Wciąż jednak brakuje mu wielu niezbędnych elementów, w które wyposażymy go w kolejnych częściach tego dodatku.

Inwestycje
Tomasz Bursa, OPTI TFI: WIG ma szanse na rekord, nawet na 100 tys. pkt.
https://track.adform.net/adfserve/?bn=77855207;1x1inv=1;srctype=3;gdpr=${gdpr};gdpr_consent=${gdpr_consent_50};ord=[timestamp]
Inwestycje
Emil Łobodziński, BM PKO BP: Nasz rynek pozostaje atrakcyjny, ale...
Inwestycje
GPW i rajd św. Mikołaja. Czy to może się udać?
Inwestycje
Co dalej z WIG20? Czy zbliża się moment korekty spadkowej?
Materiał Promocyjny
Cyfrowe narzędzia to podstawa działań przedsiębiorstwa, które chce być konkurencyjne
Inwestycje
Ropa naftowa szuka pretekstu do ruchu w górę
Inwestycje
O tym huczy cała Wall Street. Jak Saylor zahipnotyzował inwestorów?