English Русский 中文 Español Deutsch 日本語
Transferência de um Código Indicador para um Código Expert Advisor. Conclusão

Transferência de um Código Indicador para um Código Expert Advisor. Conclusão

MetaTrader 4Exemplos | 19 fevereiro 2016, 14:31
991 0
Nikolay Kositsin
Nikolay Kositsin

Introdução

Nos artigos anteriores (Transferência de um Código Indicador para um Código Expert Advisor. Estrutura do Indicador e Transferência de um Código Indicador para um Código Expert Advisor. Esquema Geral do Expert Advisor e suas Funções Indicadoras analisamos um esquema geral de escrever uma função de indicador com base em um código indicador pronto e definimos sua correlação com um Expert Advisor. Agora é hora de reescrever um código de um Expert Advisor real. Vamos começar.

Código fonte do EA

Então, temos o seguinte código Expert Advisor:


//+------------------------------------------------------------------+
//|                                         ASCTrend1RAVI_Expert.mq4 |
//|                             Copyright © 2006,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru"
//---- INPUT PARAMETERS
extern int RAVI_Timeframe = 240;
extern int ASCT_Timeframe = 1440;
//---- FILTER OF TRADE CALCULATION DIRECTION
extern int Buy_Sell_Custom = 2; //0-Buy, 1-Sell, 2-Buy+Sell
//---- INPUT PARAMETERS OF EA FOR BUY TRADES 
extern double Money_Management_Up=0.1;
extern int RISK_Up = 3;
extern int Period1_Up = 7; 
extern int Period2_Up = 65; 
extern int MA_Metod_Up = 0;
extern int PRICE_Up = 0;
extern int STOPLOSS_Up = 50;
extern int TAKEPROFIT_Up = 100;
//---- INPUT PARAMETERS OF EA FOR SELL TRADES 
extern double Money_Management_Dn = 0.1;
extern int RISK_Dn = 3;
extern int Period1_Dn = 7; 
extern int Period2_Dn = 65; 
extern int MA_Metod_Dn = 0;
extern int PRICE_Dn = 0;
extern int STOPLOSS_Dn = 50;
extern int TAKEPROFIT_Dn = 100;
//---- Emulated indicator buffers
double RAVI_Up[3];
double RAVI_Dn[3];
double ASCTrend1_Up[2];
double ASCTrend1_Dn[2];
//+------------------------------------------------------------------+
//| Custom Expert functions                                          |
//+------------------------------------------------------------------+
#include <Lite_EXPERT.mqh>
//+------------------------------------------------------------------+
//| Custom Expert initialization function                            |
//+------------------------------------------------------------------+
int init()
  {
//---- 
   if(RAVI_Timeframe != 1)
       if(RAVI_Timeframe != 5)
           if(RAVI_Timeframe != 15)
               if(RAVI_Timeframe != 30)
                   if(RAVI_Timeframe != 60)
                       if(RAVI_Timeframe != 240)
                           if(RAVI_Timeframe != 1440)
                               Print("Parameter RAVI_Timeframe cannot" + 
                                     " be equal to " + RAVI_Timeframe+"!!!");
//---- 
   if(ASCT_Timeframe != 1)
       if(ASCT_Timeframe != 5)
           if(ASCT_Timeframe != 15)
               if(ASCT_Timeframe != 30)
                   if(ASCT_Timeframe != 60)
                       if(ASCT_Timeframe != 240)
                           if(ASCT_Timeframe != 1440)
                               Print("Parameter ASCT_Timeframe cannot" + 
                                     " be equal "+ASCT_Timeframe+"!!!");
//----                      
   if(RAVI_Timeframe > ASCT_Timeframe) 
       Print("Parameter ASCT_Timeframe should not be less" + 
             " than RAVI_Timeframe");                   
//---- initialization end
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom Expert iteration function                                 |
//+------------------------------------------------------------------+
int start()
  {
//---- Checking whether the bars number is enough for further calculation  
   if(iBars(NULL, ASCT_Timeframe) < 3 + RISK_Up*2 + 1 + 1)
       return(0);
   if(iBars(NULL, ASCT_Timeframe) < 3 + RISK_Dn*2 + 1 + 1)
       return(0);
//----
   if(iBars(NULL, RAVI_Timeframe) < MathMax(Period1_Up, Period2_Up + 4))
       return(0);
   if(iBars(NULL, RAVI_Timeframe) < MathMax(Period1_Dn, Period2_Dn + 4))
       return(0);
//---- Declaration of variables
   static double ASCTrend1_Trend_Up, ASCTrend1_Trend_Dn;
   static int LastBars;
   int    bar;
   bool   BUY_Sign, SELL_Sign; 
//---- CALCULATION OF INDICATOR VALUES AND LOADING THEM TO BUFFERS
   if(LastBars != iBars(NULL, RAVI_Timeframe))
       switch(Buy_Sell_Custom)
         {
           case 0: 
             {           
               for(bar = 1; bar <= 3; bar++)
                   RAVI_Up[bar-1] = iCustom(NULL, RAVI_Timeframe, 
                                            "RAVI", Period1_Up, Period2_Up,
                                            MA_Metod_Up, PRICE_Up, 0, bar); 
               //----+
               ASCTrend1_Up[0] = iCustom(NULL, ASCT_Timeframe, 
                                         "ASCTrend1", RISK_Up, 0, 1); 
               ASCTrend1_Up[1] = iCustom(NULL, ASCT_Timeframe, 
                                         "ASCTrend1", RISK_Up, 1, 1); 
               //----+
               ASCTrend1_Trend_Up = ASCTrend1_Up[1] - ASCTrend1_Up[0];       
               break;
             }
           //---- 
           case 1: 
             {            
               for(bar = 1; bar <= 3; bar++)
                   RAVI_Dn[bar-1] = iCustom(NULL, RAVI_Timeframe, 
                                            "RAVI", Period1_Dn, 
                                            Period2_Dn, MA_Metod_Dn, 
                                            PRICE_Dn, 0, bar);
               //----+              
               ASCTrend1_Dn[0] = iCustom(NULL, ASCT_Timeframe, 
                                         "ASCTrend1", RISK_Dn, 0, 1); 
               ASCTrend1_Dn[1] = iCustom(NULL, ASCT_Timeframe, 
                                         "ASCTrend1", RISK_Dn, 1, 1); 
               //----+
               ASCTrend1_Trend_Dn =ASCTrend1_Dn[1] - ASCTrend1_Dn[0];
               break;
             }
           //----
           default:
             {
               for(bar = 1; bar <= 3; bar++)
                   RAVI_Up[bar-1] = iCustom(NULL, RAVI_Timeframe, 
                                            "RAVI", Period1_Up, 
                                            Period2_Up, MA_Metod_Up, 
                                            PRICE_Up, 0, bar); 
               //----+
               ASCTrend1_Up[0] = iCustom(NULL, ASCT_Timeframe, 
                                         "ASCTrend1", RISK_Up, 0, 1); 
               ASCTrend1_Up[1] = iCustom(NULL, ASCT_Timeframe, 
                                         "ASCTrend1", RISK_Up, 1, 1);
               //----+ 
               ASCTrend1_Trend_Up = ASCTrend1_Up[1] - ASCTrend1_Up[0];
               //----+             
               for(bar = 1; bar <= 3; bar++)
                   RAVI_Dn[bar-1] = iCustom(NULL, RAVI_Timeframe, 
                                            "RAVI", Period1_Dn, 
                                            Period2_Dn, MA_Metod_Dn,
                                            PRICE_Dn, 0, bar);
               //----+             
               ASCTrend1_Dn[0] = iCustom(NULL, ASCT_Timeframe, 
                                         "ASCTrend1", RISK_Dn, 0, 1); 
               ASCTrend1_Dn[1] = iCustom(NULL, ASCT_Timeframe, 
                                         "ASCTrend1", RISK_Dn, 1, 1); 
               //----+
               ASCTrend1_Trend_Dn = ASCTrend1_Dn[1] - ASCTrend1_Dn[0];
             }
         }
//---- Variable initialization
   LastBars = iBars(NULL, RAVI_Timeframe);
//---- DEFINING SIGNALS FOR TRADES
   switch(Buy_Sell_Custom)
     {
       //----
       case 0: 
         {
           if(RAVI_Up[1] - RAVI_Up[2] < 0)
               if(RAVI_Up[0] - RAVI_Up[1] > 0)
                   if(ASCTrend1_Trend_Up > 0)
                       BUY_Sign = true;
           break;
         }
       //----+ +---------------------------+ 
       case 1: 
         {
           if(RAVI_Dn[1] - RAVI_Dn[2] > 0)
               if(RAVI_Dn[0] - RAVI_Dn[1] < 0)
                   if(ASCTrend1_Trend_Dn < 0)
                       SELL_Sign = true;
           break;
         }
       //----
       default:
         {
           if(RAVI_Up[1] - RAVI_Up[2] < 0)
               if(RAVI_Up[0] - RAVI_Up[1] > 0)
                   if(ASCTrend1_Trend_Up > 0)
                       BUY_Sign = true;
           //----                 
           if(RAVI_Dn[1] - RAVI_Dn[2] > 0)
               if(RAVI_Dn[0] - RAVI_Dn[1] < 0)
                   if(ASCTrend1_Trend_Dn < 0)
                       SELL_Sign = true;
         }
     }
//---- EXECUTING TRADES
   switch(Buy_Sell_Custom)
     {
       //----
       case 0: 
         {
           OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, 
                        TAKEPROFIT_Up);
           break;
         }
       //----
       case 1: 
         {
           OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn,
                         TAKEPROFIT_Dn);
           break;
         }
       //----
       default:
         {
           OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, 
                        TAKEPROFIT_Up);
           OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn,
                         TAKEPROFIT_Dn);
         }
     }
   return(0);
  }
