English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Filtragem de Sinais com Base em Dados Estatísticos de Correlação de Preço

Filtragem de Sinais com Base em Dados Estatísticos de Correlação de Preço

MetaTrader 5Negociação | 17 fevereiro 2014, 16:27
1 258 0
Михаил Тарачков
Михаил Тарачков

Como Isso Começou

A ideia que levou a escrever este artigo surgiu depois de eu ter lido o livro de Larry Williams "Long-Term Secrets to Short-Term Trading", no qual o detentor do recorde mundial em investimentos (em 1987 ele aumentou o seu capital em 11.000%) está desfazendo completamente os mitos de "... professores universitários e outros acadêmicos, que são ricos em teoria e pobres em conhecimento do mercado..." sobre a ausência de qualquer correlação entre o comportamento passado dos preços e as tendências futuras.

Se você jogar uma moeda 100 vezes, ela cairá 50 vezes cara e 50 vezes - coroa. Com cada lance sucessivo, a probabilidade de cara é de 50%, o mesmo vale para coroa. A probabilidade não muda de lance a lance, porque o jogo é aleatório e não tem memória. Suponha que os mercados estejam se comportando como uma moeda, de uma forma caótica.

Consequentemente, quando uma nova barra aparece, um preço tem igual oportunidade de ir para cima ou para baixo, e as barras anteriores não afetam nem mesmo um pouco a atual. Idílico! Crie um sistema de negociação, defina obter lucro maior do que interromper perda (ou seja, defina a expectativa matemática para a zona positiva), e o truque está feito. Simplesmente de tirar o fôlego. No entanto, o problema é que a nossa suposição sobre o comportamento do mercado não é bem verdadeira. Francamente falando, é um absurdo! E irei provar.

Vamos criar um template de Expert Advisor usando o MQL5 Wizard e usando intervenções alfanuméricas simples, apresentando-o em condições adequadas para o cumprimento da tarefa. Vamos codificar um Expert Advisor para simular uma compra que segue uma, duas e três barras fechadas. Simulação quer dizer que o programa irá simplesmente lembrar os parâmetros das barras analisadas. Enviar ordens (uma forma mais usual), neste caso, não vai funcionar, porque os spreads e swaps são capazes de questionar a confiança das informações recebidas.

Aqui está o código:

//+------------------------------------------------------------------+
//|                                                     explorer.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//---Variables---
double profit_percent,open_cur,close_cur;
double profit_trades=0,loss_trades=0,day_cur,hour_cur,min_cur,count;
double open[],close[];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
/* Calculate percent of closures with increase from the total number */
   profit_percent=NormalizeDouble(profit_trades*100/(profit_trades+loss_trades),2);
   Print("Percent of closures with increase ",profit_percent,"%");   // Enter data to the Journal
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---find out the time---
   MqlDateTime time;                        // Create a structure to store time
   TimeToStruct(TimeCurrent(),time);         // Structuring the data
   day_cur=time.day_of_week;              // Receive the value of the current day
   hour_cur=time.hour;                    // Receive the current hour
   min_cur=time.min;                      // Receive the current minute
//---Find out the prices---
   CopyOpen(NULL,0,0,4,open);ArraySetAsSeries(open,true);
   CopyClose(NULL,0,0,4,close);ArraySetAsSeries(close,true);

   if(close[1]<open[1]/*&&close[2]<open[2]&&close[3]<open[3]*/ && count==0) // If it closed with a loss
     {
      open_cur=open[0];                   // Remember open price of the current bar
      count=1;
     }
   if(open_cur!=open[0] && count==1)      // The current bar has closed
     {
      close_cur=close[1];                 // Remember the close price of the formed bar
      count=0;
      if(close_cur>=open_cur)profit_trades+=1;  // If the close price is higher than open,
      else loss_trades+=1;                      // +1 to closures with profit, otherwise +1 to closures with loss
     }
  }
//+------------------------------------------------------------------+
    

O teste será realizado em EUR/USD, no intervalo de 1 de janeiro de 2000 a 31 de dezembro de 2010:

