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:

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.

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.

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.