Descargar MetaTrader 5

Indicador NRTR y módulos comerciales en su base para el Asistente de MQL5

20 diciembre 2017, 10:57
Dmitrii Troshin
0
533

Introducción

Vamos a analizar el indicador que construye un canal dinámico de precios. A base de este canal se construye un Asesor Experto (EA). Se sabe que semejantes sistemas trabajan bien en las tendencias, pero dan muchas señales falsas en los movimientos laterales. Por eso, para mejorar el resultado, se requieren los indicadores de tendencia adicionales. La elección de este indicador no es una tarea fácil porque a menudo depende de las condiciones concretas del mercado. Por eso, una buena solución sería encontrar la manera de conectar rápidamente cualquier indicador seleccionado al sistema de trading.

Para eso, se utiliza el siguiente enfoque. Vamos a crear un módulo especial de señales de trading para el Asistente MQL5 para nuestro indicador. Luego, para cualquier indicador tendencial que seleccionamos, se puede crear rápidamente un módulo similar que da sólo las señales «Sí» / «No» sobre la presencia o la ausencia de la tendencia. Puesto que durante el diseño de un sistema comercial se puede usar varios módulos, podemos componer fácilmente diferentes combinaciones de los indicadores, sin vincularnos a alguna de ellas en concreto.

Indicador NRTR

El indicador NRTR —Nick Rypock Trailing Reverse— es un indicador cuya idea peretenece a Konstantin Kopyrkin. Una información interesante: el nombre Nick Rypock oculta el apellido «Kopyrkin» escrito al revés.

Pero bueno, volvamos al indicador. Representa un canal dinámico de precios. El autor ilustra su idea principal con la siguiente imagen:


El sistema comercial a base de NRTR pertenece a la clase de la ruptura. Las señales de compra es cuando los precios superan el máximo anterior durante un determinado período de tiempo; las señales de venta es cuendo el precio cae por debajo del mínimo. Durante el cambio de la tendencia, en semejantes sistemas a menudo se toman en cuenta los precios de la tendencia anterior, los máximos y los mínimos anteriores. En nuestro sistema, el período de los cálculos se determina dinámicamente con el fin de evitar eso.

El autor ha definido el NRTR como un indicador tendencial de la ruptura del canal dinámico de precios.

Trabaja de la siguiente manera: si la tendencia es alcista, la línea del indicador (canal) se encuentra a un determinado nivel por debajo del máximo del precio en un intervalo de tiempo establecido. La línea de la tendencia bajista se encuentra por encima de los precios, a una distancia permanente del mínimo durante el período establecido.

Además, el período del canal de precios para los cálculos del indicador se aumenta dinámicamente, partiendo desde el momento del surgimiento de la tendencia. Con este enfoque, el precio del perído anterior de los cálculos no influye en el indicador.

En la imagen se muestra como el indicador primero sigue la tendencia a una determinada distancia. Luego, se encuentra a una distancia fija de los máximos locales H1 y H2. El máximo local H3 es menor que el anterior y no participa en los cálculos.

Luego, el precio rompe el canal en el punto L3. Es una señal de venta. El valor en el punto L3 se hace un nuevo mínimo. A partir de este momento, se empieza la cuenta del tiempo, es decir, todos los precios anteriores se omiten y no participan en los cálculos. Según vaya desarollando la tendencia, el mínimo se actualiza a L3-L4-L5. El período del canal de precios crece también, hasta que la tendencia no se cambie, o el período no alcance el valor máximo establecido.

El ancho del canal se calcula en por cientos del tamaño del extremo, o bien, como opción, depende de la volatilidad de los precios. Ambos enfoque están implementados en este artículo.

La ruptura de la línea del canal por el precio nos sirve como una señal de compra/venta. Si el precio rompe la línea de soporte, se trata de una señal de compra. Si se rompe la línea de resistencia, es una señal de venta.

Tenemos por delante pasar la descripción del trabajo del indicador al lenguaje MQL5. ¡Manos a la obra!

Escribiendo el indicador: "de simple a complejo".

