Descargar MetaTrader 5

Filtrar Señales Basadas en Datos Estadísticos de Correlación de Precios

25 marzo 2014, 15:09
Михаил Тарачков
0
687

Cómo Empezó Todo

La idea que me llevó a escribir este artículo se me ocurrió tras leer el libro de Larry Williams "Long-Term Secrets to Short-Term Trading" ("Secretos a Largo Plazo para el Trading a Corto Plazo"), en el que la persona con el récord mundial de inversiones (en 1987 aumentó su capital en un 11.000%) echa por tierra los mitos creados por "... profesores universitarios y otros académicos con mucho conocimiento de la teoría, pero poco conocimiento del mercado..." sobre la ausencia de correlación alguna entre el comportamiento pasado de precios y las tendencias futuras.

Si lanza una moneda al aire 100 veces, 50 veces obtendrá cara, y las otras 50 veces, cruz. Con cada lanzamiento de la moneda, la probabilidad de que salga cara es del 50%, al igual que cruz. La probabilidad no cambia de lanzamiento en lanzamiento, porque este juego es aleatorio y no tiene memoria. Supongamos que los mercados se comportan como una moneda, de forma caótica.

Consecuentemente, cuando aparece una nueva barra, un precio tiene las mismas posibilidades de ir hacia arriba que hacia abajo, y las barras anteriores no le afectarán en absoluto. ¡Idílico! Cree un sistema de trading, configure el Take Profit mayor que el Stop Loss (es decir, configure las expectativas matemáticas en la zona positiva), y el truco está listo. Simplemente maravilloso. No obstante, el problema está en que nuestras suposiciones sobre el comportamiento del mercado no son del todo ciertas. Hablando francamente, ¡es absurdo! Y se lo demostraré.

Creemos una plantilla de Asesor Experto (EA, por sus siglas en inglés) usando el MQL5 Wizard y, usando intervenciones alfanuméricas simples, presentémosla en buenas condiciones para el cumplimiento de esta tarea. Codificaremos un Asesor Experto para simular una compra que sigue a una, dos y tres barras cerradas. La simulación significa que el programa simplemente recordará los parámetros de las barras analizadas. Enviar órdenes (una forma más común) no funcionará en este caso, porque los diferenciales e intercambios pueden poner en tela de juicio la fiabilidad de la información recibida.

Aquí está el código:

//+------------------------------------------------------------------+
//|                                                     explorer.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//---Variables---
double profit_percent,open_cur,close_cur;
double profit_trades=0,loss_trades=0,day_cur,hour_cur,min_cur,count;
double open[],close[];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
/* Calculate percent of closures with increase from the total number */
   profit_percent=NormalizeDouble(profit_trades*100/(profit_trades+loss_trades),2);
   Print("Percent of closures with increase ",profit_percent,"%");   // Enter data to the Journal
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---find out the time---
   MqlDateTime time;                        // Create a structure to store time
   TimeToStruct(TimeCurrent(),time);         // Structuring the data
   day_cur=time.day_of_week;              // Receive the value of the current day
   hour_cur=time.hour;                    // Receive the current hour
   min_cur=time.min;                      // Receive the current minute
//---Find out the prices---
   CopyOpen(NULL,0,0,4,open);ArraySetAsSeries(open,true);
   CopyClose(NULL,0,0,4,close);ArraySetAsSeries(close,true);

   if(close[1]<open[1]/*&&close[2]<open[2]&&close[3]<open[3]*/ && count==0) // If it closed with a loss
     {
      open_cur=open[0];                   // Remember open price of the current bar
      count=1;
     }
   if(open_cur!=open[0] && count==1)      // The current bar has closed
     {
      close_cur=close[1];                 // Remember the close price of the formed bar
      count=0;
      if(close_cur>=open_cur)profit_trades+=1;  // If the close price is higher than open,
      else loss_trades+=1;                      // +1 to closures with profit, otherwise +1 to closures with loss
     }
  }
//+------------------------------------------------------------------+

La simulación se llevará a cabo en EUR/USD, o en el intervalo desde el 1 de enero del 2000 al 31 de diciembre de 2010:

Figura 1. El porcentaje de cierres con el aumento.

Figura 1. El porcentaje de cierres con el aumento

(La primera columna muestra datos para el período entero; la segunda, tercera y cuarta, tras una solo cierre, uno doble y uno triple.)

¡A esto me refería! Las barras anteriores tienen un impacto bastante significativo en la actual, porque el precio siempre tiende a recuperar sus pérdidas.


Otro paso adelante

¡Genial! Una vez que estamos seguros de que el comportamiento de precios no es accidental, deberíamos aprovechar este sorprendente hecho lo antes posible. Por supuesto, no es suficiente para un sistema de trading independiente, pero será una buena herramienta que le liberará de las pesadas y a menudo incorrectas señales. ¡Implementémoslo, pues!

Esto es lo que necesitamos:

  1. Un sistema de auto-trading que muestre resultados positivos al menos durante el pasado año.
  2. Un divertido ejemplo que confirme la presencia de correlaciones en el comportamiento de los precios.

Yo encontré muchas ideas útiles en el libro de L. Williams. Compartiré una de ellas con usted.

La estrategia TDW (Trade Day Of Week, o Día de Trading de la Semana). Nos permitirá ver qué ocurre si algunos de los días de la semana solo compramos, y en los otros solo abrimos posiciones cortas. Después de todo, podemos asumir que el precio dentro de un día crece en un porcentaje mayor de casos que dentro de otro. ¿Cuál es la razón? ¿La situación geopolítica, estadísticas macroeconómicas o el hecho de que, como se dice en el libro de A. Elder, los lunes y martes son días de gente sencilla, mientras que los jueves y los viernes son días de profesionales? Tratemos de entenderlo.

Primero, solo compraremos cada día de la semana, y después solo venderemos. Al final del estudio compararemos los resultados, y esto será un filtro para nuestro sistema de trading. Por cierto, tengo algunos comentarios sobre ello. ¡Es un clásico!

El sistema está basado en dos MAs y MACDake. Señales:                                                            

  1. Si la media móvil rápida cruza la lenta de abajo hacia arriba y el histograma MACD se encuentra por debajo de la línea de cero, entonces COMPRE.
  2. Si la media móvil rápida cruza la lenta de arriba hacia abajo y el histograma MACD se encuentra por encima de la línea de cero, entonces VENDA

Salga de una posición usando un trailing stop (rastreo de detención) desde un punto. El lote está fijado - 0,1. 

 Por motivos de conveniencia, he colocado la clase del Asesor Experto en un archivo de encabezamiento separado:

//+------------------------------------------------------------------+
//|                                                       moving.mqh |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//+------------------------------------------------------------------+
//| Класс my_expert                                                  |
//+------------------------------------------------------------------+
class my_expert
  {                                                  // Creating a class
   // Closed class members
private:
   int               ma_red_per,ma_yel_per;          // Periods of MAs
   int               ma_red_han,ma_yel_han,macd_han; // Handles
   double            sl,ts;                          // Stop orders
   double            lots;                           // Lot
   double            MA_RED[],MA_YEL[],MACD[];       // Arrays for the indicator values
   MqlTradeRequest   request;                         // Structure of a trade request
   MqlTradeResult    result;                          // Structure of a server response
                                                    // Open class members   
public:
   void              ma_expert();                                   // Constructor
   void get_lot(double lot){lots=lot;}                               // Receiving a lot  
   void get_periods(int red,int yel){ma_red_per=red;ma_yel_per=yel;} // Receiving the periods of MAs
   void get_stops(double SL,double TS){sl=SL;ts=TS;}                  // Receiving the values of stops
   void              init();                                         // Receiving the indicator values
   bool              check_for_buy();                                // Checking for buy
   bool              check_for_sell();                               // Checking for sell
   void              open_buy();                                     // Open buy
   void              open_sell();                                    // Open sell
   void              position_modify();                              // Position modification
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
/* Function definition */
//---Constructor---
void my_expert::ma_expert(void)
  {
//--- Reset the values of variables
   ZeroMemory(ma_red_han);
   ZeroMemory(ma_yel_han);
   ZeroMemory(macd_han);
  }
//---The function for receiving the indicator values---
void  my_expert::init(void)
  {
   ma_red_han=iMA(_Symbol,_Period,ma_red_per,0,MODE_EMA,PRICE_CLOSE); // Handle of the slow MA
   ma_yel_han=iMA(_Symbol,_Period,ma_yel_per,0,MODE_EMA,PRICE_CLOSE); // Handle of the fast MA
   macd_han=iMACD(_Symbol,_Period,12,26,9,PRICE_CLOSE);               // Handle of MACDaka
//---Copy data into arrays and set indexing like in a time-series---
   CopyBuffer(ma_red_han,0,0,4,MA_RED);
   CopyBuffer(ma_yel_han,0,0,4,MA_YEL);
   CopyBuffer(macd_han,0,0,2,MACD);
   ArraySetAsSeries(MA_RED,true);
   ArraySetAsSeries(MA_YEL,true);
   ArraySetAsSeries(MACD,true);
  }
//---Function to check conditions to open buy---   
bool my_expert::check_for_buy(void)
  {
   init();  //Receive values of indicator buffers
/* If the fast MA has crossed the slow MA from bottom up between 2nd and 3rd bars, 
   and there was no crossing back. MACD-hist is below zero */
   if(MA_RED[3]>MA_YEL[3] && MA_RED[1]<MA_YEL[1] && MA_RED[0]<MA_YEL[0] && MACD[1]<0)
     {
      return(true);
     }
   return(false);
  }
//----Function to check conditions to open sell---
bool my_expert::check_for_sell(void)
  {
   init();  //Receive values of indicator buffers
/* If the fast MA has crossed the slow MA from up downwards between 2nd and 3rd bars,
  y no hubo un cruce de vuelta. MACD-hist is above zero */
   if(MA_RED[3]<MA_YEL[3] && MA_RED[1]>MA_YEL[1] && MA_RED[0]>MA_YEL[0] && MACD[1]>0)
     {
      return(true);
     }
   return(false);
  }
//---Open buy---
/* Form a standard trade request to buy */
void my_expert::open_buy(void)
  {
   request.action=TRADE_ACTION_DEAL;
   request.symbol=_Symbol;
   request.volume=lots;
   request.price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   request.sl=request.price-sl*_Point;
   request.tp=0;
   request.deviation=10;
   request.type=ORDER_TYPE_BUY;
   request.type_filling=ORDER_FILLING_FOK;
   OrderSend(request,result);
   return;
  }
//---Open sell---
/* Form a standard trade request to sell */
void my_expert::open_sell(void)
  {
   request.action=TRADE_ACTION_DEAL;
   request.symbol=_Symbol;
   request.volume=lots;
   request.price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   request.sl=request.price+sl*_Point;
   request.tp=0;
   request.deviation=10;
   request.type=ORDER_TYPE_SELL;
   request.type_filling=ORDER_FILLING_FOK;
   OrderSend(request,result);
   return;
  }
//---Position modification---
void my_expert::position_modify(void)
  {
   if(PositionGetSymbol(0)==_Symbol)
     {     //If a position is for our symbol
      request.action=TRADE_ACTION_SLTP;
      request.symbol=_Symbol;
      request.deviation=10;
      //---If a buy position---
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
        {
/* if distance from price to stop loss is more than trailing stop
   and the new stop loss is not less than the previous one */
         if(SymbolInfoDouble(Symbol(),SYMBOL_BID)-PositionGetDouble(POSITION_SL)>_Point*ts)
           {
            if(PositionGetDouble(POSITION_SL)<SymbolInfoDouble(Symbol(),SYMBOL_BID)-_Point*ts)
              {
               request.sl=SymbolInfoDouble(Symbol(),SYMBOL_BID)-_Point*ts;
               request.tp=PositionGetDouble(POSITION_TP);
               OrderSend(request,result);
              }
           }
        }
      //---If it is a sell position---                
      else if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
        {
/*  if distance from price to stop loss is more than the trailing stop value
   and the new stop loss is not above the previous one. Or the stop loss from the moment of opening is equal to zero */
         if((PositionGetDouble(POSITION_SL)-SymbolInfoDouble(Symbol(),SYMBOL_ASK))>(_Point*ts))
           {
            if((PositionGetDouble(POSITION_SL)>(SymbolInfoDouble(Symbol(),SYMBOL_ASK)+_Point*ts)) || 
               (PositionGetDouble(POSITION_SL)==0))
              {
               request.sl=SymbolInfoDouble(Symbol(),SYMBOL_ASK)+_Point*ts;
               request.tp=PositionGetDouble(POSITION_TP);
               OrderSend(request,result);
              }
           }
        }
     }
  }
//+------------------------------------------------------------------

Mis humildes reconocimientos para el autor del artículo "Escribir un Asesor Experto usando el Enfoque Orientado al Objeto de MQL5". ¡Qué haría sin él! Recomiendo leer este artículo a cualquiera que no esté muy familiarizado con esta perversa pero extremadamente funcional programación orientada al objeto.

Añada el archivo con la clase al código principal del Asesor Experto, cree un objeto e inicialice las funciones:

//+------------------------------------------------------------------+
//|                                                       Moving.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//---Include a file with the class---
#include <moving.mqh>
//---External Variables---
input int MA_RED_PERIOD=7; // The period of a slow MA
input int MA_YEL_PERIOD=2; // The period of a fast MA
input int STOP_LOSS=800;   // Stop loss
input int TRAL_STOP=800;   // Trailing stop
input double LOTS=0.1;     // Lot
//---Create an object---
my_expert expert;
//---Initialize the MqlDataTime structure---
MqlDateTime time;
int day_of_week;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---Initialize the EA
   expert.get_periods(MA_RED_PERIOD,MA_YEL_PERIOD);   // Set the MA periods
   expert.get_lot(LOTS);                              // Set the lot
   expert.get_stops(STOP_LOSS,TRAL_STOP);             // Set stop orders  
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   TimeToStruct(TimeCurrent(),time);
   day_of_week=time.day_of_week;
   if(PositionsTotal()<1)
     {
      if(day_of_week==5 && expert.check_for_buy()==true){expert.open_buy();}
      else if(day_of_week==1 && expert.check_for_sell()==true){expert.open_sell();}
     }
   else expert.position_modify();
  }