//+------------------------------------------------------------------+

Primeiro, precisamos analisar este Expert Advisor. O Expert Advisor destina-se ao trading com base em gráficos de 4 horas e gráficos diários em um par de moedas escolhido por um operador. O EA pode abrir apenas uma posição em um par de moedas nesse sentido do trading. A EA tem dois algoritmos de cálculo independentes para comércio de compra e venda, é por isso que pode abrir posições opostas.

Para uma otimização mais rápida do EA no strategy tester, ele contém uma variável externa Buy_Sell_Custom - se for igual a zero, o EA calcula só sinais de Compra. Se a variável Buy_Sell_Custom for igual a um, apenas sinais de Venda serão calculados. Se precisarmos de ambos os cálculos, a variável externa Buy_Sell_Custom deve ser igual a dois. Outras variáveis externas são divididas em dois grupos: de Compra e de Venda.

Os sinais do mercado são as mudanças de sentido do movimento do indicador personalizado RAVI.mq4, o filtro, cortando sinais falsos está a direção de tendência, determinada pelo indicador personalizado ASCTrend1.mq4. O Expert Advisor tem duas chamadas do indicador ASCTrend1.mq4 para receber a partir de zero e os primeiros valores de origem do buffer do indicador; o sinal de suas diferenças determina a direção da tendência. O EA também tem duas chamadas do indicador RAVI.mq4, para receber duas variantes (Compra e Venda) de valores de origem para os dois algoritmos de cálculo.

