English Русский 中文 Español Deutsch 日本語
Otimização Visual de Indicador e Sinal de Rentabilidade

Otimização Visual de Indicador e Sinal de Rentabilidade

MetaTrader 4Exemplos | 4 novembro 2015, 15:34
885 0
Sergey Kravchuk
Sergey Kravchuk

Este artigo é uma continuação e desenvolvimento de meu artigo anterior "Testes Visuais de Rentabilidade dos Indicadores e Alertas". Tendo acrescentado alguma interatividade com o processo de mudança de parâmetro e reformulado os objetivos do estudo, além de obter uma nova ferramenta que mostra os potenciais resultados com base nos sinais utilizados, também permite que você obtenha imediatamente um layout de operações, gráfico do saldo e o resultado final da negociação, movendo controles deslizantes virtuais que funcionam como controladores para os valores dos parâmetros do sinal no gráfico principal.


Introdução

Em primeiro lugar, um aviso a todos os caçadores do Graal e censuradores por aí a fora: assim como a ferramenta descrita no artigo anterior, este não é de modo algum uma varinha mágica que irá ajudá-lo a evitar perdas por completo e só obter lucro. É apenas uma ferramenta que permite calcular rapidamente e exibir os resultados de uma forma visual prática. Os desenhos do indicador devem ser considerados como um alimento à análise do trader sobre as táticas de negociação e sinais utilizados. Este indicador pode tornar-se uma ferramenta bastante útil na negociação a curto prazo (especialmente intraday).

A idéia de reformular o indicador antigo e dar-lhe uma nova forma surgiu de um comentário ingênuo e claramente sincero que foi postado com a descrição de um Expert Advisor num dos nossos tópicos do fórum: "Ele tem feito bem ao longo de 2009. Até agora, eu estou satisfeito. Para facilitar o monitoramento do sinal que eu tenho ... " O Expert Advisor realmente teve um bom desempenho negociando o símbolo e o timeframe que o autor da postagem especificou. Mas qualquer tentativa de alterar os parâmetros iria transformar uma boa performance numa assassina indisfarçável que estaria perdendo todo o depósito num instante. Embora o autor do Expert Advisor não propôs usá-lo em negociação ao vivo, um pensamento ficou preso na minha mente - além de como verificar os resultados da negociação em potencial, como avaliar o comportamento da negociação e a estabilidade dos resultados? Eu queria fazê-lo rápido e óbvio para poder demonstrar visualmente a ineficácia de alguns sinais e táticas de negociação. Também outro pensamento estava assombrando minha mente: o Expert Advisor poderia render um lucro decente de negociação com os parâmetros existentes? E se eu pudesse negociar manualmente, eu ficaria muito feliz com os resultados? Os resultados poderiam ser ainda melhorados? De um modo geral o problema parecia interessante "em si" e eu comecei a olhar para as formas de resolvê-lo.


Definição do Problema

Ficou claro que a solução deveria ser baseada no meu indicador do artigo "Testes Visuais de Rentabilidade dos Indicadores e Alertas", ou seja, a maior parte do trabalho já havia sido feito e era necessário apenas uma atualização. O que faltou na aplicação anterior? Claramente foi um prático mecanismo de seleção dos parâmetros. Seria muito trabalhoso fazer alterações todas as vezes que verificássemos os parâmetros do indicador e então analisássemos os resultados das figuras e linhas nas ordens usando os dados do histórico. Isso é compreensível - o indicador original visava verificar sinais prontos, enquanto que neste caso foi necessário algo mais. O que poderia ser feito? Aqueles que usam ativamente o Testador de Estratégia em MT devem ter uma idéia muito clara sobre isso. Para avaliar os resultados das negociações é preciso acima de tudo gráficos do saldo e a possibilidade de modificar os parâmetros iniciais para o cálculo dos valores do sinal.


Gráficos do Saldo

Este acabou sendo o mais fácil de fazer. Uma vez que todas as operações são plotadas no gráfico e os resultados para cada uma delas são conhecidos, tudo o que precisamos é obtê-las e somar como uma execução total. Um gráfico de aumento (ou redução) pode ser exibido numa janela separada. Para satisfazer as necessidades de quem gosta de analisar os resultados expressos em valor monetário ou pontos, devemos prever um parâmetro adequado.


Emulação de Controles Deslizantes Triangulares

Foi muito mais difícil de ajustar a plataforma orientada a negociação automática em relação as tarefas que requerem interação com o trader. Os recursos padrão me permitiram implementar apenas uma seqüência de ações: a seleção de um indicador, chamada de suas propriedades, a modificação dos parâmetros e recálculo. Essa iteração tem pelo menos uma dúzia de variantes com uma grande quantidade de tempo. No tempo que levou para obter os resultados da décima variante, você já esqueceu completamente os resultados da primeira.