Figura 1. A porcentagem de fechamentos com o aumento.

Figura 1. A porcentagem de encerramentos com o aumento.

(A primeira coluna mostra os dados para todo o período, a segunda, terceira e quarta - depois de um simples, duplo e triplo fechamento)

Era isso que eu estava falando! As barras anteriores têm um impacto bastante significativo sobre a atual, porque o preço está sempre em busca de ganhar as perdas.


Outro passo adiante

ótimo! Uma vez que temos a certeza de que o comportamento dos preços não é acidental, devemos usar este fato surpreendente o mais breve possível. Claro, não é suficiente para um sistema de negociação independente, mas vai ser uma bela ferramenta que pode livrá-lo de sinais tediosos e geralmente errados. Vamos implementá-la!

Então, é isso que precisamos:

  1. Um sistema de auto-negociação, mostrando resultados positivos, pelo menos para o ano passado.
  2. Alguns exemplos divertidos que confirmam a presença de correlações no comportamento dos preços.

Encontrei várias ideias úteis no livro de L Williams. Vou compartilhar algumas com você.

A estratégia TDW (Trade Day Of Week - Dia de Negociação da Semana). Ela nos permitirá ver o que acontecerá se alguns dos dias da semana apenas comprarmos, e nos outros - apenas abrir posições curtas. Afinal, podemos supor que o preço dentro de um dia cresce em maior porcentagem dos casos do que dentro do outro. Qual a razão para isso? A situação geopolítica, estatísticas macroeconômicas, ou, como está escrito no livro de A. Elder, segundas e terças são os dias de leigos, enquanto que as quintas e sextas são dos profissionais? Vamos tentar entender.

Primeiro, vamos só por cada dia da semana e depois só vender. No final do estudo, vamos combinar os melhores resultados, e este será um filtro para o nosso sistema de negociação. A propósito, eu tenho algumas palavras a dizer sobre o assunto. é um clássico puro!

O sistema é baseado em dois MAs e MACDake. Sinais:

  1. Se a média móvel rápida cruza a lenta de baixo para cima e o histograma MACD está abaixo da linha zero, então COMPRE.
  2. Se a média móvel rápida cruza a lenta de cima para baixo e MACD está acima de zero, então VENDA.

Saia de uma posição utilizando um limite móvel a partir de um ponto. O lote está fixado - 0,1.

Para fins de conveniência, eu coloquei a classe do Expert Advisor em um arquivo de cabeçalho separado:

//+------------------------------------------------------------------+
//|                                                       moving.mqh |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| Класс my_expert                                                  |
//+------------------------------------------------------------------+
class my_expert
  {                                                  // Creating a class
   // Closed class members
private:
   int               ma_red_per,ma_yel_per;          // Periods of MAs
   int               ma_red_han,ma_yel_han,macd_han; // Handles
   double            sl,ts;                          // Stop orders
   double            lots;                           // Lot
   double            MA_RED[],MA_YEL[],MACD[];       // Arrays for the indicator values
   MqlTradeRequest   request;                         // Structure of a trade request
   MqlTradeResult    result;                          // Structure of a server response
                                                    // Open class members   
public:
   void              ma_expert();                                   // Constructor
   void get_lot(double lot){lots=lot;}                               // Receiving a lot  
   void get_periods(int red,int yel){ma_red_per=red;ma_yel_per=yel;} // Receiving the periods of MAs
   void get_stops(double SL,double TS){sl=SL;ts=TS;}                  // Receiving the values of stops
   void              init();                                         // Receiving the indicator values
   bool              check_for_buy();                                // Checking for buy
   bool              check_for_sell();                               // Checking for sell
   void              open_buy();                                     // Open buy
   void              open_sell();                                    // Open sell
   void              position_modify();                              // Position modification
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
/* Function definition */
//---Constructor---
void my_expert::ma_expert(void)
  {
//--- Reset the values of variables
   ZeroMemory(ma_red_han);
   ZeroMemory(ma_yel_han);
   ZeroMemory(macd_han);
  }
//---The function for receiving the indicator values---
void  my_expert::init(void)
  {
   ma_red_han=iMA(_Symbol,_Period,ma_red_per,0,MODE_EMA,PRICE_CLOSE); // Handle of the slow MA
   ma_yel_han=iMA(_Symbol,_Period,ma_yel_per,0,MODE_EMA,PRICE_CLOSE); // Handle of the fast MA
   macd_han=iMACD(_Symbol,_Period,12,26,9,PRICE_CLOSE);               // Handle of MACDaka
//---Copy data into arrays and set indexing like in a time-series---
   CopyBuffer(ma_red_han,0,0,4,MA_RED);
   CopyBuffer(ma_yel_han,0,0,4,MA_YEL);
   CopyBuffer(macd_han,0,0,2,MACD);
   ArraySetAsSeries(MA_RED,true);
   ArraySetAsSeries(MA_YEL,true);
   ArraySetAsSeries(MACD,true);
  }
//---Function to check conditions to open buy---   
bool my_expert::check_for_buy(void)
  {
   init();  //Receive values of indicator buffers
/* If the fast MA has crossed the slow MA from bottom up between 2nd and 3rd bars, 
   and there was no crossing back. MACD-hist is below zero */
   if(MA_RED[3]>MA_YEL[3] && MA_RED[1]<MA_YEL[1] && MA_RED[0]<MA_YEL[0] && MACD[1]<0)
     {
      return(true);
     }
   return(false);
  }
//----Function to check conditions to open sell---
bool my_expert::check_for_sell(void)
  {
   init();  //Receive values of indicator buffers
/* If the fast MA has crossed the slow MA from up downwards between 2nd and 3rd bars,
  and there was no crossing back. MACD-hist is above zero */
   if(MA_RED[3]<MA_YEL[3] && MA_RED[1]>MA_YEL[1] && MA_RED[0]>MA_YEL[0] && MACD[1]>0)
     {
      return(true);
     }
   return(false);
  }
//---Open buy---
/* Form a standard trade request to buy */
void my_expert::open_buy(void)
  {
   request.action=TRADE_ACTION_DEAL;
   request.symbol=_Symbol;
   request.volume=lots;
   request.price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   request.sl=request.price-sl*_Point;
   request.tp=0;
   request.deviation=10;
   request.type=ORDER_TYPE_BUY;
   request.type_filling=ORDER_FILLING_FOK;
   OrderSend(request,result);
   return;
  }
//---Open sell---
/* Form a standard trade request to sell */
void my_expert::open_sell(void)
  {
   request.action=TRADE_ACTION_DEAL;
   request.symbol=_Symbol;
   request.volume=lots;
   request.price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   request.sl=request.price+sl*_Point;
   request.tp=0;
   request.deviation=10;
   request.type=ORDER_TYPE_SELL;
   request.type_filling=ORDER_FILLING_FOK;
   OrderSend(request,result);
   return;
  }
//---Position modification---
void my_expert::position_modify(void)
  {
   if(PositionGetSymbol(0)==_Symbol)
     {     //If a position is for our symbol
      request.action=TRADE_ACTION_SLTP;
      request.symbol=_Symbol;
      request.deviation=10;
      //---If a buy position---
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
        {
/* if distance from price to stop loss is more than trailing stop
   and the new stop loss is not less than the previous one */
         if(SymbolInfoDouble(Symbol(),SYMBOL_BID)-PositionGetDouble(POSITION_SL)>_Point*ts)
           {
            if(PositionGetDouble(POSITION_SL)<SymbolInfoDouble(Symbol(),SYMBOL_BID)-_Point*ts)
              {
               request.sl=SymbolInfoDouble(Symbol(),SYMBOL_BID)-_Point*ts;
               request.tp=PositionGetDouble(POSITION_TP);
               OrderSend(request,result);
              }
           }
        }
      //---If it is a sell position---                
      else if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
        {
/*  if distance from price to stop loss is more than the trailing stop value
   and the new stop loss is not above the previous one. Or the stop loss from the moment of opening is equal to zero */
         if((PositionGetDouble(POSITION_SL)-SymbolInfoDouble(Symbol(),SYMBOL_ASK))>(_Point*ts))
           {
            if((PositionGetDouble(POSITION_SL)>(SymbolInfoDouble(Symbol(),SYMBOL_ASK)+_Point*ts)) || 
               (PositionGetDouble(POSITION_SL)==0))
              {
               request.sl=SymbolInfoDouble(Symbol(),SYMBOL_ASK)+_Point*ts;
               request.tp=PositionGetDouble(POSITION_TP);
               OrderSend(request,result);
              }
           }
        }
     }
  }
//+------------------------------------------------------------------

Minhas humildes reverências ao autor do artigo "Writing an Expert Advisor using the MQL5 Object-Oriented Approach". O que eu faria sem ele! Recomendo a leitura deste artigo para quem não conhece muito bem esse mal, mas tem programação orientada a objetoextremamente funcional.

Adicionar o arquivo com a classe no código principal do Expert Advisor? Crie um objeto e inicie as funções:

//+------------------------------------------------------------------+
//|                                                       Moving.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//---Include a file with the class---
#include <moving.mqh>
//---External Variables---
input int MA_RED_PERIOD=7; // The period of a slow MA
input int MA_YEL_PERIOD=2; // The period of a fast MA
input int STOP_LOSS=800;   // Stop loss
input int TRAL_STOP=800;   // Trailing stop
input double LOTS=0.1;     // Lot
//---Create an object---
my_expert expert;
//---Initialize the MqlDataTime structure---
MqlDateTime time;
int day_of_week;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---Initialize the EA
   expert.get_periods(MA_RED_PERIOD,MA_YEL_PERIOD);   // Set the MA periods
   expert.get_lot(LOTS);                              // Set the lot
   expert.get_stops(STOP_LOSS,TRAL_STOP);             // Set stop orders  
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   TimeToStruct(TimeCurrent(),time);
   day_of_week=time.day_of_week;
   if(PositionsTotal()<1)
     {
      if(day_of_week==5 && expert.check_for_buy()==true){expert.open_buy();}
      else if(day_of_week==1 && expert.check_for_sell()==true){expert.open_sell();}
     }
   else expert.position_modify();
  }
