English Русский 中文 Deutsch 日本語 Português
Optimización visual de la rentabilidad de indicadores y señales

Optimización visual de la rentabilidad de indicadores y señales

MetaTrader 4Ejemplos | 11 mayo 2016, 12:53
1 034 0
Sergey Kravchuk
Sergey Kravchuk

Este artículo es una continuación y un desarrollo de mi artículo anterior "Pruebas visuales y rentabilidad de los indicadores y señales". Después de haber añadido un poco de interactividad al proceso de cambio de los parámetros y cambiado los objetivos del estudio, he podido conseguir una nueva herramienta que no sólo muestra los posibles resultados del trading en base a las señales que se usan, sino también nos permite obtener inmediatamente la distribución de las transacciones, el gráfico del balance y el resultado final del trading moviendo los botones deslizantes virtuales que controlan los valores de los parámetros de la señal en el gráfico principal.


Introducción

En primer lugar quiero advertir a los buscadores del Santo Grial y a los criticones: al igual que la herramienta descrita en el artículo anterior, esta no es para nada una varita mágica que permite evitar todas las pérdida y obtener nada más que beneficios. Es simplemente una herramienta que permite hacer los cálculos rápidamente y mostrar sus resultados en un formato visual práctico. Los dibujos del indicador son como elementos de reflexión del trader acerca de las estrategias y señales que se usan en el trading. No obstante, este indicador se convierte en una herramienta muy útil en el trading a corto plazo (en particular el intradía).

La idea de modificar el indicador anterior y darle una nueva forma surgió de un comentario ingenuo y muy sincero publicado junto con la descripción del Asesor Experto en uno de los temas de nuestro foro: "Ha ido bien a lo largo del 2009. De momento estoy satisfecho. Para facilitar el seguimiento de la señal he... El Asesor Experto tenía muy buenas prestaciones en el trading con el símbolo y período de tiempo según el autor. Pero cualquier intento de cambiar los parámetros convertía un buen actor en un criminal que funde casi inmediatamente todo el depósito. Y aunque el autor no haya propuesto utilizar el Asesor Experto en el trading real, se me quedó grabada una idea en la mente: no sólo comprobar los posibles resultados de las operaciones, sino también evaluar el comportamiento y la estabilidad de los resultados del trading. Quería hacerlo de manera rápida y evidente para poder demostrar visualmente la ineficacia de algunas señales y estrategias de trading. Además, me obsesionaba otra idea: el Asesor Experto podría obtener un beneficio decente con los parámetros existentes. Pensé que si podía operar manualmente de esta manera, estaría muy contento con los resultados. ¿Y si se pueden mejorar los resultados todavía más? En general, la tarea "en sí" parecía interesante y empecé a buscar la forma de conseguirlo.


Definición del problema

Estaba claro que la solución tenía que basarse en mi indicador del artículo "Pruebas visuales y rentabilidad de los indicadores y señales", lo que significa que la mayor parte del trabajo ya estaba hecha y sólo hacía falta una mejora. ¿En qué fallaba la implementación anterior? Sin duda, la falta de un mecanismo que permite elegir los parámetros. Sería muy laborioso tener que comprobar los parámetros del indicador cada vez que haya un cambio y luego analizar el dibujo resultante y las líneas de las órdenes mediante los datos del historial. Esto es comprensible, ya que el indicador original fue diseñado para comprobar señales listas, mientras que en este caso se requiere algo más. ¿Qué sería? Aquellos que suelen utilizar a menudo la Prueba de estrategias en MT se lo pueden imaginar. Para evaluar los resultados de una operación hace falta básicamente disponer de los gráficos del balance y la posibilidad de cambiar los parámetros iniciales para el cálculo de los valores de las señales.


Gráfico del balance

Esta resultó ser la tarea más fácil. Puesto que todas las operaciones se dibujan en el gráfico y se conocen los resultados de cada una, sólo tenemos que recogerlos e ir sumando al total. Se puede mostrar el gráfico de aumento (o disminución) en una ventana por separado. Para satisfacer a los que les gusta analizar los resultados expresados en dinero o en puntos hay que proporcionar el parámetro adecuado.


Emulación del control deslizante triangular