Suponho que o significado da maioria dos parâmetros de entrada do EA deve ser compreensível a partir de seus nomes. As variáveis MA_Metod_Up e MA_Metod_Dn determinam o método de cálculo da média. Elas podem ter valores diferentes, de zero a três. As variáveis PRICE_Up e PRICE_Dn têm valores de constantes de preços, os limites de alteração são de zero a seis.

Este Expert Advisor não é inequivocamente de perda, e apesar de sua simplicidade mostra resultados muito bons à uma boa otimização. Então, vale a pena se esforçar para transformá-lo a partir de um conjunto de arquivos em um único arquivo auto-suficiente. O código EA usa o arquivo Lite_EXPERT.mqh que é na verdade duas funções personalizadas, chamando a qual o EA executa as operações:


//+------------------------------------------------------------------+
//|                                                  Lite_EXPERT.mqh |
//|                                   Version  January 7, 2007 Final |
//|                             Copyright © 2006,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+
//---- Declaring a global variable for remembering the time 
//     of the last reference to a server
int LastTime; 
//+------------------------------------------------------------------+
//| OpenBuyOrder()                                                   |
//+------------------------------------------------------------------+
int OpenBuyOrder(bool BUY_Signal, double Money_Management, int STOPLOSS, 
                 int TAKEPROFIT)
  {
   if(!BUY_Signal)
       return(0); 
   if(TimeLocal() - LastTime < 11)
       return(0); 
   int total = OrdersTotal();
//---- Checking if there is an open position on this trading 
//     pair in Buy direction
   for(int ttt = total - 1; ttt >= 0; ttt--)     
       if(OrderSelect(ttt, SELECT_BY_POS, MODE_TRADES))
           if((OrderSymbol() == Symbol()) && (OrderType() == 0))
               return(0); 
//---- 
   double ask = NormalizeDouble(Ask, Digits);              
   double bid = NormalizeDouble(Bid, Digits);
//----
   if(ask == 0.0)
       return(-1);  
   if(bid == 0.0)
       return(-1);  
//----  
   double LotVel;      
   double tickVel = MarketInfo(Symbol(), MODE_TICKVALUE);    
   if(tickVel == 0)
       return(-1); 
//----
   if(Money_Management > 0)
       LotVel = tickVel*AccountEquity()*Money_Management / 10000.0;
   else 
       LotVel = -tickVel*10000*Money_Management / 10000.0;
//----
   double Lot = NormalizeDouble(LotVel, 1);  
   if(Lot < 0.1)
       return(-1);     
//----+ Open Buy position
   double Stoploss = NormalizeDouble(bid - STOPLOSS*Point, Digits);  
   double TakeProfit = NormalizeDouble(ask + TAKEPROFIT*Point, Digits);
//----
   int ticket = OrderSend(Symbol(), OP_BUY, Lot, ask, 3, Stoploss, 
                          TakeProfit, NULL, 0, 0, CLR_NONE); 
   //----
   LastTime = TimeLocal(); 
   //----
   if(ticket > 0)
       return(1);
   else 
       return(-1);
  }  
//+------------------------------------------------------------------+
//|  OpenSellOrder()                                                 |
//+------------------------------------------------------------------+
int OpenSellOrder(bool SELL_Signal, double Money_Management, int STOPLOSS, 
                  int TAKEPROFIT)
  { 
   if(!SELL_Signal)
       return(0); 
   if(TimeLocal() - LastTime < 11)
       return(0); 
   int total = OrdersTotal();
//---- Checking if there is an open position on this trading 
//     pair in Sell direction 
   for(int kkk = total - 1; kkk >= 0; kkk--)      
       if(OrderSelect(kkk, SELECT_BY_POS, MODE_TRADES))
           if((OrderSymbol() == Symbol()) && (OrderType() == 1))
               return(0); 
//---- 
   double bid = NormalizeDouble(Bid, Digits); 
   double ask = NormalizeDouble(Ask, Digits);
//----
   if(bid == 0.0)
       return(-1); 
   if(ask == 0.0)
       return(-1); 
//----      
   double LotVel;      
   double tickVel = MarketInfo(Symbol(), MODE_TICKVALUE);
   if(tickVel == 0.0)
       return(-1);   
//----   
   if(Money_Management > 0)
       LotVel = tickVel*AccountEquity()*Money_Management / 10000.0;
   else 
       LotVel = -tickVel*10000*Money_Management / 10000.0;
//----
   double Lot = NormalizeDouble(LotVel, 1); 
   if(Lot < 0.1)
       return(-1);       
//----+ Open Sell position 
   double Stoploss = NormalizeDouble(ask + STOPLOSS*Point, Digits);         
   double TakeProfit = NormalizeDouble(bid - TAKEPROFIT*Point, Digits);
//----   
   int ticket = OrderSend(Symbol(), OP_SELL, Lot, bid, 3, Stoploss, 
                          TakeProfit, NULL, 0, 0,CLR_NONE);
//----   
   LastTime = TimeLocal(); 
//----
   if(ticket > 0)
       return(1);
   else 
       return(-1);
  }              
