Plantilla universal de Asesor experto

Вадим Андреевич | 30 marzo, 2016

Introducción

Muchos traders se enfrentan al problema de escribir sus propios Asesores expertos. ¿Qué es lo primero? ¿Cómo se configura en un Asesor experto un código take-profit, stop-loss o trailing-stop? ¿Cómo se configura la funcionalidad de una estrategia? En este artículo se lidiará con las funciones principales para crear un Asesor experto. Quizás alguien creerá que el código de trailin es útil.

Variables del Asesor Experto

¿Cuántas variables se necesitan en cada Asesor experto? ¿Qué se debería hacer para que un tester pase también por los parámetros establecidos por las variables de tipo bool? Primero voy a hablar de un código de AE general que funciona con todos los pares de divisas; para una velocidad más alta, se recomienda ajustarlos según el tipo de divisa de cada trader. Después, 0-inhabilitado, 1-habilitado (porque queremos que todos los parámetros se comprueben en un optimizador. Si un código final se optimiza correctamente, se recomienda cambiar su parámetro). A continuación, los integradores inician los niveles de variables (stops), y en los códigos en los que sea necesario, se cambian a números fraccionarios. Aquí hay una plantalla del trade real en diferentes divisas. Por último, si los parámetros de stop son iguales a cero, quiere decir que no funciona.

Definir las variables

Vamos a empezar a definir las variables. Empezamos con aquellas que están expuestas a la optimización: las variables externas.

extern double MaxLot;
extern double TakeProfit;
extern double TrailingStop;
extern double StopLoss;
extern double MinProfit;
extern double ProfitPoints;
extern int    Slippage=0;
extern int Condition1=1;
extern double LotSpliter=1.0;
extern int CloseByOtherSideCondition;

La variable MaxLot establece el lote máximo cuando se quiere limitar (el lote también se limita por un servidor, pero de esto hablaré más tarde).
TakeProfit, StopLoss y TrailingStop funcionan cuando son superiores a cero.
MinProfit y ProfitPoints funcionan cuando ProfitPoints son superiores a cero, según el principio: un precio alcanza ProfitPoints y vuelve hasta MinProfit.
ConditionX habilita la entrada de las condiciones.
LotSpliter es una división de lotes. Sólo utiliza una parte de los lotes disponibles, por ejemplo, 0,1 incluye sólo lotes 10 veces más pequeño que la tasa disponible para el depósito entero.
CloseByOtherSideCondicion cierra una orden cuando aparece una condición positiva en el otro lado.

Vamos a configurar las variables internas, de las que se hablará junto con la descripción del AE.

double Lot;
double PP=0;
double slu,sld,a,b;
double tp,sl;

Código de inicialización

Veamos qué se puede calcular iniciando sólo un Asesor experto y utilizándolo más adelante en un código.

int init()
  {
   tp=TakeProfit;
   sl=StopLoss;
   return(0);
  }

Se cogen los valores de esas variables para el cambio de stop-levels. También se puede calcular un lote si va el trading va a realizarse todo el tiempo con el mismo volumen, y mostrar el exceso (más adelante se analiza el lote de cálculo en el artículo). También se puede crear un comentario desplegable que contenga la descripción o copyright del EA. Se hace de la siguiente manera:

Comment("cloud trade \n v2.0.11");

"\n": turnos principales de la siguiente línea que se muestre, "salto de línea".


Estructura del código

Veamos un código cuando no hay ninguna orden:

if(OrdersTotal()==0)
   {   
      preinit();
      if(U()==1)
      {
         OrderBuy();
         return(0);
      }
      if(U()==2)
      {
         OrderSell();
         return(0);
      }
      return(0);
   }

Parte de estas funciones se analizarán más tarde. Aquí está el principio: iniciar parámetros, comprobar si hay entrada de condiciones, introducir una condición.

Veamos un código cuando hay una orden:


if(OrderType()==OP_BUY)
        {
         if((slu)>PP)
           {
            PP=slu;
           }
         if(((slu)>0.001) && (OrderStopLoss()<(b-TrailingStop))
          && (OrderOpenPrice()<(b-TrailingStop))
           && (OrderProfit()>MathAbs(OrderSwap())))
           {
            if(TrailingStop!=0)
              {
               OrderModify(OrderTicket(), 0, b-TrailingStop, 0, 0, 0);
              }
           }
        }
      if(OrderType()==OP_SELL)
        {
         if((sld)>PP)
           {
            PP=sld;
           }
         if(((sld)>0.001) && (OrderStopLoss()>(a+TrailingStop))
          && (OrderOpenPrice()>(a+TrailingStop)))
           {
            if(TrailingStop!=0)
              {
               OrderModify(OrderTicket(), 0, a+TrailingStop, 0, 0, 0);
              }
           }
        }
      if(ProfitPoints!=0)
        {
         if(OrderType()==OP_BUY && PP>=ProfitPoints && (slu)<=MinProfit)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
         if(OrderType()==OP_SELL && PP>=ProfitPoints && (sld)<=MinProfit)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
        }
      if(CloseByOtherSideCondition==1)
        {
         if(OrderType()==OP_BUY && U()==2)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
         if(OrderType()==OP_SELL && U()==1)
           {
            CloseOnlyOrder(OrderTicket());
            return(0);
           }
        }

Primero se elige la única orden para futuras acciones (este código se analizará en una parte diferente del artículo). Luego se asignan variables a los precios para no cambiar el orden. Por ejemplo, en una trailing-stop en la dirección equivocada o en nuevos precios no rentables. Primero se comprueba una orden para la probabilidad de trailing-stop, al mismo tiempo se recopilan datos para la siguiente función: beneficio mínimo, del que se habló anteriormente. Luego es el turno de la función de cierre de una orden cuando aparezca una condición contraria y una apertura de una orden en la misma dirección.

Funciones que se analizan en el artículo

Veamos las funciones destinadas para acortar el código y que incorporan en bloques los pedidos utilizados más frecuentemente, para que se pueda llamar a los bloques completos. Vamos a configurar y comprobar estas condiciones:

//+------------------------------------------------------------------+
//|  returns a signal to buy or to sell                              |
//+------------------------------------------------------------------+
int U()
  {
      if((U1()==2 && Condition1==1)
       || (U2()==2 && Condition2==1)){return(2);}
      if((U1()==1 && Condition1==1)
       || (U2()==1 && Condition2==1)){return(1);}
   return(0);
  }
//+------------------------------------------------------------------+
//|  returns a signal based on stochastic values                     |
//+------------------------------------------------------------------+
int U1()
  {
   if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_SIGNAL,1)>=80)
     {
      if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,2)
           <=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_MAIN,2))
        {
         if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,1)
           >=iStochastic(Symbol(),Period(),
              Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,1))
           {
            return(2);
           }
        }
     }
   if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,1)<=20)
     {
      if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,2)
           >=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,2))
        {
         if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_SIGNAL,1)
              <=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,1))
           {
            return(1);
           }
        }
     }
   return(0);
  }
//+------------------------------------------------------------------+
//| find trend direction using fractals                              |
//+------------------------------------------------------------------+
int U2()
  {
   double fu=0,fd=0;
   int f=0,shift=2;
   while(f<2)
     {
      if(iFractals(Symbol(),Period(),MODE_UPPER,shift)>0)
        {
         fu=fu+1;
         f=f+1;
        }
      if(iFractals(Symbol(),Period(),MODE_LOWER,shift)>0)
        {
         fd=fd+1;
         f=f+1;
        }
      shift=shift+1;
     }
   if(fu==2){return(2);}
   if(fd==2){return(1);}
   return(0);
  }

La primera función comprueba las condiciones, las dos siguientes las configuran.

