English Русский 中文 Deutsch 日本語 Português
Prueba visual de la rentabilidad de los indicadores y alertas

Prueba visual de la rentabilidad de los indicadores y alertas

MetaTrader 4Ejemplos | 4 mayo 2016, 16:53
727 0
Sergey Kravchuk
Sergey Kravchuk

De lo que avisa un indicador de trading, o simplemente el método de su cálculo, se decide generalmente cuando los AEs de prueba usan estas alertas. Sin embargo, no siempre es posible/necesario/razonable escribir un AE para cada indicador. Se puede calcular rápidamente la rentabilidad de trading en alertas de otros indicadores, utilizando un indicador especial que recoge sus alertas él mismo y dibuja una imagen del trading ideal con ellas. Puede ayudar tanto a hacer una estimación visual de los resultados obtenidos y elegir rápidamente los mejores parámetros.

Recuerde cuantas veces, mirando un indicador encontrado aleatoriamente, o a uno que buscó durante mucho tiempo y finalmente encontró, quiso saber inmediatamente cuál sería el resultado del trading por sus alertas. Lo mismo ocurre cuando se le ofrece un nuevo sistema de trading para el que no hay aún AEs o indicadores. Antes de comenzar un trabajo serio y escribir un AE que funcione, querrá estimar si hay semillas sanas en el material que se ofrece.

O puede encontrarse con esta situación: Hay un indicador con buenas alertas, pero tiene un presentimiento de que sus parámetros no son los mejores, que puede limpiarlo, e incluso sabe cómo hacerlo. ¿Cómo puede probar su idea rápidamente sin involucrarse en una codificación larga y complicada?

Planteamiento del problema

Pensemos qué tenemos y qué queremos. Vamos a coger un Zig-Zag conocido de la entrega estándar de MetaTrader 4 como ejemplo. Se adjunta a cualquier par de divisas de cualquier periodo de tiempo. ¿Quiere hacer trade con eso? Todo está claro: debería vender en el kink más alto y cerrar la posición comprando en el más bajo.

Pero, una pregunta: ¿Cuánto dinero ganaría este trading? Es muy fácil obtener la respuesta a esta pregunta: Sume todos las alturas de los segmentos y recalcule considerando el volumen de la posición en lotes y el precio de un punto en la moneda de depósito. Puede acceder al búfer de los valores ZigZag llamando a la función iCustom:

P=iCustom(NULL,0,"ZigZag",0,i);

en la que ies el número de la barra para la que va a obtener el valor.

Todo lo que tiene que hacer ahora es buscar en todos los valores del búfer y encontrar todos los puntos con valores diferentes a cero: estos son los puntos en los que construir ZigZag. Bueno, también tiene que sumar las alturas de los segmentos. Por razones descriptivas, puede incluso dibujar esas líneas y colorearlas según los colores de los trades y su rentabilidad. La tarea es bastante sencilla y puede asignarse satisfactoriamente a un indicador.

Una solución universal

Para que este indicador pueda probar cualquier otro indicador, debe asegurar su universalidad. Como cualquier indicador del sistema de trading, generalmente, asume que sólo se hacen 4 operaciones: BUY, SELL, BUY, CLOSE, y SELL, CLOSE, se debería tener una gama especial para cada una de ellas. Tiene que ser posible rellenar esta gama desde cualquier fuente. Es lo único que tiene que editar añadiendo un código de relleno de gamas de alertas (bueno, probablemente tenga que colocar también algunos parámetros en las variables externas).

