English Русский 中文 Deutsch 日本語 Português
Filtrado por Historial

Filtrado por Historial

MetaTrader 4Sistemas comerciales | 11 mayo 2016, 10:40
606 0
Andrey Khatimlianskii
Andrey Khatimlianskii

Introducción


Hay diferentes valores de filtros: valores de los indicadores, inestabilidad del mercado, tiempo, día de la semana. Se pueden utilizar todos para tamizar los trades perdidos. Es bastante fácil de añadir un filtro a un Asesor experto - sólo hay que añadir una condición más antes de la apertura del bloque.

Pero, ¿qué se debería hacer si se quiere utilizar el historial del AE como filtro? Hay que cambiar el sistema de trader después de varios trades sin éxito, no habrá historial luego y, por lo tanto, no habrá nada que analizar. Para resolver este problema, necesitamos enseñar a un Asesor Experto a hacer trade virutalmente, es decir, simular la apertura, modicación y cierre de trades sin una actividad de trading real.

De esto trata el artículo.

Estrategia experimental


Para la implementación de nuestro sistema, se harán varios cambios en el Asesor Experto CrossMACD_DeLuxe.mq4:
  • en apertura/modificación/cierre de cada posición, se escribirán los cambios en una gama de posiciones virtuales;
  • se añade el seguimiento de la actuación de StopLoss y TakeProfit de las posiciones virtuales;
  • se añaden los criterios de filtrado - una condición sobre la que no se abrirán trades reales.
Intentaré describir cada paso de la modificación del AE con el máximo de detalles. Si no está interesado, puede descartar el Asesor Experto preparado y pasar a la parte de "¿Es que el juego no merece la vela?"

Posiciones de contabilidad virtuales


Al abrir una señal, apareció una posición. Los parámetros de StopLoss y TakeProfit ya se han calculado, todo está listo para llamar a la función OrderSend(). Exactamente en este momento, se abre el trade virtual - sólo hay que guardar todos los parámetros necesarios en las variables adecuadas.

void OpenBuy()
  {
    int _GetLastError = 0;
    double _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel;
    _OpenPriceLevel = NormalizeDouble(Ask, Digits);
 
    if(StopLoss > 0)
        _StopLossLevel = NormalizeDouble(_OpenPriceLevel - 
                                     StopLoss*Point, Digits); 
    else
        _StopLossLevel = 0.0; 
    if(TakeProfit > 0)
        _TakeProfitLevel = NormalizeDouble(_OpenPriceLevel + 
                                   TakeProfit*Point, Digits); 
    else
        _TakeProfitLevel = 0.0; 
 
    //---- open the virtual position
    virtOrderSend(OP_BUY, _OpenPriceLevel, _StopLossLevel, 
                  _TakeProfitLevel);
 
    if(OrderSend(Symbol(), OP_BUY, 0.1, _OpenPriceLevel, 3, 
       _StopLossLevel, _TakeProfitLevel, "CrossMACD", 
       _MagicNumber, 0, Green) < 0)
      {
        _GetLastError = GetLastError();
        Alert("Error OrderSend № ", _GetLastError);
        return(-1);
      }
  }
 
//---- Save parameters of the opened position in main variables
void virtualOrderSend(int type, double openprice, double stoploss,
                      double takeprofit)
  {
    virtTicket = 1;
    virtType = type;
    virtOpenPrice = openprice;
    virtStopLoss = stoploss;
    virtTakeProfit = takeprofit;
  }


Sólo se utilizan cinco variables:

int       virtTicket     = 0;   
// determines, if there is an open virtual position
int       virtType       = 0;   // position type
double    virtOpenPrice  = 0.0; // position opening price
double    virtStopLoss   = 0.0; // position StopLoss
double    virtTakeProfit = 0.0; // position TakeProfit


No se necesitan otras característcas para guardar esta tarea. Si quiere profundizar en la funcionalidad de este ejemplo, sólo añada la cantidad necesaria de variables.

Para la posición de seguimiento, cierre y modificación, se necesitará hacer más. Se copia el bloque de control de las posiciones abiertas, que está en el Asesor Experto, y se cambie el orden de las características a las virtuales:

int start()
  {
    // skipped...
 
    //+------------------------------------------------------------------+
    //| Control block of "virtual" positions                             |
    //+------------------------------------------------------------------+
    if(virtTicket > 0)
      {
        //---- if BUY-position is open,
        if(virtType == OP_BUY)
          {
            //---- if MACD crossed 0-line downwards,
            if(NormalizeDouble(MACD_1 + CloseLuft*Point*0.1, 
               Digits + 1) <= 0.0)
              {
                //---- close position
                virtOrderClose(Bid);
              }
            //---- if the signal did not change, accompany the position by 
            //     TrailingStop
            else
              {
                if(TrailingStop > 0)
                  {
                    if(NormalizeDouble(Bid - virtOpenPrice, 
                       Digits ) > 0.0)
                      {
                        if(NormalizeDouble( Bid - TrailingStop*Point - 
                           virtStopLoss, Digits) > 0.0 || virtStopLoss < Point)
                        {
                          virtStopLoss = Bid - TrailingStop*Point;
                        }
                      }
                  }
              }
          }
        //---- if SELL position is open
        if(virtType == OP_SELL)
          {
            //---- if MACD crossed 0-line upwards,
            if(NormalizeDouble(MACD_1 - CloseLuft*Point*0.1, 
               Digits + 1 ) >= 0.0)
              {
                //---- close the position
                virtOrderClose(Ask);
              }
            //---- if the signal did not change, accompany the position by
            //     TrailingStop
            else
              {
                if ( TrailingStop > 0 )
                  {
                    if(NormalizeDouble( virtOpenPrice - Ask, 
                       Digits ) > 0.0 )
                      {
                        if(NormalizeDouble( virtStopLoss - ( Ask + 
                           TrailingStop*Point ), Digits ) > 0.0 ||
                           virtStopLoss <= Point )
                          {
                            virtStopLoss = Ask + TrailingStop*Point;
                          }
                      }
                  }
              }
          }
      }
    // skipped...
    return(0);
  } 
 
 
//---- virtual position closing function
void virtOrderClose(double closeprice)
  {
    //---- Save the parameters of the closed position in the array
    ArrayResize(virtClosedOrders, virtClosedOrdersCount + 1);
 
    virtClosedOrders[virtClosedOrdersCount][0] = virtType;
    virtClosedOrders[virtClosedOrdersCount][1] = virtOpenPrice;
    virtClosedOrders[virtClosedOrdersCount][2] = virtStopLoss;
    virtClosedOrders[virtClosedOrdersCount][3] = virtTakeProfit;
    virtClosedOrders[virtClosedOrdersCount][4] = closeprice;
 
    virtClosedOrdersCount ++;
 
    //---- clear variables
    virtTicket = 0;
    virtType = 0;
    virtOpenPrice = 0.0;
    virtStopLoss = 0.0;
    virtTakeProfit = 0.0;
  }


La modificación resultó en una asignación simple de un nuevo valor a la variable virtStopLoss. Y el cierre es algo complicado - todas las características de las órdenes cerradas se guardan en una gama. Más tarde está guardado todo el historial virtual. De ahí se coge la información sobre la posición cerrada para tomar una decisión sobre abrir una nueva posición.

Ahora hay que procesar el cierre de la posición sobre StopLoss y TakeProfit. Para ello, hay que añadir varias series al bloque de control que se ha creado:

if(virtType == OP_BUY)
  {
    //---- check, whether SL was not activated 
    if(virtStopLoss > 0.0 && NormalizeDouble(virtStopLoss - Bid, 
       Digits ) >= 0.0)
      {
        virtOrderClose(virtStopLoss);
      }
    //---- check, whether TPL was not activated
    if(virtTakeProfit > 0.0 && NormalizeDouble( Bid - virtTakeProfit, 
       Digits ) >= 0.0)
      {
        virtOrderClose(virtTakeProfit);
      }
  }


Ahora el historial virtual está listo y se pueden añadir los criterios de filtración.

¿Qué es "bueno" y qué es "malo"?


Hay que impedir que la posición se abra tras implementar una cierta condición. Pero, ¿qué condición hay que escoger? Varios trades con pérdidas sucesivos, activación de StopLoss, o reducir el beneficio medio de varios de los últimos trades. Es difícil de responder, desde luego - cada variante puede tener sus ventajas y sus inconvenientes.

Para comprobar la eficiencia de cada condición, se intentarán codificar las tres y probarlas en el historial:

extern int TradeFiltrVariant = 0;
 
//---- Function of checking the necessity of the real trading
bool virtCheckCondition()
  {
    int pos, check_pos = 2;
    double last_profit = 0.0, pre_last_profit = 0.0;
    
    //---- depending on the value of TradeFiltrVariant:
    switch(TradeFiltrVariant)
      {
        //---- 1: prohibit real trading, if 2 last deals are losing
        case 1:
          {
            //---- if the virtual history contains enough orders,
            if(virtClosedOrdersCount >= check_pos)
              {
                for(pos = 1; pos check_pos; pos ++)
                  {
                    //---- if the deal is profitable, return true
                    if((virtClosedOrders[virtClosedOrdersCount-pos][0] == 0 && 
                        virtClosedOrders[virtClosedOrdersCount-pos][4] - 
                        virtClosedOrders[virtClosedOrdersCount-pos][1] >= 0.0) ||
                        (virtClosedOrders[virtClosedOrdersCount-pos][0] == 1 && 
                        virtClosedOrders[virtClosedOrdersCount-pos][1] - 
                        virtClosedOrders[virtClosedOrdersCount-pos][4] >= 0.0))
                      {
                        return(true);
                      }
                    }
              }
            return(false);
          }
        //---- 2: prohibit real trading if the last position was closed 
        //        by StopLoss
        case 2:
          {
            //---- if the virtual history contains enough orders,
            if(virtClosedOrdersCount > 0)
              {
                //---- if the closing price of the last order is equal to StopLoss,
                if(virtClosedOrders[virtClosedOrdersCount-1][2] - 
                   virtClosedOrders[virtClosedOrdersCount-1][4] < Point &&
                   virtClosedOrders[virtClosedOrdersCount-1][4] - 
                   virtClosedOrders[virtClosedOrdersCount-1][2] < Point)
                  {
                    return(false);
                  }
              }
            return(true);
          }
        //---- 3: prohibit real trading, if the profit of the last position  
        //----    is lower than that of the last but one position (or loss is higher)
        case 3:
          {
            if(virtClosedOrdersCount >= 2)
              {
                if(virtClosedOrders[virtClosedOrdersCount-1][0] == 0)
                  {
                    last_profit =  virtClosedOrders[virtClosedOrdersCount-1][4] - 
                                   virtClosedOrders[virtClosedOrdersCount-1][1];
                  }
                else
                  {
                    last_profit =  virtClosedOrders[virtClosedOrdersCount-1][1] - 
                                   virtClosedOrders[virtClosedOrdersCount-1][4];
                  }
                if(virtClosedOrders[virtClosedOrdersCount-2][0] == 0)
                  {
                    pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][4] - 
                                      virtClosedOrders[virtClosedOrdersCount-2][1];
                  }
                else
                  {
                    pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][1] - 
                                      virtClosedOrders[virtClosedOrdersCount-2][4];
                  }
 
                if(pre_last_profit - last_profit > 0.0)
                  {
                    return(false);
                  }
              }
            return(true);
          }
        //---- by default the filter is off, i.e. positions will be always opened in reality
        default: return(true);
      }
    return(true);
  }
 
void OpenBuy()
  {
    int _GetLastError = 0;
    double _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel;
    _OpenPriceLevel = NormalizeDouble(Ask, Digits);
 
    if(StopLoss > 0)
      { 
        _StopLossLevel = NormalizeDouble(_OpenPriceLevel - StopLoss*Point, Digits); 
      }
    else
      { 
        _StopLossLevel = 0.0; 
      }
 
    if(TakeProfit > 0)
      { 
        _TakeProfitLevel = NormalizeDouble(_OpenPriceLevel + TakeProfit*Point, Digits); 
      }
    else
      { 
        _TakeProfitLevel = 0.0; 
      }
 
    //---- open a virtual position
    virtOrderSend(OP_BUY, _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel);
 
    //---- if virtual positions filter prohibits trading, exit
    if(virtCheckCondition() == false) 
      { 
        return(0); 
      }
 
    if(OrderSend( Symbol(), OP_BUY, 0.1, _OpenPriceLevel, 3, _StopLossLevel, 
          _TakeProfitLevel, "CrossMACD", _MagicNumber, 0, Green) < 0 )
      {
        _GetLastError = GetLastError();
        Alert("Error OrderSend № ", _GetLastError);
        return(-1);
      }
  }


