Asesores expertos basados en sistemas de trading populares y alquimia de la optimización de robots de trading (Parte IV)

Nikolay Kositsin | 12 abril, 2016

Introducción

En mis artículos anteriores números 2 y 3 describí los fundamentos del backtesting. En mi opinión, la finalidad principal del backtesting es el análisis cualitativo del comportamiento de un asesor experto dentro de un cierto periodo de tiempo siempre que los parámetros del asesor experto se modifiquen de vez en cuando. La estrategia de utilizar los resultados de la optimización en este proceso será una regla estricta de selección de la forma de los parámetros de todas las variantes recibidas como resultado de cada optimización. Por ejemplo, una variante con máxima rentabilidad y mínima reducción.

Dicha variante se selecciona entre todas las variantes de una optimización por separado, con independencia de lo que teníamos en optimizaciones anteriores. Si detectamos que dicha estrategia es rentable en algunos periodos y en otros periodos está cercada al nivel break-even, podemos concluir que nuestro sistema de trading con dicha estrategia de uso de parámetros optimizados es probable que sea rentable en el futuro en un cierto periodo de tiempo.

Este es el caso perfecto. Pero ¿qué debemos hacer si un asesor experto con una lógica operativa aparentemente muy racional parece generar pérdidas irremediablemente en la mitad de todos los casos de backtesting? En realidad, las estrategias basadas en la selección de los parámetros del asesor experto dentro de cada optimización por separado no es el único método posible. Es más interesante realizar análisis estadísticos y comparar los parámetros del asesor experto de distintas optimizaciones.

Además, las optimizaciones en el backtesting requieren mucho tiempo y no es razonable realizar estas optimizaciones solo para el backtesting. Por ejemplo, junto con las optimizaciones podemos guardar los resultados de todas las optimizaciones rentables en un archivo en forma de tabla que puede ser fácilmente procesado mediante el análisis estadístico de tablas disponibles en programas como Microsoft Excel. El terminal de MetaTrader 4 ofrece la posibilidad de guardar los resultados de la optimización en forma de tabla HTML:

que puede ser fácilmente cargada en Microsoft Excel. Pero para el procesamiento solo se presentan en forma de tabla los informes finales de cada optimización. Los parámetros externos de un asesor experto no se incluyen en la tabla:>

Además, es el resultado de una optimización. Y para el análisis necesitamos los resultados de todas las optimizaciones registradas en un archivo. En realidad, todo esto puede implementarse en MQL4, por lo que en este artículo me gustaría ofrecer mi propia variante de la solución.



Registro de los resultados de la optimización del asesor experto en forma de tabla HTML en un archivo

Para implementar dicho registro en un archivo, he escrito la siguiente función:

void Write_Param_htm
(
bool ToResolveWrite_Up, int Timeframe_Up, string ExtrVarblsNemes_Up, string ExtrVarblsVelues_Up, 
bool ToResolveWrite_Dn, int Timeframe_Dn, string ExtrVarblsNemes_Dn, string ExtrVarblsVelues_Dn
)

Esta función permite registrar los resultados de ejecuciones rentables de todas las optimizaciones realizadas para un par en un periodo de tiempo y en una dirección de transacción. Esta llamada a la función se coloca en el bloque de deinicialización del asesor experto (dentro de la función deinit()):

int deinit()
{
//----+
//---- Recording EA parameters into a text file
if (IsOptimization())
{ 
//---- +------------------------------------------+
//Here is the code of external variables initialization of the Write_Param_htm() function
//---- +------------------------------------------+
//---- RECORDING STRINGS INTO A HTML FILE
Write_Param_htm(Test_Up, Timeframe_Up, ExtVarNemes_Up, ExtVarVelues_Up, Test_Dn, Timeframe_Dn, 
ExtVarNemes_Dn, ExtVarVelues_Dn);
//----+ +-------------------------------------------------------+
}
//---- End of the EA deinitialzation
return(0);
//----+ 
}

Esta función escribe tres archivos en el directorio C:\: dos archivos de los resultados de la optimización (para las posiciones largas y cortas respectivamente) y un archivo de registro (MetaTraderTester.log), en el que se escriben las rutas y nombres de estos dos archivos. Los nombres de los dos archivos son los siguientes (OptReport_Exp_5_2_GBPUSD_240_Long.htm):

La función Write_Param_htm() se incluye en el archivo por la directiva:

#include <TestReport.mqh>