Uma vez que os elementos da interface gráfica padrão do sistema operacional (botões, caixas, caixas de combinação, controles deslizantes, etc.) não estão disponíveis para uso em indicadores e EAs, eu tive que procurar um substituto adequado (a menos que você use bibliotecas DLL escritas em outras linguagens de programação). Decidi adaptar um triângulo, um objeto que pode ser facilmente adicionado a qualquer gráfico para usar como um controle deslizante padrão que iria alterar o valor a partir de um dado mínimo a um dado máximo. Se dois de seus vértices são dispostos verticalmente (ou horizontal) e o terceiro é movido entre eles, podemos obter um modelo linear bastante adequado de um controle deslizante. A posição vertical de uma tal barra permite a obtenção de um fluxo suave (contínuo) de valores e a fim de mudar vários parâmetros ao mesmo tempo, é preciso implementar a possibilidade de trabalhar com vários triângulos diferentes separadamente.

Uma função especial foi escrita para trabalhar com controles deslizantes triangulares:

double ParamValue(int ParamNo, string ParamName, double ParamValue, double vMin, double vMax, color clr)
{
  double Triangle[3],vCur, WMax, WMin; datetime tt1, tt2;

  // se não há nenhum triângulo, crie ele
  if(ObjectFind(ParamName) < 0)
  {
    // determinar os limites do gráfico verticalmente na escala atual
    WMax = WindowPriceMax();  WMin = WindowPriceMin();

    // calcular as coordenadas de pontos pelo tempo ...
    tt1 = Time[0] + Period()*60*ParamNo*20; tt2 = tt1 + Period()*60*20;

    // ... e "preço"
    vCur = WMin + (ParamValue - vMin) * (WMax - WMin) / (vMax - vMin);

    // criar um objeto e preenchê-lo com a cor especificada nos parâmetros
    ObjectCreate(ParamName,OBJ_TRIANGLE, 0, tt1,WMax, tt2,vCur, tt1,WMin);
    ObjectSet(ParamName,OBJPROP_COLOR,clr);
  }

  // existe o triângulo - obter suas coordenadas
  Triangle[0] = ObjectGet(ParamName,OBJPROP_PRICE1);
  Triangle[1] = ObjectGet(ParamName,OBJPROP_PRICE2);
  Triangle[2] = ObjectGet(ParamName,OBJPROP_PRICE3);

  // organizar os vértices na ordem de "aumento"
  ArraySort(Triangle);

  // converter o ponto médio das coordenadas para a escala de valores reais entre vMin e vMax
  vCur = vMin + (Triangle[1] - Triangle[0]) / (Triangle[2] - Triangle[0]) * (vMax - vMin);

  // escreve o valor ao objeto do comentário
  ObjectSetText(ParamName,DoubleToStr(vCur,2));

  // retorna o valor para o módulo principal
  return(vCur);

}

Os cometários fornecem uma descrição bastante detalhada do algoritmo da função, por isso vamos nos limitar à explicação da finalidade aos parâmetros da função.

ParamNo - O número do parâmetro usado (que determina como os triângulos se movem em relação um ao outro ao longo do eixo do tempo). Você pode depois mudar suas posições e tamanhos, conforme necessário.

ParamName - Nome do parâmetro que deve ser exclusivo para diferenciação entre os triângulos e exibição na dica de ferramenta.

ParamValue - O valor do parâmetro inicial (que é usado para colocar corretamente o vértice médio entre o valor mínimo vMin e o valor máximo vMax a ser utilizado na otimização).

сlr – Cor do triângulo.

O código a seguir é usado para trabalhar com os triângulos:

MAPeriod  = ParamValue(0, SliderPrefix+"MA Period", MAPeriod, 5, 35, Blue);

RSIPeriod = ParamValue(1, SliderPrefix+"RSI Period", RSIPeriod, 2, 25, Red);

RSILevel  = ParamValue(2, SliderPrefix+"RSI Level", RSILevel, 5, 95, Orange);

Os valores obtidos são ainda usadas para calcular os sinais correspondentes.

Para ilustrar o desenvolvimento de indicadores e de depuração, eu escolhi um indicador proposto pelo usuário <s1>Helen</s1> (<a2>HI_Line_E_RSI_MA.mq4</a2>), basicamente me inspirou a fazer tudo isso. O bloco de cálculo de sinal tinha de ser reescrito para adequar o uso dentro do meu indicador, embora o código permaneceu essencialmente o mesmo:

// preencher os arrays com valores de sinal e contar seus números
  for(i=DisplayBars;i>=0;i--)
  {

    double t1=iRSI(NULL,0,RSIPeriod,MAPrice,i+1);
    double t11=iRSI(NULL,0,RSIPeriod,MAPrice,i+2);

    double t2=iMA(NULL,0,MAPeriod,0,MAMode,MAPrice,i+1);
    double t3=iMA(NULL,0,MAPeriod*3,0,MAMode,MAPrice,i+1);

    if (t1>RSILevel&&t11<RSILevel&&t1>t11&&t1>RSILevel&&t2>t3) {sBuy[i]=1; sBuyCnt++;}
    if (t1<(100-RSILevel)&&t11>(100-RSILevel)&&t1<t11&&t1<(100-RSILevel)) {sCloseBuy[i]=1; sBuyCloseCnt++;}

    if (t1<(100-RSILevel)&&t11>(100-RSILevel)&&t1<t11&&t1<(100-RSILevel)&&t2<t3) {sSell[i]=1; sSellCnt++; }
    if (t1>RSILevel&&t11<RSILevel&&t1>t11&&t1>RSILevel) {sCloseSell[i]=1; sSellCloseCnt++;}
  }

Eu decidi não ter um quarto parâmetro - a proporção de ampliação de período para obter uma MA lenta - pelo menos ainda não. Então eu simplesmente usei uma MA que é três vezes maior do que a principal (MAPeriod*3). Se desejar, você pode facilmente implementá-lo a seu próprio gosto.

Outra adição ao indicador original é o bloco de cálculo da curva do saldo e exibição:

// plotar o gráfico do saldo
// obter os valores do lucro, um a um e adicioná-los 
i2 = DisplayBars; bBallance[i2] = 0; 
for(i=DisplayBars-1;i>=0;i--) { if(bBallance[i] != 0) { bBallance[i2] = bBallance[i2+1] + bBallance[i]; i2--;  } }
double multiplier; if(ProfitInPoints) multiplier = 1; else multiplier = ToCurrency;
for(i=0;i<DisplayBars-2;i++) bBallance[i] = bBallance[i+i2+1] * multiplier;
SetIndexStyle(0,DRAW_HISTOGRAM,STYLE_SOLID,ProfitWidth,Blue);

O primeiro loop adiciona os valores definidos anteriormente ao lucro operacional acumulado, enquanto o segundo recebe-os juntos numa único "pilha", sem espaços entre elas. Em uma nota lateral não existe pontos para todas as correspondências entre os gráficos superiores e inferiores: linhas verticais de abertura e fechamento das ordens não estão relacionadas com o gráfico mais baixo de qualquer forma (por isto são desativados por padrão).

Como resultado, o texto do indicador é o seguinte:

/*///——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

    IndicatorOptimizer.mq4 
  
    Teste visual de rentabilidade de indicadores e alertas
    
    Copyright © 2009, Sergey Kravchuk, http://forextools.com.ua

/*///——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#property copyright "Copyright © 2006-2009, Sergey Kravchuk. http://forextools.com.ua"
#property link      "http://forextools.com.ua"

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_level1 0

// Parâmetros para a exibição de elementos no gráfico
extern bool   ShowZZ          = true;           // Se tiver que plotar ZZ
extern bool   ShowMARKERS     = false;           // Se tiver que desenhar linhas do marcador vertical
extern int    ProfitWidth     = 1;
extern bool   ProfitInPoints  = true;

// datas dos gráficos plotados
extern datetime DateStart     = D'1.01.1970';
extern datetime DateEnd       = D'31.12.2037';

// parâmetros de cálculo do lucro
extern double LotForCalc      = 0.05;           // Tamanho do lote para cálculo do lucro

// Parâmetros dos indicadores RSI
extern int    RSIPeriod       = 8;              // Período de cálculo do RSI
extern int    RSILevel        = 73;             // Nível de cálculo do RSI

// Parâmetros do indicador MA 
extern int    MAPeriod        = 20;             // período de cálculo do indicador МА
extern int    MAMode          = 3;              // 0-MODE_SMA 1-MODE_EMA 2-MODE_SMMA 3-MODE_LWMA
extern int    MAPrice         = 6;              // 0-Close 1-Open 2-High 3-Low 4-(H+L)/2 5-(H+L+C)/3 6-(H+L+2*C)/4


// Parâmetros do indicador MACD
extern double MACDOpenLevel   = 3;              
extern double MACDCloseLevel  = 2;
extern double MATrendPeriod   = 26;

// cores das linhas para COMPRAR
extern color  ColorProfitBuy  = Blue;           // cor da linha para posição comprada com lucro
extern color  ColorLossBuy    = Red;            // cor da linha para posição comprada com perdas
extern color  ColorZeroBuy    = Gray;           // cor da linha para posição comprada no empate