Ahora hay una variable externa, TradeFiltrVariant. Se encarga de elegir los criterios de filtración:

extern int TradeFiltrVariant = 0;
//---- 0: filter is off, i.e. position is always opened in reality
//---- 1: prohibit real trading, if 2 last positions are losing
//---- 2: prohibit real trading, if the last position closed by StopLoss
//---- 3: prohibit real trading, ifthe profit of the last position is lower, 
//----    than that of the last but one psition (or loss is higher)


Ahora pruebe el Asesor Experto con los diferentes filtros y compare los resultados.

¿El juego no se merece la vela?


Para la prueba, elejí los siguientes parámetros:
Símbolo: GBPUSD
Periodo: H4, 01,01.2005 - 01,01.2006
Modo de modelo: todos los ticks (calidad de modelo 90%, las cotizaciones del HistoryCenter)

Parámetros del AE:
StopLoss: 50
TakeProfit: 0 (deshabilitado)
TrailingStop: 0 (deshabilitado)
FastEMAPeriod: 12
SlowEMAPeriod: 26
OpenLuft: 10
CloseLuft: 0

La siguiente tabla muestra la dependencia de los resultados el filtro utilizado:

TradeFiltrVariant Total beneficio/pérdida
Trades totales
Trades rentables
Trades con pérdidas
0 1678,75
41 9 (22%)
32 (78%)
1 105,65 20
2 (10%)
18 (90%)
2 -550,20 11 0 (0%)
11 (100%)
3 1225,13 28 7 (25%)
21 (75%)









La teoría sobre la utilidad del filtro no se ha probado. Además, los resultados de los trades con el filtro son más bajos que aquellos de los trados sin filtro. La única excepción es la tercera variante - la tasa de trades rentables es más alta (25% contra 22%), pero el beneficio total es más bajo en las tres variantes.

Entonces, ¿qué es lo que estaba mal? Probablemente, lo que estaba mal era la filtración de los criterios. Vamos a intentar cambiar los tres filtros a sus contrarios, es decir, cerrar el trading real si:
  • los dos últimos trades tienen beneficios;
  • la última posición tiene beneficios (no tenemos un analógico de StopLoss, porque TakeProfit está deshabilitado);
  • El beneficio de la última posición es más alto que aquello de la penúltima posición.
Para no limitar al Asesor Experto, sólo hay que añadir tres valores más de TradeFiltrVariant - 4, 5 y 6:

//---- 4: prohibit real trading, if two last trades are profitable
//---- 5: prohibit real trading, if the last position is profitable
//---- 6: prohibit real trading, if the profit of the last position is higher, 
//----    than that of the last but one position (or loss is lower)
 
    //---- 4: prohibit real trading, if two last trades are profitable
    case 4:
      {
        if(virtClosedOrdersCount >= check_pos)
          {
            for(pos = 1; pos check_pos; pos ++)
              {
                //---- if the trade is losing, return true
                if((virtClosedOrders[virtClosedOrdersCount-pos][0] == 0 && 
                   virtClosedOrders[virtClosedOrdersCount-pos][1] - 
                   virtClosedOrders[virtClosedOrdersCount-pos][4] > 0.0) ||
                   (virtClosedOrders[virtClosedOrdersCount-pos][0] == 1 && 
                   virtClosedOrders[virtClosedOrdersCount-pos][4] - 
                   virtClosedOrders[virtClosedOrdersCount-pos][1] > 0.0))
                  {
                    return(true);
                  }
              }
          }
        return(false);
      }
    //---- 5: prohibit real trading, if the last position is profitable
    case 5:
      {
        if(virtClosedOrdersCount >= 1)
          {
            if(virtClosedOrders[virtClosedOrdersCount-1][0] == 0)
              {
                last_profit =  virtClosedOrders[virtClosedOrdersCount-1][4] - 
                               virtClosedOrders[virtClosedOrdersCount-1][1];
              }
            else
              {
                last_profit =  virtClosedOrders[virtClosedOrdersCount-1][1] - 
                               virtClosedOrders[virtClosedOrdersCount-1][4];
              }
 
            if(last_profit > 0.0)
              {
                return(false);
              }
          }
        return(true);
      }
    //---- 6: prohibit real trading, if the profit of the last position is higher, 
    //----    than that of the last but one position (or loss is lower)
    case 6:
      {
        if(virtClosedOrdersCount >= 2)
          {
            if(virtClosedOrders[virtClosedOrdersCount-1][0] == 0) 
              {
                last_profit =  virtClosedOrders[virtClosedOrdersCount-1][4] - 
                               virtClosedOrders[virtClosedOrdersCount-1][1];
              }
            else
              {
                last_profit =  virtClosedOrders[virtClosedOrdersCount-1][1] - 
                               virtClosedOrders[virtClosedOrdersCount-1][4];
              }
            if(virtClosedOrders[virtClosedOrdersCount-2][0] == 0)
              {
                pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][4] - 
                                  virtClosedOrders[virtClosedOrdersCount-2][1];
              }
            else
              {
                pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][1] - 
                                  virtClosedOrders[virtClosedOrdersCount-2][4];
              }
 
            if(last_profit - pre_last_profit > 0.0)
              {
                return(false);
              }
          }
        return(true);
      }