En primer lugar, vamos a determinar el comportamiento del indicador. Va a construirse a base de los precios de cierre close. Está claro que la construcción según los datos históricos va a interpretarse unívocamente. ¿Pero qué pasará si el precio rompe la línea de soporte/resistencia en una vela no formada? En esta implementación, la tendencia no se cambia y la señal no aparece hasta que la vela no quede formada. Por un lado, posemos perder una parte del movimiento. Si, por ejemplo, el movimiento ha empezado a partir de una vela enorme que ha roto el canal, entraremos en la transacción sólo en la siguiente. Por otro lado, así, nos defendemos de varias rupturas falsas.

NB: este indicador tiene muchas variantes, por eso aquí se describe sólo su variante original descrita por el autor.

Puede encontrar la implementación de este indicador en CodeBase, donde el período es dinámico sólo parcialmente. Se pone a cero cuando se cambia la tendencia, pudiendo crecer en el futuro sin limitación alguna. Es decir, la línea de soporte se calcula como MathMax() del valor anterior y del precio actual close. En caso de esta implementación, el soporte sólo puede crecer y la resistencia sólo caer. Originalmente, se suponía que los valores anteriores pierden su valor y se omiten fuera del período establecido. Por eso, aquí max/min se busca a través de ArrayMaximum/Minimum(close,i,dynamic_period). Con este enfoque, las líneas de soporte/resistencia pueden tanto crecer, como bajar. Por tanto, pueden surgir las situaciones, por ejemplo, durante los períodos dinámicos pequeños, cuando la línea de soporte «se deriva» bastante hacia abajo en un movimiento lateral «lento». Pero estas tendencias suaves rolongadas son muy raras, y los métodos ideales no existen. Y como ya ha sido dicho antes, nuestro principio básico consiste en seguir la idea principal del autor.

Otra cosa importante son las series temporales. En MQL5, los arrays de precios (close) tienen por defecto el valor ArraySetAsSeries = false. Para los que trabajaban en MQL4, era más acostumbrado que los arrays de precios tenían la bandera de la serie temporal, y Close[0] era el precio de cierre de la barra derecha (normalmente, no vemos la barra más izquierda). Yo entiendo que es la cosa de la costumbre, pero en este artículo es ArraySetAsSeries(close,true).

Ahora, pasamos a la ejecución. Tendremos cuatro búferes de indicadores: dos se usarán para las líneas de soporte/resistencia y otros dos, para las señales de compra/venta.

#property indicator_chart_window
#property indicator_buffers 4 
#property indicator_plots   4

//Indicators lienes style
#property indicator_type1  DRAW_LINE
#property indicator_color1 Green
#property indicator_style1 STYLE_DASH

#property indicator_type2  DRAW_LINE
#property indicator_color2 Red
#property indicator_style2 STYLE_DASH

#property indicator_type3  DRAW_ARROW
#property indicator_color3 Green

#property indicator_type4  DRAW_ARROW
#property indicator_color4 Red

Declaramos los búferes de indicadores y los parámetros externos del indicador.

input int    period =12;      //período dinámico
input double percent =0.2;    //porcentaje del margen 

double Buff_Up[],Buff_Dn[];  
double Sign_Up[],Sign_Dn[];

Las señales van a mostrarse como flechas. Estableceremos otros parámetros personalizados en la función OnInit(). Tengo DRAW_ARROW  establecidos en 236,238 con loscaracteres de la fuente Wingdings. Los parámetros para la señal «arriba», por ejemplo:

   SetIndexBuffer(2,Sign_Up,INDICATOR_DATA);
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,0.0);
   PlotIndexSetInteger(2,PLOT_ARROW,236);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,1);
   ArraySetAsSeries(Sign_Up,true);