//+------------------------------------------------------------------+

Suponho que essas funções são bastante simples e que não haverá nenhuma dificuldade. Aqui está o algoritmo de referência para as funções:

OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up);
OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn);

Aqui se BUY_Sign=true a função OpenBuyOrder() abre uma posição longa, se SELL_Sign=true, a função OpenSellOrder() abre uma posição curta. Significado dos parâmetros: Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn são compreensíveis a partir de seus nomes!

Escrevendo uma função indicadora Get_ASCTrend1Series()

No final do artigo anterior (Transferência de um Código Indicador para um Código Expert Advisor. Esquema Geral do Expert Advisor e suas Funções Indicadoras) Eu apresentei a função do indicador Get_RAVISeries(). Será bastante útil agora. Tudo que precisamos é escrever uma função análoga para o indicador ASCTrend1.mq4. Agora, na base deste código indicador vamos escrever a função Get_ASCTrend1Series(). Então, vamos olhar para este código indicador:

//+------------------------------------------------------------------+
//|                                                        ASCTrend1 |
//|                                        Ramdass - Conversion only |
//+------------------------------------------------------------------+
//---- drawing the indicator in the main window
#property indicator_chart_window 
//---- number of indicator buffers
#property indicator_buffers 2 
//---- indicator color
#property indicator_color1 Magenta
#property indicator_color2 Aqua
//---- width of indicator lines
#property indicator_width1 2
#property indicator_width2 2
//---- INPUT PARAMETERS OF THE INDICATOR
extern int RISK = 3;
//---- indicator buffers
double val1[];
double val2[];
//+------------------------------------------------------------------+
//| ASCTrend1 initialization function                                |
//+------------------------------------------------------------------+
int init()
  {
//---- Chart drawing style
   SetIndexStyle(0, DRAW_HISTOGRAM, 0, 2);
   SetIndexStyle(1, DRAW_HISTOGRAM, 0, 2);
//---- 2 indicator buffers are used for calculation
   SetIndexBuffer(0, val1);
   SetIndexBuffer(1, val2);
//---- setting indicator values that will be unseen on the chart
   SetIndexEmptyValue(0, 0.0);
   SetIndexEmptyValue(1, 0.0);
//---- name for data windows and labels for subwindows
   IndicatorShortName("ASCTrend1");
   SetIndexLabel(0, "DownASCTrend1");
   SetIndexLabel(1, "UpASCTrend1");
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| ASCTrend1                                                        |
//+------------------------------------------------------------------+
int start()
  {
//---- introducing memory variables  
   static double x1, x2;
//---- Introducing floating point variables
   double value1, value2, value3, TrueCount, Range, AvgRange, MRO1, MRO2;
//---- Introducing integer variables and getting already calculated bars
   int MaxBar, iii, kkk, bar, value10, value11, 
       counted_bars = IndicatorCounted();
//---- checking for possible errors
   if(counted_bars < 0)
       return(-1);
//---- the last calculated bar must be recalculated 
   if(counted_bars > 0)
       counted_bars--;
//---- variable initialization
   value10 = 3 + RISK*2;
//---- checking whether the bars number is enough for further calculation
   if((Bars <= value10) || (Bars < 10)) 
       return(0);
//---- defining the number of the oldest bar, 
//     starting from which all bars will be fully recalculated 
   MaxBar = Bars - 1 - value10;
//---- defining the number of the oldest bar, 
//     starting from which only new bars will be recalculated 
   bar = Bars - 1 - counted_bars;
//---- zero initialization
   if(bar >= MaxBar)
     {
       x1 = 67 + RISK;
       x2 = 33 - RISK;
       bar = MaxBar;
       //----
       for(kkk = Bars - 1; kkk >= MaxBar; kkk--) 
         {
           val1[kkk] = 0.0;
           val2[kkk] = 0.0;
         }
     }
//---- THE MAIN CYCLE OF INDICATOR CALCULATION
   while(bar >= 0)
     {  
       Range = 0.0;
       AvgRange = 0.0;
       for(iii = 0; iii <= 9; iii++) 
       AvgRange += MathAbs(High[bar+iii] - Low[bar+iii]);
       //----
       Range = AvgRange / 10;
       iii = 0;
       TrueCount = 0;
       while(iii < 9 && TrueCount < 1)
         {
           if(MathAbs(Open[bar+iii] - Close[bar+iii]) >= Range*2.0) 
           TrueCount++;
           //----
           iii++;
         }
       if(TrueCount >= 1)
           MRO1 = bar + iii; 
       else 
           MRO1 = -1;
       //----
       iii = 0;
       TrueCount = 0;
       while(iii < 6 && TrueCount < 1)
         {
           if(MathAbs(Close[bar+iii+3] - Close[bar+iii]) >= Range*4.6) 
           TrueCount++;
           //----
           iii++;
         }
       if(TrueCount >= 1)
           MRO2 = bar + iii; 
       else 
           MRO2 = -1;
       //----
       if(MRO1 > -1)
           value11 = 3; 
       else 
           value11 = value10;
       //----
       if(MRO2 > -1)
           value11 = 4; 
       else 
           value11 = value10;
       //----
       value2 = 100 - MathAbs(iWPR(NULL, 0, value11, bar));
       //---- 
       val1[bar] = 0;
       val2[bar] = 0;
       //---- 
       if(value2 > x1)
         {
           val1[bar] = Low [bar];
           val2[bar] = High[bar];
         }
       //---- 
       if(value2 < x2)
         {
           val1[bar] = High[bar]; 
           val2[bar] = Low [bar];
         }
       //---- 
       bar--;
     }
   return(0);
  }
//+------------------------------------------------------------------+



Eu otimizei este indicador. A versão original está no arquivo anexado ASCTrend1_Old!. mq4. Agora vamos preparar a função Get_ASCTrend1Series(). Para este propósito vamos transformar o código do indicador ASCTrend1.mq4 de acordo com o esquema do seu código de melhoria, descrito no artigo anterior. Como resultado, temos a seguinte função personalizada:

//+------------------------------------------------------------------+
//|                                          Get_ASCTrend1Series.mqh |
//|                        Copyright © 2006,        Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru |
//+------------------------------------------------------------------+
bool Get_ASCTrend1Series(int Number, string symbol,int timeframe, 
                         bool NullBarRecount, int RISK, 
                         double& InputBuffer[])    
  {
//---- getting the number of all bars of a chart
   int IBARS = iBars(symbol, timeframe);  
//---- Checking whether the bars number is enough for further calculation
   if((IBARS < 3 + RISK*2 + 1)||(IBARS < 10))
       return(false);
//---- EMULATION OF INDICATOR BUFFERS
   if(ArraySize(InputBuffer) < IBARS)
     {
       ArraySetAsSeries(InputBuffer, false);
       //----  
       ArrayResize(InputBuffer, IBARS); 
       //----
       ArraySetAsSeries(InputBuffer, true);
     } 
//----+  introducing static memory variables
   static double x1[], x2[];
   static int IndCounted[]; 
//----+ changing size of static variables
   if(ArraySize(IndCounted) < Number + 1)
     {
       ArrayResize(x1, Number + 1); 
       ArrayResize(x2, Number + 1); 
       ArrayResize(IndCounted, Number + 1); 
     }
 //----+ introducing integer variable
   int LastCountBar;
//----+ Checking whether the zero bar recalculation is allowed
   if(!NullBarRecount)
       LastCountBar = 1;
//----+ Introducing floating point variables 
   double value1, value2, value3, val1, val2;
   double TrueCount, Range, AvgRange, MRO1, MRO2;
//----+ Introducing integer variables and getting already calculated bars
   int MaxBar, iii, kkk, bar, value10, value11,
       counted_bars = IndCounted[Number];
//----+ Remembering the number of all bars of the chart
   IndCounted[Number] = IBARS - 1;
//---- variable initialization
   value10 = 3 + RISK*2;
//---- defining the number of the oldest bar, 
//     starting from which new bars will be recalculated
   bar = IBARS - counted_bars - 1; 
//---- defining the number of the oldest bar, 
//     starting from which all bars will be recalculated
   MaxBar = IBARS - 1 - value10;
//---- zero initialization 
   if(bar > MaxBar)
     {
       bar = MaxBar;
       x1[Number] = 67 + RISK;
       x2[Number] = 33 - RISK;
       //----
       ArrayInitialize(InputBuffer, 0.0); 
     } 
//---- THE MAIN CYCLE OF INDICATOR CALCULATION
   while(bar >= LastCountBar)
     {  
       Range = 0.0;
       AvgRange = 0.0;
       for(iii = 0; iii <= 9; iii++) 
           AvgRange += MathAbs(iHigh(symbol, timeframe, bar + iii) -
                               iLow(symbol, timeframe, bar + iii));
       //----
       Range = AvgRange / 10;
       iii = 0;
       TrueCount = 0;
       while(iii < 9 && TrueCount < 1)
         {
           if(MathAbs(iOpen(symbol, timeframe, bar + iii) -
                      iClose(symbol, timeframe, bar + iii)) >= Range*2.0) 
               TrueCount++;
           //----
           iii++;
         }
       if(TrueCount >= 1)
           MRO1 = bar + iii; 
       else 
           MRO1 = -1;
       //----
       iii = 0;
       TrueCount = 0;
       while(iii < 6 && TrueCount < 1)
         {
           if(MathAbs(iClose(symbol, timeframe, bar + iii + 3) -
                      iClose(symbol, timeframe, bar + iii)) >= Range*4.6) 
               TrueCount++;
           //----
           iii++;
         }
       if(TrueCount >= 1)
           MRO2 = bar + iii; 
       else 
           MRO2 = -1;
       //----
       if(MRO1 > -1)
           value11 = 3; 
       else 
           value11 = value10;
       if(MRO2 > -1)
           value11 = 4; 
       else 
           value11 = value10;
       //----
       value2 = 100 - MathAbs(iWPR(symbol, timeframe, value11, bar));
       //---- 
       val1 = 0;
       val2 = 0;
       InputBuffer[bar] = 0;
       //---- 
       if(value2 > x1[Number])
         {
           val1 = iLow (symbol, timeframe, bar);
           val2 = iHigh(symbol, timeframe, bar);
         }
       if(value2 < x2[Number])
         {
           val1 = iHigh(symbol, timeframe, bar);
           val2 = iLow(symbol, timeframe, bar);
         } 
       InputBuffer[bar]=val2-val1;
       bar--;
     }
   //----+  
   return(true);
  }
//+------------------------------------------------------------------+

Claro que esta função é mais difícil do que a descrita no final do artigo anterior. Mas enquanto o código fonte indicador for escrito e otimizado sem erros, o processo de criar essa função não será muito problemático!

Depois a função precisa ser testada para verificar a correspondência de seus valores com os valores do indicador, baseado na função que foi desenvolvida. Para isso, devemos criar novamente um verificador do Expert Advisor para a função Get_ASCTrend1Series():

//+------------------------------------------------------------------+
//|                                      Get_ASCTrend1SeriesTest.mq4 |
//|                      Copyright © 2007, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, MetaQuotes Software Corp."
#property link      "https://www.metaquotes.net/"
//---- INPUT PARAMETERS OF THE EA
extern bool NullBarRecount = true;
//---- indicator buffers
double IndBuffer0[];
double IndBuffer1[];
double IndBuffer2[];
//+------------------------------------------------------------------+
//| Get_ASCTrend1Series() functions                                  |
//+------------------------------------------------------------------+
#include <Get_ASCTrend1Series.mqh>
//+------------------------------------------------------------------+
//| Custom Expert initialization function                            |
//+------------------------------------------------------------------+
int init()
  {
//---- initialization end
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom Expert iteration function                                 |
//+------------------------------------------------------------------+
int start()
  {
//---- 
   double Ind_Velue,Resalt;
//---- 
   if(!Get_ASCTrend1Series(0, Symbol(), 0, NullBarRecount, 1, IndBuffer0))
       return(0);
   if(!Get_ASCTrend1Series(1, Symbol(), 240, NullBarRecount, 3, IndBuffer1))
       return(0);
   if(!Get_ASCTrend1Series(2, Symbol(), 1440, NullBarRecount, 5, IndBuffer2))
       return(0);
//---- getting indicator values for the test 0
   Ind_Velue = iCustom(NULL, 0, "ASCTrend1", 1, 1, 2) - 
               iCustom(NULL, 0, "ASCTrend1", 1, 0, 2); 
   Resalt = IndBuffer0[2] - Ind_Velue; 
   Print("0:     " + Ind_Velue + "    " + IndBuffer0[2] + 
         "    " + Resalt + "");
//---- getting indicator values for the test 1
   Ind_Velue = iCustom(NULL, 240, "ASCTrend1", 3, 1, 2) - 
               iCustom(NULL, 240, "ASCTrend1", 3, 0, 2); 
   Resalt = IndBuffer1[2] - Ind_Velue; 
   Print("H4:    " + Ind_Velue + "    " + IndBuffer1[2] + 
         "    " + Resalt + "");
//---- getting indicator values for the test 2
   Ind_Velue = iCustom(NULL, 1440, "ASCTrend1", 5, 1, 2) - 
               iCustom(NULL, 1440, "ASCTrend1", 5, 0, 2); 
   Resalt = IndBuffer2[2] - Ind_Velue; 
   Print("Daily: " + Ind_Velue + "    " + IndBuffer2[2] + 
         "    " + Resalt + "");
//----
   return(0);
  }
//+------------------------------------------------------------------+

Comece a testar este Expert Advisor no strategy tester e depois, verifique o arquivo de log para certificar-se que os valores da nossa função são totalmente idênticos aos dos indicadores em termos de preenchimento com os valores do buffer de indicador emulado!



Transformação Final do Código Inicial do Expert Advisor

E agora, finalmente, podemos transformar o código EA, substituindo chamadas personalizadas do indicador para chamadas personalizados da função do indicador:


//+------------------------------------------------------------------+
//|                                      NewASCTrend1RAVI_Expert.mq4 |
//|                             Copyright © 2006,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru"
//---- INPUT PARAMETERS
extern int RAVI_Timeframe = 240;
extern int ASCT_Timeframe = 1440;
//---- FILTER OF TRADE CALCULATION DIRECTION
extern int Buy_Sell_Custom = 2; // 0-Buy, 1-Sell, 2-Buy+Sell
//---- INPUT PARAMETERS OF EA FOR BUY TRADES 
extern double Money_Management_Up = 0.1;
extern int RISK_Up = 3;
extern int Period1_Up = 7; 
extern int Period2_Up = 65; 
extern int MA_Metod_Up = 0;
extern int PRICE_Up = 0;
extern int STOPLOSS_Up = 50;
extern int TAKEPROFIT_Up = 100;
//---- INPUT PARAMETERS OF EA FOR SELL TRADES 
extern double Money_Management_Dn = 0.1;
extern int RISK_Dn = 3;
extern int Period1_Dn = 7; 
extern int Period2_Dn = 65; 
extern int MA_Metod_Dn = 0;
extern int PRICE_Dn = 0;
extern int STOPLOSS_Dn = 50;
extern int TAKEPROFIT_Dn = 100;
//---- Emulated indicator buffers
double RAVI_Up[];
double RAVI_Dn[];
double ASCTrend1_Up[];
double ASCTrend1_Dn[];
//+------------------------------------------------------------------+
//| Get_ASCTrend1Series functions()                                  |
//+------------------------------------------------------------------+
#include <Get_ASCTrend1Series.mqh>
//+------------------------------------------------------------------+
//| Get_RAVISeries functions()                                       |
//+------------------------------------------------------------------+
#include <Get_RAVISeries.mqh>
//+------------------------------------------------------------------+
//| Custom Expert functions                                          |
//+------------------------------------------------------------------+
#include <Lite_EXPERT.mqh>
//+------------------------------------------------------------------+
//| Custom Expert initialization function                            |
//+------------------------------------------------------------------+
int init()
  {
//---- 
   if(RAVI_Timeframe != 1)
       if(RAVI_Timeframe != 5)
           if(RAVI_Timeframe != 15)
               if(RAVI_Timeframe != 30)
                   if(RAVI_Timeframe != 60)
                       if(RAVI_Timeframe != 240)
                           if(RAVI_Timeframe != 1440)
                               Print("Parameter RAVI_Timeframe cannot" + 
                                     " be equal to " +
                                     RAVI_Timeframe + "!!!");
//---- 
   if(ASCT_Timeframe != 1)
       if(ASCT_Timeframe != 5)
           if(ASCT_Timeframe != 15)
               if(ASCT_Timeframe != 30)
                   if(ASCT_Timeframe != 60)
                       if(ASCT_Timeframe != 240)
                           if(ASCT_Timeframe != 1440)
                               Print("Parameter ASCT_Timeframe cannot" + 
                                     " be equal to "+
                                     ASCT_Timeframe+"!!!");
//----                      
   if(RAVI_Timeframe > ASCT_Timeframe) 
       Print("Parameter ASCT_Timeframe should not be " + 
             "less than RAVI_Timeframe");                   
//---- initialization end
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom Expert iteration function                                 |
//+------------------------------------------------------------------+
int start()
  {
//---- Checking whether the bars number is enough for further calculation  
   if(iBars(NULL, ASCT_Timeframe) < 3 + RISK_Up*2 + 1 + 1)
       return(0);
   if(iBars(NULL, ASCT_Timeframe) < 3 + RISK_Dn*2 + 1 + 1)
       return(0);
//----
   if(iBars(NULL, RAVI_Timeframe) < MathMax(Period1_Up, Period2_Up + 4))
       return(0);
   if(iBars(NULL, RAVI_Timeframe) < MathMax(Period1_Dn, Period2_Dn + 4))
       return(0);
//---- Declaring variables for blocking zero bar recalculation 
   static int LastBars;
//---- Declaring logic variables for trend signals
   bool   BUY_Sign, SELL_Sign;
//---- CALCULATION OF INDICATOR VALUES AND LOADING THEM TO BUFFERS 
   if(LastBars != iBars(NULL, RAVI_Timeframe))
       switch(Buy_Sell_Custom)
         {
           case 0: 
             {
               Get_RAVISeries(0, Symbol(), RAVI_Timeframe, false, 
                              Period1_Up, Period2_Up, MA_Metod_Up,
                              PRICE_Up, RAVI_Up);
               //----
               Get_ASCTrend1Series(0, Symbol(), ASCT_Timeframe, 
                                   false, RISK_Up, ASCTrend1_Up);  
               break;
             }
           case 1: 
             {            
               Get_RAVISeries(1, Symbol(), RAVI_Timeframe, false, 
                              Period1_Dn, Period2_Dn, MA_Metod_Dn, 
                              PRICE_Dn, RAVI_Dn);
               //----
               Get_ASCTrend1Series(1, Symbol(), ASCT_Timeframe, 
                                   false, RISK_Dn, ASCTrend1_Dn); 
               break;
             }
           default:
             {
               Get_RAVISeries(0, Symbol(), RAVI_Timeframe, false,
                              Period1_Up, Period2_Up, MA_Metod_Up,
                              PRICE_Up, RAVI_Up);
               //----
               Get_ASCTrend1Series(0, Symbol(), ASCT_Timeframe, 
                                   false, RISK_Up, ASCTrend1_Up); 
               //----              
               Get_RAVISeries(1, Symbol(), RAVI_Timeframe, false,
                              Period1_Dn, Period2_Dn,MA_Metod_Dn,
                              PRICE_Dn,RAVI_Dn);
               //----
               Get_ASCTrend1Series(1, Symbol(), ASCT_Timeframe, 
                                   false, RISK_Dn, ASCTrend1_Dn); 
             }
         }
       //---- Variable initialization
       LastBars = iBars(NULL, RAVI_Timeframe);
       //---- DEFINING SIGNALS FOR TRADES 
       switch(Buy_Sell_Custom)
         {
       case 0: 
         {
           if(RAVI_Up[2] - RAVI_Up[3] < 0)
               if(RAVI_Up[1] - RAVI_Up[2] > 0)
                   if(ASCTrend1_Up[1] > 0)
                       BUY_Sign = true;
           break;
         }
       case 1: 
         {
           if(RAVI_Dn[2] - RAVI_Dn[3] > 0)
               if(RAVI_Dn[1] - RAVI_Dn[2] < 0)
                   if(ASCTrend1_Dn[1] < 0)
                       SELL_Sign = true;
           break;
         }
       default:
         {
           if(RAVI_Up[2] - RAVI_Up[3] < 0)
               if(RAVI_Up[1] - RAVI_Up[2] > 0)
                   if(ASCTrend1_Up[1] > 0)
                       BUY_Sign = true;
           //----+                  
           if(RAVI_Dn[2] - RAVI_Dn[3] > 0)
               if(RAVI_Dn[1] - RAVI_Dn[2] < 0)
                   if(ASCTrend1_Dn[1] < 0)
                       SELL_Sign = true;
         }
     }
//---- EXECUTING TRADES
   switch(Buy_Sell_Custom)
     {
       case 0: 
         {
           OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, 
                        TAKEPROFIT_Up);
           break;
         }
       case 1: 
         {
           OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn, 
                         TAKEPROFIT_Dn);
           break;
         }
       default:
         {
           OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, 
                        TAKEPROFIT_Up);
           OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn, 
                         TAKEPROFIT_Dn);
         }
     }
   return(0);
  }
//+------------------------------------------------------------------+

Claro que a última transformação do código EA precisava de algumas mudanças dentro da função Iniciar() na parte "DEFINIR SINAIS DE TRANSAÇÃO" por causa de alterações nas posições de células utilizadas nos buffers de indicador emulados em comparação com buffers de origem.

Testes dos Resultados do Expert Advisor de Origem e do ExpertAdvisor Final

Agora podemos carregar o EA em um strategy tester e comparar os resultados de sua operação no histórico com os mesmos resultados do EA antes da transformação. E não vemos nenhuma diferença nos resultados de trading no teste do EA pelo histórico em ambos os casos. Ambas variantes do EA, em mesmos períodos, fornecem resultados de testes absolutamente idênticos, os mesmos valores de variáveis externas são carregados no EA e o mesmo método de teste é usado.

Mas o que está claro à primeira vista é que em todas as situações, o Expert Advisor final funciona mais lentamente do que o EA fonte!







Qual a razão para um teste mais demorado de EA? Podemos supor que é de alguma forma conectado ao uso de emulação do modo do buffer de indicador e retorna valores de funções indicadoras em buffers por referência. Claro que tudo isso pode ser desenvolvido omitindo a emulação do modo indicador do funcionamento dos buffers. Você pode querer dar uma olhada no EA FastNewASCTrend1RAVI_Expert. mq4 e testá-lo. Mas neste caso, a situação é absolutamente a mesma - este EA funciona tão lentamente quanto o anterior. Assim, a seguinte conclusão é óbvia: no nosso caso simples caso de transformação de código usando indicadores de recurso lentos, sua substituição para funções personalizadas para uma operação mais rápida de EA é absolutamente irracional!