Funcionalmente, el indicador tiene los siguientes bloques:

  • Inicialización: aquí se coloca la memoria para las gamas de alertas y se reinician los contadores;
  • Rellenar las gamas de alertas: aquí se va a editar el código añadiendo varios algoritmos de cálculo de alertas o de recibirlas de otros indicadores;
  • Eliminar alertas repetidas: este bloque es necesario para "adelgazar" las alertas de los indicadores que no funcionan en modo discreto que generan una alerta, sino en un modo continuo en el que el indicador fija continuamente la disponibilidad de apertura de condiciones, no la primera apariencia de la alerta por la que, de hecho, debe estar abierta la orden. En el bloque se realiza este mecanismo: Si dos alertas idénticas están colocadas en barras vecinas, la derecha está en reposo, ya que se ha considerado sólo el uso de una orden que ya se ha abierto en la barra anterior (izquierda). Aquí también se eliminan todas las alertas fuera del rango de fecha configuradas en los parámetros.
  • Colocar las marcas de OPEN y CLOSE: en este bloque, las alertas "adelgazadas" (discretas) son las que dibujan ZigZag, se colocan líneas verticales, si es necesario, para rastrear la sincronización de las alertas con los gráficos de otros indicadores, incluidos los que producen alertas.
  • Calcular los resultados con las marcas colocadas: las cantidades de órdenes abiertas y sus beneficios se calculan en el curso de ubicación de las marcas. Este bloque hace algunos cálculos adicionales y muestra sus resultados como comentarios en la ventana principal del gráfico.
  • Funciones de ayuda: hay dos funciones aquí: una para colocar líneas de marcado vertical, y otra para dibujar los segmentos ZigZag.

Realización

Debajo del código del propio indicador, que tiene un ejemplo de alimentación de datos desde el indicador ZigZag.

/*///———————————————————————————————————————————————————————————————————————————————————————————————————————
 
    IndicatorTester.mq4 
  
    Visual Testing the Profitability of Indicators and Alerts
    
    Copyright © 2006, Кравчук Сергей,  http://forextools.com.ua
 
/*///———————————————————————————————————————————————————————————————————————————————————————————————————————
#property copyright "Copyright © 2006-2008, Sergey Kravchuk. http://forextools.com.ua"
#property link      "http://forextools.com.ua"
 
#property indicator_chart_window
#property indicator_buffers 0
 
// parameters for displaying the elements of the chart
extern bool   ShowZZ          = true;           // should the ZZ be drawn?
extern bool   ShowMARKERS     = true;           // should the vertical marking lines be drawn?
 
//dates of drawing the chart
extern datetime DateStart     = D'1.01.1970';
extern datetime DateEnd       = D'31.12.2037';
 
//parameters of profit calculations
extern double LotForCalc      = 0.05;           // the amount of lots for profit calculations
extern int    Optimizm        = 0;              // -1 gives a pessimistic calculation; 0 gives the calculation on bar opening prices;  
                                                //+1 is optimistic
 
// BUY lines colors
extern color  ColorProfitBuy  = Blue;           // line color for profitable BUY trades
extern color  ColorLossBuy    = Red;            // line color for losing BUY trades
extern color  ColorZeroBuy    = Gray;           // line color for BUY trades with zero profits
 
// SELL lines colors
extern color  ColorProfitSell = Blue;           // line color for profitable SELL trades
extern color  ColorLossSell   = Red;            // line color for losing SELL trades
extern color  ColorZeroSell   = Gray;           // line color for SELL trades with zero profits
 