Cuando se empiezan los cálculos, en la función OnCalculate() se realizan las comprobaciones estándar de la suficiencia de los datos y la verificación del primer inicio del cálculo del indicador.

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
  
  int start =0;                                           //punto del cálculo
  
  int trend =0;                                           //valor de la tendencia arriba 1, abajo -1
  static int trend_prev =0;
  
  double value =0;                                        //valor del indicador  
  static double value_prev =0;
  
  int dyn_period =1;                                     //valor del período                                    
  static int curr_period =1;
  
  
  double maxmin =0;                                       //variable técnica para los cálculos
  
  ArraySetAsSeries(close,true);
  
  if(rates_total<period) return(0);
  
     if(prev_calculated==0)                              // verificación del primer inicio del cálculo del indicador
  {
      start=rates_total-1;                               // número inicial para el cálculo de todas las barras
      trend_prev =1;
      value=close[start]*(1-0.01*percent);      
  }
  
  else
     {
      start=rates_total-prev_calculated;                  // número inicial para el cálculo de nuevas barras
     }

trend =trend_prev;
value =value_prev;
dyn_period =curr_period;

Aquí mismo se determinan las variables principales. Para los valores de la tendencia y del canal se determinan dos variables, una de las cuales es estática. La variable estática es necesaria para almacenar el valor hasta el siguiente ciclo de los cálculos. Ella va a cambiar sólo en la barra ya formada. En caso de la ruptura del canal en una vela no formada, se cambian sólo las variables locales no estáticas. Y si el precio vuelve dentro de los límites del canal, la tendencia se guarda.

Ahora, escribiremos el ciclo principal de los cálculos tomando en cuenta las advertencias arriba descritas.

trend =trend_prev;
value=value_prev;
dyn_period =curr_period;    
//-------------------------------------------------------------------+
//                        Ciclo principal del cálculo   
//-------------------------------------------------------------------+  
for(int i=start;i>=0;i--)
{
    Buff_Up[i] =0.0;
    Buff_Dn[i] =0.0;
    Sign_Up[i] =0.0;
    Sign_Dn[i] =0.0;
    
    if(curr_period>period) curr_period=period;
    if(dyn_period>period) dyn_period=period;
    
 //if trend ascending   
    if(trend>0)
    {
    maxmin =close[ArrayMaximum(close,i,dyn_period)];
    value =maxmin*(1-percent*0.01);
    
    if(close[i]<value)
      {
      maxmin =close[i];
      value =maxmin*(1+percent*0.01);
      trend =-1;
      dyn_period =1;
      }
    }
  
//  if trend descending
    else
    {
    maxmin =close[ArrayMinimum(close,i,dyn_period)];
    value =maxmin*(1+percent*0.01);
    if(close[i]>value)
      {
      maxmin =close[i];
      value =maxmin*(1-percent*0.01);
      trend =1;
      dyn_period =1;
      }
    }  
 // trend changes 
  
      if(trend>0) Buff_Up[i] =value;
      if(trend<0) Buff_Dn[i] =value;

      if(trend_prev<0  &&  trend>0) 
      {
      Sign_Up[i] =value;
      Buff_Up[i] =0.0;
      }
      if(trend_prev>0 && trend<0)
      {
      Sign_Dn[i] =value;
      Buff_Dn[i] =0.0;
      }

  dyn_period++;
  
  if(i)
  {
  trend_prev =trend;
  value_prev =value;
  if(dyn_period==2)curr_period =2;
  else curr_period++;
  }

}

En el ciclo, el período dinámico se limita con un valor establecido. Se encuentran nuevos valores de soporte/resistencia y se realiza la comprobación del cambio de la tendencia si el canal ha sido roto por el precio de cierre. El último operador if() sirve de la comprobación de la terminación de la barra. Sólo si la barra ya está formada, se cambian los valores trend_prev, value_prev,а y por consiguiente, se puede dar la señal para la compra/venta. Aquí mismo el período dinámico puede ser «reseteado».

El código completo del indicador se encuentra en el archivo adjunto NRTR.mq5.

Veamos el trabajo del indicador, colocando en el gráfico dos NRTR con diferentes parámetros: el primero con el período 12 y el ancho 0,1%; el segundo con el período 120 y el ancho 0,2%.


En la imagen se ve muy bien que en caso de un período pequeño, la línea de soporte puede tanto crecer, como bajar. Eso sucede debido a la «salida» de los precios fuera del período dinámico. En caso de los períodos grandes, suele ser ascendiente.

