English Русский 中文 Español Deutsch 日本語
preview
Funcionalidades do assistente MQL5 que você precisa conhecer (Parte 1): Análise de regressão

Funcionalidades do assistente MQL5 que você precisa conhecer (Parte 1): Análise de regressão

MetaTrader 5Testador | 8 setembro 2022, 08:54
863 0
Stephen Njuki
Stephen Njuki

1. Introdução

O assistente MQL5 permite que você crie e execute Expert Advisors rapidamente, pois a maioria dos aspectos secundários da negociação estão pré-codificados na biblioteca MQL5. Isso permite que os traders se concentrem em aspectos específicos do trading, como condições de entrada e saída. A biblioteca inclui algumas classes de sinais de entrada e de saída, como Accelerator Oscillator, Adaptive Moving Average e muitos outros. No entanto, elas se baseiam em indicadores atrasados, que são bastante difíceis de converter em estratégias de sucesso. A habilidade de criar seus próprios sinais é, portanto, particularmente importante. Neste artigo veremos como isto pode ser feito utilizando a análise de regressão.


2. Criando uma classe

2.1 De acordo com a Wikipedia, a análise de regressão é um conjunto de métodos estatísticos para averiguar o efeito de uma ou mais variáveis independentes sobre uma variável dependente. Pode ser útil para EAs personalizados, pois os dados de preços são uma série temporal. Essa análise verifica como os preços anteriores e as mudanças de preços influenciam os preços futuros e suas respectivas mudanças. A análise de regressão pode ser representada pela seguinte equação

onde y é dependente, portanto, a variável prevista depende de valores anteriores x, cada um com seu próprio coeficiente β e erro ε. Valores x e y podem ser considerados como os níveis de preços anteriores e previstos, respectivamente. Além dos níveis de preços, as variações de preços podem ser analisadas de forma semelhante. O y incógnito depende de xs, βs e ε. Destes, no entanto, apenas xs e β0 (a inserção y) são conhecidos. A intersecção y é conhecida porque é o preço logo antes de xi1. Por isso, precisamos encontrar o βs adequado para cada x e depois para εComo cada xi1 era yI na série temporal anterior, podemos encontrar uma solução para os valores de β usando equações simultâneas. Por exemplo, se a próxima alteração de preço depender apenas das duas alterações anteriores, nossa equação atual pode ser:   eqn_2
E as equações anteriores serão:  eqn_3

Como estamos estimando o erro ε separadamente, podemos resolver duas equações simultâneas para os valores de β. A numeração dos valores de x na fórmula da Wikipedia não segue o formato de "série" MQL5, ou seja, o x com o maior número é o mais recente. Por isso, renumerei os valores de x nas duas equações acima para mostrar como torná-los simultâneos. Começamos novamente com as interseções y de xi1 e xi0 para representar β0 na equação 1. A resolução de equações simultâneas é feita utilizando matrizes para aumentar a eficiência. As ferramentas necessárias estão disponíveis na biblioteca MQL5.

2.2 A biblioteca MQL5 tem uma extensa coleção de classes estatísticas e algoritmos gerais que eliminam explicitamente a necessidade de codificá-los do zero. O código da biblioteca é aberto, então você pode verificar tudo sozinho. Para nossos propósitos, usaremos a função RMatrixSolve na classe CDenseSolver no arquivo solvers.mqh. Esta função é baseada no uso da decomposição da matriz LU para encontrar de forma rápida e eficiente uma solução para os valores β. Artigos sobre este tópico podem ser encontrados no arquivo da MetaQuotes. A Wikipédia também tem uma explicação.