//+------------------------------------------------------------------+

¡Conseguido! Me gustaría anotar algunos elementos especiales. Utilicé la estructura MqlDateTime para identificar los días de la semana en el nivel de software. Primero, transformamos la fecha actual del servidor a un formato estructurado. Obtuvimos así un índice del día actual (1-lunes, ..., 5-viernes) y lo comparamos con el valor que hemos configurado.

¡Probémoslo! Para no sobrecargarle con investigaciones pesadas y más dígitos, aquí le pongo todos los resultados sobre la mesa.

Aquí está: 

Tabla 1. Resumen de compras en cada día de la semana

Tabla 1. Resumen de compras en cada día de la semana

Tabla 2. Resumen de ventas en cada día de la semana

Tabla 2. Resumen de ventas en cada día de la semana

Los mejores resultados se señalan en verde, y los peores en naranja.

Después de las acciones descritas arriba, el sistema debe asegurar un beneficio en combinación con un nivel relativamente bajo de reducción, un buen porcentaje de operaciones rentables (aquí, cuantas menos operaciones, mejor) y un beneficio relativamente alto por operación.

Obviamente, el sistema más efectivo es comprar los viernes y vender los lunes. Combine ambas condiciones:

if(PositionsTotal()<1){
      if(day_of_week==5&&expert.check_for_buy()==true){expert.open_buy();}
      else if(day_of_week==1&&expert.check_for_sell()==true){expert.open_sell();}}
   else expert.position_modify();

Ahora, el Asesor Experto abre posiciones en ambas direcciones, pero en días definidos estrictamente. Por motivos de claridad, dibujaré los diagramas obtenidos sin y con el filtro:

Figura 2. Los resultados de la simulación del EA sin usar un filtro (EURUSD, H1, 01.01.2010-31.12.2010,)

Figura 2. Los resultados de la simulación del EA sin usar un filtro (EURUSD, H1, 01.01.2010-31.12.2010,)