que debe realizarse mejor antes de la declaración de las variables externas del asesor experto. Además de esta función, el archivo TestReport.mqh contiene otras funciones que se usan en el código de la función Write_Param_htm(); explicaré su significado más tarde. El archivo también contiene la ya conocida función IsBackTestingTime() con las variables externas para el backtesting (la función se describió en el artículo anterior). La llamada de la función debe realizarse en el bloque de la función start():

//----+ Execution of backtesting conditions
if (!IsBackTestingTime())
return(0);

Por tanto, el uso más simple del archivo TestReport.mqh es completamente análogo al uso de IsBackTestingTime.mqh del artículo anterior, pero en este caso durante la compilación del asesor experto no se usará ninguna de las demás funciones del asesor experto. Como parámetros externos en las funciones Write_Param_htm() se usan ocho variables. Estas variables pueden dividirse en dos grupos: para el registro en un archivo de los resultados de la optimización del asesor experto con posiciones largas que terminan en _Up y para el registro en un archivo con posiciones cortas que terminan en _Dn.

Vamos a analizar un grupo, el segundo es análogo. El parámetro ToResolveWrite_Up pasa a la función la autorización o prohibición de grabar en el archivo. El parámetro Timeframe_Up pasa el periodo de tiempo en el que funciona el algoritmo largo del asesor experto. El parámetro ExtrVarblsNemes_Up pasa a la función una cadena de caracteres compuesta por los nombres de los parámetros externos del asesor experto para las posiciones largas. De la misma forma, el parámetro ExtrVarblsVelues_Up se usa para pasar una cadena de caracteres compuesta por los valores de los parámetros externos del asesor experto para las posiciones largas.

Vamos a discutir la inicialización de las últimas dos variables. Supongamos que tenemos las siguientes variables externas para posiciones largas:

n_ExternParam_1, n_ExternParam_2, d_ExternParam_3, n_ExternParam_4, b_ExternParam_5, d_ExternParam_6, 
d_ExternParam_7, n_ExternParam_8

El prefijo "n_" indica que el parámetro es de tipo entero, "d_" significa que el parámetro es del tipo doble, "b_" - del tipo booleano. Antes de la inicialización de ExtrVarblsNemes_Up y ExtrVarblsVelues_Up, debe declararse e inicializarse un par de variables string adicionales mediante partes del código html:

string n_Width = "</td><td><center>";
string d_Width = "</td><td class=mspt><center>";

Después de esto, podemos ensamblar las cadenas de caracteres necesarias. Para la variable externa ExtrVarblsNemes_Up este código es de la forma siguiente:

ExtVarNemes_Up =
StringConcatenate
(
n_Width, "n_ExternParam_1", 
n_Width, "n_ExternParam_2", 
n_Width, "d_ExternParam_3", 
n_Width, "n_ExternParam_4", 
n_Width, "b_ExternParam_5", 
n_Width, "d_ExternParam_6", 
n_Width, "d_ExternParam_7", 
n_Width, "n_ExternParam_8"
);

La inicialización de la variable externa ExtVarVelues_Up es un poco más compleja:

ExtVarVelues_Up = 
StringConcatenate
(
n_Width, n_ExternParam_1, 
n_Width, n_ExternParam_2, 
d_Width, d_ExternParam_3, 
n_Width, n_ExternParam_4, 
n_Width, b_ExternParam_5, 
d_Width, d_ExternParam_6, 
d_Width, d_ExternParam_7, 
n_Width, n_ExternParam_8
);

En este código, antes de los parámetros externos del asesor experto, siempre se coloca la variable d_Width y se escribe n_Width antes de todos los demás parámetros. En dicha configuración de la última cadena de caracteres, todos los parámetros de tipo doble se pasarán a la función Write_Param_htm() con cuatro signos después del punto decimal. Si se necesita otra cantidad de signos, usamos la siguiente función:

DoubleToStr( double value, int digits)

Recuerde que estas cadenas de caracteres no pueden contener más de 255 símbolos. Si la longitud es mayor que esta, se omiten los símbolos en exceso y el compilador muestra la alerta correspondiente. Solo hay una forma de solventar esta situación: los nombres en ExtVarNemes_Up para las variables externas deben acortarse, y en ExtVarVelues_Up el número de variables para ensamblar las cadenas de caracteres debe recortarse. Pero para la mayoría de tareas, 255 símbolos es más que suficiente.

Esta es la variante del registro de la implementación en un archivo HTML en el ejemplo de Exp_5_2.mq4:

//+==================================================================+
//| expert deinitialization function |
//+==================================================================+ 
int deinit()
{
//----+
//---- Recording EA parameters into a text file
if (IsOptimization())
{
string ExtVarNemes_Up, ExtVarVelues_Up;
string ExtVarNemes_Dn, ExtVarVelues_Dn, n_Width, d_Width;

//---- INITIALIZATION OF STRINGS FOR THE Write_Param_htm FUNCTION
//----+ +-------------------------------------------------------+ 
n_Width = "</td><td><center>";
d_Width = "</td><td class=mspt><center>";
//---- 
ExtVarNemes_Up =
StringConcatenate( 
n_Width, "IndLevel_Up",
n_Width, "FastEMA_Up",
n_Width, "SlowEMA_Up",
n_Width, "SignalSMA_Up",
n_Width, "STOPLOSS_Up",
n_Width, "TAKEPROFIT_Up",
n_Width, "TRAILINGSTOP_Up",
n_Width, "PriceLevel_Up",
n_Width, "ClosePos_Up");

ExtVarVelues_Up = 
StringConcatenate(
d_Width, DoubleToStr(IndLevel_Up, Digits), // 9
n_Width, FastEMA_Up, // 10
n_Width, SlowEMA_Up, // 11
n_Width, SignalSMA_Up, // 12
n_Width, STOPLOSS_Up, // 13
n_Width, TAKEPROFIT_Up, // 14
n_Width, TRAILINGSTOP_Up, // 15
n_Width, PriceLevel_Up, // 16
n_Width, ClosePos_Up); // 17 
//----+ +-------------------------------------------------------+
ExtVarNemes_Dn =
StringConcatenate( 
n_Width, "IndLevel_Dn",
n_Width, "FastEMA_Dn",
n_Width, "SlowEMA_Dn",
n_Width, "SignalSMA_Dn",
n_Width, "STOPLOSS_Dn",
n_Width, "TAKEPROFIT_Dn",
n_Width, "TRAILINGSTOP_Dn",
n_Width, "PriceLevel_Dn",
n_Width, "ClosePos_Dn"); 

ExtVarVelues_Dn = 
StringConcatenate(
d_Width, DoubleToStr(IndLevel_Dn, Digits), // 9
n_Width, FastEMA_Dn, // 10
n_Width, SlowEMA_Dn, // 11
n_Width, SignalSMA_Dn, // 12
n_Width, STOPLOSS_Dn, // 13
n_Width, TAKEPROFIT_Dn, // 14
n_Width, TRAILINGSTOP_Dn, // 15
n_Width, PriceLevel_Dn, // 16
n_Width, ClosePos_Dn); // 17 

//---- RECORDING STRINGS INTO HTML FILE
Write_Param_htm
(Test_Up, Timeframe_Up, ExtVarNemes_Up, ExtVarVelues_Up, 
Test_Dn, Timeframe_Dn, ExtVarNemes_Dn, ExtVarVelues_Dn);
//----+ +-------------------------------------------------------+
}
//---- End of the EA deinitialization
return(0);
//----+ 
}

Esta es la tabla de parámetros HTML resultante para este asesor experto abierto en Microsoft Excel:


La tabla contiene los resultados de todas las optimizaciones realizadas. La propia tabla tiene la forma siguiente (las primeras ocho columnas contienen los resultados de las transacciones del asesor experto):

Recuerde que los parámetros Drawdown $ y Drawdown % se calculan solo para las transacciones cerradas, y por esta razón se diferencian de aquellos disponibles en un probador de estrategias. También debemos tener en cuenta que el parámetro 'Profit factor' solo tiene sentido si hubo al menos una transacción perdedora, no tiene sentido si no había ninguna transacción perdedora. Inicialmente, la tabla no contienen transacciones perdedoras, y por esta razón para las situaciones sin ninguna pérdida haré que este parámetro sea igual a cero.

A la derecha de los resultados de la transacción del asesor experto hay parámetros de este optimizados:

De este modo, tenemos en forma de tabla todos los valores necesarios para cada optimización y todas las optimizaciones al mismo tiempo. Esto permite dejar algo de tiempo al probador y el terminal para realizar análisis estadísticos sobre la base de la información contenida en un archivo html usando medios muy eficientes disponibles en analizadores de programa actualizados de los contenidos de la tabla.

Una cosa más. El archivo html descrito y grabado de esta forma tendrá un código html incompleto debido a la adición constante de datos al archivo. Si no vamos a añadir datos al archivo más tade, deben escribirse las siguientes líneas al final del código html (lo abrimos en cualquier editor de texto):

</table>
</body></html>


