MQL4 könyv   Változók   A változók típusai

A változók típusai

Egy MQL4 alkalmazási program tartalmazhat több tíz vagy több száz változót. Mindegyik változó egy nagyon fontos tulajdonsága az a lehetőség hogy az értékét a program felhasználja. Ennek a lehetőségnek a korlátozása határozza meg a változó hatókörét.

A változó hatóköre a program azon része, ahonnan a változó értéke elérhető. Minden változónak van hatóköre. Hatókörük szerint a változóknak az MQL4-ben két fajtája van: helyi és globális.

Helyi (lokális) és globális változók

Lokális változó: a változót egy függvényen belül deklarálták. A lokális változók hatóköre az a függvénytörzs, amiben a változót deklarálták. A lokális változót lehet inicializálni egy állandó vagy egy kifejezés megfelelő típusával.

A globális változó egy olyan változó, amit mindenen függvényen kívül deklaráltak. A globális változók hatóköre az egész program. Egy globális változót csak egy hasonló típusú állandóval lehet inicializálni (kifejezéssel nem). A globális változókat csak egyszer inicializáljuk a különleges függvények végrehajtása előtt.

Ha a program vezérlése egy bizonyos függvényben van, annak a lokális változónak az értéke, amit egy másik függvényben deklaráltak, nem elérhető. Bármilyen globális változó értéke elérhető bármilyen különleges és felhasználói függvényből. Nézzünk egy egyszerű példát!

Feladat

22. feladat Hozz létre egy olyan programot, ami tickeket számol!

A 22. feladat megoldási algoritmusa, ami egy globális változót használ  (countticks.mq4):

//--------------------------------------------------------------------
// countticks.mq4
// The code should be used for educational purpose only.
//--------------------------------------------------------------------
int Tick; // Global variable
//--------------------------------------------------------------------
int start() // Special function start()
 {
 Tick++; // Tick counter
 Comment("Received: tick No ",Tick); // Alert that contains number
 return; // start() exit operator
 }
//--------------------------------------------------------------------

Ebben a programban csak egy globális változót használunk: Tick. Ez azért globális, mert azt start() leírásán kívül deklaráljuk. Ez azt jelenti, hogy a változó meg fogja őrizni az értékét tickről tickre. Lássuk a programvégrehajtás részleteit!

A Különleges Függvények részben megismertük azokat a feltételeket, amelyek a különleges függvényeket elindítják. Röviden: Expert Advisorban a start() függvényt elindítja az ügyfélterminál, amikor egy új tick jön. Az Expert Advisornak a charthoz való csatolásának a pillanatánál a következő események történnek:

1. A Tick globális változó deklarációja. Ezt a változót nem inicializálja egy állandó, az értéke ebben az esetben egyenlő nullával.

2. A vezérlést magánál tartja az ügyfélterminál, amíg egy új tick nem jön.

3. A ticket megkaptuk. A vezérlés átkerül a különleges start() függvénybe.

3.1. A start() függvény törzsében a vezérlés átkerül az első operátorhoz:

 Tick++; // Tick counter

Az operátor végrehajtásnak eredményeképpen Tick értéke növekszik 1-el (egy lesz).

3.2. A vezérlést megkapja a következő operátor:

 Comment("received: tick No ",Tick); // Alert that contains number

A Comment() beépített függvény végrehajtása egy feliratot jelenít meg:

Received: tick No 1

3.3. A vezérlés tovább kerül a következő operátorra:

 return; // start() exit operator

A return végrehajtása következtében a start() befejezi a műveletet, és a vezérlés vissza tér az ügyfélterminálhoz. A globális változó továbbra is létezik, megtartj aaz értékét ami egyenlő 1-gyel.

A további műveletek a 2. ponttól fognak ismétlődni. Ismét a Tick változót használjuk a számításokban, de a második ticknél, vagyis a start() kezdődő pillanatban a Tick változó értéke egyenlő 1-el ezért az operátor újbóli végrehajtásának az eredménye:

 Tick++; // Tick counter

a Tick változó egy új értéke lesz, - azt növelni fogják 1-el és most egyenlő lesz 2-vel, a Comment() függvény végrehajtása az új értéket fogja megjeleníteni:

Received: tick No 2

Így Tick értéke növekedni fog 1-el a különleges start() függvény mindegyik indításánál, vagyis mindegyik ticknél. Az ilyen feladat megoldása csak úgy lehetséges, ha olyan változót használunk, ami megőrzi az értékét miután kiléptünk egy függvényből, (ebben az esetben egy globális változót használtunk). Értelmetlen erre a célra lokális változót használni: egy lokális változó elveszti az értékét, ha a függvény, amiben deklarálták, befejezi a műveletét.

Ezt könnyen beláthatjuk, ha elindítunk egy Expert Advisort, amiben Ticket helyi változó (a program egy algoritmikus hibát tartalmaz):

int start() // Special function start()
{
int Tick; // Local variable
Tick++; // Tick counter
Comment("Received: tick No ",Tick);// Alert that contains number
return; // start() exit operator
}

A szintaxisa alapján nincsenek a kódban hibák. Ezt a programot sikeresen lefordíthatjuk és elindíthatjuk. Működni fog, de az eredmény minden alkalommal ugyanaz lesz:

received tick No 1

Ez természetes, mert a Tick változót a különleges start() függvény mindegyik indításánál inicializálni fogjuk nulla értékre. A Tick változó minden további, egyel történő növekedése ellenére: a kijelzett érték mindig egyenlő lesz 1-gyel.

Statikus változók

A fizikai szinten a lokális változókat a hozzájuk tartozó függvények ideiglenes memóriarekeszeiben tároljuk. Van mód arra, hogy egy változót, amit egy függvényen belül deklaráltak az állandó programmemóriában lokalizáljunk, - a deklaráció során módosítani kell a változó típusát a 'static' szó beszúrásával:

 static int Number; // Static variable of integer type

Lent látható a 22. feladat megoldása statikus változó használatával ( staticvar.mq4 Expert Advisor ):

//--------------------------------------------------------------------
// staticvar.mq4
// The code should be used for educational purpose only.
//--------------------------------------------------------------------
int start() // Special function start()
 {
 static int Tick; // Static local variable
 Tick++; // Tick counter
 Comment("Received: tick No ",Tick); // Alert that contains number
 return; // start() exit operator
 }
//--------------------------------------------------------------------

A statikus változókat egyszer inicializáljuk. Mindegyik statikus változót csak egy megfelelő típusú állandó inicializálhatja(ebben különbözik egy egyszerű lokális változótól, mert azt inicializálhatja bármilyen kifejezés is). Ha inicializálása nincs, egy statikus változó kezdeti értéke nulla. A statikus változókat egy állandó memóriarészben raktározzák el, az értéke nem veszik el, ha kilépünk a függvényből. Azonban a statikus változóknak vannak olyan korlátozásaik, amelyek a lokális változókra jellemzőek, - a statikus változó hatásköre az a függvény, amiben a változót deklarálják, ebben különböznek azoktól a globális változóktól, amelyeknek az értékei elérhetőek az egész programból. Figyeld meg, hogy a countticks.mq4 és a staticvar.mq4 programok azonos eredményt adnak.

Minden tömb eredendően statikus, vagyis ezek statikus típusúak, még akkor is, ha azt nyíltan nem jelezzük ( lásd: Tömbök).

External (külső) változók

External (külső) változó egy olyan változó, ami a program tulajdonságok ablakából elérhető. Egy külső változót minden függvényen kívül deklarálunk és hatókörük globális - az egész programból elérhetők. Amikor deklarálunk egy külső változót, ezt az érték típusa előtt az 'extern' szóval kell jelezni:

 extern int Number; // External variable of integer type

A külső változókat a program fejrészében deklaráljuk, mégpedig minden olyan függvény leírása előtt, amely függvény használja az adott külső változót. A külső változók használata nagyon kényelmes, erre időről időre szükség van, ha egy programot különböző változó értékekkel kell elindítanunk.

Feladat

23. feladat: Hozzunk létre egy programot, amiben a következő feltételeket teljesülnek: ha egy ár elért egy bizonyos szintet (Level) és visszament e szint alá n ponttal, ezt a tényt jelenteni kell a kereskedőnek.