Ahora vamos a probar tres nuevas variantes y añadirlas a la tabla:

AdaptVariant Total beneficio/pérdida
Trades totales
Trades con beneficios
Trades con pérdidas
0 1678,75
41 9 (22%)
32 (78%)
1 105,65 20 2 (10%)
18 (90%)
2 -550,20 11 0 (0%)
11 (100%)
3 1225,13 28 7 (25%)
21 (75%)
4
1779,24
39 9 (23%) 30 (77%)
5
2178,95
31
9 (29%)
22 (71%)
6
602,32
24
5 (21%)
19 (79%)














La sexta variante filtró la mitad de los trades - tanto los que tenían beneficios como los que no. El cuarto tamizó dos trades con pérdidas, aumentando el beneficio total a 100.49 dólares.

Y la mejor es la variante, prohibiendo el trading después de cada trade con beneficios - filtró 10 trades con pérdidas y trades sin beneficios.

Así que hay esperanza - incluso una estrategía tan simple y popular puede mejorarse.

Conclusión


Creo que estos filtros no son suficientes para la mejora de un sistema real - hay que realizar investigaciones mucho más profundas y hacer nueva conclusiones.

Los filtros descritos pueden ser más complejos y completamente diferentes en cada estrategia. La eficiencia depende directamente en el intercambio de las posiciones rentables y con pérdidas.

Este artículo insiste sólo en el asunto de los filtros. Pero espero que dé un impulso a mejoras profundas.




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

Archivos adjuntos |
Modelado de las recotizaciones en el Tester y análisis de estabilidad del Asesor Experto Modelado de las recotizaciones en el Tester y análisis de estabilidad del Asesor Experto
La recotización es una lacra para muchos Asesores Expertos, especialmente para aquellos que tienen condiciones más bien sensibles de entrada/salida de un trade. En el artículo, se ofrece una manera para controlar al Asesor Externo en la estabilidad de las recotizaciones.
Mostrar los niveles de soporte/resistencia Mostrar los niveles de soporte/resistencia
El artículo trata sobre la detección e indicación de los niveles de soporte/resistencia en el programa MetaTrader 4. El indicador adecuado y universal está basado en un algoritmo simple. El artículo también aborda el tema de la creación de un indicador simple que pueda mostrar los resultados de diferentes periodos de tiempo en un espacio de trabajo.
Gráficos de tres dimensiones - una herramienta profesional de análisis del mercado Gráficos de tres dimensiones - una herramienta profesional de análisis del mercado
En este artículo escribiremos una biblioteca simple para la construcción de gráficos en 3D, y su visualización futura en Microsoft Excel. Se utilizarán las opciones estándar de MQL4 para prerarlo y exportar los datos en un archivo *.csv.
Un método de escritura de los niveles de soporte/resistencia Un método de escritura de los niveles de soporte/resistencia
Este artículo describe el proceso de crear un script simple para detectar los niveles de soporte/resistencia. Está escrito para principiantes, y tiene una explicación detallada de cada fase del proceso. Sin embargo, aunque el guión es muy simple, el artículo también será útil para traders más avanzados y para los usuarios de la plataforma MetaTrader 4. Contiene ejemplos de la exportación de datos en formato tabular, la importación de la tabla a Microsoft Excel, y la esquematización de gráficos para su futuro análisis más detallado.