MQL4 könyv   Változók    Az ügyfélterminál globális változói (GlobalVariables)

Az ügyfélterminál globális változói (GlobalVariables)

Több alkalmazási program működhet az ügyfélterminálban egyidejűleg. Néhány esetben szükségessé válhat néhány adat átadása egyik programból a másikba. Történetesen ezért vannak az MQL4-ben az ügyfélterminálnak globális változói.

Global variable of Client Terminal egy változó, az az érték, ami elérhető minden alkalmazási programból, amit az ügyfélterminálban elindítottak (rövidített alak: GV).

Figyelem!

Jegyezd meg: az „ügyfélterminál globális változója” és a „globális változó” különböző változó típusok hasonló nevekkel. A globális változók hatóköre az a program, amiben a változót deklarálják; míg az ügyfélterminál globális változóinak a hatóköre minden olyan program, ami az ügyfélterminálban fut.

GlobalVariables tulajdonságai 

A GV abban különbözik az egyéb változóktól, hogy bármely programból nemcsak létre lehet hozni, hanem törölni is. A GV értékét a merevlemezen tárolják és mentik az ügyfélterminál bezárásakor. A deklarált GV-t az ügyfélterminál, az utolsó hívástól számított 4 héti tárolja. Ha ez alatt az időszak alatt semelyik program sem használja a változót, az ügyfélterminál törli azt. A GV csak double típusú lehet.

A GlobalVariables függvényei

GV-vel való együttműködésre az MQL4-nek van egy függvény készlete (lásd még: GlobalVariables). 

Elemezzük azokat, amelyeket a további példákban használni fogunk!

GlobalVariableSet() függvény

datetime GlobalVariableSet( string name, double value)

Ez a függvény létrehozza egy globális változó egy új értékét. Ha a változó nem létezik, a rendszer létrehozza az új globális változót is. Sikeres végrehajtás esetében a függvény visszaküldi az utolsó hozzáférés idejét, egyéb esetben a visszatérési érték 0. Hibainformációt a GetLastError() függvény hívásával kaphatunk.

Paraméterek:

name - A globális változó neve.

value – Az új számszerű érték.

GlobalVariableGet() függvény

double double GlobalVariableGet( string name)

A függvény visszaküldi egy létező globális változó értékét vagy hiba esetében 0-t küld vissza. Hibainformációt, a GetLastError() függvény hívásával kaphatunk.

Paraméterek:

name - A globális változó neve.

GlobalVariableDel() függvény

bool GlobalVariableDel( string name)

Ez a függvény töröl egy globális változót. Egy sikeres törlés esetében a függvény visszaküldi aTRUE-t – egyéb esetben FALSE-t. Hibainformációt most is a GetLastError() függvény hívásával kaphatunk.

Paraméterek:

name - A globális változó neve.

Hogy szemléltessük a GlobalVariables használatának előnyeit, oldjuk meg a következő feladatot:

Feladat

24. feladat: Több Expert Advisor dolgozik egyszerre a terminálban. A letét 10 000 dollár. Az összes nyitott megbízás által lekötött tőkének nem szabad meghaladnia a letét 30 százalékát. Egyenlő összeget kell elkülöníteni mindegyik Expert Advisor részére. Hozz létre egy olyan EA programot, ami kiszámítja a kerekedésre elkülönített összeget.

Egy EA részére elkülönítettek összeg kiszámítása nem nehéz. Azonban ehhez szükségünk van arra, hogy tudjuk azon Expert Advisorok számát amelyek egy időben működnek. Nincs olyan MQL4 függvény ami választ adhatna erre a kérdésre. Az egyetlen lehetőség arra, hogy kiszámoljuk az elindított programok számát az, hogy mindegyik programnak be kell jelentenie magát azáltal, hogy megváltoztatja egy bizonyos GV értékét. Minden program elküldi ezt a szükséges információt, ehhez a GV-hez, és ez jelzi az aktuális állapotot.