Volatilidad y NRTR

En el enfoque anterior, se utiliza la desviación fija porcentual del canal de precios. Sería más lógico si el canal se extendiera en caso del aumento de la volatilidad, y se restringiera en caso de su desminución. Para estimar la volatilidad en el mercado, suelen usar el indicador ATR (average true range). El valor de ATR puede servir para establecer el ancho del canal. Podemos calcularlo personalmente, o bien podemos usar el indicador técnico ya hecho que ya entra en la entrega estándar del terminal.

Para vincular el ancho del canal con la volatilidad, simplemente reemplazamos la desviación porcentual por el valor del indicador ATR. Dejaremos el propio coeficiente para el escalamiento. Que tenga por defecto un 1. Para el indicador ATR, declaramos otro búfer de indicador double Buff_ATR[]. Reemplazamos el parámetro del por ciento por el parámetro del coeficiente K =1. Para obtener los valores de ATR, creamos un puntero a él:

handle_atr =iATR(_Symbol,PERIOD_CURRENT,period);

El período de ATR puede diferenciarse del período dinámico existente, pero sería lógico que coincidan, y el número de los parámetros quede el mismo.

Abajo se muestra el código sólo de las líneas recién añadidas.

#property indicator_buffers 5 
#property indicator_plots   4
.............................
input double K =1;            //coeficiente de la escala
double Buff_ATR[];
int handle_atr;
.............................
SetIndexBuffer(4,Buff_ATR,INDICATOR_CALCULATIONS);
ArraySetAsSeries(Buff_ATR,true);
         
handle_atr =iATR(_Symbol,PERIOD_CURRENT,period);
.....................................................
int OnCalculate(){
.....................................................
  if(CopyBuffer(handle_atr,0,0,start+1,Buff_ATR)==-1)
  {
  return(0);
  Print("Fallo al copiar los datos al búfer de ATR");
  }
.....................................................

//if trend ascending  
  if(trend>=0)
  {
  maxmin =close[ArrayMaximum(close,i,dyn_period)];
  value =maxmin-K*Buff_ATR[i];
  
  if(close[i]<value)
   {
   maxmin =close[i];
   value =maxmin+K*Buff_ATR[i];
   trend =-1;
   dyn_period =1;
   }
  }
 
}

Los valores de las líneas del canal se encuentran como value = maxmin(+-)K*Buff_ATR[i], respectivamente. Puede ver el código completo del indicador en el archivo adjunto NRTRvolatile.mq5.

Para la amyor claridad, vamos a arrancar ambos indicadores con los mismos parámetros en el gráfico, y compararemos su comportamiento.


En la imagen podemos ver que en caso de una volatilidad baja y los valores de ATR pequeños, la línea NRTRvolatile prácticamente «se pega» al gráfico de precios. Luego, cuando la volatilidad se aumenta, ella se aparta de él.

Ahora, vamos a escribir el EA a base de nuestro indicador. Como ya ha sido planeado, lo vamos a hacer a través de la escritura del módulo de señales de trading.

Módulo comercia para el Asistente MQL5

A menudo resulta más cómodo escribir semejantes módulos a través del método copy/paste, usando los que ya existen. Pero en este caso, será más fácil empezar desde el principio que explicar qué es lo que es necesario cambiar o modificar.

Describiremos la estructura común de todos los módulos.

  • Handle del módulo
  • Parámetros del trading y funciones para su inicialización
  • Verificación de los parámetros de entrada
  • Vinculación del indicador seleccionado a este módulo
  • Descripción de la estrategia comercial

En primer lugar, en la carpeta con las señales, es mejor crear una carpeta aparte para sus propias señales. Por ejemplo, Include\Expert\MySignals. Hacemos clic derecho en la carpeta seleccionada y elegimos «Nuevo archivo» en el menú contextual. Se abre el Asistente para MQL5 Elegimos «Nueva clase» en el menú. La llamaremos NRTRsignal. Todas las señales se heredan de la clase base CExpertSignal, vamos a indicar eso en el Asistente.


