Automatikusan kereskedő robot ... - forex-szignal.hu · A Forex lényege, hogy a pénznemekkel...

54
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

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

Automatikusan kereskedő robot fejlesztése és optimalizálása

52

EURCAD

Automatikusan kereskedő robot fejlesztése és optimalizálása

53

USDJPY

Automatikusan kereskedő robot fejlesztése és optimalizálása

54

Demo számla kivonata 2011.04.21-től 2011.08.15-ig