// alert lines colors
extern color  ColorBuy        = CornflowerBlue; // line color for BUY alerts
extern color  ColorSell       = HotPink;        // line color for SELL alerts
extern color  ColorClose      = Gainsboro;      // line color for closing alerts
 
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
double sBuy[],sCloseBuy[],sSell[],sCloseSell[]; // arrays for alerts
int sBuyCnt,sSellCnt,sBuyCloseCnt,sSellCloseCnt;// alerts counters 
int i,DisplayBars;
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
// service codes
#define MrakerPrefix "IT_"
#define OP_CLOSE_BUY  444
#define OP_CLOSE_SELL 555
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
int init()   { ClearMarkers(); return(0); }
int deinit() { ClearMarkers(); return(0); }
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
int start() 
{ 
  double Profit=0,P1,P2; int CntProfit=0,CntLoose=0,i1,i2;
 
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // delete all marks, in case the indicator is going to be redrawn
  ClearMarkers(); 
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // prepare alerts counters
  sBuyCnt=0; sSellCnt=0; sBuyCloseCnt=0; sSellCloseCnt=0; 
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // allocate some memory for alerts arrays and zeroize their valuesя
  DisplayBars=Bars; // the amount of bars to be displayed
  ArrayResize(sBuy,DisplayBars);  ArrayInitialize(sBuy,0);
  ArrayResize(sSell,DisplayBars); ArrayInitialize(sSell,0);
  ArrayResize(sCloseBuy,DisplayBars);  ArrayInitialize(sCloseBuy,0);
  ArrayResize(sCloseSell,DisplayBars); ArrayInitialize(sCloseSell,0);
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // find the first point and save its location and price
  for(i1=Bars-1;i1>=0;i1--) { P1=iCustom(NULL,0,"ZigZag",0,i1); if(P1!=0) break; }
  // process the ZigZag points
  for(i2=i1-1;i2>=0;i2--) 
  {
    // find the next point and save its location and price
    for(i2=i2;i2>=0;i2--) { P2=iCustom(NULL,0,"ZigZag",0,i2); if(P2!=0) break; }
    
    if(i2<0) break; // place the last point on the current price 
 
    // the opening conditions are at the same time the conditions of closing an opposite order
    if(P1>P2) { sSell[i1]=1; sBuy[i2]=1; sCloseSell[i2]=1; }
    if(P1<P2) { sBuy[i1]=1; sSell[i2]=1; sCloseBuy[i2]=1; }
 
    P1=P2; i1=i2; // save the bar in which the point has been found
  }
    //——————————————————————————————————————————————————————————————————————————————————————————————————————
  // delete the repeated alerts having saved only the very first ones located to the left on the chart
  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;
  }
  // delete the alerts outside the specified range of dates
  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; }
  }
  // add forcible closing marginal positions
  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; }
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // count the amount of alerts

  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++;
  }
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // place the marks, draw a ZZ and calculate the profits
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // process BUY trades
  for(i=DisplayBars-1;i>=0;i--) // go and collect the points
  {
    // find the next OPEN point and save its location and price
    for(i1=i;i1>=0;i1--) if(sBuy[i1]!=0) break; 
 
    // find the next CLOSE point of a BUY trade and save its location and price
    for(i2=i1-1;i2>=0;i2--) if(sCloseBuy[i2]!=0) break;
    if(i2<0) i2=0; // for the last unclosed position, calculate the CLOSE on the current price
    i=i2; // new bar to continue searching for OPEN points
 
    // define the prices for drawing according to the parameter of optimism, Optimizm
    if(Optimizm<0)  { P1=High[i1]; P2=Low[i2];  } 
    if(Optimizm==0) { P1=Open[i1]; P2=Open[i2]; } 
    if(Optimizm>0)  { P1=Low[i1];  P2=High[i2]; } 
    
    P1/=Point; P2/=Point; // express prices in points
    
    // find the profit and fill out the corresponding buffer
    if(i1>=0) 
    { 
      Profit=Profit+P2-P1; // collect the summed profit
      if(P2-P1>=0) CntProfit++; else CntLoose++; // count the number of orders
      DrawLine(i1,i2,OP_BUY,Optimizm); // draw the order line
      PlaceMarker(i1,OP_BUY); 
      PlaceMarker(i2,OP_CLOSE_BUY); 
    }
  }
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // process the SELL trades
  for(i=DisplayBars-1;i>=0;i--) // go and collect the points
  {
    // find the next OPEN point and save its location and price
    for(i1=i;i1>=0;i1--) if(sSell[i1]!=0) break; 
 
    // find the next CLOSE point of a SELL trade and save its location and price
    for(i2=i1-1;i2>=0;i2--) if(sCloseSell[i2]!=0) break;
    if(i2<0) i2=0; // for the last unclosed position, calculate the CLOSE on the current price
    i=i2; // new bar to continue searching for OPEN points
 
    // define the prices for drawing according to the parameter of optimism, Optimizm
    if(Optimizm<0)  { P1=Low[i1];  P2=High[i2]; } 
    if(Optimizm==0) { P1=Open[i1]; P2=Open[i2]; } 
    if(Optimizm>0)  { P1=High[i1]; P2=Low[i2];  } 
    
    P1/=Point; P2/=Point; // express prices in points
    
    // if there are both points available, find the profit and fill the corresponding buffer
    if(i1>=0) 
    { 
      Profit=Profit+P1-P2; // collect the summed profit
      if(P1-P2>=0) CntProfit++; else CntLoose++; // count the number of orders
      DrawLine(i1,i2,OP_SELL,Optimizm); // draw the order line
      PlaceMarker(i1,OP_SELL); 
      PlaceMarker(i2,OP_CLOSE_SELL);
    }
  }
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // calculating the totals for commenting  
  int Cnt=CntProfit+CntLoose; // total number of operations
  // coefficient to transfer points into the deposit currency
  double ToCurrency = MarketInfo(Symbol(),MODE_TICKVALUE)*LotForCalc;    
  string msg="Период: "+TimeToStr(MathMax(DateStart,Time[Bars-1]))+" - "
                                                      + TimeToStr(MathMin(DateEnd,Time[0]))+"\n\n";
  
  msg=msg+
  sBuyCnt+" BUY trades and "+sBuyCloseCnt+" their closings\n"+
  sSellCnt+" SELL trades and "+sSellCloseCnt+" their closings\n\n";
  
  // total time in days
  int TotalDays = (MathMin(DateEnd,Time[0])-MathMax(DateStart,Time[Bars-1]))/60/60/24; 
                                                                       //translate seconds into days
  if(TotalDays<=0) TotalDays=1; // to avoid zero divide for shorter days
  
  if(Cnt==0) msg=msg+("No operations");
  else msg=msg+
  (
    DoubleToStr(Profit,0)+" point on "+Cnt+" operations for "+TotalDays+" days\n"+
    DoubleToStr(Profit/Cnt,1)+" point for operation ("+
    DoubleToStr(Profit/TotalDays,1)+" within a day)\n\n"+
    "When trading with "+DoubleToStr(LotForCalc,2)+" obtain in "+AccountCurrency()+":\n"+
    DoubleToStr(Profit*ToCurrency,0)+" totally, by "+
    DoubleToStr(Profit/Cnt*ToCurrency,1)+" per trade ("+
    DoubleToStr(Profit/TotalDays*ToCurrency,1)+" within one 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);
  
}
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
 
 
 
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
// deleting all objects from our chart
void ClearMarkers() 
{ 
  for(int i=0;i<ObjectsTotal();i++) 
  if(StringFind(ObjectName(i),MrakerPrefix)==0) { ObjectDelete(ObjectName(i)); i--; } 
}
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
// placing a vertical line - marks of the operation of the op_type type
void PlaceMarker(int i, int op_type)
{
  if(!ShowMARKERS) return; // displaying markers disabled
 
  color MarkerColor; string MarkName; 
 
  // __ for the CLOSE line to be drawn below the OPEN line at sorting 
  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);
}
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
// placing a line on the chart for the operation of the op_type type at the prices of parameter Optimizm
void DrawLine(int i1,int i2, int op_type, int Optimizm)
{
  if(!ShowZZ) return; // ZZ displaying disabled
  
  color СurColor;
  string MarkName=MrakerPrefix+"_"+i1+"_"+i2;
  double P1,P2;
  
  // define prices for drawing, according to parameter Optimizm
  if(Optimizm<0 && op_type==OP_BUY)  { P1=High[i1]; P2=Low[i2];  } 
  if(Optimizm<0 && op_type==OP_SELL) { P1=Low[i1];  P2=High[i2]; } 
  if(Optimizm==0)                    { P1=Open[i1]; P2=Open[i2]; } 
  if(Optimizm>0 && op_type==OP_BUY)  { P1=Low[i1];  P2=High[i2]; } 
  if(Optimizm>0 && op_type==OP_SELL) { P1=High[i1]; P2=Low[i2];  } 
 
  ObjectCreate(MarkName,OBJ_TREND,0,Time[i1],P1,Time[i2],P2);
  
  ObjectSet(MarkName,OBJPROP_RAY,False); // draw segments, not lines
  ObjectSet(MarkName,OBJPROP_BACK,False);
  ObjectSet(MarkName,OBJPROP_STYLE,STYLE_SOLID);
  ObjectSet(MarkName,OBJPROP_WIDTH,2);
 
  // set line color depending on the profitability of the trade
  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);
}
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
Los parámetros del indicador tienen un parámetros especial, Optimizm. Establece el grado deseado de optimismo en los cálculos. Si el valor está por debajo de cero, significa que los cálculos serán completamente pesimistas: para los precios de BUY elegirá el High de la barra de alerta; para los precios SELL, Bajo. Así es cómo se modelan los peores resultados posibles que se pueden obtener con estas alertas. Si el valor está por encima de cero, se modelan los cálculos más optimistas: comprar al más bajo y vender al más alto. Si el valor de este parámetro es igual a cero, se forma el comportamiento neutral en el que se abren y cierran órdenes en los precios OPEN de las barras: esta es la situación que normalmente se realiza cuando se hace trading con los AEs.