Añadimos la ubicación de la clase base al código generado por el Asistente CExpertSignal: #include "..\ExpertSignal.mqh"

//+------------------------------------------------------------------+
//|                                                   SignalNRTR.mqh |
//|                                                       Orangetree |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Orangetree"
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "..\ExpertSignal.mqh"                  // clase CExpertSignal 
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class SignalNRTR : public CExpertSignal
  {
private:

public:
                     SignalNRTR();
                    ~SignalNRTR();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
SignalNRTR::SignalNRTR()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
SignalNRTR::~SignalNRTR()
  {
  }
//+------------------------------------------------------------------+

Pues, el comienzo ya está dado.

Ahora, para que el Asistente MQL5 pueda identificar nuestro código como un módulo de señales, crearemos el handle de nuestro módulo a imagen y semejanza de otras señales.

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of indicator 'NRTR'                                |
//| Type=SignalAdvanced                                              |
//| Name=NRTR                                                        |
//| ShortName=NRTR                                                   |
//| Class=SignalNRTR                                                 |
//| Page=????                                                        |
//| Parameter=PeriodDyn,int,12,Período del canal dinámico           |
//| Parameter=PercentDev,double,0.1,Ancho del canal en por cientos      |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class SignalNRTR.                                                |
//| Purpose: Class of generator of trade signals based on            |
//|          the 'NRTR' indicator.                                   |
//| Is derived from the CExpertSignal class.                         |
//+------------------------------------------------------------------+

El handle comienza con las palabras "wizard description start" y se termina con las palabras " wizard description end". Dentro se encuentra el nombre del módulo y los parámetros externos. En cuanto compilemos el módulo junto con el handle, nuestro módulo aparecerá en el menú del Asistente (Nuevo archivo/Asesor Experto(generar)/Parámetros generales/Parámetros de señales para EAs/Añadir).

Módulo

Hay que añadir las variables para almacenar los parámetros externos y los métodos de su inicialización a nuestra clase.

Los nombres de los métodos de la inicialización de los parámetros externos tienen que coincidir con los nombres de los parámetros externos que figuran en el handle.

class SignalNRTR : public CExpertSignal
  {
protected:
   int m_period_dyn;                                   //Período del canal
   double m_percent_dev;           //Ancho del canal en por cientos del precio
 
public:
                     SignalNRTR();
                    ~SignalNRTR();
   //--- methods of setting adjustable parameters
   void              PeriodDyn(int value)                 { m_period_dyn=value;}
   void              PercentDev(double value)             { m_percent_dev=value;}
   
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
SignalNRTR::SignalNRTR() : m_period_dyn(12),
                           m_percent_dev(0.1)
  {
  //--- initialization of protected data
   m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }

Los miembros de la clase se inicializan a través de la lista de inicialización. Usted puede reemplazar "private" generado por el Asistente por "protected", pero eso no es necesario.

Para comprobar la corrección de la entrada de los parámetros, en la clase CExpertBase se usa el método virtual bool ValidationSettings().

En la clase creada por nosotros, hay que añadir el prototipo del método y redefinirlo. Por ejemplo, vamos a comprobar que el período sea más de 1 y el porcentaje de la desviación sea positivo.

//+------------------------------------------------------------------+
//| el método  comprueba los parámetros de entrada                              |
//+------------------------------------------------------------------+
bool SignalNRTR:: ValidationSettings()
  {
   // llamamos al método de la clase base
   if(!CExpertSignal::ValidationSettings())  return(false);
   
   // el período tiene que ser más de 1
   if(m_period_dyn<2)
   {
   Print("El período tiene que ser más de 1");
   return(false);
   }
   // El ancho del canal tienen que ser positivo
   if(m_percent_dev<=0)
   {
   Print("El ancho del canal tienen que ser positivo");
   return(false);
   }
   
   return true;
  }

Obsérvese una particularidad: primero se llama el método de la clase base.

Para conectar un determinado indicador a nuestro módulo, usamos el método InitIndicators(). Hacemos de nuevo el prototipo de este m”etodo en nuestra clase: virtual bool InitIndicators(CIndicators *indicators), luego hacemos su descritción. Para eso, existen unos procedimientos estándar de la verificación del puntero al indicador y trabaja la inicializaciñin de los indicadores y series temporales en los filtros adicionesles.

//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool SignalNRTR::InitIndicators(CIndicators *indicators)
   {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);  
//--- create and initialize NRTR indicator
if(!InitNRTR(indicators))
      return(false);
//--- ok
   return(true);
   }

В строке InitNRTR(indicators) creamos e inicializamos nuestro indicador. Además, hay que añadir el prototipo y la descripción de la función InitNRTR(indicators).

//+------------------------------------------------------------------+
//| Create NRTR indicators.                                          |
//+------------------------------------------------------------------+  
bool SignalNRTR::InitNRTR(CIndicators *indicators)
   {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- add object to collection
   if(!indicators.Add(GetPointer(m_nrtr)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- establecimiento de los parámetros de NRTR
   MqlParam parameters[3];
//---
   parameters[0].type=TYPE_STRING;
   parameters[0].string_value="Orangetree\\NRTR.ex5";
   parameters[1].type=TYPE_INT;
   parameters[1].integer_value=m_period_dyn;      // período
   parameters[2].type=TYPE_DOUBLE;
   parameters[2].double_value=m_percent_dev;      // ancho del canal
//--- initialize object
   if(!m_nrtr.Create(m_symbol.Name(),m_period,IND_CUSTOM,3,parameters))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);   
   }

El indicador se crea a través de la estructura MqlParam y el método Create().

Todas las construcciones previas están hechas. Ahora es necesario escribir el algoritmo del trading. Los métodos LongCondition() y ShortCondition() nos ayudarán en eso. Añadimos los métodos para obtener las señal del indicador.

   //--- methods of getting data
   double            UpSignal(int index)                   { return(m_nrtr.GetData(2,index));}
   double            DnSignal(int index)                   { return(m_nrtr.GetData(3,index));}

La función  GetData() obtiene el valor del búfer del indicador según su índice o el índice de la barra. Nuestro indicador ya contiene la señal sobre el cambio de la tendencia. Por eso las condiciones para la apertura de la posición son simples. Compramos si el indicador da la señal «arriba» y vendemos si la señal es «abajo».

//+------------------------------------------------------------------+
//| "Voting" that price will grow.                                   |
//+------------------------------------------------------------------+
int SignalNRTR::LongCondition(void)
   {
   int idx   =StartIndex();
   if(UpSignal(idx))
      return 100;
   else return 0;
   }
//+------------------------------------------------------------------+
//| "Voting" that price will fall.                                   |
//+------------------------------------------------------------------+
int SignalNRTR::ShortCondition(void)
   {
   int idx   =StartIndex();
   if(DnSignal(idx))
      return 100;
   else return 0;
   }

En estas funciones, se determina no sólo el algoritmo de trading, sino también las particularidades de su comportamiento. Aquí, se usa la función StartIndex().

En la descripción de la función virtual int StartIndex() se dice lo siguiente: "Si la bandera del análisis de la barra actual está establecida, se devuelve 0 (el análisis va a realizarse a partir de la barra actual). Si la bandera del análisis de la barra actual no está puesta, se devuelve 1 (el análisis va a realizarse a partir de la última barra formada)." En nuestro sistema comercial, se utiliza solamanete las señales de las barras formadas. Por defecto, la función StartIndex() devuelve 1, lo que corresponde a nuestra estrategia. En el EA obtenido después a base del módulo, eso será reflejado en el parámetro Expert_EveryTick con el valor false.

Aquí, la creación del módulo de las señales comerciales está terminada.

Para comprobar que todo funciona correctamente, vamos a usar el Probador de estrategias.


De paso, optimizamos los parámetros comerciales. La optimización fue realizada para el último mes 25.09.17 — 18.10.17 en EURUSD, timeframe H1. Fueron optimizados sólo los parámetros del indicador: período y ancho del canal. Stop Loss y Take Profit = 0.


En la imagen, se muestra el resultado para el período 48 y el ancho del canal 0,25%.

Combinaciones de NRTR + diferentes indicadores de tendencia

Supongamos que queremos la confirmación de las señales de nuestro indicador. Puesto que trabaja bien en la tendencia, sería lógico añadir también un indicador tendencial al sistema. En este artículo, tenemos hechos los módulos de señales del Asistente MQL5. Por eso, seguiremos trabajado según esta metodologís: vamos a añadir el indicador tendencial a nuestro EA a través de los módulos de las señales.

La definición de la tendencia no es una tarea fácil. Por eso, no vamos a discutir aquí cuál de los indicadores de tendencia es mejor o peor. Simplemente elegimos cualquiera de ellos en la entrega estándar, porque nuestro objetivo principal es sólo probar la metodología del «enlace» del indicador a través del módulo comercial. El resultado del trading no nos interesa en esta etapa.

Todos los pasos de la creación del módulo han sido analizados en el apartado anterior. Entonces, desde este momento será más conveniente usar el método "copy/paste" y evaluar sus ventajas. Simplemente cogemos cualquier módulo hecho y reemplazamos todas las líneas necesarias.

Supongamos que hemos elegido ADX en la sección «Tendenciales», que forma parte de los indicadores técnicos. Como referencia a él, se puede usar el puntero CiADX reservado especialmente para él, en vez del puntero al indicador personalizado CiCustom. Por tanto, se puede crearlo de una manera un poco diferente a través del método Create, sin indicar obligatoriamente la ruta hacia él.

protected:
   CiADX m_adx;                                    // object-indicator
   int m_period_adx;                               //Período ADX
....................... otro código.....................................

//--- initialize object
   if(!m_adx.Create(m_symbol.Name(),m_period,m_period_adx))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }

Este indicador tiene sólo un parámetro, es el período. Hay que reflejar eso en el handle y en las funciones del establecimiento de los parámetros. También hay que añadir las funciones para obtener los valores de los búferes ADX.

//| Parameter=PeriodADX,int,14,Período del indicador ADX 
.....................................................

//--- methods of setting adjustable parameters
void              PeriodADX(int value)                { m_period_adx=value;}
.....................................................

//--- methods of getting data
double            MainADX(int index)                   { return(m_adx.Main(index));}
double            ValueIDPlus(int index)               { return(m_adx.Plus(index));}
double            ValueIDMinus(int index)              { return(m_adx.Minus(index));}

En una palabra, hacemos todos los pasos necesarios descritos en el apartado de la creación del módulo comercial. Reemplazamos NRTR por ADX donde sea necesario. Las condiciones del trading simlemente las cogemos de la descripción del indicador ADX, sin comprobar su certeza. La versión clásica es:

  • Comprar si +DI >-DI y ADX crece.
  • Vender si +DI <-DI y ADX crece.
//+------------------------------------------------------------------+
//| "Voting" that trend is "Down".                                   |
//+------------------------------------------------------------------+
int SignalADX::LongCondition(void)
   {
   int idx   =StartIndex();
   if(ValueIDPlus(idx)>ValueIDMinus(idx)&&MainADX(idx)>MainADX(idx+1))
      return (100);
   else
      return (0);
   }
//+------------------------------------------------------------------+
//| "Voting" that trend is "UP".                                    |
//+------------------------------------------------------------------+
int SignalADX::ShortCondition(void)
   {
   int idx   =StartIndex();
   if(ValueIDPlus(idx)<ValueIDMinus(idx)&&MainADX(idx)>MainADX(idx+1))
      return (100);
   else
      return (0);
   }

Es el principio básico. Damos la señal de compra si consideramos que el indicador muestra una tendencia alcista, y la señal de venta si la tendencia es bajista. Por conveniencia, el peso de la señal es igual a 100.

Volvemos a abrir el Asistente para MQL5. Seleccionamos dos señales comerciales durante la creación del EA: SignalNTRTR y ADXTrendSignal. Si hay varias señales, se busca su valor medio. Por eso, asignamos los coeficientes de peso iguales a 1 para ambas señales. Por tanto, el valor umbral para la apertura será de 100. Ponemos a cero todos los demás parámetros, salvo el período y el ancho del canal. Iniciamos el Probador de estrategias y nos cercionamos de que todo funciona correctamente.


Conclusión

Hagamos el resumen. Hemos analizado el indicador tendencial de la ruptura del canal dinámico de precios NRTR. Han sido desarrolladas dos de sus versiones: una con desviación fija porcentual de la línea de tendencia desde los extremos del precio, y otra con desviación que depende de la volatilidad de los precios en el mercado.

Amvas versiones del indicador se adjuntan al artículo. A base del NRTR, hemos escrito el módulo de señales comerciales, a través del Asistente para MQL5, hemos generado un Asesor Experto.

Como ejemplo del uso del NRTR, ha sido creado el módulo para el indicador ADX, junto con los indicadores tendenciales de acuerdo con la metodología arriba expuesta. En el Asistente para MQL5, hemos generado el Asesor Experto a base de NRTR + ADX. La optimización de la combinación NRTR + indicador tendencial no ha sido realizada porque la selección de un indicador de tendencia es la cuestión de una preferencia personal, siendo un tema de otro artículo. Este enfoque se basa en una filosofía modular, combinatoria.

Durante el trabajo con los archivos adjuntos, hace falta recordar que las rutas hacia los indicadores y señales comerciales se indican tomando en cuenta el lugar donde se ubica el módulo o el indicador: por ejemplo, en el archivo SignalNRTR, como lo tengo yo:

   parameters[0].string_value="NRTR.ex5";

Pero es necesario especificar la ruta dependiendo del lugar donde Usted coloca sus propios indicadores.

Archivos:

#NombreTipoDescripción
1NRTR.mq5IndicadorCódigo fuente del indicador considerado en el artículo
2NRTRvolatile.mq5IndicadorCódigo fuente del indicador que toma en cuenta la volatilidad de los precios
3SignalNRTR.mqhMódulo comercialMódulo de señales comerciales. Se usa para la generación de los EAs en el Asistente para MQL5
 ADXTrendSignal.mqhMódulo comercial Módulo de prueba del indicador de tendencia

En la carpeta MQL5.zip  los archivos se ubican de acuerdo con los directorios de MetaEditor.

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

Archivos adjuntos |
NRTR.mq5 (11.09 KB)
NRTRvolatile.mq5 (11.93 KB)
SignalNRTR.mqh (14.21 KB)
ADXTrendSignal.mqh (12.54 KB)
MQL5.zip (8.39 KB)
Simulación de patrones que surgen al comerciar con cestas de parejas de divisas. Parte II Simulación de patrones que surgen al comerciar con cestas de parejas de divisas. Parte II

Seguimos con la simulación de los patrones y la comprobación de las metodologías descritas en los artículos sobre la negociación con cestas de parejas de divisas. Vamos a considerar en la práctica si se puede usar los patrones de la intersección de la media móvil por el gráfico de WPR combinado, y si se puede, de qué manera.

Comparación de diferentes tipos de media móvil en el comercio Comparación de diferentes tipos de media móvil en el comercio

Se han analizado 7 tipos de medias móviles (MA), asimismo, se ha desarrollado una estrategia comercial para trabajar con ellas. Se ha realizado la simulación y la comparación de diferentes MA en una estrategia comercial, dando una característica comparativa de la efectividad del uso de las diferentes MA.

Evaluación del riesgo en la secuencia de transacciones con un activo. Continuación Evaluación del riesgo en la secuencia de transacciones con un activo. Continuación

Este artículo desarrolla las ideas propuestas en la parte anterior y continua su análisis. Aquí se describen las cuestiones de la distribución de los beneficios, la modelación y el estudio de las regularidades estadísticas.

El comercio nocturno en la sesión asiática: cómo mantener los beneficios El comercio nocturno en la sesión asiática: cómo mantener los beneficios

En el artículo se analizan el concepto de comercio nocturno, sus estrategias comerciales y su implementación en MQL5. Se han realizado varias simulaciones y se han sacado las conclusiones pertinentes.