//+------------------------------------------------------------------+

Pronto! Eu gostaria de observar algumas características especiais. Para identificar os dias da semana a um nível de software, eu usei a estrutura MqlDateTime. Primeiro, vamos transformar a hora atual do servidor em um formato estruturado. Obtemos um índice do dia atual (1-segunda, ..., 5-sexta) e o comparamos com o valor que nós definimos.

Experimente! A fim de não sobrecarregá-lo com pesquisas tediosas e dígitos extras, estou trazendo todos os resultados na tabela.

Aqui está:

Tabela 1. Resumo de Compras em cada dia da semana

Tabela 1. Resumo de Compras em cada dia da semana

Tabela 2. Resumo de Vendas em cada dia da semana

Tabela 2. Resumo de Vendas em cada dia da semana

Os melhores resultados são destacados em verde, os piores são de cor laranja.

Eu fiz uma ressalva, que após as ações descritas acima o sistema deve garantir lucro em combinação com o baixo levantamento relativo, uma boa porcentagem de negociações ganhas (aqui, quanto menos negociações, melhor) e um nível relativamente elevado de lucro por operação.

Obviamente, o sistema mais efetivo é comprar na sexta-feira e vender na segunda-feira. Combine ambas dessas condições:

if(PositionsTotal()<1){
      if(day_of_week==5&&expert.check_for_buy()==true){expert.open_buy();}
      else if(day_of_week==1&&expert.check_for_sell()==true){expert.open_sell();}}
   else expert.position_modify();

Agora, o Expert Advisor abre posições em ambas as direções, mas em dias estritamente definidos. Para maior clareza, vou desenhar os diagramas obtidos com e sem o filtro:

Figura 2. Os resultados do EA testando sem usar um filtro (EURUSD, H1, 01.01.2010-31.12.2010,)

Figura 2. Os resultados do EA testando sem usar um filtro (EURUSD, H1, 01.01.2010-31.12.2010,)

