Podstawy programowania strategii w języku MQL4 (część 6)

Kontynuujemy cykl poświęcony budowaniu robotów inwestycyjnych. Dziś pokazujemy, jak stworzyć funkcję sprawdzającą liczbę świec na wykresie. Dzięki niej robot ograniczy liczbę zajmowanych pozycji.

Publikacja: 19.08.2016 06:29

Podstawy programowania strategii w języku MQL4 (część 6)

Foto: Archiwum

W poprzednim odcinku „Profesjonalnego inwestora" pokazaliśmy, jak zbudować prostego robota inwestycyjnego, który będzie otwierał pozycję długą, gdy na wykresie pojawi się sekwencja trzech wzrostowych świec, i krótką, gdy pojawi się sekwencja trzech świec spadkowych. 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()

Na wstępie chcieliśmy zaznaczyć, że dzisiejszym odcinkiem wkraczamy na nieco bardziej zaawansowany poziom programowania, do którego zrozumienia potrzebna jest przynajmniej lektura poprzednich części tego cyklu. 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. Dlatego też zachęcamy czytelników do wysyłania sugestii, uwag i propozycji na nasz adres e-mail, najlepiej e-mail autora tego cyklu.

Przejdźmy teraz do sedna dzisiejszego tematu. Tydzień temu wspominaliśmy, że instrukcje 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 była 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 była kolejna świeca, a trzy poprzednie były wzrostowe, to z każdym tickiem robot otwierał długą pozycję (dopóki nie zabrakło mu środków na rachunku). Z każdą nową transakcją robot dostawał 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ć nasz problem, musimy zakodować robotowi 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ę vlogera (https://www.youtube.com/channel/UC6NkmY-LH2p8tJdpLJ2M7iA) zaprezentowaną w odcinku 11. Kod funkcji logicznej „IsNewCandle()" zaprezentowany jest na obrazku obok. Logika tej funkcji polega w skrócie na tym, że sprawdza ona, czy na 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ż w tym cyklu artykułów (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 statytyczna 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 „Bid" 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 zakutalizowana – 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 nasza dzisiejsza 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()".

W kolejnych odcinkach cyklu będziemy kontynuować rozbudowywanie kodu robota. Pokażemy m.in., jak kontrolować liczbę otwartych pozycji i zarządzać jej wielkością.

[email protected]

Inwestycje
Trzy warstwy regulacji
https://track.adform.net/adfserve/?bn=77855207;1x1inv=1;srctype=3;gdpr=${gdpr};gdpr_consent=${gdpr_consent_50};ord=[timestamp]
Inwestycje
Jak przeprowadzić spółkę przez spór korporacyjny?
Inwestycje
Porozumienia akcjonariuszy w spółkach publicznych
Materiał Promocyjny
Cyfrowe narzędzia to podstawa działań przedsiębiorstwa, które chce być konkurencyjne
Inwestycje
Unikanie sporów potransakcyjnych