Resultó ser mucho más difícil adaptar la plataforma del trading automatizado orientado a objetos a las tareas que requieren la interacción con el trader. Los recursos estándar sólo me han permitido implementar la siguiente secuencia de pasos: seleccionar un indicador, llamar a sus propiedades, modificar los parámetros y volver a calcular. Llevar a cabo esta secuencia por lo menos con una docena de combinaciones requiere un tiempo considerable. Y cuando recibimos los resultados de la décima combinación, se nos habrán olvidado por completo los resultados de la primera.

Al no poder utilizar los elementos estándar de la interfaz gráfica de usuario (GUI) del sistema operativo (botones, casillas de comprobación, casillas combinadas, controles deslizantes, etc.) en los indicadores y Asesores Expertos (a menos que se vayan a utilizar las librerías DLL escritas en otros lenguajes de programación), he tenido que buscar una alternativa adecuada. He optado por el triángulo; es un objeto que se puede añadir fácilmente a cualquier gráfico para utilizarlo como un control deslizante estándar que cambia su valor desde un mínimo hasta un máximo. Si se disponen dos de sus vértices verticalmente (u horizontalmente), mientras se mueve el tercero entre ellos, podemos obtener un control deslizante lineal bastante bueno. La posición vertical de estos vértices permite obtener un flujo más suave (continuo) de valores. Y para poder cambiar varios parámetros a la vez tenemos que implementar la posibilidad de trabajar con distintos triángulos por separado.

Una función especial fue escrito para trabajar con los 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;

  // if there is no triangle, create it
  if(ObjectFind(ParamName) < 0)
  {
    // determine the chart boundaries in the current scale vertically
    WMax = WindowPriceMax();  WMin = WindowPriceMin();

    // calculate the coordinates of points by time...
    tt1 = Time[0] + Period()*60*ParamNo*20; tt2 = tt1 + Period()*60*20;

    // ... and "price"
    vCur = WMin + (ParamValue - vMin) * (WMax - WMin) / (vMax - vMin);

    // create an object and fill it with the color specified in the parameters
    ObjectCreate(ParamName,OBJ_TRIANGLE, 0, tt1,WMax, tt2,vCur, tt1,WMin);
    ObjectSet(ParamName,OBJPROP_COLOR,clr);
  }

  // the triangle exists - get its coordinates
  Triangle[0] = ObjectGet(ParamName,OBJPROP_PRICE1);
  Triangle[1] = ObjectGet(ParamName,OBJPROP_PRICE2);
  Triangle[2] = ObjectGet(ParamName,OBJPROP_PRICE3);

  // arrange the vertices in the order of "increase"
  ArraySort(Triangle);

  // convert the midpoint coordinate to the scale of real values between vMin and vMax
  vCur = vMin + (Triangle[1] - Triangle[0]) / (Triangle[2] - Triangle[0]) * (vMax - vMin);

  // write the value to the object comment
  ObjectSetText(ParamName,DoubleToStr(vCur,2));

  // return the value to the main module
  return(vCur);

}

Los comentarios describen en detalle el algoritmo de la función, por lo que nos vamos a limitar a explicar los parámetros de la función.

ParamNo – el número del parámetro utilizado (determina cómo se mueven los triángulos uno respecto a otro a lo largo del eje el tiempo). Posteriormente, puede cambiar sus ubicaciones y tamaños según sea necesario.

ParamName – el nombre del parámetro que tiene que ser único para distinguir entre los triángulos y su significado que se mostrará en la descripción.

ParamValue – el valor inicial del parámetro (se usa para colocar correctamente el vértice intermedio entre el valor mínimo vMin y el valor máximo vMax que se usaremos en la optimización).

сlr – el color del triángulo.

Se usa el siguiente código para trabajar con los 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);

Se usarán los valores obtenidos posteriormente para calcular las señales correspondientes.

Como ejemplo para del desarrollo y la depuración del indicador, he elegido el indicador propuesto por el usuario <s1>Helen</s1> (<a2>HI_Line_E_RSI_MA.mq4</a2>) que en realidad me inspiró para hacer todo esto. Había que reescribir el bloque del cálculo de la señal para poder utilizarlo en mi indicador, aunque el código casi no cambia:

// fill signal arrays with values and count their number
  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++;}
  }