Analizar los resultados

Vamos a ver los resultados. Aquí están los resultados obtenidos con el análisis objetivo de zigzag.

Ve, el gráfico muestra ocho partes no rentables. Bueno, el zigzag "trabaja" en los mejores precios y para reconstruirlo de nuevo hay que configurar el parámetro Optimizm = 1.

Si se configura el parámetro Optimizm = -1, se puede ver cuál sería el resultado si se hace trade lo peor posible.


Un pequeño inciso

Queridos traders,

No me culpen, pero este indicador puede convertirse en un azote si se tiene lugar en cuidadosas manos de la administración, que normalmente no están interesados en los detalles de las tácticas de trading, sino sólo en los resultados. Subiendo al tester el algoritmo de las alertas ZigZag y configurando Optimizm = 1, obtendrán las figuras del beneficio máximo que se pueda obtener jamás de esta parte del gráfico, y querrán que lo obtengan. Y si usted siempre hace trade con menos de la mitad, esto les hará pensar que sus obligaciones le son indiferentes.

Por otro lado, esta herramienta puede ser una buena defensa para las demandas empinadas injustamente. Tendrá un argumento: los planes que le enviaron no eran reales y no podían obtenerse incluso en las mejores condiciones.

Ya vemos, el uso del único parámetro Optimizm le permite utilizar el indicador para la estimación potencial de un indicador de alertas probado en él. E incluso si los cálculos más optimistas no generan beneficios, el indicador de alertas debería modificarse: tiene que encontrar otros parámetros, o en el peor de los casos olvidarlo por desesperación, ahorrando tiempo en el desarrollo del AE, y ahorrando dinero de su depósito, que podría perderse por obtener pruebas de que el indicador no funciona. Por lo que el indicador de prueba permite ahorrar, no sólo tiempo, sino también dinero.