// cores das linhas para VENDER
extern color  ColorProfitSell = Blue;           // cor da linha para posição vendida com lucro
extern color  ColorLossSell   = Red;            // cor da linha para posição vendida com perdas 
extern color  ColorZeroSell   = Gray;           // cor da linha para posição vendida no empate

// Cores de linhas de sinal
extern color  ColorBuy        = CornflowerBlue; // cor da linha do sinal para COMPRAR
extern color  ColorSell       = HotPink;        // cor da linha sinal para VENDER
extern color  ColorClose      = Gainsboro;      // cor da linha sinal para fechamentoc

//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
double sBuy[],sCloseBuy[],sSell[],sCloseSell[]; // arrays para sinais
int sBuyCnt,sSellCnt,sBuyCloseCnt,sSellCloseCnt;// contadores de sinais
int i,DisplayBars;
double bBallance[]; // para o saldo das operações
int IndicatorWindowNo;  // número da janela do indicador
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// códigos de serviço
#define MrakerPrefix "IO_"
#define SliderPrefix "SL_"
#define OP_CLOSE_BUY  678
#define OP_CLOSE_SELL 876
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
int init()   
{ 
  SetIndexBuffer(0,bBallance);
  IndicatorShortName("IndicatorOptimizer");
  
  return(0); 
}
int deinit() 
{ 
  ClearMarkers(); 
  ClearSliders();
  return(0); 
}

double ParamValue(int ParamNo, string ParamName, double ParamValue, double vMin, double vMax, color clr)
{
  double Triangle[3],vCur, WMax, WMin; datetime tt1, tt2; 

  // se não há nenhum triângulo, crie ele
  if(ObjectFind(ParamName) < 0)
  {
    // determinar os limites do gráfico verticalmente na escala atual
    WMax = WindowPriceMax();  WMin = WindowPriceMin();

    // calcular as coordenadas de pontos pelo tempo ...
    tt1 = Time[0] + Period()*60*ParamNo*20; tt2 = tt1 + Period()*60*20;
    // ... e "preço"
    vCur = WMin + (ParamValue - vMin) * (WMax - WMin) / (vMax - vMin);
    // criar um objeto e preenchê-lo com a cor especificada nos parâmetros
    ObjectCreate(ParamName,OBJ_TRIANGLE, 0, tt1,WMax, tt2,vCur, tt1,WMin);
    ObjectSet(ParamName,OBJPROP_COLOR,clr);
  }
  // existe o triângulo - obter suas coordenadas
  Triangle[0] = ObjectGet(ParamName,OBJPROP_PRICE1);
  Triangle[1] = ObjectGet(ParamName,OBJPROP_PRICE2);
  Triangle[2] = ObjectGet(ParamName,OBJPROP_PRICE3);
  // organizar os vértices na ordem de "aumento"
  ArraySort(Triangle);
  // converter o ponto médio das coordenadas para a escala de valores reais entre vMin e vMax
  vCur = vMin + (Triangle[1] - Triangle[0]) / (Triangle[2] - Triangle[0]) * (vMax - vMin);
  // escreve o valor ao objeto do comentário
  ObjectSetText(ParamName,DoubleToStr(vCur,2)); 
  // retorna o valor para o módulo principal
  return(vCur); 
}