Algunas explicaciones sobre el contenido de TestReport.mqh

Esta archivo que he usado para escribir código MQL4 que proporciona la exportación de los datos a tablas HTML contiene muchas funciones universales definidas por el usuario. Estas funciones en una forma disponible para su uso pueden ser útiles para cualquier escritor de asesores expertos, por lo que me gustaría analizar estas funciones en detalle:

El archivo comienza con la declaración de variables externas para el backtesting y IsBackTestingTime() descrita en el artículo anterior. Después de esto va la declaración de una función CountTime() especializada que se usa en algunas funciones del archivo, pero no es probable que sea usada por un lector.

La directiva

#include <Read_Write_File.mqh>

incluye en el archivo TestReport.mqh el contenido del archivo Read_Write_File.mqh: importación de funciones para registrar y leer archivos en cualquier directorio de módulos del sistema operativo Windows:

#include <WinUser32.mqh>
#import "kernel32.dll"
int _lopen (string path, int of);
int _lcreat (string path, int attrib);
int _llseek (int handle, int offset, int origin);
int _lread (int handle, int& buffer[], int bytes);
int _lwrite (int handle, string buffer, int bytes);
int _lclose (int handle);
#import

El significado del uso de esta función puede comprenderse a partir del código de cuatro funciones universales definidas por el usuario y contenidas en este archivo:

int _FileSize
(
string path
)

bool WriteFile 
(
string path, string buffer
) 

bool ReadFile
(
string path, string&amp;amp; StrBuffer[]
)

SpellFile
(
string path, string&amp; SpellBuffer[]
)

Estas funciones contienen la ruta de la variable que introduce una cadena de texto que contiene la ruta hacia el archivo de texto y su nombre.

La función _FileSize() devuelve el tamaño del archivo en bytes.

La función WriteFile() registra al final del archivo los contenidos de la cadena de caracteres 'buffer'. Si necesitamos escribir cada cadena de caracteres desde una nueva línea, añadimos "\n" al final de cada línea:


La función ReadFile() cambia el tamaño del búfer de la cadena de caracteres StrBuffer[] y lo carga en los contenidos del archivo mediante cadenas de caracteres compuestas por cuatro letras en una celda del búfer.

La función SpellFile() cambia el tamaño del búfer de la cadena de caracteres y carga el contenido del archivo letra a letra.

Después de la directiva #include <Read_Write_File.mqh> en el archivo TestReport.mqh hay un grupo de funciones universales definidas por el usuario que se usan para calcular los llamados parámetros de optimización,

CountProfit(int cmd) 
CountMaxDrawdownPrs(int cmd) 
CountMaxDrawdown(int cmd) 
CountAbsDrawdown(int cmd) 
CountProfitFactor(int cmd) 
CountProfitTrades(int cmd) 
CountTotalTrades(int cmd) 
CountExpectedPayoff(int cmd)

que son análgogas a las que aparecen en la pestaña "Resultados de la optimización" en un probador de estrategias. Estas funciones realizan cálculos basados solo en los datos de transacciones cerradas, por esta razón las funciones CountMaxDrawdownPrs(), CountMaxDrawdown(), CountAbsDrawdown() devuelven sus valores de forma distinta a como se obtiene en un probador de estategias. Si la variable 'cmd' acepta el valor OP_BUY, los cálculos en todas las funciones se realizan solo para las posiciones largas cerradas, si es OP_SELL - para las posiciones cortas cerradas. Cualquier otro valor de esta variable proporciona los cálculos para todas las transacciones cerradas.

Después de estas funciones, se declaran cuatro funciones más en el archivo: para registrar los resultados de la optimización y los parámetros optimizados en los archivos:

void Write_Param_htm
(
bool ToResolveWrite_Up, int Timeframe_Up, string ExtrVarblsNemes_Up, string ExtrVarblsVelues_Up, 
bool ToResolveWrite_Dn, int Timeframe_Dn, string ExtrVarblsNemes_Dn, string ExtrVarblsVelues_Dn
)

void Write_Param_1htm
(
int Timeframe, string ExtrVarblsNemes, string ExtrVarblsVelues
)

void Write_Param_txt
(
bool ToResolveWrite_Up, int Timeframe_Up, string ExtrVarblsVelues_Up,
bool ToResolveWrite_Dn, int Timeframe_Dn, string ExtrVarblsVelues_Dn
)

void Write_Param_1txt
(
int Timeframe, string ExtrVarblsVelues
)

Respecto a Write_Param_htm(), esta se describe anteriormente.

