Automatikusan kereskedő robot ... - forex-szignal.hu · A Forex lényege, hogy a pénznemekkel...
Transcript of Automatikusan kereskedő robot ... - forex-szignal.hu · A Forex lényege, hogy a pénznemekkel...
Szegedi Tudományegyetem
Informatikai Tanszékcsoport
Automatikusan kereskedő robot
fejlesztése és optimalizálása
MQL nyelven martingale módszer alapján
a nemzetközi devizapiacra
Szakdolgozat
Készítette: Témavezető:
Vig Jácint Dr. Bánhelyi Balázs
gazdaságinformatikus BSc
szakos hallgató
egyetemi adjunktus
Szeged
2011
Automatikusan kereskedő robot fejlesztése és optimalizálása
2
Feladatkiírás
Megoldandó feladat:
A MetaTrader 4 (MT4) egy tőzsdei kereskedő rendszer. A feladat ezen rendszer
környezetének és működésének megismerése után egy stratégiát MQL4 programnyelven
létrehozni, amely több devizapárral képes kereskedni. A feladat része továbbá a fenti módszer
használatával egy — a MetaTrader4-be épített — algoritmus segítségével a hatékonyság
javításának megkísérlése, valamint ennek mérése.
A megoldáshoz rendelkezésre álló eszközök:
A MetaTrader 4 programcsomag ingyenesen letölthető és telepíthető
(http://www.metatrader4.com/), valamint demó számlákkal ingyenesen használható. A
rendszer angol nyelvű dokumentációja elérhető a fejlesztők honlapján.
Elérendő cél:
Minimális elérendő cél egy devizákkal kereskedő stratégia megvalósítása. A
megvalósított stratégia hatékonyságának mérése a MetaTrader 4-be épített algoritmussal.
Automatikusan kereskedő robot fejlesztése és optimalizálása
3
Tartalmi összefoglaló
A téma megnevezése:
A téma egy automatikusan kereskedő robot szoftver kifejlesztése és optimalizálása a
devizapiacra (Forex), amely a martingale módszer egy sajátos változatán alapul.
A megadott feladat megfogalmazása:
A MetaTrader 4 (MT4) egy tőzsdei kereskedő rendszer. A feladat ezen rendszer
környezetének és működésének megismerése után egy stratégiát MQL4 programnyelven
létrehozni, amely több devizapárral képes kereskedni. A feladat része továbbá a fenti módszer
használatával egy — a MetaTrader4-be épített — algoritmus segítségével a hatékonyság
javításának megkísérlése, valamint ennek mérése.
A megoldási mód, alkalmazott eszközök, módszerek:
A piac, a környezet és a fejlesztőeszközök megismerése után felvázoljuk a martingale
módszer alapjait és hibát, illetve részletezzük a Forex-ben való alkalmazásának előnyeit és
problémáit. A martingale módszert átdolgozzuk, új ötletekkel javítjuk hatékonyságát, majd
lekódoljuk MQL4 programnyelven a MetaEditor segítségével. A kódolás közben felmerülő
problémákat kezeljük illetve megelőzzük. Az implementálás végeztével a hatékonyságot
javítjuk genetikus algoritmus felhasználásával, ami a Strategy Tester része. Végezetül
szimulációval mérjük és összegezzük az elért eredményeket.
Elért eredmények:
A kifejlesztett szoftver több devizapáron képes hatékonyan működni, átlagosan évi
75%-os hozamot termel egy devizapáron a szimulált környezetben, múltbeli adatok
felhasználásával.
Kulcsszavak:
Forex, automatizált kereskedés, optimalizálás, szoftverfejlesztés
Automatikusan kereskedő robot fejlesztése és optimalizálása
4
Tartalomjegyzék
Feladatkiírás 2
Tartalmi összefoglaló 3
Tartalomjegyzék 4
Bevezetés 5
1. A Forex 7
1.1 Automatizált kereskedés, kereskedő „robotok” 8
1.2 A Metatrader platform 9
1.2.1 A terminál 10
1.2.2 Az MQL4, vagyis a MetaQuotes Language 4 10
1.2.3 A MetaEditor 4 és a készíthető programok fajtái 11
1.2.4 A stratégia tesztelő 12
2. A stratégia 13
2.1 A „grid” stratégia 13
2.2 A „martingale” módszer 13
2.3 A MacroScalper stratégia összeállítása 15
2.3.1 A véges idő problémája 15
2.3.2 A véges tőke problémája 15
2.3.3 A csekély hozam problémája 16
2.4 A stratégia bemutatása 16
3. A stratégia implementálása MQL4 nyelven 19
3.1 A „robot” vezérlése, működésének folyamata 19
3.2 Állapot- és helyzetfelismerés, visszaállítás 21
3.3 Kötésméret meghatározása 24
3.4 A központi logika 25
3.5 A stratégia indítása 26
3.6 Javított megbízáskiadó függvény 27
3.7 Megbízások komplex visszaellenőrzése 29
3.8 Szintek építése 30
3.9 A stratégia zárása, kiszállás 32
4. Tesztelés és az optimális paraméterek meghatározása 35
4.1 Tesztelés múltbeli adatokon 35
4.2 Optimalizálás 37
4.3 A portfólió összeállítása 41
5. Konklúzió, összefoglalás 46
Nyilatkozat 48
Köszönetnyilvánítás 49
Melléklet 50
Automatikusan kereskedő robot fejlesztése és optimalizálása
5
Bevezetés
A nemzetközi devizapiac, röviden Forex, kiváló lehetőséget nyújt a profitszerzésre
azoknak, akik a megfelelő tudással és eszközökkel rendelkeznek. Ezen a piacon a világ
fejlettebb országainak fizetőeszközeivel spekulálhatunk egy másik ország devizájával
szemben. Például a legnagyobb forgalmat bonyolító devizapár az EUR/USD. Az árfolyamot a
globális gazdasági helyzet változásai mozgatják.
Az utóbbi években lényegesen kedvezőbb feltételekkel kapcsolódhat be kisbefektető a
kereskedésbe, így Magyarországon is egyre népszerűbb a Forex. A tőkeáttétel lehetősége
többszöröse a többi tőzsdéhez viszonyítva, tehát a pénzünk akár százszorosával is
kereskedhetünk, így megsokszorozva a nyereményünket, természetesen nagyobb kockázat
mellett. Emellett a piac sohasem pihen, minden hétköznap nonstop nyitva tart.
A devizapiacon legelterjedtebb kereskedési platform a MetaTrader, amellyel
otthonunk kényelméből forgathatjuk a tőkénket. A program bárki számára ingyen
hozzáférhető, akár játékpénzzel való gyakorlásra is használható. Továbbá lehetőségünk van
egy speciális programnyelv (MQL) használatával saját szoftvereket készíteni hozzá, majd
ezeknek a teljesítményét múltbeli adatokon letesztelni, mérni.
Jelen dolgozat témája egy ilyen program elkészítése. A kereskedési stratégia alapja
egy 18. századi, Franciaországból származó fogadási módszer, amit főleg a ruletten
alkalmaztak, amíg a kaszinók bizonyos szabályokkal el nem lehetetlenítették. A módszer neve
martingale, és a lényege, hogy „dupla vagy semmi” alapon tesszük meg a téteket. Például
addig duplázzuk a piros színre tett összeget, amíg nem nyerünk, majd áttérünk a feketére. A
stratégia népszerűsége abból fakad, hogy ha elég pénzünk és időnk van, továbbá kis téttel
indítunk, akkor ugyan lassan, de biztosan gyarapodik a nyereményünk, vagyis amit
elvesztenénk, azt mindig visszanyerjük a duplázás által.
Ez a stratégia kiválóan alkalmazható a Forex-ben, ugyanis a körülmények kedveznek;
például kis kötésméret lehetséges, az alaptőkének százszorosa rendelkezésre áll és a robot
automatikusan „játszik” helyettünk. Továbbá a stratégiát kibővítve saját ötletekkel a kockázat-
nyereség arányt is növelhetjük, vagy kezelhetjük az ismert gyengeségeket.
A fejlesztés során a program helyességén túl oda kell figyelnünk néhány
hibalehetőségre, és felkészülni rájuk. A brókerünk adatközpontja könnyen túlterhelődik
forgalmas időszakokban, például világgazdasági hírek bejelentésénél, vagy felléphet egyszerű
szerver vagy hálózati hiba. Minden hasonló esetre fel kell készülni a program írásakor. Ki kell
védeni, vagy legalább le kell kezelni a potenciálisan veszteséget okozó eseményeket. Például
Automatikusan kereskedő robot fejlesztése és optimalizálása
6
rendszerösszeomlásnál akár másik gépről is folytatható legyen a megkezdett ciklus, vagy
hálózati hibáknál vissza kell ellenőrizni minden ügyletet, és pótolni az esetlegesen
hiányzókat.
Miután a robot elkészült, le kell tesztelnünk a MetaTrader beépített tesztelőjét
használva, amellyel a helyes működést ellenőrizzük. Amennyiben ez sikerült, áttérünk az
optimalizálásra, tehát — genetikus algoritmussal — megállapítjuk a legjövedelmezőbb
beállításokat.
Mivel a robot több devizapáron való használatra készült, ezért keresünk három olyan
párt, amelyek árfolyamai nem mozognak együtt, vagyis nem korrelálnak, majd ezekre is
végrehajtjuk az optimalizálást. Nevezhetjük ezt diverzifikálásnak is, mivel több egymástól
független devizapáron futtatva növelhetjük a nyereséget a kockázat csökkentése mellett.
Végezetül összegezzük a portfóliónk várható hozamát, amely a következőképpen
alakul 2010.01.01-től 2011.10.01-ig tesztelve. Minden tesztet 10000 EUR alaptőkével indítva
a profit: EURUSD 12462, EURCAD 44295, USDJPY 29202. A részletes kimutatások
megtalálhatók a mellékletek között, akárcsak a játékpénzzel élesben futtatott számla
eredményei is.
“The greatest mathematical discovery of all time is compound interest.”
“Minden idők legnagyobb matematikai felfedezése a kamatos kamat.”
Albert Einstein
Automatikusan kereskedő robot fejlesztése és optimalizálása
7
1. A Forex
A Forex kifejezés az angol “Foreign Exchange” rövidítése, devizatőzsdét jelent. A
Forex elsősorban országok és bankok közötti deviza elszámolás és kereskedés piaci színtere.
Azonban az információs technológia rohamos fejlődésével és elterjedésével
magánbefektetőknek is lehetőségük nyílt otthonuk kényelméből bekapcsolódni a
kereskedésbe. Nem köztudott, ám a nemzetközi devizatőzsde a világon legnagyobb forgalmat
bonyolító piac, az ügyletek összes forgalma többszöröse a világ összes egyéb
tőzsdeforgalmának.
Az ekkora likviditás a spekulánsok paradicsoma, mivel senki sem tudja egymaga az
árfolyamot manipulálni, befolyásolni — ami ezzel ellentétben például a Budapesti
Értéktőzsde általános sajátossága. Az árfolyamot a valós pénzáramlás, illetve a globális
makroökonómiai helyzettel kapcsolatos várakozások, hírek, bejelentések alakítják. A
bennfentes kereskedelem szinte lehetetlen, hiszen a hírek publikusak, és azokhoz mindenki
egységesen hozzáfér.
A Forex lényege, hogy a pénznemekkel egymás ellenében kereskednek, tehát a
részvénypiacot példának véve, minden devizapár egyedi instrumentumnak számít, és — az
ISO 4217 nemzetközi szabvány szerinti — három karakteres jelölést használva adják meg a
bázis- és az ellendevizát. Például EURUSD jelenleg 1.3531-en áll, ami egy euró amerikai
dollárban kifejezett értéke. A kötésméretet lot-okban mérik. Egy lot százezer egységet jelent a
bázisdevizából, valamint egy lot-os kötés mellett az árfolyam egy pip-es (pont) változása
körülbelül 10$-os egyenleg változást jelent a számlánkon. Megkülönböztetünk short és long
ügyleteket. Előbbi az árfolyam esésére játszik, utóbbi pedig az emelkedésére.
Mint minden piacon, a Forex-nél is megfigyelhető egy árkülönbözet a vételi és az
eladási ár között. Ezt a szaknyelvben spread-nek nevezik. A brókerünk, aki a bankközi
piacról szerzi be a likviditást és teszi lehetővé, hogy bekapcsolódjunk a kereskedésbe mint
kisbefektetők, ezt a különbözetet könyvelheti el mint nyereséget minden ügyletünk után. A
brókerek semmilyen más — számlavezetési vagy egyéb — díjakat nem számolnak fel. A
brókercég érdeke tehát, hogy minél többször, minél nagyobb kötésegységekkel kereskedjük.
Ezért a részvénypiactól eltérően — ahol a tőkeáttét maximálisan 1:5 — a Forexben nem
szokatlan az 1:100 vagy akár az 1:500. (A tőkeáttét azt jelenti, hogy a fedezetként letétbe
helyezett kockázati tőkénk hányszorosával kereskedhetünk.) Ennek köszönhetően a
multiplikátor hatás lehetővé teszi, hogy minimális tőkével szép hozamokat érjünk el.
Ugyanakkor ez ellenünk is dolgozhat, megsokszorozva a veszteségeinket. Talán ennek és a
Automatikusan kereskedő robot fejlesztése és optimalizálása
8
könnyű piacra lépés lehetőségének az oka, hogy a Forex-szel ismerkedő kisbefektetők
számláinak körülbelül 90%-a egy éven belül lenullázódik, a tőkéjüket a piac felszívja. Ez
nagyon drasztikusnak hangzik, azonban egy pozitívumot meg kell említeni: a devizapiacon a
befektető kizárólag a letétbe helyezett kockázati tőkéjével felelős a döntései
következményéért az értékpapír tőzsdével ellentétben, ahol a befektető korlátlanul felelős,
akár személyes vagyonával, tulajdonával is.
A devizapiac a hét minden munkanapján nonstop nyitva tart. Amint az európai tőzsdék
bezárnak, nyílnak az amerikai, majd az ázsiai tőzsdék és így tovább. Tehát a világ devizáival
folyamatosan kereskedhetünk, reagálva akkor a hírekre, amikor azokat bejelentik, nem pedig
várva a piac nyitását, ahogyan ez a többi tőzsde esetén történik.
Senki sem képes napi 24 órában a rengeteg devizapár árfolyamának alakulását és a
kapcsolódó bejelentéseket figyelemmel kísérni. Valószínűleg ez is ösztönözte az automatizált
kereskedő rendszerek kifejlesztését és elterjedését.
1.1. Automatizált kereskedés, kereskedő „robotok”
Kezdetben az informatika csak „számítástechnikai” értelemben volt jelen a tőzsdén,
ugyanis egy-egy komplex indikátor (pl. RSI – Relative Strength Index, CCI – Commodity
Channel Index) kiszámolása még számológéppel is sok idejét vette el a kereskedőknek,
elemzőknek, így felmerült az igény nem csak ezek értékeinek automatizált kiszámítására,
hanem az árfolyamok grafikonjának indikátorokkal együtt történő kirajzolására,
megjelenítésére. Az új szoftverek hatalmas segítséget jelentettek, hiszen az érdekeltek
felszabadulva a nyers információ-feldolgozó „robotmunka” alól, a tényleges döntéshozásra
fordíthatták idejüket. Az új számítási lehetőséget kihasználva tucatjával jelentek meg régi
indikátorok felújított változatai, illetve teljesen új indikátorok is.
A fejlődés egy másik, nagyvállalati szinten is elindult, bár ebben az esetben a piaci
megbízások automatizált kiadására volt szükség. Tegyük fel, hogy egy befektetési alapkezelő
úgy ítéli meg, hogy a részvényportfólióját át kell rendeznie a piaci változások miatt, így az
összes részvényt a portfólióban értékesíteni akarja. Ha a pakettet egyszerre kínálná eladásra,
akkor ez a tőzsdén hatalmas eladói nyomásként jelentkezne a nagy volumen miatt. Egyrészt
az árfolyamok zuhanni kezdenének, ami sem a részvénytulajdonosoknak, sem a vállalatnak
nem kedvez, sőt árfolyam-manipulálásért pert is indíthatnának az alapkezelő ellen, másrészt a
részvényeket is csak nyomott áron vennék meg. Erre megoldás egy kereskedő szoftver, ami a
pakettet kis részletekben, vételi túlsúly esetén és csak bizonyos ár fölött kínálja eladásra. A
Automatikusan kereskedő robot fejlesztése és optimalizálása
9
teljes folyamat beállításoktól függően heteket is igénybe vehet, ám végezetül a piacra
gyakorolt nyomás és a veszteség elenyésző lesz.
A két elgondolás, vagyis az indikátorok használata és az emberi beavatkozás nélküli
ügyletek csak az utóbbi pár évben találtak egymásra, legalábbis a kisbefektetői körökben,
majd rohamos fejlődés következett. Egymással nem korreláló indikátorok használatával olyan
stratégiákat alakítottak ki, amelyek jó eséllyel helyes szignálokat, vagyis egyértelmű
jelzéseket adnak, hogy mikor kell venni illetve eladni. A kereskedők pedig ezek alapján,
szinte gondolkodás nélkül adhatták ki a piaci megbízásokat és tehettek szert profitra. Innen
már csak egy lépés hiányzik a teljesen automatizált kereskedő rendszerekhez, amelyek szinte
felügyelet nélkül képesek tekintélyes hasznot termelni.
Ma már bárki hozzájuthat ilyen szoftverekhez változó árakon (100-2000 $). Míg
hazánkban csak mostanában kezdenek elterjedni, addig az Amerikai Egyesült Államokban
weboldalak tömkelegével találkozhatunk, ahol több tíz oldalon keresztül próbálnak minket
meggyőzni igen ízléstelen reklámokkal, hogy a termékük évente 1000% fölötti hasznot
termel. Természetesen ezen szoftverek közül majdnem mind semmit sem ér, mivel éles
számlán veszteséget produkálnak.
A fejlődéshez nagyban hozzájárult a legelterjedtebb és kisbefektetők által
előszeretettel használt kereskedési platform, az orosz MetaQuotes cég által fejlesztett
MetaTrader.
1.2. A MetaTrader platform
A 2000-ben alakult MetaQuotes ugyanezen a néven adta ki első kereskedő szoftverét,
amelyben megjelent a még kiforratlan MQL (MetaQuotes Language), ami lehetővé tette a
kereskedési folyamatok automatizálását, de még csak igen korlátozottan, így nem is aratott
nagy sikert. Folyamatos fejlesztés és több megelőző kiadást követően 2006-ban jelent meg a
MetaTrader 4-es változata. Rövid időn belül nagy hírnévre tett szert, és manapság nehéz olyan
Forex brókercéget találni, amely kínálatából hiányozna. A népszerűség oka pedig, hogy a
letisztult felület egy jól strukturált, modulokból álló szoftvert takar. Egy hasonló kombináció
eléréséhez más, külön gyártóktól származó (fizetős) programokat kellene együttműködésre
bírni. Ezzel szemben a MetaTrader mindenki számára ingyen elérhető és használható.
Automatikusan kereskedő robot fejlesztése és optimalizálása
10
1.2.1. A terminál
A terminál a platform azon része, amire minden kereskedőnek szüksége van, mivel
ezen funkciók többsége szükséges a kereskedéshez. Ezek többnyire megtalálhatók a
brókercégek saját webes vagy egyéb kereskedési felületén. A terminálban
jelentkezhetünk be a kereskedési számlánkra,
kísérhetjük figyelemmel a futó ügyleteket, zárhatjuk azokat, vagy nyithatunk újakat,
nézhetjük meg a számlatörténetet, a számlaegyenleget, az össz- vagy részprofit
mennyiségét,
különböző devizapárok grafikonjait nyithatjuk meg tetszőleges idősíkon,
a grafikonokhoz hozzáadhatunk beépített indikátorokat, rajzolhatunk a technikai
elemzésünkhöz,
a chart-okhoz, vagyis grafikonokhoz hozzárendelhetünk expert advisor-okat
(robotokat), szkripteket, saját indikátorokat, amelyeket korábban leprogramoztunk.
Valamint ezeken kívül a terminálból érhetjük el az MQL4 IDE (Integrated Developer
Environment – Integrált fejlesztői környezet) részeit.
1.2.2. Az MQL4, vagyis a MetaQuotes Language 4
Az MQL4 a platform beépített programozási nyelve kereskedési stratégiák
leprogramozására. Segítségével megalkothatjuk a saját automatizált stratégiánkat vagyis
expert advisor-unkat. Emellett lehetőségünk nyílik egyéni indikátorok, szkriptek és
könyvtárak létrehozására. Az MQL4 tartalmaz rengeteg beépített függvényt, amelyek
szükségesek a bejövő új árfolyamszintek vagy múltbéli árfolyam és egyéb adatok
feldolgozásához, analizálásához. A nyelv részei még a szokásos aritmetikai és logikai
operátorok, függvények, illetve a megbízások és indikátorok kezeléséhez szükséges speciális
metódusok. Általánosságban elmondható, hogy a C/C++ nyelvekhez hasonlít leginkább a
szintaxis, azonban objektumorientált programozást a nyelv nem támogat.
Az MQL következő verziója, az MQL5 már nyújt lehetőséget objektumorientált
programozásra sok egyéb újítás mellett, azonban a hibák nagy számára és a visszafelé
kompatibilitás hiányára való tekintettel sem a brókercégek, sem a közösség nem fogadta
kitörő lelkesedéssel.
Automatikusan kereskedő robot fejlesztése és optimalizálása
11
A MetaQuotes évről-évre megrendezi az „Automated Trading Championship”-et,
vagyis a kereskedő robotok versenyét, ahol a legtöbb profitot termelő szoftverek mérhetik
össze képességeiket visszamenőlegesen tesztelve és éles környezetben. A versenyre 2010 óta
csak MQL5-ben írt programmal lehet nevezni.
1.2.3 A MetaEditor 4 és a készíthető programok fajtái
A MetaEditor a hangzatos névvel ellentétben egy meglehetősen puritán
fejlesztőkörnyezet, összehasonlítva a NetBeans, Visual Studio vagy Eclipse nevű
termékekkel. Gyakorlatilag egy egyszerű text editor, vagyis szövegszerkesztő, amely kiemeli
különböző színekkel a beépített függvények neveit és a szerkezeteket, hogy egyszerűbben
eligazodhassunk folyamatosan bővülő kódunkban. A súgó elég hasznos, hiszen az összes
nyelvi elemről találunk leírást kategorizálva, rendezve, beleértve a speciális függvényeket és
foglalt szavakat. Megtalálható még a gyakran használatos „Compile” — vagyis fordítás —
gomb, amivel a kódunkat az *.mq4 kiterjesztésből futtatható *.ex4-re fordíthatjuk. A fordító
közepesen segítőkész a hibák megtalálásánál, a hiba helyét és okát megadja, ám gyakran
tévesen. Például visszatérési értékkel rendelkező függvényből elmaradt return esetén nem dob
hibát. A következő típusú programok készíthetők vele:
Expert Advisor: ezek a szoftverek nevezhetők az automata rendszereknek, hiszen egy
bizonyos chart-hoz csatolva feldolgoznak a leprogramozott módon minden beérkező
új árfolyam és egyéb adatot. Információt nyújthat grafikusan vagy jelzésen keresztül,
illetve akár el is küldheti a megbízást a bróker szerverének. Számunkra ezek lesznek a
legfontosabbak, hiszen múltbeli adatokon letesztelhető a teljesítményük.
Egyéni indikátor: technikai indikátor, amelyet a beépítetteken kívül fejlesztettünk.
Akárcsak a terminál saját indikátorai, ezek sem kereskedhetnek önállóan. Kizárólag
analitikai függvények implementálására szolgálnak.
Szkript: ahogyan a szoftverfejlesztés más területén, úgy itt is előre meghatározott
feladatok egy sorozatát hajtja végre. Például az összes nyitott pozíció zárása egy
gyakran használt szkript.
Könyvtár: főleg egyéni vagy speciális függvények tárolására használjuk. Magukban
nem képesek működésre.
Automatikusan kereskedő robot fejlesztése és optimalizálása
12
Include fájl: olyan forráskód fájl, amit a fordításnál a fordító egyszerűen bemásol az
eredeti forráskódba. Nagy forrásokat érdemes ilyen fájlokra darabolni az átláthatóság
miatt.
1.2.4. A stratégia tesztelő
Tegyük fel, hogy elkészült az első kereskedő robotunk. Azonban ekkor a fejlesztés
még közel sem ért véget. Éppen ellenkezőleg, egy nagyon fontos szakaszhoz értünk: a
robotunkat alá kell vetni a hibakeresés és –javítás folyamatának, valamint optimalizálás is
szükséges, hogy piaci körülmények között profitot termeljen, ne csak elméletben.
A múltbeli adatokon való tesztelés elengedhetetlen feltétele egy jövedelmező
automatizált kereskedési rendszer megalkotásának. Viszont ennek manuális kivitelezése
rengeteg időt és energiát emésztene fel, ezért is létfontosságú ez a speciális eszköz. Most sorra
vesszük röviden a teljesség igénye nélkül a modul tulajdonságait:
Flexibilitás: az expert advisor bármely inputját optimalizálhatjuk tetszőleges
összetételben, illetve korlátozó függvényeket adhatunk meg — pl. a tőkére, a profit
faktorra, a maximális lehívásra stb. — akármelyik idősíkon, amennyiben a múltbeli
adatok rendelkezésre állnak
Részletes jelentés: az eredmények jobb és gyorsabb feldolgozása érdekében a tesztelő
többfajta jelentéssel szolgál a folyamat befejeztével: tőke és egyenleg grafikon az
ügyletek függvényében, egyszerű vagy virtuális 3d grafikon az optimalizálás
eredményéről, valamint egy részletes statisztikai táblázat
Vizuális tesztelés: jócskán megkönnyíti a hibakeresést, ugyanis az árfolyam
grafikonon követhetjük nyomon a robot tevékenységét, így nem szükséges kizárólag a
kötéslista és a statisztika alapján a képzeletünkre hagyatkozni
Genetikus algoritmus használata: a tesztelő lehetőséget nyújt genetikus
algoritmussal való optimalizálásra, tesztelésre az egyszerű brute-force helyett, így a
művelthez szükséges idő a töredékére csökken amellett, hogy az optimális megoldásra
egy jó közelítést kapunk
Megismerkedtünk a piaccal, a környezettel és a lehetőségeinkkel. Kövessük végig egy
kereskedelmi forgalomban kapható (bérelhető) robot fejlesztésének folyamatát a kezdetektől a
felmerülő nehézségeken, problémákon keresztül a késztermék üzembe állításáig.
Automatikusan kereskedő robot fejlesztése és optimalizálása
13
2. A stratégia
A szakmai gyakorlatom elején — a környezettel való megismerkedés után —
megbízást kaptam a később MacroScalper fantázianévre keresztelt automatikus kereskedő
rendszer kifejlesztésére. A cég portfóliójában már szerepeltek rövid és hosszú távú
trendkövető robotok, amelyek exponenciális mozgóátlagok és egyéb szűrő indikátorok
segítségével próbáltak profitot termelni. Ezen robotoknál azonban elkerülhetetlen az időnkénti
újraoptimalizálás a piaci folyamatok változása miatt, esetlegesen a stratégia teljes elvetése. A
cél egy — indikátorok helyett — matematikai modellre épülő robot implementálása volt,
amely a piac változásai mellett is képes folyamatos profitot termelni.
A trendkövető robotok helyes stratégiával és beállításokkal hatalmas profitot képesek
termelni, azonban ezt nem egyenletesen, hanem nyerő és veszteséges ügyletek sorozatával
egyenetlenül, így nagyon nehéz megmondani, hogy mikor van szükség a stratégia
újragondolására. Esetlegesen a robot a profit nagy részét ekkorra már el is vesztette.
A kivitelezendő rendszer egy fordított grid, azaz háló stratégia martingale
pozícióépítéssel kombinálva.
2.1. A grid stratégia
A megközelítés lényege, hogy a piac természetes trendelő mozgását próbáljuk
kihasználni úgy, hogy az aktuális piaci ár fölé vételi és alá eladási függő megbízásokat
helyezünk egy meghatározott távolságra, így ha az árfolyam megindul az egyik irányba, akkor
profitra teszünk szert. Ez azért tűnik kedvezőnek, mivel nem szükséges hozzá az árfolyam
irányának előre jelzése. Ennek azonban az az ára, hogy igen komplikált tőke menedzsmentre
lesz szükség, és meg kell birkózzunk a kereskedői pszichológiával és a háló vizualizációjával.
Szerencsére a pszichológián kívül minden előre számítható vagy automatizálható. Ennek
ellenére a stratégia vitatott, sok követője és ellenzője is akad.
2.2. A martingale módszer
Az eredeti stratégia a 18. századi Franciaországból származik, ahol főleg kaszinókban
alkalmazták a szerencsejátékosok. A legismertebb és legegyszerűbb példa a piros-fekete vagy
páros-páratlan esetében való alkalmazás a rulett asztalnál. A módszer menete meglehetősen
egyszerű: a játékos megteszi az alaptétet a két lehetőség közül az egyikre, mondjuk a pirosra.
Ha nyer, az alaptétet megteszi a másik lehetőségre, a feketére. Ha veszít az előző tétet
Automatikusan kereskedő robot fejlesztése és optimalizálása
14
duplázva teszi meg ugyanazt a mezőt. Nevezhetnénk veszteségminimalizáló stratégiának is,
ugyanis a játékos minden egyes nyerő tét után csak az alaptéttel lesz gazdagabb, ugyanis a
veszteségeket az alaptét duplázásával kompenzálja. Probléma akkor jelentkezik, amikor a két
lehetőség közül sorozatban csak az egyik fordul elő, ugyanis a tétek exponenciálisan nőnek.
Abban a pillanatban, amikor a játékos nem képes folytatni a tét duplázását, kénytelen
elkönyvelni a hatalmas veszteséget. Mondhatjuk, hogy a kockázat a stratégiában aggregáltan
jelentkezik.
Elemezzük matematikai szempontból a stratégiát: Az egyszerűség kedvéért érme
feldobással példázzuk korlátlan tőkével és idővel, ami egy idealizált változat. Legyen a
feldobások sorozata X0, X1 … független véletlen változók, amelyek mindegyike egyenlő F-fel
(fej), ahol a valószínűség p, és I(írás), ahol a valószínűség q = 1 – p. Legyen N F első
előfordulásának ideje; más szóval, X0, X1, …, XN-1 = I és XN = F. Ha az érme sosem mutat F-
et, azt mondjuk, hogy N végtelen. N maga is véletlen változó, ugyanis a véletlen feldobások
kimenetétől függ.
Az első N – 1 feldobás során a martingale-t követő játékos 1,2,…2N-1
egységet veszít,
összegezve 2N-1. Az N-edik feldobás során pedig 2
N egységet nyer, vagyis a nettó profitja 1
egység. Például egy négyes sorozat: I,I,I,F esetén N=3. A játékos veszít 1,2 és 4 egységet az
első 3 feldobáson, vagyis összesen 7-et, majd a 4. feldobáson visszanyer 8-at, 1 egységnyi
nettó nyereséggel. Tehát amíg az érme valaha is F-et mutat, addig a játékos nyer.
Mi a valószínűsége, hogy N végtelen, vagyis az érme sosem lesz fej? Világos, hogy
nem lehet nagyobb, mint annak a valószínűsége, hogy az első k feldobás mind I, ami qk.
Hacsak q nem 1, az egyetlen nem negatív szám, ami kisebb vagy egyenlő mint qk – k minden
értékére – a 0. Eszerint N véges 1-es valószínűséggel.
Természetesen ezek az idealizált körülmények nem léteznek (kivéve a hedge fund-
oknál, amik a mostani válság egy részéért felelősek). Ezért magában a martingale használata
nem kifizetődő, mivel nagy kockázat mellett csekély hozamot ígér, azonban jó alap lehet
megfelelő kockázatkezelés esetén.
A martingale módszer támogatói között általánosan elterjedt érv a stratégia
sikeressége mellett, hogy az elterjedése után a kaszinókban sorra vezették be a ruletten a „0”
majd a „00” színtelen, paritás nélküli számokat a módszer sikerességének csökkentésére,
ugyanis így a várható érték még végtelen fedezet mellett is negatív. Ezt fokozva vezették be a
minimum és maximum téteket, amelyek már teljesen ellehetetlenítik a módszer sikeres
alkalmazását. A stratégia ellenzői ezeket a megszorításokat egyszerűen azzal magyarázzák,
Automatikusan kereskedő robot fejlesztése és optimalizálása
15
hogy egy hatalmas nyertes tét akár csődbe is vihetné a házat, így kénytelenek fenntartani a
korlátozást.
2.3. A MacroScalper stratégia összeállítása
Mint már említettük, a martingale módszer a szerencsejátékosok számára immáron
nem kifizetődő a megszorítások miatt, azonban korlátozások helyett a devizapiac megfelelő
hely a stratégia implementálására, ugyanis a brókerek — akaratukon kívül — kiváló teret
teremtettek. A nehézségek csaknem mindegyike megoldható vagy kezelhető, illetve
éppenséggel már nem létezik a piac sajátossági révén. Vegyük sorra ezeket és elemezzük!
2.3.1. A véges idő problémája
A martingale módszer ugyan elméletben folyamatosan visszanyeri a veszteségeket,
azonban még ha adott is a végtelen tőke, a játékkal eltöltött idő a nyeremények lassú
növekedése miatt nem biztos, hogy megtérül. A problémára kiváló megoldás az automatizált
kereskedés, ugyanis az elkészült program emberi beavatkozás nélkül minden hétköznap a nap
24 órájában folyamatosan „játszik” helyettünk.
Senki sem szeretné az otthoni számítógépét majdnem egész héten keresztül futtatni,
ami teljes mértékben érthető. Szerencsére havi pár ezer forintért bérelhetünk VPS-t (Virtual
Private Server). A szolgáltatást úgy kell elképzelni, hogy az üzembentartónál nagy
teljesítményű szervergépeken 50-100 operációs rendszer is futtatható virtualizálva, így
költséghatékonyan üzemeltethetők. Az egyes rendszereknek dedikált fizikai memória és
tárhely van kiosztva, így azok egymástól függetlenül, biztonságosan üzemelnek.
Leggyakrabban RDS (Remote Desktop Service) vagyis távoli asztal szolgáltatással érhetjük el
őket saját felhasználónévvel és jelszóval. A szolgáltatás lehetővé teszi, hogy úgy kezeljük a
VPS-t, mintha a saját gépünk előtt ülnénk. A MetaTrader 4 platform nem üzemeltethető
stabilan Linux alatt „wine” emulációval sem, ezért arról szándékosan nem ejtünk szót.
2.3.2. A véges tőke problémája
A martingale módszer legnagyobb „Achilles-sarka”, ugyanis ez veszélyezteti
leginkább a befektetésünket. Ha a tétek duplázását nem tudjuk folytatni, kénytelenek vagyunk
realizálni veszteségeinket. Ez a veszély a devizapiacon sokkal kevésbé fenyegeti a tőkénket,
mint a kaszinókban. Egyrészt azért, mert a Forex brókercégek — engedve a piac nyomásának
— egyre kisebb minimális kötésegységeket vezetnek be, felső korlát pedig csak néhány
Automatikusan kereskedő robot fejlesztése és optimalizálása
16
cégnél létezik. Tehát helyes brókercég választással kiküszöbölhetjük ezt a problémát; sőt,
ahogy a bevezetőben említettük, nem ritka, hogy 1:500 tőkeáttételt is igénybe vehetünk,
vagyis a pénzünk 500-szorosa áll rendelkezésre a „játékhoz”. (Hogy a brókercégek miért
engedhetik meg ügyfeleiknek és maguknak ezt a hatalmas hitelnyújtást, az nagyon érdekes,
ám nem ennek a dolgozatnak a témája.)
Az USA pénzpiaci felügyelete 2011-ben bevezetett korlátozása szerint a tőkeáttét
maximuma 1:50 ill. a major devizapároknál 1:20 — sok más megszorítás mellett — ami
általános felháborodást váltott ki mind a brókerek, mind a kereskedők részéről. Azóta néhány
amerikai brókercég megkülönböztetett szabályozással, vagy egyáltalán nem fogad(!) USA-
ban élő ügyfeleket. Valamint erőteljesen megindult a Forex „offshore”-ozás, vagyis az ott élő
kereskedők olyan országokba viszik a tőkéjüket, ahol a szabályozás nem érvényes, de mégis
relatív biztonságban érzik a pénzüket (pl. Oroszország, Ciprus, Egyiptom).
2.3.3. A csekély hozam problémája
A probléma forrása, hogy a stratégia kis kezdő téteket ír elő a kockázatkezelés miatt,
ezért egy hosszabb ciklus végén is csak az alaptéttel leszünk gazdagabbak, ami már elég rossz
kockázat/hozam arányt jelent. Erre megoldás a martingale ötvözése a grid stratégiával, illetve
egyéb megoldások, amik a fejlesztés közben merültek fel.
2.4. A stratégia bemutatása
A fent említett stratégiák, módszerek, illetve azok problémáira talált megoldások
összesítésével, egymáshoz illesztésével jött létre a MacroScalper stratégia. A központi elv,
ami egyáltalán lehetővé teszi a sikeres alkalmazást, egy az összes tőzsdére általános érvényű
törvényszerűség, a piaci korrekció. Lényege, hogy bármely trendelő (egy irányba mozgó)
árfolyam visszatér valamely hosszabb periódusú mozgó átlaghoz. A kérdés, hogy ez előbb
vagy utóbb következik be és milyen mértékű korrekcióra számíthatunk. Általában egy
erősebb trend után nagyobb visszacsapás következik, azonban ezt nem állíthatjuk olyan
bizonyossággal, mint magát a korrekció tényét, így a stratégiában nem kerül felhasználásra. A
továbbiakat egy konkrét példán keresztül mutatjuk be:
A stratégia alkalmazását 2011. október 3-án 0:00-kor kezdjük. A grid módszer szerint
meghatározunk egy távolságot — legyen ez 50 pip — majd ezzel számolva árfolyamszinteket
hozunk létre. A kiindulási szint lesz a 0, felfelé 50 pip-enként 1,2,3 stb, lefelé lépkedve 50
pip-enként pedig -1,-2,-3 stb. A kezdő kötésegységet az egyszerűség kedvéért vegyük 1.0 lot-
Automatikusan kereskedő robot fejlesztése és optimalizálása
17
nak. Az 1. és a -1. szintre függő megbízásokat helyezünk úgy, hogy az adott szintről
bekövetkező korrekció az előző szintre hasznot eredményezzen. Ezt úgy érjük el, hogy az 1.
szinten 2 lot-nyi shor-tot és 1 lot-nyi long-ot nyitunk; a -1. szinten pedig 2 lot-nyi long-ot és 1
lot-nyi short-ot. (Az alap stratégia működéséhez felesleges az ügyleteket ily módon
szétválasztani, elegendő lenne 1 lot-os short ill. 1 lot-os long is, azonban később látni fogjuk,
hogy ez miért hasznos.) Viszont a szint elérésekor felkészülünk arra az esetre, hogy a
korrekció később következne be azzal, hogy az előző szint megbízásait dupla kötésegységgel
alkalmazzuk a martingale módszer szerint, valamint a már szükségtelen, ellenkező
orientáltságú függő megbízásokat törölhetjük. Lássuk tehát, hogyan is zajlik pontról pontra a
stratégia egy ciklusa, ahogy az 1. ábrán is látható (teljes méretű a mellékletben):
1. ábra: A stratégia szemléltetése
A stratégia indulása: 0. szint: 1.33453 árfolyamon, függő megbízások elhelyezése az
1. (1.33553) és -1. (1.32553) szintre; 2 lot short, 1 lot long illetve 2 lot long, 1 lot
short
Némi ingadozás után az árfolyam eléri a -1. szintet, a függő megbízások aktiválódnak,
az 1. szintről törölhetjük a „pending order”-eket, valamint a -2. szintre kitesszük a
duplázott megbízásokat (4 lot short, 2 lot long)
Az árfolyam eléri a -2. szintet, a megbízások aktiválódnak, majd kitesszük a
következő szint order-eit (8 lot short, 4 lot long)
Tovább esik az ár, így ahogy az előző szinten, cselekszünk (16 lot short, 8 lot long)
Az árfolyam éppen nem éri el a következő szintet, majd bekövetkezik a várva várt
korrekció, vagyis visszakanyarodunk az eggyel fentebb lévő szintre, így annak
elérésekor profittal zárhatjuk az összes pozíciót
Automatikusan kereskedő robot fejlesztése és optimalizálása
18
A stratégia sikeressége a fenti példában egyértelmű, a benne használt kötési egységekkel
és szinttávolsággal — nem számolva az ügyletek költségeit — a profit számítása:
A számításból is kitűnik, hogy a stratégia a visszacsapáskor akkora profitot termel,
amennyi az „alaptét” és az elért szintek számának szorzata, így jóval kedvezőbb kockázat-
haszon aránnyal számolhatunk, mint a puszta martingale esetén, ahol minden ciklus után csak
az alaptétet nyerjük meg a „szintek” számától függetlenül. Ezt a grid módszer
beolvasztásának köszönhetjük. Az elméleti bizonyítás után érdemes a stratégiát hosszú távon
kipróbálni, majd megtalálni a megfelelő paramétereket, azonban ez csak automatizálással
lehetséges, továbbá elengedhetetlenül szükséges a money management, vagyis
kockázatkezelés helyes beállításához, ugyanis a véges tőke problémáját a piac sajátosságai
enyhítik, de mint fő probléma további kezelést igényel.
Automatikusan kereskedő robot fejlesztése és optimalizálása
19
3. A stratégia implementálása MQL4 nyelven
Ahhoz, hogy működőképes robotot tudjunk készíteni, ismernünk kell az MQL nyelven
megvalósítható három alkalmazás közül a legösszetettebb, vagyis az expert advisorok
(röviden EA-k) alapvető szerkezeti felépítését és kapcsolódását a terminálhoz.
Egy chart-hoz, vagyis megnyitott grafikonhoz csak egy EA-t kapcsolhatunk,
ugyanakkor nem mindegy, hogy a chart milyen idősíkot használ, és mely devizapárra
vonatkozik, valamint ezt érdemes érintetlenül hagyni a program zavartalan működése
érdekében, és új grafikont nyitni az egyéb feladatoknak. Az expert advisor 3 fő speciális
függvényre bontható:
init(); a program indítása után közvetlenül fut le egyszer, miután a terminál betöltötte
a chart adatait, valamint akkor, ha a chart idősíkját elváltottuk, az EA-t
újrafordítottuk, illetve a célszámlát megváltoztattuk
deinit(); a program futását követően, valamint az init()-nél felsorolt egyéb okokból
fut le, illetve egy 2,5 másodperces időhatár korlátozza, amit követően a terminál a
végrehajtás állapotától függetlenül lezárja
start(); a bróker szervere másodpercenként többször adatokat küld az általunk
megnyitott chart-nak megfelelően. Egy ilyen adatcsomag neve tick, ami a friss
jegyzési árfolyamot ill. annak pontos idejét tartalmazza az adott devizapárnak. A
start() függvény minden tick-re lefut kivéve, ha az előző hívás még nem zárult le.
Fontos megjegyezni, hogy az init() vagy deinit() függvényekben minden változónk
értékét állítsuk be vagy nullázzuk, mivel a szokásostól eltérő indítás esetén ezek értékei
megmaradnak!
A következő részekben sorra vesszük a fejlesztés során felmerülő problémákat,
buktatókat, és a MacroScalper-ben is alkalmazott — helyenként speciális — megoldásokat
bemutatjuk, elemezzük, miután röviden összefoglaljuk a működését, vezérlési szerkezetét.
3.1. A robot vezérlése, működésének folyamata
A főbb függvényhívásokat és a vezérlést a 2. ábra szemlélteti a teljesség igénye nélkül.
Automatikusan kereskedő robot fejlesztése és optimalizálása
20
2. ábra: A robot vezérlése
A szoftver indítását követően először az init() függvény kerül végrehajtásra. A mi
esetünkben a változók inicializálása már a deklaráláskor megtörtént. Viszont helyet kapott
egy apró, de annál fontosabb megoldás, amely néhány kereskedelmi termékből sajnos
hiányzik.
A komolyabb brókercégek a pontosság érdekében, illetve a napon belül kereskedő
„daytrader” ügyfelek kedvéért egy tizedesjeggyel pontosabban jegyzik az árakat, ezért ilyen
esetekben egy 10-es szorzót kell beépítenünk mindenhová, ahol pip-ekben mért elmozdulással
szeretnénk számolni. Szerencsére úgy alakult, hogy a devizapárok árfolyamát 4 (pl.
EURUSD) illetve 2 (pl. USDJPY) tizedes pontossággal számolják alapesetben. Ha viszont 5
és 3 tizedesig számol a bróker, akkor szükség van a 10-es szorzóra. Segítségünkre van a
Digits globális beépített változó, amely az árban lévő tizedesjegyek számát tartalmazza.
Néhány apróbb számítást követően két igen lényeges függvény kerül meghívásra. A
calcLot() majd a reStart() függvény. Előbbi a money management, vagyis a kockázatkezelés
részeként kiszámolja az alap kötésegységet, valamint túl kis tőke esetén figyelmeztet, az
utóbbi pedig egy esetleges korábban félbehagyott futás állapotát rekonstruálja. Az init()
függvény befejeztével a terminál meghívja az első tick-re a start() függvényt.
Automatikusan kereskedő robot fejlesztése és optimalizálása
21
A start() metódus a robot központi eleme. Az árfolyamot és néhány állapotváltozót
folyamatosan figyelve hívja meg a megfelelő függvényeket. Mivel a start()-ot a terminál
másodpercenként többször is meghívja, ezért igyekezzünk tartalmát minimálisra korlátozni a
processzor terhelésének csökkentése érdekében. A mi esetünkben sincs ez másként.
Kezdetben egy állapotváltozót ellenőrzünk, hogy a stratégia indítása megtörtént-e
korábban. Ha nem, meghívjuk a begin() függvényt, amely megállapítja a kezdő szintet, és
kiadja a függő megbízásokat az alatta illetve felette lévő szintre, majd igazra állítja az
állapotváltozót. A vezérlés visszakerül a start()-hoz, de változás csak akkor fog bekövetkezni,
ha az árfolyam eléri valamelyik következő szintet. Ekkor annak megfelelően hívódik meg a
Short() vagy a Long() metódus. Ezen metódusok feladata, hogy:
átállítsák az állapotváltozókat
kiadják az új függő megbízásokat
a closeOpposite() meghívásával töröljék a szükségtelen ellenoldali order-eket
a stopLevel() hívásával a régebbi ügyletek StopLoss és TakeProfit szintjeit beállítsák
a checkNewOrders() segítségével pedig a folyamat eredményét ellenőrzi, és hiba
esetén javítja
Tegyük fel, hogy több szint elérését követően az árfolyam korrigál, és
visszakanyarodik valamely előző szinthez. Ekkor teljesül a zárási feltétel a start()
függvényben, és következik a CloseAll(), amelynek feladata törölni és zárni minden függő és
aktív ügyletet, illetve statisztikai célú adatgyűjtés után a kezdeti állapotra visszaállítani, vagy
kinullázni az állapotváltozókat. Ezután a felhasználó korábbi beállításának megfelelően a
robot újrakezdi működését, vagy leáll és eltávolítja magát a chart-ról a deinit() függvény
futása után. A következőkben rátérünk a konkrét megoldások megvalósítására a program
működésének különböző területein.
3.2. Állapot- és helyzetfelismerés, visszaállítás
Egy kereskedő rendszer indítás utáni első feladata — természetesen a változók
deklarálása után — felismerni a számla állapotát, amelyet rábíztunk, ugyanis előfordulhat,
hogy egy korábbi futás vagy ciklus megszakadását követő újraindítás következett be. Ebben
az esetben a korábbi állapotba kell visszaállítani a programot, speciálisan megállapítani a
változók korábbi értékeit. Szerencsére a vezérlési állapottal nem kell foglalkoznunk, ugyanis a
program struktúrája ezt lehetővé teszi. A visszaállítási folyamat során a bróker szerverén
Automatikusan kereskedő robot fejlesztése és optimalizálása
22
tárolt információkat használjuk fel, a robot merevlemezre nem készít mentést. Ennek fő oka,
hogy a saját szerverünk összeomlása esetén — ami jóval valószínűbb, mint a bróker
adatközpontjának meghibásodása — a kereskedői számla és a robot indítási paramétereinek
birtokában gyakorlatilag bármilyen internet hozzáféréssel rendelkező PC-ről 10-15 percen
belül folytatni tudjuk a megkezdett ciklust, majd a szerver helyreállását követően az vissza
tudja venni a kereskedés vezérlését. Ez a „dinamikus” megközelítés igencsak hasznos ilyen
stratégiáknál, amelyek megszakítása biztos veszteséget jelent a befektető számára.
Ezen folyamatért a reStart() függvény felel. Működésének alapja egy elterjedt és sok
más helyen használt megoldás, amellyel indexeik fordított sorrendjében kérdezhetjük le az
ügyleteket:
void reStart()
{
bool inited = False;
double zeroLev = 0.0;
// ezzel a ciklussal végigpásztázzuk a már létező megbízásokat
for (int cnt = OrdersTotal(); cnt >=0 ; cnt--)
{// az adatbázis elemét kiválasztjuk a lekérdezések célpontjául
OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == magic) // csak a robot megbízásai
{
if ((OrderComment()=="macroscalper v5 long" ||
OrderComment()=="macroscalper v5 init long") && OrderType()==OP_BUY) {
// emelkedő trend megbízásai
inited = True;
trend = 1;
multi *=2.0;
level++;
if (zeroLev < OrderOpenPrice()) zeroLev =
OrderOpenPrice();// alapszint és állapotváltozók újraépítése
}
if ((OrderComment()=="macroscalper v5 short" ||
OrderComment()=="macroscalper v5 init short") && OrderType()==OP_SELL) {
// csökkenő trend megbízásai
inited = True;
trend = (-1);
multi *=2.0;
level--;
if (zeroLev == 0.0) zeroLev = OrderOpenPrice();
if (zeroLev > OrderOpenPrice()) zeroLev =
OrderOpenPrice();
} // alapszint és állapotváltozók újraépítése
if ((OrderComment()=="macroscalper v5 init short") &&
OrderType()==OP_BUYLIMIT) { // nulladik megkezdett szint esetén alapszint
inited = True;
if (zeroLev == 0.0) zeroLev = OrderTakeProfit();
}
}
}
if (inited == False) return;
zeroLevel = zeroLev;
began = True;
}
Automatikusan kereskedő robot fejlesztése és optimalizálása
23
Az OrdersTotal() függvény lekérdezi a számla összes aktív megbízásának számát,
majd egy ciklus segítségével a legmagasabb indexűtől a legkisebbig végighaladunk rajtuk.
Fontos, hogy ebben az irányban haladjunk, ugyanis a robotunk mellett lehetséges kézzel
kereskedni, vagy egyéb szoftvert használni ugyanezen a számlán, amelyek nyithatnak vagy
zárhatnak hozzájuk tartozó megbízásokat. Előbbi nem zavarja meg a lekérdezést, ugyanis az
új orderek a sor végére kerülnek index szerint, viszont a törlés vagy zárás a sorból bárhonnan
kivehet megbízást. Ezt követően a terminál azonnal újraindexeli az aktív megbízásokat, akkor
is, ha éppen a vezérlés a ciklusunk közepén tart. Ha a sor elejéről a vége felé haladnánk, akkor
ebben az esetben kimaradhatnának ügyletek, viszont így biztosan ki tudjuk mindegyiket
választani.
A kiválasztásért az OrderSelect() függvényt hívjuk. Gyakorlatilag a következő hívásig
a kiválasztott ügylet marad a célkeresztben, vagyis az összes lekérdező függvény ennek az
adataival fog visszatérni. Első paramétere az index száma. A második és harmadik pedig azt
szolgálja, hogy „select by position” vagyis az index szerint választunk ki, illetve
„mode_trades”, ami megadja, hogy az aktív order-ek között keressen. Később más
beállítással is használni fogjuk.
Az OrderMagicNumber() egy lekérdező függvény, amely a megbízás „varázsszámát”
adja vissza. Minden expert advisor-nak érdemes megadni egy ilyen számot, amellyel
egyértelműen azonosítani tudjuk a számlánkon futó különböző programok order-jeit, illetve
azok is meg tudják határozni, hogy melyek az általuk menedzselt ügyletek.
Miután képesek vagyunk kiválasztani, azonosítani és lekérdezni a megbízásokat, már
csak a stratégia logikáját kell alkalmaznunk:
ha találunk emelkedő trendhez tartozó aktív order-t, akkor már elkezdtük a stratégiát
és emelkedő trendben vagyunk (inited = true, trend = 1)
ahány ilyen order-t találunk, annyi az elért szintek száma (level++) és hozzáállítjuk a
kötésméret szorzót (multi *= 2)
meghatározzuk a legmagasabb szinthez tartozó árfolyamot
inverz módon járunk el negatív trendben
ha csak függő megbízásokat találunk, akkor már futott a robot, de szintet nem értünk
el
A stratégia indításához vagy folytatásához elengedhetetlen a megfelelő kötésméret
meghatározása, ami a következő lépés.
Automatikusan kereskedő robot fejlesztése és optimalizálása
24
3.3. Kötésméret meghatározása
Ezen funkciót a calcLot() függvényünk végzi:
void calcLot()
{ // a kockáztatni kívánt tőke meghatározása
double riskCapital = AccountBalance() * maxLoss / 100;
double x = 0.0;
if (lots != 0.0)
{ // ha kézzel meg van adva a lotméret, nem számolunk
lot = lots;
return;
}
else
{
for (int i = 1; i <= maxLevel; i++)
{ // a megadott paramétereknek megfelelő tőkeigény számolása
x += levelDistance *
MarketInfo(Symbol(),MODE_TICKVALUE)*digitMul*(MathPow(2.0,i))*(maxLevel -
i);
} // visszaosztás lotméretre
lot = MathRound(riskCapital * 100 / x) / 100;
//egy tizedes pontosságú megadhatóság esetén lefelé kerekítés
if ((MarketInfo(Symbol(),MODE_LOTSTEP)) == 0.1)
lot = MathFloor(lot * 10) / 10;
// riasztás ha kevés a tőke a megadott paraméterekhez
if (lot < MarketInfo(Symbol(),MODE_MINLOT)) {
lot = MarketInfo(Symbol(),MODE_MINLOT);
Alert("Warning! Capital not enough to reach maxLevel at minimum lot
size! Using minimum lot size, but risks are higher!");
}
}
}
Először is meghatározzuk, hogy mekkora tőkét szeretnénk kockára tenni, amit a
riskCapital változóban eltárolunk. Segítségünkre, az AccountBalance() visszatér a számlán
lévő letét méretével, majd a maxLoss extern változóval számolunk. Amennyiben kézzel adtuk
meg a kötésméretet a lots extern-ben, úgy a következő számolást nem vesszük figyelembe. A
kiszámításhoz létrehozott képlet a következő:
∑
ahol tickValue az árfolyam egy pip-es változása és egy lot-os kötésméret esetén bekövetkező
profit vagy veszteség, amit a MarketInfo függvénnyel lekérdezünk. A többi változó ismert.
A maxLevel változóval megadjuk, hogy hány szintet bírjon ki a stratégia, mielőtt elérnénk a
letét korlátját. (Ezt később optimalizálással határozzuk meg minden devizapárra.) A ciklusban
az x változóba összegezzük a szükséges tőkemennyiséget. Majd ezt követően a riskCapital-t
osztjuk x-szel, hogy megkapjuk a kötésméretet, viszont ezt két tizedes jegyre kell kerekíteni,
Automatikusan kereskedő robot fejlesztése és optimalizálása
25
mert a brókerek — jobb esetben — ilyen pontossággal fogadják. Ha mégsem így lenne, tehát
a brókerünk eggyel pontatlanabb, akkor ez a MarketInfo függvény „mode_lotstep”
argumentumával kiolvasható. Elképzelhető viszont, hogy a számlán lévő tőke a robot
paraméterek szerinti működéséhez kevés. Ekkor egy riasztás ablakot jelenítünk meg,
miszerint a kockázatok magasabbak a letét csekélysége miatt, és folytatjuk a működést a
lehetséges legkisebb kötésegységgel.
Miután a változóink értékeit kiszámoltuk vagy beállítottuk — az esetleges korábbi értékekre
— az init() átadhatja a vezérlést a start() függvénynek.
3.4. A központi logika
Mint már korábban említettük, ezt a speciális metódust a terminál (majdnem) minden
tick-re meghívja, ezért a bonyolultságát, hosszát, futási idejét minimálisra kell szorítani. Ezt
az elgondolást követve a MacroScalper esetében gyakorlatilag csak az árfolyam és a szintek
viszonyának a figyelése a feladata, eltekintve egy-két apróságtól.
int start()
{
if (CheckV()) return(0); // ha jogosulatlan a használat, visszatérés
timer(); // napon belüli időzítés
Comment("current level: ",level,"\nbasic lot size: ",lot,"\nlevel price:
",zeroLevel,"\nnew cycle allowed: ",newCycle); // komment kiírása a chartra
// kényszerített leállítás
if (ForceCloseAllandExit) { newCycle=false; CloseAll(); Sleep(3000); }
// ha nincs másik ciklus, akkor új indítása
if (newCycleAllowed && !began && newCycle) begin();
// szintlépés felfelé és lefelé
if ((aboveLevel() < Close[0]) && trend != (-1)) marketSenti = 1;
if ((belowLevel() > Close[0]) && trend != 1) marketSenti = (-1);
// zárási feltételek, vagyis visszacsapás esetén zárás
if (((aboveLevel()-closeGp) <= Close[0]) && trend == (-1)) CloseAll();
if (((belowLevel()+closeGp) >= Close[0]) && trend == 1) CloseAll();
// szintépítő függvények hívása
if (marketSenti == 1 && began) Long();
if (marketSenti == (-1) && began) Short();
return(0);
}
Az indulást követően meghívjuk a felhasználó jogosultságát ellenőrző függvényt, amit
később részletesebben tárgyalunk. Amennyiben nincs jogosultság vagy lejárt, a robot nem
indítja el a stratégia végrehajtását, hanem mindig visszatér a start()-ból.
Automatikusan kereskedő robot fejlesztése és optimalizálása
26
A timer() metódus segítségével időzíthetjük, hogy a program a nap mely szakában
kereskedjen, így lehetővé téve a „skalpolás” technika alkalmazását pl. az ázsiai tőzsdék nyitva
tartása alatt. (A piac mozgásának jellege eltérő a nap különböző szakaszaiban.)
A ForceCloseAllandExit egy manuális boolean kapcsoló az extern-ek között, amellyel
lezárhatjuk az összes futó ügyletet és leállíthatjuk a robotot. A Comment(…) metódus a chart
bal felső sarkába ír ki általunk megadott szöveget. Használata javasolt úgy hibakeresésnél,
mint normális működés esetén információközlés célzattal.
A lényegi részekhez érve láthatjuk, hogy három boolean változó korlátozza a begin(),
vagyis a stratégia indító függvényének hívását. A newCycleAllowed értékét a korábban
említett timer() metódus kezeli a beállításainak megfelelően, tehát új ciklus nem indulhat a
megadott időintervallumon kívül. A newCycle extern hasonló feladatot lát el annyi
különbséggel, hogy kézzel állítható. Egyszerűségéhez képest igen hasznos nagy levelDistance
esetén, amikor egy ciklus napokig is tarthat, és nem szeretnénk a kikapcsolhatóságra várva
óránként ellenőrizni a szoftvert. Végül a began változó akkor válik igazzá, amikor a begin()
lefutott a ciklus elején, de többször már nincs rá szükség. Az aboveLevel() és belowLevel()
egyszerű függvények, a jelenlegi fölötti és alatti szint árfolyamának értékét adják vissza,
amiket felhasználunk a marketSenti változó értékének beállításához. Az érték 1, ha az utolsó
gyertya záró ára (Close[0]) meghaladja a következő szintet, illetve -1, ha Close[0] az alsó
szint alá esik, valamint egyik esetben sem vagyunk az ellentétes trendben, ugyanis ekkor más
következik. Ez pedig a CloseAll() metódus, aminek a feladata a ciklus zárása, az összes ügylet
törlése. A közbenső szintek kialakításához a Long() és Short() függvényeket használjuk, amik
a CloseAll()-lal ellentétes esetben hívódnak. A start() első hívásánál rögtön következik a
begin() indító metódus.
3.5. A stratégia indítása
void begin()
{
// fő vezérlő gomb használhatóvá tétele
if(!IsExpertEnabled() && !IsTesting()) return;
Sleep(1000);
RefreshRates(); // új tick adatainak betöltése
zeroLevel = Close[0]; // alapszint az utolsó gyertya záró ára
//Emelkedő trend megbízásainak kiadása
orderSend(Symbol(),OP_SELLLIMIT,lot*2.0,aboveLevel()+spreadCalc(),slippage,
0,zeroLevel,"macroscalper v5 init long",magic,0,Green);
Automatikusan kereskedő robot fejlesztése és optimalizálása
27
orderSend(Symbol(),OP_BUYSTOP,lot,aboveLevel()-
spreadCalc(),slippage,zeroLevel,0,"macroscalper v5 init
long",magic,0,Green);
//csökkenő trend megbízásainak kiadása
orderSend(Symbol(),OP_BUYLIMIT,lot*2.0,belowLevel()-
spreadCalc(),slippage,0,zeroLevel,"macroscalper v5 init
short",magic,0,Green);
orderSend(Symbol(),OP_SELLSTOP,lot,belowLevel()+spreadCalc(),slippage,zeroL
evel,0,"macroscalper v5 init short",magic,0,Green);
checkNewOrders(); // kiadott megbízások ellenőrzése
began = true; // elindult a ciklus
}
Rögtön az első sorban IsTesting() és IsExpertEnabled() függvények ilyen alkalmazása
először furcsának tűnhet, azonban egy a terminálban felfedezhető hibát orvosol. A terminál
kezelőfelületén található egy gomb, amellyel az összes robotot lehet abban megakadályozni,
hogy élesben kereskedjenek, viszont a futásukat semmiben sem gátolja. Ennek a gombnak az
állapotát kérdezi le az IsExpertEnabled(), az IsTesting() pedig tesztelés futtatása esetén ad
vissza igazat. A fenti összeállítás lehetővé teszi, hogy élesben a gomb megfelelően működjön,
ne csak hibák dobálására késztesse a robotot, ugyanakkor a tesztelésre ne legyen hatással.
A következő részben a Sleep(int ms) metódussal egy másodperc pihenőre késztetjük, majd a
RefreshRates() függvénnyel manuálisan frissítjük a legújabb tick-re az adatokat. Ezt követően
pedig beállítjuk az induló szintet. Ennek a kódrésznek akkor van jelentősége, ha hétvégén
helyezzük új számlára a robotot, ugyanis ekkor a piac áll, nem érkeznek új adatok, viszont az
előző adatokat nem akarjuk felhasználni, mivel jellemzően hétvége után réssel nyit a piac.
Következnek az orderSend(), vagyis a pozíciónyitó függvények. A stratégia szerint
nyitjuk meg a függő megbízásokat az alsó és a felső szinten, némi korrekcióval, amire később
kitérünk. A checkNewOrders() — a kód leghosszabb metódusa — egy esetleges hálózati-
vagy szerverhiba esetén helyreállítja a megfelelő állapotot, majd a began állapotváltozót
igazra állítjuk.
Az MQL beépített függvénye OrderSend(), viszont ez magában megbízhatatlan.
Ehelyett készítettem egy visszaellenőrző és javító függvényt, amit kis kezdőbetűvel írtam.
3.6. Javított megbízáskiadó függvény
A függvényt sikeresen alkalmaztam több elkészült Forex robotban is.
int orderSend(string symbol, int cmd, double volume, double price, int
slippage, double stoploss, double takeprofit, string comment, int magicn,
datetime expiration, color arrow_color)
{
RefreshRates();
Automatikusan kereskedő robot fejlesztése és optimalizálása
28
int ticket = (-1); // azonosító tárolására
for (int i = 0; i<=reTryCount; i++) // újrapróbálkozások hiba esetén
{
ticket =
OrderSend(symbol,cmd,volume,price,slippage,stoploss,takeprofit,comment,magi
cn,expiration,arrow_color); // megbízás kiadása és azonosító elmentése
Sleep(reTryTime*1000); // várunk a feldolgozásra
// ha sikerül megtalálni az ordert az adatbázisban, minden OK
if (OrderSelect(ticket, SELECT_BY_TICKET)) break;
Print("Order Open Error: ", GetLastError()); // hiba kiírása a naplóba
}
return (ticket); // visszatérünk az azonosítóval
}
Mint látható, meglehetősen sok argumentummal kell számolnunk, ez azonban teljesen
megegyezik az eredeti függvény argumentumaival. Vegyük sorra őket:
symbol: a cél devizapár jelölése pl. EURUSD (string)
cmd: az ügylet fajtája pl. OP_SELL, OP_BUY, OP_SELLLIMIT, OP_BUYSTOP stb
volume: az ügylet kötésmérete lot-okban
price: nyitási ár
slippage: a nyitóártól való eltűrt legnagyobb eltérés
stoploss: stoploss árszint (maximális eltűrt veszteség szintje)
takeprofit: takeprofit árszint (nyereséggel kiszállás szintje)
comment: szöveges megjegyzés
expiration: lejárati idő (csak függő megbízásoknál)
arrow_color: a chart-on megjelenő jelzés színe
A beépített OrderSend() visszatérési értéke egy ticket szám. Ez a megbízás egyedi
azonosítója. A probléma, hogy túlterheltség esetén — ami gyakran előfordul — egyszerűen
hibával tér vissza a függvény, anélkül hogy újra próbálkozna. Gyakorlatilag ezt teszi meg ez a
keretfüggvény. Megadott számú másodperc késleltetés után (Sleep(ms)) rákeresünk a ticket-re
a bróker adatbázisában az OrderSelect függvény segítségével. Ez a függvény igazzal tér
vissza, ha megtalálta a megbízást, így ebben az esetben kiléphetünk abból az ismétlő
ciklusból, amely megadott alkalommal újrapróbálkozik hiba esetén, illetve kiírja a naplóba a
hiba okát. Nagyon fontos a próbálkozások között frissíteni az adatokat, főleg azonnali
megbízásoknál, ugyanis az árfolyam folyamatosan változik.
Automatikusan kereskedő robot fejlesztése és optimalizálása
29
Éles tesztek során bizonyítást nyert, hogy a fenti egyszerű megoldás szép számú hibát kezelt
le, viszont egy-két esetben kevésnek bizonyult, így kénytelen voltam egy komplexebb
megoldást alkalmazni, amit a checkNewOrders() valósít meg.
3.7. Megbízások komplex visszaellenőrzése
A checkNewOrders() kétségtelenül a program legterjedelmesebb metódusa, ezért a
kódból csak egy-két fontosabb részletet mutatunk be. Az elgondolás és megközelítés nagyon
hasonló a reStart() metódushoz, amiben a meglévő aktív ügyletekből rekonstruáltuk a ciklus
indítását követő eseményeket, és ennek megfelelően állítottuk be a változókat. Jelen függvény
esetében viszont inverz módon a változók értékeihez hasonlítjuk, majd ha kell, korrigáljuk a
számlán lévő aktív és függő megbízásokat.
…
for (int c = OrdersTotal(); c >=0 ; c--) // megbízások végigpásztázása
{
OrderSelect(c,SELECT_BY_POS,MODE_TRADES); //kiválasztás
if (OrderMagicNumber() == magic) // EA szűrő
{
if (level > 0) //növekvő trend esetén
{
if ((limitLot == OrderLots()) && (OrderType() ==
OP_SELLLIMIT)) // megfelelő selllimit order azonosítása
{ // ha találtunk, akkor elmentjük
if (limitCount == 0) limitTicket = OrderTicket();
limitCount++;
if (limitCount > 1)
{ // ha többet találtunk, töröljük a feleslegeseket
if (OrderDelete(OrderTicket()))
{
limitCount--;
// a hiba naplózása
Print("Duplicate selllimit deleted!");
}
…
A forráskód ezen része megkeresi a szükséges függő eladási megbízást növekvő trend
esetén. Ezt az order-t a szint számának megfelelő kötésmérettel lehet azonosítani. Az első
ilyen megbízás számát eltároljuk, majd az összes többi ilyen megbízást töröljük. (Az
egyszerűbb korrigáló metódus „túlműködése” okozhat dupla order-eket.) Ugyanezt a
módszert követjük a többi hét fajta megbízás esetén. Amennyiben az order-ek közül hiányzik
valamelyik, azt pótolnunk kell:
…
if (level > 0)
{ //emelkedő trend ordereinek újranyitása, ha nem találtuk meg
if (limitTicket == (-1))
{ // limit order esetén
Automatikusan kereskedő robot fejlesztése és optimalizálása
30
Alert("Retrying SellLimit order! Please check reTry* externs and
network connection!"); // riasztás a hibáról
limitTicket =
orderSend(Symbol(),OP_SELLLIMIT,(lot*(2.0*multi)),aboveLevel()+spreadCalc()
,slippage,/*(aboveLevel()+(2.0*levelDist))*/0,zeroLevel,"macroscalper v5
long",magic,0,Yellow); // újranyitás, majd azonosító elmentése
}
if (stopTicket == (-1))
{ // stop order esetén
Alert("Retrying BuyStop order! Please check reTry* externs and
network connection!"); // riasztás a hibáról
stopTicket = orderSend(Symbol(),OP_BUYSTOP,(lot*multi),aboveLevel()-
spreadCalc(),slippage,zeroLevel,/*(aboveLevel()+(2.0*levelDist))*/0,"macros
calper v5 long",magic,0,Yellow); // újranyitás, azonosító elmentése
}
…
A pótlások közben is eltároljuk a jó megbízások azonosítóját, így a metódus végén
ellenőrizni tudjuk, hogy érvénytelen maradt-e bármelyik érték:
…
if ((level != 0) && ((limitTicket == (-1)) || (stopTicket == (-1))))
{ // trend megbízásai megvannak-e
Alert("Still couldnt put level orders! Retrying...");
Sleep(1000*60*2); // ha nem, várunk, és újra próbálkozunk
checkNewOrders();
}
if ((level == 0) && ((initBuyLimitTicket == (-1)) || (initBuyStopTicket ==
(-1)) || (initSellStopTicket == (-1)) || (initSellLimitTicket == (-1))))
{ // kezdő megbízások megvannak-e
Alert("Still couldnt put init orders! Retrying...");
Sleep(1000*60*2); // ha nem, várunk, és újra próbálkozunk
checkNewOrders();
}
…
Ha még ilyenkor is maradtak ki order-ek, az egyértelműen szerver vagy hálózati
hibára utal. Ilyen esetben két percre várakozó stádiumba tesszük a robotot, majd ismét
megpróbálkozunk a korrekcióval. Előbb vagy utóbb mindenképpen sikerrel járunk, és
folytatódhat a végrehajtás.
3.8. A szintek építése
Visszatérve a hálózati hibák lekezelésétől folytathatjuk a stratégia implementálását. A
begin() metódus sikeres végrehajtása után a start() figyeli az árfolyam alakulását. Az egyik
lehetséges eset, hogy az ár átlépi az 1-es árfolyam szintet, és teljesül a korábban kiadott két
függő megbízás. Inverz módon bekövetkezhet a másik oldalon, a -1-es szinten levő order-ek
teljesülése. Ezen szintek elérésekor az oldaltól függően egy-egy metódus hívására van
szükség a stratégia következő lépésének megtételéhez.
Automatikusan kereskedő robot fejlesztése és optimalizálása
31
void Long()
{
if (level == 1) closeOpposite(); // felesleges megbízások törlése
Print("long");
trend = 1; // állapotváltozók korrigálása
level++;
multi = multi*2.0;
RefreshRates();
zeroLevel = Ask; // új alapszint
orderSend(Symbol(),OP_SELLLIMIT,(lot*(2.0*multi)),aboveLevel()+spreadCalc()
,slippage,0,zeroLevel,”macroscalper v5 long”,magic,0,Yellow);
orderSend(Symbol(),OP_BUYSTOP,(lot*multi),aboveLevel()-
spreadCalc(),slippage,zeroLevel,0,”macroscalper v5 long”,magic,0,Yellow);
// megbízások kiadva, időközi trend semleges
marketSenti = 0;
checkNewOrders(); // megbízások ellenőrzése
stopLevel(); // stoploss és takeprofit szintek beállítása
}
Kezdetben beállítjuk a trend, level és multi változókat, illetve a zeroLevel-t az aktuális
szintre állítjuk. A trend, level és zeroLevel a későbbi szintek azonosításához illetve a vezérlés
logikájához szükségesek. A multi változó az alap lot-méret martingale szerinti szorzója, így
minden szint elérésekor kétszeresére emeljük. Majd megtesszük a szükséges megbízásokat, és
a korábban bemutatott checkNewOrders() függvénnyel bizonyosodunk meg azok meglétéről.
Azonban a régebbi megbízások Stoploss és Takeprofit szintjéről sem feledkezhetünk el:
void stopLevel()
{
for (int cnt = OrdersTotal(); cnt >=0 ; cnt--)// megbízások végigpásztázása
{
OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES); // kiválasztás
if (OrderMagicNumber() == magic) // EA szűrő
{
// a 4 fajta ordert 4 különböző stoploss és takeprofit értékre kell
módosítani
if((OrderType()==OP_BUY) && (trend == 1))
OrderModify(OrderTicket(),OrderOpenPrice(),belowLevel(),OrderTakeProfit(),0
,Violet);
if((OrderType()==OP_BUY) && (trend == (-1)))
OrderModify(OrderTicket(),OrderOpenPrice(),OrderStopLoss(),aboveLevel(),0,V
iolet);
if((OrderType()==OP_SELL) && (trend == 1))
OrderModify(OrderTicket(),OrderOpenPrice(),OrderStopLoss(),belowLevel(),0,V
iolet);
if((OrderType()==OP_SELL) && (trend == (-1)))
OrderModify(OrderTicket(),OrderOpenPrice(),aboveLevel(),OrderTakeProfit(),0
,Violet);
}
}
}
Automatikusan kereskedő robot fejlesztése és optimalizálása
32
A stopLevel() metódus egyszerűen végigjárja az összes aktív ügyletet, és az
OrderModify() beépített függvény segítségével gondoskodik a záró árak megfelelő
beállításáról. Ezen szinteknek a robot megfelelő működése esetén nincs jelentősége, azonban
egy észrevétlenül maradt leállás, üzemzavar esetén sem hagyhatjuk az ügyleteinket céltalanul,
egy intervallumba kell szorítani őket a tőkénk védelme érdekében.
Amikor az árfolyam több szintet elért, már nincs szükség a kezdetben kiadott
ellenoldali függő megbízásokra. Ezeket minden további nélkül törölhetjük, és meg is tesszük
a closeOpposite() metódussal. A megvalósítás az előzőek ismeretében igen egyszerű. A
megbízások végignézésével könnyedén megállapítható melyek a törlendő order-ek.
Legegyszerűbb, ha az OrderComment() függvénnyel lekérdezzük a megbízás komment
mezőjében tárolt string-et. Ha trend=1 esetén ez „macroscalper v5 init short”, illetve trend=-1
esetén „macroscalper v5 init long”, akkor törölhetők az order-ek.
Tegyük fel, hogy az árfolyam szépen ível felfelé, egyre nagyobb kötésegységek
használatára kényszerítve a robotot. Minden szinttel feljebb egyre valószínűbb egy korrekció
kialakulása. Amikor az árfolyam visszacsap az előző szinthez, a számlánkon futó ügyletek
egyenlege pozitívba fordul, így zárhatjuk az összes pozíciónkat szép profittal. Erre a feladatra
a CloseAll() metódus készült.
3.9. A stratégia zárása, kiszállás
A CloseAll() függvény ugyanazt a sémát követi, amit eddig használtunk, vagyis a
megbízásokon végighaladva teszi a dolgát, jelen esetben az ügyletek zárását:
void CloseAll()
{
int closecnt = 0;
Print("CloseAll");
for (int cnt = OrdersTotal(); cnt >=0 ; cnt--) //pásztázzuk a megbízásokat
{
Sleep(300);
OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES); // célmegbízás kiválasztása
if (OrderMagicNumber() == magic) // EA szűrés
{
RefreshRates(); // mindig friss árfolyamadat kell
if (OrderType()==OP_BUY) // vételi megbízások
for (int b = 0; b < reTryCount; b++)
{ // ha gond van, újra próbálkozás
if(!OrderClose(OrderTicket(),OrderLots(),Bid,slippage,Violet))
{ // ha gond van, hamis a visszatérés értéke
Sleep(reTryTime*1000);
RefreshRates();
Print("Error while closing: ", GetLastError()); // hiba logolása
} else
{ break;
Automatikusan kereskedő robot fejlesztése és optimalizálása
33
cnt++; }
}
// itt a függő megbízások, és a sell order-ek zárása van analogikusan
…
A CloseAll() függvény terjedelmére való tekintettel kihagyjuk a függő és eladási megbízások
lekezelésére használatos kódrészt. A fenti, vételi order-ek esetén alkalmazott rész
analógiájára egyszerűen elkészíthető.
…
// megszámoljuk, maradt-e megbízás
for (int ct = OrdersTotal(); ct >=0 ; ct--)
{
OrderSelect(ct,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == magic)
closecnt++;
}
if (closecnt > 0)
{ // ha igen, újra hívjuk a függvényt, és a naplóba írjuk a hibát
CloseAll();
Print("CloseAll function couldnt close all orders, retrying! Check your
network connection!");
}
else { // ha minden rendben ment, nullázzuk a változóinkat az újrakezdéshez
level = 0;
marketSenti = 0;
trend = 0;
multi = 1.0;
began = false; // nincs folyamatban ciklus
calcLot(); // lotméret kiszámítása
if (sendMail == true) SendMail("MacroScalper cycle complete on
"+AccountName()+" "+AccountNumber()+" account","New balance: "+"
"+AccountBalance()+"\nAccount profit: "+AccountProfit()); // email küldése
if (!newCycle) PostMessageA( WindowHandle( Symbol(), Period()), WM_COMMAND,
33050, 0); // ha nincs engedélyezve új ciklus, akkor bezárjuk a programot
}
}
Az order-ek zárását illetve a megmaradt függő megbízások törlését az OrderClose() és
az OrderDelete() függvények hajtják végre. Visszatérési értékük igaz, ha a művelet sikeresen
ért véget. Minden megbízásnak záródni kell közel azonos árfolyamon ahhoz, hogy a stratégia
egy ciklusa sikerrel záruljon, ezért biztosítani kell, hogy ez megtörténik. A fenti forrásban ez
duplán jelen van. Egyrészt az orderSend() saját függvénynél bemutatott visszaellenőrzéssel és
újrapróbálkozással megoldva. Másrészt a törlő ciklust követően megszámoljuk a megmaradt
order-eket, és ha a számuk nagyobb mint nulla, akkor újra hívjuk a függvényt.
A sikerrel lezárt ciklust követően kezdeti állapotukra kell állítsuk az
állapotváltozóinkat, és mivel a tőke mennyisége is megváltozott, így a kötésméretet is újra
kell számolni. További lehetőség a felhasználó kívánságára automatizált e-mail küldése,
amelyben a számla egyenlegén kívül közölhetünk egyéb hasznos adatokat is. A levelező
szerver eléréséhez a beállításokat a terminálban kell megtenni. A newCycle extern változó
Automatikusan kereskedő robot fejlesztése és optimalizálása
34
hamisra állításával jelezhetjük a robotnak korábban, hogy több ciklust ne indítson, így ekkor a
chart-ról automatikusan leválik és véget ér futása.
Automatikusan kereskedő robot fejlesztése és optimalizálása
35
4. Tesztelés és az optimális paraméterek meghatározása
Az automatizált kereskedő rendszer első működőképes változatának leprogramozása után
a következő lépés a szoftver letesztelése. A tesztelés két fajtáját különböztetjük meg:
„back testing”, azaz „vissza” tesztelés: Jelentése, hogy az elkészült robotot múltbeli
adatokon lefuttatjuk egy szimulált környezetben. Ehhez a MetaTrader platform
beépített stratégia tesztelő modulját használjuk. A fejlesztés korai fázisaiban szokás
alkalmazni ezt a módszert. Előnye, hogy pár perc alatt akár hónapok, évek
árfolyamadatain próbálhatjuk ki a kereskedő szoftvert. Azonban ezek az adatok sok
helyen hibásak, rések figyelhetők meg bennük, ami igen hátrányosan befolyásolja a
tesztelés eredményének pontosságát.
„forward testing”, vagyis „előre” tesztelés: A tesztelés ezen módja jóval közelebb áll
a valósághoz, mivel élő piaci adat inputokra kell reagálnia a szoftvernek. Továbbá a
futási környezet, a bróker szerverével való kapcsolat is teljesen megegyezik az éles
számlánál tapasztalhatókkal. A teszteléshez egy demo számlát kell nyissunk
valamelyik brókercégnél, amelyet tetszőleges mennyiségű játékpénzzel indítunk el. A
robot működését így csaknem valós környezetben figyelhetjük meg. Hátránya, hogy
rendkívül időigényes. A roboton végzett ilyen jellegű tesztelés eredménye 2011.04.21-
től 2011.08.15-ig a mellékletben található.
4.1. Tesztelés múltbeli adatokon
A tesztelés kezdeti fázisában célunk még nem a robot teljesítményének mérése, hanem
kizárólag helyes működésének ellenőrzése. Ezt a lépést nagyban megkönnyíti, ha korábban a
kritikus részekhez beépítettünk egy-egy hibakeresést segítő naplófájlba írást. Ilyenek lehetnek
például a robot állapotával kapcsolatos változók kiíratása, a vezérlés helyzetének
meghatározása. Egy esetleges hiba vagy helytelen működés esetén a naplófájl segítségével
egyszerűen felderíthető a hiba forrása, illetve eszközölhető a javítás.
Ezen túlmenően a hibakeresést nagyban leegyszerűsíti a stratégia tesztelő modulba
épített vizuális tesztelési lehetőség, amit a 3. ábrán szemléltetünk. A tesztelés működése
lényegesen lelassul a bekapcsolásával, ám így a chart-on követhetjük az eseményeket, a
folyamat sebességét szabályozhatjuk, vagy akár egyéb indikátorokat is csatolhatunk a chart-
hoz.
Automatikusan kereskedő robot fejlesztése és optimalizálása
36
3. ábra: Vizuális visszatesztelés
Az esetleges hibák felfedezését és elhárítását követően a figyelmünket a robot
eredményességére fordíthatjuk. A vizuális módot kikapcsoljuk, mert csökkenti a teszt
sebességét és pontosságát. Az „expert tulajdonságok” menüpont alatt ésszerű beállításokkal
látjuk el a bemeneti változókat, mivel az optimális értékeket ezen a ponton még nem
ismerjük. Kiválasztjuk a kívánt idősíkot és devizapárt, illetve a tesztelni kívánt
időintervallumot, ami jelen esetben 2010. január 1. és 2011. január 1. közötti időszak, majd
elindítjuk a tesztet. A teszt pár percet követően véget ér, és a 4. ábrán látható jelentést
szolgáltatja.
4. ábra: A robot egy visszatesztelésének jelentése
A jelentésből a következő adatok olvashatók ki:
a modellezési minőség 90%-os, tehát elfogadható jó közelítésnek a teszt eredménye
Automatikusan kereskedő robot fejlesztése és optimalizálása
37
a 10000 euró kezdőtőkéhez a robot nyert 5537 eurót, ami éves 55,37%-os hozamot
jelent
a maximális lehívás 33,54%, tehát a tesztelt időszakban a tőkénk ekkora részét
kockáztattuk a legrosszabb esetben, ami azt jelenti, hogy a kötésméret emelésével és
nagyobb kockázat elviselésével a hozam tovább növelhető
A többi adat a stratégia jellege miatt lényegtelen, ám pontos beszállásra játszó robotok
esetében nagyon hasznos információk. Azonban a tőkegrafikonra (5. ábra) is érdemes egy
pillantást vetni.
5. ábra: A tőke mennyiségének alakulása a visszatesztelés alatt
A függőleges tengely a tőkét, a vízszintes pedig az ügyletek számát jelenti, így a stratégia
sajátosságai miatt a grafikon eltorzult, mivel nagy számú kötés záródik egyszerre. A
valóságban a tőkében bekövetkező rapszodikus hullámzás tíz másodpercen belül történik.
Mindent összevetve nem teljesít rosszul a robot, főleg ha figyelembe vesszük, hogy a
bemeneti változók nem az optimálisak voltak, tehát magasabb profitot is kihozhatunk belőle.
4.2. Optimalizálás
Az optimalizálás az a folyamat, amelynek során megállapítjuk vagy közelítjük azokat
az input paramétereket, amelyek a leghatékonyabbak illetve a legjobb eredményt hozzák.
Több megközelítés és módszer létezik a tőzsdei robotok optimalizálására, amelyek
más-más típusú stratégiák esetén hoznak megfelelő eredményt. Azon robotok, amelyek rövid
időtávú chart-okra — például M1, M5, M15 (egy perces, öt perces, tizenöt perces)
grafikonokra — lettek tervezve és viszonylag sok ügyletet kötnek gyakori optimalizálásra
szorulnak, mivel a piaci mozgások jellege állandóan változik. Egy jól jövedelmező időszak
után az ilyen szoftver egyre több veszteséges ügyletet fog kötni. A következő technikát
alkalmazzuk a teljesítmény helyreállításához. A számlánk kötéslistájából meghatározzuk azt
Automatikusan kereskedő robot fejlesztése és optimalizálása
38
az időszakot, amelyben a profit faktor csökkenni kezd. Az optimalizálás mintájának ezen
időszakot vesszük a jelenig bezárólag. Több hónapra vagy évre visszamenőleg már nem
relevánsak az adatok, kivéve különleges eseteket. Például a 2008 őszén kibontakozó válság
időszaka mutat hasonlóságokat a 2011 augusztusától jelen dolgozat írásának idejéig.
Amennyiben nem rendelkezünk korábbi tapasztalatokkal, úgy megfelelő 2-3 hónapos, a
jelenlegit megelőző időszakot venni.
A kisebb, de hosszabb ideig stabil növekedést ígérő robotok — mint például a
trendkövető rendszerek — szélesebb időtávokon használatosak, így az optimalizálás is más
technikát kíván. Főleg egy és négyórás chart adatokat használunk több évre visszamenőleg
úgy, hogy egy pár hónapos időszakot kihagyunk a jelenig. Az optimalizálás során kijött
paraméterekkel pedig tesztet készítünk erre az időszakra. Amennyiben az eredmény kielégítő,
várhatóan hónapokig csak a hozamgörbe emelkedését kell figyelnünk. Jelen rendszerünk is az
utóbbi csoportba tartozik.
Az optimalizálás elvégzéséhez a MetaTrader stratégia tesztelőjét kell igénybe
vennünk. A teszteléssel szemben itt intervallumokat és a lépések nagyságát kell megadnunk
minden optimalizálni kívánt paraméterhez, ahogyan a 6. ábrán is láthatjuk. A többi inputnál
az egyszerű értékeket veszi figyelembe a program.
6. ábra: Inputok megadása a stratégia tesztelőben
Az „optimalizáció” fül alatt megszorításokat adhatunk ki az elfogadott eredményekre nézve, a
7. ábrán látható kritériumokkal. Ezek megadása gyorsíthatja a folyamatot, ugyanis a korlátot
elérve egy eredmény még az aktuális teszt vége előtt elvethető. Számunkra a maximális
lehívás és a minimális margin szint érdekes, ugyanis ezek határozzák meg a tőkéből
kockáztatott legnagyobb összeg korlátját.
Automatikusan kereskedő robot fejlesztése és optimalizálása
39
7. ábra: Megszorítások az optimalizálásban
A művelet során a modul gyakorlatilag múltbeli adatokon való tesztelések sorát végzi
el. A MetaTrader régebbi verzióiban ez a lehetséges összes variáció kiszámítását jelentette,
ami igen idő- és számításigényes, azonban pontos adatokkal szolgál. Az újabb stratégia
tesztelőben megvalósították a genetikus algoritmus használatát, amivel akár tizedére is
csökkenthető az optimalizáláshoz szükséges idő, ugyanis nem szükséges az összes variáció
kiszámítása, azonban nem kapunk pontos eredményt. Az optimalizálandó input paraméterek
számának növelésével a szükséges idő exponenciálisan nő, és az eredmények is
pontatlanabbak, azonban ezeket később ellenőrizhetjük és pontosíthatjuk egyszerűen. A
MacroScalper optimalizálásánál a következő beállításokat használtuk az EURUSD párra:
M30 (fél órás) chart, 2010.04.01-2011.04.01 időszak,
optimalizálandó paraméterek: levelDistance 50 és 150 között 10-es
lépésközzel, valamint maxLevel 5 és 10 között 1-es lépésközzel.
Tehát az optimalizációs minta egy év. Az ezt követő fél évre pedig lehetőségünk lesz
tesztelni, ellenőrizni a beállításokat. A levelDistance optimális értéke minden devizapár
esetén különböző, illetve ehhez kell meghatározni a legnagyobb használható kötésegységet a
profitmaximalizálást szem előtt tartva. Az optimalizáció a 8. ábrán látható eredménnyel
zárult.
Automatikusan kereskedő robot fejlesztése és optimalizálása
40
8. ábra: Optimalizáció eredményei
Jól látható, hogy a szintek közötti optimális távolság 120 pip ezen időszakban, a maximális
elérhető szint pedig 6. Az optimalizálás eredményét ezen kívül megtekinthetjük egy
„majdnem” háromdimenziós grafikonon (9. ábra), ahol a szín erőssége jobb eredményt jelent.
A vízszintes tengely a levelDistance, a függőleges tengely pedig a maxLevel változó értékeit
mutatja. Továbbá minél sötétebb színt látunk, az a négyzet annál magasabb hozamot jelent.
Jól látható, hogy az optimalizálás során egyértelműen a 120-as szinttávolság a
legjövedelmezőbb, és a maximális elviselhető kockázat a maxLevel 6-os értéke esetén
jelentkezik. Kisebb érték esetén a profit negatív, tehát túl nagy a kockáztatott tőke
mennyisége, így bukik a stratégia.
9. ábra: Optimalizációs grafikon 3D-ben
Ellenőrizzük le egy egyszerű visszateszteléssel a kapott eredményt.
Automatikusan kereskedő robot fejlesztése és optimalizálása
41
10. ábra: Optimalizálás eredményének letesztelése
A 10. ábrán, vagyis a grafikon elején egy meglehetősen nagy visszalépést láthatunk.
Szándékosan választottuk ezt az időszakot, ugyanis 2010. május 6-án az EURUSD devizapár
a New York-i tőzsdén történt „Flash Crash” miatt soha nem látott zuhanásba kezdett, tehát ez
a stratégiánk számára a legkedvezőtlenebb környezet. Magyarul, ha egy olyan beállítást
találunk, amellyel ezt az időpontot veszteség nélkül túléljük, akkor folyamatos növekedésre
számíthatunk a jövőben is. A maxLoss változót alacsonyabbra állítva a 11. ábrán látható
eredményt kapjuk.
11. ábra: Optimalizálás eredménye némi finomhangolással
Az alkalmazott módszer utolsó lépésében pedig az eddig kihagyott „jövőre” vonatkozó
adatokat is belevesszük a tesztelésbe, illetve a biztonság kedvéért az optimalizált időszak
előtti négy hónapot is, így tehát 2010.01.01-től 2011.10.01-ig ellenőrizzük a robot működését,
amelynek eredménye a 12. ábrán látható.
Automatikusan kereskedő robot fejlesztése és optimalizálása
42
12. ábra: Visszatesztelés hosszabb időszakra
Az eredmény 44,3%-os maximális lehívás mellett 22462.25 euró 10000 kezdőtőkéből
kiindulva. A részletes kötéslista a mellékletek között található.
4.3 A portfólió összeállítása
Az előző részben láthattuk hogyan is lehet egy devizapárra meghatározni a robot
jövedelmező futtatásához szükséges beállításokat. Szerencsére nem kell megelégednünk ezzel
a hozammal, ugyanis több devizapáron való párhuzamos üzemeltetéssel egyszerre növelhető a
profit és csökkenthető a kockázat. A befektetési szakemberektől is gyakran lehet hallani, hogy
„diverzifikálni kell a portfóliót”, így mi sem mehetünk el mellette.
A diverzifikálás egyik alapszabálya, hogy az egymással erősen korreláló eszközök
együttes alkalmazását kerülni kell. A korreláló pénzügyi eszközök árfolyamai együtt vagy egy
irányba mozognak. A Forex esetében sincs ez másképpen. A legjobb példa erre az EURUSD
és a GBPUSD pár, amelyek árfolyama 0,7 körüli korrelációs együtthatót mutat, tehát az idő
körülbelül 70%-ában együtt mozognak. Ennek oka, hogy Nagy Britannia ugyanúgy az
Európai Unió tagja csak saját pénznemmel, így a makrogazdasági események ugyanúgy
hatnak az angol fontra, mint az euróra.
A megfelelő devizapár-kombináció kiválasztásához nem árt némi gazdaságföldrajzi és
–politikai ismeret, viszont a segítségünkre lehet az internetről elérhető, folyamatosan frissülő
Forex korrelációs táblázat, amely a 13. ábrán látható.
Automatikusan kereskedő robot fejlesztése és optimalizálása
43
13. ábra: Forex korrelációs táblázat (H1)
A táblázatból könnyen leolvashatók az együtthatók. A kombináció kiválasztásánál ügyelnünk
kell, hogy sem negatív, sem pozitív erős (50 <) korreláció nem lehet a párok között. A
portfólió összeállításánál azonban arra is érdemes figyelmet fordítani, hogy a brókerünk
mekkora jutalékot számol fel. Egy-két egzotikus páron ez felemésztheti a nyereségünket is.
Ezért a fenti táblázatban is csak viszonylag olcsón kereskedhető devizapárok kaptak helyet. A
portfóliónkhoz három devizapárt választunk ki, amelyek korrelációja minimális.
A kiválasztott párok az EURCAD (euró – kanadai dollár), EURUSD (euró – amerikai
dollár), és az USDJPY (amerikai dollár – japán jen). Meglepő lehet, hogy az euró és az
amerikai dollár kétszer is szerepel a devizák között, viszont a korrelációs együtthatók nem
haladják meg a 0,15-öt. Az alábbi táblázat (14. ábra) mutatja a pontos számokat.
14. ábra: Kiválasztott devizapárok korrelációja
Az ok a devizapárok sajátosságaiban rejlik. Az USDJPY nem korrelál erősen szinte semelyik
másik instrumentummal, ami az USA és Japán sajátos és szoros kereskedelmi kapcsolatának
köszönhető. Az EURCAD-ról és az EURUSD-ről első ránézésre szoros kapcsolat lenne
feltételezhető, hiszen mindkettőben az euró a bázisdeviza, illetve az USA és Kanada egy azon
kontinensen egymás szomszédságában található. Azonban amíg a két ország szoros
kereskedelmi kapcsolatban áll, vagyis Kanadából az USA nyersanyagokat importál, illetve
iparcikkeket exportál oda, addig az EU és Kanada gazdasági kapcsolata nem túl erős, viszont
az USA és az EU nagy lelkesedéssel vásárolják egymás termékeit.
Automatikusan kereskedő robot fejlesztése és optimalizálása
44
Az optimalizálást követően a megfelelő beállítások kiválasztásánál kettős szempontot
kell figyelembe venni. Ha pusztán a maximális profitra koncentrálunk bármi áron, akkor
nagyobb eséllyel következik be a katasztrófa szituáció, tehát némi hasznot fel kell áldoznunk
a kockázatkezelés oltárán. Amennyiben a profit 10-20%-ának elengedésével 30-40%-kal
csökkenthető a maximális lehívás, azt muszáj megtenni. A portfólió párjainak paraméterei is
ebben a szellemiségben lettek kiválasztva.
EURUSD: levelDistance = 120; maxLevel = 6; maxLoss = 50
Profit: 12462,25; maximális lehívás: 44,3%
A grafikon megtekinthető az előző fejezetben (12. ábra).
EURCAD: levelDistance = 230; maxLevel = 4; maxLoss = 100
Profit: 44295.29; maximális lehívás: 20,9%
15. ábra: EURCAD visszatesztelés grafikonja
USDJPY: levelDistance = 120; maxLevel = 4; maxLoss = 100
Profit: 29202,29; maximális lehívás: 28,88%
16. ábra: USDJPY visszatesztelés grafikonja
Automatikusan kereskedő robot fejlesztése és optimalizálása
45
A részletes eredmények és kimutatások a mellékletben kaptak helyet. A vizsgált időszak
minden esetben 2010.01.01-től 2011.10.01-ig tart 10000 EUR kezdőtőkével. A lehívások
összege éppen meghaladja a 100%-ot, de ez valójában szinte nulla valószínűséggel
következik be, mivel ez csak akkor lehetséges, ha a legrosszabb eset egyszerre következik be
mindhárom devizapáron. A diverzifikációnak és korreláció hiányának köszönhetően ennek
esélye csaknem zéró. További devizapárok hozzáadásával, illetve a maximális lehívás
összegét tovább csökkentve még jobban mérsékelhető a kockázat és növelhető az összprofit.
A portfólió hozama összegszerűen az adott időszakban tehát 85959 EUR, viszont ez a
becslés elmarad a reálistól, ugyanis a stratégiát egyszerre mindhárom devizapáron futtatva
azok egymást „segítik”, tehát a kamatos kamat hatása fokozottan érvényesül. Éppen ezért
nyugodtan kerekíthetjük havi bontásra a hozamot egyszerű osztással. Tehát így adódik a
85959 EUR 21 hónapról egy hónapra lebontva 4093,2 EUR, ami a 10000 EUR kezdőtőkéből
számolva körülbelül 40,9%-os havi hozamnak felel meg. Természetesen ezen értékek
szimulációs környezetben születtek, így optimista becslésnek tekinthetők. A valóságban a
bróker jutaléka, illetve az éves 16%-os nyereségadó terheli.
Automatikusan kereskedő robot fejlesztése és optimalizálása
46
5. Konklúzió, összefoglalás
A feladat egy olyan emberi beavatkozás nélkül működni képes program kifejlesztése
volt, amely a nemzetközi devizapiacon a rábízott tőkéből profitot termel pénzpiaci ügyletek
kereskedési stratégia szerinti nyitásával és zárásával minimális felügyelet mellett. Másodlagos
cél a terület megismerése során szerzett tapasztalatok összegyűjtése, valamint a fejlesztés
folyamatának részletes leírása a felmerülő problémák megoldásával együtt, ugyanis az erre a
területre való szoftverfejlesztést oktató, dokumentáló irodalom magyar nyelven egyáltalán
nem, vagy csak több százezer forintos költségtérítéses tanfolyamokon érhető el.
A dolgozat bevezető részében megismerkedtünk a nemzetközi devizapiac jellegével,
sajátosságaival, illetve a tradicionális értelemben vett „tőzsde” és a Forex (Foreign Exchange
- Devizatőzsde) közötti lényeges különbségekkel. Majd szemügyre vettük a legelterjedtebb
kereskedési platformot, vagyis a MetaTrader 4-et, valamint az MQL IDE (MetaQuotes
Language Integrated Developer Environment – MetaQuotes programozási nyelv és integrált
fejlesztői környezet) részeit, működését nagy vonalakban, amelyek a következők:
MetaEditor: a text-editorszerű fejlesztői környezet nyelvi kiemelésekkel
MQL: maga a programozási nyelv
Strategy Tester: a kész rendszerek optimalizálására, tesztelésére való modul
MetaTrader terminal: a fő rendszermodul, amely összefogja a fentieket
A környezet és az eszközök áttekintése után rátértünk magára a stratégiára, amelyet
implementáltunk. A rendszer két — a szakmai közösséget megosztó — módszer
kombinálásával, illetve saját ötleteken alapuló változtatásával jött létre. Ezek pedig a
következők:
grid stratégia: a grafikont egy egyenlő sorközzel rendelkező hálószerkezettel látjuk
el, majd a stratégia alapján cselekszünk, ahogy az árfolyam a háló egyes részei között,
vagy azt átlépve mozog
martingale módszer: a 18. századból származó, de a mai napig vitatott fogadási
módszer. Leegyszerűsítve a tétek duplázását jelenti veszteség esetén. Részletesen,
matematikai alapon tárgyaltuk a stratégiában való alkalmazását, ugyanis a Forex-es
szakmai közönség egy része különösen ellenzi, másik része pedig használja
Automatikusan kereskedő robot fejlesztése és optimalizálása
47
Az elméleti áttekintést követően rátértünk a tényleges programozási folyamatra. Sorra
vettük azokat a buktatókat, problémákat, amelyek egy egyébként jól kigondolt robot
működését megnehezítik, ugyanekkor egy-egy lehetséges — a kész szoftverben is használt —
megoldást mutattunk be. A stratégia folyamatos piaci jelenlétet kíván, így a szoftver minden
hétköznap nonstop működését biztosítani kell, tehát fokozottan kitett a külső hibáknak. Ilyen
problémák adódhatnak a következőkből:
rendszerhiba, újraindítás: sajnos nem szokatlan, de a stratégiát nem szabad fél úton
abbahagyni, így a robot belső állapotát vissza kell hozni az esemény előtti állapotba
hálózati- és túlterheltségből fakadó hibák: fontosabb makrogazdasági hírek
bejelentésének idején általános, hogy a brókerünk adatközpontja túlterhelődhet,
ugyanis sokan ekkor próbálnak nagy haszonra szert tenni
Miután megoldottuk a rendszer stabil működését, áttértünk a stratégia optimális
paramétereinek meghatározására devizapáronként. Erre tökéletes eszköz a stratégia tesztelő
modul, ami — a gyorsabb eredmény elérése érdekében — genetikus algoritmusokat is képes
használni a változók optimálishoz közeli értékeinek meghatározására. Ezen értékekkel pedig
múltbeli adatokon futtattunk szimulációt a szoftver működésére. A szimuláció eredményeit
kitűnően tudtuk használni a robot esetleges hibáinak felderítésére, valamint a stratégia
tökéletesítésére. Végül kiválasztottunk néhány nem korreláló devizapárt a diverzifikáció
szellemében, és kialakítottunk egy alacsony kockázatú és nyereséges portfóliót.
A szakdolgozat témáját képező szoftver szakmai gyakorlat során készült, és
kereskedelmi forgalomban kapható (bérelhető) a Forex Consult Kft-től MacroScalper
fantázianév alatt. A múltbeli adatokon való tesztelést alapul véve átlagosan évi 75% hozam
várható egy devizapáron való futtatással. Az eredmények a dolgozat mellékletében
megtekinthetők. A demo számlán végzett forward test kimutatása is ugyanott hozzáférhető,
azonban a robot a fejlesztés egy korai stádiumától kezdve optimizálatlanul és nem
diverzifikált párokon futott. Ettől függetlenül az eredmény magáért beszél, érdemes egy
pillantást vetni rá.
A szakdolgozat befejezésétől függetlenül a fejlesztés nem áll le, ugyanis egy szoftver
soha nincs „kész”. Az új ötletek és hatékonyabb megoldások implementálása jelenleg is
folyik a robot második generációs változatának fejlesztése közben.
Automatikusan kereskedő robot fejlesztése és optimalizálása
48
Nyilatkozat
Alulírott, Vig Jácint gazdaságinformatikus BSc szakos hallgató, kijelentem, hogy a
dolgozatomat a Szegedi Tudományegyetem, Informatikai Tanszékcsoport Számítógépes
Optimalizálás Tanszékén készítettem, gazdaságinformatikus BSc diploma megszerzése
érdekében.
Kijelentem, hogy a dolgozatot más szakon korábban nem védtem meg, saját munkám
eredménye, és csak a hivatkozott forrásokat (szakirodalom, eszközök, stb.) használtam fel.
Tudomásul veszem, hogy szakdolgozatomat a Szegedi Tudományegyetem
Informatikai Tanszékcsoport könyvtárában, a helyben olvasható könyvek között helyezik el.
2011. november 29.
_______________
Vig Jácint
Automatikusan kereskedő robot fejlesztése és optimalizálása
49
Köszönetnyilvánítás
Hálával tartozom szüleimnek és keresztanyámnak, amiért támogattak a tanulmányaim során.
Köszönettel tartozom témavezetőmnek, Dr Bánhelyi Balázsnak, amiért szívesen fogadott az
egyedi szakdolgozat témával is, illetve a dolgozat írása közben adott hasznos tanácsokért.
Köszönöm munkaadómnak, Várkuti Gézának a kezdetektől fogva belém fektetett bizalmát.
Köszönöm Nagyné Hecskó Gabriellának, hogy engedélyezte a hozzáférésemet a „winterm1”
szerverhez a robot tesztelésére és optimalizálására.
Végül, de nem utolsó sorban köszönöm a Szegedi Tudományegyetemnek és Szeged
városának a szerzett tapasztalatokat, élményeket és tudást.
Automatikusan kereskedő robot fejlesztése és optimalizálása
50
Melléklet
Az 1. ábra teljes méretben:
Automatikusan kereskedő robot fejlesztése és optimalizálása
51
Részletes tesztelési eredmények:
EURUSD