Nyilvánvaló ebben a feladatban szükség van arra, hogy a beállításokat meg tudjuk változtatni, mert a mai árak különböznek a tegnapiaktól; és a holnapiak különbözni fognak a maiaktól. A változó külső beállításának opcióját az externvar.mq4 Expert Advisorban alkalmazzuk:

//--------------------------------------------------------------------
// externvar.mq4
// The code should be used for educational purpose only.
//--------------------------------------------------------------------
extern double Level = 1.2500; // External variable
extern int n = 5; // External variable
 bool Fact_1 = false; // Global variable
 bool Fact_2 = false; // Global variable
//--------------------------------------------------------------------
int start() // Special function start()
 {
 double Price = Bid; // Local variable
 if (Fact_2==true) // If there was an Alert..
 return; //..exit
 
 if (NormalizeDouble(Price,Digits) >= NormalizeDouble(Level,Digits))
 Fact_1 = true; // Event 1 happened
 
 if (Fact_1 == true && NormalizeDouble(Price,Digits)<=
 NormalizeDouble(Level-n*Point,Digits)) 
 My_Alert(); // User-defined function call
 
 return; // Exit start()
 }
//--------------------------------------------------------------------
void My_Alert() // User-defined function
 {
 Alert("Conditions implemented"); // Alert
 Fact_2 = true; // Event 2 happened
 return; // Exit user-defined function
 }
//--------------------------------------------------------------------

Ebben a programban a következő sorokban külső változókat helyeztünk el:

extern double Level = 1.2500; // External variable
extern int n = 1; // External variable

A külső változók értékei elérhetők a program paraméter ablakából. Ezeknek a változóknak az előnye az, hogy bármikor meg tudjuk ezeket változtatni - a szimbólum ablakhoz csatolt program végrehajtása alatt is.


54. ábra. Program tulajdonságok ablak; itt változtathatjuk meg a külső változók értékeit.

Amikor csatoljuk a programot egy szimbólumablakhoz, a programkódban lévő külső változók értékeit a program paraméter ablakában fogjuk látni. A felhasználó meg tudja változtatni ezeket az értékeket. Amikor a felhasználó az OK-ra kattint, a programot el fogja indítani az ügyfélterminál. A külső változók értékei azok az értékek lesznek, amelyeket a felhasználó a paraméterablakban lát. A futása alatt ezeket az értékeket megváltoztathatja a végrehajtott program.

Ha a felhasználónak a program futása alatt meg kell változtatnia a külső változók értékeit, a paraméterablakot ki kell nyitni és változtatásokat el kell végezni. Figyelembe kell venni, hogy a program tulajdonságok ablakot csak abban az időszakban lehet kinyitni mikor a program (Expert Advisor vagy indikátor) egy új tickre várakozik, vagyis semelyik különleges függvény nem fut. A program végrehajtási időszak alatt ezt az eszköztárt nem nyithatjuk ki. Ezért ha egy programot úgy írnak, hogy a végrehajtása túl hosszú (több másodperc vagy tíz másodpercek), a felhasználó nehézségekkel nézhet szembe, amik megpróbál hozzáférni a paraméter ablakhoz. A scriptek külső változóinak az értékei csak akkor elérhetőek amikor a programot csatoljuk egy charthoz, azonban nem tudjuk megváltoztatni őket a script végrehajtása alatt. Ha a paraméter ablak nyitva van, az Expert Advisor nem dolgozik, a vezérlést az ügyfélterminál magánál tartja, és nem adja át a különleges függvényeket tartalmazó programba.

Figyelem!

Jegyezd meg, amikor egy EA tulajdonságok ablak nyitva van és a felhasználó a külső változók értékeit kezeli, az EA (vagy indikátor) nem dolgozik. A külső változók értékeinek beállítása után és az OK-ra kattintva a felhasználó újra lefuttatja a programot.