Figura 3. Os resultados do EA testado usando o filtro (EURUSD, H1, 01.01.2010-31.12.2010,)

Figura 3. Os resultados do EA testado usando o filtro (EURUSD, H1, 01.01.2010-31.12.2010)

Você gostou do resultado? Ao utilizar o filtro, o sistema de negociação tornou-se mais estável. Antes das modificações, o Expert Advisor aumentava principalmente o equilíbrio na primeira metade do período de testes, após o "upgrade" vai aumentando em todo o período.

Nós comparamos os relatórios:

Tabela 3. Resultados do teste antes e depois de utilizar o filtro

Tabela 3. Resultados do teste antes e depois de utilizar o filtro

O único fator angustiante, que não pode ser ignorado, é a queda do lucro líquido em cerca de 1000 USD (26%). Mas estamos reduzindo o número de negociações em quase 3,5 vezes, ou seja, reduzindo significativamente, em primeiro lugar, o potencial para fazer uma transação negativa e, em segundo, as despesas para o spread (218 * 2-62 * 2 = 312 USD e é só para EUR / USD). A porcentagem de vitórias é aumentada para 57%, o que já é significativo. Enquanto o lucro por transação aumenta em cerca de 14% para 113 USD. Como L.Williams diria: "Esta é a quantia que vale negociar!"


Conclusão

Os preços não se comportam de forma aleatória - é um fato. Esse fato pode e deve ser usado. Eu dei apenas um exemplo, que é uma pequena fração das inúmeras variações e técnicas que podem melhorar o desempenho do seu sistema de negociação. No entanto, essa diversidade esconde um vício. Nem todo filtro pode ser integrado, por isso deve ser escolhido com cuidado, pensando em todos os cenários possíveis.

Não se esqueça que não importa o quão perfeito o filtro seja, ele elimina negócios rentáveis​ também, ou seja, seu lucro... Boa sorte!

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

Arquivos anexados |
explorer.mq5 (2.84 KB)
moving.mq5 (2.28 KB)
moving.mqh (6.98 KB)
3 Métodos de Aceleração de Indicadores através do Exemplo da Regressão Linear 3 Métodos de Aceleração de Indicadores através do Exemplo da Regressão Linear
O artigo lida com os métodos de otimização de algorítimos computacionais de indicadores. Todos encontrarão um método que seja melhor para suas necessidades. Três métodos são descritos aqui. Um deles é bastante simples, o outro requer conhecimento sólido em matemática e o último requer um pouco de perspicácia. Indicadores ou o design do terminal do MetaTrader 5 são usados para realizar a maioria dos métodos descritos. Os métodos são bastante universais e podem ser usados não apenas para aceleração do cáluclo de regressão linar, mas também para muitos outros indicadores.
O papel das distribuições estatísticas no trabalho de negociação O papel das distribuições estatísticas no trabalho de negociação
Este artigo é uma continuação lógica do meu artigo de Distribuições de probabilidade estatística em MQL5 que apresenta as classes para trabalhar com algumas distribuições estatísticas teóricas. Agora que temos uma base teórica, sugiro que devemos prosseguir diretamente para conjuntos de dados reais e tentar fazer algum uso informativo desta base.
Distribuições de probabilidade estatística em MQL5 Distribuições de probabilidade estatística em MQL5
O artigo aborda as distribuições de probabilidade (normal log-normal, binominal, logística, exponencial, distribuição de Cauchy, distribuição T de Student, distribuição Laplace, distribuição Poisson, distribuição Secante Hiperbólica, distribuição Beta e Gama) de variáveis aleatórias usadas nas Estatísticas Aplicadas. Também apresenta classes para lidar com estas distribuições.
Usando Pseudo-modelos como Alternativa para Modelos C++ Usando Pseudo-modelos como Alternativa para Modelos C++
O artigo descreve uma forma de programação sem usar templates, mas mantendo o estilo de programação inerente a eles. Ele nos diz sobre a implementação de templares usando métodos personalizados e possui um script pronto para uso anexo para criação de código com base de templates especificados.