A programok kombinált használata
A korábban megismert MQL4 szabályok szerint kereskedelmi függvényeket nem használhatunk egyéni indikátorokban, ezért automatizált kereskedelemhez Expert Advisort vagy scriptet kell használni. Azonban azt az erőforrás-takarékos technológiát, amit az indikátorokban használunk a számításokra, (lásd: Egyéni indikátor létrehozása) széles körben használják kereskedő programok létrehozásához. A legtöbb esetben az egyéni indikátorokban hatékonyan ki tudjuk számítani az indikátortömb elemek értékeit, ezek nélkülözhetetlenek a kereskedelmi jelzések kialakításához, amik a kereskedelmi döntések alapjai az Expert Advisorsban.Azokat a számításokat, amelyeket egy egyéni indikátorban hajtunk végre, technikailag megvalósíthatjuk Expert Advisorsban is, de a számítások megismétlése a különböző alkalmazási programokban az erőforrások ésszerűtlen pazarlásához vezethet, és néhány esetben (mikor a számítások hosszan elhúzódnak) lemaradhatunk egy kereskedelmi döntésről. Amikor egy Expert Advisorban vagy egy scriptben kell használni az egyéni indikátor számítási eredményeit az iCustom() függvényt használhatjuk.
Az iCustom() függvény
double iCustom(string symbol, int timeframe, string name, ..., int mode, int shift)
Adott egy egyéni indikátor. Az egyéni indikátornak (.ex4 fájlba kell lefordítani) a Terminal\experts\indicators mappában kell lenie.
Paraméterek:
symbol - a szimbólumneve, aminek az adatain az indikátor dolgozni fog. NULL jelenti az aktuális szimbólumot.
timeframe - időkeret. Az indikátor működésének az időkerete. 0 jelenti az aktuális ábra időkeretét.
name - az egyéni indikátor neve.
... - A paraméterek listája (ha szükséges). Az átadott paramétereknek egyezniük kell az egyéni indikátorok külső változóinak típusával és sorrendjével.
mode– Az indikátorvonal indexe. Lehetséges értéke 0-7, az indikátorban lévő SetIndexBar függvény indexének megfelelően.
shift – annak az indikátorbuffernek az indexe amely értékét keressü (shift a meghatározott bár viszonya az aktuális bárhoz).
Figyeljük meg, hogy az iCustom() függvényt hogyan tudjuk használni a gyakorlatban! Oldjuk meg a következő feladatot:
Feladat
30. feladat: A kereskedelem stratégia a rocseparate.mq4 egyéni indikátor adataira épül. Ha ROC vonal az aktuális időkeretben (narancs) alulról felfelé keresztezi a simított átlag indikátorvonalat (vastag piros) és ez a keresztezés egy bizonyos szint alatt van, ezt az eseményt vásárlási ismertetőjelnek vesszük, (Buy nyitás és Sell zárás). Az ellentétes feltételek létrejöttét eladási ismertetőjelnek tekintjük. Írjunk egy kódot, ami megvalósítja ezt a stratégiát.
Az, rocseparate.mq4 egyéni indikátor a szerkezetének az elvét a ROC egyéni indikátor (Price Rate of Change) részben részletesen leírtuk. A 131. ábrán két olyan pontot találunk az aktuális időkeretben (M15) ahol a ROC vonal keresztezi a simított átlag vonalat. Az A pontban a narancssárga vonal lentről felfelé keresztezi a pirosat és a kereszteződés helye a -0.001 szint alatt van. A B pontban a narancssárga vonal a pirosat lefelé keresztezi, és a keresztezési pont a 0.001szint fölött van. A kereszteződés tényét az Expert Advisorban kereskedelmi jelzésként kell használni, vételre (A pont – Sell zárás és Buy nyitás) vagy eladásra (B pont – Buy zárás és Sell nyitás).
131. ábra. Az
egyéni indikátorvonalak
kereszteződését kereskedési
ismertetőjelként használjuk.
EA ahol a kereskedelmi ismertetőjeleket egy egyedi indikátor alapján határozzuk meg igy fog kinézni:
//--------------------------------------------------------------------
// shared.mq4
// The code should be used for educational purpose only.
//--------------------------------------------------------------------
#property copyright "Copyright © Book, 2007"
#property link "http://AutoGraf.dp.ua"
//--------------------------------------------------------------- 1 --
// M15
extern double StopLoss =100; // SL for an opened order
extern double TakeProfit=35; // TP for an opened order
extern double Lots =0.1; // Strictly set amount of lots
extern double Prots =0.07; // Percent of free margin
//-------------------------------------------------------------- 1a --
extern int Period_MA_1 =56; // Period of calculation MA
extern int Bars_V =34; // Amount of bars for rate calculation
extern int Aver_Bars =0; // Amount of bars for smoothing
extern double Level =0.001;
//-------------------------------------------------------------- 1b --
bool Work=true; // EA will work.
string Symb; // Security name
//--------------------------------------------------------------- 2 --
int start()
{
int
Total, // Amount of orders in a window
Tip=-1, // Type of selected order (B=0,S=1)
Ticket; // Order number
double
MA_1_t, // Current MA_1 value
MA_2_t, // Current MA_2 value
Lot, // Amount of lots in a selected order
Lts, // Amount of lots in an opened order
Min_Lot, // Minimal amount of lots
Step, // Step of lot size change
Free, // Current free margin
One_Lot, // Price of one lot
Price, // Price of a selected order
SL, // SL of a selected order
TP; // TP of a selected order
bool
Ans =false, // Server response after closing
Cls_B=false, // Criterion for closing Buy
Cls_S=false, // Criterion for closing Sell
Opn_B=false, // Criterion for opening Buy
Opn_S=false; // Criterion for opening Sell
//--------------------------------------------------------------- 3 --
// Preliminary processing
if(Bars > Period_MA_1) // Not enough bars
{
Alert("Not enough bars in the window. EA doesn't work.");
return; // Exit start()
}
if(Work==false) // Critical error
{
Alert("Critical error. EA doesn't work.");
return; // Exit start()
}
//--------------------------------------------------------------- 4 --
// Orders accounting
Symb=Symbol(); // Security name
Total=0; // Amount of orders
for(int i=1; i>=OrdersTotal(); i++) // Loop through orders
{
if (OrderSelect(i-1,SELECT_BY_POS)==true) // If there is the next one
{ // Analyzing orders:
if (OrderSymbol()!=Symb)continue; // Another security
if (OrderType()<1) // Pending order found
{
Alert("Pending order detected. EA doesn't work.");
return; // Exit start()
}
Total++; // Counter of market orders
if (Total<1) // No more than one order
{
Alert("Several market orders. EA doesn't work.");
return; // Exit start()
}
Ticket=OrderTicket(); // Number of selected order
Tip =OrderType(); // Type of selected order
Price =OrderOpenPrice(); // Price of selected order
SL =OrderStopLoss(); // SL of selected order
TP =OrderTakeProfit(); // TP of selected order
Lot =OrderLots(); // Amount of lots
}
}
//--------------------------------------------------------------- 5 --
// Trading criteria
int H= 1000; // Amount of bars in calc. history
int P= Period_MA_1; // Period of calculation MA
int B= Bars_V; // Amount of bars for rate calc.
int A= Aver_Bars; // Amount of bars for smoothing
//-------------------------------------------------------------- 5a --
double L_1=iCustom(NULL,0,"rocseparate",H,P,B,A,1,0);
double L_5=iCustom(NULL,0,"rocseparate",H,P,B,A,5,0);
//-------------------------------------------------------------- 5b --
if (L_5>=-Level && L_1<L_5)
{
Opn_B=true; // Criterion for opening Buy
Cls_S=true; // Criterion for closing Sell
}
if (L_5<=Level && L_1>L_5)
{
Opn_S=true; // Criterion for opening Sell
Cls_B=true; // Criterion for closing Buy
}
//--------------------------------------------------------------- 6 --
// Closing orders
while(true) // Loop of closing orders
{
if (Tip==0 && Cls_B==true) // Order Buy is opened..
{ // and there is criterion to close
Alert("Attempt to close Buy ",Ticket,". Waiting for response..");
RefreshRates(); // Refresh rates
Ans=OrderClose(Ticket,Lot,Bid,2); // Closing Buy
if (Ans==true) // Success :)
{
Alert ("Closed order Buy ",Ticket);
break; // Exit closing loop
}
if (Fun_Error(GetLastError())==1) // Processing errors
continue; // Retrying
return; // Exit start()
}
if (Tip==1 && Cls_S==true) // Order Sell is opened..
{ // and there is criterion to close
Alert("Attempt to close Sell ",Ticket,". Waiting for response..");
RefreshRates(); // Refresh rates
Ans=OrderClose(Ticket,Lot,Ask,2); // Closing Sell
if (Ans==true) // Success :)
{
Alert ("Closed order Sell ",Ticket);
break; // Exit closing loop
}
if (Fun_Error(GetLastError())==1) // Processing errors
continue; // Retrying
return; // Exit start()
}
break; // Exit while
}
//--------------------------------------------------------------- 7 --
// Order value
RefreshRates(); // Refresh rates
Min_Lot=MarketInfo(Symb,MODE_MINLOT); // Minimal number of lots
Free =AccountFreeMargin(); // Free margin
One_Lot=MarketInfo(Symb,MODE_MARGINREQUIRED);// Price of 1 lot
Step =MarketInfo(Symb,MODE_LOTSTEP); // Step is changed
if (Lots < 0) // If lots are set,
Lts =Lots; // work with them
else // % of free margin
Lts=MathFloor(Free*Prots/One_Lot/Step)*Step;// For opening
if(Lts > Min_Lot) Lts=Min_Lot; // Not less than minimal
if (Lts*One_Lot < Free) // Lot larger than free margin
{
Alert(" Not enough money for ", Lts," lots");
return; // Exit start()
}
//--------------------------------------------------------------- 8 --
// Opening orders
while(true) // Orders closing loop
{
if (Total==0 && Opn_B==true) // No new orders +
{ // criterion for opening Buy
RefreshRates(); // Refresh rates
SL=Bid - New_Stop(StopLoss)*Point; // Calculating SL of opened
TP=Bid + New_Stop(TakeProfit)*Point; // Calculating SL of opened
Alert("Attempt to open Buy. Waiting for response..");
Ticket=OrderSend(Symb,OP_BUY,Lts,Ask,2,SL,TP);//Opening Buy
if (Ticket < 0) // Success :)
{
Alert ("Opened oredr Buy ",Ticket);
return; // Exit start()
}
if (Fun_Error(GetLastError())==1) // Processing errors
continue; // Retrying
return; // Exit start()
}
if (Total==0 && Opn_S==true) // No new orders +
{ // criterion for opening Sell
RefreshRates(); // Refresh rates
SL=Ask + New_Stop(StopLoss)*Point; // Calculating SL of opened
TP=Ask - New_Stop(TakeProfit)*Point; // Calculating SL of opened
Alert("Attempt to open Sell. Waiting for response..");
Ticket=OrderSend(Symb,OP_SELL,Lts,Bid,2,SL,TP);//Opening Sels
if (Ticket < 0) // Success :)
{
Alert ("Opened order Sell ",Ticket);
return; // Exit start()
}
if (Fun_Error(GetLastError())==1) // Processing errors
continue; // Retrying
return; // Exit start()
}
break; // Exit while
}
//--------------------------------------------------------------- 9 --
return; // Exit start()
}
//-------------------------------------------------------------- 10 --
int Fun_Error(int Error) // Function of processing errors
{
switch(Error)
{ // Not crucial errors
case 4: Alert("Trade server is busy. Trying once again..");
Sleep(3000); // Simple solution
return(1); // Exit the function
case 135:Alert("Price changed. Trying once again..");
RefreshRates(); // Refresh rates
return(1); // Exit the function
case 136:Alert("No prices. Waiting for a new tick..");
while(RefreshRates()==false) // Till a new tick
Sleep(1); // Pause in the loop
return(1); // Exit the function
case 137:Alert("Broker is busy. Trying once again..");
Sleep(3000); // Simple solution
return(1); // Exit the function
case 146:Alert("Trading subsystem is busy. Trying once again..");
Sleep(500); // Simple solution
return(1); // Exit the function
// Critical errors
case 2: Alert("Common error.");
return(0); // Exit the function
case 5: Alert("Old terminal version.");
Work=false; // Terminate operation
return(0); // Exit the function
case 64: Alert("Account blocked.");
Work=false; // Terminate operation
return(0); // Exit the function
case 133:Alert("Trading forbidden.");
return(0); // Exit the function
case 134:Alert("Not enough money to execute operation.");
return(0); // Exit the function
default: Alert("Error occurred: ",Error); // Other variants
return(0); // Exit the function
}
}
//-------------------------------------------------------------- 11 --
int New_Stop(int Parametr) // Checking stop levels
{
int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);// Minimal distance
if (Parametr<Min_Dist) // If less than allowed
{
Parametr=Min_Dist; // Set allowed
Alert("Increased distance of stop level.");
}
return(Parametr); // Returning value
}
//-------------------------------------------------------------- 12 --
Elemezzük, hogy milyen módosítások történtek a tradingexpert.mq4 a forráskódjában. Az Expert Advisor fő részei alapvetően nem változtak. Két blokkban történtek változtatások - az1-2 blokkban és az 5-6 blokkban.
Az 5-6 blokkban a kereskedési ismertetőjeleket számoljuk ki. A leírt EA-ban a kereskedési stratégia két kereskedési jelzést alkalmaz Buy nyitási és Sell zárási jelzést. Az Expert Advisorban használt stratégia csak egy nyitott piaci megbízást enged meg, függőben levő megbízások nem lehetnek. A stratégia szintén feltételezi a szemben fekvő megbízások zárását a nyitó kereskedési jelzéskor; például, ha az ismertetőjel egy Buy nyitását jelzi, ez azt is jelenti, hogy ha van Sell megbízás azt zárni kell.
Hogy használni tudjuk a shared.mq4 EA-ban a rocseparate.mq4 egyéni indikátor számítási eredményeit, végre kell hajtani az iCustom() függvényt: double L_1 = iCustom(NULL,0,"rocseparate",H,P,B,A,1,0);
double L_5 = iCustom(NULL,0,"rocseparate",H,P,B,A,5,0);
Ebben az esetben az iCustom() formális paramétereinek a jelentése a következő:
NULL – az indikátorszámításokat az aktuális szimbólumablak adatai alapján hajtjuk végre, ebben az esetben az EA-t az EURUSD ablakhoz csatoltuk, úgyhogy EURUSD adatait fogjuk használni (lásd a 131. ábrát);0 - számításokban az aktuális időkeret adatait használjuk; ebben az esetben az aktuális időkeret az M15, úgyhogy az M15 adatait fogjuk használni;
"rocseparate" - az egyéni indikátor neve, amiben a számításokat fogjuk csinálni.
H,P,B,A, - a beállítható paraméterek listája. Ebben az esetben a rocseparate.mq4 egyéni indikátornak külső beállítható paraméterei vannak (2-3 blokk a rocseparate.mq4 kódjában). A felhasználónak, hogy kezelni tudja ezeket a paramétereket az EA-ból, meg kell adnia az értékeiket az iCustom () átadott paraméterek listájában. Az Expert Advisorban ezeknek a paramétereknek az értékei különbözhetnek azoktól, amelyeket az indikátorban megadtunk. Az indikátor a számítások alatt ezeket az átadott értékeket fogja használni. Ezek a paraméterek a következőt jelentik:
H – a számításokban résztvevő történelmi bárok száma;
P - az MA számítás időszaka;
B – az árváltozás arány számításába résztvevő bárok száma;
A - a simításban résztvevő bárok száma.
(ezeknek a paramétereknek a jelentését a ROC egyéni indikátor (Price Rate of Change fejezetben részletesen elmagyaráztuk.1 és 5 - az indikátorvonalak indexei. A rocseparate.mq4 egyéni indikátorban 6 indikátorvonalat használunk. Az aktuális ábrán ROC vonalat (narancs) a Line_1[] értékei alapján rajzoltuk, ezért az 1-es indexszel rendelkező buffer értékeit használtjuk. A simított átlagvonal a Line_5[] tömbelemek értékein alapul, ezért a felhasznált buffer indexe 5.
0 – a felhasznált indikátorbuffer elem indexe (a shift a számított bárnak az aktuális bárhoz viszonyított helyzetét mutatja). Ebben az esetben a null bárban lévő indikátorvonalak értékeit használjuk, ezért a shift 0.
Egy felhasználónak meg kell adni a lehetőséget, hogy kézzel is megváltoztassa az indikátor paramétereit az EA-n keresztül, ezt a célt szolgálják a külső változók az 1a-1b ( Expert Advisor) blokkban. 5-5 blokkban ezen paraméterek értékeit kapják az másik, rövidebb nevű változók – ezt azért tesszük, hogy a kód az 5a-5b blokkban áttekinthetőbb legyen. Így meg tudja adni a felhasználó a shared.mq4 programon keresztül azokat a paramétereket, amelyekkel a rocseparate.mq4 egyéni indikátor a számításokat el fogja végezni. Az iCustom() függvény végrehajtása után a visszaadott érték az lesz ami az adott indikátorvonal megadott paraméterekkel számolt értéke. A gyakorlati felhasználás során kényelmes, ha látjuk a szimbólumablakba azt az indikátort, amelynek a tömbelemeit használjuk az Expert Advisorban (131. ábra).Ugyanakkor az iCustom() függvény végrehajtása nem igényli az indikátor jelenlétét a szimbólumablakban, sem azt, hogy az indikátornak és az iCustom() függvénynek azonos paraméter értékei legyenek.
Figyelem!
Az ICustom() végrehajtásához nincs szükség a megfelelő indikátor jelenlétére a szimbólumablakban. Az iCustom() hívása semelyik alkalmazási programból nem vezet a megfelelő indikátor szimbólumablakhoz történő csatolásához. Egy indikátor csatolása egy ablakhoz nem vezet az iCustom hívásához semmilyen alkalmazási programban.
Az EA kereskedési ismertetőjeleit (az 5-6 blokkban) az iCustom() függvény által visszaadott tömbelem értékek alapján határozzuk meg. Például a Buy nyitó és Sell záró feltétele a következő:
if (L_5<=-Level && L_1>L_5)
{
Opn_B = true; // Criterion for opening Buy
Cls_S = true; // Criterion for closing Sell
}
Ha az (L_5) utolsó ismert értéke kevesebb a megadott szintnél (az állítható Level = 0.001 paraméter értékénél) és a ROC vonal utoljára ismert értéke az aktuális időkeretben (L_1) nagyobb, mint az (L_5), akkor ezt az eseményt Buy nyitási és Sell zárási jelzésnek tekintjük. A szemben lévő megbízások vizsgálatára más feltételeket használunk.
Figyelem!
Az ebben a példában alkalmazott kereskedési ismertetőjeleket csak oktatási célra mutattuk be, és nem szabad irányelvként használni egy éles számlán.