Antes de examinarmos as soluções para os valores de β, seria útil ver como a classe CExpertSignal funciona, pois é a base da nossa classe. Quase todas as classes de sinais de EAs que podem ser montadas no assistente possuem funções LongCondition e ShortCondition. Elas devolvem um valor que determina se devemos abrir uma posição longa ou curta, respectivamente. Esse valor deve ser um número inteiro no intervalo de 0 a 100 para corresponder aos parâmetros de entrada Signal_ThresholdOpen e Signal_ThresholdClose do assistente. Como regra geral, ao negociar, queremos que nossas condições de fechamento sejam menos conservadoras do que nossas condições de abertura. Isso significa que o limite de abertura será maior que o limite de fechamento. Assim, ao desenvolver um sinal, teremos parâmetros de entrada para o cálculo do limite de fechamento e parâmetros de entrada separados, mas semelhantes, para o limite de abertura. A escolha dos dados de entrada ao calcular a condição será determinada se tivermos posições abertas. Se tivermos posições abertas, usaremos os parâmetros de fechamento. Se não houver posições, usaremos os parâmetros de abertura. Abaixo está uma listagem da interface da classe de sinal do nosso Expert Advisor, que possui esses dois conjuntos de parâmetros.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CSignalDUAL_RA : public CExpertSignal
  {
protected:
   CiMA              m_h_ma;             // highs MA handle
   CiMA              m_l_ma;             // lows MA handle
   CiATR             m_ATR;
   //--- adjusted parameters
   int               m_size;
   double            m_open_determination,m_close_determination;
   int               m_open_collinearity,m_open_data,m_open_error;
   int               m_close_collinearity,m_close_data,m_close_error;
public:
                     CSignalDUAL_RA();
                    ~CSignalDUAL_RA();
   //--- methods of setting adjustable parameters
   
   //--- PARAMETER FOR SETTING THE NUMBER OF INDEPENDENT VARIABLES
   void              Size(int value)                  { m_size=value;                  }
   
   //--- PARAMETERS FOR SETTING THE OPEN 'THRESHOLD' FOR THE EXPERTSIGNAL CLASS
   void              OpenCollinearity(int value)      { m_open_collinearity=value;     }
   void              OpenDetermination(double value)  { m_open_determination=value;    }
   void              OpenError(int value)             { m_open_error=value;            }
   void              OpenData(int value)              { m_open_data=value;             }
   
   //--- PARAMETERS FOR SETTING THE CLOSE 'THRESHOLD' FOR THE EXPERTSIGNAL CLASS
   void              CloseCollinearity(int value)     { m_close_collinearity=value;    }
   void              CloseDetermination(double value) { m_close_determination=value;   }
   void              CloseError(int value)            { m_close_error=value;           }
   void              CloseData(int value)             { m_close_data=value;            }
   
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods for detection of levels of entering the market
   virtual bool      OpenLongParams(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      OpenShortParams(double &price,double &sl,double &tp,datetime &expiration);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);
protected:
   //--- method of initialization of the oscillator
   bool              InitRA(CIndicators *indicators);
   //--- methods of getting data
   int               CheckDetermination(int ind,bool close);
   double            CheckCollinearity(int ind,bool close);
   //
   double            GetY(int ind,bool close);
   double            GetE(int ind,bool close);
   
   double            Data(int ind,bool close);
   //
  };

Abaixo está uma listagem das funções LongCondition e ShortCondition. 

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CSignalDUAL_RA::LongCondition(void)
   {
      int _check=CheckDetermination(0,PositionSelect(m_symbol.Name()));
      if(_check>0){ return(_check); }
      
      return(0);
   }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CSignalDUAL_RA::ShortCondition(void)
   {
      int _check=CheckDetermination(0,PositionSelect(m_symbol.Name()));
      if(_check<0){ return((int)fabs(_check)); }
      
      return(0);
   }

 Para encontrar uma solução para os valores de β, usamos a função GetY. A listagem é mostrada abaixo.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CSignalDUAL_RA::GetY(int ind,bool close)
  {
      double _y=0.0;
      
      CMatrixDouble _a;_a.Resize(m_size,m_size);
      double _b[];ArrayResize(_b,m_size);ArrayInitialize(_b,0.0);
      
      for(int r=0;r<m_size;r++)
      {
         _b[r]=Data(r,close);
         
         for(int c=0;c<m_size;c++)
         {
            _a[r].Set(c,Data(r+c+1, close));
         }
      }
      
      int _info=0;
      CDenseSolver _S;
      CDenseSolverReport _r;
      double _x[];ArrayResize(_x,m_size);ArrayInitialize(_x,0.0);
      
      _S.RMatrixSolve(_a,m_size,_b,_info,_r,_x);
      
      for(int r=0;r<m_size;r++)
      {
         _y+=(Data(r,close)*_x[r]);
      }
      //---
      return(_y);
  }

