Zanim
utoniecie w programowaniu proponuję przeprowadzić prosty test. Czy
będziecie w stanie grać stworzonym automatem w realu? Wbrew pozorom nie
jest to łatwe. Bo jak nie macie ku temu predyspozycji - próżny Wasz trud
- szkoda czasu.
Test stróża
Weźcie
jakąś strategię, którą da się prowadzić ręcznie w perspektywie jednego
dnia i która w Waszej ocenie może być "profitowa". Może coś w tym stylu:
sygnał otwarcia - zmknięcie na TP lub SL. Obstawiacie na koncie
rzeczywistym jakimiś drobnymi stawkami. Ot tyle aby poczuć "emocje".
I
teraz najtrudniejsze. Przez miesiąc - dzień po dniu - bez względu na
narastające wyniki: wstajecie, otwieracie zlecenie, ustawiacie parametry
i zamykacie platformę - zapominacie o pozycji, czas wolny !!! Przed snem sprawdzacie czy coś się "złapało" czy jeszcze nie.
Jak
nie dacie rady tak żyć przez miesiąc to po co Wam robot? Szukacie
posady stróża? Chcecie stale kontrolować robota i może jeszcze go
"poprawiać" z ręki? Nie lepiej od razu poszukać posady stróża (w tym
nocnego) niż tworzyć robota? Pieniądz pewniejszy, a stres mniejszy.
Pomijając
wszelkie inne aspekty robotyki to jest chyba największa bariera z jaką
trzeba sobie poradzić. Bariera zaufania do algorytmu. W praktyce
bariera zaufanie do własnej osoby. Być może wystarczy Wam półautomat
(zmiana parametrów zleceń bezpośrednio z wykresu) np:
Kryterium
Kelly'ego jest dobrze opisane na polskich stronach dotyczących hazardu
więc nie ma co się rozpisywać. Oni tam nawet nie cofają się przed
używaniem zwrotu "giełda" zakładów sportowych. Jest też dobrze znane
części graczy z rynku futures warszawskiej giełdy na kontrakty
terminowe. Wiecie to taki twardy giełdowy hazard gdzie można stracić
więcej niż się postawiło. Przebitka stawkowania do 1:10, więc przy
Forexie to i tak kontrakty wyglądają na bardzo łagodny hazard. Na
Forexie maxymalne przebitki sięgają 1:100 czy 1:500, a są i tacy
brokerzy co pozwalają na jeszcze wyższe stawkowanie. W powiązaniu z
niskimi wymogami kapitałowymi do otwarcia zakładu powstaje mieszanka
wybuchowa rozsadzająca portfele najtwardszych (najmłodszych) graczy.
Nawet niewielka niekorzystna zmiana kursu wyrzuca niedokapitalizowanych
graczy z gry.
Ten temat jakoś w forexowych kręgach jest pomijany. Może chodzi o to aby ludzie tracili szybko?
Moja próba zainicjowania dyskusji na pewnym forum nie wzbudziła
zainteresowania. Niestety na forexie mało kto myśli co stanie się z jego
kontem za miesiąc. Gra na ile broker pozwala.
Paul Wilmott on Quantitative Finance, Chapter 17, Kelly criterion
O co chodzi, że nie wychodzi
Chodzi
o pieniądze. Przy pomocy kryterium maxsymalizujemy wartość oczekiwaną
gry - spodziewany wynik. Gra jest tak prowadzona aby maxymalizować
geometryczną stopę zwrotu. Gra ma tylko jedno optymalne rozwiązanie.
Filozofia jest tu inna niż przykładowo w metodzie portfelowej, w której
możemy wybierać pomiędzy wieloma równoważnymi rozwiązaniami. Stosując
kryterium mamy trzy w jednym: optymalizujemy stawkę zakładu,
minimalizujemy prawdopodobieństwo bankructwa oraz maxymalizujemy tempo
wzrostu naszych zysków. Krótko mówiąc wyliczamy ile procent posiadanego
kapitału postawić na zdarzenie aby zmaksymalizować zysk i zminimalizować
stratę.
Założenia - jak zwykle najsłabsze ogniwo
Poprawne zastosowanie kryterium wymaga spełnienia warunku:
Bułka z masłem. Strategia większego jelenia (idioty) - klucz do sukcesu na Forexie Jak
nie zarabiamy to stosowanie kryterium nic nam nie pomoże - szkoda na
nie czasu - stan rachunku szybciej czy wolniej będzie i tak zmierzał do
zera. Generalnie ilość pieniędzy jaką zarabiamy musi być większa od
ilości pieniędzy jaką tracimy (może coś takiego: ilość zleceń zyskownych
razy średni zysk > ilości zleceń stratnych razy średnia strata albo
prawdopodobieństwa wygranej razy średnia wygrana > prawdopodobieństwa
porażki razy średnia strata). W przeciwnym wypadku kryterium da wynik:
nie obstawiaj - w sensie prawdopodobieństwa: obstaw zdarzenie przeciwne.
Ze względu na koszty (spread) w praktyce nie da się otworzyć zakładu
przeciwnego (to odpowiada na pytanie: dlaczego nie chcą działać
strategie przeciwne do przegrywających).
Wspomnę o jeszcze jednym
warunku - stawka wyliczana z kryterium powinna dawać dzielić się w
nieskończoność. Przy odpowiednio dużym stanie konta warunek ten można
zlekceważyć. W przypadku zakładów bukmacherskich warunki zapisywane są
zwykle jako: prawdopodobieństwo wygranej wg. naszej oceny większe od 0,5
oraz prawdopodobieństwo wygranej wg. naszej oceny razy kurs zdarzenia
wg. buka większe od 1. Przykładowo kurs zdarzenia 1,85 odpowiada
prawdopodobieństwu 54% (1/1,85) czyli nasza ocena prawdopodobieństwa
musi być wyższa - przewaga nad bukiem - dla 0,55x1,85>1.
Ale to wredne
Kryterium
ma swoje maximum. Widać to dobrze pod koniec klipu wyżej, albo na
grafice niżej. Co to znaczy? Nie można bezkarnie zwiększać stawki
zakładu. Dalsze zwiększanie stawki ponad maximum wyliczone z kryterium
do niczego dobrego nie prowadzi. Skutek jest wręcz odwrotny - zyski z
gry spadają. Można mieć bardzo dobry system, ale można go bardzo łatwo
położyć przeholowaną stawką. Nie ma sensu dalsze zwiększanie stawki.
Matematycznie wygląda to tak, że przy stawkach zmierzających do
podwojenia ponad optimum tempo wzrostu kapitału zmierza do zera.
Tempo
przyrostu naszych zysków powiązane jest ze skutecznością systemu i
wielkością ryzykowanej stawki. No nie jest to informacja warta
reklamowania przez brokerów. Być może dlatego kryterium jest
"zapomniane" na forexie - niech ludziska stawiają na ile broker pozwala -
szybciej/więcej przegrają. Po co mają wiedzieć, że śrubowanie stawki
może ich jedynie doprowadzić do MC niezależnie od zastosowanej
strategii. Po coś ten "lewar" jest. Nie wszyscy muszą wiedzieć, że stawka zmienia się liniowo, a ryzyko geometrycznie.
Nie
jest to też dobra informacja dla "producentów" wszelkiego rodzaju
systemów zarabiających podobno niewiarygodne ilości pipsów. Można
oszacować skuteczność takiej metody, zestawić z proponowaną stawką i
sprawdzić czy to w ogóle jest możliwe w dłuższym horyzoncie. Ocenić w
jakim stopniu podawane informacje mogą być wiarygodne.
Wykres funkcji
The Kelly Criterion has applications in gambling and stocks. This video explains the concept and how to use it in a variety of situations. There are 4 examples, including coin flipping, stock investing, football betting, and lotteries.
Understanding Kelly Criterion
Jak z tego skorzystać
Całą
naszą dotychczasową grę na forexie potraktujemy jako jeden zakład. Kasę
straconą dodajemy do zarobionej i liczymy ile % stanowi kasa zarobiona.
Przykładowo niech to będzie 52% - wygrana jest większa od przegranej,
system zarabia. Ile w takim razie należy postawić w kolejnym zakładzie?
Liczymy: 52% to inaczej 0,52 podwajamy i odejmujemy 1. Zostaje
0,04 czyli kwotę jaką mamy przeznaczoną na grę mnożymy przez 0,04 (4%) i
już wiemy ile można maxsymalnie postawić kwotowo (odległość SL) w
kolejnym zakładzie. Po każdym zagraniu aktualizujemy: stan konta,
skuteczność strategii i wyliczamy stawkę na kolejny zakład.
Krótko
mówiąc nie należy nigdy ryzykować więcej niż wynosi nasza statystyczna
przewaga nad organizatorem zakładów (brokerem). Jakie to proste. Chyba
za proste aby to zamieszczać w literaturze przedmiotu czy "uczyć" na
forexowych szkoleniach. Wystarczy zapamiętać ten "uproszczony" sposób liczenia i przed
postawieniem kolejnego zakładu na forexie zastanowić się: czy aby nie za
dużo stawiam?
Jeśli - posiadając bardzo dobrą strategię o
skuteczności 52% (już po kosztach) - zaczniecie stawiać z 8% na zakład
to MC macie pewne jak w banku. Myślicie, że skuteczność 52% to "kiepściocha"? 4% przewagi? Pomyślcie:
kasyna z europejską ruletką mają mniejszą przewagę, i to przed kosztami,
a i tak "jakoś" sobie radzą - robią z właścicieli milionerów. Jak mało
potrzeba do "szczęścia".
Kryterium
Kelly'ego nie jest lekiem na całe zło. Zastosowanie kryterium mówi
jedynie o tym, że prawdopodobieństwo podwojenia kapitału jest większe od
prawdopodobieństwa utraty połowy kapitału. Nadal jednak
prawdopodobieństwo wcześniejszej utraty połowy kapitału niż jego
podwojenia jest bardzo znaczne: 1:3. Z tego powodu w praktyce zaleca się
stosować co najwyżej 1/2 Kelly, 1/3 Kelly lub 1/4 Kelly, a przy
większej przewadze nie więcej niż 1/15. Ma to swoje matematyczne
uzasadnienie w tym, że stopa zwrotu przy tej metodzie spada wolniej niż
stawka zakładu. Zmniejszenie stawki o połowę nie spowoduje spadku zysków
o połowę.
Chyba najsłabszym ogniwem w tej metodzie jest
potrzeba zgromadzenie wartościowego materiału statystycznego potrzebnego
do poprawnego wyznaczenia skuteczności stosowanej strategii. Błąd w
szacowaniu skuteczności może mieć tu opłakane skutki (nadstawkowanie).
Jak pamiętamy stosowanie kryterium ma tylko wtedy sens gdy dysponujemy
wygrywającą strategią - więcej zarabia niż traci. Wtedy resztę "roboty"
wykona za nas Pani Statystyka. Niestety na forexie króluje gra na "widzi
mi się".
Podstawowe pytanie: czy naprawdę posiadamy zarabiającą
strategię? Czy jej dodatnia skuteczność została stwierdzona w oparciu o
odpowiednio duży materiał statystyczny zebrany na rzeczywistym rynku?
Kryterium Kelly jest metodą, której siła opiera się na statystyce -
konsekwentnym powtarzaniu tak strategii jak i obliczeń po każdym
zagraniu. Zbiór przypadkowych danych z gry "na czuja" czy podobny mix
zleceń to za mało do jej praktycznego wykorzystania. Pomiar skuteczności
nie może być dziełem przypadku, 51% czy 52% czy 53% robi sporą różnicę i
może zdecydować o naszym być albo nie być. Trzeba pamiętać, że w
klasycznym hazardzie teoretyczny rozkład prawdopodobieństwa jest z góry
znany. Na forexie nie mamy takich luxusów. Nie znamy wszystkich
możliwych wyników i nie będziemy znać.
CZŁOWIEK ROZSĄDNY NIE GRA W GRY O NIEJASNYCH REGUŁACH.
Kolejne
schody pojawią się gdy będziemy utrzymywać więcej niż jedno otwarte
zlecenie. Błąd szacowania wzrośnie z powodu niezamkniętych zleceń. Z
kolei niedokapitalizowani uczestnicy będą zmuszeni do znacznego
zaokrąglania wyników aby "wpasować" się w dopuszczalny rozmiar kwotowy
zleceń. Dla bezpieczeństwa należy zaokrąglać wyłącznie w dół. Czyli
uogólniając w celach praktycznych - nigdy nie stawiamy więcej niż...
Kryterium jest jak ściana, do której nie należy się nigdy zbliżać aby
nie rozbić się o MC.
Jest to metoda dla ludzi, którzy potrafią
konsekwentnie stosować daną strategię w długim terminie (setki zleceń).
Pieniądze przychodzą tu z "czasem". Dla wygładzenia zmienności wyników
zaleca się stosować kryterium na zdywersyfikowanym portfelu instrumentów
finansowych. Pamiętajcie:
kryterium stanowi optimum w sensie statystycznym.
... będę z Tobą (Kelly)
Blue Affair & Sasha Dith
Gotowa funkcja
...
najważniejsze. Po lewej macie link MQL4/KJK, a pod nim do pobrania
podręcznik. Pod sam koniec podręcznika (173 strona) jest gotowa funcja
kryterium, którą można "dokręcić" do robota.
[strona nie istnieje, próba dostępu kwiecień 2021]
Funkcja oblicza
stosunek transakcji wygrywających do wszystkich transakcji o niezerowym
saldzie oraz stosunek średniej wygranej do średniej straty i na tej
podstawie wyznacza kryterium. Komu nie wystarcza zapamiętać aby nigdy
nie stawiać więcej niż wynosi jego przewaga nad brokerem oraz ma
zacięcie matematyczne może przeanalizować podaną funkcję i coś niecoś
sobie ulepszyć...
Stosunek średniej straty do średniego zysku
obliczany jest w ujęciu kwotowym. Proponuję rozważyć obliczanie w ujęciu
procentowym. Czyli średni przyrost procentowy do średniego spadku
procentowego. Przejaskrawiony przykład: przyrost o 1% ze 100$ wyniesie
1$, przyrost o 1% przy 1000$ wyniesie 10$. Skok 10x, ale procentowo
ciągle jest to to samo. Pamiętacie: wynik kryterium jest podawany w
procentach, a nie kwotowo.
Idealna strategia
Idealną
strategią do zastosowania kryterium będzie zarabiająca strategia
(pozytywna wartość oczekiwana) o stabilnych w czasie parametrach -
powtarzalność, prawdopodobieństwo, średnia wygrana, średnia strata.
Kryterium wykorzystuje średnie - im mniejszy rozrzut pojedynczych
wyników tym lepiej. Natomiast idealny użytkownik to ktoś z bardzo grubym
portfelem - niestety bez pieniędzy znacznie trudniej zarobić
pieniądze.
Przykładowo: przy małym kapitale będzie nas stać na grę na jednym
instrumencie. W takim przypadku maksymalizując stopę zwrotu
(dopuszczalną stawkę zakładu) łatwo możemy rozbić się o MC. Przy dużym
kapitale możemy grać na ile Kelly pozwala na wielu instrumentach. Część
rynków zamknie się zapewne na MC, ale sumaryczna stopa zwrotu dla całego
portfela zostanie zmaksymalizowana, a ryzyko zminimalizowane - korzyści
z dywersyfikacji. Z powodu jak wcześniej ktoś kto gra małym kapitałem -
bez dywersyfikacji - musi grać ostrożniej jeśli nie chce skończyć na MC
tym samym jego stopa zwrotu będzie niższa niż kogoś kto może sobie
pozwolić na grę zdywersyfikowaną. Na forexie łatwo rozpoznacie tych co
nie mają pieniędzy, wbrew matematyce grają najagresywniej.
Gra
na forexie to prosta gra wygrał-przegrał. W przypadku wyścigów konnych
jest trudniej bo startuje wiele zakładów na raz. Ile należy postawić na
dowolnego konia oblicza się w 4 etapach. Pamiętajcie, że jak przyjmują
zakład 1:15 to tak naprawdę szanse na zwycięstwo konia oceniają na 1:16.
Dywersyfikacja w celu poprawy wyników polega w tym przypadku na
obstawianiu więcej niż jednego konia w danym wyścigu. Jest to jednak
ułomna dywersyfikacja ponieważ nie mamy do czynienia ze zdarzeniami
niezależnymi.
Podobno Kelly nigdy nie wykorzystał swojej formuły w praktyce. Zmarł w 1965 roku w wieku 41 lat. Dopadł go udar na ulicy.
Wzorek
No i chyba nie uda się bez wzoru: Kelly% = W - [(1 - W) / R]
W odniesieniu do forexiku może tak:
W
- prawdopodobieństwo - w tym przypadku liczone jako trafność czyli %
wygranych zleceń, obliczamy stosunek zleceń wygranych do sumy zleceń
wygranych i przegranych
R - w tym przypadku liczone jako
skuteczność czyli wskaźnik średniego zysku % z transakcji wygranych do
średniej straty % z transakcji przegranych, zastosowanie ujęcia %
pozwala nam ujednolicić różne stawki kwotowe
Przykładowo:
Na
sto zleceń były 52 wygrane czyli prawdopodobieństwo (trafność) 52/100=
0,52. Średni przyrost kapitału po każdym zleceniu wygranym był 1,1%
natomiast średni spadek kapitału po każdym zleceniu przegranym był 1%.
Skuteczność 1,1/1=1,1. Kelly% = 0,52 - [(1 - 0,52) / 1,1]
I co z tego
Cholercia.
Badania na historycznych danych finansowych pokazały, że wyliczane
stawki są prawie identyczne jak stawki wyliczane na podstawie danych
losowych. Sporo roboty w to włożył Ed Thorp
(pogrzebcie w internecie, nie mylić z Tharp'em). Profesor matematyki, a
jednocześnie hazardzista. Zasłynął książką z 1962, w której wykazał, że
licząc karty w blackjack'u można pokonać kasyno. Sprawdził to w
praktyce grając w kasynach uzbrojony w system liczenia kart i system
stawkowania. Był też pionierem wykorzystania komputerów podczas gry w
kasynach. Domyślacie się jak kasyna go polubiły. Musiał się bawić w
przebieranki i inne cuda na kiju. Impas pomiędzy graczami w blackjack'a i
kasynami skończył się w ten sposób, że kasyna wprowadziły grę 4ema
taliami zamiast jednej. Natomiast Thorp wszedł do panteonu sław związanych z blackjack'iem.
Według
wyliczeń Thorp'a majątek Warrena Buffetta rozrastał się zgodnie z
zasadami kryterium. Sam Thorp chwali się 20% wieloletnią stopą zwrotu
(dodam tylko, że jego fundusz hedgingowy był oskarżany o nielegalne
praktyki i został zlikwidowany). Wykręcanie wyższych zwrotów okazuje się
matematyczną niemożliwością lub zwykłym szczęściem ?
[strona nie istnieje, próba dostępu kwiecień 2021] Znajdziecie na niej i to całkowicie za darmo takie pozycje jak: THE KELLY CRITERION IN BLACKJACK, SPORTS BETTING, AND THE STOCK MARKET czy BEAT THE MARKET Przy
okazji porównajcie czym się różni strona kogoś co coś potrafi od setek
stron ludzi, którzy raczej nic nie potrafią, a jedynie próbują Wam
sprzedać prawie wszystko.
Na koniec wypada wspomnieć o "ulepszonej" wersji Kelly. Kiedy nasza
przewaga w grze wynosi 10%, 20% albo i ze 30% stawka wyliczana z
kryterium rośnie do "astronomicznych" rozmiarów w stosunku do
posiadanego kapitału. W takich przypadkach kilka stratnych transakcji z
rzędu może doprowadzić do finansowej demolki. Chłopaki sprawdźcie sami. Z
tego powodu zaleca się przy takiej przewadze nie stawiać więcej niż
1/15 wyliczonej stawki. Z tym problemem zmierzył się:
Experyment
zaproponowany przez Ralpha polegał na rozegraniu 100 prób w grze, w
której prawdopodobieństwo wygranej wynosi 60%, a pula startowa 1000$.
Wygrywamy stawkę lub przegrywamy stawkę. O wielkości stawki decyduje
gracz. Proste - na sto zagrań wygramy jakieś 60 razy - przewaga po
naszej stronie. Trudno nie zarobić. A jednak zaledwie 2 osoby na 40
kończyło grę z wynikiem dodatnim. Jak to możliwe? Co ciekawe Vince do
experymentu zaprosił ludzi z doktoratami z tym, że odrzucił tych co
mieli doktorat ze statystyki.
Usprawnienie
Optimal
F czyli optymalna frakcja czyli optymalna część kapitału jaką można
postawić. Usprawnienie polega na tym, że Ralph wielkość stawki uzależnia
od największej historycznej procentowej straty (największa seria strat w
ujęciu procentowym). Efekt jaki otrzymuje to generalizując wolniejszy
wzrost stawki przy rosnącej przewadze w porównaniu do kryterium Kelly.
Facet napisał kilka książek, więc bez problemu wyguglujecie sporo
oryginalnego materiału z internetu jak i sam wzór.
Moje trzy grosze (konie)
Do
czego mogę się przyczepić. Stawka uzależniona jest od pojedynczego
zdarzenia - największej procentowej straty. Zależność stawki od dużej
"wtopy". Teraz pytanie czy trafimy na nią na początku "kariery" czy
później. Albo stawka będzie "przeszacowana" albo "niedoszacowana", ale w
zasadzie nigdy optymalna. Teoretycznie wzór będzie "lepszy" dopóki nie
trafimy na jeszcze większą stratę. Przy odrobinie szczęścia nie stanowi
to problemu.
Problemem jest wiara w istnienie strategii o
wysokiej przewadze. Niestety mnie jej brak. Po prostu nie wierzę w
możliwość działania w realu strategii o znacznie większej przewadze niż
ma kasyno czy broker. Jak ktoś pokazuje takie "coś" to
najprawdopodobniej coś z "tym" jest nie tak - albo oszustwo, albo jakiś
błąd w algorytmie. Nie zajmuję się takim "wodotryskami" ignorującymi siłę
procentu składanego. W takim razie pozostaje pytanie czy "ulepszania"
kryterium Kelly jest pragmatycznie uzasadnione czy to raczej sztuka dla
wodotryskowego kiczu.
Drobna przewaga jaką posiada broker wystarczyła głównemu współwłaścicielowi XTB wejść do 100ti najbogatszych ludzi w Polsce.
WDFX Marzec 09, 2017, 09:50:26 am -----
Witam,
mam pytanie odnośnie R bo nie mogę dojść do ładu i czasem wychodzą kosmiczne wartości np. 47%
Win/loss wychodzi mi 0.5322 a AvgWin/AvgLoss wychodzi 0.5268
WinRate = 108/(108+50)=0,68
Kelly %= WinRate - ((1- WinRate) / (AvgWin/AvgLoss));
wydaje mi się, że źle liczę średni zysk/stratę czy R to (zysk/ilość zyskownych) / (strata / ilość stratnych)
Jak ten wskaźnik średniego zysku/straty % powinienem policzyć?
Marzec 12, 2017, 09:56:23 pm -----
Przy dużej przewadze mogą wychodzić "kosmiczne wartości". Zostało to zasygnalizowane wyżej ... i jak sobie z tym radzić też.
Jak nie zarabiasz na forexie to nie musisz sobie KK zawracać głowy. Ogólna zasada jest taka aby zwiększać stawkę po wygranej i zmniejszać po przegranej czyli przykładowo stawka jako procent posiadanego kapitału gdzie ów procent bazuje na wielkości oczekiwanej. Po każdej zmianie kapitału ustalasz stawkę na nowo. Oczywiści dotyczy to gry jednym zleceniem. Przy dwóch trzeba stawkę podzielić przez dwa, a przy kolejnych odpowiednio przez ich ilość.
Przypomnę: beneficjentami stosowania KK będą gracze zarabiający, posiadający duży kapitał i dużą próbę statystyczną dla stosowanej strategii. Po więcej odsyłam do popularnej wyszukiwarki. Wystarczy wpisać "Kelly criterion pdf".
Najlepiej
pobrać bezpośrednio ze strony (linki wyżej). Z innych źródeł (od
brokerów) może mieć blokady. Najlepiej zainstalować na czystej
instalce MT4 (nic się nie będzie "gryzło"). Program ma tyle
opcji, że na dobrą sprawę nic więcej nie jest potrzebne do handlu
półautomatycznego (można też podpiąć pod niego pełne automaty). Robot
wymiata wszystkie inne "wynalazki". Ilość opcji może w
pierwszej chwili przytłoczyć - trzeba opanować za co, która ikona
odpowiada. Do wygodnej obsługi dobrze jest mieć mysz - "pocieranie"
może być za wolne. Jedyna rzecz do jakiej mogę się przyczepić to brak
prowadzenia zleceń po krzywych. Po prostych działa bez problemu. W
przypadku zmiany ich położenia na wykresie robot automatycznie
uwzględnia zmianę.
AutoGraf 4
Komercjalizacja
Niestety
produkt od czasu powstania wpisu w 2012 roku przeszedł proces
komercjalizacji. Nie wiem czy można go uzyskać bezpłatnie w wersji "pełnosprawnej". Jak macie konto u jednego z "preferowanych" brokerów to pewnie bez problemu. Lista "preferowanych" jest na stronie AutoGrafa.
Uwagi
W języku MQL nie da się zaprogramować "przycisków", na które można najechać myszką i uruchomić klikając. W języku MQL "uruchomienie" realizowane jest przez "przeciągnięcie" obiektu w inne dowolne miejsce na wykresie. Czyli nie klikamy myszą tylko "łapiemy" i przesuwamy obiekt graficzny na inne miejsce - wtedy następuje wykonanie zapisanego "pod nim" polecenia.
Z AutoGraf'em 4 możecie spędzić wiele "niezapomnianych" nocy. Dziewczyna w piosence obiecuje dać (tylko) sto nocy...
Originally presented on June 14, 2011, this webinar is presented by Dr. Alexander Elder.
Godzinka z Alexandrem Elderem, poznajcie jego umiejętności w roli prowadzącego, a przy okazji posmakujcie konkurencyjny produkt do MetaTrader'a - program MetaStock. Programowanie w Metastock'u jest znacznie łatwiejsze, testowanie znacznie wygodniejsze, baza gotowych wskaźników i strategii znacznie bogatsza - niestety program sporo kosztuje. Nie wiem czy jakiś broker forexowy oferuje konta z nim. Program ma moduł do podpięcia danych zewnętrznych, a to praktyka niemile widziana na detalicznym forexie.
Przy jego pomocy możecie zbudować robota do handlu automatycznego (zwanego też: "expert advisor" lub w skrócie "ea") w pół godziny. Gotowy projekt zapisujecie bezpośrednio z przeglądarki poleceniem na dole "Complete!"
i już możecie testować/handlować. Proste i wygodne i co ważne
całkowicie darmowe. Licencja umożliwia wykorzystanie stworzonych przy
pomocy strony robotów w celach niekomercyjnych - nie można ich
sprzedawać.
Przy
pomocy Expert Advisor'a może nie zbudujecie super skomplikowanej
strategii, ale przeciętna strategia jest znacznie mniej rozbudowana niż
możliwości apletu działającego na stronie. Stronę możecie też używać
jako edytora do pisania kawałków kodu do wstawienia w inne projekty.
Pomocne materiały
Biblioteka - ogromny zbiór gotowych skryptów, wskaźników, robotów do wykorzystania (rosyjski, angielski),
Expert Advisor - link do strony z omawianym apletem to tworzenia strategii,
Język C - podręcznik języka C bardzo podobnego do języka MQL4, warto chociaż zerknąć jak działają pętle (polski),
KJK
- podręcznik języka MQL po polsku - niestety strona już nie istnieje.
Wielka szkoda. Link usunięty. Nie pamiętam jak się chłopak nazywał, ale
wielkie podziękowania dla niego za ogrom bezinteresownej pracy.
Uwagi
Proszę
zwrócić uwagę, że to opracowanie było pisane w 2011 roku. Nie mam
zielonego pojęcia w jakim stopniu aplet uwzględnił zmiany jakie zaszły
od tamtego czasu. Od dawna z niego nie korzystam.
To co mogę podpowiedzieć. W razie problemów z apletem proszę zmienić przeglądarkę i spróbować ponownie.
Sądzę, że text niżej warto przeczytać bo zawiera też pewne moje doświadczenia "ponadczasowe" związane z programowaniem MQL. Mogą zaoszczędzić czasu.
Instrukcja oraz kod robota (EA) o nazwie "MakeGrid193" do stawiania siatki zleceń [1].
Instrukcja
Following on numerous mails, I would like to point out that this is
NOT a trading system and a straight implementation of MakeGrid on any
currency pair is bound to blow your account - sooner or later - unless
you are very rich and patient.
Risk
As
a simple exercise, try calculating the drawdown on your account for 1k
lots on a 6 pip grid over a range of 3000 pips (this is typical of an
annual move). It comes out to something like 60'000 $ depending on
the pair you trade. That is a lot of money for something like 300 pips a
day.
Other than that, I found it to be a super tool to learn the
different ways of trading grids and the variants that people in the
boards were mentioning and trying.
After back and forward testing
it with a lot of variants, I really changed my way of looking at grids.
It is a really strange beast to trade.
Before trying this with
real money, please do your maths. Your account chould be able to handle a
3000 pip drop in a few days without being near a margin call.
Personally, I use 50 pip grids and count 4 - 6000 $ of Equity per
currency traded per 1000 lot size. Also, watch out for rollover interest
/ charges as, depending on the broker, this can really mess you up.
Having lots of GBP/JPY short positions is not a good idea!
What the EA does
The
basic program does the following: Every few minutes ( determined by
UpdateInterval ), it will calculate the first entry price at current
price minus gridsize * gridsteps / 2.
ex. if we are at 1.2000, gridsize is 50, gridsteps is 12, 50 x 12 /2 = 300. The
first order would be placed at 1.2000 - .0300 = 1.1700 and the last
order at 1.2300. This gives 12 orders at 50 pip intervals. Note that
orders are placed at round numbers : 100, 150, 200 etc for a 50 pip
grid, 10, 20, 30, 40 etc for a 10 pip grid.
Before placing
orders, the EA looks to see if we either have a position or an existing
order near the relevant price. By 'near' I mean within 9/10th of the
grid size. i.e. for a 50 pip grid, the EA will look to see if we have an
existing order or position 45pips above or 45 pips below the required
price. This looks a bit extreme but is a simple way to reduce the risk of duplicate positions.
If
an order / position does not exist at the slot, it will create one
(stop or limit) with the TP and SL as specified. TP is necessary, SL is
optional.
There are many flage to determine whether the order should be placed. They are discussed below.
Once
it has placed orders, it can do some housekeeping. For example, it can
delete orders that are too far out ( in out example, orders that are
more than 300pips away from the current price) so as to limit the server
load. It can also delete orders after a specified number or hours.
Parameters
There are lots of different flags that allow you to test variants :
Lots - the lot size you want to trade. GridSize - the interval between orders, in pips GridSteps - the number of open orders the EA will try to set above and below the current price TakeProfit - the TP in pips StopLoss - If you want a stoploss, specify in pips. 0 means no stoploss. wantLongs - if you want longs to be opened. ex. eur/huf, you may not want longs wantShorts - if u want short positions opened. - if both are true, both longs and shorts will be opened
Some
people wanted to open positions only if 'with the trend' (i.e. for
longs, above the current price ) and others only against the trend (i.e.
if longs, only below the current price).
wantBreakout - sets orders above the price for longs and below the current price for shorts wantCounter - sets long orders below the current price, shorts above current price.
GridMaxOpen
- will make sure that no more than this number of positions is open at
any one time. This is a way of limiting drawdown risk.
minFromPrice
- this is the minumum distance, in pips, from the current price, that
one can place a trade. For example, we only want a breakout of at least
30 pips from the current price. This can be used in conjunction with
wantBreakout and wantCounter.
All the above parameters will work
on ANY time frame chart and give exactly the same results. The
parameters below are time frame dependent. I have mostly used them on 5
min charts but lots of people have tried on longer time frames.
It
is possible to limit long orders only if they are above an EMA and
shorts below. The EMA period is set by the EMAPeriod flag and the flag
is limitEMA. If true, it will test this condition. The housekeeping
routine will remove orders that end up on the wrong side of the EMA.
UseMACD
and useOSMA are similar. If true, only longs will be placed if the MACD
(OsMA) signal is above zero. All short orders will be cancelled. The
opposite is true for MACD below zero. All the MACD parameters are
specifiable (fast and slow ema, signal period), including the chart time
frame (timeFrame). When either of these signals is true, it is
possible to have the EA close open positions (whether gain or loss) that
are on the wrong side. i.e. if MACD crosses up, all short orders are
cancelled but if CloseOpenPositions is true, all short open positions
are closed. The new grid is setup as a long grid.
These flage work in conjunction with wantLongs and wantShorts. Hence
it is possible to setup a grid of longs only, above the 34 EMA, above
the current price plus 20 pips (minFromPrice) and only if MACD is
positive.
With a bit of simple programming, you can change either of these to use your favourite index.
Future direction
I
regularly add in suggestions other traders have found useful. I have
not read this whole thread so if someone can summarise the variants that
are needed, I may try to program them in.
However, as a good
contribution to the advancement of grid trading, if someone has an
effective way of limiting drawdown, I will be very happy to hear it.
Other
than MACD and OsMA, I have not found that the other methods are useful
in improving the system. These can limit the drawdown by up to about
50%.
In particular, I have found that any stoploss, time limit or CloseOpenPositions lead to losing strategies.
For
real trading, the main direction I have moved in is trading a group of
selected currency pairs. This is impossible to backtest properly on
MetaTrader so I have an API as well as some custom programs and tons of
tick data.
Conclusion
I
hope this short tutorial on MakeGrid helps better understand how it
works and the risks inherant in grid trading. If we can come up with
ways to reduce drawdown, then we can have a good simple automated
trading system that would be accessible to the normal retail trader.
extern double longGridCenter = 0; // defines the center point of a fixed width long grid extern double shortGridCenter = 0; // defines the center point of a fixed width short grid
extern double longGridLow = 0; // defines the bottom of a fixed width long grid extern double longGridHigh = 0; // defines the top of a fixed width long grid
extern double shortGridLow = 0; // defines the bottom of a fixed width short grid extern double shortGridHigh = 0; // defines the top of a fixed width short grid
extern double profitTarget = 99999; // if > 0, will close out all positions once the $ target has been met
extern bool suspendGrid = false; // if set to true, will close all unfilled Orders extern bool shutdownGrid = false; // if set to true, will close all orders and positions.
// modified by cori. internal variables only string GridName = "Grid"; // identifies the grid. allows for several co-existing grids - old variable.. shold not use any more double LastUpdate = 0; // counter used to note time of last update double startTime = 0; // counter to note trade start time. double closedProfit = 0; // counts closed p&l double openProfit = 0; // counts open p&l double accumulatedProfit = 0; // for back testing only bool haveHitTarget = false; // if there is a target, this flag says we have hit it int openLongs = 0; // how many longs are open int openShorts = 0; // how many shorts are open bool gridActive = true; // is the grid active bool gridOneShot = false; // is this a one shot? if so, it stops after the profitTarget has been reached
//+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- #property show_inputs // shows the parameters - thanks Slawa... //---- GridName = StringConcatenate( "Grid-", Symbol(),"-",uniqueGridMagic ); return(0); } //+------------------------------------------------------------------------+ //| tests if there is an open position or order in the region of atRate | //| will check for longs if checkLongs is true, else will check | //| for shorts | //+------------------------------------------------------------------------+
bool IsPosition(double atRate, double inRange, bool checkLongs ) { int totalorders = OrdersTotal(); for(int i=0;i<totalorders;i++) // scan all orders and positions... { OrderSelect(i, SELECT_BY_POS); // modified by cori. Using OrderMagicNumber to identify the trades of the grid // hdb added or gridname for compatibility if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol... { int type = OrderType(); if (MathAbs( OrderOpenPrice() - atRate ) < (inRange*0.9)) // dont look for exact price but price proximity (less than gridsize) - added 0.9 because of floating point errors { if ( ( checkLongs && ( type == OP_BUY || type == OP_BUYLIMIT || type == OP_BUYSTOP ) ) || (!checkLongs && ( type == OP_SELL || type == OP_SELLLIMIT || type == OP_SELLSTOP ) ) ) { return(true); } } } } return(false); }
//+------------------------------------------------------------------+ //| Delete order after x hours | //+------------------------------------------------------------------+ void DeleteAfter( double xHours ) // delete pending orders or open positions after x hours { int totalorders = OrdersTotal(); for(int i=totalorders-1;i>=0;i--) OrderSelect(i, SELECT_BY_POS, MODE_TRADES); // we use iTime so it works in backtesting if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol... { if (( MathAbs(iTime(Symbol(),5,0)-OrderOpenTime()) >= xHours*60*60 ) && (iTime(Symbol(),5,0)>0)) { bool result = false; //Close opened long position if ( OrderType() == OP_BUY ) result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red ); //Close opened short position if ( OrderType() == OP_SELL ) result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red ); //Close pending order if ( OrderType() > 1 ) result = OrderDelete( OrderTicket() ); } }
} // proc DeleteAfter()
//+------------------------------------------------------------------------+ //| cancells all pending orders | //+------------------------------------------------------------------------+
void CloseAllPendingOrders( ) { int totalorders = OrdersTotal(); for(int i=totalorders-1;i>=0;i--) // scan all orders and positions... { OrderSelect(i, SELECT_BY_POS); // modified as per cori. Using OrderMagicNumber to identify the trades of the grid // hdb added or gridname for compatibility if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol... { if ( OrderType() > 1 ) bool result = OrderDelete( OrderTicket() ); } } return; } //+------------------------------------------------------------------------+ //| cancells all pending orders and closes open positions | //+------------------------------------------------------------------------+
void ClosePendingOrdersAndPositions() { int totalorders = OrdersTotal(); for(int i=totalorders-1;i>=0;i--) { OrderSelect(i, SELECT_BY_POS); bool result = false; // modified by cori. Using OrderMagicNumber to identify the trades of the grid // hdb added or gridname for compatibility if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol... { //Close opened long positions if ( OrderType() == OP_BUY ) result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red ); //Close opened short positions if ( OrderType() == OP_SELL ) result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red ); //Close pending orders if ( OrderType() > 1 ) result = OrderDelete( OrderTicket() ); } } return; }
//+------------------------------------------------------------------------+ //| cancells all open orders which fall on the wrong side of the EMA | //+------------------------------------------------------------------------+
void CloseOrdersfromEMA( double theEMAValue ) { int totalorders = OrdersTotal(); for(int i=totalorders-1;i>=0;i--) // scan all orders and positions... { OrderSelect(i, SELECT_BY_POS); if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol... { int type = OrderType(); bool result = false; //if (type > 1) Print(type," ",theEMAValue," ",OrderOpenPrice()); if ( type == OP_BUYLIMIT && OrderOpenPrice() <= theEMAValue ) result = OrderDelete( OrderTicket() ); if ( type == OP_BUYSTOP && OrderOpenPrice() <= theEMAValue ) result = OrderDelete( OrderTicket() ); if ( type == OP_SELLLIMIT && OrderOpenPrice() >= theEMAValue ) result = OrderDelete( OrderTicket() ); if ( type == OP_SELLSTOP && OrderOpenPrice() >= theEMAValue ) result = OrderDelete( OrderTicket() ); } } return; }
//+------------------------------------------------------------------------+ //| counts the number of open positions | //+------------------------------------------------------------------------+
int openPositions( ) { int op =0; int totalorders = OrdersTotal(); for(int i=totalorders-1;i>=0;i--) // scan all orders and positions... { OrderSelect(i, SELECT_BY_POS); if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol... { int type = OrderType(); if ( type == OP_BUY ) {op=op+1;} if ( type == OP_SELL ) {op=op+1;} } } return(op); }
//+------------------------------------------------------------------+ //| Close on profit target | //+------------------------------------------------------------------+ void TestForProfit( int forMagic, double profittarget, bool testOpen, bool testHistory ) // based on trailing stop code from MT site... but modified as per Hiro { if (profittarget > 0 ) { closedProfit = 0; // counts closed p&l
if (testHistory == true) { int total = HistoryTotal(); for(int i=0;i<total;i++) // scan all closed / cancelled transactions { OrderSelect(i, SELECT_BY_POS, MODE_HISTORY ); if ( OrderSymbol() == Symbol() && OrderMagicNumber() == forMagic ) // only look if mygrid and symbol... { closedProfit = closedProfit + OrderProfit(); } } } else { accumulatedProfit =0; }
openProfit = 0; // counts open p&l
if (testOpen == true) { total = OrdersTotal(); openLongs = 0; openShorts = 0; for(i=0;i<total;i++) // scan all open orders and positions { OrderSelect(i, SELECT_BY_POS ); if ( OrderSymbol() == Symbol() && OrderMagicNumber() == forMagic ) // only look if mygrid and symbol... { openProfit = openProfit + OrderProfit(); int type = OrderType(); if ( type == OP_BUY ) {openLongs=openLongs+1;} if ( type == OP_SELL ) {openShorts=openShorts+1;} } } } if ( ( closedProfit + openProfit) >= (profittarget + accumulatedProfit) ) { Print("Closing grid due to profit target"); ClosePendingOrdersAndPositions(); accumulatedProfit = accumulatedProfit + closedProfit + openProfit; haveHitTarget = true; if (gridOneShot==true) { gridActive = false; } } } }
//+------------------------------------------------------------------+ //| Trailing stop procedure | //+------------------------------------------------------------------+ void TrailIt( int byPips ) // based on trailing stop code from MT site... thanks MT! { if (byPips >=5) { for (int i = 0; i < OrdersTotal(); i++) { OrderSelect(i, SELECT_BY_POS, MODE_TRADES); if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol... { if (OrderType() == OP_BUY) { //if (Bid > (OrderValue(cnt,VAL_OPENPRICE) + TrailingStop * Point)) { // OrderClose(OrderTicket(), OrderLots(), Bid, 3, Violet); // break; //} if (Bid - OrderOpenPrice() > byPips * MarketInfo(OrderSymbol(), MODE_POINT)) { if (OrderStopLoss() < Bid - byPips * MarketInfo(OrderSymbol(), MODE_POINT)) { OrderModify(OrderTicket(), OrderOpenPrice(), Bid - byPips * MarketInfo(OrderSymbol(), MODE_POINT), OrderTakeProfit(), Red); } } } else if (OrderType() == OP_SELL) { if (OrderOpenPrice() - Ask > byPips * MarketInfo(OrderSymbol(), MODE_POINT)) { if ((OrderStopLoss() > Ask + byPips * MarketInfo(OrderSymbol(), MODE_POINT)) || (OrderStopLoss() == 0)) { OrderModify(OrderTicket(), OrderOpenPrice(), Ask + byPips * MarketInfo(OrderSymbol(), MODE_POINT), OrderTakeProfit(), Red); } } } } } }
} // proc TrailIt()
//+------------------------------------------------------------------+ //| script program start function | //+------------------------------------------------------------------+ int start() { //---- int i, j,k, ticket, entermode, totalorders; bool doit; double point, startrate, traderate, temp; //---- setup parameters
//---- test if we want to shutdown or suspend if (suspendGrid == true) { // close unfilled orders and then test if profit target CloseAllPendingOrders(); } if (shutdownGrid == true) { // close all positions and orders. then exit.. there is nothing more to do ClosePendingOrdersAndPositions(); return(0); } if (haveHitTarget == true) { // in case we hit target and there are still some open orders and positions ClosePendingOrdersAndPositions(); if (gridOneShot==true) { gridActive = false; } } //---- if (gridActive == false) { // if grid not active, do nothing. return(0); }
//----
if (MathAbs(CurTime()-LastUpdate)> UpdateInterval*60) // we update the first time it is called and every UpdateInterval minutes {
if (profitTarget >0) { TestForProfit(uniqueGridMagic, profitTarget, true, false ); if (!IsTesting()) { Comment(" v 1.93 "," Server time is ",TimeToStr(CurTime( )), "\n", // "\n"," Closed p&l = ",closedProfit, "\n"," Open p&l = ",openProfit, // "\n"," Total p&l = ",closedProfit + openProfit, "\n"," Long, Short = ",openLongs," ",openShorts, "\n"," Net pos = ",openLongs-openShorts, "\n", "\n"," Balance = ",AccountBalance(), "\n"," Equity = ",AccountEquity(), "\n"," Margin = ",AccountMargin(), "\n"," Free mrg = ",AccountFreeMargin(), ()); } }
LastUpdate = CurTime(); point = MarketInfo(Symbol(),MODE_POINT); startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // round to a number of ticks divisible by GridSize k = startrate ; k = k * GridSize ; startrate = k * point - GridSize*GridSteps/2*point ; // calculate the lowest entry point double myEMA=iMA(NULL,0,EMAperiod,0,MODE_EMA,PRICE_CLOSE,0); int currentOpen = 0; if ( GridMaxOpen > 0 ) { currentOpen = openPositions(); if (currentOpen >= GridMaxOpen) {CloseAllPendingOrders(); } }
if (limitEMA) { if (doHouseKeeping) CloseOrdersfromEMA(myEMA);} if (keepOpenTimeLimit > 0) DeleteAfter(keepOpenTimeLimit); if (trailStop >0) TrailIt(trailStop); if ( UseMACD || UseOsMA) { if ( UseMACD ) { double Trigger0=iMACD(NULL,timeFrame,emaFast,emaSlow,signalPeriod,PRICE_CLOSE,MODE_MAIN,0); double Trigger1=iMACD(NULL,timeFrame,emaFast,emaSlow,signalPeriod,PRICE_CLOSE,MODE_MAIN,1); double Trigger2=iMACD(NULL,timeFrame,emaFast,emaSlow,signalPeriod,PRICE_CLOSE,MODE_MAIN,2); } if ( UseOsMA ) { Trigger0=iOsMA(NULL,timeFrame,emaFast,emaSlow,signalPeriod,PRICE_CLOSE,0); Trigger1=iOsMA(NULL,timeFrame,emaFast,emaSlow,signalPeriod,PRICE_CLOSE,1); Trigger2=iOsMA(NULL,timeFrame,emaFast,emaSlow,signalPeriod,PRICE_CLOSE,2); }
if( (Trigger0 > 0) && (Trigger1 > 0) && (Trigger2 < 0 )) // cross up { CloseAllPendingOrders(); if ( CloseOpenPositions == true ) { ClosePendingOrdersAndPositions(); } } if( (Trigger0<0) && (Trigger1<0) && (Trigger2>0)) // cross down { CloseAllPendingOrders(); if ( CloseOpenPositions == true ) { ClosePendingOrdersAndPositions(); } } myWantLongs = false; myWantShorts = false; if( (Trigger0>0) && (Trigger1>0) && (Trigger2>0) && (wantLongs==true) ) // is well above zero { myWantLongs = true; } if( (Trigger0<0) && (Trigger1<0) && (Trigger2<0) && (wantShorts== true) ) // is well below zero { myWantShorts = true; } } int myGridSteps = GridSteps; if (( GridMaxOpen > 0 ) && (currentOpen >= GridMaxOpen)) { myGridSteps = 0; }
if (suspendGrid == true) { //profit target and exit conditions tested so finished return(0); }
startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // round to a number of ticks divisible by GridSize k = startrate ; k = k * GridSize ; startrate = k * point - GridSize*GridSteps/2*point ; // calculate the lowest entry point traderate = startrate + i*point*GridSize + gridOffset*point;
if (myWantLongs && (!limitEMA || traderate > myEMA)) { if (longGridCenter > point) { temp = GridSteps / 2; k = temp; startrate = longGridCenter - k * GridSize * point; } else { startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // round to a number of ticks divisible by GridSize k = startrate ; k = k * GridSize ; startrate = k * point - GridSize*GridSteps/2*point ; // calculate the lowest entry point }
traderate = startrate + i*point*GridSize + gridOffset*point; // now test if traderate within limits doit = true; if (traderate < longGridLow) { doit = false; } if ((traderate > longGridHigh) && (longGridHigh > point)) { doit = false; }
if (( IsPosition(traderate,point*GridSize,true) == false ) && (doit == true)) { // test if i have no open orders close to my price: if so, put one on
double myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate-point*StopLoss ; } if ( traderate > Ask ) { Print("BUY STOP",i); entermode = OP_BUYSTOP; } else { Print("BUY LIMIT",i); entermode = OP_BUYLIMIT ; } if ( ((traderate > (Ask +minFromPrice*Point) ) && (wantBreakout)) || ((traderate <= (Ask-minFromPrice*Point) ) && (wantCounter)) ) { // modified by cori. Using OrderMagicNumber to identify the trades of the grid ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate+point*TakeProfit,GridName,uniqueGridMagic,0,Green); } } } if ( myWantShorts && (!limitEMA || traderate < myEMA)) { if (shortGridCenter > point) { temp = GridSteps / 2; k = temp; startrate = shortGridCenter - k * GridSize * point ; } else { startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // round to a number of ticks divisible by GridSize k = startrate ; k = k * GridSize ; startrate = k * point - GridSize*GridSteps/2*point ; // calculate the lowest entry point }
traderate = startrate + i*point*GridSize + gridOffset*point; // now test if traderate within limits doit = true;
if (traderate < shortGridLow) { doit = false; } if ((traderate > shortGridHigh) && (shortGridHigh > point)) { doit = false; }
if ((IsPosition(traderate,point*GridSize,false)== false ) && (doit == true)) { // test if i have no open orders close to my price: if so, put one on myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate+point*StopLoss ; } if ( traderate < Bid ) { Print("SELL STOP",i); entermode = OP_SELLSTOP; } else { Print("SELL LIMIT",i); entermode = OP_SELLLIMIT; } if ( ((traderate < (Bid -minFromPrice*Point) ) && (wantBreakout)) || ((traderate >= (Bid+minFromPrice*Point) ) && (wantCounter)) ) { // modified by cori. Using OrderMagicNumber to identify the trades of the grid ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate-point*TakeProfit,GridName,uniqueGridMagic,0,Red); } } } } } return(0); } //+------------------------------------------------------------------+
Temat wydzielony z: Piramida użyta w forex konkursie BOSSY
------------------------------------------
[1] Robot napisany dla platformy MetaTrader4 (MT4), do znalezienia w popularnych wyszukiwarkach na hasło : "MakeGrid193".