Vamos a mirar la función, a calcular los niveles de stop, si se han configurado mal, y a definir un valor de lote;

//+------------------------------------------------------------------+
//| preliminary initialization of variables                          |
//+------------------------------------------------------------------+
int preinit()
  {
   Lot=NormalizeDouble(MathFloor(LotSpliter*AccountBalance()*AccountLeverage()
      /Ask/MathPow(10,Digits+1)*10)/10,1);
   if(MaxLot>0 && Lot>MaxLot){Lot=MaxLot;}
   if(Lot>MarketInfo(Symbol(),MODE_MAXLOT)){Lot=MarketInfo(Symbol(),MODE_MAXLOT);}
   PP=0;
   StopLoss=sl;
   TakeProfit=tp;
   if(TakeProfit!=0 && TakeProfit<(MarketInfo(Symbol(),MODE_STOPLEVEL)))
     {
      TakeProfit=MarketInfo(Symbol(),MODE_STOPLEVEL);
     }
   if(StopLoss!=0 && StopLoss<(MarketInfo(Symbol(),MODE_STOPLEVEL)))
     {
      StopLoss=MarketInfo(Symbol(),MODE_STOPLEVEL);
     }
   return(0);
  }

Ahora configure las funciones, apertura de órdenes dependiendo de los niveles de stop predefinidos:

//+------------------------------------------------------------------+
//| returns true in case of a successful opening of Buy              |
//+------------------------------------------------------------------+
bool OrderBuy()
  {
   bool res=false;
   if(StopLoss!=0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage,
       NormalizeDouble(Ask-StopLoss,4),
        NormalizeDouble(Ask+TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage, 0,
       NormalizeDouble(Ask+TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask,
       Slippage, 0, 0, 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss!=0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage,
       NormalizeDouble(Ask-StopLoss,4), 0, 0, 0, 0, 0);
      return(res);
     }
   return(res);
  }
//+------------------------------------------------------------------+
//|   returns true in case of a successful opening of Sell           |
//+------------------------------------------------------------------+
bool OrderSell()
  {
   bool res=false;
   if(StopLoss!=0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit!=0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss==0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   if(StopLoss!=0 && TakeProfit==0)
     {
      res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage,
       NormalizeDouble(Bid+StopLoss,4),
        NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0);
      return(res);
     }
   return(res);
  }

La siguiente función cierra una orden con un tick, volumen y precio indicados.

//+-------------------------------------------------------------------------+
//|  returns true in case of a successful closing of an order with Ticket   |
//+-------------------------------------------------------------------------+
bool CloseOnlyOrder(int Ticket, double Lots ,double priceClose)
  {
   bool res=false;
   res=OrderClose(Ticket, Lots, priceClose, Slippage, 0);
   return(res);

Ahora miremos la función para elegir una orden sobre el número de posición para un funcionamiento futuro:

//+--------------------------------------------------------------------------------+
//| returns true in case of a successful choosing of an order in the position pos  |
//+--------------------------------------------------------------------------------+
bool SelectOnlyOrder(int pos)
  {
   bool res=false;
   res=OrderSelect(pos,SELECT_BY_POS,MODE_TRADES);
   return(res);
  }
//+------------------------------------------------------------------+

Algunas recomendaciones de codificación

Primero: configure las opciones como 0 y 1 en lugar de verdadero o falso. Esto le ayudará a optimizar mejor su Asesor experto. Segundo: no pase por alto stop-loss para limitar las posibles pérdidas cuando el mercado se mueva en la dirección opuesta a las condiciones. Tercero: no pruebe los expertos sin stop-loss: es probable que lleve a una pérdida rápida de depósito. Cuarto: utilice las funciones y los bloques, que le ayudarán a que el código se entienda de manera más fácil.

Conclusión

Es fácil crear un Asesor experto. Y para hacerlo aún más fácil, el siguiente archivo adjunto contiene el Asesor experto que se ha analizado en este artículo.