Egy szokásos program szerkezete
Egy szokásos program lényeges tulajdonsága a szerkezete, ami lehetővé teszi valamennyi felhasználói és egyéb függvény egyszerű használatát. Az egyszerűség kedvéért a felhasználói függvényeket általában ”include” fájlokban (.mqh) hozzuk létre és a Terminal_directory\experts\include mappában tároljuk.
Legtöbbször egy szokásos program tartalmazza mind a három különleges függvényt, amelyek a végrehajtásuk során hívják a szükséges felhasználói függvényeket. A felhasználói függvények a futásuk során hívhatnak egyéb felhasználói függvényeket, mindegyiket a funkcionálisan meghatározott célra.
Egy Expert Advisor a legkülönbözőbb tulajdonságú felhasználói függvényeket tartalmazhatja. Néhány függvénynek például az a feladata, hogy figyelemmel kövesse az eseményeket és megfelelő tájékoztatást adjon, egyéb függvényeket arra használunk, hogy a kereskedelmi kéréseket kialakítsák, a harmadik féle függvényeknek a feladata a különböző számítások elvégzése, kereskedési ismertetőjelek meghatározása, a megbízások költségének a meghatározása, stb. Annak eldöntése, hogy milyen függvényeket használjunk a programban az EA céljától függ és attól, hogy a programozó milyen szolgáltatásokkal szándékozik ellátni a felhasználót. A 155. ábrán láthatjuk, hogy egy szokásos kereskedő EA blokkdiagramja a felhasználói függvények készletére épült.
155. ábra. Egy
szokásos program blokkdiagramja (Expert Advisor).
A diagramban a nyilak mutatják a függvények közti kapcsolatokat. Például, az EA-ban a megbízásokat nyilvántartó függvényt hívjuk az init() és start() különleges függvényekből, és szintén hívhatjuk a program bármelyik másik pontjáról. A diagram jobb szélén a csatlakozó nyilak jelzik, hogy lehetősége van a felhasználói függvényeknek másik felhasználói függvény hívására. Például azt a függvényt, ami a kereskedési ismertetőjeleket határoz meg, nem hívjuk a különleges függvényekből csak a kereskedelmi függvényből. Az adatfüggvényt hívjuk a deinit() és start() különleges függvényekből, és ha szükséges másik függvényekből is, például a hibafeldolgozó függvényből, a kereskedelemi függvényből vagy az eseménykövető függvényből. A változók leírását tartalmazó fájlt nem hívhatjuk függvényekből, mert a kód, amit ez a fájl tartalmaz, nem egy függvényleírás, igy nem hívható és nem végrehajtható. Ez a fájl tartalmazza a globális változók leírását, ezért ez is az EA része. Hogy megértsük egy EA különböző részei közötti kölcsönös kapcsolatot, vizsgáljuk meg az ”include” fájlok létrehozását és használatát.
Az include fájlok használata
Ha egy alkalmazási program sok, különféle programsort tartalmaz, ez a hibakeresésben sokszor nehézséget okoz, a programozónak sokszor kell görgetnie a programszöveget, hogy a kódban a különböző helyszíneken a változtatásokat elvégezze. Ilyen esetben célszerű a programot több részre osztani és mindegyik részt egy különálló include fájlban elhelyezni. Az include fájlok bármilyen, a programban használt kódtöredéket tartalmazhatnak. Mindegyik függvényt, amit a programban használnak általában egy különálló include fájlban alakítanak ki. Ha több függvény logikailag összefügg, egy include fájl több felhasználói függvény leírását is tartalmazhatja.
A Számlainformáció részben találunk egy példát egy védelmi kódra, ami megakadályozza az üzleti programok jogosulatlan használatát. A check.mq4 Expert Advisorban a programkód megfelelő részét a Check() felhasználói függvényben helyeztük el, aminek a leírását közvetlenül tartalmazza az EA forráskódja. Az usualexpert.mq4 EA ezt a függvényt szintén használja. Azonban ebben az esetben a függvényt a Check.mqh fájlban alakítjuk ki.
Check() felhasználói függvény
bool Check()
A függvény visszaküldi aTRUE-t, ha megvannak a program használatának a feltételei. Különben visszaküldi FALSE-t.
A program használható, ha teljesülnek a következő feltételek:
- a programot egy demó számlán használjuk;
- a számlát a SuperBanknál nyitottuk;
- a felhasználó helyesen állította be a Parol külső változó értékét, valódi számla használata esetén.
A Check.mqh include fájl tartalmazza a Check() felhasználói függvény leírását:
//----------------------------------------------------------------------------------
// Check.mqh
// The program is intended to be used as an example in MQL4 Tutorial.
//----------------------------------------------------------------------------- 1 --
// The function checking legality of the program used
// Inputs:
// - global variable 'Parol'
// - local constant "SuperBank"
// Returned values:
// true - if the conditions of use are met
// false - if the conditions of use are violated
//----------------------------------------------------------------------------- 2 --
extern int Parol=12345; // Password to work on a real account
//----------------------------------------------------------------------------- 3 --
bool Check() // Felhasználói függvény
{
if (IsDemo()==true) // Ha ez egy demó számla..
return(true); // .. akkor nincs korlátozás
if (AccountCompany()=="SuperBank") // For corporate clients..
return(true); // ..no password is required
int Key=AccountNumber()*2+1000001; // Calculate the key
if (Parol==Key) // If the password is true, then..
return(true); // ..allow the user to work on a real account
Inform(14); // Message about unauthorized use
return(false); // Exit the user-defined function
}
//----------------------------------------------------------------------------- 4 --
Könnyen észrevehető, hogy az include fájl neve ugyanaz, mint a benne foglalt felhasználói függvényé. Ezt az MQL4 szabályai nem igénylik. Általában nem szükséges, hogy az include fájl neve ugyanaz legyen, mint a benne lévő függvény neve. Ez még nyilvánvalóbbá válik, ha figyelembe vesszük, hogy egy fájl tartalmazhatja több függvény leírását, vagy egy olyan programrészt, ami egyáltalán nem tartalmaz függvényt. Azonban a gyakorlatban az include fájloknak a benne megvalósított függvény nevét adjuk. Ez jelentősen megkönnyíti a programozó munkáját: miközben az állományneveket használja, tudni fogja, hogy milyen függvények vannak a Terminal_directory\experts\include mappában. Azért, hogy alkalmazni tudjuk az include fájlban lévő programrészletet, az #include utasítást kell használnunk.
Az #include utasítás
#include <File name> #include "File name" |
Az #include utasítást a program bármely részén elhelyezhetjük. A preprocesszor fel fogja cserélni az #include <file_name> (vagy #include "file_name") sorokat a hivatkozott fájl tartalmával.
A csúcsos zárójel (kacsacsőr) azt jelenti, hogy az include fájl a Terminal_directory\experts\include rendszeresített könyvtárban van (a forrásszöveg mappáját nem vizsgáljuk). Ha az állománynevet idézőjelek közé zárjuk, akkor az include fájlt abban a mappában keresi a preprocesszor, ahol a program forrásszövege található (a Terminal_directory\experts\include rendszeresített könyvtárat nem vizsgálja).
Lent látható az usualexpert.mq4 Expert Advisor. Minden include fájlt a program fejrészébe helyeztek.//----------------------------------------------------------------------------------------
// usualexpert.mq4
// The code should be used for educational purpose only.
//----------------------------------------------------------------------------------- 1 --
#property copyright "Copyright © Book, 2007"
#property link "http://AutoGraf.dp.ua"
//----------------------------------------------------------------------------------- 2 --
#include <stdlib.mqh>
#include <stderror.mqh>
#include <WinUser32.mqh>
//----------------------------------------------------------------------------------- 3 --
#include <Variables.mqh> // Description of variables
#include <Check.mqh> // Checking legality of programs used
#include <Terminal.mqh> // Order accounting
#include <Events.mqh> // Event tracking function
#include <Inform.mqh> // Data function
#include <Trade.mqh> // Trade function
#include <Open_Ord.mqh> // Opening one order of the preset type
#include <Close_All.mqh> // Closing all orders of the preset type
#include <Tral_Stop.mqh> // StopLoss modification for all orders of the preset type
#include <Lot.mqh> // Calculation of the amount of lots
#include <Criterion.mqh> // Trading criteria
#include <Errors.mqh> // Error processing function
//----------------------------------------------------------------------------------- 4 --
int init() // Special function 'init'
{
Level_old=MarketInfo(Symbol(),MODE_STOPLEVEL );//Min. distance
Terminal(); // Order accounting function
return; // Exit init()
}
//----------------------------------------------------------------------------------- 5 --
int start() // Special function 'start'
{
if(Check()==false) // If the usage conditions..
return; // ..are not met, then exit
PlaySound("tick.wav"); // At every tick
Terminal(); // Order accounting function
Events(); // Information about events
Trade(Criterion()); // Trade function
Inform(0); // To change the color of objects
return; // Exit start()
}
//----------------------------------------------------------------------------------- 6 --
int deinit() // Special function deinit()
{
Inform(-1); // To delete objects
return; // Exit deinit()
}
//----------------------------------------------------------------------------------- 7 --
A 2-3 blokkban találhatók a program stdlib.mqh, stderror.mqh és WinUser32.mqh standard fájljai használatára utaló #include utasítások. Nem mindig szükséges használni ezeket a fájlokat a programban. Például az stderror.mqh tartalmazza a hibakódok definícióját. Ha hibafeldolgozás nincs a programban (és ezeket az állandókat nem használjuk), nem szükséges tartalmaznia ezt a fájlt a forrásszövegnek. Ugyanakkor a szokásos programok általában tartalmazzák ezeket a fájlokat.
A 3-4 blokkban, a program tartalmaz néhány olyan fájlt melyekben a felhasználói függvények leírása található. Használatukat az #include utasítás teszi lehetővé: az
#include <Check.mqh> // Checking legality of programs used
program forrásszövege tartalmazza a Check() felhasználói függvényt. A programozó az EA (ebben az esetben az usualexpert.mq4) forráskódját a fenti formátumban látja. Azonban a program forrásszövege a fordítás során úgy módosul, hogy mindegyik sort, ami # include utasítást tartalmaz felvált a programkódban az utasításban szereplő fájl. Így, az .ex4 végrehajtható állomány az Expert Advisor teljes kódját tartalmazza, amiben mindegyik #include<fájlnév> (vagy #include "fájlnév") sort a fordító (compiler) lecserélt a megfelelő kódtöredékre.
A példa egy olyan fájl, ami egy olyan programtöredéket tartalmaz, ami nem függvényleírás, ez a fájl a Variables.mqh. Ezt a fájlt a programszövegbe a következő sorral illesztjük be:#include <Variables.mqh> // Description of variables
ez a fájl tartalmazza azoknak a globális változóknak a leírását, amiket a különböző felhasználói függvények használnak.
//----------------------------------------------------------------------------
// Variables.mqh
// The code should be used for educational purpose only.
//----------------------------------------------------------------------- 1 --
// Description of global variables
extern double Lots = 0.0;// Amount of lots
extern int Percent = 0; // Allocated funds percentage
extern int StopLoss =100; // StopLoss for new orders (in points)
extern int TakeProfit =40; // TakeProfit for new orders (in points)
extern int TralingStop=100; // TralingStop for market orders (in points)
//----------------------------------------------------------------------- 2 --
int
Level_new, // New value of the minimum distance
Level_old, // Previous value of the minimum distance
Mas_Tip[6]; // Order type array
// [] order type: 0=B,1=S,2=BL,3=SL,4=BS,5=SS
//----------------------------------------------------------------------- 3 --
double
Lots_New, // Amount of lots for new orders
Mas_Ord_New[31][9], // Current order array ..
Mas_Ord_Old[31][9]; // .. old order array
// 1st index = order number in the list
// [][0] cannot be detected
// [][1] order open price (abs. price value)
// [][2] StopLoss of the order (abs. price value)
// [][3] TakeProfit of the order (abs. price value)
// [][4] order number
// [][5] order volume (abs. price value)
// [][6] order type 0=B,1=S,2=BL,3=SL,4=BS,5=SS
// [][7] Order magic number
// [][8] 0/1 the fact of availability of comments
//----------------------------------------------------------------------- 4 --
Az MQL4 szabályai szerint, minden változót (beleértve a globális változókat is) az erre a változóra történő első utalás előtt deklarálni kell. Ezért a Variables.mqh fájl bele kell illesztenünk a programba, mégpedig az olyan függvények include fájljai előtt, amik használják azon változók értékeit, amelyeket ebben a fájlban leírtunk. Ezért minden globális változót ebbe a fájlba helyeztünk el.
Néhány (ritka) esetben, műszakilag lehetséges deklarálni egy globális változót az olyan include fájlban is ami olyan függvényleírást tartalmaz, amelyben ennek a változónak az értékét először használjuk a programban. Ilyen esetben az include fájlok megfelelő sorrendjét be kell tartani a programban. Vagyis annak a programsornak, amely az arra a fájlra vonatkozó #include utasítást tartalmazza, ahol a globális változók leírása szerepel, meg kell előznie minden olyan programsort ahol ezek a globális változók szerepelnek.
Sok esetben még technikailag is lehetetlen ezt megvalósítani. Például ha van két include fájl és mindkettő használ két globális változót, az egyiket az egyik fájlban írjuk le, a másikat pedig a másik fájlban. Ha egy ilyen programot akarunk lefordítani, akkor hibajelzést fogunk kapni, mert azelőtt próbálunk egy változót használni, mielőtt azt deklaráltuk a programban. Ez az oka annak, hogy egy szokásos programban az a gyakorlat, hogy kivételek nélkül minden globális változót egy fájlban írunk le, amit még azelőtt beillesztünk a programba, mielőtt a többi, a felhasználói függvények leírását tartalmazó fájlokat beillesztenénk.
Az 1-2 blokkban a Variables.mqh include fájl tartalmazza minden külső változó leírását, az új megbízások lot összegét, a felhasználható szabad margin százalékát, a TakeProfit és StopLoss kért értékét, valamint a TralingStop távolságát. A 2-4 blokkokban az egyéb globális változókat hozzuk létre, amelyek a későbbiekben tárgyalandó felhasználói függvényekhez tartoznak. Az ebben a fejezetben említett include fájlokban lévő felhasználói függvények leírását a következő fejezetekben ismertetjük.