A função Data alternará entre alterações no preço de fechamento do símbolo negociado ou alterações na média móvel do mesmo preço de fechamento. A opção utilizada será determinada pelo parâmetro de entrada m_open_data ou m_close_data dependendo de se estamos calculando um limite de abertura ou um limite de fechamento. A listagem de seleção de dados é mostrada na enumeração abaixo.

enum Edata
  {
      DATA_TREND=0,        // changes in moving average close
      DATA_RANGE=1         // changes in close
  };

Abaixo está a função Data que seleciona os dados.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CSignalDUAL_RA::Data(int ind,bool close)
   {
      if(!close)
      {
         if(Edata(m_open_data)==DATA_TREND)
         {
            m_h_ma.Refresh(-1);
            return((m_l_ma.Main(StartIndex()+ind)-m_l_ma.Main(StartIndex()+ind+1))-(m_h_ma.Main(StartIndex()+ind)-m_h_ma.Main(StartIndex()+ind+1)));
         }
         else if(Edata(m_open_data)==DATA_RANGE)
         {
            return((Low(StartIndex()+ind)-Low(StartIndex()+ind+1))-(High(StartIndex()+ind)-High(StartIndex()+ind+1)));
         }
      }
      else if(close)
      {
         if(Edata(m_close_data)==DATA_TREND)
         {
            m_h_ma.Refresh(-1);
            return((m_l_ma.Main(StartIndex()+ind)-m_l_ma.Main(StartIndex()+ind+1))-(m_h_ma.Main(StartIndex()+ind)-m_h_ma.Main(StartIndex()+ind+1)));
         }
         else if(Edata(m_close_data)==DATA_RANGE)
         {
            return((Low(StartIndex()+ind)-Low(StartIndex()+ind+1))-(High(StartIndex()+ind)-High(StartIndex()+ind+1)));
         }
      }
      
      return(0.0);
   }

Uma vez que temos os valores de β, podemos passar para o cálculo do erro.

2.3 O erro padrão, de acordo com a Wikipedia, é calculado usando a fórmula abaixo.

eqn_4  

Onde s é o desvio padrão e n é o tamanho da amostra. O erro serve como um lembrete de que nem todas as previsões, por mais completas que sejam, sempre serão completamente precisas. Devemos sempre esperar e considerar os erros de nossa parte. O desvio padrão mostrado na fórmula será medido entre nossos valores previstos e reais. Como comparação, também podemos observar a última diferença entre nossos valores previstos e reais. Estes dois parâmetros podem ser selecionados a partir da lista abaixo. 

enum Eerror
  {
      ERROR_LAST=0,        // use the last error
      ERROR_STANDARD=1     // use standard error
  }

A função GetE então retorna nossa estimativa de erro dependendo do parâmetro de entrada m_open_error ou m_close_error usando a fórmula acima. A listagem é mostrada abaixo.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CSignalDUAL_RA::GetE(int ind,bool close)
  {
      if(!close)
      {
         if(Eerror(m_open_error)==ERROR_STANDARD)
         {
            double _se=0.0;
            for(int r=0;r<m_size;r++) { _se+=pow(Data(r,close)-GetY(r+1,close),2.0); }
            _se=sqrt(_se/(m_size-1)); _se=_se/sqrt(m_size); return(_se);
         }
         else if(Eerror(m_open_error)==ERROR_LAST){ return(Data(ind,close)-GetY(ind+1,close)); }
      }
      else if(close)
      {
         if(Eerror(m_close_error)==ERROR_STANDARD)
         {
            double _se=0.0;
            for(int r=0;r<m_size;r++){  _se+=pow(Data(r,close)-GetY(r+1,close),2.0); }
            _se=sqrt(_se/(m_size-1)); _se=_se/sqrt(m_size); return(_se);
         }
         else if(Eerror(m_close_error)==ERROR_LAST){ return(Data(ind,close)-GetY(ind+1,close)); }
      }
//---
      return(Data(ind,close)-GetY(ind+1,close));
  }