La función Write_Param_1htm() es completamente análoga a la función anterior, pero se crea para los asesores expertos en los que los parámetros externos no se dividen en aquellos para las posiciones largas y cortas. La función ToResolveWrite no es necesaria aquí y por eso la he borrado.

La función Write_Param_txt() es análoga a Write_Param_htm(), y registra los mismos datos pero sin la indicación html. La variable adicional para ensamblar un string consistente en los resultados de la optimización y los parámetros optimizados se inicializa de la forma siguiente:

Width = " ";

Cada nuevo string se registra en el archivo en una nueva línea y al final de cada string en el archivo de texto se escribe ";". Entre los valores de las variables externas de un string, los espacios se escriben en el archivo de texto.

La función Write_Param_1txt() es completamente análoga a la función Write_Param_txt(), pero se crea para los asesores expertos en los que los parámetros externos no se dividen en aquellos para las posiciones largas y cortas.

Y las últimas dos funciones

void Write_Param_htm_B
(
bool ToResolveWrite_Up, int Timeframe_Up, string ExtrVarblsNemes_Up, string ExtrVarblsVelues_Up, 
bool ToResolveWrite_Dn, int Timeframe_Dn, string ExtrVarblsNemes_Dn, string ExtrVarblsVelues_Dn
)

void Write_Param_1htm_B
(
int Timeframe, string ExtrVarblsNemes, string ExtrVarblsVelues
)

son completamente análogas a Write_Param_htm() y Write_Param_1htm(), pero los archivos html recibidos con su ayuda tienen colores inversos. Este es un ejemplo:

Probablemente hay personas que prefieren trabajar con dichos archivos. Personalmente me gusta este tipo de presentación de la información.



Sistema de trading parabólico

El indicador de trabajo de este sistema se incluye en todas las plataformas de trading populares para trabajar en Forex y en los mercados bursátiles.

Aquí voy a presentar un sistema con órdenes pendientes del tipo BuyLimit y SellLimit.

Esta es la variante de la implementación del algoritmo para BuyLimit:


La variante del algoritmo para las órdenes SellLimit será análoga:

Esta es la implementación del código del programa para un asesor experto:

//+==================================================================+
//|                                                        Exp_8.mq4 |
//|                             Copyright © 2008,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+==================================================================+
#property copyright "Copyright © 2008, Nikolay Kositsin"
#property link "farria@mail.redcom.ru"
//----+ +------------------------------------------------------------+
//---- EA INPUT PARAMETERS FOR BUY TRADES 
extern bool   Test_Up = true;//filter of trade calculations direction
extern int    Timeframe_Up = 240;
extern double Money_Management_Up = 0.1;
extern double Step_Up = 0.02; 
extern double Maximum_Up = 0.2;
extern int    STOPLOSS_Up = 50;  // stop loss
extern int    TAKEPROFIT_Up = 100; // take profit
extern int    TRAILINGSTOP_Up = 0; // trailing stop
extern int    PriceLevel_Up =40; // difference between the current price and
                          // pending order triggering price
extern bool   ClosePos_Up = true; // forced position closing 
                                              //is allowed
//----+ +------------------------------------------------------------+
//---- EA INPUT PARAMETERS FOR SELL TRADES 
extern bool   Test_Dn = true;//filter of trade calculations direction
extern int    Timeframe_Dn = 240;
extern double Money_Management_Dn = 0.1;
extern double Step_Dn = 0.02; 
extern double Maximum_Dn = 0.2;
extern int    STOPLOSS_Dn = 50;  // stop loss
extern int    TAKEPROFIT_Dn = 100; // take profit
extern int    TRAILINGSTOP_Dn = 0; // trailing stop
extern int    PriceLevel_Dn = 40; // difference between the current price and 
                          // pending order triggering price
extern bool   ClosePos_Dn = true; // forced position closing
                                              //is allowed
//----+ +------------------------------------------------------------+
//---- Integer variables for the minimum of calculation bars
int MinBar_Up, MinBar_Dn;
//+==================================================================+
//| TimeframeCheck() functions                                       |
//+==================================================================+
void TimeframeCheck(string Name, int Timeframe)
  {
//----+
   //---- Checking the correctness of Timeframe variable value
   if (Timeframe != 1)
    if (Timeframe != 5)
     if (Timeframe != 15)
      if (Timeframe != 30)
       if (Timeframe != 60)
        if (Timeframe != 240)
         if (Timeframe != 1440)
           Print(StringConcatenate("Parameter ",Name,
                     " cannot ", "be equal to ", Timeframe, "!!!"));    
//----+ 
  }
