Műveletek a chartokkal
A gyakorlatban egy kereskedő általában egy szimbólumablakban több segédablakot is kinyit, ahol indikátorokat helyez el. Korlátozások nincsenek az indikátorok számában, őket bármilyen sorrendben csatolhatjuk. Egy szimbólumablakban levő segédablakok száma sem korlátozott. Mindegyik segédablaknak van száma. A fő ablak száma, ami az árdiagramot tartalmazza és mindig elérhető: 0. Mindegyik indikátor segédablaknak szintén van egy száma. A segédablakokat egyszerűen fölülről lefelé számozzuk: az fő ablak alatti indikátor segédablak száma 1, az alatta lévőé 2, a következőé 3, stb.
140.
ábra a segédablakok elhelyezkedése a
szimbólum ablakban.
A segédablakok számát könnyen meghatározhatjuk a következő függvénnyel:
int WindowsTotal()
A függvény visszaküldi az indikátor segédablakok összegét a főablakot is beleértve. A legnagyobb sorszámú (a legalsó) segédablak sorszám 1-el kisebb a szimbólumablakban lévő segédablakok összegénél (a fő ablakot is beleértve, aminek a sorsszáma 0). Ha a 140. ábra esetében valamelyik alkalmazásból végrehajtjuk WindowsTotal() függvényt, a visszaadott érték egyenlő lesz 3-mal, míg a legnagyobb sorszámú (a legalsó) segédablak sorszáma 2 lesz.
A fent ismertetett számozási sorrend megmarad, ha egy új indikátor segédablakot nyitunk vagy egy létező segédablakot törlünk a szimbólumablakból. Ha hozzáadunk egy új segédablakot az minden más segédablak alatt fog megjelenni és sorszáma 1-el több a fölötte lévő utolsó ablak sorszámánál. Ha törölünk egy segédablakot a szimbólumablakból, minden ez alatti segédablak automatikusan újra fog számozódni - mindegyikük száma 1-el kisebb lesz.
Az MQL4-ben lehetséges grafikus objektumokat létrehozni (és tulajdonságaikat megváltoztatni) bármelyik létező segédablakban. Az ObjectCreate() függvény 'window' paramétere lehetőséget nyújt a szimbólumablak azon segédablakának a meghatározására ahová az objektumot el akarjuk helyezni. A segédablak sorszámát meghatározhatjuk a következő függvénnyel:int WindowFind(string name)
A függvény visszaküldi annak a segédablaknak a számát, ahol a 'name' paraméterben megadott indikátort megtalálta. Ha nem talált ilyen ablakot, akkor -1-et küld vissza. Az egyéni indikátor az init() futtása alatt saját magát nem találja meg (0-t fog visszaküldeni a WindowFind()).
Paraméterek:
name - az indikátor rövid neve.
Egy szimbólumablakban levő segédablakok száma bármelyik pillanatban változhat, ha a felhasználó töröl egy indikátort. Ezért egy olyan alkalmazás algoritmusának, ami támogatja a grafikus objektumok ellenőrzését, folytonosan követnie kell az ablakok számát, amikben az indikátorokat futtatjuk.
Feladat
34. feladat: Grafikus objektumok segítségével mutass be üzeneteket a két indikátor állapotáról. Ha a megfelelő indikátort csatoljuk a szimbólumablakhoz, az üzenet jelenjen meg az indikátorablakkal. Egyébként pedig a fő ablakban.
A feladat megoldásához válasszunk az RSI és Momentum indikátorokat. Az Expert Advisor általános algoritmusát ennek megfelelően építjük fel. Az init() függvényben megadjuk azokat a szövegeket, amelyeket majd az indikátoroktól függően fogunk látni a képernyőn, ezeket a számításokat csak egyszer hajtjuk végre a programban. A start() függvényben neked kell kiválasztanod az indikátor üzenetet, meg határozni a segédablakok elérhetőségét és a számát, azután a helyzetnek megfelelően meg jeleníteni a megfelelő üzenetet a megfelelő segédablakban. A deinit() függvény végrehajtásakor törölni kell minden grafikus objektumot, amit a program létrehozott. Lent látható a charts.mq4 EA, amely vezérli a grafikus objektumokat a szimbólumablakban és a segédablakban.
//-----------------------------------------------------------------------------------
// charts.mq4
// The code should be used for educational purpose only.
//------------------------------------------------------------------------------ 1 --
int Win_Mom_old=0, // Old number of subwindow Moment.
Win_RSI_old=0; // Old number of subwindow RSI
color Color[5]; // Declaration of the color array
string Text[5]; // Declaration of the string array
//------------------------------------------------------------------------------ 2 --
int init() // Special function init()
{
Win_RSI_old=0; // Technical moment
Win_Mom_old=0; // Technical moment
Text[0]= "RSI(14) is below 30. Buy"; // Texts for situations RSI
Text[1]= "RSI(14) is above 70. Sell"; // Texts for situations RSI
Text[2]= "RSI(14) is between 30 and 70"; // Texts for situations RSI
Text[3]= "Momentum(14) is growing"; // Texts for situations Momentum
Text[4]= "Momentum(14) is sinking"; // Texts for situations Momentum
Color[0]= DeepSkyBlue; // Object color for ..
Color[1]= LightPink; // .. different situations ..
Color[2]= Orange; // .. of the indicator RSI
Color[3]= Color[0]; // The same colors for Momentum
Color[4]= Color[1]; // The same colors for Momentum
Create_RSI(0); // Creation of the first object
Create_Mom(0); // Creation of the second object
Main(); // Call to user-defined function
return; // Exit init()
}
//------------------------------------------------------------------------------ 3 --
int start() // Special function 'start'
{
Main(); // Call to the user-defined function
return; // Exit start()
}
//------------------------------------------------------------------------------ 4 --
int deinit() // Special function deinit()
{
ObjectDelete("Obj_RSI"); // Deletion of the object
ObjectDelete("Obj_Mom"); // Deletion of the object
return; // Exit deinit()
}
//------------------------------------------------------------------------------ 5 --
int Main() // User-defined function
{
int // Integer variables
Win_RSI_new=0, // New number of the subwindow RSI
Win_Mom_new=0, // New number of the subwindow Moment.
Ind_RSI, Ind_Mom; // Indexes for situations
double // Real variables
RSI, // Value of RSI on bar 0
Mom_0, Mom_1; // Value of Mom. on bars 0 and 1
//------------------------------------------------------------------------------ 6 --
RSI=iRSI(NULL,0,14,PRICE_CLOSE,0); // RSI(14) on zero bar
Ind_RSI=2; // RSI between levels 30 and 70
if(RSI < 30)Ind_RSI=0; // RSI at the bottom. To buy
if(RSI > 70)Ind_RSI=1; // RSI on the top. To sell
//------------------------------------------------------------------------------ 7 --
Win_RSI_new=WindowFind("RSI(14)"); // Window number of indicator RSI
if(Win_RSI_new==-1) Win_RSI_new=0; // If there is no ind., then the main window
if(Win_RSI_new!=Win_RSI_old) // Deleted or placed ..
{ // .. window of indicator RSI
ObjectDelete("Obj_RSI"); // Deletion of the object
Create_RSI(Win_RSI_new); // Create an object in the desired window
Win_RSI_old=Win_RSI_new; // Remember this window
} // Change the textual description:
ObjectSetText("Obj_RSI",Text[Ind_RSI],10,"Arial",Color[Ind_RSI]);
//------------------------------------------------------------------------------ 8 --
Mom_0=iMomentum(NULL,0,14,PRICE_CLOSE,0); // Value on zero bar
Mom_1=iMomentum(NULL,0,14,PRICE_CLOSE,1); // Value on the preceding bar
if(Mom_0 >=Mom_1)Ind_Mom=3; // Indicator line goes up
if(Mom_0 < Mom_1)Ind_Mom=4; // Indicator line goes down
//------------------------------------------------------------------------------ 9 --
Win_Mom_new=WindowFind("Momentum(14)"); // Window number of indicator Momen
if(Win_Mom_new==-1) Win_Mom_new=0; // If there is no ind., then the main window
if(Win_Mom_new!=Win_Mom_old) // Deleted or placed ..
{ // .. the window of Momentum indicator
ObjectDelete("Obj_Mom"); // Deletion of the object
Create_Mom(Win_Mom_new); // Create an object in the desired window
Win_Mom_old=Win_Mom_new; // Remember this window
} // Change the textual description:
ObjectSetText("Obj_Mom",Text[Ind_Mom],10,"Arial",Color[Ind_Mom]);
//----------------------------------------------------------------------------- 10 --
WindowRedraw(); // Redrawing the image
return; // Exit the user-defined function
}
//----------------------------------------------------------------------------- 11 --
int Create_RSI(int Win) // User-defined function
{ // ..of creation of an object
ObjectCreate("Obj_RSI",OBJ_LABEL, Win, 0,0); // Creation of an object
ObjectSet("Obj_RSI", OBJPROP_CORNER, 0); // Anchoring to an angle
ObjectSet("Obj_RSI", OBJPROP_XDISTANCE, 3); // Coordinate X
if (Win==0)
ObjectSet("Obj_RSI",OBJPROP_YDISTANCE,20);// Coordinate Y
else
ObjectSet("Obj_RSI",OBJPROP_YDISTANCE,15);// Coordinate Y
return; // Exit the user-defined function
}
//----------------------------------------------------------------------------- 12 --
int Create_Mom(int Win) // User-defined function
{ // ..creating an object
ObjectCreate("Obj_Mom",OBJ_LABEL, Win, 0,0); // Creation of an object
ObjectSet("Obj_Mom", OBJPROP_CORNER, 0); // Anchoring to an angle
ObjectSet("Obj_Mom", OBJPROP_XDISTANCE, 3); // Coordinate X
if (Win==0)
ObjectSet("Obj_Mom",OBJPROP_YDISTANCE, 5);// Coordinate Y
else
ObjectSet("Obj_Mom",OBJPROP_YDISTANCE,15);// Coordinate Y
return; // Exit the user-defined function
}
//----------------------------------------------------------------------------- 13 --
Mielőtt a fenti kódot részletesen megvizsgálnánk, tekintsük át annak néhány jellemzőjét. Ha egy grafikus objektumot egyszer létrehoztunk (ebben az esetben a szövegeket) úgy tűnik, hogy az folyamatosan jelen van a képernyőn. A látható szövegről azt hihetnénk, hogy az pontosan visszatükrözi a jelenlegi helyzetet. A szöveg tartalmát meg kell változtatni a start() függvény minden végrehajtásánál minden ticknél. Azonban, amikor a különböző időkeretek között kapcsolgatjuk az ablakot, ahová az EA-t csatoltuk, a program végrehajtja a következő lépéseket: deinit(), init(), (várakozás a következő tickre), és start(). A start() legelső végrehajtásakor létrehozott objektum minden alkalommal, amikor egy másik időkeretbe kapcsolunk, a következő tick megérkezéséig el fog tűnni a képernyőről. Ez különösen akkor nagyon kellemetlen, ha gyakran kapcsolgatunk az időkeretek között.
Egy megfelelően felépített programban a szükséges üzeneteket a képernyőn abban a pillanatban megjelenítjük, ahogy a programot a szimbólumablakhoz csatoltuk, vagy az időkeretet váltunk (nem várunk vele az új tick érkezésére). Ezért a szükséges kódrészeket végrehajtjuk minden ticknél a start() különleges függvény indításánál, és az init() különleges függvény végrehajtásakor is. Azért hogy ne kelljen megismételni ugyanazt a kódot mindkét különleges függvényben, a kódot különálló felhasználói függvénybe írjuk. Ezért tartalmazza az EA a Main() felhasználói függvényt. Ezt a függvényt hívjuk az inicializáláskor (2-3 blokk) és az EA további működése során minden ticknél (3-4 blokk).
A programban (11-13 blokk), van még két további felhasználói függvény - Create_RSI() és Create_Mom(), melyek feladata az objektumok létrehozása és tulajdonságaik módosítása. Az init() függvény végrehajtásánál a szükséges objektumokat ezen függvények segítségével létrehozzuk. A Main() függvény hívása következtében létrejönnek az objektumok (a megfelelő színű szövegek megjelennek a kívánt ablakban).
Vizsgáljuk meg a Main() függvényt (5-11 blokk) alaposan. A 6-7 blokkban az RSI indikátor értékét számoljuk ki. Attól függően, hogy az indikátor értéke 70 fölött, 30 alatt, vagy a két érték közötti tartományon belül van, az Ind_RSI változó különböző értéket fog kapni. Ezt az értéket tömbindexként fogjuk használni a Color[] és Text[] tömbökhöz ( 7-8 blokk) és ezzel megváltoztatjuk az Obj_RSI grafikus objektum (a felirat) tulajdonságait.
7-8.blokk: Meghatározzuk, hogy melyik ablakban helyezkedik el az RSI indikátor:
Win_RSI_new = WindowFind("RSI(14)");// Window number of indicator RSI
Az RSI(14) string értéket átadott paraméterként használjuk. Ez annak az indikátornak a rövid neve, aminek a helyét észlelni kell. Ebben az esetben az összes karakter, köztük a zárójelek és számjegyek alkotja a nevet. Ez azért szükséges, mert ugyanazon indikátor, különböző paraméterekkel lehet különböző ablakokhoz csatolva például: RSI(14), RSI(21) és RSI(34). Mindegyik segédablaknak, ahová ezeket az indikátorokat csatoltuk van saját száma. A könnyebb azoníthatóság érdekében kaptak a technikai indikátorok rövid nevet. A technikai indikátorok rövid neve látható a segédablakában a bal felső sarokban (egy egyéni indikátor rövid nevét létrehozhatja a programozó, ha használja az IndicatorShortName() függvényt).
Ha a keresett indikátor nincs a szimbólumablakba, a Win_RSI_new változó (a segédablak száma ahol az üzenetet be kellene mutatni) -1 lesz, vagyis nincs ilyen ablak. Ebben az esetben a program a grafikus objektumot (az üzenetet) a 0 sorszámú ablakban jeleníti meg, vagyis a főablakban:
if(Win_RSI_new == -1) Win_RSI_new=0;// If there is no ind., then the main window
A program működése alatt a felhasználó törölhet egy létező indikátort, vagy helyezhet el újakat. Hogy a program figyelemmel tudja követni a változásokat, használjuk a Win_RSI_old és Win_Mom_old globális változókat. Mindkét változó értéke annak a segédablaknak a száma, ahol az objektumot korábban létrehoztuk. Ha a Win_RSI_new és Win_RSI_old változók értékei nem esnek egybe, ez azt jelenti, hogy indikátorablakot csatoltunk vagy töröltünk (az előző tick óta). Mindkét esetben a korábban megalkotott objektumot törölni kell, és egy újat kell létrehozni a kívánt ablakban:
ObjectDelete("Obj_RSI"); // Deletion of the object
Create_RSI(Win_RSI_new); // Create an object in the desired window
Miután az objektumot létrehoztuk a Win_RSI_new paraméternek megfelelő ablakban, a Win_RSI_old változónak is ezt az értéket adjuk, vagyis a program emlékszik az ablak számára, amiben a grafikus objektumot létrehoztuk:
Win_RSI_old = Win_RSI_new; // Remember this window
Ha a Win_RSI_new és Win_RSI_old változók értékei azonosak, ez azt jelenti, hogy elegendő a szövegre vonatkozó paramétereket beállítani (és a paraméterek módosítását az objektumok jelenlegi helyén végrehajtani). Hasonlóan, mint az új objektumok létrehozásakor:
ObjectSetText("Obj_RSI",Text[Ind_RSI],10,"Arial",Color[Ind_RSI]);
Ugyanilyen számításokat végzünk a másik segédablakra a Momentum indikátorral (8-10 blokk). A Main() függvény végén, minden elérhető grafikus objektumot újrarajzolunk WindowRedraw() függvény végrehajtásával.
Könnyű észrevenni, hogy a segédablakokban lévő grafikus objektumokat kezelő program globális változókat használ (használhatna statikus változókat is). Ilyenkor, a program kódolása közben fokozattan kell figyelni arra, hogy milyen értékeket vehetnek fel a különböző helyzetekben a globális változók, és, hogy ez milyen eredménnyel végződhet. A programban, amit fent láthatunk a globális változókat nullázzuk az init() függvényben :
Win_RSI_old = 0; // Technical moment
Win_Mom_old = 0; // Technical moment
Ezek a sorok azért vannak a programban, mert a globális változók csak akkor veszítik el az értékeiket, ha a felhasználó leállította az alkalmazási program végrehajtását a szimbólumablakban. Azonban, ha a felhasználó külső változókat állít be vagy időkeretet vált, a program keresztülmegy a deinicializáción és utána rögtön az inicializáláson, de a globális változók értékei megmaradnak.
Figyeljük meg, hogy mi történne, ha ezek a sorok hiányoznának a programból! Tegyük fel, hogy, amikor a felhasználó időkeretet vált mindkét indikátor a segédablakban van, az 1.-ben és a 2.-ban. A szóban forgó példában, mikor a program a deinicializációt végrehajtja, a grafikus objektumok törlődnek. Az init() különleges függvény végrehajtásánál, az objektumokat a nulla ablakban hozzuk létre. A Main() függvény végrehajtásánál a 7-8 és 9-10 blokkokban, a program összehasonlítja azon ablak számát, amiben az objektumot el kell helyezni, és azon ablak számát amiben az objektum az előző ticknél volt. Valójában, a tárgyak a nulla ablakban vannak, de a globális változók értékei más eredményt fognak mutatni, értékük 1 és 2 lesz. Végül a grafikus objektumok addig fognak maradni a fő ablakban, amíg a felhasználó le nem választja a megfelelő indikátorokat. Azért hogy meg akadályozzuk ezeket a nemkívánatos fejleményeket, a program elvégzi a globális változók nullázását az init() függvény végrehajtásánál. Így ezeknek a változóknak az értékei a valóságos helyzetet tükrözik.
A charts.mq4 EA végrehajtása után az ablakok és grafikus objektumok következő kombinációit láthatjuk:
141. ábra. A
grafikus objektumok megjelenítése egy
szimbólumablakban
és segédablakaiban.
Ha mindkét indikátor a szimbólumablakban van, a megfelelő grafikus objektumok a saját segédablakaikban fognak meg jelenni. Ha ezek az indikátorok nincsenek csatolva, akkor mindkét objektumot a fő ablakban fogja létre hozni a program. Bármelyik indikátor hozzáadása vagy törlése, amit a programban szerepeltetünk, azzal fog végződni, hogy a grafikus objektum a megfelelő ablakba fog vándorolni. Egyéb indikátorok hozzáadása vagy törlése a szimbólumablakból nem fog előidézni semmilyen változást.
Észre kell venni, hogy azt az esetet, amikor a felhasználó töröl egy grafikus objektumot, nem dolgozzuk föl ebben a programban. Egy programnak, amit a gyakorlati kereskedelmedben használnak, tartalmaznia kell az ilyen helyzet elemzését az azt követő helyreállítást (lásd a 33. feladat megoldását).
A chartokkal kapcsolatos függvények
Függvény | Összefoglaló információ |
---|---|
HideTestIndicators | A függvény egy flaggel megjelöli az Expert Advisor által hívott, a teszt alatt elrejtendő indikátorokat. A tesztelő ábra megnyitásnál a megjelölt indikátorok nem fognak megjelenni a tesztgrafikonban. Mindegyik indikátorhívás előtt először ki kell tenni ezt a flaget (csak azok az indikátorok láthatók a tesztgrafikonban, amelyeket a teszt alatt közvetlenül hívtak az EA-ból). |
Period | Visszaküldi az aktuális chart időkeretének értékét percekben. |
RefreshRates | Az előre definiált változók és tömbök adatait frissíti. Ezt a függvényt használjuk akkor, amikor egy EA vagy egy script sokáig számolt és frissített adatokra van szüksége. Visszaküldi a TRUE-t, ha az adat frissítés sikerrel járt. Különben FALSE-t küld vissza. A régebbi adatok csak akkor maradnak érvényesek, ha egyeznek az ügyfélterminál aktuális adataival. |
Symbol | Visszaküld az aktuális szimbólum nevét. |
WindowBarsPerChart | A függvény visszaküldi az aktuális ablakban elérhető bárok számát. |
WindowExpertName | Visszaküldi a futó EA, script, egyéni indikátor vagy library nevét, attól az MQL4 programtól függően, ahonnan ezt a függvényt hívjuk. |
WindowFind | Visszaküldi annak a segédablaknak a számát, ahol a megnevezett indikátor, található, ha azt megtalálta. Ha nem találta meg -1-et küld vissza. A WindowFind() -1-et küld vissza akkor is ha az egyéni indikátor az inicializálás (init()) alatt kutat maga után. |
WindowFirstVisibleBar | A függvény visszaküldi az aktuális chart első látható bárjának a számát. Figyelembe kell venni, hogy a bárokat fordított sorrendben számozzuk a legutolsótól visszafelé. Az aktuális bárnak, ami a legutolsó a sorban az indexe 0. A legrégebbi bárnak indexe Bars-1. Ha az első látható bárnak a száma több mint 2-vel kisebb, mint a lehetséges bárok száma, ez azt jelenti, hogy az ablak nincs tele bárokkal és van egy üres tér a baloldalon. |
WindowHandle | Visszaküldi azt az ablak azonosítót, ami tartalmazza az adott paraméterű chartot. Ha adott szimbólummal és időkerettel nincs nyitott chart 0-t küld vissza. |
WindowIsVisible | TRUE értéket küld vissza, ha az adott segédablak látható. Különben FALSE-t küld vissza. A segédablak láthatóságát/elrejtését az indikátor tulajdonságainak beállítása határozza meg. |
WindowOnDropped | Visszaküldi annak az ablaknak az indexét, amiben az EA-t, scriptet, vagy egyéni indikátort leejtették. Ez az érték csak akkor lesz igaz, ha az EA-t, indikátort vagy scriptet az egér húzásával csatoljuk az ablakhoz, ('drag and drop' módszer). Ha ezt a függvényt az egyéni indikátor inicializálásakor használjuk (az init() függvényből hívjuk), a hívó indikátor indexét nem tudja meghatározni. A visszaküldött index annak az ablaknak a száma (0 indexe van a főablaknak, az indikátor segédablakok számozása mindig 1-gyel kezdődik), amiben az egyéni indikátor dolgozik. Inicializálás alatt egy egyéni indikátor létre fogja hozni a saját új segédablakát, és ennek a sorszáma különbözni fog annak az ablaknak a számától, amiben az indikátort valójában leejtettük. |
WindowPriceMax | Visszaküldi az aktuális ábra adott segédablaka függőleges skálájának a maximális értékét (0 a fő ábraablak,az indikátor segédablakok számozása pedig 1-gyel kezdődik). Ha híváskor az ablak indexet elhagyjuk, akkor a főablak árskálájának a maximális értékét fogja visszaküldeni. |
WindowPriceMin | Visszaküldi az aktuális ábra adott segédablaka függőleges skálájának a minimális értékét (0 a fő ábraablak, az indikátor segédablakok számozása pedig 1-gyel kezdődik). Ha híváskor az ablak indexet elhagyjuk, akkor a főablak árskálájának a minimális értékét fogja visszaküldeni. |
WindowPriceOnDropped | Visszaküldi az árértéket arról a pontról, ahová az EA-t vagy a scriptet leejtettük. Az érték csak akkor lesz igaz, ha az EA-t vagy a scriptet az egér húzásával csatoltuk, ('drag and drop' technológia). Ezt az értéket nem határozzák meg az egyéni indikátorok. |
WindowRedraw | Erőszakosan újrarajzolja az aktuális ábrát. A függvényt általában azután használjuk, miután az objektum tulajdonságokat megváltoztattuk. |
WindowScreenShot | Menti az aktuális képernyőképet egy GIF fájlban. Ha képtelen menteni FALSE-t küld vissza. |
WindowTimeOnDropped | Visszaküldi az időértéket arról a pontról, ahová az EA-t vagy a scriptet leejtettük. Az érték csak akkor lesz igaz, ha az EA-t vagy a scriptet az egér húzásával csatoltuk ('drag and drop' technológia). Ezt az értéket nem határozzák meg az egyéni indikátorok. |
WindowsTotal | A függvény visszaküldi a chart valamennyi indikátorablakának számát a fő ablakot is beleértve. |
WindowXOnDropped | Visszaküldi annak a pontnak az X koordinátáját pixelekben, ahová az EA-t vagy a scriptet leejtettük. Az érték csak akkor lesz igaz ha az EA-t vagy a scriptet az egér húzásával csatoltuk, ('drag and drop' technológia). |
WindowYOnDropped | Visszaküldi annak a pontnak az Y koordinátáját pixelekben, ahová az EA-t vagy a scriptet leejtettük. Az érték csak akkor lesz igaz, ha az EA-t vagy a scriptet az egér húzásával csatoltuk, ('drag and drop' technológia). |