Como já mencionado, o uso de m_open_error ou m_close_error será determinado se tivermos posições abertas. Uma vez que tenhamos uma estimativa do erro, podemos fazer uma previsão aproximada para y. No entanto, a análise de regressão também tem suas armadilhas. Uma delas é a habilidade das variáveis independentes de serem muito semelhantes e, portanto, prever em demasia o valor previsto. Este fenômeno é chamado de colinearidade e vale a pena aprofundar nele.

2.4 A colinearidade (definição da Wikipedia) pode ser caracterizada como uma forte relação entre duas ou mais variáveis independentes em um modelo de regressão múltipla (Investopedia). A colinearidade não tem uma fórmula como tal, e é encontrada pelo fator de inflação de variância (VIF, variance inflation factor). Este fator é medido por todas as variáveis independentes (x) para ajudar a entender o quão única cada uma dessas variáveis é na previsão de y. A fórmula necessária é mostrada abaixo. Nela, R é a regressão de cada variável independente em relação às demais.

eqn_5

Mantendo a colinearidade em mente, para nossos propósitos, vamos pegar a correlação inversa de Spearman entre os dois últimos conjuntos de dados de variáveis independentes e normalizá-la. O comprimento de nossos conjuntos de dados será dado pelo parâmetro de entrada m_size, que tem um comprimento mínimo de 3. Ao normalizar, simplesmente o subtraímos de dois e invertemos o resultado. Este peso normalizado pode então ser multiplicado pela estimativa de erro ou pelo valor previsto, ou ambos, ou não utilizado. Estes parâmetros estão indicados na lista abaixo.

enum Echeck
  {
      CHECK_Y=0,           // check for y only
      CHECK_E=1,           // check for the error only
      CHECK_ALL=2,         // check for both the y and the error
      CHECK_NONE=-1        // do not use collinearity checks
  };

A escolha do peso aplicado também é dada pelo parâmetro de entrada m_open_collinearity ou m_close_collinearity. Novamente, dependendo se as posições estão abertas. Abaixo está a listagem CheckCollinearity.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CSignalDUAL_RA::CheckCollinearity(int ind,bool close)
  {
      double _check=0.0;
      double _c=0.0,_array_1[],_array_2[],_r=0.0;
      ArrayResize(_array_1,m_size);ArrayResize(_array_2,m_size);
      ArrayInitialize(_array_1,0.0);ArrayInitialize(_array_2,0.0);
      for(int s=0; s<m_size; s++)
      {
         _array_1[s]=Data(ind+s,close);
         _array_2[s]=Data(m_size+ind+s,close);
      }
      _c=1.0/(2.0+fmin(-1.0,MathCorrelationSpearman(_array_1,_array_2,_r)));
      
      double   _i=Data(m_size+ind,close),    //y intercept
               _y=GetY(ind,close),           //product sum of x and its B coefficients
               _e=GetE(ind,close);           //error
      
      
      
      if(!close)
      {
         if(Echeck(m_open_collinearity)==CHECK_Y){ _check=_i+(_c*_y)+_e;          }
         else if(Echeck(m_open_collinearity)==CHECK_E){ _check=_i+_y+(_c*_e);     }
         else if(Echeck(m_open_collinearity)==CHECK_ALL){ _check=_i+(_c*(_y+_e)); }
         else if(Echeck(m_open_collinearity)==CHECK_NONE){ _check=_i+(_y+_e);     }
      }
      else if(close)
      {
         if(Echeck(m_close_collinearity)==CHECK_Y){ _check=_i+(_c*_y)+_e;          }
         else if(Echeck(m_close_collinearity)==CHECK_E){ _check=_i+_y+(_c*_e);     }
         else if(Echeck(m_close_collinearity)==CHECK_ALL){ _check=_i+(_c*(_y+_e)); }
         else if(Echeck(m_close_collinearity)==CHECK_NONE){ _check=_i+(_y+_e);     }
      }
      
//---
      return(_check);
  }

Além de verificar a colinearidade, há momentos em que a análise de regressão não é tão previsível quanto poderia ser devido a mudanças externas do mercado. Para acompanhar esses momentos e medir a capacidade das variáveis independentes de nosso sinal de influenciar nossa variável dependente, usamos o coeficiente de determinação.