//+==================================================================+
//| Custom Expert functions                                          |
//+==================================================================+
#include <Lite_EXPERT1.mqh>
//+==================================================================+
//| Custom Expert initialization function                            |
//+==================================================================+
int init()
  {
//---- Checking the correctness of Timeframe_Up variable value
   TimeframeCheck("Timeframe_Up", Timeframe_Up);                                                          
//---- Checking the correctness of Timeframe_Dn variable value 
   TimeframeCheck("Timeframe_Dn", Timeframe_Dn);  
//---- Initialization of variables             
   MinBar_Up  = 5;
   MinBar_Dn  = 5;                               
//---- end of initialization
   return(0);
  }
//+==================================================================+
//| expert deinitialization function                                 |
//+==================================================================+  
int deinit()
  {
//----+
   
    //---- End of the EA deinitialization
    return(0);
//----+ 
  }
//+==================================================================+
//| Custom Expert iteration function                                 |
//+==================================================================+
int start()
  {
   //----+ Declaring local variables
   double SAR1, SAR2, CLOSE1, CLOSE2;
   //----+ Declaring static variables
   //----+ +---------------------------------------------------------------+
   static datetime StopTime_Up, StopTime_Dn; 
   static int LastBars_Up, LastBars_Dn;
   static bool BUY_Sign, BUY_Stop, SELL_Sign, SELL_Stop;
   //----+ +---------------------------------------------------------------+
   //----++ CODE FOR LONG POSITIONS 1
   if (Test_Up) 
    {
      int IBARS_Up = iBars(NULL, Timeframe_Up);
      
      if (IBARS_Up >= MinBar_Up)
       {
         if (LastBars_Up != IBARS_Up)
          {
           //----+ Initialization of variables 
           BUY_Sign = false;
           BUY_Stop = false;
           LastBars_Up = IBARS_Up;
           StopTime_Up = iTime(NULL, Timeframe_Up, 0)
                                           + 60 * Timeframe_Up;
           
           //----+ CALCULATING INDICATOR VALUES AND UPLOADING THEM TO BUFFERS                                        
           SAR1 = iSAR(NULL, Timeframe_Up, Step_Up, Maximum_Up, 1);         
           SAR2 = iSAR(NULL, Timeframe_Up, Step_Up, Maximum_Up, 2);
           //---
           CLOSE1 = iClose(NULL, Timeframe_Up, 1);
           CLOSE2 = iClose(NULL, Timeframe_Up, 2);
           
           //----+ DEFINING SIGNALS FOR TRADES                                           
           if (SAR2 > CLOSE2)
             if (SAR1 < CLOSE1)
                          BUY_Sign = true;
                          
           if (SAR1 > CLOSE1)
                          BUY_Stop = true;                                           
          }
          //----+ EXECUTION OF TRADES
          if (PriceLevel_Up == 0)
           {           
            if (!OpenBuyOrder1(BUY_Sign, 1, 
                Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up))
                                                                return(-1);
           }
          else
           {           
            if (!OpenBuyLimitOrder1(BUY_Sign, 1, 
                Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up,
                                            PriceLevel_Up, StopTime_Up))
                                                                return(-1);
           }
           
          if (ClosePos_Up)
                if (!CloseOrder1(BUY_Stop, 1))
                                        return(-1);
                                        
          if (!Make_TreilingStop(1, TRAILINGSTOP_Up))
                                                  return(-1);
        }
     }
   //----+ +---------------------------------------------------------------+
   //----++ CODE FOR SHORT POSITIONS 1
   if (Test_Dn) 
    {
      int IBARS_Dn = iBars(NULL, Timeframe_Dn);
      
      if (IBARS_Dn >= MinBar_Dn)
       {
         if (LastBars_Dn != IBARS_Dn)
          {
           //----+ Initialization of variables 
           SELL_Sign = false;
           SELL_Stop = false;
           LastBars_Dn = IBARS_Dn;
           StopTime_Dn = iTime(NULL, Timeframe_Dn, 0)
                                           + 60 * Timeframe_Dn;
           
           //----+ CALCULATING INDICATOR VALUES AND UPLOADING THEM TO BUFFERS                                        
           SAR1 = iSAR(NULL, Timeframe_Dn, Step_Dn, Maximum_Dn, 1);         
           SAR2 = iSAR(NULL, Timeframe_Dn, Step_Dn, Maximum_Dn, 2);
           //---
           CLOSE1 = iClose(NULL, Timeframe_Dn, 1);
           CLOSE2 = iClose(NULL, Timeframe_Dn, 2);
           
           //----+ DEFINING SIGNALS FOR TRADES                                           
           if (SAR2 < CLOSE2)
             if (SAR1 > CLOSE1)
                          SELL_Sign = true;
                          
           if (SAR1 < CLOSE1)
                          SELL_Stop = true;                                           
          }
          //----+ EXECUTION OF TRADES
          if (PriceLevel_Dn == 0)
           {           
            if (!OpenSellOrder1(SELL_Sign, 2, 
                Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn))
                                                                return(-1);
           }
          else
           {           
            if (!OpenSellLimitOrder1(SELL_Sign, 2, 
                Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn,
                                            PriceLevel_Dn, StopTime_Dn))
                                                                return(-1);
           }
           
          if (ClosePos_Dn)
                if (!CloseOrder1(SELL_Stop, 2))
                                        return(-1);
                                        
          if (!Make_TreilingStop(2, TRAILINGSTOP_Dn))
                                                  return(-1);
        }
     }
   //----+ +---------------------------------------------------------------+
//----+ 
    
    return(0);
  }