He optado por prescindir del cuarto parámetro; la relación de ampliación del período para obtener el MA (promedio móvil) largo, por el momento. Simplemente he utilizado el MA que es tres veces más largo que el MA principal (MAPeriod*3). Puede implementarlo por sí mismo si lo desea.

Otra cosa que he añadido al indicador original es el bloque de cálculo y visualización de la curva de balance.

// plot the balance chart
// get profit values one by one and add them up 
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);

El primer bucle lleva a cabo la suma acumulativa de los valores de beneficio de las operaciones establecidas con anterioridad, mientras que el segundo los pone juntos en una "pila" sin espacios entre ellos. En cierto modo, no hay ninguna razón para buscar la correspondencia entre el gráfico superior e inferior: las líneas verticales de apertura y cierre de órdenes no tienen ninguna relación con el gráfico de abajo (es por eso que están desactivadas por defecto).

El código del indicador es el siguiente:

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

    IndicatorOptimizer.mq4 
  
    Visual testing of profitability of indicators and alerts
    
    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

// parameters for displaying chart elements
extern bool   ShowZZ          = true;           // whether to draw ZZ
extern bool   ShowMARKERS     = false;           // whether to draw vertical marker lines
extern int    ProfitWidth     = 1;
extern bool   ProfitInPoints  = true;

//chart plotting dates
extern datetime DateStart     = D'1.01.1970';
extern datetime DateEnd       = D'31.12.2037';

//profit calculation parameters
extern double LotForCalc      = 0.05;           // lot size for profit calculation

// RSI indicator parameters
extern int    RSIPeriod       = 8;              // RSI calculation period
extern int    RSILevel        = 73;             // RSI calculation level

// MA indicator parameters
extern int    MAPeriod        = 20;             // МА calculation period
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


// MACD indicator parameters
extern double MACDOpenLevel   = 3;              
extern double MACDCloseLevel  = 2;
extern double MATrendPeriod   = 26;

// colors of Buy lines
extern color  ColorProfitBuy  = Blue;           // line color for profitable Buys 
extern color  ColorLossBuy    = Red;            // line color for unprofitable Buys
extern color  ColorZeroBuy    = Gray;           // line color for zero-profit Buys

// colors of Sell lines
extern color  ColorProfitSell = Blue;           // line color for profitable Sells
extern color  ColorLossSell   = Red;            // line color for unprofitable Sells
extern color  ColorZeroSell   = Gray;           // line color for zero-profit Sells

// colors of signal lines
extern color  ColorBuy        = CornflowerBlue; // Buy signal line color
extern color  ColorSell       = HotPink;        // Sell signal line color
extern color  ColorClose      = Gainsboro;      // line color of the signal for closing

//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
double sBuy[],sCloseBuy[],sSell[],sCloseSell[]; // arrays for signals
int sBuyCnt,sSellCnt,sBuyCloseCnt,sSellCloseCnt;// signal counters
int i,DisplayBars;
double bBallance[]; // for the balance on operations
int IndicatorWindowNo;  // indicator window number
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// service codes
#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; 

  // if there is no triangle, create it
  if(ObjectFind(ParamName) < 0)
  {
    // determine the chart boundaries in the current scale vertically
    WMax = WindowPriceMax();  WMin = WindowPriceMin();

    // calculate the coordinates of points by time...
    tt1 = Time[0] + Period()*60*ParamNo*20; tt2 = tt1 + Period()*60*20;
    // ... and "price"
    vCur = WMin + (ParamValue - vMin) * (WMax - WMin) / (vMax - vMin);
    // create an object and fill it with the color specified in the parameters
    ObjectCreate(ParamName,OBJ_TRIANGLE, 0, tt1,WMax, tt2,vCur, tt1,WMin);
    ObjectSet(ParamName,OBJPROP_COLOR,clr);
  }
  // the triangle exists - get its coordinates
  Triangle[0] = ObjectGet(ParamName,OBJPROP_PRICE1);
  Triangle[1] = ObjectGet(ParamName,OBJPROP_PRICE2);
  Triangle[2] = ObjectGet(ParamName,OBJPROP_PRICE3);
  // arrange the vertices in the order of "increase"
  ArraySort(Triangle);
  // convert the midpoint coordinate to the scale of real values between vMin and vMax
  vCur = vMin + (Triangle[1] - Triangle[0]) / (Triangle[2] - Triangle[0]) * (vMax - vMin);
  // write the value to the object comment
  ObjectSetText(ParamName,DoubleToStr(vCur,2)); 
  // return the value to the main module
  return(vCur); 
}