//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
int start() 
{ 
  double Profit=0,P1,P2; int CntProfit=0,CntLoose=0,i1,i2;
  // coeficiente de conversão dos pontos para a moeda de depósito
  double ToCurrency = MarketInfo(Symbol(),MODE_TICKVALUE)*LotForCalc;    
  
   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // excluir todos os marcadores no caso do indicador redesenhar
  ClearMarkers(); 
   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // preparar contadores de sinal
  sBuyCnt=0; sSellCnt=0; sBuyCloseCnt=0; sSellCloseCnt=0; 
   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // alocar memória para arrays de sinal e zerar seus valores
  DisplayBars=Bars; // número de barras exibidas
  ArrayResize(sBuy,DisplayBars);  ArrayInitialize(sBuy,0);
  ArrayResize(sSell,DisplayBars); ArrayInitialize(sSell,0);
  ArrayResize(sCloseBuy,DisplayBars);  ArrayInitialize(sCloseBuy,0);
  ArrayResize(sCloseSell,DisplayBars); ArrayInitialize(sCloseSell,0);

  // preparar o cálculo do saldo
  ArrayInitialize(bBallance,0); 
   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————


   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // criando (se necessário) e obtendo os parâmetros de controloe do triângulo
  MAPeriod  = ParamValue(0, SliderPrefix+"MA Period", MAPeriod, 5, 35, Blue);
  RSIPeriod = ParamValue(1, SliderPrefix+"RSI Period", RSIPeriod, 2, 25, Red);
  RSILevel  = ParamValue(2, SliderPrefix+"RSI Level", RSILevel, 5, 95, Orange);
   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————


  // preencher os arrays com valores de sinal e contar seus números
  for(i=DisplayBars;i>=0;i--) 
  {
    double t1=iRSI(NULL,0,RSIPeriod,MAPrice,i+1);
    double t11=iRSI(NULL,0,RSIPeriod,MAPrice,i+2);

    double t2=iMA(NULL,0,MAPeriod,0,MAMode,MAPrice,i+1);

    double t3=iMA(NULL,0,MAPeriod*3,0,MAMode,MAPrice,i+1);

    if (t1>RSILevel&&t11<RSILevel&&t1>t11&&t1>RSILevel&&t2>t3) {sBuy[i]=1; sBuyCnt++;}
    if (t1<(100-RSILevel)&&t11>(100-RSILevel)&&t1<t11&&t1<(100-RSILevel)) {sCloseBuy[i]=1; sBuyCloseCnt++;}

    if (t1<(100-RSILevel)&&t11>(100-RSILevel)&&t1<t11&&t1<(100-RSILevel)&&t2<t3) {sSell[i]=1; sSellCnt++; } 
    if (t1>RSILevel&&t11<RSILevel&&t1>t11&&t1>RSILevel) {sCloseSell[i]=1; sSellCloseCnt++;}
  }

 
         //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // excluir sinais repetidos deixando apenas os primeiros, no lado esquerdo do gráfico
  for(i=0;i<DisplayBars;i++) 
  {
    if(sBuy[i]==sBuy[i+1]) sBuy[i]=0;
    if(sSell[i]==sSell[i+1]) sSell[i]=0;
    if(sCloseBuy[i]==sCloseBuy[i+1]) sCloseBuy[i]=0;
    if(sCloseSell[i]==sCloseSell[i+1]) sCloseSell[i]=0;
  }
  // exclui sinais fora do intervalo na data especificada
  for(i=0;i<DisplayBars;i++) 
  {
    if(Time[i]<DateStart || DateEnd<Time[i]) { sBuy[i]=0; sSell[i]=0; sCloseBuy[i]=0; sCloseSell[i]=0; }
  }
  // adiciona fechamento forçado no limite do alcance
  if(DateEnd<=Time[0]) { i=iBarShift(Symbol(),Period(),DateEnd); sBuy[i]=0; sSell[i]=0; sCloseBuy[i]=1; sCloseSell[i]=1; }
  if(DateEnd >Time[0]) { sCloseBuy[0]=1; sCloseSell[0]=1; }
   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // contar o número de sinais
  for(i=0;i<DisplayBars;i++) 
  {
    if(sBuy [i]!=0) sBuyCnt++;  if(sCloseBuy [i]!=0) sBuyCloseCnt++;
    if(sSell[i]!=0) sSellCnt++; if(sCloseSell[i]!=0) sSellCloseCnt++;
  }
   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // definir marcadores, desenhar ZZ e calcular o lucro
   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // processo para COMPRAS
  for(i=DisplayBars-1;i>=0;i--) // obter os pontos
  {
    // encontrar o próximo ponto para abertura e salvar a posição e preço
    for(i1=i;i1>=0;i1--) if(sBuy[i1]!=0) break; 

    // encontrar o próximo ponto de fechamento da COMPRA e salvar a sua posição e preço
    for(i2=i1-1;i2>=0;i2--) if(sCloseBuy[i2]!=0) break;
    if(i2<0) i2=0; // a última posição não fechada, calculando o fechamento no preço atual
    i=i2; // nova barra para continuar a busca de pontos de abertura

    // determinar preços para desenhar 
    P1=Open[i1]; P2=Open[i2];  
    
    P1/=Point; P2/=Point; // converter os preços para pontos
    
    // determina o lucro e preenche o buffer correspondente
    if(i1>=0) 
    { 
      Profit=Profit+P2-P1; // obtém o lucro acumulado
      if(P2-P1>=0) CntProfit++; else CntLoose++; // contar o número de ordens
      DrawLine(i1,i2,OP_BUY); // desenhar a linha da ordem
      PlaceMarker(i1,OP_BUY); 
      PlaceMarker(i2,OP_CLOSE_BUY); 
      
      bBallance[i2] += P2-P1;
    }
  }
   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // processo para VENDAS
  for(i=DisplayBars-1;i>=0;i--) // obter os pontos
  {
    // encontrar o próximo ponto para abertura e salvar a posição e preço
    for(i1=i;i1>=0;i1--) if(sSell[i1]!=0) break; 

    // encontrar o próximo ponto de fechamento da COMPRA e salvar a sua posição e preço
    for(i2=i1-1;i2>=0;i2--) if(sCloseSell[i2]!=0) break;
    if(i2<0) i2=0; // a última posição não fechada, calculando o fechamento no preço atual
    i=i2; // nova barra para continuar a busca de pontos de abertura

    // determinar os preços para desenhAR, depende do parâmetro Optimizm
    P1=Open[i1]; P2=Open[i2]; 
    
    P1/=Point; P2/=Point; // converter os preços para pontos
    
    // se existem dois pontos, determinar o lucro e preencher o buffer correspondente
    if(i1>=0) 
    { 
      Profit=Profit+P1-P2; // obtém o lucro acumulado
      if(P1-P2>=0) CntProfit++; else CntLoose++; // contar o número de ordens
      [parcial]DrawLine(i1,i2,OP_BUY); // desenhar a linha da ordem
      PlaceMarker(i1,OP_SELL); 
      PlaceMarker(i2,OP_CLOSE_SELL);
      
      bBallance[i2] += P1-P2;
    }
  }

   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // plotar o gráfico do saldo
  // obter os valores do lucro, um a um e adicioná-los 
  i2 = DisplayBars; bBallance[i2] = 0; 
  for(i=DisplayBars-1;i>=0;i--) { if(bBallance[i] != 0) { bBallance[i2] = bBallance[i2+1] + bBallance[i]; i2--;  } }
  double multiplier; if(ProfitInPoints) multiplier = 1; else multiplier = ToCurrency;
  for(i=0;i<DisplayBars-2;i++) bBallance[i] = bBallance[i+i2+1] * multiplier;
  SetIndexStyle(0,DRAW_HISTOGRAM,STYLE_SOLID,ProfitWidth,Blue);

   //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // cálculo dos valores finais no comentário  
  int Cnt=CntProfit+CntLoose; // número total de operações
  string msg="Period: "+TimeToStr(MathMax(DateStart,Time[Bars-1]))+" - "+TimeToStr(MathMin(DateEnd,Time[0]))+"\n\n";
  
  msg=msg + 
  "RSI period: " + RSIPeriod + "\n" +
  "RSI level: " + RSILevel + "\n" +
  "МА period: " + MAPeriod + "\n\n" +
  sBuyCnt+" Buys and "+sBuyCloseCnt+" their closings\n"+
  sSellCnt+" Sells and "+sSellCloseCnt+" their closings\n\n";
  
  // tempo total em dias
  int TotalDays = (MathMin(DateEnd,Time[0])-MathMax(DateStart,Time[Bars-1]))/60/60/24; //converter segundos para dias
  if(TotalDays<=0) TotalDays=1; // para evitar a divisão de zero por um dia incompleto
  
  if(Cnt==0) msg=msg+("No operation");
  else msg=msg+
  (
    DoubleToStr(Profit,0)+" points for "+Cnt+" operations over "+TotalDays+" days\n"+
    DoubleToStr(Profit/Cnt,1)+" points per operation ("+
    DoubleToStr(Profit/TotalDays,1)+" per day)\n\n"+
    "When trading the lot "+DoubleToStr(LotForCalc,2)+" get in "+AccountCurrency()+":\n"+
    DoubleToStr(Profit*ToCurrency,0)+" total, "+
    DoubleToStr(Profit/Cnt*ToCurrency,1)+" per operation ("+
    DoubleToStr(Profit/TotalDays*ToCurrency,1)+" per day)\n\n"+
    CntProfit+" profitable ("+DoubleToStr(((CntProfit)*1.0/Cnt*1.0)*100.0,1)+"%)\n"+
    CntLoose+" losing ("+DoubleToStr(((CntLoose)*1.0/Cnt*1.0)*100.0,1)+"%)"
  );
  Comment(msg);
  
}
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// excluir todos os objetos do nosso gráfico
void ClearMarkers() 
{ 
  for(int i=ObjectsTotal()-1;i>=0;i--) if(StringFind(ObjectName(i),MrakerPrefix)==0) ObjectDelete(ObjectName(i)); 
}
void ClearSliders() 
{ 
  for(int i=ObjectsTotal()-1;i>=0;i--) if(StringFind(ObjectName(i),SliderPrefix)==0) ObjectDelete(ObjectName(i)); 
}
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// definir uma linha vertical - o marcador de operação op_type
void PlaceMarker(int i, int op_type)
{
  if(!ShowMARKERS) return; // Exibindo marcadores desativados

  color MarkerColor; string MarkName; 

  // __ a fim de que a linha de fechamento seja plotada abaixo da linha de abertura pela classificação 
  if(op_type==OP_CLOSE_SELL) { MarkerColor=ColorClose; MarkName=MrakerPrefix+"__SELL_"+i; }
  if(op_type==OP_CLOSE_BUY)  { MarkerColor=ColorClose; MarkName=MrakerPrefix+"__BUY_"+i;  }  
  if(op_type==OP_SELL)       { MarkerColor=ColorSell;  MarkName=MrakerPrefix+"_SELL_"+i;  }
  if(op_type==OP_BUY)        { MarkerColor=ColorBuy;   MarkName=MrakerPrefix+"_BUY_"+i;   }

  ObjectCreate(MarkName,OBJ_VLINE,0,Time[i],0); 
  ObjectSet(MarkName,OBJPROP_WIDTH,1); 
  if(op_type==OP_CLOSE_BUY || op_type==OP_CLOSE_SELL) ObjectSet(MarkName,OBJPROP_STYLE,STYLE_SOLID); 
  else ObjectSet(MarkName,OBJPROP_STYLE,STYLE_DOT);
  ObjectSet(MarkName,OBJPROP_BACK,True);  

  ObjectSet(MarkName,OBJPROP_COLOR,MarkerColor);
}
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// definindo a linha no gráfico ao tipo de operação op_type, usando os valores do parâmetro Optimizm
void DrawLine(int i1,int i2, int op_type)
{
  if(!ShowZZ) return; // a exibição do indicador ZZ está desativada
  
  color СurColor;
  string MarkName=MrakerPrefix+"_"+i1+"_"+i2;
  double P1,P2;
  
  // determinar os preços para desenhAR, depende do parâmetro Optimizm
  P1=Open[i1]; P2=Open[i2];  

  ObjectCreate(MarkName,OBJ_TREND,0,Time[i1],P1,Time[i2],P2);
  
  ObjectSet(MarkName,OBJPROP_RAY,False); // desenha os segmentos em vez das linhas
  ObjectSet(MarkName,OBJPROP_BACK,False);
  ObjectSet(MarkName,OBJPROP_STYLE,STYLE_SOLID);
  ObjectSet(MarkName,OBJPROP_WIDTH,2);

  // define a cor da linha, dependendo da rentabilidade da operação
  if(op_type==OP_BUY) 
  { 
    if(P1 <P2) СurColor = ColorProfitBuy;
    if(P1==P2) СurColor = ColorZeroBuy;
    if(P1 >P2) СurColor = ColorLossBuy;
  }
  if(op_type==OP_SELL) 
  { 
    if(P1 >P2) СurColor = ColorProfitSell;
    if(P1==P2) СurColor = ColorZeroSell;
    if(P1 <P2) СurColor = ColorLossSell;
  }
  ObjectSet(MarkName,OBJPROP_COLOR,СurColor);
}
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