//+------------------------------------------------------------------+

El bloque de ejecución de la transacción es más complejo en este asesor experto. Aquí las funciones para entrar al mercado OpenBuyOrder1(), OpenSellOrder1() y las funciones para colocar las órdenes pendientes OpenBuyLimitOrder1() y OpenSellLimitOrder1() se usan conjuntamente. Esto se hace para el caso en que las variables externas PriceLevel_Up y PriceLevel_Dn son iguales a cero. En tal situación, el asesor experto abre las transacciones desde el mercado, mientras que un asesor experto que trabaja solo con órdenes pendientes colocará estas órdenes a la mínima distancia del mercado.



Sistema de trading de erupción

Respecto a los sistemas de trading basados en niveles de erupción, hay muchos de ellos y siempre es posible inventar un sistema de erupción adicional. En este artículo describiré un sistema en el que los niveles de erupción se definen por los lados de un canal sobre la base de un desplazamiento:

La erupción se definirá en las barras cerradas. Además, usaré un sistema de trading de erupción con algún rebote tras la erupción. Esta es la variante de estos sistemas de trading con órdenes BuyLimit:

La misma para SellLimit:

El código del asesor experto no tiene ninguna peculiaridad en su construcción, por esta razón no lo incluyo en el artículo. Puede encontrar el código adjunto al asesor experto (Exp_9.mq4). No hay cierre de posición forzada en el asesor experto. Las nuevas variables globales se inicializan en el bloque de inicialización del asesor experto.

dMovLevel_Up = MovLevel_Up * Point;
dMovLevel_Dn = MovLevel_Dn * Point;

estas variables se usan para calcular los valores de los niveles de UpMovLeve1 y DownMovLevel1.



Trading en comunicados de prensa

Con mucha frecuencia se produce una situación en el mercado en la que aparecen violentos movimientos de forma invariable al mismo tiempo. Es difícil decir de antemano con seguridad en qué dirección tendrá lugar el movimiento. Pero puede afirmarse de antemano que dicho movimiento se producirá. Por ejemplo, dichos movimientos violentos pueden dar lugar a nóminas no agrícolas. A muchos traders les gusta capturar dichos movimientos violentos. Sería interesante comprobar si dicho sistema de trading es razonable. La idea del sistema consiste en colocar dos órdenes pendientes del tipo BuyStop y SellStop y esperar hasta que un movimiento violento abra una transacción y sea cerrada por Take Profit:

Esta es una variante más de un sistema de erupción. La implementación de dicho sistema en el código de un programa no es muy difícil:

//+==================================================================+
//|                                                       Exp_10.mq4 |
//|                             Copyright © 2008,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+==================================================================+
#property copyright "Copyright © 2008, Nikolay Kositsin"
#property link "farria@mail.redcom.ru"
//----+ +------------------------------------------------------------+
//---- EA INPUT PARAMETERS FOR PLACING PENDING ORDERS
extern int    NewsWeekDay = 5;  // Weekday for news release
// if parameter is less than 1 or more than 5 any working day is used
extern int    NewsHour = 15;  // hour of news release
extern int    NewsMinute = 0;  // minute of news release
extern int    OrderLife = 30;  // Number of minutes of pending order validity
//----+ +------------------------------------------------------------+
//---- ea INPUT PARAMETERS FOR CLOSING POSITIONS
extern int    PosLife = 120;  // Number of minutes of an opened position validity
                                              //from news release time