A tulajdonságok ablak bezárása után ügyfélterminál egymás után elkezdi a különleges függvények végrehajtását, először a deinit(), azután az init() függvény, végül mikor egy új tick jön – a start(). A deinit() végrehajtásánál, amikor befejezünk egy programot, a külső változók értékei az előző munkamenetből származnak, azok elérhetők amikor az EA beállítási ablakot kinyitjuk. Az init() végrehajtása előtt a külső változók új értékeket kaphatnak és az init() végrehajtás azokkal az új külső változó értékekkel történik, amelyeket beállított a felhasználó. Így a külső változók új értékei az új munkamenet kezdetétől (init - start - deinit) válnak érvényessé, az Expert Advisor új munkamenete az init() végrehajtásával kezdődik.

Az a tény, hogy kinyitottunk egy beállítási ablakot, nem befolyásolja a globális változók értékeit. Az alatt az idő alatt, amikor az ablak nyitva van, és miután az ablakot bezártuk, a globális változók megőrzik azokat az értékeiket, amik a beállítási ablak kinyitásakor érvényesek voltak.

Az externvar.mq4 programban egy helyi és két globális változót használunk.
 bool Fact_1 = false; // Global variable
 bool Fact_2 = false; // Global variable
 double Price = Bid; // Local variable

A problémamegoldás algoritmusa így néz ki. Két eseményt azonosítunk: az első a Level elérése, és a második, a figyelmeztetés (Level-nél n ponttal alacsonyabb szintre történő visszaesés). Ezeket az eseményeket Fact_1 és Fact_2 változók értékeiben jelenítjük meg: ha az esemény nem történt meg, a változó értéke false (hamis), minden más esetben true (igaz).A következő sorokban:

 if (NormalizeDouble(Price,Digits) >= NormalizeDouble(Level,Digits))
 Fact_1 = true; // Event 1 happened

azt a tényt, hogy az első esemény megtörtént, megállapítottuk. A NormalizeDouble() egy beépített függvény, ami lehetővé teszi, hogy a változók értékeivel meghatározott pontossággal végezzük a számításokat, (a szimbólum árának pontossága). Ha az ár egyenlő vagy magasabb a jelezett szintnél az első feltétel teljesül és a Fact_1 globális változó true (igaz) értéket kap. A program úgy van felépítve, hogy ha Fact_1 egyszer a true értéket kapja, azt soha ne változtassa meg hamissá (false) - nincs az ezzel kapcsolatos kód a programban.

A következő sorokban:
 if (Fact_1 == true && NormalizeDouble(Price,Digits)<=
 NormalizeDouble(Level-n*Point,Digits)) 
 My_Alert(); // User-defined function call

az üzenet megjelenítése van kódolva. Ha az első feltétel teljesül és az ár n pont esett (annyit vagy többet) a jelezett szintről egy üzenetet fog megjeleníteni a My_Alert() felhasználói függvény. A felhasználói függvényben az üzenet megjelenítése után, a Fact_2 változó true értéket kap. Majd a felhasználói függvény és ezután a különleges start() függvény is véget ér.

A miután a Fact_2 változó a true értéket kapja, a program végleg be fogja fejezni a munkáját, az egyszer már bemutatott üzenetet nem fogja megismételni ez alatt a munkamenet alatt mert:

 if (Fact_2==true) // If there was an Alert..
 return; //..exit

Nagy jelentősége van ebben a programban annak a ténynek, hogy a globális változók értékeit bárhonnan megváltoztathatjuk, (a különleges és a felhasználói függvényekből egyaránt) és az értékük megmarad a programoperáció egész időszaka alatt, a tickek közti szünetekben, a külső változók módosítása után és az idősíkok váltása után is.

Általában a globális változók értékeit bármelyik különleges függvényből megváltoztathatjuk. Ezért kell rendkívül figyelmesnek lenni, az olyan operátorokkal, amelyek megváltoztathatják a globális változók értékeit az init()-ben és a deinit()-ben. Például ha lenullázzuk egy globális változó értékét az init() függvényben, a start() első végrehajtásánál ennek a változónak az értéke egyenlő lesz nullával, tehát azok az értékek, amit az előző start() végrehajtás alatt megszereztek ezek a változók elvesznek (például az extern változók módosítása után).