//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
int start() 
{ 
  double Profit=0,P1,P2; int CntProfit=0,CntLoose=0,i1,i2;
  // coefficient for conversion of points to the deposit currency
  double ToCurrency = MarketInfo(Symbol(),MODE_TICKVALUE)*LotForCalc;    
  
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // delete all markers in case the indicator is redrawn
  ClearMarkers(); 
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // prepare signal counters
  sBuyCnt=0; sSellCnt=0; sBuyCloseCnt=0; sSellCloseCnt=0; 
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // allocate memory for signal arrays and zero out their values
  DisplayBars=Bars; // number of bars 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);

  // prepare balance calculation
  ArrayInitialize(bBallance,0); 
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————


  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // creating (if necessary) and getting parameters of the control triangle
  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);
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————


  // fill signal arrays with values and count their number
  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++;}
  }

 
        //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // delete repeated signals leaving only the first ones, on the left of 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 signals outside the specified date range
  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 forced closing at the range limit
  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 number of signals
  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++;
  }
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // set markers, draw ZZ and calculate profit
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // process Buys
  for(i=DisplayBars-1;i>=0;i--) // get the points
  {
    // find the next point of opening and save its position and price
    for(i1=i;i1>=0;i1--) if(sBuy[i1]!=0) break; 

    // find the next Buy closing point and save its position and price
    for(i2=i1-1;i2>=0;i2--) if(sCloseBuy[i2]!=0) break;
    if(i2<0) i2=0; // for the last non-closed position, calculate closing on the current price
    i=i2; // new bar to continue the search for points of opening

    // determine prices for drawing 
    P1=Open[i1]; P2=Open[i2];  
    
    P1/=Point; P2/=Point; // convert prices to points
    
    // determine the profit and fill the corresponding buffer
    if(i1>=0) 
    { 
      Profit=Profit+P2-P1; // get the cumulative profit
      if(P2-P1>=0) CntProfit++; else CntLoose++; // count the number of orders
      DrawLine(i1,i2,OP_BUY); // draw the order line
      PlaceMarker(i1,OP_BUY); 
      PlaceMarker(i2,OP_CLOSE_BUY); 
      
      bBallance[i2] += P2-P1;
    }
  }
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // process sells
  for(i=DisplayBars-1;i>=0;i--) // get the points
  {
    // find the next point of opening and save its position and price
    for(i1=i;i1>=0;i1--) if(sSell[i1]!=0) break; 

    // find the next Buy closing point and save its position and price
    for(i2=i1-1;i2>=0;i2--) if(sCloseSell[i2]!=0) break;
    if(i2<0) i2=0; // for the last non-closed position, calculate closing on the current price
    i=i2; // new bar to continue the search for points of opening

    // determine prices for drawing depending on the Optimizm parameter
    P1=Open[i1]; P2=Open[i2]; 
    
    P1/=Point; P2/=Point; // convert prices to points
    
    // if both points exist, determine the profit and fill the corresponding buffer
    if(i1>=0) 
    { 
      Profit=Profit+P1-P2; // get the cumulative profit
      if(P1-P2>=0) CntProfit++; else CntLoose++; // count the number of orders
      DrawLine(i1,i2,OP_SELL); // draw the order line
      PlaceMarker(i1,OP_SELL); 
      PlaceMarker(i2,OP_CLOSE_SELL);
      
      bBallance[i2] += P1-P2;
    }
  }

  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // plot the balance chart
  // get profit values one by one and add them up 
  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);

  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // calculation of the final values for the comment  
  int Cnt=CntProfit+CntLoose; // total number of operations
  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";
  
  // total time in days
  int TotalDays = (MathMin(DateEnd,Time[0])-MathMax(DateStart,Time[Bars-1]))/60/60/24; //convert seconds to days
  if(TotalDays<=0) TotalDays=1; // to avoid zero divide for an incomplete day
  
  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);
  
}
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// deleting all objects from our chart
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)); 
}
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// setting a vertical line - the op_type operation marker
void PlaceMarker(int i, int op_type)
{
  if(!ShowMARKERS) return; // displaying markers is disabled

  color MarkerColor; string MarkName; 

  // __ so that the closing line is drawn below the opening line by 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);
}
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// setting the line on the chart for the op_type operation type using the Optimizm parameter values
void DrawLine(int i1,int i2, int op_type)
{
  if(!ShowZZ) return; // displaying ZZ is disabled
  
  color СurColor;
  string MarkName=MrakerPrefix+"_"+i1+"_"+i2;
  double P1,P2;
  
  // determine prices for drawing depending on the Optimizm parameter
  P1=Open[i1]; P2=Open[i2];  

  ObjectCreate(MarkName,OBJ_TREND,0,Time[i1],P1,Time[i2],P2);
  
  ObjectSet(MarkName,OBJPROP_RAY,False); // draw segments instead of lines
  ObjectSet(MarkName,OBJPROP_BACK,False);
  ObjectSet(MarkName,OBJPROP_STYLE,STYLE_SOLID);
  ObjectSet(MarkName,OBJPROP_WIDTH,2);

  // set the line color depending on profitability of the operation
  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);
}
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