//----+ +------------------------------------------------------------+
//---- EA INPUT PARAMETERS FOR BUY TRADES 
extern bool   Test_Up = true;//filter of trade calculations direction
extern double Money_Management_Up = 0.1;
extern int    STOPLOSS_Up = 50;  // stop loss
extern int    TAKEPROFIT_Up = 100; // take profit
extern int    TRAILINGSTOP_Up = 0; // trailing stop
extern int    PriceLevel_Up =40; // difference between the current price and
                          // the price of pending order triggering
extern bool   ClosePos_Up = true; // forced position closing
                                              //is allowed
//----+ +------------------------------------------------------------+
//---- EA INPUT PARAMETERS FOR SELL TRADES 
extern bool   Test_Dn = true;//filter of trade calculations direction
extern double Money_Management_Dn = 0.1;
extern int    STOPLOSS_Dn = 50;  // stop loss
extern int    TAKEPROFIT_Dn = 100; // take profit
extern int    TRAILINGSTOP_Dn = 0; // trailing stop
extern int    PriceLevel_Dn = 40; // difference between the current price and 
                          // the price of pending order triggering
extern bool   ClosePos_Dn = true; // forced position closing
                                              //is allowed
//+==================================================================+
//| Custom Expert functions                                          |
//+==================================================================+
#include <Lite_EXPERT1.mqh>
//+==================================================================+
//| Custom Expert initialization function                            |
//+==================================================================+
int init()
  {
//---- 
    if (NewsHour > 23) 
             NewsHour = 23;
    if (NewsMinute > 59)
           NewsMinute = 59;                               
//---- end of initialization
   return(0);
  }
//+==================================================================+
//| expert deinitialization function                                 |
//+==================================================================+  
int deinit()
  {
//----+
   
    //---- End of the EA deinitialization
    return(0);
//----+ 
  }
//+==================================================================+
//| Custom Expert iteration function                                 |
//+==================================================================+
int start()
  {
   //----+ Declaring static variables
   //----+ +---------------------------------------------------------------+
   static datetime StopTime, PosStopTime; 
   static bool BUY_Sign, SELL_Sign, BUY_Stop, SELL_Stop;
   //----+ +---------------------------------------------------------------+
   
   //----+ DEFINING SIGNALS FOR TRADES 
   if (DayOfWeek() == NewsWeekDay || NewsWeekDay < 1 || NewsWeekDay > 5)
     if (Hour() == NewsHour)
        if (Minute() == NewsMinute)
    {
     StopTime = TimeCurrent() + OrderLife * 60;
     PosStopTime = TimeCurrent() + PosLife * 60;
     BUY_Sign = true;
     SELL_Sign = true;
    }
    
    
    
   //----+ +---------------------------------------------------------------+ 
   //----++ CODE FOR LONG POSITIONS 1
   if (Test_Up) 
    {
      //----+ EXECUTION OF TRADES          
      if (!OpenBuyStopOrder1(BUY_Sign, 1, 
                Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up,
                                            PriceLevel_Up, StopTime))
                                                                return(-1);
      if (TimeCurrent() >= PosStopTime)                                                                    
          if (ClosePos_Up)
                if (!CloseOrder1(BUY_Stop, 1))
                                           return(-1);
                                        
      if (!Make_TreilingStop(1, TRAILINGSTOP_Up))
                                           return(-1);
     }
   //----+ +---------------------------------------------------------------+
   //----++ CODE FOR SHORT POSITIONS 1
   if (Test_Dn) 
     {
      //----+ EXECUTION OF TRADES
      if (!OpenSellStopOrder1(SELL_Sign, 2, 
                Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn,
                                            PriceLevel_Dn, StopTime))
                                                                return(-1);
      if (TimeCurrent() >= PosStopTime)            
          if (ClosePos_Dn)
                if (!CloseOrder1(SELL_Stop, 2))
                                           return(-1);
                                        
      if (!Make_TreilingStop(2, TRAILINGSTOP_Dn))
                                           return(-1);
     }
   //----+ +---------------------------------------------------------------+
//----+ 
    
    return(0);
  }
//+------------------------------------------------------------------+


Conclusión

En este artículo he ofrecido un método universal para exportar información sobre los resultados de la optimización en formato de hoja de cálculo, que abre amplias posibilidades para un análisis profundo de esta información y una importante mejora de los resultados del trading usados por los asesores expertos en el trading automatizado. Espero que mi método sea útil a cualquier escritor de asesores expertos.