2.5 O coeficiente de determinação é uma medida estatística que examina como as diferenças em uma variável podem ser explicadas por uma diferença em uma segunda variável ao prever o resultado de um determinado evento (Investopedia). A Wikipedia fornece uma definição mais abrangente e nossas fórmulas mostradas abaixo são retiradas dela.

  eqn_6

Fórmula da soma dos quadrados (onde y é o valor real e f é o valor previsto),  


eqn_7

A fórmula para a soma dos valores finais (onde y é o valor real e ÿ é a média móvel desses valores),  


eqn_8

O próprio coeficiente é R ao quadrado. 

O coeficiente mede até que ponto xs afeta y. Isso é importante porque, como mencionado, há momentos em que a regressão diminui, o que significa que é mais seguro nos afastar dos mercados. Ao rastrear isso por meio de um filtro, é mais provável que negociemos quando o sistema estiver sólido. Como regra geral, queremos que o coeficiente seja maior que 0, sendo 1 o valor ideal. O parâmetro de entrada usado para determinar nosso limite será m_open_determination ou m_close_determination, novamente dependendo do número de posições abertas. Se o coeficiente de determinação calculado pela função CheckDetermination abaixo for menor que este parâmetro, as condições de compra ou venda retornarão zero.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CSignalDUAL_RA::CheckDetermination(int ind,bool close)
  {
      int _check=0;
      m_h_ma.Refresh(-1);m_l_ma.Refresh(-1);
      double _det=0.0,_ss_res=0.0,_ss_tot=0.0;
      for(int r=0;r<m_size;r++)
      {
         _ss_res+=pow(Data(r,close)-GetY(r+1,close),2.0); 
         _ss_tot+=pow(Data(r,close)-((m_l_ma.Main(r)-m_l_ma.Main(r+1))-(m_h_ma.Main(r)-m_h_ma.Main(r+1))),2.0);
      }
      
      if(_ss_tot!=0.0)
      {
         _det=(1.0-(_ss_res/_ss_tot));
         if(_det>=m_open_determination)
         {
            double _threshold=0.0;
            for(int r=0; r<m_size; r++){ _threshold=fmax(_threshold,fabs(Data(r,close))); }
         
            double _y=CheckCollinearity(ind,close);
            
            _check=int(round(100.0*_y/fmax(fabs(_y),fabs(_threshold))));
         }
      }
//---
      return(_check);
  }

Assim que pudermos verificar o coeficiente de determinação, teremos um sinal de trabalho. Em seguida, devemos integrar este sinal no Expert Advisor usando o assistente MQL5.


3. Montando um EA mediante o assistente MQL5

3.1 Ao montar um Expert Advisor, uma lista de códigos auxiliares personalizados pode ser usada junto com o código do assistente MQL5. Isso é totalmente opcional e depende do estilo do trader. Para os propósitos deste artigo, vamos analisar a abertura de uma ordem pendente personalizada com base no símbolo ATR existente, bem como o traling de posições abertas com base no mesmo indicador. Não utilizaremos níveis de take-profit.

3.1.1  Ordens pendentes baseadas no ATR podem ser definidas sobrecarregando as funções OpenLongParams e OpenShortParams e configurando-as em nossa classe de sinais, como mostrado abaixo.

//+------------------------------------------------------------------+
//| Detecting the levels for buying                                  |
//+------------------------------------------------------------------+
bool CSignalDUAL_RA::OpenLongParams(double &price,double &sl,double &tp,datetime &expiration)
  {
   CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL;
//---
   if(general==NULL)
     {
      m_ATR.Refresh(-1);
      //--- if a base price is not specified explicitly, take the current market price
      double base_price=(m_base_price==0.0) ? m_symbol.Ask() : m_base_price;
      
      //--- price overload that sets entry price to be based on ATR
      price      =m_symbol.NormalizePrice(base_price-(m_price_level*(m_ATR.Main(0)/m_symbol.Point()))*PriceLevelUnit());
      
      sl         =0.0;
      tp         =0.0;
      expiration+=m_expiration*PeriodSeconds(m_period);
      return(true);
     }
//---
   return(general.OpenLongParams(price,sl,tp,expiration));
  }
