Radu MetaTrader a blogja | További ingyenes és hasznos eszközök MetaTraderhez | Kérdésed merült fel? Kérdezz!
MQL4 Könyv tartalomjegyzék | Stratégiák programozása MetaTrader platformra | Fogalomtár | Gyakran Ismételt Kérdések

MQL4 könyv    Egyszerű  MQL4 programok   A programok kombinált használata


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:

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.

Az ilyen problémák megoldásához egy kész Expert Advisort tudunk használni, ha megváltoztatjuk benne a kereskedelmi ismertetőjelek számításának a módszerét. Ebben az esetben alapként vehetjük a tradingexpert.mq4 Expert Advisort amit a Simple Expert Advisor részben ismertettün. A shared.mq4 

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 &amp;&amp; L_1<L_5)
     {
      Opn_B=true;                               // Criterion for opening Buy
      Cls_S=true;                               // Criterion for closing Sell
     }
   if (L_5<=Level &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; 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 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.

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.

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.