A descrição detalhada do algoritmo e o seu funcionamento podem ser encontrados no meu artigo anterior. Perceba que eu removi a solução alternativa para o parâmetro Optimizm. Nesta versão do indicador, sinais para as barras em andamento (atuais) são calculadas com base nos valores das barras totalmente completas anteriormente. Isto sugere a utilização da abordagem clássica na negociação com base na análise da barra: tendo analisado os resultados de uma barra recém-concluída, você abre uma posição no início da que está em andamento (atual), isto nos permite dizer que os resultados dos cálculos obtidos são bastante confiáveis.


Otimização em Ação

Depois de compilar o indicador e adicioná-lo no gráfico, podemos proceder à análise. Este processo pode ser descrito em detalhes e em profundidade, mas tudo se tornará muito claro se você assistir a uma pequena animação, demonstrando operação ao vivo do indicador.

Devemos notar uma coisa importante aqui: o indicador volta a calcular os seus valores a cada novo tick, assim depois de mover o cursor triangular, devemos aguardar o novo preço ou atualizar o gráfico.

A otimização funcionando como está, transforma-se num jogo peculiar conhecido como "e se?" Basta selecionar os controles deslizantes triangulares e começar a mover seus pontos médios para cima/baixo. A posição horizontal do vértice do triângulo não importa, somente é importante a posição vertical dos vértices. Então você move pontos médios do triângulo e tentar entender onde estes movimentos levam. Sua intuição e sua experiência prática irá certamente mostrar o que e para onde ir. Bem, se você não tiver a experiência, use o método de tentativa e erro: tentar, olhar para as variantes que seriam adequadas e mais tarde olhar sobre a negociação com base nos parâmetros determinados.