Itt kell megjegyezni, hogy nem minden program támogatja ennek a feladatnak a megoldását. Ha egy Expert Advisor nem jelentkezik be, akkor nem fog részt venni a számításban. Ebben a feladatmegoldásban csak azok az EA-k használhatók, amelyek tartalmazzák a szükséges kódot - amellyel meg tudják változtatni a GV értéket, írni és olvasni tudják ezt a változót.

Itt van egy olyan Expert Advisor (globalvar.mq4), amely a 24. feladat megoldása során demonstrálja a GlobalVariables  használatát:
//--------------------------------------------------------------------
// globalvar.mq4
// The code should be used for educational purpose only.
//--------------------------------------------------------------------
int    Experts;                                // Amount of EAs
double Depo=10000.0,                            // Set deposit
      Persent=30,                              // Set percentage    
      Money;                                  // Desired money
string Quantity="GV_Quantity";                  // GV name
//--------------------------------------------------------------------
int init()                                      // Special funct. init()
  {
  Experts=GlobalVariableGet(Quantity);        // Getting current value
  Experts=Experts+1;                          // Amount of EAs
  GlobalVariableSet(Quantity, Experts);        // New value
  Money=Depo*Persent/100/Experts;                // Money for EAs
  Alert("For EA in window ", Symbol()," allocated ",Money);
  return;                                      // Exit init()
  }
//--------------------------------------------------------------------
int start()                                    // Special funct. start()
  {
  int New_Experts= GlobalVariableGet(Quantity);// New amount of EAs
  if (Experts!=New_Experts)                    // If changed
    {
      Experts=New_Experts;                      // Now current
      Money=Depo*Persent/100/Experts;            // New money value 
      Alert("New value for EA ",Symbol(),": ",Money);
    }
  /*
  ...
  Here the main EA code should be indicated.
  The value of the variable Money is used in it.
  ...
  */
  return;                                      // Exit start()
  }
//--------------------------------------------------------------------
int deinit()                                    // Special funct. deinit()
  {
  if (Experts ==1)                            // If one EA..
      GlobalVariableDel(Quantity);              //..delete GV
  else                                        // Otherwise..
      GlobalVariableSet(Quantity, Experts-1)//..diminish by 1
  Alert("EA detached from window ",Symbol());  // Alert about detachment
  return;                                      // Exit deinit()
  }
//--------------------------------------------------------------------

Ez az EA három különleges függvényt tartalmaz. Röviden: minden különleges függvényt elindít az ügyfélterminál: az init() függvényt amikor az EA-t csatoljuk a charthoz, a deinit()-et mikor az EA-t leválasztjuk az ablakból, a start()-ot akkor amikor a tickek jönnek. A program fejrész tartalmazza a globális változók deklarációját (az ilyen változók hatóköre ez a program).

A pénz elosztása az EA-k között egy változó értékétől függ – ez az egyidejűleg dolgozó EA-k száma. Az a GV, amely az EA-k számát visszatükrözi, ebben a sorban van meghatározva:

string Quantity = "GV_Quantity"; // GV name

Figyelem!

Megjegyzés: A GlobalVariable nevét egyeztetni kell a program létrehozásakor a többi programmal (az egyéb változók neveit a programozó szabadon megválaszthatja).