Analizar las alertas del sistema de trading

Los búfers de otros indicadores no son la única fuente para rellenar las alertas de gamas en las que funciona el indicador de prueba. En algún lugar de los bloques o en las profundidades de Internet, se pueden encontrar definiciones de alertas de un sistema de trading, para las que no hay indicadores o Asesores Expertos. Esto es sólo un conjunto de reglas que se pueden implementar fácilmente en MQL4. Puede escribir los cálculos de las alertas para estos sistemas y rellenar los búfers de alertas con ellos, el indicador de prueba le mostrará los resultados que puede obtener utilizando ese sistema.

Si hay un código preparado para un sistema, puede seleccionar el cálculo de las alertas en las que funciona el AE, y construir los "resultados de su funcionamiento" directamente en el gráfico. Por supuesto, se pueden éstos se pueden obtener, incluso de forma más precisa, en el tester de estrategia de MetaTrader 4, pero el indicador realizará las reconstrucciones más rápido y las reflejará mejor que las líneas estrictas del tester.

Un momento importante en este caso es la posibilidad de unir el gráfico de los resultados obtenidos con otros indicadores. Las líneas de marca verticales que cruzan los indicadores adicionales puede que le digan cómo se pueden utilizar para especificar las alertas principales, o cómo detectarán los lugares de su funcionamiento inadecuado. Finalmente, sólo con el método al azar se puede elegir este parámetro de los valores que probablemente nos encajarán mejor que los resultados del optimizador.