Como Usar o Indicador. Parte I: O Que NÃO Devo Fazer

Este indicador, assim como o meu indicador anterior, deve ser utilizado quando você entender o que ele faz e os resultados que obtém. Você pode substituir o bloco de cálculo do sinal com seu próprio e aumentar ou diminuir o número de sinais utilizados, mas quando olhar os resultados sempre tenha em mente que se você conseguiu otimizar os parâmetros do indicadores para o EURUSD М30 e mostra uma boa curva de lucro, não significa que terão os mesmos resultados em outro par de moedas, num timeframe diferente ou ambos. Para entender o motivo, basta dar uma olhada nos gráficos М1 e D1. A diferença na natureza das alterações das barras e tamanhos das barras é tão óbvio que não há necessidade de comentários adicionais.

A diferença entre os pares de moedas não é tão claro, mas também pode ser facilmente identificadas utilizando a técnica descrita no meu artigo "Diagnóstico do Mercado pelo Pulso". As capturas de telas neste artigo mostrarão por que você não deve esperar os mesmos resultados em todos os pares de moedas, mesmo que as configurações dos cálculos do bloqueio de sinal sejam as mesmas.


Como usar o indicador. Parte II: O que DEVE ser feito

No entanto, não é tão ruim quanto parece. Como alguns filósofos dizem, "deméritos são extensões de nossos méritos". Se formos ver as falhas, ainda estão no local para identificar as vantagens, isso não significa que não existe nenhuma. Dê uma olhada no gráfico D1 com uma longa e constante tendência de alta. Você realmente acha que o indicador otimizado com base no início deste período, não renderá lucro no meio desta tendência?!

