szerda, március 23, 2011

Készre csiszolás

Megint kicsit elmaradtam, de majd most megpróbálom bepótolni a várva várt készre csiszolással...

Tehát FOREX robotunk már készen van nagyjából, bár igazából még csak a pozíció nyitásokat beszéltük meg. Arról volt szó, hogy pozíció zárás nem is lesz benne, hiszen stop-loss-t fogunk beállítani, ez fogja zárni a pozíciónkat, méghozzá úgy, hogy az árhoz minél közelebb húzzuk.
A folyamatos ár után húzott - követő - stopunkat addig húzogatjuk, amíg a stop-loss a kötési ár fölé/alá (függően attól, hogy long, vagy short pozíciónk van) kerül, lehetőleg minél jobban.
Ekkor, ha az ár visszaesik, akkor a stop-loss ugyan bezárja a pozíciót, de ekkor már nyereséges lesz.
Na, jó, de hogyan lehet ezt csinálni?

A dolog rém egyszerű, a Parabolic trendchaser egyéni indikátort fogjuk ügyesen felparaméterezni, és az ő jelzéseire állítjuk be a stop-loss-t. Sajnos ez nem lesz mindig lehetséges, de erről majd picit később.

Mindenek előtt, a programunk elején, közvetlenül a start() függvény elejére illesszünk be egy új sort, ahol három új változót fogunk felvenni.
Tehát a start() függvényünknek így kell kezdődnie :
int start()
  {
   int err, ticket;
   double stoploss, ParUp, ParDn;
A három double változó feladat lesz a stop-loss kiszámítása és húzása. Az első két int változó feladata a pozíció nyitások lebonyolítása, a ticket számát tartalmazza és az esetleges hibakódot.

No, de nézzük csak hogyan kell a stopot húzni.A teljes kód a következőképpen néz ki, a jelentését mindjárt meg is beszéljük :
orders=OrdersTotal();
      
if (orders != 0)
      {
         for(pos=0;pos
         {         
            if(OrderSelect(pos, SELECT_BY_POS,MODE_TRADES))
            {  
               ParUp=iCustom(NULL,0,"Parabolic trendchaser", false, 0.06,0.1,7,0,0,1);
               ParDn=iCustom(NULL,0,"Parabolic trendchaser", false, 0.06,0.1,7,0,1,1);
               
               if (OrderType() == OP_BUY && OrderSymbol() == Symbol() && ParDn != 0)
               {
                  stoploss = ParDn;                  
                  
                  if (OrderModify(OrderTicket(),OrderOpenPrice(), stoploss, OrderTakeProfit(),0,Blue))
                     Print("Stop-loss módosítva!");
                  else
                  {
                     Print("Stop-loss nem módosult! ", DoubleToStr(stoploss,5));
                     Print("Hibaüzenet : ",ErrorDescription(GetLastError()));
                  }
               }else if (OrderType() == OP_SELL && OrderSymbol() == Symbol() && ParUp != 0)
               {
                  stoploss = ParUp;

                  if (OrderModify(OrderTicket(),OrderOpenPrice(), stoploss, OrderTakeProfit(),0,Blue))
                     Print("Stop-loss módosítva!");
                  else
                  {
                     Print("Stop-loss nem módosult! ", DoubleToStr(stoploss,5));
                     Print("Hibaüzenet : ",ErrorDescription(GetLastError()));
                  }
               }                  
            }else
               Print("Nem sikerült húzni a Stop-Loss-t, nem találom a pozíciót!");
         }
      }
Az OrdersTotal() függvény elárulja nekünk, hogy mennyi nyitott pozíció van ezen a számlán, minden devizapáron.
A legelső if utasítás arról gondoskodik, hogy csakis kizárólag akkor foglalkozzunk a stop húzással, ha van nyitott pozíciónk.
Ezután egyesével végig szaladunk egy for ciklus segítségével a pozíciókon. A ParUp és a ParDn értékek kiszámításával kezdjük, hiszen nemsokára szükségünk lesz rá. Ezek adják majd a stop szinteket.

A következő if utasítással azt vizsgáljuk, hogy :
  • Long pozíció-e az éppen vizsgált soron következő pozíció
  • Az aktuális chart-nak megfelelő devizapáron köttetett-e (képzeljük csak el, ha egy EURUSD-n futó programunk lezárná az EURHUF long pozíciónkat... Kellemetlen lenne...)
  • És azt is vizsgáljuk, hogy van-e kiszámított érték egyáltalán, mert ha nincs, akkor minek túráztatjuk magunkat
Ha a feltételek teljesülnek, akkor az OrderModify() függvénnyel beállítjuk a stopot. A top értéke a Parabolic trendchaser indikátor alsó pöttyének az értéke lesz, ezért a stoploss változónkba is ezt írjuk be és ezt is állítjuk be stopnak.
Figyeljük meg, hogy az aktuális adatokat kikérjük a pozícióról és azokat vissza is írjuk az OrderModify() függvénybe, tehát csak a stopot módosítjuk. (tehát az OrderTicket() függvény megmondja az aktuálisan kiválasztott pozíciónk ticket számát, az OrderOpenPrice() elárulja milyen áron nyitottuk a pozíciót, ha van take profit beállítva, akkor az OrderTakeProfit() ezt is elárulja. Mindezeket visszaírjuk a módosításba eredeti formájukban, tehát nem bántjuk őket, így tudjuk csak  stop-loss-t módosítani)

Természetesen vizsgáljuk a visszatérési értékét a függvénynek, tehát ha igaz értékkel tér vissza, akkor közöljük a program felhasználójával, hogy sikerült, ha pedig nem sikerült, azt is közöljük, de a hiba okát is kiírjuk, erre való az ErrorDescription(GetLastError()) összefüggés.
Az igazsághoz persze az is hozzátartozik, hogy a programunk elejére be kell szúrnunk még két sort, ahhoz, hogy a hibakiírás működhessen, mégpedig ezt a két sort :
#include <stderror.mqh>
#include <stdlib.mqh>
Ezekkel biztosíthatjuk, hogy az előbb említett hibakezelő függvények működhessenek.
Érdemes a többi include utasítás alá beilleszteni, ha van. De mindenképpen a többi #-kal kezdődő sorokhoz.

A  short pozíciónál ugyanez az eljárás, de ott a Parabolic trendchaser indikátor felső pöttyének az értékét fogjuk beállítani.

A FOREX robotunk még nem az igazi, összeraktuk, készre csiszoltuk, de még nem políroztuk fel, ugyanis vannak még szépség hibái.
Például az, hogyha a Parabolic trendchaser indikátor éppen nem mutat alul pöttyöt, csak felül (mert ugye ez is egy Parabolic SAR rokon és vagy fönt, vagy lent vannak pöttyei), akkor nem húz stopot a program.
Akkor sem fog stopot húzni, hogyha túlságosan közel vagyunk pillanatnyi árhoz.

Ezeket az eseményeket le kell kezelnünk, különben stop nélkül maradunk és nem, vagy túl későn lesz lezárva a pozíciónk, amiből komoly veszteségek származhatnak.
Mindenesetre ez a kis program jól szemlélteti, hogy hogyan érdemes nekifeszülni egy ilyen program megírásának és mire érdemes gondolni közben.

A következő post-ban a legutóbbi két esemény kezelésével foglalkozunk, megoldást keresünk rá, szemléltetve a MetaTrader további lehetőségeit.

Ezután a teljes programkódot közzéteszem, hogyha valakinek nincs kedve az egészet begépelni, vagy ha esetleg lemaradt, akkor egyben láthatja a kódot.
Telis-tele lesz megjegyzésekkel, hogy mi miért van, így talán azok is követni tudnak majd, akik eddig nem olvasták el az összes post-ot.

Ha pedig mindenki a kezébe kaparintotta a működő robotot, jöhet a tesztelés, melynek fázisait szintén végignézzük, illetve a fejlesztés további szakaszai jönnek, a veszteségek kiküszöbölése és egy jó kis money management kerül bele.

péntek, február 25, 2011

Építkezés - folytatás II. ...

Szép jó estét mindenkinek! Gondolom már vártátok a folytatást, hát itt van.

Eddig ugye szó esett a FOREX robot és a MetaTrader kapcsolatáról, szó esett a robot felépítéséről is.
Sőt, mi több, el is kezdtük építeni a kis okos robotunkat MetaTrader-ben, a saját C# programozási nyelvén.

Eddig ott tartunk, hogy az indikátorok alapján eldöntöttük, hogy merre az arra, vagyis azt, hogy a mi kis okos FOREX robotunk long - azaz vételi -, vagy short - azaz eladási - pozíciót nyisson.
Most azt fogjuk megbeszélni, hogy na, akkor hogyan is nyissunk pozíciót!

Csapjunk is a közepébe, íme a kód és már meg is beszéljük hogyan működik :
      if (TMTrend == "Long" && TVITrend == "Long" && !nyitott)
      {
         ticket=OrderSend(Symbol(),OP_BUY,maxlots,Ask,slippage,0,0,"TrendMagic-TVI - Long",MathRand(),0,Green);
         err = GetLastError();
         if (err != 0 && ticket < 0)
         {
            Print("Error # ", err, "  ", ErrorDescription(err));
         }
      } 
Első ránézésre talán bonyolultnak tűnik, de nem az.
Minden ahhoz az alapvető feltételhez van kötve, hogy az indikátorok mit mutatnak.
Tehát három feltétel meglétét vizsgáljuk. Az első kettő a két indikátor együttállása, a harmadik pedig a start() függvény elején vizsgált feltétel szerint beállított nyitott nevű változónk. Ez ugye igaz értéket vesz fel, ha az aktuális devizapáron van már nyitott pozíciónk.
Tehát a feltétel vizsgálja, hogy long nyitási lehetőség van-e és azt, hogy NINCS nyitott pozíciónk. Mert ha már van, akkor nem nyitunk rá. (ez majd a rákötésnél lesz érdekes, de ott még nem tartunk)
Tehát a '!' jel az, amely a tagadás (szakmaibban szólva negálás) ebben a nyelvben, ha egy változó hamis értéket tartalmaz, akkor ez igazzá változtatja és fordítva. Tehát, ha van nyitott pozíciónk, akkor ezzel a jellel hamis értéket kapunk és nem teljesül az if utasításunk, ha pedig nincs nyitott pozíciónk, akkor igaz értéket kapunk és ha mindkét indikátor long-ot mutat, akkor már folytatjuk is a végrehajtást a következő utasítás soron.

Nem gatyázunk, ez már maga a pozíció nyitás. Sajnos ez is kétesélyes, vagy sikerül, vagy nem. Éppen ezért ha nem sikerül, akkor arról tudnunk kell.
De ne szaladjunk ennyire előre.
Az OrderSend() függvény gondoskodik arról, hogy a pozíció megnyíljon, bármilyen irányba. Nyilván az első paramétere az instrumentum neve - vagyis a devizapár neve - lesz, ahol a pozíciót nyitni szeretnénk, a második a már sokkal érdekesebb, mert itt mondjuk meg miféle pozíciót nyitunk.
Nézzük csak, miket lehet nyitni :
  • OP_BUY : ez egyszerűen egy long, azaz vásárlási (buy) pozíció nyitást jelent, semmi extra
  • OP_SELL : a long párja, vagyis a short, eladási (sell) pozíció
  • OP_BUYLIMIT : na, ez már érdekes, ha az ár elér egy bizonyos szintet, akkor nyit egy long-ot
  • OP_SELLLIMIT : ez az előző short testvére
  • OP_BUYSTOP : ez nagyon hasonló a buy limit-hez, de kicsit másképp működik, mindjárt kitérünk rá
  • OP_SELLLIMIT : ez pedig az előző párja
Mi a különbség a LIMIT és a STOP pozíció nyitás között? Sok!
A LIMIT mindig egy felső határt, a STOP pedig egy alsó határt jelöl. Vagyis, például egy buy limit esetén amikor a limitet meghaladja az ár, akkor nyit pozíciót, minimálisan a megadott limit áron és nem kevesebbért.
A buy stop pedig akkor fog pozíciót nyitni, amikor az ár leesik arra a bizonyos árszintre, amit megadunk és legfeljebb azon az áron nyit pozíciót, amit megadunk. Tehát a limit ár általában magasabb, mint a pillanatnyi ár, a stop pedig alacsonyabb, de ez a stratégiától függ természetesen. Mindenesetre így tervezték ezeket a pozíció nyitási lehetőségeket.

Két következtetést lehet levonni ebből. Az egyik, hogy a limit egy felső határ fölött, de legalább annyiért, ha a beérkező tick magasabb, akkor magasabban fog pozíciót nyitni, a stop pedig egy alsó határ alatt nyit pozíciót, maximum annyiért, de ha a tick alacsonyabb, akkor alacsonyabban fog pozíciót nyitni.
A másik következtetés, hogy ezek nem azonnali pozíció nyitások, hanem feltételesek, tehát amíg a pozíció meg nem nyílik, törölni is lehet őket mindenféle következmények nélkül.

Az első kettőt fogjuk használni, ugyanis ezek az azonnali pozíció nyitások. A többit nem is fogjuk használni, ezek általában kézi kötésnél játszanak szerepet, automatikus kereskedésben még sosem láttam ilyen kötést...

Nos, visszatérve a pozíció nyitó OrderSend() függvényünkre, a harmadik paraméterünk azt mondja meg, hogy mekkora méretű pozíciót nyitunk. Erről a nap végére tartogatok egy kis magyarázatot.
A következő paraméter az ár, amin szeretnénk pozíciót nyitni.Ezt megadhatjuk közvetlenül is, de ennek nem sok értelme van, ugyanis a program végrehajtása során ez az ár változhat. Tehát érdemes a pillanatnyi áron vásárolni.

No és akkor itt most álljunk meg egy szóra, mert itt jön az a rész, amit néha a kereskedők elfelejtenek. Aki nem felejti el ezeket, nyugodtan átlépheti ezt a bekezdést, de szerintem érdemes elolvasni. Fél perc...
A devizapárokkal történő kereskedés két áron zajlik. A vételi és az eladási áron. A MetaTrader a vételi árat Ask-nak hívja, az eladási árat pedig Bid-nek. A kettő közötti árrést nevezzük spread-nek.
Mivel a brókereknek az eladási ár a legfontosabb, így az eladási árat követhetjük nyomon a grafikonokon. Tehát venni az Ask áron tudunk, eladni viszont a Bid áron.

Éppen azért, ha pillanatnyi áron szeretnénk long pozíciót nyitni, akkor az az Ask ár lesz.

A következő három paraméter a slippage, amit már a múltkori post-ban megbeszéltünk, majd a stop-loss és a take-profit következik, melyeket hogyha 0-ra állítunk, akkor nem létezők lesznek, most ezt használjuk.
A következő paraméter egy egyszerű szöveges komment, amit úgy fogalmazunk meg, ahogy akarunk.

Az ezt követő paraméter a magic number, amit senki sem tud pontosan mi célt szolgál, ami biztos, hogy a felhasználó saját döntése alapján azt ír ide, amit akar, mint egyedi azonosítót.
Egyetlen dolgot fedeztem fel ezzel kapcsolatban, hogy a MetaTrader nem szereti, ha két különböző devizapáron azonos magic number-rel jelzett pozíció van nyitva. Egyszerűen megkavarodik és hülyeséget csinál.
Éppen ezért ide mindig kivétel nélkül valamilyen véletlen számot szoktam tenni. Lehet egy jól meghatározott konstans érték is, de akkor mindenképpen gondoskodjunk arról, hogy a különböző devizapárokon különböző magic number-eket használjunk!
Ezt követően a pozíció nyitás lejárati idejét lehet megadni, ami persze csak akkor értelmes, ha limit, vagy stop pozíciókat nyitunk és akkor is csak addig, amíg meg nem nyílik a pozíció. Ezért ez nekünk mindig 0.

Megnyitott pozíciót csak lezárni lehet, törölni nem!
Ezt azért húztam alá, mert nagyon fontos! Törölni csakis azokat a megbízásokat lehet, amelyek még nem teljesültek, amelyek már teljesültek, azok nyitott pozíciók és csak lezárni lehet őket, ez persze már pénzbe kerül (ára a spread-től és a pozíció méretétől függ), míg a nem teljesült megbízásokat büntetlenül törölhetjük bármikor, ingyenesen.

A legutolsó paraméter pedig a chart-on a nyitást ábrázoló nyilacska színe, ami szintén szabadon választott.

A függvény visszatérési értéke a pozíció nyitási jegy száma, ha sikerült a nyitás. (emlékszünk ugye a múltkori leírásra, miért kezeli így a program ezeket).
Ha ticket nem valami értelmes értéket tartalmaz, akkor nem sikerült a pozíció nyitás és akkor a hibát a felhasználó tudtára kell adni. Erre valók a következő sorok.

Először is pozíció nyitás után kiolvassuk a hiba számát a GetLastError() függvénnyel. Ha ez nem nulla és a ticket változónk is valamilyen nullánál kisebb értéket tartalmaz (tipikusan -1), akkor nem sikerült a pozíció nyitás és a hibár egy Print() függvénnyel a Naplóba írjuk.
A Napló tartalma a MetaTrader kereskedési felületén megtekinthető bármikor a program futásakor, tehát ide mindig üzenhetünk, hogyha a felhasználót szeretnénk tájékoztatni valamiről, ami nem a chart-on kell, hogy legyen.

Tehát ennyit a long pozíció nyitásáról.
A short pozíció nyitása is ugyanilyen egyszerű, csak ott a Bid árat kell megadnunk, és már nyílik is a pozíció.
Tehát így néz ki a short nyitás :
if (TMTrend == "Short" && TVITrend == "Short" && !nyitott)
      {
         ticket=OrderSend(Symbol(),OP_SELL,maxlots,Bid,slippage,0,0,"TrendMagic-TVI - Short",MathRand(),0,Green);
         err = GetLastError();
         if (err != 0 && ticket < 0)
         {
            Print("Error # ", err, "  ", ErrorDescription(err));
         }
      }

Látható milyen egyszerű.

A következő post-ban a stop húzást fogjuk megvalósítani, ezáltal lesz egy stratégiánk, ami jelek alapján pozíciót nyit és zár, indulhat a back test. A back test-ek végrehajtásához a legjobb a hétvége, akkor lehet nyugodtan tesztelgetni.
Tehát igyekszünk holnap minden finomra csiszolni a programunkon, hogy vasárnap békésen tesztelhessen mindenki!

A pozíció méretről ígértem egy kis elmélkedést.
A FOREX esetében - amikor is nem részvényeket vásárlunk, hanem devizapárokat - nem darabonként vesszük, adjuk, hanem kötegekben, csomagokban. Ezt a FOREX úgy nevezi, hogy Lot. Egy ilyen kereskedési egység 100.000 alapdevizát jelent, ha azt a tizedespont után 5 számjegy követi.
Ehhez a tőkeáttétel szerinti fedezet szükséges, ha a tőkeáttételünk 1:100, akkor ennek az egy század részét kell a számlán tartanunk, ha vásárolni akarunk. Ez 1000 USD. Tehát ez nagyon sok. Éppen ezért, mivel a pénzünknek csak maximum 3%-át kockáztatjuk, a maximális kötési mennyiséget be kell lőnünk.

Ha 0.01 lot-ot kötünk, akkor "csak" 10 USD-t kockáztatunk, tehát az óvatosság nem csakhogy nem árt, hanem inkább még használ is.

csütörtök, február 24, 2011

Építkezés - folytatás...

Tegnap elkezdtük a FOREX robotunk építését, ma pedig folytatjuk.
Beszéltünk tegnap a stratégiáról egész részletesen, sőt, el is kezdtük a kódolást a felhasználótól bekért kezdő adatokkal és az első lépést is megtettük a robot építésében.

Ma egy újabb lényeges résszel folytatjuk, mégpedig a start() függvényünket csiszolgatjuk még tovább.
Egész konkrétan azt fogjuk lekódolni, amikor a program megvizsgálja van-e nyitott pozíciónk.
Nem is nagyon szaporítom a szót fölöslegesen, íme a kód, aztán pedig megbeszéljük :
   nyitott = false;
   orders = OrdersTotal();
  
   for(int pos=0;pos
   {
      if(OrderSelect(pos,SELECT_BY_POS)==false)
         continue;
      else
            if (OrderSymbol() == Symbol())
               nyitott=true;
   }
Gondolom emlékeztek rá, hogy tegnap felvettünk egy globális változót, amely bool típusú. Ha ez igaz (azaz true) értéket tartalmaz, akkor van nyitott pozíciónk, ha pedig hamis (false), akkor nincs.

Felmerülhet a kérdés, hogy mi a fenének ez rögtön az elejére. A magyarázat rém egyszerű. Azért, mert ha nem ezzel kezdenénk a műveleteket, akkor a programunk minden alkalommal, amikor pozíció nyitási jeleket lát a chart-on, minden alkalommal nyitna egy pozíciót. Minden egyes gyertyánál, amíg csak jel van.
Ez oda vezetne, hogyha mondjuk egy 100 gyertyából álló trend indulna el, akkor nyitna 100 pozíciót. Ha megfelelően nagy pozíció méretet állítunk be, akkor egyszer csak nem tudnánk már nyitni, mert a teljes tőkénket befektettük a sok pozíció nyitással és gyakorlatilag elfogyna a pénzünk. A baj nem itt van, hanem ott, amikor lezárjuk őket. Ugyanis a java része veszteséges lenne, és csak kis hányada - egész konkrétan a legelőször nyitottak - lennének nyereségesek.

Ez azt jelenti, hogy viszonylag gyorsan el is fogyna a pénzünk...

Itt azért meg kell jegyeznem a teljesség kedvéért, hogy vannak olyan technikák, amikor nyitunk egy pozíciót, majd amikor jónak látjuk, nyitunk egy másikat is ugyanabba az irányba, azután még egyet, de ezek száma korlátos és egyszerre zárjuk le őket. de ezeket jól átgondoltan akkor nyitjuk, amikor megbizonyosodtunk arról, hogy a trend merre megy és amikor mindet egyszerre bezárjuk, akkor legfeljebb az utolsó veszteséges, a többi viszont óriási nyereséggel zárul. Ezt hívják piramis építési technikának, beszélünk is majd róla később, de most egyenlőre maradunk az egy nyitott pozíciónál.

Nézzük a kódot! Mivel minden új gyertya "keletkezésekor" lefut a robot lelke, vagyis a start() függvényünk, ezért minden új gyertya indulásakor meg is vizsgáljuk van-e nyitott pozíciónk.
Ehhez legelőször is azt feltételezzük, hogy nincs nyitott pozíciónk és beállítjuk hamis értékre a nyitott nevű változónkat.
Ezután használjuk az orders változót, amely egész típusú és egy egyszerű függvénnyel megadjuk neki azt, hogy hány nyitott pozíciónk van. Erre való az OrdersTotal() beépített MetaTrader függvény.
Ez a függvény visszaad egy egész számot, amely a nyitott pozíciók méretének számát tartalmazza.

Ezzel itt vége is, gondolhatnánk, hiszen ez a függvény megmondja mennyi nyitott pozíciónk van, minek a további kód? Aki ezt gondolja, teljesen igaza is van. Egyetlen egy dolgot azonban nem szabad elfelejtenünk!
A MetaTrader több devizapáron is megjeleníti a chart-ot és mindegyiken köthetünk üzletet, viszont ha pozíció nyitási jelet látunk mondjuk az EURUSD-n, de az USDCHF-en már van nyitott pozíciónk, akkor EURUSD-n nem fog nyitni, mert az OrdersTotal() függvény beleszámolja az ÖSSZES nyitott pozíciót!

Ezért hát a kód többi része. Egy egyszerű for ciklust indítunk el, amely csak akkor fut le, ha a változó értéke nagyobb nullánál, tehát ha legalább egy nyitott pozíciónk van.
Az OrderSelect() függvény lépeget végig a nyitott pozíciókon, méghozzá a paramétereiben megadott módon.
Kétféle módon tudja ezt megtenni, vagy a pozíció nyitási jegy száma alapján (erről mindjárt beszélünk kicsit), vagy pedig pozíció szám alapján, amely pozíció nem más, mint a pozíció nyitásának sorszáma időrendben, függetlenül az instrumentumtól, vagy bármi mástól.
Mivel a nyitási jegy számát nem tudjuk, ezért pozíciónként megyünk végig a nyitott üzleteken.

A pozíció nyitási jegyekről pár szóban.
Annak idején, amikor még a kereskedést a tőzsdén a placcon nyomták, akkor a brókerek egy cetlire írták fel, hogy miből mennyit akarnak vásárolni, vagy eladni. Aztán amikor jött az ajánlati könyv vezetője, beordított egy árat, hogy akkor most venne ennyiért ezt és ezt. A brókerek meg üvöltve tették meg az ajánlataikat, amelyet, ha elfogadott az ajánlati könyvbe a kereskedő, akkor az volt a hivatalos tranzakció, új alapokra helyezve a következő tranzakciót (nő, vagy csökken az ár mindegyik után, hiszen ha sok az eladó, akkor az lenyomja az árat, ha pedig a vevő sok, akkor az meg felveri az árat).
Ezeknek a cetliknek, mint kötési jegyeknek, egyedi sorszáma van, melyet az ajánlati könyvbe bejegyeznek.

A dolog az intelligens számítógépek korában is pontosan így működik, azzal a különbséggel, hogy nem brókerek üvöltenek a placcon, hanem számítógépek zúdítják a biteket a brókercéghez, ahol az ajánlati könyvet kezelik. Vannak olyan bróker cégek, ahol az ajánlati könyv legfelső néhány tételét látni is lehet a weboldalon, így lehet tudni nagyjából, hogy eladói, vagy vevői nyomás van a piacon.

Mivel a MetaTrader nem csak devizapárok, hanem részvények (pontosabban származtatott részvény termékek, EFT-k) kereskedésére is alkalmas, ezért a deviza kereskedelemben is megtartották a szisztémát és ugyanígy kezelik az ajánlatokat.

Tehát ott tartottunk, hogy a nyitott pozíciónak van egy egyedi azonosító száma, amely megkülönbözteti az összes többitől, legyen az bármelyik chart-on.
Az OrderSelect() függvénynek két paramétere van. Az egyik a pozíció száma, vagy pedig a kötési jegy száma, a második paramétere pedig azt mondja meg, hogy az első paraméter egy kötési jegy szám, vagy sorszám.
Ezen adatok alapján megkeresi a pozíciót és kiválasztja (mintha csak egy listában sárga kijelölő filctollal kisárgítaná nekünk). Ezek után az összes pozícióra vonatkozó függvény ezzel az egy pozícióval foglalkozik.
Van jó pár, akit érdekel és otthon van alapszinten az angol nyelvben, végig nézegetheti a Help-ben. Csak párat megemlítek közülük, le lehet kérdezni a kötés idejét, méretét, az árat, az aktuális profit/loss-t, a stop-ot hová húztuk, a take profit hol van, stb.
De megtudhatjuk belőle azt is, hogy melyik instrumentumra kötöttük azt a bizonyos pozíciót.

Éppen ez kell nekünk. Tehát a for ciklusunk végig megy a nyitott pozíciókon sorszám szerint, és megnézegeti, hogy a pozíció milyen instrumentumon köttetett. Az OrderSymbol() függvény visszaadja a nyitott pozíció instrumentumát, a Symbol() függvény pedig azt mondja meg, hogy az aktuális chart éppen milyen instrumentumon van.
Az OrderSelect() függvény visszatérő értékként azt adja vissza, hogy sikeres volt-e a pozíció kiválasztása. Tehát a kód egyszerűen végig sétál a nyitott pozíciókon, ha van egyáltalán, és megnézi, hogy bármelyik nyitott pozíció instrumentuma megegyezik-e a chart-on lévővel.

FOREX robotunk újabb alkatrésze jön, mégpedig a pozíció nyitásokhoz szükséges vizsgálat.
Itt is gyorsan mutatom a kódot, azután megbeszéljük :
if (iCustom(NULL,0,"TrendMagic",TrendMagicCCI,TrendMagicATR,0,1) != EMPTY_VALUE && iCustom(NULL,0,"TrendMagic",TrendMagicCCI,TrendMagicATR,1,1) == EMPTY_VALUE) // Long
      {
         TMTrend="Long";
      }
Ez itt egy egyszerű vizsgálat, if utasítással. A trükk azonban a részletekben rejlik.
Gyors magyarázat az egyszerűség kedvéért. Az iCustom függvénnyel lehet az egyéni indikátorokat lekérdezni. Az összes beépített indikátornak van saját beépített függvénye (pl. a MACD-nek az iMACD függvény).
Az indikátorok lekérdezését végző függvények paraméter listája mindig két érték megadásával kezdődnek.
Az első a megfelelő instrumentum megadása, a második pedig az időtáv, amin dolgoznia kell.

Ha egészen precízek szeretnénk lenni, akkor az instrumentumnak megadhatnánk a Symbol() függvényt, amiről fentebb már volt szó, az időtávnak pedig a Period() függvényt. Ez az aktuális chart éppen használatos időtávját adja meg.

Ehelyett azonban az alapértékeket adjuk meg, az instrumentumnak a NULL értéket, az időtávnak pedig a 0-t.
Ha megnézzük a help-ben a iCustom() függvényt, akkor látjuk, hogy az instrumentum paraméterként megadott NULL érték az aktuális instrumentumot jelenti, a 0 időtáv pedig szintén az aktuálisat.

Persze megadhatunk fix értékeket is, de akkor csak azon az instrumentumon és csak azon az időtávon fog működni a FOREX robotunk.
Folytatva az iCustom() függvény magyarázatát, a következő paraméter az egyéni indikátor neve string-ként megadva. Ez a név pontosan az kell, hogy legyen, amit az egyéni indikátorok listában látunk a Navigation ablakban. Különben nem fogja megtalálni. A mi esetünkben ez a TrendMagic egyéni indikátor lesz.
Ezután következnek a TrendMagic paraméterlistája, majd két fontos információ.
Az első azt adja meg, hogy a TrendMagic indikátor melyik paraméterét kérdezzük le, a második pedig azt, hogy a pillanatnyi gyertyához képest visszafelé hányadik gyertyánál lévő értékre vagyunk kíváncsiak.

Az egyéni indikátorok lekérdezhető paraméterei függenek az egyéni indikátortól. Egy mozgóátlagnak (iMA) egyetlen paramétere van, de egy ADX-nek rögtön három. A paraméter számozás 0-val kezdődik, tehát a legelső paraméter a 0-ás, a második az 1-es és így tovább.

Honnan lehet tudni, hogy melyik a 0-ás paraméter? Onnan, hogyha feltesszük a chart-ra, fentről lefelé ez jelenik meg legelőször, általában az indikátor neve mellett.

A mi esetünkben a TrendMagic-nek két paramétere van, jól lehet egyetlen vonalat látunk a képernyőn, ami hol piros, hol kék. A kék és piros értékeket külön kezeli, ezért ez két különféle paraméter.
A 0-ás érték az a kék vonal esetén él, az 1-es érték pedig a piros vonal esetén él. Tehát ha a 0-ás paraméter nem üres, akkor tudjuk, hogy a TrendMagic vonala kék, azaz emelkedő trendet mutat, ha az 1-es paramétere nem üres, akkor piros a vonal és csökkenő trendet mutat.

Az iCustom() függvény legutolsó paramétere, amit már megbeszéltünk, az pedig a pillanatnyi gyertyát megelőző gyertya sorszámára utal, az ott lévő indikátor értéket vizsgáljuk. Itt a pillanatnyi gyertya előtti, tehát a legutolsó bezárt gyertyánál lévő indikátor értékre vagyunk kíváncsiak, mivel a pillanatnyi gyertya mindig változik, tehát a hozzá tartozó indikátor érték is. Egy folyamatosan változó értékre alapozni egy pozíció nyitást, öngyilkosság, de minimum hazárdjáték. A tőzsdézés viszont nem hazárdjáték.

Az említett if utasítás tehát egész egyszerűen azt az esetet vizsgálja, hogy a TrendMagic paramétere nem üres, de az 1-es paramétere üres (vagyis a vonal kék ÉS nem piros), akkor a TrendMagic emelkedő trendet mutat, vagyis long pozíció nyitására van lehetőség eszerint az indikátor szerint.

Ugyanez fordítva a short trend nyitásának feltétele :
if (iCustom(NULL,0,"TrendMagic",TrendMagicCCI,TrendMagicATR,0,1) == EMPTY_VALUE && iCustom(NULL,0,"TrendMagic",TrendMagicCCI,TrendMagicATR,1,1) != EMPTY_VALUE) // Short
      {
         TMTrend="Short";
      }
Tehát itt pedig az előző feltétel ellentétét vizsgáljuk.
Felhívnám a figyelmet az egyenlőség és a nem egyenlőség vizsgálatát végző operátorokra. A dupla '=' jel a megfelelőséget, a '!=' pedig a nem megfelelőséget vizsgálja. Azért említem meg, mert tipikus programozói hiba szokott lenni, hogy a dupla '=' jel helyett csak szimplát használnak, ami ugye értékadást jelent. Tehát a feltétel MINDIG igaz lesz, de ha egy változó van a bal oldalon, akkor az felveszi azt az értéket, ami a jobb oldalon van. Ez nem egészséges.

A másik tipikus hiba, hogyha valaki más nyelvben is programozik, mondjuk például Visual Basic-ben, akkor a nem megfelelőség jeleként a kacsacsőrt használja, vagyis a '<>' jelet. Ez azonnali fordítási hibát dob, tehát ezt nem nehéz kivédeni, de sok kezdő nem érti a hiba üzenetet, hogy miért nem tetszik a fordítónak ez a megszokott jel... Hát mert csak. Ez egy C-szerű nyelv, márpedig ennek a nyelvnek a szintaktikája nem szereti a más nyelvben megszokott jelet. Ennyi az egész.

Tehát túl is vagyunk a TrendMagic indikátorunk által mutatott jelek értelmezésén, amit el is tettünk egy string változóba. Azért string-be, mert ez így mindenkinek olvashatóbb, jobban is lehet értelmezni.

Következzék hát a TVI jeleinek vizsgálata.
Mivel ez pont ugyanúgy működik, mint a TrendMagic így nincs meglepetés, csak a paraméterek száma különbözik, mert itt három paraméter van, nem kettő. De ettől eltekintve ugyanígy kell vizsgálni a zöld és piros értékeket. Sőt, mi több, még a paraméterek lekérdezése is ugyanígy működik :
if (iCustom(NULL,0,"TVI_2color",TVI_rs,TVI_rs,5,TVI_TF,0,1) != EMPTY_VALUE && iCustom(NULL,0,"TVI_2color",TVI_rs,TVI_rs,5,TVI_TF,1,1) == EMPTY_VALUE)
      {
         TVITrend="Long";
      }
     
      if (iCustom(NULL,0,"TVI_2color",TVI_rs,TVI_rs,5,TVI_TF,0,1) == EMPTY_VALUE && iCustom(NULL,0,"TVI_2color",TVI_rs,TVI_rs,5,TVI_TF,1,1) != EMPTY_VALUE)
      {
         TVITrend="Short";
      }
Tehát szinte ugyanazt a kódot kapjuk, csak egy paraméterrel több van és másképp hívják az indikátort (és persze más paramétert kapnak az indikátorok is).

Ezzel szinte készen is vagyunk, már ami az indikátorok vizsgálatát illeti, a következő post-ban már a pozíció nyitásokkal leszünk elfoglalva, azután pedig stop-loss húzásokkal.

Aztán, ha ezekkel mind meg vagyunk, akkor jöhet a puding próbája, a back test.

Jó elmélkedést, programozást, help olvasgatást!

szerda, február 23, 2011

Építkezés

Már megint jó sok idő telt el, mentségemre legyen mondva, elég rendesen felborult a megszokott életritmusom. De lassan elülnek a hullámok, a FOREX persze marad, az automatikus kereskedelem és a robot építés még mindig a szívem csücske, így természetesen nem hagyok fel ezzel. Minden nap új tapasztalatokat szerzek.

Fura a mai cím, de mégis jó ide, ugyanis elkezdjük "megépíteni" a robotunkat. Nem kell igazi robotra gondolni, de ebben a szakmában így hívják azokat a programokat, amelyek automatikusan kereskednek.

FIGYELEM! Az itt közzétett programkódok saját szellemi termékeim, de szabadon felhasználhatja bárki. Felelősséget azonban nem tudok érte vállalni,  mint ahogyan a kód használatából származó anyagi károkért sem! MINDENKI SAJÁT FELELŐSSÉGÉRE HASZNÁLJA! A kódok CSAK oktatási céllal kerültek ide! Kellő hozzáértés és fegyelem nélkül TILOS éles számlán használni!

A FOREX robotunk két egyéni indikátort használ, mindkettőt kiveséztem a legutóbbi post-ban. Az egyik a TVI, a másik pedig a TrendMagic. Illetve van még egy harmadik indikátor is, amely a stop-loss-okat húzogatja utánunk. Ő a Parabolic SAR.

A két egyéni indikátorral az a szerencsénk, hogy mindkettő forráskódját fel lehet lelni az interneten, ha esetleg valaki nem találná, vagy nem biztos abban, hogy azt találta meg, amire szükség van, az bátran írjon nekem levelet, "postafordultával" elküldöm az indikátorok forráskódját. Javaslom, hogy módosítás nélkül használja mindenki!

Mindkét indikátor színekkel jelzi, hogy szerinte a trend merre megy. De sajnos egyedül egyik sem megbízható, ezért van szükség arra, hogy legalább kettőt használjunk.

A TVI-ből ráadásul kettőt fogunk használni, mert egy kevés lesz.
Kicsit furmányos ez az indikátor, mert nem egy, hanem két forráskódból áll. Az egyik a TVI.mq4, amely a normális TVI jeleket számolja. A másik a TVI_2color.mq4, amely a nevéhez méltóan két színnel jelöli a trend lehetséges irányát. Ez utóbbi indikátor képtelen egyedül működni, csakis kizárólag az előzőekben említett TVI.mq4 indikátorral együtt működik, tehát mindkettőt be kell másolni az indicators mappába.

A TVI-nek három, a TVI_2color-nak négy paramétere van. Ezek magyarázatára nem térnék ki, legyen elég annyi, hogy elmondom hogyan kell beállítani őket.

A TVI paraméter beállításai tehát a következők :
  • r : 50
  • s : 50
  • u : 5
  • tf : 0
Ezekkel a paraméterekkel fel is tehetjük egy chart-ra tanulmányozni, hogy mit is mutat! Szerintem tanulságos.

A TrendMagic-ről is írtam részletesen legutóbb, összesen két paramétere van :
  • CCI : 50
  • ATR : 12
Ezt is feltehetjük ugyanarra a chart-ra, amire feltettük a TVI-t.
Más dolgunk már nincs is, mint megbarátkozni a Parabolic SAR-ral. Ennek is egy színes változatát használjuk, csak azért, mert programozás szempontjából könnyebb ezt kezelni. Aki átírta, úgy nevezte el, hogy "Parabolic trendchaser", vagyis trend hajhász... :o)
Beállításai :
  • AlertsEnabled : false
  • Step : 0.06
  • Maximum : 0.1
  • Precision : 7
  • TimeFrame : 0
A paraméterek értelmezését most szintén nem taglalnám! A lényege, hogy így kell beállítani. Aki nem akar a Parabolic trendchaser-rel bajlódni, az használhatja a beépített Parabolic SAR-t is, a Step és a Maximum paramétereket felhasználva ugyanezt az eredményt fogjuk kapni, csak nem lesz szép színes és később a programozás során nehezebb kezelni.
Ha ezekkel a beállításokkal ezt is felteszitek a chart-ra, akkor látható, hogy igen szűk stop-okat lehet vele húzni, ha a bróker hagyja. De erről kicsit később.

Tehát, meg is vagyunk az indikátorok beállításával. Látszik szépen a chart-on, hogy milyen jól együtt járnak ezek az indikátorok :

TVI-TrandMagic stratégia


A stratégia pedig rém egyszerű, amikor a TVI zöld, a TrendMagic kék, és a Parabolic alsó kék pöttyöket rajzol, akkor long pozíciót nyitunk és a Parabolic-nak megfelelően húzzuk a stop-ot. Amikor a trend vált, akkor egyszerűen "kistoppolódunk" és már készen is állunk a következő pozíció nyitásra.

A programunk tehát a következő részekből fog állni :
  • Indikátorok adatainak begyüjtése
  • A jelzések alapján pozíció nyitás
  • A nyitott pozíciók stop-jainak húzogatása
A zárással azért nem foglalkozunk, mert a kistoppolódás miatt úgysem kell zárnunk.

A program kód eleje mindig azzal kezdődik, hogy a felhasználótól bekérjük az indulási paramétereket, illetve az alapbeállítások módosítását tesszük lehetővé számukra. Akinek nem tetszik az 50-es érték a TVI esetében, bátran átállíthatja saját felelősségére.

Nem szeretném elmagyarázni a nyelv egyes elemeit, remélem mindenki programozott már és tudja mi az a változó, meg hogy globális változó, függvényhívás, deklaráció, definíció, stb.

Tehát a program azoknak a változóknak a definíciójával kezdődik, amelyeket a felhasználó számára is elérhetővé szeretnénk tenni, egyben a programunk ezeken keresztül tartja a kapcsolatot a felhasználóval, ha adatokat kérünk be.
Ezek a változók a hagyományos C#-ban megszokott típusúak lehetnek, de az elé írt extern klauzulával lehet őket láthatóvá tenni a felhasználó számára.
A mi esetünkben a következő lesz a lista :
extern double maxlots=0.01;
extern int slippage=5;
extern int TrendMagicCCI=50;
extern int TrendMagicATR=5;
extern int TVI_rs=50;
Látható tehát, milyen adatokat kérünk, illetve az is látható, hogy nem csak kérünk, de alapbeállításként fel is ajánlunk egy-egy értéket. Ennek ugyebár ott az értelme, hogyha a felhasználó ránk bízná a program paraméterezését, akkor is legyen valami induló adat.

Nézzük sorban őket:
  • maxlots : ez a kötéseink során fontos, azt fogja tartalmazni, milyen méretű pozíciót nyithatunk. Ez most egyenlőre egy fix érték lesz, amit ide beállítunk.
  • slippage : ez egy csúszó érték, amely szintén a kötések során fontos. Azt az értéket tartalmazza, amivel a bróker eltérhet az általunk megadott kötési, zárási ártól. Erről mindjárt írok egy-két sort, mert ez fontos, meg kell értenetek, mire való ez.
  • TrendMagicCCI : ez ugyebár a TrendMagic indikátorunk CCI paramétere
  • TrendMagicATR : ez pedig a TrendMagic indikátor ATR paramétere
  • TVI_rs : ez pedig a TVI indikátorunk r és s értéke (a kettőt mindig ugyanarra az értékre állítjuk) az u értéket viszont nem engedjük ki a kezünk közül, az fixen 5.
Tehát pár mondat a slippage-ről. Amikor a MetaTrader-en keresztük utasítást adunk a brókernek, hogy nyisson, vagy zárjon egy pozíciót, akkor meg kell adnunk egy árat. Ez az ár azonban nem biztos, hogy a pillanatnyi ár. Ha ugyanis miközben az utasítás az internet éterén keresztül beérkezik a brókerhez, ott feldolgozásra kerül és közben egy újabb tick érkezik, az ár máris megváltozik és a kötést nem engedi végrehajtani a rendszer.
Ezért vezették be a slippage nevű paramétert, amely megadja, hogy a bróker a pozícióink kezelésekor mennyivel térhet le az utasításban megadott ártól. Ez minden esetben az aktuális valutapár, vagy részvény értékének felel meg, tehát ha a tizedespont után 5 számjegyet látunk, akkor az ötödik számjegyre vetített értéket jelenti. Az alapként beállított 5-ös érték EURUSD esetében (ahol 5 számjegy követi a tizedespontot, de a negyedik számjegy jelenti az 1 PIP-et) mindössze 0.5 PIP csúszást enged meg a brókernek.

Ha ezt az értéket 0-ra állítanánk, egy gyorsan változó piac esetében többszöri próbálkozás ellenére sem biztos, hogy ott nyitunk pozíciót, ahol akarunk. Esetleg előfordulhat az is, hogy egyáltalán nem tudunk pozíciót nyitni, vagy zárni.

Az 5-ös érték általában jól működik és kellően kicsi ahhoz, hogy kötni lehessen. Nem ajánlott módosítani, de ezt mindenki maga döntheti el. Ha kivesszük az extern klauzulát előle, a felhasználó nem tudja piszkálni, de az érték ott lesz benne.

Ahogyan már egy korábbi post-ban ecseteltük, az Expert Advisor három részből épül fel. Van egy init(), egy deinint() és egy start() függvénye. Ezek közül az init() akkor fut le, amikor a chart-ra feltesszük a programot, de csak egyetlen egyszer fut le. A feladata azoknak a tevékenységeknek az elvégzése, amelyeket a kereskedés előtt egyszer meg kell tenni.
Ugyanígy a deinit() függvény pedig akkor fut le, amikor levesszük a chart-ról a FOREX robotunkat, ez is csak egyszer fut le, hasonlóképpen az előzőekhez a futás utáni takarítás a dolga.
A start() függvény viszont a szíve az Expert Advisor-nak, ugyanis ez fut le minden egyes alkalommal, amikor csak érkezik egy tick, azaz egy kereskedési adat.

Miután programunk nagyon egyszerű és nem helyez el mindenféle objektumot a chart-on (erről is lesz később szó), ezért csak a start() függvény megírására kell koncentrálnunk.

Mielőtt azonban a lelkét kezdenénk fejlesztgetni a robotunknak, érdemes az extern változók után felvenni a globális változóinkat.
Azokat a változókat érdemes ide felvenni, amelyek értékére két beérkező tick között is szükségük lesz, tehát ha ezt a start() függvényen belül vennénk fel, minden egyes tick alkalmával, amikor lefut  start() függvény, a változó újra és újra létrejönne, de azzal a kezdőértékkel, amivel definiáljuk, illetve ha az nincs, akkor valamilyen véletlen szerű kezdőértékkel.
Ilyenek azok a globális változók, amelyek a program futása közben végig meg kell, hogy őrizzék az értéküket, amíg le nem állítjuk.

Tipikusan állapot jelző változókra van itt szükség, vagy számlálókra, és ehhez hasonlókra.
Valami ilyesmi lehet :
int currentbar;
string TMTrend, TVITrend;
int orders;
bool nyitott;
 Némi magyarázat :
  • A currentbar változó fogja tartalmazni az aktuális gyertyák számát, amelyet a chart megjelenít. Ez fontos lesz majd.
  • a string változók arra valók, hogy az egyes indikátorok által jelzett trendet jelöljék. Ez lesz az alapja a pozíció nyitásnak
  • Az orders változó arra lesz hivatott, hogy a pozíció kezelések alkalmával a pozíció egyedi azonosítóját tartalmazza majd.
  • A nyitott nevű változónk pedig azt mutatja majd, hogy van-e nyitott pozíciónk már, avagy sem
 Most pedig lássuk a FOREX robot lelkét!

Azzal fogjuk kezdeni, hogy amikor egy újabb tick érkezik, megvizsgáljuk, hogy ez a tick egy új gyertya legelső tick-je, vagy pedig egy már folyamatban lévő gyertya valahányadik tick-je.
Miért jó ez nekünk?
Azért, mert a tőzsdeiskolákban mindenhol azt tanítják, hogy csak a már bezárult gyertya az igazi gyertya, a még be nem zárult gyertya változhat, hiszen a piacon bármi megtörténhet. Előfordulhat, hogy a bika gyertyából az adott időintervallumon belül hirtelen medve gyertya lesz. Na, ekkor aztán fuccs a stratégiának. Tehát csak a bezárult gyertyákkal foglalkozunk.

A kód így néz ki :
if (currentbar < Bars)
      currentbar = Bars;
   else
      return;
A magyarázat pedig nagyon egyszerű.
A currentbar nevű változónk, amelyet globálisnak vettünk fel, tartalmazza a chart-on található gyertyák számát. Kezdetben egyébként valami teljesen kiszámíthatatlan értéket tartalmaz, tehát elsőre biztosan lefut a start() függvényünk. (ha ez semmiképpen sem akarjuk, akkor az init() függvényünkben ennek a változónak adhatunk értéket, valahogy így : currentbar = Bars; Így pontosan azt az értéket fogja tartalmazni, ami a chart-on van, így a programunk addig nem fut le, amíg az aktuális gyertya le nem zárul. Íme egy lehetséges és értelmes módja az init() függvény használatának.)
A Bars rendszerváltozó az aktuális gyertyák számát tartalmazza, amelybe beletartozik az éppen be nem zárt gyertya is. Ez a globális rendszerváltozó a MetaTrader saját globális változója és csakis olvasható értéket tartalmaz. Lesz még pár ilyen amivel megismerkedünk.
Tehát a kódrészlet úgy működik, hogy ha az általunk megjegyzett gyertyák száma kevesebb, mint a chart-on lévő aktuális gyertyák száma, akkor bizony ez éppen egy új gyertya nyitását jelenti, tehát jól megjegyezzük mennyi is a chart-on a gyertyák száma és hagyjuk lefutni a start() függvényt.
Ha viszont az eltárolt gyertyaszám megegyezik a chart-on lévő gyertyaszámmal, akkor az érkező tick az aktuális gyertyához tartozik, tehát egy return utasítással be is fejezzük a start() függvényünk futását.

Miután az új gyertyát megkezdő tick az előző gyertya záró tick-je is egyben, így a start() függvényünk minden esetben lefut, amikor egy újabb gyertya lezárul, de csakis akkor, nem máskor. Ilyen egyszerű.

A legközelebbi post-ban innen folytatjuk a kód írását. Talán kedvcsinálónak ennyi is elég lesz mára. Igyekszem nem három hónap múlva folytatni... :o)

szerda, december 01, 2010

Nézzük a stratégiát

Lassan tradíciót csinálok abból, hogy a blog majdnem mindegyik bejegyzése úgy kezdődik, ahogyan ez is...
Nagyon régen sikerült utoljára írnom a blogba, talán azért is, mert mindig sokat szeretnék írni, de kevés az időm, de leginkább azért, mert folyamatosan tanulom a szakmát én is.
Ezért úgy döntöttem, hogy nem fogok hosszú írásokat közzétenni, hanem relatíve rövidebbeket, viszont ezt sűrűbben teszem majd. 

Legutóbb azt írtam, hogy a megvalósítandó stratégiát fogom leírni, ami igaz is. Ezért most röviden a stratégiáról fogok írni.

Nagy általánosságban a stratégiákat három alapvető részre oszthatjuk, hogyha programozás technikailag nézzük a szerkezetét.
  1. Pozíció nyitás
  2. Pozíció módosítás
  3. Pozíció zárás
A pozíció nyitásához azonban nem csak a stratégia számításai a fontosak, hanem a money management számítások is rendkívül fontosak! Tudom, hogy folyton ezen lovagolok, de higgyétek el, tényleg nagyon fontos!
Egyenlőre azonban a program fejlesztésére koncentrálunk, így a stratégiát úgy fogjuk elkészíteni, ahogyan én is szoktam a gyakorlatban csinálni.
A fejlesztés fázisai a következők lesznek :
  • A pozíció nyitások és zárások elméletének ellenőrzése
  • Money management-tel történő támogatása
  • Veszteségek további csökkentése
  • Nyereségek növelése
  • Demó számlán történő tesztelés
  • Éles számlán történő tesztelés kis összegekkel
Nézzük szépen sorban, mert hiszen komoly magyarázatra szorul mindegyik rész szerintem.

A pozíció nyitások és zárások elméletének ellenőrzése nem másról szól, mint arról, hogy a trader kitalálja milyen jelzések alapján akar kereskedni, majd ezekre a jelzésekre "összeüt" egy rövid kis kódot és backtest-tel leteszteli, hogy az általa kitalált elmélet mennyire állja meg a helyét.Ennek ugye ott az értelme, hogy a backtest alkalmával látni fogod, hogy valóban jókor nyit-e pozíciót a programod és jókor zárja-e le. Előfordulhat ugyanis, hogy kitalálod a frankót, de amikor backtest-telsz, azt fogod látni, hogy bizony nem minden esetben akkor nyit long-ot, amikor tényleg felfelé indul el az árfolyam, vagy az is lehet, hogy elindul felfelé az ár, de mégsem nyit long-ot. Tehát ez fontos, hogy a kitalált elméletet leellenőrizzük.

Money management támogatás. Itt egész egyszerűen arról van szó, hogy meghatározzuk azokat a kritériumokat, amely szerint a pozíció méreteket kitalálja a program magától. Ezt a részt persze ki is hagyhatnánk és mondhatnánk, hogy fix lot-okkal kereskedünk, ilyen is van, ezt fix pozíció méretnek nevezzük. Itt kell azonban kitalálnunk azt is, hogy hová húzzuk a stop-okat (SL), hová tesszük a take profit-okat (TP). Ezek ismeretében pedig ki tudjuk számítani a Risk/Reward arányt is (RR), ami meg fogja mondani nekünk, hogy érdemes-e egyáltalán pozícióba lépnünk. Sajnos ez egy elég bonyolult algoritmus, nem biztos, hogy ezt az elején fogjuk tárgyalni, de mindenképpen fontos.

A veszteségek csökkentése is egy olyan technika, amikor a backtest által nyújtott információkat használjuk fel arra, hogy növeljük a profit faktorunkat, vagyis a nyerő kereskedések számát meghagyva csökkentjük azoknak a pozíció nyitásoknak a számát, amelyek veszteséget termelnek. Ez persze azt jelenti, hogy kevesebb pozíciót fog nyitni a programunk, de legalább ezek nagyobb részt lesznek nyereségesek, mint veszteségesek.

A nyereségek növelése pedig azt a célt szolgálja, hogy a nyereséges pozíció nyitások nyereségét fogjuk feltornászni mindenféle trükkökkel, hogy azután a veszteségek eltörpüljenek mellettük. Nem kell óriási trükkökre gondolni, egyszerűen arról van szó, hogyha az árfolyam elindul felfelé és long-ot nyitunk például, akkor figyeljük, hogy az ár mozog-e még tovább felfelé. Ha igen, akkor újabb long-ot nyitunk, vagyis rákötünk az előző pozíciónyitásra. Ezt piramis építésnek, vagy piramidális pozíció építésnek is hívják. A pozíciók SL-i és TP-i ugyanazok és egyszerre is zárjuk őket. Elképzelhető, hogy záráskor lesznek veszteséges pozíciók, de a piramis építésekor a csúcson lévők lesznek a veszteségesek, az alattuk lévő (vagyis korábban nyitott) pozíciók azonban nagyobb és nagyobb nyereséggel rendelkeznek, ahogy szélesedik a piramis lefelé.

Ha minden a helyére kerül, akkor lehet tesztelni éles adatokkal egy demó számlán, ugyanis a backtest csak informál a lehetséges sikerekről, de mivel már a múlt, ezért az nem biztos, hogy a jövőre nézve is igaz. Az esélye meg van, de ki tudja mit hoz a jövő... Itt legalább egy, de inkább három hónapig teszteljük a programunkat, minden héten alaposan kiértékelve a nyitott és zárt pozíciókat.

Ha pedig elégedettek vagyunk a programunk teljesítményével a demó számlán, elkezdődhet az éles számlán történő tesztelés kis összegekkel. Itt egészen kicsi összegekről van szó, 500 USD, maximum 1000 USD-ről. Persze ez van, akinek komoly összeg, de ha már a demó számlán jól teljesített a programunk, akkor nyilván nem félünk attól, hogy elveszítjük a pénzünket. Itt azonban szintén komolyan kell venni néhány irányelvet, amit majd e rész tárgyalásakor részletesen le is írok.

És akkor most lássuk a stratégiát!
Ez egy régi stratégia, sokan használják kézi és félautomata kereskedésekhez (amikor csak jelez a program, hogy pozíciót kellene nyitni, vagy zárni, de nem nyitja/zárja). Egyébként rém egyszerű dologról van szó.
Három indikátort fogunk használni. Mielőtt azonban ténylegesen ismertetném a stratégiát szeretnék megosztani Veletek egy igen fontos dolgot.

A stratégiák megalkotásakor sokan vagyunk hajlamosak arra, hogy a beépített indikátorok és a tanult indikátorok alapján találjuk ki, hogy mikor nyitunk pozíciót és mikor zárjuk azt.
A probléma abból adódik, hogy ezek az általánosan ismert és a kereskedési platformokba beépített indikátorok még akkor születtek, amikor a számítástechnika gyerekcipőben járt, ezért nagyon általános információkat szolgáltatnak. Kézi kereskedéshez jók, ha az ember látja a chart-ot, mert akkor tudja, hogy most éppen oldalaz a piac, fölösleges hinni az ADX-nek. De egy automata program nem "látja" a chart-ot és akkor is pozícióba fog lépni, amikor oldalazás van.

Ez egyébként az automatikus programok egyik rákfenéje is, vagy ha úgy tetszik a Szent Grálja. Ha a program képes "rájönni" arra, hogy mikor van oldalazás, akkor nem fog pozícióba lépni az indikátorok jelzésére, ha pedig elindul a trend, akkor meg tök mindegy melyik klasszikus indikátort használod, akkor is nyerni fogsz, csak a nyereség nagysága különbözik. Ilyenkor az RSI, az ADX, a Stochastic, vagy bármi más igazat mond, köthetsz. De ha oldalazik az árfolyam, akkor is jelet fognak adni ezek az indikátorok, így becsapod magad és a spread miatt, meg a folyamatos zavar miatt elveszíted a fáradtságosan megkeresett pénzedet...

Nem szabad elfelejteni, hogy általános érvényű az a szabály, hogy a piac 70%-ban oldalazik és mindössze 30%-ban mozog trendszerűen!!! Ezt nagyon komolyan kell venni!

(Csak zárojelben jegyezném meg, hogy a másik megoldás az agresszív stratégia, de ez nagyon veszélyes. Ez tulajdonképpen olyan, mint a sörétes puska, mindenre lő, ami a grafikonon van, ráadásul hatalmas lot méretekkel (akár 6 lot is lehet), amit egy-két gyertya után be is zár. Ehhez azonban nagy tőke kell, még okosabb indikátorok és hihetetlen bátorság! Ezzel nem is fogunk foglalkozni, mert a mi szintünkön ez még annyira durva, hogy jobb, ha félünk tőle. Akinél dolgozik a tőzsdepszichológia, annál néhány óra alatt lenullázott számlát jelent ez a fajta kereskedés! Mivel nagy tőkéről van szó, a veszteség is nagy!!! Mindenkit óvva intenék ettől!!!)

Tehát, a hagyományos indikátorokat gyakorlatilag el is felejthetjük. Az említett három indikátorból kettőt használunk a pozíció megnyitására, a harmadikat (ami egyébként egy beépített indikátor lesz), pedig a SL húzásra használunk.
A stratégiánk is erre alapul, nincs TP, viszont van SL, RR nem számítható (itt a rizikó), viszont követő stop-okat húzunk, amit aztán az árfolyam kiüt. Tehát konkrét pozíció zárás sem lesz a stratégiában, hanem a SL-ra bízzuk a zárást. Attól a pillanattól kezdve, amikor a SL vonala a pozíció nyitás fölött lesz, már nyereséges a pozíció zárása, illetve jelen esetben a "kistoppolódása".

Tehát két olyan indikátort fogunk használni, melyek nincsenek beépítve a Metatrader-be, erről volt szó.
Az egyik egy - egyébként meglehetősen jól ismert - mások által sűrűn használt indikátor, a TVI.
A TVI, azaz a Trend Volume Index az OBV (On Balance Volume) indikátor továbbfejlesztett változata.
Az OBV nem használható eredményesen napközben, ellenben a TVI-t erre találták ki.

Bár minden tőzsdeiskolában azt tanítják, hogy a deviza kereskedésnél a forgalom értékeket nem szabad figyelembe venni, mert azok hamis adatok, ennek ellenére a Metatrader-ben a forgalmi információk megbízhatók, így nyugodtan használhatjuk a részvény kereskedésnél megszokott indikátorainkat, melyek a forgalmi adatokat is felhasználják. A TVI is ilyen indikátor. A forgalmi adatok és a Bid, Ask árak figyelembe vételével számol ki egy úgynevezett biztonsági mutatót, amely a vásárlás, vagy az eladás biztonságosságát hivatott mutatni egy görbe formájában a chart-on. Ráadásul nem követő indikátor, mert a forgalmi adatok jól mutatják meg egy árfolyam mozgás esetében, hogy mikor fárad ki a trend, vagy mikor tör ki az árfolyam.

A másik indikátor egy igen furfangos indikátor, a CCI (Common Channel Index) és az ATR (Average True Range) indikátorokat használja trend meghatározásra. A CCI önmagában is igen jól használható indikátor, különösképpen, ha a középvonal átlépést vizsgáljuk elég jól meg tudjuk mondani, hogy merre indul a trend, de sajnos igen "izgága" indikátor, ezért oldalazásban becsaphat bennünket. Az indikátorunk, amelyről szó van, az ATR-rel szelídíti meg a CCI mozgását, egy igen ügyes technikával. Így egy sokkal kevésbé ugráló vonalat kapunk, ráadásul mindezt a chart-on, tehát nem különálló ablakban. Ez az indikátor a TrendMagic.

E két indikátor jelzéseit fogjuk figyelni, hogy éppen mikor merre mozdul el, amikor pedig mindkét indikátor ugyanazt mutatja, akkor pozícióba lépünk a mutatott iránynak megfelelően.

A kilépésekkel és a SL-al nem sokat fogunk törődni, hanem a Parabolic SAR indikátor megfelelően paraméterezett változatával határozzuk meg a stop-okat, amelyet minden egyes gyertyánál módosítunk, így amikor elindul a trend, akkor egyszerűen követjük azt, amikor pedig megfordul, akkor a SL kilépteti pozíciót, és meg is kaptuk a pozíció nyereségét.
Ugyancsak eme indikátor miatt nem fogunk TP-t sem számolgatni, de aki szeretne majd, beállíthat TP-t. Ez esetben a hosszabb trendeket nem lehet majd maximális profittal kihasználni, de a semminél mindenképpen több lesz a nyereség, és ami fontos : biztos nyereség lesz.

Amire majd a fejlesztés során megoldást kell találnunk, az az oldalazásban történő pozíció nyitás kivédése, itt ugyanis kapunk majd jelet, de sajnos olyan rövidek a lokális trendek, hogy a spread és a SL miatt szinte semmi hasznunk nem marad, sőt, inkább veszteséges pozíció zárások történnek. De erre is van recept!

A következő post-ban összerakunk egy kódot, amit majd tesztelgetni fogunk mindenféle beállításokkal.

péntek, június 18, 2010

Kezdjünk programozni

Átesett a blog némi ráncfelvarráson, mert elég lehangoló volt az egész, de talán most kicsit motiválóbb lesz, és Nektek is tetszeni fog.

Mostantól megpróbálok kicsit sűrűbben írni a blogba, mert a program írása közben is szeretném, ha tudnátok követni.
A következőkben írunk egy programot, amely kereskedni fog, méghozzá nyereségesen.
Megtanulunk egyszerűbb fogásokat, illetve olyan segédeszközöket készítünk - mellék termékként -, melyek a kézi kereskedésben is a segítségükre lehet. Kitalálunk egy jó kis Money Management stratégiát és tesztelünk, javítunk, okoskodunk és győzünk! Mert hát erről szól az egész! Nem?

Azt hiszem, hogy eleget filozofáltunk, el kellene kezdeni programozni.
Csapjunk a közepébe!

Hogy értsük is, hogy mit csinálunk, némi magyarázat előzetesen arról, amit csinálni fogunk.

A MetaTrader-ben alapvetően 6 különböző programfájlt készíthetünk, ebből 3 különféle van, ami futtatható programként viselkedik.
Mivel eleinte csak alap dolgokat fogunk csinálni, így nem tárgyaljuk egyenlőre a nem futtatható kódokat, koncentrálunk a futtatható kódokra!

FIGYELEM! Az itt leírt kódok működéséért, azok éles számlán való futtatásáért ezen blog írója nem vállal felelősséget! Bárki, aki követi az utasításokat, csakis kizárólag a saját felelősségére tegye! Éles számlán történő futtatása a tőke elvesztésével járhat! A leírt kódok kizárólag oktatási célokat szolgálnak.

A MetaTrader-ben 3 féle futtatható kódot írhatunk (kódnak nevezzük a program szövegét, az ember számára olvasható kódot, melyet le kell fordítanunk futtatható programmá, azaz a gép számára olvasható kóddá. Szokás forráskódnak is nevezni, mivel ez lesz a futó program forrása.) :
  1. Script : ezek olyan nagyon egyszerű programok, melyek egyetlen egyszer futnak le. Azután a program végrehajtásnak vége szakad.
  2. Indicator : ezek a kódok speciális programok, amelyek a chart-on indikátorként viselkednek. Meglehetősen bonyolult a programozása, ez később fogjuk tárgyalni, de tárgyaljuk mindenképpen, mert igen fontos. Az indikátorok eredményeit - akárcsak a beépített indikátorok eredményeit - fel tudjuk használni a kereskedő programjainkban, hogy döntéseket tudjunk hozni. De manuális kereskedésben is használhatjuk. Az indikátorokban nem használhatjuk a kereskedéssel kapcsolatos utasításokat.
  3. Expert Advisor : ezek az igazi kereskedő programok, ezek képezik az automatikus kereskedés gerincét. Egy chart-on csak egy futhat, és nem több! De a jó hír az, hogy több chart is nyitva lehet egyszerre...
Miután az automata kereskedéshez Expert Advisor-t (mostantól egyszerűen csak EA-t) kell futtatnunk, így ezzel folytatjuk, később pedig elkészítjük első indikátorunkat, menet közben pedig script írási tudásunkat is csiszolgatjuk.

Egy EA ugyanúgy működik, mint egy klasszikus program. Bemenete és kimenete van. Bemenete a különböző paraméterek, melyekkel beállítjuk a programunk működését, kimenete pedig a megkeresett (rossz esetben az elveszített) pénz.

Amikor egy EA-t szeretnénk futtatni, akkor hozzá kell csatolnunk egy chart-hoz. Kétféleképpen tehetjük ezt meg, az egyik az, hogy egérrel megfogjuk a bal oldali listából és ráhúzzuk a chart-ra.
A másik megoldás pedig az, hogy az EA-n nyomunk egy jobb egér gombot, és a "Chart-hoz csatol" menüpontot választjuk a felugró menüből.

Ekkor felugrik egy ablak, ahol be tudjuk állítani az EA bemeneti paramétereit, illetve a futtatásához szükséges egyéb paramétereket.

Próbáld csak ki. Ott a "Moving Average" EA az "Expert Advisor" lenyíló listában a Navigáció ablakban.
Ha ráhúzod a chart-ra, akkor máris ott az ablak. Két fül van, az "Általános" és a "Bemenő adatok".

Az "Általános" fülön néhány nagyon fontos beállítás van. Keretekre van osztva, melyek a következők:

Általános :
  • Long & Short pozíciók : itt szabályozhatod, hogy long (vásárlás), vagy short (eladás) illetve mindkettőt engedélyezed a program futása során. Függetlenül attól, hogy mit írtál a programodban, itt felülbírálhatod!
  • Riasztások : ezekkel nem kell most foglalkoznunk, ahogy van, úgy jó
Élő kereskedés :
  • Élő kereskedés engedélyezése : itt mondhatod meg, hogy a programod végezhet-e élő kereskedést. Ha demó számlával tesztelgetsz, akkor a demó számlán fog "éles" kereskedéseket végezni azzal a pénzzel, amit a demó számlára kaptál. a viszont élő, azaz valódi pénzzel rendelkező számlád van, akkor a TE pénzeddel kereskedik!
  • Kézi megerősítés kérése : Ha nem vagyunk biztosak a programunk sikerében, akkor bepipálhatjuk, ekkor minden kötés előtt kézzel meg kell erősíteni, hogy mehet a pozíció nyitás. Ezzel persze elveszítjük az automatizáltságod, de legalább a mi döntésünk is benne van...
Biztonság :
  • Itt mindenféle rejtélyes dolgot lehet beállítani, hagyjuk úgy, ahogy van, nem érdekes most a beállítás.
A "Bemenő adatok" fülön pedig a programunk paraméterei vannak, ha a "Moving Average" EA-t húztad a grafikonra, akkor "Lots", "MaximumRisk" és ehhez hasonlókat látsz.

Mielőtt azonban futtatni kezdenénk bámilyen EA-t, legelőször is szedjük ízeire, vesézzük ki!

Ha a "Moving Average" EA-t kiválasztjuk a listában és nyomunk egy jobb egérgombot rajta, akkor a felugró menüből válasszuk ki a "Módosítás" menüpontot.
Ekkor a program megnyitja a MetaEditor nevű programot, amellyel a programjainak fogjuk szerkesztgetni ezentúl.

Ez egy tökéletes környezet a programjaink fejlesztéséhez, mert egy kódszerkesztőt, fordítót és súgót is magában foglaló rendszert ad a kezünkbe, amellyel igen hatékonyan lehet programot írni.

Ha minden jól megy, akkor láthatjuk a Moving Average.mq4 forráskódját, azaz magát az olvasható programot. A forráskódok fájl kiterjesztése mindig mq4, a lefordított program neve ugyanaz marad, de a kiterjesztése ex4 lesz.

Ha jól megfigyeljük, akkor a program kódja a következő részekből áll :
  • fejléc
  • init() függvény
  • start() függvény
  • deinit() függvény
  • egyéb függvények
A fejlécet mindjárt kitárgyaljuk, most legelőször a következő részek lényegét kell megértenünk.
Az init() függyvény a programunk indulásakor fut le, egyetlen egyszer. Egész konkrétan akkor fut le, amikor a paraméter ablak bezárul egy OK-val.

Ennek a fügvénynek a párja a deinit() függvény, amely a program leállításakor, újraindításakor fut le egyetlen egyszer.

E két függvénnyel óvatosan kell bánnunk, mert ha a bróker, vagy a VPS szolgáltató (erről is részletesen beszélgetünk majd) újraindít egy karbantartás miatt, akkor ezek a függvények lefuthatnak és ha nincsenek jól megírva, akkor komoly problémákat okozhatnak.
A deinit() függvény például vizsgálhatja a program leállításának okát a UninitializeReason() függvény segítségével, hogy miért állt le a program.
Ezek az okok sokfélék lehetnek, amelyekre mindre másképpen reagálhat a programunk. Lássuk csak :
  • REASON_REMOVE - Az EA-t eltávolítottuk a chart-ról, ez ugye egyértelmű. Ez az EA-k klasszikus végrehajtás megszakítása.
  • REASON_RECOMPILE - Újrafordítottuk az EA-t. Ennek elvileg csak fejlesztés közben szabadba előfordulnia, egy éles környezetben ez nem fordulhat elő. A lényeg, hogyha egy EA-t újrafordítunk, legtöbbször az a célra vezető, ha eltávolítjuk a chart-ról és utána újra rádobjuk az egérrel, mert előfordulhat, hogy nem úgy működik egy újrafordítás után, ahogy azt elvárjuk és ahogy kellene. Ha levesszük a chart-ról az EA-t és újra rádobjuk, ezeket a problémákat a legtöbbször ki tudjuk kerülni, meg tudjuk oldani.
  • REASON_CHARTCHANGE - A chart megváltozott. Vagy egy másik instrumentum került rá, vagy az időtávot változtattuk meg. Ez igen fontos lehet, mert ha egy EA-t egy bizonyos instrumentumra, vagy időtávra optimalizáltuk, komoly veszteséget termelhet a program, ha megváltoznak a körülmények a chart-on.
  • REASON_CHARTCLOSE - bezártuk az aktuális chart-ot, természetesen ilyenkor meg kell szakítani a program működését, mivel nincs értelme tovább futnia. Ekkor kapjuk ezt a kódot, hogy tudjuk nem más okból jött létre a program megszakítás.
  • REASON_PARAMETERS - A futó EA-nak megváltoztattuk valamelyik paraméterét. Ez mindig hatással van az EA életére, ezért ez egy nagyon fontos jelzés. Ilyenkor ugyanis újraindul az EA az új paraméterekkel. Nagyon nagyon fontos ok, tehát erre komolyan oda kell figyelnünk, amikor írjuk az EA-t.
  • REASON_ACCOUNT - Megváltozott a számlaszám, amelyen a chart-okat megjelenítjük, illetve ahol az EA fut. Ez gondolom nem is kell magyaráznom, hogy miért és mennyire fontos. Ha a számlaszámunk megváltozik, akkor megváltozhatnak a pozíció nyitási feltételek, a tőke nagysága, és akár maga a bróker is lehet teljesen más. Tehát ne higgyük, hogy ez elhanyagolható tényező lenne.
Természetesen azok az EA-k, melyek ezekkel a kódokkal törődnek, már nagyon profi programok, egyenlőre nem is fogunk ilyen programokat írni, esetleg nagyon elvétve foglalkozunk ezekkel a paraméterekkel.
Amivel legelőször foglalkozunk, az leginkább a jó stratégia kialakítása és leprogramozása, hogy nyereséget érjünk el. Hiszen ezért csináljuk az egészet.

A legfontosabb része a programunknak a start() függvény. Itt történik minden (legalábbis a dolgok 99%-a), ami a stratégiánk működését képviseli, illetve ami a kereskedéseinket illeti.
Ezt a függvény a MetaTrader minden egyes tick beérkezésekor lefuttatja egyszer. (azt ugye nem kell megmagyaráznom, hogy a tick az az esemény, amikor valamilyen tranzakció történik a piacon az adott instrumentummal, amely árváltozást okoz. Minden időtávon ugyanakkor érkeznek a tick-ek.)

Abban a pillanatban, amikor érkezik egy tick, a start() függvényünk lefut és vagy történik valami közben, vagy nem. Vagy pozíciót nyitunk, vagy nem. Vagy lezárjuk azt, vagy nem. Tulajdonképpen az egész stratégiánkat itt kódoljuk le. Ez a leglényegesebb része a programunknak. Éppen ezért, ha bármikor is az EA törzsére, vagy a futó kódra célozgatunk ebben a blogban, akkor erre a függvényre kell gondolnunk elsősorban.

A fejléc is igen fontos része a programunknak, mert bizony a fejlécben rengeteg maradandó tulajdonságát határozzuk meg az EA-nak. A fejlécünk tovább tagolódik, ennek megfelelően a következőket találjuk itt :
  • A program információs része, itt kommentek formájában tárolhatjuk a forráskódunkban a program nevét, verzióját, az esetleges tovább fejlesztési ötleteinket, és szinte bármit, amit csak akarunk.
  • Fordítási direktívákat, vagyis megmondhatjuk a fordító programnak, hogy amikor lefordítja a forráskódunkat a gép számára értelmes kóddá, akkor azt milyen egyéb feltételekkel hajtsa végre. Olyanokra kell itt gondolni, mint pl. a végleges kódba fixen beégetett információk (copyright infók, a szerző elérhetőségei link formájában, stb.), vagy a jó kis függvény könyvtárunkat is használja, vagy azt, hogy megmutassa-e a felhasznált indikátorokat, stb. Ezekkel meg fogunk ismerkedni hamarosan, mert minden programban szükség van ezekre. Nem túl bonyolult, nem kell megijedni tőle. Szeretetre méltó kis okosságok ezek.
  • Include-ok, melyek egy nem futtatható forráskódot illesztenek be a programunkba. Erről később beszélünk majd, a komolyabb fejlesztések során vesszük hasznát, kezdéshez egyáltalán nem foglalkozunk velük, vagy csak érintőlegesen.
  • Az úgynevezett extern változók, melyek tulajdonképpen a programunk bemenő adatainak való változók definíciói. Ez jelenti a programunk kapcsolatát a külvilággal.
  • Globális változók, melyeket egy programozással foglalkozó fejlesztőnek talán nem kell bemutatni. Azokról a változókról van szó, melyeket minden függvényünk, és maga a program törzse (start() függvény) is lát, írhatja, olvashatja.
  • Konstansok, melyek a teljes EA-ra vonatkoznak, tulajdonképpen olyan változók, melyek értékeit nem lehet megváltoztatni. Ezek leginkább a forráskód olvashatóságát javítják.
Az egyéb függvények azok a függvények, melyeket a start() függvényből hívunk meg és a program végrehajtás folyamán fontos tevékenységet végző program modulok, egységek. Ezt szinte mindig használni fogjuk. Ez nagyon fontos része lesz a programunknak. Már-már haladó szint, de mivel nélkülözhetetlen, fontos dolog.

Következő bejegyzés alkalmával már részletesebben kitárgyaljuk a megvalósítandó stratégiát, a pozíció nyitását és zárását, illetve belekóstolunk egy kicsit a Money Management-be is.
Szóval nekiesünk a kódolásnak!

csütörtök, május 20, 2010

Money Management általában

Beszéljünk kicsit a Money Management-ről (mostantól MM)!

Nem véletlenül írok erről a témáról, ugyanis fájó tapasztalataim vannak. Nem viccelek!
Hogyha egy kicsit alaposabban végig gondoljuk azt, hogy miből is áll egy tőzsdéző (FOREX-ező, de ez most szinte mindegy) kereskedési gyakorlata, akkor azt fogjuk tapasztalni, hogy hűen igazodik az öt legfontosabb szabályhoz :
  1. Keress több pénzt
  2. Védd meg a pénzedet
  3. Tervezd meg pénzügyeidet
  4. Érj el hatástöbbszörözést
  5. Javítsd pénzügyi tájékozottságodat
Nem egyedül találtam ki ezeket a szabályokat, sőt mi több, semmi közöm hozzá. Robert T. Kiyosaki "Fejleszd pénzügyi IQ-dat" c. könyve taglalja eme szabályokat.

(Aki esetleg nem tudná ki is ő, azoknak nagyon ajánlom, hogy nézzen utána. Kötelező olvasmány a "Gazdag papa, szegény papa", a "Cashflow négyszög" c. könyvei, az összes többi pedig ajánlott olvasmány!!! Komolyan mondom, hogy ezen könyvek nélkül SENKI ne nyisson éles számlát, különben el fog vérezni!!!)

Nézzük csak FOREX-re fordítva a dolgokat :
  1. Keress több pénzt = legyen egy remek stratégiád, ami nyereséges, kicsi a drawdown (a veszteséges pozíció zárásokból adódó "visszaesések")
  2. Védd meg a pénzedet = használj stop-loss-t (ez ugye mindenkinek a könyökén jön ki, mert minden oktató, könyv, szakember ezt szajkózza folyton), de ide tartozik az is, hogy válassz jó brókert, ahol nincs kötési jutalék, alacsonyak a kamatok, megfelelően jó méretű pozíciókat lehet felvenni és persze kevés pénzzel lehet indulni, ez volt az egyik alapkövetelmény, amiért elindult ez a blog...
  3. Tervezd meg a pénzügyeidet = ha fogalmad sincs, hogy a stratégiáddal mennyi pénzt tudsz keresni, akkor ehhez a ponthoz hozzá sem tudsz szólni. Pedig fontos! Igaz, hogy a tőzsdén bármi megtörténhet, de akkor is kell, hogy legyen egy terved! Meg kell fogalmaznod, le kell írnod és szem előtt kell tartanod! Milyen egy terv nekünk FOREX-ezőknek? Hát mondjuk olyan, hogy "havi 5% nyereség elérése, maximum 10 PIP drawdown-nal". Merészebbeknek : "napi 1,5% nyereség elérése, havi szinten maximum 1% veszteséggel". Még merészebbeknek : "Egy év alatt megduplázom a befektetett tőkémet"
  4. Érj el hatás többszörözést = akár a stratégiáddal, akár a pénzügyi tervezéseddel azt kell elérned, hogy a befektetett tőkéd egyre nagyobb és nagyobb legyen! Ezt a stratégiáddal úgy tudod elérni, hogyha a kötéseid ún. piramidális kötések. Utálom ezt a szót, de nincs jobb. Ez nagyjából annyit jelent, hogy a stratégiád nyit egy pozíciót, amelyet természetesen valamilyen jelre teszi, majd a már nyitott pozíció mellé egy ugyanolyan irányú újabb pozíciót nyit a következő jelre, és ezt egészen addig teszi, amíg mondjuk a trend egy irányba mozog. Amikor ki kell szállni, mert megfordul a trend, vagy oldalazik, akkor lesz tizenöt nyitott pozíciód, amelyek vagy mind nyereségesek, vagy legfeljebb kettő veszteséges, de a többi nyeresége bőségesen fedezi a veszteségeket. A pénzügyi tervezés maximum annyi lehet, hogy nem veszed ki havonta, vagy hetente a nyereségedet, így a stratégiád egyre többet és egyre nagyobb pozíciókat tud nyitni.
  5. Javítsd pénzügyi tájékozottságodat = ezt gondolom felesleges taglalni, fontos, hogy más "rokon" devizapárokat is figyelj (mondjuk EURJPY esetén a többi EURXXX és más XXXJPY devizapárokat), de az is lényeges lehet, hogy figyeled a híreket. Ami még ennél is fontosabb, folyamatosan tapasztalatokat gyűjtesz és képzed magad a FOREX-en történő kereskedéssel kapcsolatban!
Most ugye a 2. pontról beszélgetnénk, az 1. pontot szándékosan nem tárgyaltam eddig. Azt fogom legutoljára.
De mind fontos és mind része a jó FOREX robotnak.

Az MT4-ben (vagy nem sokára za MT5-ben) az MM nagyon jól leprogramozható. A számlád információit csodás függvényekkel lehet lekérdezni, a korábban már említett paraméterekkel együtt.
Nézzük csak!
AccountBalance() --> Ez a függvény az éppen aktuális egyenlegről tájékoztat. Arról a pénzről, ami már a Tiéd, amit befektethetsz, vagy visszautalhatsz magadnak, vagyis a számládon lévő tényleges pénz.
AccountEquity() --> a számlán lévő pénz, + a nyitott pozíciók értéke. Mindenképpen pozitív érték kell legyen a kettő együtt. Ha a nyitott pozíciók értéke negatív, akkor a balance-nál mindenképpen kevesebb lesz, ha pozitív a nyitott pozíciók értéke, akkor több lesz a balance-nál. Ha viszont a nyitott pozíciók nagyon negatív értéket kezdenek felvenni, akkor a bizonyos equity értéknél a bróker cég bármikor dönthet a margin call végrehajtásáról, vagyis bezárja a pozícióidat és marad a számlán annyi, amennyi. Ezért fontos, hogy a balance jó nagy legyen, a kötés mérete pedig minél kisebb, hogy minél később jöjjön a margin call...
AccountFreeMargin() --> a még szabadon beköthető tőke mennyisége
AccountLeverage() --> A számlán lévő tőkeáttét nagysága. Ha azt adja vissza, hogy 100, akkor az azt jelenti, hogy az áttét 1:100.
AccountMargin() --> A bekötött tőke nagysága. Ez csupán annyit jelent, hogy mennyit költöttünk az aktuális pozíció megnyitására.
MarketInfo() --> Ennek a függvénynek igen sokféle funciója van, elsősorban a jelenleg is nyitva lévő chart-ról ad információkat. Két paramétere van, az első az aktuális instrumentum neve, a második pedig a megtudakolni kívánt információra vonatkozó azonosító.
A legfontosabbak :
  • MODE_DIGITS --> Az intrumentum árának tizedes pont utáni számjagyeinek száma. Ez igen fontos, amikor PIP-eket szeretnénk számolni!
  • MODE_SPREAD --> a jelenlegi spread mérete PIP-ekben. Ez ugye változhat (bár vannak brókerek, akik azt hirdetik magukról, hogy fix spread-ekkel dolgoznak), de két különféle instrumentumnak általában azért különbözik a spread-je.
  • MODE_STOPLEVEL --> sok brókernél korlátozzák a stop szinteket, vagyis megmondják, hogy mi az a minimális PIP, ahová a stop-odat teheted. Tehát nem teheted a kötési ár alá 5 PIP-el, ha ez az érték 20-at ad vissza. Ebben az esetben a minimális stop húzás az aktuális ár alatt 20 PIP-el van.
  • MODE_LOTSIZE --> ez azt mondja meg, hogy az aktuális instrumentum esetében mi a lot mérete. Ez a bázis valuta egységeiben értendő. Ez természetesen függ a tőkeáttéttől is! A tőkeáttéttel, valamint ezzel az értékkel lehet kiszámítani a bekötött tőke mennyiségét, ami ha minden igaz, akkor megegyezik a korábban már említett AccountMargin() függvény által kiszámított értékkel. (természetesen csak akkor, ha a kötés árával számolunk és nem a pillanatnyi árral!!!)
  • MODE_MINLOT --> A pozíció nyitásához szükséges minimális lot mérete! Ez az egyik legfontosabb és az egyik legmeghatározóbb érték, ami az adott instrumentum kereskedéséhez kell. Brókere válogatja, hogy ez mennyi! Általában a demó számlán egészen kicsi, de az éles számlán már nagyobb (beetetés). Szóval ne csodálkozzunk, ha a demón jól működő programunk az élesen "túlkereskedi" a számlánkat. (persze ilyen egy jó MM-mel nem fordulhat elő...)
  • MODE_LOTSTEP --> A már meglévő pozíció módosításához használható lot méret. Vagyis, ah rákötünk, esetleg a pozíciót részlegesen zárjuk, akkor mi az a lot méret, amivel ezt megtehetjük. Ez sokszor kisebb, jó esetben egyenlő az előző értékkel (MINLOT).
  • MODE_MAXLOT --> a kereskedés folyamán nyitható lot-ok együttes száma ezt nem lépheti túl. Többnyire mikró számlákon van ilyen, amikor a minimális lot méret mondjuk 0.05, akkor ez az érték 2 lot szokott lenni. Vagyik addig nyitogathatunk pozíciókat, amíg a nyitott pozíciók lot számának összege el nem éri ezt az értéket. Tehát a példával élve, ha minden pozíciónkat 0.05 lot-tal nyitjuk meg - és nem változtatjuk később -, akkor összesen 40 ilyen pozíciót lehet nyitni.
Nos, nagyjából ennyit érdemes tudni ezekről a függvényekről, később, amikor használjuk őket, úgyis kivesézzük tövéről-hegyére.

Jó olvasgatást mindenkinek!