Elemezzük részletesen, hogy a Quantity változó értéke hogyan befolyásolja a program végrehajtását! Amikor egy EA-t hozzácsatolnak egy ablakhoz be kell jelentenie a létezését, hogy a többi EA a terminálban tudhasson erről. Ennek korán meg kell történnie (lehetőleg az EA csatolásának pillanatában. Ezért a legjobban hely a számára az init() különleges függvény. Ennek a függvénynek az első sorában az EA kéri a Quantity GV változó értékét, és ezt az értéket kapja az Experts változó, erre a célra a GlobalVariableGet()függvényt használjuk:

 Experts = GlobalVariableGet(Quantity); // Getting current value

Most az EA az Experts változó értékét, függetlenül annak értékétől növelni fogja 1-el. Ezzel jelzi az EA, hogy csatolták egy ablakhoz és a terminálban az egyidejűleg működő EA-k száma 1-el nőtt:

 Experts = Experts+1; // Amount of EAs

Az Experts globális változót kényelemesen használhatjuk, de csak ebben a programban. Az értékét nem érik el másik EA-k. A Quantity GV értékének megváltozatására a GlobalVariableSet() függvényt kell használni amellyel beállítjuk a GV új értéket:

 GlobalVariableSet(Quantity, Experts); // New value

Ez azt jelenti, hogy az Experts új értékét adjuk a Quantity GV-nek. Most ez az új GV érték rendelkezésére áll minden programnak, ami a terminálban működik. Azután kiszámolja (a legutóljára csatolt EA) azt az összeget, ami egy kereskedő EA-nak jut és létrehoz egy riasztást (itt riasztást csak azért alkalmazzuk, hogy illusztrálni tudjuk mikor és milyen események történnek, a tényleges programokban a riasztást csak szükség esetén alkalmazzuk).

  Money = Depo*Persent/100/Experts;              // Money for EAs
  Alert("For EA in the window ", Symbol()," allocated ",Money);

Jegyezd meg, az EA-nk csak a csatolt EA-k alapján számította ki a kívánt összeget (önmagát is beleértve). Amikor az init() végrehajtás kész, a vezérlés visszakerül az ügyfélterminálhoz és az EA elkezdésével vár egy új tickre. Amikor egy új tick jön,a terminál el fogja indítani a különleges start() függvényt.

Most a feladatnak azt a részét hajtjuk végre ahol az EA folyamatosan számontartja a csatolt EA-k aktuális mennyiségét. Az Expert Advisorokat csatolhatjuk és eltávolíthatjuk; ennek következtében az egyidejűleg dolgozó EA-k száma változhat. Ettől függően az EA-nak újra kell számolnia azt az összeget, amit a feladat kiírásával összhangban kiutalhat. Tehát az első dolog, hogy mindegyik új ticknél az EA kéri a Quantity GV új értékét:

 int New_Experts= GlobalVariableGet(Quantity);// New amount of EAs

és ha a New_Experts változó új értéke  különbözik az utoljára ismert Experts változótól, az új érték figyelembevételével újraszámoljuk a Money változó aktuális értékét, ezt az összeget kapja az EA, és létre hozzuk a megfelelő riasztást:

  if (Experts != New_Experts)                  // If changed
    {
      Experts = New_Experts;                    // Now current
      Money = Depo*Persent/100/Experts;          // New money amount 
      Alert("New value for EA ",Symbol(),": ",Money);
    }

Ha a New_Experts és Experts változók azonosak, számítást itt nem fojtatjuk az EA-kódjában (az 'if' operátor törzsét nem hajtjuk végre) a Money változó korábban kiszámított értékét használjuk továbbra is. A helyzettől függően minden ticknél vagy az újra kiszámolt Money értéket, vagy az előzőt használjuk.

A 24. feladat korrekt megoldása érdekében mindegyik Expert Advisornak tájékoztatnia kell a többi Expert Advisort arról, ha eltávolították és a működő Expert Advisorok száma csökkent. Azonfelül, ha ez az utolsó EA a GV-t törölni kell. A deinit() végrehajtása jelzi az EA eltávolítását, az ennek megfelelő kódot kell létrehozni ebben a függvényben:

int deinit() // Special funct. deinit()
 {
 if (Experts ==1) // If one EA..
 GlobalVariableDel(Quantity); //..delete GV
 else // Otherwise..
 GlobalVariableSet(Quantity, Experts-1); //..diminish by 1
 Alert("EA detached from window ",Symbol()); // Alert about detachment
 return; // Exit deinit()
 }

A deinit() függvényben minden számítást egy if operátoron belül végünk. Ha az EA-k száma egyenlő 1-gyel, vagyis ez az EA az utolsó, a GV-t töröljük a GlobalVariableDel() függvénnyel, más esetben (mikor az EA-k száma több 1-nél) a Quantity GV változó egy új, 1-el kisebb érték fog kapni a GlobalVariableSet() függvény segítségével. Azok az EA-k, amelyek működésben maradtak, a start() függvényük következő végrehajtása kezdetén észlelni fogják az új Quantity értéket és újraszámolják a Money változó értékét.

Láthatjuk, hogy GlobalVariables értékeit olvashatjuk vagy módosíthatjuk bármelyik EA-ból a megfelelő függvények végrehajtásával. Közvetlen számítások GV értékekkel nem lehetségesek. Ha a GV értékét kell használ valamely kifejezésben, a GV értékét kell adni bármilyen másik változónak és a számításokban ezt a változót kell használni. Ennek megfelelően használjuk a két változót: Experts és New_Experts a következő sorokban:

 Experts = GlobalVariableGet(Quantity); // Getting current value
 int New_Experts= GlobalVariableGet(Quantity);// New amount of EAs

Javaslom a lefordított  globalvar.mq4 EA-t több ablakban elindítani. Az eseményektől függően a megfelelő tájékoztatást láthatjuk az Alert függvény ablakában. Például:


55. ábra. Riasztások az Alert ablakban, egymásután csatoljuk a  globalvar.mq4 EA-t három különböző szimbólumablakhoz.

Van egy opció az ügyfélterminálban, a ”Globális Változók” eszköztár, ahol valós időben láthatunk minden létező Globális Változót és azok értékeit. Ez az eszköztár az ügyfélterminál menüjén keresztül érhető el Eszközök>> Globális Változók vagy (F3 billentyű):


56. ábra. Globális Változók eszköztára mikor a három  globalvar.mq4 fut egyszerre.

Ha az EA-kat eltávolítjuk, akkor az eszköztárból is eltűnik a bejegyzés az ügyfélterminál nyitott globális változóiról.

Hibák a GlobalVariables használata során

Ha a globalvar.mq4 EA-t különböző ablakokban indítjuk el egymás után és nyomon követjük az eseményeket, látni fogjuk, hogy a kód sikeresen működik. Azonban ez csak akkor igaz, ha a szünetek az események között eléggé nagyok. Figyeljük meg az 'if' operátort a deinit()-ben:
 if (Experts ==1) // If one EA..

Ebben az esetben az Experts globális változó értékét elemezzük. Bár ez visszatükrözi a GV értéket, de elavulttá is válhat (emlékezzünk, minden program valós idejű módban működik). Hogy megértsük az okokat lássuk a következő diagramot:



 57. ábra Az EA-t leválasztjuk az EUR/USD ablakról a harmadi tick érkezése előtt.

Az 57. ábrán látható, hogy az események alakulása hogyan érintik Quantity GV értékét. Lássuk, hogyan fog ez az érték változni attól függően, hogy mi történik. Tételezzük fel azt, hogy az EA végrehajtása a t 0 pillanatban kezdődött. Ebben a pillanatban a Quantity GV még nem létezik. A t 0 - t 1 időszakban az EA végrehajtja az init() különleges függvényt és létrehozza a Quantity GV-t, aminek az értéke t 1 időpontban egyenlő 1-gyel. Az EUR/USD következő tickjei elindítják a start() különleges függvényt. A t 0 - t 6 időszakban csak egy EA van az ügyfélterminálban ezért Quantity GV értéke nem változik.

A t 6 időpontban a második EA-t hozzáerősítjük a GBP/USD charthoz. Az init() végrehajtása során a Quantity GV értéke megváltozik és a t 7 pillanatban egyenlő 2-vel. Azután a t 8 pillanatban a harmadik EA-t is csatoljuk az USD/CHF charthoz ezért a t 9 pillanatban a Quantity GV egyenlő 3-mal.

A t 10 időpontban a kereskedő úgy dönt, hogy leválasztja az EA-t az EUR/USD ablakról. Vegyük észre, hogy ennek az EA-nak az Experts változója, a start() legutolsó végrehajtása alatt kapott értékét őrzi, amit a második ticknél a t 4 - t 5 időszakban kapott. A t 10 pillanatban az EUR/USD ablakban működő EA Experts változójának az értéke még mindig egyenlő 1-el. Ezért mikor a deinit() függvényt ez az EA végrehajtja, A Quantity GV-t a következő sorok végrehajtásával törölni fogja:

 if (Experts ==1) // If one EA..
 GlobalVariableDel(Quantity); //..delete GV

Így, bár kettő EA is dolgozik, GlobalVariable-t mégis törlik! Nem nehéz belátni, hogy ez milyen következményekkel jár a csatolt EA-k számításaira. A start() végrehajtásnál, ezek az EA-k azt fogják érzékelni, hogy a New_Experts értéke egyenlő nullával, ezért az Experts változó értékét szintén nullázni fogják. Végül Money értékét nem lehet kiszámolni, mert a képletben, amit számításokra használunk, az Experts van a nevezőben. Így a további számítások az EA-kban hibásak lesznek.

Azonkívül az EA-k a deinit( ) függvények végrehajtásánál (mikor leválasztjuk őket a GBP/USD-ről és USD/CHF-ről) a GV-t megint létre fogják hozni, de a Quantity értéke az első EA leválasztásánál -1, a második leválasztásánál -2 lesz. Mindez a Money változó negatív értékéhez vezet. Ez fontos tény, mert a GV Quantity változó az EA-k bezárásától függetlenül továbbra is megmarad az ügyfélterminálban és a későbbiekben minden EA működésére hatással lesz az értéke.

Egy másik eset is lehetséges. Az 58. ábra azt szemlélteti, hogy a GV értéke hogyan fog változni fog, ha az EA eltávolítása előtt még egy tick jön.


58. ábra. Az EA leválasztása a harmadik tick után az EUR/USD-ablakból.


Az 58. ábrán látható események a t 0 - t 9 időszakban teljesen egybeesnek az 57. ábrán látható eseményekkel. A diagram alapján a t 12 pillanatban egy harmadik EUR/USD tick is jön, ennek következtében a start() függvény végrehajtása alatt az Experts értéke változni fog és egyenlő lesz 3-mal. Ezen EA-nak az EUR/USD chartról történő eltávolítás után, a deinit() végrehajtásnak eredményeképpen az Experts értéke 2 lesz, és a megmaradó EA-k helyesen működnek.

Ezen érvelés alapján azt feltételezhetnénk, hogy a globalvar.mq4 EA-t helytelenül alkottuk. Az algoritmus hibája ebben az esetben az, hogy a tényleges helyzetet elemező Experts változó értéke nem mindig tükrözi vissza a ténylegesen működő EA-k összegét, mert minden esetben használják a deinit() függvényt. Az 58. ábrán leírt esetben a Experts értéke helyes, míg az 57. ábrán levő esetben nem. Tehát az EA végrehajtásának az eredménye véletlen eseményektől függ, a különböző szimbólumok tickjeinek véletlenszerű érkezésétől, amikkel az EA-k dolgoznak.

Ebben az esetben a hibát könnyen meghatározhatjuk. Nekünk egyszerűen az elemzés előtt frissítenünk kell az Experts értékét (az if operátor végrehajtása előtt):

int deinit() // Special funct. deinit()
 {
 Experts = GlobalVariableGet(Quantity); // Getting current value
 if (Experts ==1) // If one EA..
 GlobalVariableDel(Quantity); //..delete GV
 else // Otherwise..
 GlobalVariableSet(Quantity, Experts-1); //..diminish by 1
 Alert("EA detached from window ",Symbol()); // Alert about detachment
 return; // Exit deinit()
 }

Az ilyen algoritmikus hibák veszélyesek, mert nem mindig nyilvánvalóak és nehéz észlelni őket. De ez nem jelenti azt, hogy egy felhasználónak mellőznie kellene a GlobalVariables használatát. Azonban bármilyen program kódjának építései közben számításba kell venni minden eseményt, ami befolyásolhatja a program működését.

A szakmai gyakorlatban a globális változók használata nagy segítséget jelent: például segít tájékozódni egy másik szimbólumon történt kritikus eseményről (egy bizonyos árszint átlépése, letörése, stb.), letilthat egy másik Expert Advisort (a kereskedésre fordítható összeg megosztása céljából), vezetheti a több eszközön történő szinkronizált kereskedelmet. Az ügyfélterminál globális változóját létre tudjuk hozni egy indikátorból is néhány fontos eseményt értékelve; e változó értékét használhatja bármelyik Expert Advisor vagy script.