Vamos a coger un ejemplo de un código preparado del MACD estándar. La ecuación es así: Bloque de relleno de alertas de gamas, cuyos contenidos secopian y pegan desde el texto de indicador:

  // fill out alert arrays with values and count them
  for(i=DisplayBars;i>=0;i--) 
  {
    double MacdCurrent, MacdPrevious, SignalCurrent;
    double SignalPrevious, MaCurrent, MaPrevious;
  
    // to simplify the coding and speed up access
    // data are put into internal variables
    MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+0);
    MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+1);
    SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+0);
    SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+1);
    MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+0);
    MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+1);
    
    // check for long position (BUY) possibility
    if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
       MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious) sBuy[i]=1;
       
    // check for short position (SELL) possibility
    if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
       MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent<MaPrevious) sSell[i]=1;
       
    if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
       MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseBuy[i]=1;
 
    if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&  MacdPrevious<SignalPrevious && 
       MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseSell[i]=1;
  }

Y este es el resultado:

Tenga en cuenta que las líneas de las marcas de alerta coinciden por completo con los puntos de cruce de los gráficos MACD. Quizás mirando a estos gráficos decidirá qué cambiar exactamente en las alertas. Por ejemplo, que MaCurrent y MaPrevious no necesitan comprobación. Un código ligeramente corregido:

  // fill out alert arrays with values and count them
  for(i=DisplayBars;i>=0;i--) 
  {
    double MacdCurrent, MacdPrevious, SignalCurrent;
    double SignalPrevious, MaCurrent, MaPrevious;
  
    // to simplify the coding and speed up access
    // data are put into internal variables
    MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+0);
    MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+1);
    SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+0);
    SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+1);
    MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+0);
    MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+1);
    
    // check for long position (BUY) possibility
    if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
       MathAbs(MacdCurrent)>(MACDOpenLevel*Point)) sBuy[i]=1;
       
    // check for short position (SELL) possibility
    if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
       MathAbs(MacdCurrent)>(MACDOpenLevel*Point)) sSell[i]=1;
       
    if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
       MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseBuy[i]=1;
 
    if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&  MacdPrevious<SignalPrevious && 
       MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseSell[i]=1;
  }

Ve cuál es el resultado. El número de operaciones ha aumentado de 19 a 51. Aunque el total de beneficio se ha convertido en pérdidas, lo que muestra que esta no ha sido una buena idea de mejora de la calidad de la alerta.

Probando fantasías

Seguro que cada desarrollador tiene algunos pensamientos invasivos de los que no se ocupa nunca. El tester de indicadores le ayudará a visualizarlos rápidamente y a estimarlos. Si las ideas resultan correctas y se obtienen resultados positivos, un desarrollador puede pensar en escribir un indicador o un Asesor Experto. En este caso, los resultados del tester del indicador serán a mismo tiempo una ilustración de la especificación de los requisitos para el desarrollo y un ejemplo final, según la que se comprobará el producto preparado.