Conclusão

Para Expert Advisors que usam referências para abandonar o uso de indicadores de fonte lentos, a tarefa de torná-los mais rápido substituindo as chamadas do indicador personalizado por funções de chamadas personalizadas é geralmente inexplicável! No entanto, se alguém quiser desenvolver um Expert Advisor absolutamente autônomo, que consiste em um único arquivo e omite chamadas de indicadores personalizados, pode-se fazer isso. Mas isso requer muito esforço, porque esta tarefa não pode ser simplificada. Então, esse desejo deve ser apoiado por razões muito sérias.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1463

Base Teórica da Construção de Indicadores de cluster para FOREX Base Teórica da Construção de Indicadores de cluster para FOREX
Indicadores de cluster são conjuntos de indicadores que dividem pares de moedas correntes em moedas distintas. Os indicadores permitem traçar a flutuação da moeda corrente, determinar o potencial de formatação de novas tendências de moeda, receber sinais do mercado e seguir posições de médio e longo prazo.
Como desenvolver no MQL4 um Robô Negociador seguro e confiável Como desenvolver no MQL4 um Robô Negociador seguro e confiável
O artigo lida com os erros mais comuns que ocorrem no desenvolvimento e na utilização de um Expert Advisor. Também é descrito um sistema automatizado de trading exemplar.
Estratégia de Trading com Base na Análise de Pontos de Pivô Estratégia de Trading com Base na Análise de Pontos de Pivô
A análise de Pontos de Pivô (PP) é uma das estratégias mais simples e eficazes para mercados intraday de alta volatilidade. Ela é utilizada desde a era pré computador, quando os operadores que trabalham com ações não podiam usar nenhuma equipamento automatizado de análise de dados, exceto para a contagem de estruturas e aritmômetros.
Exibição simultânea dos sinais de vários indicadores dos quatro calendários Exibição simultânea dos sinais de vários indicadores dos quatro calendários
No trading manual você tem que ficar de olho nos valores de de vários indicadores. É um pouco diferente do trading mecânico. Se você tiver dois ou três indicadores e tiver escolhido somente um calendário para trading, não é uma tarefa complicada. Mas o que você faria se tivesse cinco ou seis indicadores e sua estratégia de trading necessitasse considerar os sinais em vários prazos?