//+------------------------------------------------------------------+
//| Detecting the levels for selling                                 |
//+------------------------------------------------------------------+
bool CSignalDUAL_RA::OpenShortParams(double &price,double &sl,double &tp,datetime &expiration)
  {
   CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL;
//---
   if(general==NULL)
     {
      m_ATR.Refresh(-1);
      //--- if a base price is not specified explicitly, take the current market price
      double base_price=(m_base_price==0.0) ? m_symbol.Bid() : m_base_price;
      
      //--- price overload that sets entry price to be based on ATR
      price      =m_symbol.NormalizePrice(base_price+(m_price_level*(m_ATR.Main(0)/m_symbol.Point()))*PriceLevelUnit());
      
      sl         =0.0;
      tp         =0.0;
      expiration+=m_expiration*PeriodSeconds(m_period);
      return(true);
     }
//---
   return(general.OpenShortParams(price,sl,tp,expiration));
  }

O Expert Advisor gerado pelo assistente MQL5 tem o parâmetro de entrada Signal_PriceLevel. Por padrão é zero, mas se lhe for atribuído um valor, ele ajusta a distância em pontos do preço do símbolo negociado em relação ao preço atual ao qual a ordem a mercado será colocada. Quando este parâmetro é negativo, são colocadas ordens stop. Ao colocar ordens limitadas positivas o parâmetro tem dados do tipo double. Para nossos propósitos, este parâmetro será uma fração ou um múltiplo dos pontos de preço atuais no ATR.

3.1.2 A classe de trailing ATR também é uma classe CExpertTrailing personalizada que usa o ATR para definir e mover o stop loss. A implementação de suas principais funções é apresentada na listagem abaixo.

//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for long position.          |
//+------------------------------------------------------------------+
bool CTrailingATR::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
   if(position==NULL)
      return(false);
//---
   m_ATR.Refresh(-1);
   double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
   
   //--- sl adjustment to be based on ATR
   double new_sl=NormalizeDouble(level-(m_atr_weight*(m_ATR.Main(0)/m_symbol.Point())),m_symbol.Digits());
   
   double pos_sl=position.StopLoss();
   double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
//---
   sl=EMPTY_VALUE;
   tp=EMPTY_VALUE;
   if(new_sl>base && new_sl<level)
      sl=new_sl;
//---
   return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for short position.         |
//+------------------------------------------------------------------+
bool CTrailingATR::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
   if(position==NULL)
      return(false);
//---
   m_ATR.Refresh(-1);
   double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
   
   //--- sl adjustment to be based on ATR
   double new_sl=NormalizeDouble(level+(m_atr_weight*(m_ATR.Main(0)/m_symbol.Point())),m_symbol.Digits());
   
   double pos_sl=position.StopLoss();
   double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
//---
   sl=EMPTY_VALUE;
   tp=EMPTY_VALUE;
   if(new_sl<base && new_sl>level)
      sl=new_sl;
//---
   return(sl!=EMPTY_VALUE);
  }

m_atr_weight será um parâmetro otimizável, como m_price_level, que define o quão perto podemos rastrear as posições abertas.

  3.2 A montagem posterior no assistente é bastante simples. O único passo visível é a seleção de nosso sinal, como mostrado abaixo.

wizard_1_crop


 

Além da adição de nosso método de rastreamento personalizado.

wizard_2_crop


 

4. Testando no testador de estratégia

4.1 Depois que o EA é montado com o assistente MQL5, procede-se a uma compilação para criar o arquivo do EA. Isto também garantirá que não haja erros em nosso código.

4.2 Os parâmetros de entrada padrão do EA também devem ser definidos na guia de parâmetros de entrada do testador de estratégia. Você precisa garantir que Signal_TakeLevel e Signal_StopLevel sejam zero. Isto porque, para os fins deste artigo, a saída só é definida pelo traling stop ou pelo parâmetro de entrada Signal_ThresholdClose.