Aquí tiene un "sistema" primitivo como ejemplo: compra usando un indicador MA simple. Condición de compra: MA crece; condición de venta: MA cae. Mire qué rápido se comprueba la rentabilidad de esta idea. Aquí tiene un bloque de relleno de alerta:

  // fill out alert arrays with values and count them
  for(i=DisplayBars;i>=0;i--) 
  {
    double m1=iMA(NULL,0,MAPeriod,0,MAMode,MAPrice,i+1);
    double m2=iMA(NULL,0,MAPeriod,0,MAMode,MAPrice,i+2);
    
    // open conditions are at the same time close conditions of an opposite order
    if(m2<=m1 && MathAbs(m1-m2)>0.2*Point) { sBuy[i]=1; sCloseSell[i]=1; sBuyCnt++; sSellCloseCnt++; }
    if(m2>=m1 && MathAbs(m1-m2)>0.2*Point) { sSell[i]=1; sCloseBuy[i]=1; sSellCnt++; sBuyCloseCnt++; }
  }

Y aquí los resultados:

No están mal, pero no son los mejores porque habíamos imaginado unos beneficios increíbles. Ahora probemos a disminuir el período MA para aumentar la posibilidad de ganar en los trades rentables. Al disminuir el periodo de 15 a 17 barras, conseguimos aumentar el beneficio medio diario casi el doble:

Lo que queda es hacer la relación de los trades rentables y los no rentables al menos del 80% al 20%. Pero tendrá que hacerlo sin mi ayuda.

Conclusión

Ahora tiene una herramienta más para expresar el análisis de los indicadores y las alertas de trading. Naturalmente, no sustituyen al tester o al trading real. Todos los datos que se han obtenido utilizando esta herramienta son de carácter descriptivo, una estimación. Sin embargo, la comodidad de funcionamiento y visualización, y la velocidad de los resultados obtenidos, me hacen creer que esta herramienta puede ser muy útil para cualquier desarrollador. Ayuda a comprobar rápidamente las ideas de trading, sin perder demasiado tiempo ni esfuerzo. En cierta medida, puede ser una prueba de si una idea es prometedora o desesperanzada. Y esto puede ser una herramienta para la optimización delicada de los parámetros de un indicador, si pensamos como un investigador o experimentalista.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/1557

Archivos adjuntos |
IndicatorTester.mq4 (15.96 KB)
¿Dormir, o no dormir? ¿Dormir, o no dormir?
Se propone un uso alternativo de la función Sleep() en la realización de las pausas entre las acciones del AE. El método del que se habla aquí permite un uso inteligente del tiempo de máquina.
La inactividad es el estímulo del progreso. Marcado semiautomático de una plantilla. La inactividad es el estímulo del progreso. Marcado semiautomático de una plantilla.
Entre las docenas de ejemplos de cómo trabajar con gráficos, hay un método para marcar manualmente una plantilla. Líneas de tendencia, canales, niveles de apoyo/resistencia, etc. se imponen en un gráfico. Por supuesto que hay algunos programas especiales para este tipo de programas. Cada uno decide pos sí mismo/a qué método utilizar. En este artículo, ofrezco varios métodos de marcado manual para que los considere, con la subsecuente automatización de algunos elementos de acciones rutinarias repetidas.
Carpeta de programa de la Terminal de cliente de MetaTrader4 Carpeta de programa de la Terminal de cliente de MetaTrader4
El artículo describe los contenidos de la carpeta de programa de la Terminal de cliente de MetaTrader 4. El artículo resultará de utilidad a aquellos que ya han empezado a indagar en los detalles del funcionamiento de la terminal de cliente.
Vista del Análisis Técnico en el contexto de Sistemas de Control Automáticos (SCA), o "Vista inversa". Vista del Análisis Técnico en el contexto de Sistemas de Control Automáticos (SCA), o "Vista inversa".
El artículo demuestra una vista alternativa del análisis técnico, que se basa en los principios de la teoría del control automático moderno y el análisis técnico en sí. Es un artículo introductorio representando la teoría con algunas aplicaciones prácticas.