Figura 3. Los resultados de la simulación del EA usando un filtro (EURUSD, H1, 01.01.2010-31.12.2010,)

Figura 3. Los resultados de la simulación del EA usando el filtro (EURUSD, H1, 01.01.2010-31.12.2010)

¿Qué le parecen los resultados? Usando el filtro, el sistema de trading ahora es más estable. Antes de las modificaciones, el Asesor Experto aumentaba principalmente el beneficio en la primera mitad del período de simulación, mientras que tras la "mejora", aumenta durante todo el período.

Comparemos los informes:

Tabla 3. Resultados de la simulación antes y después de usar el filtro

Tabla 3. Resultados de la simulación antes y después de usar el filtro

El único factor preocupante que no se puede ignorar es la caída del beneficio neto en casi 1.000 USD (26%). Pero estamos reduciendo el número de operaciones casi 3,5 veces, es decir, estamos reduciendo significativamente, primero, el potencial para llevar a cabo operaciones negativas, y segundo, los gastos del diferencial (218*2-62*2=312 USD y es solo para EUR/USD). El porcentaje de ganancias aumentó a un 57%, lo que ya resulta significativo. A su vez, el beneficio por operación de trading ha aumentado en un 14% a 113 USD. Como diría L. Williams: "¡Esta es la cantidad que merece la pena invertir!"


Conclusión

Los precios no se comportan de manera aleatoria, y es un hecho comprobado. Este hecho se puede usar para nuestro beneficio. Aquí solo he dado un ejemplo que es una mínima fracción de las innumerables variaciones y técnicas que pueden mejorar el rendimiento de su sistema de trading. Sin embargo, esta diversidad oculta un vicio. No todos los filtros se pueden integrar, de modo que debe elegir con cuidado, siempre teniendo en cuenta todas las posibles situaciones.

No se olvide de que, independientemente de lo perfecto que sea el filtro, también dejará fuera operaciones rentables, es decir, su posible beneficio. ¡Buena suerte!


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

Archivos adjuntos |
explorer.mq5 (2.84 KB)
moving.mq5 (2.28 KB)
moving.mqh (6.98 KB)
El Papel de las Distribuciones Estadísticas en el Trabajo del Trader El Papel de las Distribuciones Estadísticas en el Trabajo del Trader

Este artículo es una continuación lógica de mi artículo "Statistical Probability Distributions in MQL5" ("Distribuciones de Probabilidad Estadísticas en MQL5"), que presentó las clases para trabajar con algunas distribuciones estadísticas teóricas. Ahora que ya tenemos una base teórica, sugiero proceder directamente a conjuntos de datos reales para darle un uso a esta base.

Usar Pseudo-Plantillas como Alternativa a Plantillas C++ Usar Pseudo-Plantillas como Alternativa a Plantillas C++

Este artículo describe una forma de programas sin usar plantillas, pero manteniendo el estilo de programación inherente a ellas. Trata sobre la implementación de plantillas usando métodos personalizados y tiene un archivo adjunto con un script ya hecho para crear un código basado en las plantillas especificadas.

3 Métodos de Aceleración de Indicadores según el Ejemplo de Regresión Lineal 3 Métodos de Aceleración de Indicadores según el Ejemplo de Regresión Lineal

Este artículo trata sobre los métodos de optimización computacional de algoritmos de indicadores. Todos podrán encontrar un método que se adapte a sus necesidades. Aquí se describirán tres métodos. Uno de ellos es muy sencillo, el siguiente requiere conocimientos sólidos de matemáticas, y el último requiere ingenio. Para poner en práctica la mayoría de los métodos descritos, se usarán indicadores o elementos del diseño de terminal de MetaTrader5. Los métodos son bastante universales y se pueden usar no solo para la aceleración del cálculo de regresión lineal, sino también para muchos otros indicadores.

Cómo ser suministrador de señales para MetaTrader 4 y MetaTrader 5 Cómo ser suministrador de señales para MetaTrader 4 y MetaTrader 5

¿Quiere ofrecer sus señales y obtener beneficios por ello? Regístrese en la página MQL5.com con el estatus de vendedor, indique su cuenta comercial y podrá proponer a los traders suscribirse a sus señales.