Puede encontrar una descripción detallada del algoritmo y de su funcionamiento en mi artículo anterior. Hay que tener en cuenta que he eliminado la solución temporal para el parámetro de optimización. En esta versión del indicador, se calculan las señales para la barra actual en base a los valores las barras anteriores formadas completamente. Esto sugiere el uso del enfoque de trading clásico basado en el análisis de las barras: después de analizar los resultados de una barra recién formada, abrimos una posición al principio de la barra actual. Podemos decir que los resultados obtenidos son bastante fiables.


El optimizador en acción

Después de compilar el indicador y añadirlo al gráfico, podemos proceder con el análisis. Nos podemos extender en explicar este proceso en detalle, pero gracias a una pequeña animación que muestra el funcionamiento del indicador, todo quedará muy claro.

Hay que tener en cuenta una cosa importante: el indicador vuelve a calcular sus valores con cada nuevo tick, así que después de mover el control deslizante triangular tenemos que esperar el nuevo precio o actualizar el gráfico manualmente o utilizar el emulador de ticks.

Trabajar con el optimizador se está convirtiendo en una especie de juego del tipo "¿y si?". Sólo tiene que elegir los controles deslizantes triangulares y mover sus puntos centrales hacia arriba o abajo. No importa la ubicación horizontal del vértice del triángulo; sólo importa la ubicación vertical de los vértices. Mueva los puntos centrales de los triángulos y trate de comprender lo que producen estos movimientos. Su intuición y su experiencia le dirán seguramente lo que hay que mover y hacia dónde. Bueno, si no tiene experiencia, el método de "prueba y error" no falla: pruebe y busque combinaciones que le convengan y luego haga trading en base a los parámetros establecidos.


Cómo utilizar el indicador. Primera parte: Lo que NO hay que hacer

Al igual que mi anterior indicador, este se debe utilizar mientras tiene muy claro lo que hace y los resultados obtenidos. Puede sustituir el bloque del cálculo de señales con el suyo, así como aumentar o reducir el número de señales a utilizar. Pero al observar los resultados, siempre hay que tener en cuenta que si lleva a cabo la optimización de los parámetros del indicador para EURUSD M30 y le muestran una buena curva de beneficios, esto no quiere decir para nada que los resultados serían buenos con otro par de divisas o un período de tiempo distinto o ambos. Para entender lo que quiero decir, simplemente eche un vistazo a los gráficos M1 y D1. La diferencia entre la naturaleza de los cambios de las barras y sus tamaños es tan evidente que no hace falta hacer ningún comentario más.

La diferencia entre los pares de divisas no es tan obvia pero se puede detectar fácilmente mediante, por ejemplo, la técnica mencionada en mi artículo "Diagnóstico de mercado por pulsos". Las figuras del artículo muestran por qué no hay que esperar los mismos resultados en todos los pares de divisas, incluso si la configuración del bloque de cálculo de señales es la misma.