Se você decidir usar esta ferramenta na negociação, assim como eu estou ensinando a usá-la, de vez em quando você só precisará ajustá-la a um determinado par de moeda e prazo. Você pode tomar o Expert Advisor proposto pela Helen e experimentá-lo numa negociação automatizada, ajustando seus parâmetros aos resultados de otimização de vez em quando, especialmente quando o indicador permite que você execute facilmente este processo muitas vezes ao dia e usá-lo até mesmo para os gráficos de minutos (M5, M15 e M30).


Conclusão

O mercado é fundamentalmente imprevisível. Qualquer sinal 100% confiável e verificado pode num piscar de olhos ser transformado numa direção oposta, após uma liberação da notícia importante, por exemplo. Na discussão deste artigo, os ases da negociação provavelmente vão tentar convencê-lo de que você nunca saberá onde o preço vai mover e consequentemente nunca obterá um lucro estável se não levar em consideração coisas como sinais fundamentais ou se você não tem os dados do volume da negociação. Bem, é a opinião deles, é a forma como eles negociam e obtém sucesso. Pode-se usar a abordagem de negociação neste artigo gerenciando mais de mil dólares,

Também acredito que para pequenos depósitos, este indicador pode tornar-se uma das ferramentas mais simples e confiáveis, se você gostar. Você nunca vai ter o "quadro completo" do movimento do preço, por isso é inútil procurar pontos de reversão e tentar espremer cada centavo fora do mercado. Uma longa tendência ao longo de dias e semanas provavelmente lhe darão algum padrão geral e podendo ver o seu início, otimizar seu sistema de cálculo de sinal de acordo com a tendência, assim você poderá obter sucesso nos parâmetros otimizados, provavelmente tendo lucro num curto espaço de tempo. Mesmo que as "mudanças de vento" aconteçam, você não vai considerar isto um grande problema, já que agora o processo de otimização será muito menos trabalhoso do que era antes de você começar a utilizar esse indicador.

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

Arquivos anexados |
IndicatorOptimizer.zip (1820.28 KB)
Análise Avançada de uma Conta de Negociação Análise Avançada de uma Conta de Negociação
O artigo trata sobre sistema automático para análise de qualquer conta de negociação no terminal MetaTrader 4, são considerados os aspectos técnicos de um relatório gerado e a interpretação dos resultados obtidos. Conclusões sobre as melhorias dos fatores das negociações são mostradas após a análise detalhada do relatório. O script MQLab ™ Graphic Report é usado para análise.
Lite_EXPERT2.mqh: Kit Funcional para Desenvolvedores de Expert Advisors Lite_EXPERT2.mqh: Kit Funcional para Desenvolvedores de Expert Advisors
Este artigo continua a série "Expert Advisors Baseados nos Sistemas de Negociação Populares e na Alquimia da Otimização de Robô de Negociação". Tem o objetivo de familiarizar os leitores com uma biblioteca de funções mais universal do arquivo Lite_EXPERT2.mqh.
Verificação de Estatística do Sistema de Gestão de Dinheiro Labouchere Verificação de Estatística do Sistema de Gestão de Dinheiro Labouchere
Neste artigo vamos testar as propriedades estatísticas do sistema de gestão de dinheiro Labouchere. Este sistema é considerado um dos tipos menos agressivos dos sistemas Martingale, uma vez que as apostas não são dobradas, mas são colocadas a uma certa quantidade de cada vez.
Notificações SMS do Status do EA Notificações SMS do Status do EA
Desenvolvimento de um sistema de notificações SMS que informa sobre o status do seu EA para que você esteja sempre ciente de qualquer situação crítica, onde quer que esteja.