4.3 Idealmente, a otimização deve ser realizada em ticks reais da corretora com a qual você vai negociar. Neste artigo otimizamos com base no EURUSD, período gráfico de 4 horas, em forma de V, de 2018.01.01 a 2021.01.01. Para comparação, executaremos duas otimizações: a primeira usará apenas ordens a mercado e a segunda permitirá ordens pendentes. Eu conscientemente escrevi "permitirá". Ainda consideraremos apenas o uso de ordens a mercado, pois Signal_PriceLevel pode ser igual a zero, pois a otimização passa de um valor negativo para um positivo. A otimização pode ser configurada antecipadamente em caso de uso de ordens pendentes. A única diferença da variante que não usa ordens pendentes é que, neste último caso, o parâmetro de entrada Signal_PriceLevel permanecerá 0 e não fará parte dos dados de entrada otimizados. 


4.4 Abaixo estão os resultados de nossa otimização. Primeiro, é um relatório e uma curva de ações dos melhores resultados de negociação apenas com ordens a mercado.



Parte do relatório 1

E um relatório e curva de capital líquido semelhantes ao usar ordens pendentes.




Parte do relatório 2

Nosso sinal de regressão parece se beneficiar do uso de ordens pendentes, pois tem menos rebaixamentos durante lucros ligeiramente menores. Você pode tentar melhorar o sistema, por exemplo, alterando a classe do traling stop ou o tipo de gerenciamento de dinheiro. Para fins de teste, usamos uma porcentagem de margem fixa e otimizamos nosso conjunto de critérios para "complex criterion". Eu recomendo testar o máximo possível com dados históricos de ticks e fazer testes forward suficientes antes de aplicar recomendações que estão além do escopo deste artigo.

 

5. Considerações finais

5.1 O assistente MQL5 é uma ferramenta poderosa que deve estar no arsenal de todo trader. Neste artigo, vimos como usar alguns dos conceitos estatísticos da análise de regressão, como colinearidade e coeficiente de determinação, como base para um sistema de negociação robusto. As próximas etapas serão testes extensivos com dados históricos de ticks e explorar se esse sinal pode ser combinado com outros sinais exclusivos com base na experiência do trader ou nos sinais integrados da biblioteca MQL5 para criar um sistema de negociação mais completo. Como os demais artigos futuros desta série, este artigo não oferece um graal, mas descreve um processo que pode ser ajustado de acordo com a abordagem do trader aos mercados. Obrigado pela sua atenção!


Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/11066

Arquivos anexados |
TrailingATR.mqh (6.24 KB)
SignalDUAL_RA.mqh (18.75 KB)
Ciência de Dados e Aprendizado de Máquina (Parte 04): Previsão de um crash no mercado de ações Ciência de Dados e Aprendizado de Máquina (Parte 04): Previsão de um crash no mercado de ações
Neste artigo, eu tentarei usar nosso modelo logístico para prever o crash do mercado de ações com base nos fundamentos da economia dos EUA, nos concentraremos nas ações do NETFLIX e da APPLE, usando os crashes anteriores do mercado de 2019 e 2020, vamos ver como nosso modelo se comportará nas atuais desgraças e tristezas.
Desenvolvendo um EA de negociação do zero (Parte 30): CHART TRADE agora como indicador ?! Desenvolvendo um EA de negociação do zero (Parte 30): CHART TRADE agora como indicador ?!
Trazendo o Chart Trade de volta a ativa ... mas agora ele será um indicador e poderá ou não estar presente no gráfico.
Desenvolvendo um EA de negociação do zero (Parte 31): Em direção ao futuro (IV) Desenvolvendo um EA de negociação do zero (Parte 31): Em direção ao futuro (IV)
Vamos continuar a retirar coisas de dentro do EA. Mas no entanto este será o último artigo desta serie. A última coisa que será de fato removida, nesta serie de artigos, é o sistema de som. Talvez isto venha a lhe dar um nó no cérebro, caso você não tenha acompanhado estes artigos.
Como desenvolver um sistema de negociação baseado no indicador Acumulação/Distribuição (AD) Como desenvolver um sistema de negociação baseado no indicador Acumulação/Distribuição (AD)
Bem-vindo ao novo artigo da nossa série sobre como aprender a projetar sistemas de negociação com base nos indicadores técnicos mais populares. Neste artigo, nós aprenderemos sobre um novo indicador técnico chamado Acumulação/Distribuição e descobriremos como desenvolver um sistema de negociação em MQL5 baseado nas estratégias simples com o AD.