Cómo utilizar el indicador. Segunda parte: Lo que SE DEBE hacer

A pesar de todo, no está tan mal. Como dicen algunos filósofos: "las debilidades son la prolongación de nuestras fortalezas". Si vemos las deficiencias pero aún no hemos identificado las ventajas, esto no quiere decir que no existen. Eche un vistazo al gráfico D1 con una tendencia al alza a muy largo plazo. ¿De verdad piensa que el indicador optimizado basado en el comienzo de este período no proporcionaría beneficios en la mitad de esta tendencia?

Si decide usar esta herramienta en el trading de vez en cuando, igual que yo, sólo tiene que ajustarla para un par de divisas y un período de tiempo concretos. Puede coger el Asesor Experto propuesto por Helen y probarlo en el trading automatizado, ajustando de vez en cuando sus parámetros a los resultados de la optimización, sobre todo si se tiene en cuenta que el indicador le permite ejecutar sin mucho esfuerzo este proceso varias veces al día y así utilizarlo incluso en los gráficos de minutos (M5, M15 y M30).


Conclusión

En general, el mercado sigue siendo impredicible. Cualquier señal fiable y verificada al 100 % puede convertirse en un abrir y cerrar de ojos en la señal contraria debido a una noticia importante. Es muy probable que los ases del trading traten de convencerle de que nunca podrá conocer el movimiento de los precios y por consiguiente nunca conseguirá unos ingresos estables si no tiene en cuenta algunos conceptos como las señales fundamentales o no dispone de los datos del volumen de la operación. Bueno, es su opinión y es así como operan y triunfan. Se puede utilizar este método para gestionar depósitos de más de mil dólares.

Creo que este indicador puede ser una de las herramientas más sencillas y fiables para los depósitos pequeños. Nunca tendrá una "imagen completa" del movimiento de los precios, así que vale la pena seguir buscando los puntos de inversión y tratar de exprimir hasta el último céntimo del mercado. Las tendencias a largo plazo en días y semanas suelen tener algún patrón general y si puede ver su comienzo y optimizar su sistema de cálculo las señales de acuerdo a este patrón, podrá obtener ganancias con los parámetros optimizados y probablemente en períodos de tiempo no tan cortos. Pero incluso si "cambian los vientos", esto ya no sería un problema para usted puesto que ahora el proceso de optimización es mucho menos laborioso de lo que era antes de que empiece a utilizar este indicador.

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

Archivos adjuntos |
IndicatorOptimizer.zip (1820.28 KB)
Análisis avanzado de una cuenta de trading Análisis avanzado de una cuenta de trading
El artículo aborda el sistema de análisis automático de cualquier cuenta de trading en el terminal de MetaTrader 4. Se describen los aspectos técnicos del informe generado y la interpretación de los resultados obtenidos. Después de una revisión detallada del informe se extraen las conclusiones sobre la mejora de los parámetros del trading. Se usa el script MQLab™ Graphic Report para el análisis.
Lite_EXPERT2.mqh: Un conjunto operativo para los desarrolladores de Asesores Expertos Lite_EXPERT2.mqh: Un conjunto operativo para los desarrolladores de Asesores Expertos
Este artículo es una continuación de la serie de artículos "Asesores Expertos basados en sistemas populares de trading, y un poco de alquimia en la optimización de robots". Permite familiarizar los lectores con una librería de funciones más universales del archivo Lite_EXPERT2.mqh.
Lite_EXPERT2.mqh: Ejemplos de implementación de Asesores Expertos Lite_EXPERT2.mqh: Ejemplos de implementación de Asesores Expertos
En este artículo, el autor sigue familiarizando los lectores con las funciones de Lite_EXPERT2.mqh mediante ejemplos reales de implementación de Asesores Expertos. El artículo aborda el concepto de utilizar las órdenes pendientes flotantes y las órdenes pendientes que cambian de forma dinámica entre una transacción y otra en base al los valores del indicador Average True Range (ATR).
Notificaciones por SMS sobre el estado del Asesor Experto Notificaciones por SMS sobre el estado del Asesor Experto
El desarrollo de un sistema de notificaciones por SMS que le informa sobre el estado de su Asesor Experto para estar siempre al corriente de cualquier situación crítica dondequiera que esté.