Otimização Visual de Indicador e Sinal de Rentabilidade
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
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso