La escritura de un Asesor Experto mediante las librerías estándar de las clase de trading de MQL5

Samuel Olowoyo | 11 marzo, 2014

Introducción

El nuevo programa MQL5 trae muchas Librerías de clases estándar que están destinadas a desarrollar Asesores Expertos de MQL5, indicadores y scripts de la forma más sencilla posible para los traders y los desarrolladores.

Estás librerías de clases se encuentran en la carpeta \Include\ ubicada en la carpeta de MQL5 que se encuentra en la carpeta del terminal de cliente MetaTrader 5. Se dividen las librerías de clases en varias categorías; Arrays, ChartObjects, Charts, Files, Indicators, Strings y las clases de trading.

En este artículo, vamos a describir en detalle cómo podemos utilizar las clases de trading incorporadas, para escribir un Asesor Experto. Se basará el Asesor Experto en la estrategia que va a incluir el cierre o modificación de las posiciones abiertas cuando se cumple una determinada condición.

Si ya tiene una idea de lo que son las clases y cómo se pueden utilizar, entonces bienvenido a otro mundo de posibilidades que ofrece el nuevo lenguaje MQL5.

Si, de lo contrario, es nuevo en MQL5; entonces le sugiero leer estos dos artículos para empezar Guía paso a paso para escribir un Asesor Experto en MQL5 para principiantes, Escribir un Asesor Experto mediante la programación orientada a objetos de MQL5 o cualquier otro artículo que le pueda proporcionar una introducción al nuevo lenguaje MQL5. Muchos de los artículos escritos le pueden proporcionar los conocimientos necesarios.


1. Las clases para operaciones de trading

El repertorio de las clases de trading se compone de distintas clases que tienen el propósito de hacer la vida más fácil a los traders que quieren desarrollar un Asesor Experto para su propio uso o a los programadores que no tendrán que reinventar el proceso al desarrollar sus Asesores Expertos.

En el uso de una clase, no tiene que conocer el funcionamiento interno de la misma (es decir, cómo cumple con lo que ha dicho el desarrollador), todo lo que tiene que hacer es centrarse en la manera de utilizar la clase para resolver su problema. Es por ello que el uso de librerías de clases incorporadas hace que las cosas sean mucho más fáciles para cualquier persona que quiera utilizarlas. En este artículo nos centraremos en las principales clases que puedan ser necesarias durante el desarrollo de un Asesor Experto.

Al analizar una clase, no vamos a entretenernos con los detalles internos de la misma, pero sí que comentaremos en detalle lo que puede hacer una clase y cómo podemos utilizarla para lograr nuestro objetivo de desarrollar un Asesor Experto muy rentable. Vamos a comentarlas una por una.

1.1 La clase СAccountInfo

La clase CAccountInfo permite al usuario acceder fácilmente a todas las propiedades de la cuenta o las informaciones de la cuenta de trading abierta en el terminal de cliente.

Para entenderlo mejor, vamos a echar un vistazo a las principales funciones miembro de esta clase, susceptibles de ser utilizadas en nuestro Asesor Experto. Antes de poder utilizar una clase, antes que nada, hay que crear un objeto de esta clase, así que para utilizar la clase CAccountInfo, tenemos que crear un objeto de la clase.

Vamos a llamarlo myaccount:

//--- The AccountInfo Class Object
CAccountInfo myaccount;

Vamos a recordar que para crear un objeto de una clase, utilizará el nombre de la clase seguido del nombre que le quiere asignar al objeto.

Ahora podemos utilizar nuestro objeto myaccount para acceder a las funciones miembro públicas de la clase CAccountInfo .

Método
Descripción
Ejemplos de uso
myaccount.Login()

Se utiliza esta función para obtener el número de cuenta de la operación abierta en este momento en el terminal.

// returns account number, example 7770
long accountno = myaccount.Login()
myaccount.TradeModeDescription() Se utiliza esta función para obtener la descripción del modo de la operación para la cuenta activa actual en el terminal.
// returns Demo trading account, 
// or Real trading account or Contest trading account
string  acc_trading_mode = myaccount.TradeModeDescription();
myaccount.Leverage()

Se utiliza esta función para obtener la descripción del modo de la operación para la cuenta activa actual en el terminal.

// returns leverage given to the active account
long acc_leverage = myaccount.Leverage(); 
myaccount.TradeAllowed()  

Se utiliza esta función para comprobar si la operación está permitida en la cuenta activa del terminal. Si la operación no está permitida, la cuenta no puede llevarla a cabo.

if (myaccount.TradeAllowed())
{
    // trade is allowed
}
else
{
  // trade is not allowed
}
myaccount.TradeExpert() Se utiliza esta función para comprobar si los Asesores Expertos tienen permiso para operar en este momento en la cuenta activa del terminal.
if (myaccount.TradeExpert())
{
   // Expert Advisor trade is allowed
}
else
{
   // Expert Advisor trade is not allowed
}
myaccount.Balance() Esta función proporciona el saldo de la cuenta para la cuenta activa del terminal.
// returns account balance in the deposit currency
double acс_balance =  myaccount.Balance(); 
myaccount.Profit()  

Se utiliza esta función para obtener el beneficio actual en la cuenta activa del terminal.

// returns account profit in deposit currency
double acс_profit =  myaccount.Profit();
myaccount.FreeMargin()  

Se utiliza esta función para obtener el margen libre de la cuenta activa en el terminal.

// returns free margin for active account
double acс_free_margin = myaccount.FreeMargin();
myaccount.Currency()  

Se utiliza esta función para obtener la divisa del depósito de la cuenta activa en el terminal.

string acс_currency = myaccount.Currency();
myaccount.OrderProfitCheck(const string symbol, ENUM_ORDER_TYPE  trade_operation, double volume, double price_open, double price_close) Esta función obtiene el beneficio previsto, basado en los parámetros que recibe. Los parámetros de entrada son: el símbolo, el tipo de operación de trading, el volumen y los precios de apertura/cierre.
double op_profit=myaccount.OrderProfitCheck(_Symbol,ORDER_TYPE_BUY,
1.0,1.2950,1.3235);
Print("The amount of Profit for deal buy EURUSD",
      "at 1.2950 and sell at 1.3235 is: ",op_profit);
myaccount.MarginCheck(const string symbol,ENUM_ORDER_TYPE trade_operation,double  volume,double price) Se utiliza esta función para obtener el margen necesario para abrir una orden. Esta función tiene cuatro parámetros de entrada que son: el símbolo (par de divisas), el tipo de orden, los lotes (o volúmenes) para operar y el precio de la orden. Esta operación es muy importante cuando se coloca una operación.
// depending on the type of position to open - in our case buy
double price=SymbolInfoDouble(_Symbol,SYMBOL_ASK); 
double margin_req=myaccount.MarginCheck(_Symbol,ORDER_TYPE_BUY,LOT,price);

myaccount.FreeMarginCheck(const string symbol,ENUM_ORDER_TYPE trade_operation,double volume,double price) Se utiliza esta función para obtener la cantidad del margen libre que queda en la cuenta activa cuando se coloca una orden. Tiene cuatro parámetros de entrada que son: el símbolo (par de divisas), el tipo de orden, los lotes (o volúmenes) para operar y el precio de la orden.
double acс_fm=myaccount.FreeMarginCheck(_Symbol,ORDER_TYPE_BUY,LOT,price);
myaccount.MaxLotCheck(const string symbol,ENUM_ORDER_TYPE trade_operation,double price)  

Se utiliza esta función para obtener el máximo lote posible para colocar en la cuenta activa en el terminal. Tiene tres parámetros de entrada y son: el símbolo, el tipo de orden y el precio de apertura de la orden.

double max_lot=myaccount.MaxLotCheck(_Symbol,ORDER_TYPE_BUY,price);

1.2 La clase СSymbolInfo

La clase CSymbolInfo facilita mucho el acceso del usuario de forma rápida a todas las propiedades del símbolo actual.

Para utilizar la clase, tenemos que crear un objeta de la clase, en este caso lo llamaremos mysymbol.

// the CSymbolInfo Class object CSymbolInfo mysymbol;

 Vamos a echar un vistazo a la mayoría de las funciones de esta clase, susceptibles de ser utilizadas en el proceso de escritura de nuestro Asesor Experto:

 Método  Descripción Ejemplos de uso
mysymbol.Name(string  name)

Se utiliza esta función para establecer el símbolo del objeto de la clase. Toma el nombre del símbolo como parámetro de entrada.

// set the symbol name for our CSymbolInfo class Object
mysymbol.Name(_Symbol);
mysymbol.Refresh() Se utiliza esta función para actualizar todos los datos del símbolo. También se llama automáticamente a esta clase cuando se establece un nuevo nombre de símbolo de la clase.
mysymbol.Refresh();
mysmbol.RefreshRates() Se utiliza esta función para comprobar los datos de las últimas cotizaciones. Devuelve true en caso de éxito y false en caso de fallo. Es una función muy útil, de la que no puede prescindir.
//--- Get the last price quote using the CSymbolInfo 
// class object function
   if (!mysymbol.RefreshRates())
   {
      // error getting latest price quotes 
   }
mysymbol.IsSynchronized()

Se utiliza esta función para comprobar si los datos actuales del símbolo establecido en el terminal están sincronizados con los datos en el servidor. Si los datos están sincronizados devuelve true y devuelve false si no lo están.

// check if symbol data are synchronized with server
  if (!mysymbol.IsSynchronized())
   {
     // error! Symbol data aren't synchronized with server
   }
mysymbol.VolumeHigh()  

Se utiliza esta función para obtener el volumen máximo del día del símbolo establecido.

long max_vol = mysymbol.VolumeHigh();
mysymbol.VolumeLow()  

Se utiliza esta función para obtener el volumen mínimo del día del símbolo establecido.

long min_vol = mysymbol.VolumeLow();
mysymbol.Time()  

Se utiliza esta función para obtener el último tiempo de cotización de precio del símbolo establecido.

datetime qtime = mysymbol.Time();
mysymbol.Spread() Se utiliza esta función para obtener el valor del spread actual (en puntos) del símbolo establecido.
int spread = mysymbol.Spread();
mysymbol.StopsLevel() Se utiliza esta función para obtener el nivel mínimo (en puntos) del precio de cierre actual por el cual se puede colocar el Stop Loss del símbolo establecido. Una función muy útil si está considerando utilizar el Trailing Stop o la modificación de la orden/posición.
int stp_level = mysymbol.StopsLevel();
mysymbol.FreezeLevel() Se utiliza esta función para obtener la distancia (en puntos) de la congelación de la operación de trading del símbolo establecido.
int frz_level = mysymbol.FreezeLevel();
mysymbol.Bid()

Se utiliza esta función para obtener el precio BID (de compra) del símbolo establecido.

double bid =  mysymbol.Bid();
mysymbol.BidHigh() Se utiliza esta función para obtener el precio BID (de compra) máximo/más alto del día.
double max_bid = mysymbol.BidHigh();
mysymbol.BidLow() Se utiliza esta función para obtener el precio BID (de compra) mínimo/más bajo del día para el símbolo establecido.
double min_bid = mysymbol.BidLow();
msymbol.Ask() Se utiliza esta función para obtener el precio ASK (de venta) del símbolo establecido.
double ask = mysymbol.Ask();
mysymbol.AskHigh() Se utiliza esta función para obtener el precio ASK (de venta) máximo/más alto del día para el símbolo establecido.
double max_ask = mysymbol.AskHigh();
mysymbol.AskLow() Se utiliza esta función para obtener el precio ASK (de venta) mínimo/más bajo del día
double min_ask = mysymbol.AskLow();
mysymbol.CurrencyBase() Se utiliza esta función para obtener divisa de referencia del símbolo establecido.
// returns "USD" for USDJPY or USDCAD
string base_currency = mysymbol.CurrencyBase();
mysymbol.ContractSize() Se utiliza esta función para obtener la cantidad para el tamaño del contrato para el trading del símbolo establecido.
double cont_size =  mysymbol.ContractSize();
mysymbol.Digits()  Se utiliza esta función para obtener el número de decimales del símbolo establecido.
int s_digits = mysymbol.Digits();
mysymbol.Point() Se utiliza esta función para obtener el valor de un punto del símbolo establecido.
double s_point =  mysymbol.Point();
mysymbol.LotsMin() Se utiliza esta función para obtener el mínimo volumen necesario para cerrar una transacción del símbolo.
double min_lot =  mysymbol.LotsMin();
mysymbol.LotsMax() Se utiliza esta función para obtener el máximo volumen necesario para cerrar una transacción del símbolo.
double max_lot =  mysymbol.LotsMax();
mysymbol.LotsStep() Se utiliza esta función para obtener el mínimo paso del cambio de volumen para cerrar una transacción del símbolo.
double lot_step = mysymbol.LotsStep();
mysymbol.NormalizePrice(double price) Se utiliza esta función para obtener el precio normalizado a los dígitos correctos del símbolo establecido.
// A normalized current Ask price
double n_price = mysymbol.NormalizePrice(mysymbol.Ask()); 
mysymbol.Select() Se utiliza esta función para determinar si un símbolo ha sido seleccionado en la ventana de observación del mercado. Si el símbolo ha sido seleccionado devuelve true, de lo contrario, devuelve false.
if (mysymbol.Select())
{
  //Symbol successfully selected
}
else
{
  // Symbol could not be selected
}

mysymbol.Select(bool select) Se utiliza esta función para seleccionar un símbolo de la ventana de observación del mercado o quitar un símbolo de la ventana de observación del mercado. Cabe señalar que la eliminación de un símbolo de la ventana de observación del mercado cuando está abierto el gráfico o cuando aún hay una posición abierta devolverá false.
if (!mysymbol.Select())
{
   //Symbol not selected, Select the symbol
    mysymbol.Select(true);
}
else
{
 // Symbol already selected, 
 // remove Symbol from market watch window
    mysymbol.Select(false);
}

mysymbol.MarginInitial() Se utiliza esta función para obtener la cantidad necesaria para abrir una posición con el volumen de un lote en la divisa del margen.
double init_margin = mysymbol.MarginInitial() ; 
mysymbol.TradeMode() Se utiliza esta función para obtener el tipo de ejecución permitido de la orden del símbolo establecido.
if (mysymbol.TradeMode() == SYMBOL_TRADE_MODE_FULL)
{
 // Full trade allowed for this symbol,
 // no trade restrictions 
}
mysymbol.TradeModeDescription() Se utiliza esta función para obtener la descripción del tipo de ejecución permitido de la orden del símbolo establecido.
Print("The trade mode for this symbol is",
       mysymbol.TradeModeDescription());

1.3 La clase СHistoryOrderInfo

CHistoryOrderInfo es otra clase que permite que el manejo de las propiedades del historial de las órdenes sea muy sencillo.

Una vez creamos el objeto de una clase, podemos utilizarlo para acceder a las importantes funciones miembro públicas que necesitamos para la resolución inmediata de un problema.

A este objeto de la clase lo vamos a llamar myhistory

// The CHistoryOrderInfo Class object
CHistoryOrderInfo myhistory;

Echemos un vistazo a las principales funciones de esta clase.

Al utilizar esta clase para obtener los detalles de las órdenes en el historial, antes que nada, tenemos que obtener todas la órdenes en el historial y luego pasar el ticket de la orden al objeto de nuestra clase, myhistory.

//Select all history orders within a time period
if (HistorySelect(0,TimeCurrent()))  // get all history orders
{
// Get total orders in history
int tot_hist_orders = HistoryOrdersTotal(); 

Vamos a recorrer de forma iterativa el historial disponible de órdenes en su totalidad y obtener los detalles de cada orden del historial mediante el objeto de nuestra clase.

ulong h_ticket; // Order ticket

for (int j=0; j<tot_hist_orders; j++)
{
  h_ticket = HistoryOrderGetTicket(j));

  if (h_ticket>0)
  {
    // First thing is to now set the order Ticket to work with by our class object 
Método
 Descripción Ejemplos de uso
myhistory.Ticket(ulong ticket) Se utiliza esta función para seleccionar el ticket de la orden cuyas propiedades o detalles queremos obtener.
myhistory.Ticket(h_ticket);
myhistory.Ticket()  Se utiliza esta función para obtener el ticket de orden de una orden.
ulong o_ticket = myhistory.Ticket();
myhistory.TimeSetup() Se utiliza esta función para obtener el momento en el cual ha sido llevada a cabo la orden o ha sido ajustada.
datetime os_time = myhistory.TimeSetup();
myhistory.OrderType() Se utiliza esta función para obtener el tipo de orden (ORDER_TYPE_BUY, etc.)
if (myhistory.OrderType() == ORDER_TYPE_BUY)
{
// This is a buy order
}
myhistory.State() Se utiliza esta función para obtener el estado actual de la orden.
Si la orden ha sido cancelada, aceptada, rechazada o colocada, etc.
if(myhistory.State() == ORDER_STATE_REJECTED)
{
// order was rejected, not placed.
}
myhistory.TimeDone() Se utiliza esta función para obtener el momento de colocación, cancelación o rechazo de la orden.
datetime ot_done =  myhistory.TimeDone();
myhistory.Magic() Se utiliza esta función para obtener el Id del Asesor Experto que ha iniciado la orden.
long o_magic = myhistory.Magic();
myhistory.PositionId() Se utiliza esta función para obtener el Id de la posición en la cual se ha incluido la orden al colocarla.
long o_posid = myhistory.PositionId();
myhistory.PriceOpen() Se utiliza esta función para obtener el precio de apertura de la orden.
double o_price =  myhistory.PriceOpen();
myhistory.Symbol() Se utiliza esta función para obtener la propiedad del símbolo (par de divisas) de la orden.
string o_symbol =  myhistory.Symbol();

      

No hay que olvidar que hemos utilizado estas funciones dentro del bucle del total de órdenes en el historial.

1.4 La clase СOrderInfo

La clase COrderInfo proporciona un fácil acceso a las propiedades de todas las órdenes pendientes. Una vez creado un objeto de esta clase, lo pueden utilizar las funciones miembro públicas de esta clase.

El uso de esta clase es algo parecido al de la clase CHistoryOrderInfo comentada antes.

Vamos a crear un objeto de la clase, que llamaremos myorder.

// The OrderInfo Class object
COrderInfo myorder;

Para poder utilizar esta clase en la obtención de los detalles de una orden pendiente, antes que nada, tenemos que obtener todas de las órdenes disponibles y luego seleccionarlas mediante el ticket de orden.

// Select all history orders within a time period
if (HistorySelect(0,TimeCurrent()))   // get all history orders
   {    
     // get total orders
     int o_total = OrdersTotal();

Recorremos todas las órdenes mediante un bucle y obtenemos sus correspondientes propiedades mediante el objeto que hemos creado.

for (int j=0; j<o_total; j++)
{
 // we must confirm if the order is available for us to get its details using the Select function of the COrderInfo Class
Método
Descripción
Ejemplos de uso
myorder.Select(ulong ticket)  Se utiliza esta función para seleccionar una orden mediante el número de ticket, de modo que se pueda manejar la orden fácilmente.
if (myorder.Select(OrderGetTicket(j)) 
   { // order has been selected and can now be manipulated.
   }
myorder.Ticket()  Se utiliza esta función para obtener el ticket de orden de la orden seleccionada.
ulong o_ticket = myorder.Ticket();
myorder.TimeSetup() Se utiliza esta función para obtener el momento en el cual se ha configurado la orden.
datetime o_setup = myorder.TimeSetup();
myorder.Type() Se utiliza esta función para obtener el tipo de orden, como ORDER_TYPE_BUY_STOP, etc.
if (myorder.Type() == ORDER_TYPE_BUY_LIMIT)
{
// This is a Buy Limit order, etc
}
myorder.State() Se utiliza esta función para obtener el estado de la orden.
Si la orden ha sido cancelada, aceptada, rechazada o colocada, etc.
if (myorder.State() ==ORDER_STATE_STARTED)
{
// order has been checked 
// and may soon be treated by the broker
}
myorder.TimeDone() Se utiliza esta función para obtener el momento de colocación, rechazo  o cancelación de la orden.
datetime ot_done = myorder.TimeDone();
myorder.Magic() Se utiliza esta función para obtener el Id del Asesor Experto que ha iniciado la orden.
long o_magic =  myorder.Magic();
myorder.PositionId() Se utiliza esta función para obtener el Id de la posición en la cual se ha incluido la orden al colocarla.
long o_posid = myorder.PositionId();
myorder.PriceOpen() Se utiliza esta función para obtener el precio de apertura de la orden.
double o_price = myorder.PriceOpen();
myorder.StopLoss() Se utiliza esta función para obtener el Stop Loss de la orden.
double  s_loss = myorder.StopLoss();
myorder.TakeProfit() Se utiliza esta función para obtener el Take Profit de la orden.
double t_profit = myorder.TakeProfit();
myorder.PriceCurrent() Se utiliza esta función para obtener el precio actual del símbolo en el cual se ha colocado la orden.
double cur_price =  myorder.PriceCurrent();
myorder.Symbol() Se utiliza esta función para obtener el nombre del símbolo en el cual se ha colocado la orden.
string o_symbol = myorder.Symbol();
myorder.StoreState() Se utiliza esta función para guardar o almacenar el detalle actual de la orden, de modo que podamos comparar si hay algún cambio más adelante.
myorder.StoreState();
myorder.CheckState() Se utiliza esta función para comprobar si el detalle de la orden guardada o almacenada ha cambiado.
if (myorder.CheckState() == true)
{
// Our order status or details have changed
}


1.5 La clase CDealInfo

La clase CDealInfo proporciona el acceso a todo el historial de las propiedades o informaciones de las transacciones.  Una vez hayamos creado un objeto de esta clase, lo usaremos para obtener toda la información acerca de las transacciones en el historial, del mismo modo que en la clase CHistoryOrderInfo.

Así que, lo primero que haremos es crear un objeto de esta clase y llamarlo mydeal.

// The DealInfo Class object
CDealInfo myinfo; 

Comenzaremos con la obtención de las transacciones en el historial.

if (HistorySelect(0,TimeCurrent()))
   {    
    // Get total deals in history
    int tot_deals = HistoryDealsTotal(); 

Vamos a recorrer de forma iterativa el historial disponible de órdenes en su totalidad y obtener los detalles de cada orden del historial mediante el objeto de nuestra clase.

ulong d_ticket; // deal ticket
for (int j=0; j<tot_deals; j++)
    {
     d_ticket = HistoryDealGetTicket(j);
     if (d_ticket>0)  
     {
      // First thing is to now set the deal Ticket to work with by our class object 
Método
Descripción Ejemplos de uso
mydeal.Ticket(ulong ticket) Se utiliza esta función para establecer el ticket de la transacción para su uso posterior por el objeto que hemos creado.
mydeal.Ticket(d_ticket);
mydeal.Ticket()  Se utiliza esta función para obtener el ticket de la transacción.
ulong deal_ticket = mydeal.Ticket();
mydeal.Order() Se utiliza esta función para obtener el ticket de orden correspondiente a la orden en la cual se ha ejecutado la transacción.
long deal_order_no =  mydeal.Order();
mydeal.Time() Se utiliza esta función para obtener el momento de ejecución de la transacción.
datetime d_time = mydeal.Time();
mydeal.Type() Se utiliza esta función para obtener el tipo de transacción, tanto si es DEAL_TYPE_SELL, etc.
if (mydeal.Type() == DEAL_TYPE_BUY)
{
// This deal was executed as a buy deal type
}
mydeal.Entry()  Se utiliza esta función para obtener la dirección de la transacción, tanto si es DEAL_ENTRY_IN o DEAL_ENTRY_OUT, etc.
if (mydeal.Entry() == DEAL_ENTRY_IN)
{
// This was an IN entry deal
}
mydeal.Magic()  Se utiliza esta función para obtener el Id del Asesor Experto que ejecuta la transacción.
long d_magic = mydeal.Magic();
mydeal.PositionId()  Se utiliza esta función para obtener el identificador único de posición correspondiente a la posición de la que forma parte la transacción.
long d_post_id = mydeal.PositionId();
mydeal.Price()  Se utiliza esta función para obtener el precio de ejecución de la transacción.
double d_price = mydeal.Price();
mydeal.Volume()  Se utiliza esta función para obtener el volumen (lote) de la transacción.
double d_vol = mydeal.Volume();
mydeal.Symbol()  Se utiliza esta función para obtener el símbolo (par de divisas) para el cual se ha ejecutado la transacción.
string d_symbol = mydeal.Symbol();


1.6 La clase CPositionInfo

La clase CPositionInfo proporciona un acceso sencillo a las propiedades de la posición actual. Tenemos que crear un objeto de esta clase para poder utilizarlo en la obtención de las propiedades de la posición.

Vamos a crear un objeto de esta clase, que llamaremos myposition.

// The object of the CPositionInfo class
CPositionInfo myposition;

Ahora vamos a utilizar este objeto para obtener los detalles de las posiciones abiertas. Comenzaremos con la obtención de todas de las posiciones abiertas en el historial.

int pos_total = PositionsTotal();

Es el momento de recorrer todas las posiciones abiertas para obtener sus detalles.

for (int j=0; j<pos_total; j++)
    {
Método
 Descripción Ejemplos de uso
myposition.Select(const string symbol) Se utiliza esta función para seleccionar el símbolo correspondiente a la posición abierta actual, para que se pueda operar con él.
if (myposition.Select(PositionGetSymbol(j)))
{
 // symbol successfully selected, we can now work 
 // on the current open position for this symbol 
}
OR
// when dealing with the current symbol/chart only
if (myposition.Select(_Symbol)) 
{
 // symbol successfully selected, we can now work 
 // on the current open position for this symbol 
}

myposition.Time() Se utiliza esta función para obtener el momento de apertura de la posición.
datetime pos_time = myposition.Time();
myposition.Type() Se utiliza esta función para obtener el tipo de posición abierta.
if (myposition.Type() == POSITION_TYPE_BUY)
{
// This is a buy position
}
myposition.Magic() Se utiliza esta función para obtener el Id del Asesor Experto que abre la posición.
long pos_magic = myposition.Magic();
myposition.Volume() Se utiliza esta función para obtener el volumen (lotes) de la posición.
double pos_vol = myposition.Volume(); // Lots
myposition.PriceOpen() Se utiliza esta función para obtener el precio al cual se ha abierto la posición -precio de apertura de la posición.
double pos_op_price = myposition.PriceOpen();
myposition.StopLoss() Se utiliza esta función para obtener el Stop Loss de la posición abierta.
double pos_stoploss = myposition.StopLoss();
myposition.TakeProfit() Se utiliza esta función para obtener el Take Profit de la posición abierta.
double pos_takeprofit = myposition.TakeProfit();
myposition.StoreState() Se utiliza esta función para almacenar el estado actual de la posición.
// stores the current state of the position
myposition.StoreState();
myposition.CheckState() Se utiliza esta función para comprobar si el estado de la posición abierta ha cambiado.
if (!myposition.CheckState())
{
  // position status has not changed yet
}
 myposition.Symbol() Se utiliza esta función para obtener el nombre del símbolo en el cual se ha abierto la posición.
string pos_symbol = myposition.Symbol();


1.7 La clase СTrade

La clase CTrade proporciona un acceso sencillo a las operaciones de trading en MQL5. Para utilizar esta clase, tenemos que crear un objeto de la clase y luego utilizarlo para llevar a cabo las operaciones necesarias de trading.

Vamos a crear un objeto de esta clase, que llamaremos mytrade.

//An object of the CTrade class
CTrade mytrade;

El primer paso es establecer todos los parámetros que va a utilizar el objeto en realizar las operaciones de trading.

 Método Descripción
Ejemplos de uso
mytrade.SetExpertMagicNumber(ulong magic) Se utiliza esta función para establecer el Id del Asesor Experto (número mágico) que va a utilizar la clase en las operaciones de trading.
ulong Magic_No=12345;
mytrade.SetExpertMagicNumber(Magic_No);
mytrade.SetDeviationInPoints(ulong deviation) Esta función también se utiliza para establecer el valor de la desviación (en puntos) a utilizar al colocar una operación de trading.
ulong Deviation=20;
mytrade.SetDeviationInPoints(Deviation); 
mytrade.OrderOpen(conststring symbol,
ENUM_ORDER_TYPE
order_type,double volume,

double
limit_price,double price,doublesl,
double
tp,ENUM_ORDER_TYPE_TIME type_time,

datetime
expiration,const stringcomment="")
Se utiliza esta función para colocar una orden pendiente. Para utilizar esta función, antes que nada, hay que preparar los parámetros y luego pasarlos a esta función.
// define the input parameters
double Lots = 0.1;
double SL = 0;
double TP = 0;
// latest Bid price using CSymbolInfo class object
double Oprice = mysymbol.Bid()-_Point*550;
// place (BuyStop) pending order
mytrade.OrderOpen(_Symbol,ORDER_TYPE_SELLSTOP,Lots,0.0,Oprice,
                  SL,TP,ORDER_TIME_GTC,0);
mytrade.OrderModify(ulong ticket,double price,
double
sl,double tp,
ENUM_ORDER_TYPE_TIME type_time,datetime expiration)
Se utiliza esta función para modificar una orden pendiente existente.
// Select total orders in history and get total pending orders 
// (as shown within the COrderInfo class section). 
// Use the CSymbolInfo class object to get the current ASK/BID price
int Stoploss = 400;
int Takeprofit = 550;
for(int j=0; j<OrdersTotal(); j++)
{
  ulong o_ticket = OrderGetTicket(j);
  if(o_ticket != 0)
  {
   // Stoploss must have been defined
   double SL = mysymbol.Bid() + Stoploss*_Point;   
   // Takeprofit must have been defined  
   double TP = mysymbol.Bid() - Takeprofit*_Point; 
   // lastest ask price using CSymbolInfo class object
   double Oprice = mysymbol.Bid();                 
   // modify pending BuyStop order
   mytrade.OrderModify(o_ticket,Oprice,SL,TP,ORDER_TIME_GTC,0);
  }
}
mytrade.OrderDelete(ulong ticket) Se utiliza esta función para eliminar una orden pendiente.
// Select total orders in history and get total pending orders
// (as shown within the COrderInfo class section). 

int o_total=OrdersTotal();
for(int j=o_total-1; j>=0; j--)
{
   ulong o_ticket = OrderGetTicket(j);
   if(o_ticket != 0)
   {
    // delete the pending Sell Stop order
    mytrade.OrderDelete(o_ticket);
   }
}
mytrade.PositionOpen(const  string symbol,ENUM_ORDER_TYPE order_type,double volume,double price,double sl,double tp,const string comment="") Se utiliza esta función para abrir una posición de COMPRA o VENTA. Para utilizar esta función, antes que nada, hay que preparar todos los parámetros necesarios y luego pasarlos a esta función.
// define the input parameters and use the CSymbolInfo class
// object to get the current ASK/BID price
double Lots = 0.1;
// Stoploss must have been defined 
double SL = mysymbol.Ask() – Stoploss*_Point;   
//Takeprofit must have been defined 
double TP = mysymbol.Ask() + Takeprofit*_Point; 
// latest ask price using CSymbolInfo class object
double Oprice = mysymbol.Ask();
// open a buy trade
mytrade.PositionOpen(_Symbol,ORDER_TYPE_BUY,Lots,
                     Oprice,SL,TP,"Test Buy");
mytrade.PositionModify(const string symbol,
double
sl,double tp)
Se utiliza esta función para modificar el Stop Loss y/o Take Profit de una posición abierta existente. Para utilizar esta función, tenemos primero que seleccionar la posición a modificar mediante el objeto de clase CPostionInfo, se utiliza el objeto de clase CSymbolInfo para obtener el precio de COMPRA/VENTA (BID/ASK) actual.
if (myposition.Select(_Symbol))
{
  int newStoploss = 250;
  int newTakeprofit = 500;
  double SL = mysymbol.Ask() – newStoploss*_Point;    
  double TP = mysymbol.Ask() + newTakeprofit*_Point;  
  //modify the open position for this symbol
 mytrade.PositionModify(_Symbol,SL,TP);
}
mytrade.PositionClose(const string symbol,
ulong
deviation=ULONG_MAX)
Se utiliza esta función para cerrar una orden abierta existente.
if (myposition.Select(_Symbol))
{
 //close the open position for this symbol
 mytrade.PositionClose(_Symbol);  
}

mytrade.Buy(double volume,const string symbol=NULL,double price=0.0,double sl=0.0,doubletp=0.0,const string comment="")   Se utiliza esta función para abrir una operación de trading de Compra. Se recomienda establecer el volumen (o lotes) para operar al utilizar esta función. Mientras se puedan establecer tp (Take Profit) y sl (Stop Loss) posteriormente, modificando la posición abierta, utiliza el precio de Venta (Ask) actual para abrir la operación de trading.
double Lots = 0.1;
// Stoploss must have been defined 
double SL = mysymbol.Ask() – Stoploss*_Point; 
//Takeprofit must have been defined
double TP = mysymbol.Ask() +Takeprofit*_Point;
// latest ask price using CSymbolInfo class object
double Oprice = mysymbol.Ask();
// open a buy trade
mytrade.Buy(Lots,NULL,Oprice,SL,TP,“Buy Trade”);

//OR
mytrade.Buy(Lots,NULL,0.0,0.0,0.0,“Buy Trade”);
// modify position later
mytrade.Sell(double volume,const string symbol=NULL,double price=0.0,double sl=0.0,doubletp=0.0,const string comment="") Se utiliza esta función para abrir una operación de trading de Venta. Se recomienda establecer el volumen (o lotes) del trading al utilizar esta función. Mientras se puedan establecer tp (Take Profit) y sl (Stop Loss) posteriormente modificando la posición abierta, usa el precio de Compra (Bid) actual para abrir la operación de trading. 
double Lots = 0.1;
// Stoploss must have been defined 
double SL = mysymbol.Bid() + Stoploss*_Point;
//Takeprofit must have been defined
double TP = mysymbol.Bid() - Takeprofit*_Point; 
// latest bid price using CSymbolInfo class object
double Oprice = mysymbol.Bid();
// open a Sell trade
mytrade.Sell(Lots,NULL,Oprice,SL,TP,“Sell Trade”); 

//OR
mytrade.Sell(Lots,NULL,0.0,0.0,0.0,“Sell Trade”); 
//(modify position later)
mytrade.BuyStop(double volume,double price,const string symbol=NULL,double sl=0.0,double tp=0.0,
ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,datetime expiration=0,const string comment="")
 Se utiliza esta función para colocar una orden pendiente BuyStop. El tiempo tipo de la orden por defecto es ORDER_TIME_GTC, y el tiempo de vencimiento es 0. No hace falta indicar estas dos variables si tiene en mente el mismo tiempo de tipo de orden.
 double Lot = 0.1;
//Buy price = bar 1 High + 2 pip + spread
 int sprd=mysymbol.Spread();
 double bprice =mrate[1].high + 2*_Point + sprd*_Point;
//--- Buy price
 double mprice=NormalizeDouble(bprice,_Digits); 
//--- Stop Loss
 double stloss = NormalizeDouble(bprice - STP*_Point,_Digits);
//--- Take Profit
 double tprofit = NormalizeDouble(bprice+ TKP*_Point,_Digits);
//--- open BuyStop order
 mytrade.BuyStop(Lot,mprice,_Symbol,stloss,tprofit); 
mytrade.SellStop(double volume,double price,const string symbol=NULL,double sl=0.0,double tp=0.0, ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,datetime expiration=0,const string  comment="") Se utiliza esta función para colocar una orden pendiente SellStop con los parámetros establecidos. El tiempo tipo de la orden por defecto es ORDER_TIME_GTC, y el tiempo de vencimiento es 0. No hace falta indicar estas dos variables si tiene en mente el mismo tiempo de tipo de orden. 
 double Lot = 0.1;
//--- Sell price = bar 1 Low - 2 pip 
//--- MqlRates mrate already declared
 double sprice=mrate[1].low-2*_Point;
//--- SellStop price
 double slprice=NormalizeDouble(sprice,_Digits);
//--- Stop Loss
 double ssloss=NormalizeDouble(sprice+STP*_Point,_Digits);
//--- Take Profit
 double stprofit=NormalizeDouble(sprice-TKP*_Point,_Digits);
//--- Open SellStop Order
 mytrade.SellStop(Lot,slprice,_Symbol,ssloss,stprofit);

mytrade.BuyLimit(double volume,double price,const string symbol=NULL,double sl=0.0,double tp=0.0, ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,datetime expiration=0,const string  comment="") Se utiliza esta función para colocar una orden pendiente BuyLimit con los parámetros establecidos. 
Uso:
//--- Buy price = bar 1 Open  - 5 pip + spread
double Lot = 0.1;
int sprd=mysymbol.Spread();
//--- symbol spread
double bprice = mrate[1].open - 5*_Point + sprd*_Point;
//--- MqlRates mrate already declared
double mprice=NormalizeDouble(bprice,_Digits);
//--- BuyLimit price
//--- place buyLimit order, modify stoploss and takeprofit later
mytrade.BuyLimit(Lot,mprice,_Symbol); 
mytrade.SellLimit (double volume,double price,const string symbol=NULL,double sl=0.0,double tp=0.0, ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,datetime expiration=0,const string comment="") Se utiliza esta función para colocar una orden Sell Limit con los parámetros establecidos. 
//--- Sell Limit price = bar 1 Open  + 5 pip
double Lot = 0.1;
//--- MqlRates mrate already declared
double sprice = mrate[1].open + 5*_Point;
//--- SellLimit
double slprice=NormalizeDouble(sprice,_Digits);
//place SellLimit order, modify stoploss and takeprofit later
mytrade.SellLimit(Lot,slprice,_Symbol);

   FUNCIONES DE RESULTADOS DEL TRADING

   
mytrade.ResultRetcode() Se utiliza esta función para obtener el código del resultado de una operación de trading.
// a trade operation has just been carried out
int return_code = mytrade.ResultRetcode();
mytrade.ResultRetcodeDescription() Se utiliza esta función para obtener una descripción o interpretación completa del código devuelto de una operación de trading.
string ret_message =  ResultRetcodeDescription();
// display it
Alert("Error code - " , mytrade.ResultRetcode() ,
      "Error message - ", ret_message);
mytrade.ResultDeal() Se utiliza esta función para obtener el ticket de la transacción de la posición abierta.
long dl_ticket = mytrade.ResultDeal();
mytrade.ResultOrder() Se utiliza esta función para obtener el ticket de orden de la posición abierta.
long o_ticket = mytrade.ResultOrder();
mytrade.ResultVolume() Se utiliza esta función para obtener el volumen (lotes) de la orden para la posición abierta.
double o_volume = mytrade.ResultVolume();
mytrade.ResultPrice() Se utiliza esta función para obtener el precio de la transacción de la posición abierta.
double r_price = mytrade.ResultPrice();
mytrade.ResultBid() Se utiliza esta función para obtener el precio de COMPRA (BID) actual del mercado (precio cotizado de nuevo).
double rq_bid = mytrade.ResultBid;
mytrade.ResultAsk() Se utiliza esta función para obtener el precio de VENTA (ASK) actual del mercado (precio cotizado de nuevo).
double rq_ask = mytrade.ResultAsk;
mytrade.PrintRequest() / mytrade.PrintResult()  Se pueden utilizar estas dos funciones para mostrar en la pestaña del Diario (Journal), los parámetros de petición de trading y los parámetros resultantes respectivamente.
// after a trade operation
// prints the trade request parameters
mytrade.PrintRequest(); 
//prints the trade results
mytrade.PrintResult();  

 FUNCIONES DE PETICIONES DE TRADING

   
 mytrade.RequestAction() Se utiliza esta función para obtener el tipo de operación de trading para la última petición de trading enviada.
//determine the Trade operation type for the last Trade request
if (mytrade.RequestAction() == TRADE_ACTION_DEAL)
{
  // this is a market order for an immediate execution
}
else if (mytrade.RequestAction() == TRADE_ACTION_PENDING)
{
  // this is a pending order.
}  
 mytrade.RequestMagic() Se utiliza esta función para obtener el número mágico del Asesor Experto utilizado en la última petición.
ulong mag_no = mytrade. RequestMagic();
 mytrade.RequestOrder()
 Se utiliza esta función para obtener el ticket de la orden utilizada en la última petición. Esto se refiere principalmente a la modificación de las órdenes pendientes.
ulong po_ticket =  mytrade.RequestOrder();
mytrade.RequestSymbol() Se utiliza esta función para obtener el símbolo o par de divisas utilizado en la última petición.
string symb = mytrade.RequestSymbol(); 
mytrade.RequestVolume() Se utiliza esta función para obtener el volumen de la operación de trading utilizado en la última petición. 
double Lot = mytrade.RequestVolume();  
mytrade.RequestPrice() Se utiliza esta función para obtener el precio de la orden utilizada en la última petición.
double oprice = mytrade.RequestPrice();   
mytrade.RequestStopLimit() Se utiliza esta función para obtener el precio del Stop Loss utilizado  en la última petición.
double limitprice = mytrade.RequestStopLimit(); 
mytrade.RequestSL() Se utiliza esta función para obtener el precio del Stop Loss utilizado  en la última petición.
double sloss = mytrade.RequestSL();  
mytrade.RequestTP() Se utiliza esta función para obtener el precio del Take Profit utilizado en la última petición.
double tprofit = mytrade.RequestTP();   
mytrade.RequestDeviation() Se utiliza esta función para obtener la desviación utilizada en la última petición.
ulong dev = mytrade.RequestDeviation();  
mytrade.RequestType() Se utiliza esta función para obtener el tipo de orden utilizado en la última petición.
if (mytrade.RequestType() == ORDER_TYPE_BUY)
 {
  // market order Buy was placed in the last request.
mytrade.RequestTypeDescription() Se utiliza esta función para obtener la descripción del tipo de orden utilizado en la última petición.
Print("The type of order placed in the last request is :",
      mytrade.RequestTypeDescription());  
mytrade.RequestActionDescription() Se utiliza esta función para obtener la descripción de la operación solicitada utilizada en la última petición.
Print("The request action used in the last request is :", 
      mytrade.RequestTypeDescription());
mytrade.RequestTypeFillingDescription() Se utiliza esta función para obtener la descripción de la política de toma de órdenes utilizada en la última petición.
Print("The type of order filling policy used",
      " in the last request is :",
      RequestTypeFillingDescription()); 
 

Las funciones de petición (Request) de la clase de trading son muy útiles durante la identificación de errores relacionados con la colocación de órdenes. Hay momentos en los que recibimos mensajes de error al colocar una orden y se crea un poco de confusión al no poder identificar inmediatamente lo que hicimos mal. Mediante las funciones de petición de la clase de trading, seremos capaces de identificar lo que hicimos mal mostrando algunos parámetros de la petición que hemos enviado al servidor. Un ejemplo de dicho uso es similar al código que se muestra a continuación:

 //--- open Buy position and check the result
         if(mytrade.Buy(Lot,_Symbol,mprice,stloss,tprofit))
         //if(mytrade.PositionOpen(_Symbol,ORDER_TYPE_BUY,Lot,mprice,stloss,tprofit)) 
           { //--- Request is completed or order placed           
             Alert("A Buy order at price:", mytrade.ResultPrice() , ", vol:",mytrade.ResultVolume(),
                  " has been successfully placed with deal Ticket#:",mytrade.ResultDeal(),"!!");
            mytrade.PrintResult();
           }
         else
           {
            Alert("The Buy order request at vol:",mytrade.RequestVolume(), ", sl:", mytrade.RequestSL(),
                 ", tp:",mytrade.RequestTP(), ", price:", mytrade.RequestPrice(),
                 " could not be completed -error:",mytrade.ResultRetcodeDescription());
            mytrade.PrintRequest();
            return;
           }

En el ejemplo anterior, hemos tratado de identificar alguno de los parámetros enviados en nuestra petición en el caso de error. Por ejemplo, si no indicamos el precio de Stop Loss correcto, es posible que tengamos un error de topes (Stops) y al mostrar los valores de Stop Loss, mediante mytrade.RequestSL() seremos capaces de saber cuál es el problema con nuestro precio indicado de Stop Loss.

Después de haber dedicado el tiempo necesario para mostrar cómo se puede utilizar cada una de las clases, es el momento ahora de poner en práctica algunas de las características que hemos visto.

Tenga en cuenta que todas la funciones que vamos a utilizar en el Asesor Experto ya se han descrito antes, sería una buena idea consultar las descripciones al ver alguna de las funciones en los códigos que vamos a escribir. 


2. El uso de las funciones de las clases de trading

Con el fin de mostrar cómo se utilizan estas funciones de las clases de operaciones de trading (Trade), vamos a escribir un Asesor Experto que va a llevar a cabo las siguientes tareas.

2.1 Escribir el Asesor Experto

Para empezar, tiene que iniciar un nuevo documento MQL5, seleccionando Asesor Experto (template) y haciendo clic en el botón Siguiente (Next)::

 Empezar un nuevo documento MQL5


Figura 1. Crear un nuevo documento MQL5

Introduzca el nombre del Asesor Experto y haga clic en el botón Finalizar (Finish). Más adelante, vamos a definir los parámetros de entrada manualmente.

Proporcionar un nombre al nuevo documento

Figura 2. Poner un nombre al Asesor Experto

El nuevo documento creado tendrá un código parecido al siguiente.

Esqueleto del código del Expert Advisor

Justo después de la línea de versión de la #property, incluiremos todas las clases de trading que vamos a utilizar.

//+------------------------------------------------------------------+
//|  Include ALL classes that will be used                           |
//+------------------------------------------------------------------+
//--- The Trade Class
#include <Trade\Trade.mqh>
//--- The PositionInfo Class
#include <Trade\PositionInfo.mqh>
//--- The AccountInfo Class
#include <Trade\AccountInfo.mqh>
//--- The SymbolInfo Class
#include <Trade\SymbolInfo.mqh>

A continuación, vamos a definir nuestros parámetros de entrada:

//+------------------------------------------------------------------+
//|  INPUT PARAMETERS                                                |
//+------------------------------------------------------------------+
input int      StopLoss=100;     // Stop Loss
input int      TakeProfit=240;   // Take Profit
input int      ADX_Period=15;    // ADX Period
input int      MA_Period=15;     // Moving Average Period
input ulong    EA_Magic=99977;   // EA Magic Number
input double   Adx_Min=24.0;     // Minimum ADX Value
input double   Lot=0.1;          // Lots to Trade
input ulong    dev=100;          // Deviation 
input long     Trail_point=32;   // Points to increase TP/SL
input int      Min_Bars = 20;    // Minimum bars required for Expert Advisor to trade
input double   TradePct = 25;    // Percentage of Account Free Margin to trade

También vamos a indicar otros parámetros que se van a utilizar en el código de este Asesor Experto:

//+------------------------------------------------------------------+
//|  OTHER USEFUL PARAMETERS                                         |
//+------------------------------------------------------------------+
int adxHandle;                     // handle for our ADX indicator
int maHandle;                    // handle for our Moving Average indicator
double plsDI[],minDI[],adxVal[]; // Dynamic arrays to hold the values of +DI, -DI and ADX values for each bars
double maVal[];                  // Dynamic array to hold the values of Moving Average for each bars
double p_close;                    // Variable to store the close value of a bar
int STP, TKP;                   // To be used for Stop Loss, Take Profit 
double TPC;                        // To be used for Trade percent

Vamos a crear ahora un objeto para cada clase que hemos incluido:

//+------------------------------------------------------------------+
//|  CREATE CLASS OBJECTS                                            |
//+------------------------------------------------------------------+
//--- The Trade Class Object
CTrade mytrade;
//--- The PositionInfo Class Object
CPositionInfo myposition;
//--- The AccountInfo Class Object
CAccountInfo myaccount;
//--- The SymbolInfo Class Object
CSymbolInfo mysymbol;

Lo siguiente que queremos hacer ahora es definir algunas funciones que nos van a facilitar nuestro trabajo.

Una vez definimos estas funciones, solo las llamaremos en la sección correspondiente de las funciones OnInit() y OnTick().

2.1.1 La función checkTrading

Se utilizará esta función para realizar todas las comprobaciones iniciales con el fin de comprobar si nuestro Asesor Experto puede operar o no. Si esta función devuelve true, nuestro Asesor Experto puede continuar, de lo contrario el Asesor Experto no puede realizar ninguna operación de trading.

//+------------------------------------------------------------------+
//|  Checks if our Expert Advisor can go ahead and perform trading   |
//+------------------------------------------------------------------+
bool checkTrading()
{
  bool can_trade = false;
  // check if terminal is syncronized with server, etc
  if (myaccount.TradeAllowed() && myaccount.TradeExpert() && mysymbol.IsSynchronized())
  {
    // do we have enough bars?
    int mbars = Bars(_Symbol,_Period);
    if(mbars >Min_Bars)
    {
      can_trade = true;
    }
  }
  return(can_trade);
}

Declaramos un tipo de datos bool can_trade y le asignamos false. Usamos el objeto de la clase CAccountInfo para comprobar si la operación está permitida y también si los Asesores Expertos tienen permiso para operar en esta cuenta. También utilizamos un objeto de la clase CSymbolInfo para comprobar si el terminal está sincronizado con el servidor de trading.

Una vez satisfechas estas tres condiciones, comprobamos entonces si la cantidad total de las barras actuales supera la cantidad mínima de barras que necesita nuestro Asesor Experto para operar. Si esta función devuelve true, entonces nuestro Asesor Experto llevará a cabo las actividades de trading, de lo contrario, nuestro Asesor Experto no realizará ninguna actividad de trading hasta que no estén satisfechas las condiciones en esta función.

Como ha podido ver, hemos decidido incluir todos los procedimientos de comprobación de operaciones de trading en esta función, mediante los objetos necesarios de las librerías estándar de las clases de trading.

2.1.2 La función ConfirmMargin

//+------------------------------------------------------------------+
//|  Confirms if margin is enough to open an order                   |
//+------------------------------------------------------------------+
bool ConfirmMargin(ENUM_ORDER_TYPE otype,double price)
  {
   bool confirm = false;
   double lot_price = myaccount.MarginCheck(_Symbol,otype,Lot,price); // Lot price/ Margin    
   double act_f_mag = myaccount.FreeMargin();                        // Account free margin 
   // Check if margin required is okay based on setting
   if(MathFloor(act_f_mag*TPC)>MathFloor(lot_price))
     {
      confirm =true;
     }
    return(confirm);
  }

Utilizamos el objeto de la clase CAccountInfo para confirmar si hay suficiente margen para colocar una operación de trading en base a la utilización de un cierto porcentaje del margen libre de nuestra cuenta para colocar una orden.

Si el porcentaje requerido del margen libre de la cuenta es superior al margen requerido para la orden, entonces esta función devuelve true, de lo contrario, devuelve false.  De este modo, solo queremos colocar una orden si la función devuelve true. Esta función toma como parámetro de entrada al tipo de orden.

2.1.3 La función checkBuy

//+------------------------------------------------------------------+
//|  Checks for a Buy trade Condition                                |
//+------------------------------------------------------------------+
bool checkBuy()
{
  bool dobuy = false;
  if ((maVal[0]>maVal[1]) && (maVal[1]>maVal[2]) &&(p_close > maVal[1]))
  {
    // MA increases upwards and previous price closed above MA
    if ((adxVal[1]>Adx_Min)&& (plsDI[1]>minDI[1]))
    {
      // ADX is greater than minimum and +DI is greater tha -DI for ADX
      dobuy = true;
    }
  }
  return(dobuy);
}

Hemos decidido crear las condiciones para la apertura de una operación de compra en esta función. En este caso, no hemos utilizado ninguna de las funciones de los objetos de la clase. Estamos comprobando la condición en la cual aumentan los valores del indicador de promedio móvil, y el precio de cierre de la barra anterior es superior al valor del promedio móvil en este punto.

También queremos la situación en la cual el valor del indicador ADX sea superior al mínimo requerido establecido en los parámetros, y el valor positivo de DI del indicador ADX sea superior al valor negativo de DI. Una vez cumplidas estas condiciones, dejaremos que nuestro Asesor Experto abra una orden de COMPRA (BUY).

2.1.4 La función checkSell

//+------------------------------------------------------------------+
//|  Checks for a Sell trade Condition                               |
//+------------------------------------------------------------------+
bool checkSell()
{
  bool dosell = false;
  if ((maVal[0]<maVal[1]) && (maVal[1]<maVal[2]) &&(p_close < maVal[1]))
  {
    // MA decreases downwards and previuos price closed below MA
    if ((adxVal[1]>Adx_Min)&& (minDI[1]>plsDI[1]))
    {
      // ADX is greater than minimum and -DI is greater tha +DI for ADX
      dosell = true;
    }
  }
  return(dosell);
} 

Esta función hace las comprobaciones de manera exactamente opuesta a la función CheckBuy. En esta función, tampoco hemos utilizado ningún objeto de la clase. Esta función comprueba la condición en la cual decrecen los valores del indicador de promedio móvil, y el precio de cierre de la barra anterior es inferior al valor del promedio móvil en este punto.

También queremos la situación en la cual el valor del indicador ADX sea superior al mínimo requerido establecido en los parámetros, y el valor negativo de DI del indicador ADX sea superior al valor positivo de DI. Una vez cumplidas estas condiciones, dejaremos nuestro Asesor Experto abrir una orden de VENTA (SELL).

2.1.5 La función checkClosePos
//+------------------------------------------------------------------+
//|  Checks if an Open position can be closed                        |
//+------------------------------------------------------------------+
bool checkClosePos(string ptype, double Closeprice)
{
   bool mark = false;
   if (ptype=="BUY")
   {
      // Can we close this position
     if (Closeprice < maVal[1]) // Previous price close below MA
      {
         mark = true;
      }
   }
   if (ptype=="SELL")
   {
      // Can we close this position
      if (Closeprice > maVal[1]) // Previous price close above MA
      {
         mark = true;
      }
   }
   return(mark);
}

Se utiliza esta función para comprobar si se puede cerrar la posición abierta actual. Se utiliza esta función para comprobar si el precio de cierre de la barra anterior es superior o inferior al valor del indicador de promedio móvil en este punto (según la dirección de la operación de trading).

Si se cumple cualquiera de las condiciones, esta función devuelve true y entonces es de esperar que nuestro Asesor Experto cierre la posición. Esta función tiene dos parámetros de entrada, el tipo de orden (esta vez el nombre -BUY o SELL) y el precio de cierre de la barra anterior.

2.1.6 La función ClosePosition

//+------------------------------------------------------------------+
//| Checks and closes an open position                               |
//+------------------------------------------------------------------+
bool ClosePosition(string ptype,double clp)
  {
   bool marker=false;
     
      if(myposition.Select(_Symbol)==true)
        {
         if(myposition.Magic()==EA_Magic && myposition.Symbol()==_Symbol)
           {
            //--- Check if we can close this position
            if(checkClosePos(ptype,clp)==true)
              {
               //--- close this position and check if we close position successfully?
               if(mytrade.PositionClose(_Symbol)) //--- Request successfully completed 
                 {
                  Alert("An opened position has been successfully closed!!");
                  marker=true;
                 }
               else
                 {
                  Alert("The position close request could not be completed - error: ",
                       mytrade.ResultRetcodeDescription());
                 }
              }
           }
        }
      return(marker);
     }

Esta es la función que utiliza en realidad la función de antes (checkclosepos). Utiliza los objetos de las clases CPositionInfo y CTrade. Esta función utiliza el objeto de la clase CPositionInfo para comprobar las posiciones abiertas disponibles para la posición abierta por nuestro Asesor Experto y para el símbolo actual. Si no se encuentra ninguna posición, comprueba si se puede cerrar mediante la función checkclosepos.

Si la función checkclosepos devuelve true, entonces utilizará el objeto de la clase CTrade para cerrar la posición y mostrar los resultados de la operación de cierre de la posición. Si la posición se cierra con éxito, esta función devuelve true, de lo contrario, devuelve false.

La función toma dos parámetros de entrada (el nombre de la posición, BUY o SELL y el precio de cierre de la barra anterior). En realidad, se envían estos parámetros a la función checkclosepos y que los va a utilizar.

2.1.7 La función CheckModify

//+------------------------------------------------------------------+
//|  Checks if we can modify an open position                        |
//+------------------------------------------------------------------+
bool CheckModify(string otype,double cprc)
{
   bool check=false;
   if (otype=="BUY")
   {
      if ((maVal[2]<maVal[1]) && (maVal[1]<maVal[0]) && (cprc>maVal[1]) && (adxVal[1]>Adx_Min))
      {
         check=true;
      }
   }
   else if (otype=="SELL")
   {
      if ((maVal[2]>maVal[1]) && (maVal[1]>maVal[0]) && (cprc<maVal[1]) && (adxVal[1]>Adx_Min))
      {
         check=true;
      }
   }
   return(check);
} 

Se utiliza esta función para comprobar la condición que confirma si se puede modificar una posición abierta o no. Utiliza el nombre del tipo de orden y el precio de cierre de la barra anterior como parámetros de entrada.

Lo que hace esta función es comprobar si el promedio móvil sigue creciendo y el precio de cierre de la barra anterior sigue siendo superior al valor del promedio móvil en este punto, y además, que el valor de ADX es superior al mínimo requerido (para una posición de COMPRA), mientras comprueba si el promedio móvil sigue decreciendo y el precio de cierre de la barra anterior es inferior al valor del promedio móvil en este punto (para una posición de VENTA). De acuerdo del tipo de posición que tenemos, si se cumple cualquiera de las condiciones, el Asesor Experto considerará modificar la posición.

La función toma dos parámetros de entrada (el nombre de la posición, BUY o SELL y el precio de cierre de la barra anterior).

2.1.8 La función Modify

//+------------------------------------------------------------------+
//| Modifies an open position                                        |
//+------------------------------------------------------------------+
   void Modify(string ptype,double stpl,double tkpf)
     {
       //--- New Stop Loss, new Take profit, Bid price, Ask Price
      double ntp,nsl,pbid,pask;                  
      long tsp=Trail_point;
       //--- adjust for 5 & 3 digit prices
      if(_Digits==5 || _Digits==3) tsp=tsp*10;   
       //--- Stops Level
      long stplevel= mysymbol.StopsLevel();      
       //--- Trail point must not be less than stops level
      if(tsp<stplevel) tsp=stplevel;
      if(ptype=="BUY")
        {
          //--- current bid price
         pbid=mysymbol.Bid();           
         if(tkpf-pbid<=stplevel*_Point)
           {
            //--- distance to takeprofit less or equal to Stops level? increase takeprofit
            ntp = pbid + tsp*_Point;
            nsl = pbid - tsp*_Point;
           }
         else
           {
            //--- distance to takeprofit higher than Stops level? dont touch takeprofit
            ntp = tkpf;
            nsl = pbid - tsp*_Point;
           }
        }
      else //--- this is SELL
        {
          //--- current ask price
         pask=mysymbol.Ask();            
         if(pask-tkpf<=stplevel*_Point)
           {
            ntp = pask - tsp*_Point;
            nsl = pask + tsp*_Point;
           }
         else
           {
            ntp = tkpf;
            nsl = pask + tsp*_Point;
           }
        }
      //--- modify and check result
      if(mytrade.PositionModify(_Symbol,nsl,ntp))  
        {
          //--- Request successfully completed    
         Alert("An opened position has been successfully modified!!");
         return;
        }
      else
        {
         Alert("The position modify request could not be completed - error: ",
               mytrade.ResultRetcodeDescription());
         return;
        }

     }

 Esta función utiliza la función anterior (checkmodify) para realizar su trabajo. Utiliza los objetos de las clases CSymbolInfo CTrade. En primer lugar, hemos declarado cuatro datos de tipo double para guardar los nuevos Take Profit, Stop Loss, precio de compra y precio de venta. Y luego hemos declarado un nuevo dato tsp de tipo long para guardar el valor de Trail_point definido en las sección de los parámetros de entrada.

Se configura el valor de trail point (tsp) para precios de 3 y 5 dígitos. Después hemos utilizado el objeto CSymbolInfo para obtener el nivel de stops (stops level) y asegurarnos de que el trail point que queremos añadir nos es inferior al nivel de stops requerido. Si es inferior a nivel de stops, entonces usaremos el valor del nivel de stops

En función del tipo de posición, usaremos el objeto de clase CSymbolInfo para obtener el precio de COMPRA (BID) o VENTA (ASK) actual correspondiente. Si la diferencia ente el precio actual de BID o ASK y el precio Take Profit inicial es inferior o igual al nivel de stops, decidimos ajustar tanto los precios de Stop Loss como de Take Profit, de lo contrario, solo ajustamos el valor de Stop Loss.

A continuación, utilizamos el objeto de clase CTrade para modificar el Stop Loss y el Take Profit de la posición. En base al código de la operación de trading devuelto, se muestra un mensaje de éxito o de fallo.

Hemos acabado con las definiciones de algunas funciones definidas por el usuario y nos van a facilitar nuestro trabajo. Vamos a pasar ahora a la sección de los códigos de Asesor Experto.

2.1.9 La sección OnInit

 ",GetLastError(),"!!");
      return(1);
     }
   STP = StopLoss;
   TKP = TakeProfit;
//--- Let us handle brokers that offers 5 or 3 digit prices instead of 4
   if(_Digits==5 || _Digits==3)
     {
      STP = STP*10;
      TKP = TKP*10;
     }
   
//--- Set trade percent
    TPC = TradePct;
    TPC = TPC/100;
//---

Hemos decidido establecido el símbolo actual con el objeto de clase CSymbolInfo. También hemos establecido el número mágico del Asesor Experto y la desviación (en puntos) mediante el objeto de clase CTrade. Después de esto, decidimos obtener los identificadores para nuestros indicadores y mostrar un error si un fallo en la obtención de los identificadores.

A continuación, decidimos ajustar el Stop Loss y el Take Profit para los precios de 3 y 5 dígitos y además, hemos realizado la conversión del porcentaje del margen libre de la cuenta para utilizarlo en porcentaje para operar.

2.1.10 La sección OnDeinit

//--- Release our indicator handles
   IndicatorRelease(adxHandle);
   IndicatorRelease(maHandle);

En este punto, hemos decidido liberar todos los identificadores de los indicadores.

2.1.11 La sección OnTick

//--- check if EA can trade
    if (checkTrading() == false) 
   {
      Alert("EA cannot trade because certain trade requirements are not meant");
      return;
   }
//--- Define the MQL5 MqlRates Structure we will use for our trade
   MqlRates mrate[];          // To be used to store the prices, volumes and spread of each bar
/*
     Let's make sure our arrays values for the Rates, ADX Values and MA values 
     is store serially similar to the timeseries array
*/
// the rates arrays
   ArraySetAsSeries(mrate,true);
// the ADX values arrays
   ArraySetAsSeries(adxVal,true);
// the MA values arrays
   ArraySetAsSeries(maVal,true);
// the minDI values array
   ArraySetAsSeries(minDI,true);
// the plsDI values array
   ArraySetAsSeries(plsDI,true);

Lo primero que hacemos aquí es comprobar y asegurarnos si nuestro Asesor Experto puede operar o no. Si la función checktrade devuelve false, Asesor Experto esperará hasta el siguiente tick y hará la comprobación de nuevo.

A continuación, declaramos una estructura MQL5 MqlRates para obtener los precios de cada barra y cuando usamos la función ArraySetAsSeries para establecer las matrices necesarias.

//--- Get the last price quote using the SymbolInfo class object function
   if (!mysymbol.RefreshRates())
     {
      Alert("Error getting the latest price quote - error:",GetLastError(),"!!");
      return;
     }

//--- Get the details of the latest 3 bars
   if(CopyRates(_Symbol,_Period,0,3,mrate)<0)
     {
      Alert("Error copying rates/history data - error:",GetLastError(),"!!");
      return;
     }

//--- EA should only check for new trade if we have a new bar
// lets declare a static datetime variable
   static datetime Prev_time;
// lest get the start time for the current bar (Bar 0)
   datetime Bar_time[1];
   //copy the current bar time
   Bar_time[0] = mrate[0].time;
// We don't have a new bar when both times are the same
   if(Prev_time==Bar_time[0])
     {
      return;
     }
//Save time into static varaiable, 
   Prev_time = Bar_time[0]; 

Utilizamos el objeto de clase CSymbolInfo para obtener el precio actual de cotizaciones y luego copiar el precio de la barra actual a la matriz mrates. Justo después de esto, procedemos a comprobar la presencia de una nueva barra.

Si tenemos una barra nueva, entonces nuestro Asesor Experto procederá a comprobar si se ha cumplido un a condición de COMPRA o VENTA, de lo contrario, esperará hasta que tengamos una nueva barra.

//--- Copy the new values of our indicators to buffers (arrays) using the handle
   if(CopyBuffer(adxHandle,0,0,3,adxVal)<3 || CopyBuffer(adxHandle,1,0,3,plsDI)<3
      || CopyBuffer(adxHandle,2,0,3,minDI)<3)
     {
      Alert("Error copying ADX indicator Buffers - error:",GetLastError(),"!!");
      return;
     }
   if(CopyBuffer(maHandle,0,0,3,maVal)<3)
     {
      Alert("Error copying Moving Average indicator buffer - error:",GetLastError());
      return;
     }
//--- we have no errors, so continue
// Copy the bar close price for the previous bar prior to the current bar, that is Bar 1

   p_close=mrate[1].close;  // bar 1 close price

Aquí, hemos utilizado las funciones CopyBuffer para copiar los buffers de nuestros indicadores en matrices y si ocurre un error en el proceso, se mostrará. El precio de cierre de la barra anterior se ha copiado.

//--- Do we have positions opened already?
  bool Buy_opened = false, Sell_opened=false; 
   if (myposition.Select(_Symbol) ==true)  // we have an opened position
    {
      if (myposition.Type()== POSITION_TYPE_BUY)
       {
            Buy_opened = true;  //It is a Buy
          // Get Position StopLoss and Take Profit
           double buysl = myposition.StopLoss();      // Buy position Stop Loss
           double buytp = myposition.TakeProfit();    // Buy position Take Profit
           // Check if we can close/modify position
           if (ClosePosition("BUY",p_close)==true)
             {
                Buy_opened = false;   // position has been closed
                return; // wait for new bar
             }
           else
           {
              if (CheckModify("BUY",p_close)==true) // We can modify position
              {
                  Modify("BUY",buysl,buytp);
                  return; // wait for new bar
              }
           } 
       }
      else if(myposition.Type() == POSITION_TYPE_SELL)
       {
            Sell_opened = true; // It is a Sell
            // Get Position StopLoss and Take Profit
            double sellsl = myposition.StopLoss();    // Sell position Stop Loss
            double selltp = myposition.TakeProfit();  // Sell position Take Profit
             if (ClosePosition("SELL",p_close)==true)
             {
               Sell_opened = false;  // position has been closed
               return;   // wait for new bar
             }
             else
             {
                 if (CheckModify("SELL",p_close)==true) // We can modify position
                 {
                     Modify("SELL",sellsl,selltp);
                     return;  //wait for new bar
                 }
             } 
       }
    } 

Utilizamos el objeto de clase CPositionInfo para seleccionar y comprobar si tenemos una posición abierta para el símbolo actual.. Si la posición existe, y es una COMPRA, asignamos a Buy_opened el valor true y luego utilizamos el objeto de clase CPositionInfo para obtener el Stop Loss y Take Profit de la posición. Mediante la función definida anteriormente, ClosePosition, hemos comprobado si se puede cerrar la posición. Si la función devuelve true, entonces la posición ha sido cerrada, con lo cual podemos asignar el valor false a Buy_opened, se acaba de cerrar la posición inicial COMPRA. El Asesor Experto no esperará un nuevo tick.

No obstante, si la función devuelve false, entonces la posición no se había cerrado antes. Es el momento ahora de comprobar si podemos modificar la posición. Esto se lleva a cabo mediante la función CheckModify definida anteriormente. Si la función devuelve true, entonces se puede modificar la posición, así que usamos las función Modify para modificar la posición.

Si, por otra parte, existe una posición y es una COMPRA, asignamos el valor true a Sell_opened y utilizamos el objeto de clase CPositionInfo para obtener el Stop Loss y el Take Profit de la posición. Repetimos los mismos pasos que hicimos con la posición COMPRA para poder ver si la posición puede ser cerrada o modificada.

      if(checkBuy()==true)
        {
         //--- any opened Buy position?
         if(Buy_opened)
           {
            Alert("We already have a Buy position!!!");
            return;    //--- Don't open a new Sell Position
           }

         double mprice=NormalizeDouble(mysymbol.Ask(),_Digits);                //--- latest ask price
         double stloss = NormalizeDouble(mysymbol.Ask() - STP*_Point,_Digits); //--- Stop Loss
         double tprofit = NormalizeDouble(mysymbol.Ask()+ TKP*_Point,_Digits); //--- Take Profit
         //--- check margin
         if(ConfirmMargin(ORDER_TYPE_BUY,mprice)==false)
           {
            Alert("You do not have enough money to place this trade based on your setting");
            return;
           }
         //--- open Buy position and check the result
         if(mytrade.Buy(Lot,_Symbol,mprice,stloss,tprofit))
         //if(mytrade.PositionOpen(_Symbol,ORDER_TYPE_BUY,Lot,mprice,stloss,tprofit)) 
           {
               //--- Request is completed or order placed
             Alert("A Buy order has been successfully placed with deal Ticket#:",
                  mytrade.ResultDeal(),"!!");
           }
         else
           {
            Alert("The Buy order request at vol:",mytrade.RequestVolume(), 
                  ", sl:", mytrade.RequestSL(),", tp:",mytrade.RequestTP(),
                  ", price:", mytrade.RequestPrice(), 
                     " could not be completed -error:",mytrade.ResultRetcodeDescription());
            return;
           }
        }

O podemos utilizar la función PositionOpen

      if(checkBuy()==true)
        {
         //--- any opened Buy position?
         if(Buy_opened)
           {
            Alert("We already have a Buy position!!!");
            return;    //--- Don't open a new Sell Position
           }

         double mprice=NormalizeDouble(mysymbol.Ask(),_Digits);               //--- latest Ask price
         double stloss = NormalizeDouble(mysymbol.Ask() - STP*_Point,_Digits); //--- Stop Loss
         double tprofit = NormalizeDouble(mysymbol.Ask()+ TKP*_Point,_Digits); //--- Take Profit
         //--- check margin
         if(ConfirmMargin(ORDER_TYPE_BUY,mprice)==false)
           {
            Alert("You do not have enough money to place this trade based on your setting");
            return;
           }
         //--- open Buy position and check the result
         //if(mytrade.Buy(Lot,_Symbol,mprice,stloss,tprofit))
         if(mytrade.PositionOpen(_Symbol,ORDER_TYPE_BUY,Lot,mprice,stloss,tprofit))
           {
              //--- Request is completed or order placed            
              Alert("A Buy order has been successfully placed with deal Ticket#:",
            mytrade.ResultDeal(),"!!");
           }
         else
           {
            Alert("The Buy order request at vol:",mytrade.RequestVolume(), 
                    ", sl:", mytrade.RequestSL(),", tp:",mytrade.RequestTP(), 
                    ", price:", mytrade.RequestPrice(), 
                    " could not be completed -error:",mytrade.ResultRetcodeDescription());
            return;
           }
        }

Aquí, utilizamos la función checkbuy para comprobar  si la compra está configurada y si devuelve true, entonces se cumplen las condiciones para nuestra operación de COMPRA. Si ya tenemos una posición de COMPRA, no tenemos que colocar una orden nueva. Luego utilizamos el objeto de clase CSymbolInfo para obtener el precio de COMPRA (ASK) y calcular el Stop Loss y el Take Profit según lo requerido. 

También utilizamos la función ConfirmMargin para comprobar si el porcentaje de la cuenta asignado a colocar una orden es superior al margen necesario para colocar esta orden. Si la función devuelve true, seguimos adelante y colocamos la operación de trading, de lo contrario, no lo hacemos

Mediante el objeto de clase CTrade, hemos colocado nuestra orden y utilizado el mismo objeto de llamadas para obtener el código devuelto por la operación de trading. En base al resultado de la operación, se muestra un mensaje.

      if(checkSell()==true)
        {
         //--- any opened Sell position?
         if(Sell_opened)
           {
            Alert("We already have a Sell position!!!");
            return;    //--- Wait for a new bar
           }

         double sprice=NormalizeDouble(mysymbol.Bid(),_Digits);             //--- latest Bid price
         double ssloss=NormalizeDouble(mysymbol.Bid()+STP*_Point,_Digits);   //--- Stop Loss
         double stprofit=NormalizeDouble(mysymbol.Bid()-TKP*_Point,_Digits); //--- Take Profit
         //--- check margin
         if(ConfirmMargin(ORDER_TYPE_SELL,sprice)==false)
           {
            Alert("You do not have enough money to place this trade based on your setting");
            return;
           }
         //--- Open Sell position and check the result
         if(mytrade.Sell(Lot,_Symbol,sprice,ssloss,stprofit))
         //if(mytrade.PositionOpen(_Symbol,ORDER_TYPE_SELL,Lot,sprice,ssloss,stprofit))
           {
               //---Request is completed or order placed            
               Alert("A Sell order has been successfully placed with deal Ticket#:",mytrade.ResultDeal(),"!!");
           }
         else
           {
            Alert("The Sell order request at Vol:",mytrade.RequestVolume(), 
                    ", sl:", mytrade.RequestSL(),", tp:",mytrade.RequestTP(), 
                    ", price:", mytrade.RequestPrice(), 
                    " could not be completed -error:",mytrade.ResultRetcodeDescription());
            return;
           }

        }

O podemos utilizar la función PositionOpen:

      if(checkSell()==true)
        {
         //--- any opened Sell position?
         if(Sell_opened)
           {
            Alert("We already have a Sell position!!!");
            return;    //--- Wait for a new bar
           }

         double sprice=NormalizeDouble(mysymbol.Bid(),_Digits);             //--- latest Bid price
         double ssloss=NormalizeDouble(mysymbol.Bid()+STP*_Point,_Digits);   //--- Stop Loss
         double stprofit=NormalizeDouble(mysymbol.Bid()-TKP*_Point,_Digits); //--- Take Profit
         //--- check margin
         if(ConfirmMargin(ORDER_TYPE_SELL,sprice)==false)
           {
            Alert("You do not have enough money to place this trade based on your setting");
            return;
           }
         //--- Open Sell position and check the result
         if(mytrade.Sell(Lot,_Symbol,sprice,ssloss,stprofit))
         //if(mytrade.PositionOpen(_Symbol,ORDER_TYPE_SELL,Lot,sprice,ssloss,stprofit))
           {
               //---Request is completed or order placed            
               Alert("A Sell order has been successfully placed with deal Ticket#:",mytrade.ResultDeal(),"!!");
           }
         else
           {
            Alert("The Sell order request at Vol:",mytrade.RequestVolume(), 
                    ", sl:", mytrade.RequestSL(),", tp:",mytrade.RequestTP(), 
                    ", price:", mytrade.RequestPrice(), 
                    " could not be completed -error:",mytrade.ResultRetcodeDescription());
            return;
           }

        }

Tal como hicimos para la COMPRA, hemos utilizado la función Checksell para comprobar la configuración de la VENTA. Si devuelve true y no tenemos ninguna posición abierta ya, utilizamos la función ConfirmMargin para comprobar si tenemos bastantes fondos para abrir la orden. Si ConfirmMargin devuelve true, el se utiliza el objeto de clase CTrade para colocar la orden y en base a la respuesta desde el servidor de trading, se muestra el resultado de la operación mediante las funciones del objeto de clase CTrade.

Hasta el momento hemos visto de qué manera podemos utilizar las librerías Trade class en la escritura de un Asesor Experto. El siguiente paso es probar nuestro Asesor Experto con el probador de estrategias y ver su rendimiento.

Compile el código del Asesor Experto y luego cárguelo en el Probador de Estrategias.

Informe de compilación del EA

         Figura 3. Informe de compilación del Asesor Experto 

En el gráfico diario de GBPUSD utilizando la configuración por defecto: Take Profit - 270, Stop Loss - 100 y Trails Point (TP/SL) - 32, tenemos los siguientes resultados:

 

Figura 4. Informe de la prueba del Asesor Experto del gráfico diario de GBPUSD

 

 

Figura 5. Resultado gráfico de la prueba del Asesor Experto del gráfico diario de GBPUSD

                                                                                                                                

Figura 6. Informe de la prueba del Asesor Experto mostrando la modificación de posiciones abiertas del gráfico diario de GBPUSD

 

Figura 7.  Informe gráfico de la prueba del Asesor Experto del gráfico diario de GBPUSD

Puede probar el Asesor Experto con cualquier otro gráfico diaria de símbolo y con distintas configuraciones del Take Profit, Stop Loss y Trail point y ver el resultado obtenido. 

No obstante, debe saber que se ha escrito este Asesor Experto para los propósitos de pruebas solamente.

Vamos a ver ahora de qué manera podemos utilizar las otras clases (COrderInfo, CHistoryOrderInfo, y CDealInfo) para obtener los detalles de la orden/transacción.

2.2 Apertura/Eliminación de una orden pendiente  

En este ejemplo, vamos a escribir un Asesor Experto sencillo que colocar una orden pendiente (BuyStop o SellStop) cuando se cumplen las condiciones de Compra o Venta respectivamente.

2.2.1 Incluir las clases necesarias

//+------------------------------------------------------------------+
//|  Include ALL classes that will be used                           |
//+------------------------------------------------------------------+
//--- The Trade Class
#include <Trade\Trade.mqh>
//--- The PositionInfo Class
#include <Trade\PositionInfo.mqh>
//--- The SymbolInfo Class
#include <Trade\SymbolInfo.mqh>
//--- The OrderInfo Class
#include <Trade\OrderInfo.mqh>

Hemos incluido las cuatro clases que vamos a utilizar con este sencillo Asesor Experto. Ya se han explicado en los ejemplos anteriores.

No voy a explicar todas las partes de este Asesor Experto, ya que es similar al que se ha explicado antes, no obstante, voy a recorrer la parte fundamental del Asesor Experto en la cual se explica lo que queremos comentar en esta sección.

La única diferencia es que hemos decidido declarar mrate[] de MqlRates en un contexto global.

//--- Define the MQL5 MqlRates Structure we will use for our trade
   MqlRates mrate[];     // To be used to store the prices, volumes and spread of each bar

Una vez incluidas las clases, debemos acordarnos de de crear los objetos de cada clase:

//+------------------------------------------------------------------+
//|  CREATE CLASS OBJECTS                                            |
//+------------------------------------------------------------------+
//--- The CTrade Class Object
CTrade mytrade;
//--- The CPositionInfo Class Object
CPositionInfo myposition;
//--- The CSymbolInfo Class Object
CSymbolInfo mysymbol;
//--- The COrderInfo Class Object
COrderInfo myorder;

Las funciones CheckBuy() y CheckSell() son iguales a las del Asesor Experto explicado antes.

Lo que queremos hacer aquí es colocar una orden BUYSTOP cuando tenemos una configuración de compra y una orden SELLSTOP cuando tenemos una configuración de venta.

Vamos a recorrer ahora algunas funciones que hemos creado para facilitarnos las cosas.

2.2.2 La función CountOrders

//+------------------------------------------------------------------+
//|  Count Total Orders for this expert/symbol                       |
//+------------------------------------------------------------------+
int CountOrders()
  {
   int mark=0;

   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      if(myorder.Select(OrderGetTicket(i)))
        {
         if(myorder.Magic()==EA_Magic && myorder.Symbol()==_Symbol) mark++;
        }
     }
   return(mark);
  }

Se utiliza esta función para obtener el total de las órdenes pendientes disponibles en punto en el tiempo.

Hemos utilizado el objeto de nuestra clase COrderInfo para comprobar los detalles de la orden por si se ha seleccionado correctamente con la función myorder.Select().

Si el número mágico devuelto por el objeto de nuestra clase y el símbolo devuelto son lo que queremos, entonces la orden ha sido colocada por nuestro Asesor Experto, por lo que se cuenta y se almacena en la variable mark.

2.2.3 La función DeletePending

//+------------------------------------------------------------------+
//| Checks and Deletes a pending order                               |
//+------------------------------------------------------------------+
bool DeletePending()
  {
   bool marker=false;
//--- check all pending orders
   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      if(myorder.Select(OrderGetTicket(i)))
        {
         if(myorder.Magic()==EA_Magic && myorder.Symbol()==_Symbol)
           {
            //--- check if order has stayed more than two bars time
            if(myorder.TimeSetup()<mrate[2].time)
              {
               //--- delete this pending order and check if we deleted this order successfully?
                if(mytrade.OrderDelete(myorder.Ticket())) //Request successfully completed 
                  {
                    Alert("A pending order with ticket #", myorder.Ticket(), " has been successfully deleted!!");
                    marker=true;
                  }
                 else
                  {
                    Alert("The pending order # ",myorder.Ticket(),
                             " delete request could not be completed - error: ",mytrade.ResultRetcodeDescription());
                  }

              }
           }
        }
     }
   return(marker);
  }

Al igual que la función countorder, esta función también utiliza las funciones de la clase COrderInfo para obtener las propiedades de una orden. La función busca cualquier orden pendiente configurada con tres barras antes (el tiempo de configuración de la orden pendiente es inferior a mrate[2].time) y que no haya sido activada.

Si cualquier orden entra en esta categoría, la función OrderDelete de la clase CTrade se utiliza para eliminar la orden. Esta función devuelve true en caso de éxito y false en el caso opuesto.

Las dos funciones anteriores se utilizan justo después de la formación de una nueva barra, antes de buscar la configuración de una nueva operación de trading. Queremos asegurarnos de que no hay más de tres órdenes pendientes en cada punto en el tiempo.  Para hacer esto usamos el siguiente código:

// do we have more than 3 already placed pending orders
if (CountOrders()>3) 
  {
     DeletePending(); 
     return;  
  }

2.2.4 Colocar una orden pendiente

   if(checkBuy()==true)
     {
      Alert("Total Pending Orders now is :",CountOrders(),"!!");
      //--- any opened Buy position?
      if(Buy_opened)
        {
         Alert("We already have a Buy position!!!");
         return;    //--- Don't open a new Sell Position
        }
      //Buy price = bar 1 High + 2 pip + spread
      int sprd=mysymbol.Spread();
      double bprice =mrate[1].high + 10*_Point + sprd*_Point;
      double mprice=NormalizeDouble(bprice,_Digits);               //--- Buy price
      double stloss = NormalizeDouble(bprice - STP*_Point,_Digits); //--- Stop Loss
      double tprofit = NormalizeDouble(bprice+ TKP*_Point,_Digits); //--- Take Profit
      //--- open BuyStop order
      if(mytrade.BuyStop(Lot,mprice,_Symbol,stloss,tprofit))
      //if(mytrade.OrderOpen(_Symbol,ORDER_TYPE_BUY_STOP,Lot,0.0,bprice,stloss,tprofit,ORDER_TIME_GTC,0)) 
        {
         //--- Request is completed or order placed
         Alert("A BuyStop order has been successfully placed with Ticket#:",mytrade.ResultOrder(),"!!");
         return;
        }
      else
        {
         Alert("The BuyStop order request at vol:",mytrade.RequestVolume(), 
                 ", sl:", mytrade.RequestSL(),", tp:",mytrade.RequestTP(),
               ", price:", mytrade.RequestPrice(), 
                 " could not be completed -error:",mytrade.ResultRetcodeDescription());
         return;
        }
     }

O podemos también utilizar la función OrderOpen para colocar la orden BUYSTOP

   if(checkBuy()==true)
     {
      Alert("Total Pending Orders now is :",CountOrders(),"!!");
      //--- any opened Buy position?
      if(Buy_opened)
        {
         Alert("We already have a Buy position!!!");
         return;    //--- Don't open a new Sell Position
        }
      //Buy price = bar 1 High + 2 pip + spread
      int sprd=mysymbol.Spread();
      double bprice =mrate[1].high + 10*_Point + sprd*_Point;
      double mprice=NormalizeDouble(bprice,_Digits);               //--- Buy price
      double stloss = NormalizeDouble(bprice - STP*_Point,_Digits); //--- Stop Loss
      double tprofit = NormalizeDouble(bprice+ TKP*_Point,_Digits); //--- Take Profit
      //--- open BuyStop order
      //if(mytrade.BuyStop(Lot,mprice,_Symbol,stloss,tprofit))
      if(mytrade.OrderOpen(_Symbol,ORDER_TYPE_BUY_STOP,Lot,0.0,bprice,stloss,tprofit,ORDER_TIME_GTC,0)) 
        {
         //--- Request is completed or order placed
         Alert("A BuyStop order has been successfully placed with Ticket#:",mytrade.ResultOrder(),"!!");
         return;
        }
      else
        {
         Alert("The BuyStop order request at vol:",mytrade.RequestVolume(), 
              ", sl:", mytrade.RequestSL(),", tp:",mytrade.RequestTP(),
              ", price:", mytrade.RequestPrice(), 
                " could not be completed -error:",mytrade.ResultRetcodeDescription());
         return;
        }
     }

Al colocar nuestra orden BUYSTOP, el precio de apertura es el Máximo de la Barra 1 + 2pip + spread.

Recuerda que el precio mostrado en el gráfico es el precio de COMPRA (BID) y que al colocar órdenes largas/compra necesitas el precio de VENTA (ASK), es por eso que hemos decidido añadir el spread al Máximo de la Barra 1 de modo que ahora tenemos el correspondiente precio de Venta (Ask) + 2pip. Ya han sido definidos Stop Loss y Take Profit en los parámetros de entrada.

Cuando ya tenemos todos los parámetros necesarios, utilizamos la función BuyStop de la clase CTrade u OrderOpen para colocar nuestra orden. El tipo de orden aquí es ORDER_TYPE_BUY_STOP (orden Buy Stop). Utilizamos el mismo precio para el precio límite pero esta no es una orden BuyLimit. También establecemos el tiempo de vigencia de la orden en ORDER_TIME_GTC durante el cual las órdenes siguen siendo vigentes hasta que se cancelen.

Si utiliza ORDER_TIME_GTC o ORDER_TIME_DAY, no hace falta indicar el tiempo de vencimiento, es por eso que ponemos el tiempo de vencimiento en 0.

   if(checkSell()==true)
     {
      Alert("Total Pending Orders now is :",CountOrders(),"!!");
      //--- any opened Sell position?
      if(Sell_opened)
        {
         Alert("We already have a Sell position!!!");
         return;    //--- Wait for a new bar
        }
      //--- Sell price = bar 1 Low - 2 pip 
      double sprice=mrate[1].low-10*_Point;
      double slprice=NormalizeDouble(sprice,_Digits);            //--- Sell price
      double ssloss=NormalizeDouble(sprice+STP*_Point,_Digits);   //--- Stop Loss
      double stprofit=NormalizeDouble(sprice-TKP*_Point,_Digits); //--- Take Profit
      //--- Open SellStop Order
      if(mytrade.SellStop(Lot,slprice,_Symbol,ssloss,stprofit))
      //if(mytrade.OrderOpen(_Symbol,ORDER_TYPE_SELL_STOP,Lot,0.0,slprice,ssloss,stprofit,ORDER_TIME_GTC,0)) 
        {
         //--- Request is completed or order placed
         Alert("A SellStop order has been successfully placed with Ticket#:",mytrade.ResultOrder(),"!!");
         return;
        }
      else
        {
         Alert("The SellStop order request at Vol:",mytrade.RequestVolume(), 
              ", sl:", mytrade.RequestSL(),", tp:",mytrade.RequestTP(), 
                ", price:", mytrade.RequestPrice(), 
                " could not be completed -error:",mytrade.ResultRetcodeDescription());
         return;
        }
     }

O podemos también utilizar la función OrderOpen para colocar la orden:

   if(checkSell()==true)
     {
      Alert("Total Pending Orders now is :",CountOrders(),"!!");
      //--- any opened Sell position?
      if(Sell_opened)
        {
         Alert("We already have a Sell position!!!");
         return;    //--- Wait for a new bar
        }
      //--- Sell price = bar 1 Low - 2 pip 
      double sprice=mrate[1].low-10*_Point;
      double slprice=NormalizeDouble(sprice,_Digits);            //--- Sell price
      double ssloss=NormalizeDouble(sprice+STP*_Point,_Digits);   //--- Stop Loss
      double stprofit=NormalizeDouble(sprice-TKP*_Point,_Digits); //--- Take Profit
      //--- Open SellStop Order
      //if(mytrade.SellStop(Lot,slprice,_Symbol,ssloss,stprofit))
      if(mytrade.OrderOpen(_Symbol,ORDER_TYPE_SELL_STOP,Lot,0.0,slprice,ssloss,stprofit,ORDER_TIME_GTC,0)) 
        {
         //--- Request is completed or order placed
         Alert("A SellStop order has been successfully placed with Ticket#:",mytrade.ResultOrder(),"!!");
         return;
        }
      else
        {
         Alert("The SellStop order request at Vol:",mytrade.RequestVolume(), 
                ", sl:", mytrade.RequestSL(),", tp:",mytrade.RequestTP(), 
                ", price:", mytrade.RequestPrice(), 
              " could not be completed -error:",mytrade.ResultRetcodeDescription());
         return;
        }
     }

Al igual que la orden BuyStop, el precio de apertura Mínimo de la Barra 1 + 2pip. En este caso no tenemos que añadir el spread, ya que, normalmente, necesitamos el precio de de COMPRA (BID) para colocar órdenes cortas/venta.

También usaremos la misma función OrderOpen o la función SellStop para colocar la orden SellStop. El tipo de orden aquí es ORDER_TYPE_SELL_STOP (orden Sell Stop).

A continuación, se muestran los resultados de nuestro Asesor Experto simple.

 


Figura 8. El informe de la prueba del Asesor Experto de orden pendiente

 

Figura 9. - El resultado gráfico de la prueba del Asesor Experto

 

Figura 10. Informe gráfico de la prueba del Asesor Experto

 

2.3 Obtener los detalles de las órdenes/transacciones

En este ejemplo, mostraremos cómo obtener los detalles de la orden después de activarla.

En esta etapa, ya no es una orden pendiente, ya que ha sido activada y transformada en una transacción.

Para comprender este proceso a fondo, echemos un vistazo a los detalles del diario a partir de una de nuestras operaciones de trading:

Procesamiento de una orden

Figura 11. Procesamiento de una orden

2.3.1 Obtener las propiedades de una orden (Historial)

//+------------------------------------------------------------------+
//|  Include ALL classes that will be used                           |
//+------------------------------------------------------------------+
//--- The Trade Class
#include <Trade\HistoryOrderInfo.mqh>
//+------------------------------------------------------------------+
//|  CREATE CLASS OBJECT                                             |
//+------------------------------------------------------------------+
//--- The HistoryOrderInfo Class Object
CHistoryOrderInfo myhistory;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Get all orders in History and get their details
   int buystop=0;
   int sellstop=0;
   int buylimit=0;
   int selllimit=0;
   int buystoplimit=0;
   int sellstoplimit=0;
   int buy=0;
   int sell=0;

   int s_started=0;
   int s_placed=0;
   int s_cancelled=0;
   int s_partial=0;
   int s_filled=0;
   int s_rejected=0;
   int s_expired=0;

   ulong o_ticket;
// Get all history records
   if(HistorySelect(0,TimeCurrent())) // get all history orders
     {
      // Get total orders in history
      for(int j=HistoryOrdersTotal(); j>0; j--)
        {
         // select order by ticket
         o_ticket=HistoryOrderGetTicket(j);
         if(o_ticket>0)
           {
            // Set order Ticket to work with
            myhistory.Ticket(o_ticket);
            Print("Order index ",j," Order Ticket is: ",myhistory.Ticket()," !");
            Print("Order index ",j," Order Setup Time is: ",TimeToString(myhistory.TimeSetup())," !");
            Print("Order index ",j," Order Open Price is: ",myhistory.PriceOpen()," !");
            Print("Order index ",j," Order Symbol is: ",myhistory.Symbol() ," !");
            Print("Order index ",j," Order Type is: ", myhistory.Type() ," !");
            Print("Order index ",j," Order Type Description is: ",myhistory.TypeDescription()," !");
            Print("Order index ",j," Order Magic is: ",myhistory.Magic()," !");
            Print("Order index ",j," Order Time Done is: ",myhistory.TimeDone()," !");
            Print("Order index ",j," Order Initial Volume is: ",myhistory.VolumeInitial()," !");
            //
            //
            if(myhistory.Type() == ORDER_TYPE_BUY_STOP) buystop++;
            if(myhistory.Type() == ORDER_TYPE_SELL_STOP) sellstop++;
            if(myhistory.Type() == ORDER_TYPE_BUY) buy++;
            if(myhistory.Type() == ORDER_TYPE_SELL) sell++;
            if(myhistory.Type() == ORDER_TYPE_BUY_LIMIT) buylimit++;
            if(myhistory.Type() == ORDER_TYPE_SELL_LIMIT) selllimit++;
            if(myhistory.Type() == ORDER_TYPE_BUY_STOP_LIMIT) buystoplimit++;
            if(myhistory.Type() == ORDER_TYPE_SELL_STOP_LIMIT) sellstoplimit++;

            if(myhistory.State() == ORDER_STATE_STARTED) s_started++;
            if(myhistory.State() == ORDER_STATE_PLACED) s_placed++;
            if(myhistory.State() == ORDER_STATE_CANCELED) s_cancelled++;
            if(myhistory.State() == ORDER_STATE_PARTIAL) s_partial++;
            if(myhistory.State() == ORDER_STATE_FILLED) s_filled++;
            if(myhistory.State() == ORDER_STATE_REJECTED) s_rejected++;
            if(myhistory.State() == ORDER_STATE_EXPIRED) s_expired++;
           }
        }
     }
// Print summary
   Print("Buy Stop Pending Orders : ",buystop);
   Print("Sell Stop Pending Orders: ",sellstop);
   Print("Buy Orders : ",buy);
   Print("Sell Orders: ",sell);
   Print("Total Orders in History is :",HistoryOrdersTotal()," !");
   
   Print("Orders type summary");
   Print("Market Buy Orders: ",buy);
   Print("Market Sell Orders: ",sell);
   Print("Pending Buy Stop: ",buystop);
   Print("Pending Sell Stop: ",sellstop);
   Print("Pending Buy Limit: ",buylimit);
   Print("Pending Sell Limit: ",selllimit);
   Print("Pending Buy Stop Limit: ",buystoplimit);
   Print("Pending Sell Stop Limit: ",sellstoplimit);
   Print("Total orders:",HistoryOrdersTotal()," !");

   Print("Orders state summary");
   Print("Checked, but not yet accepted by broker: ",s_started);
   Print("Accepted: ",s_placed);
   Print("Canceled by client: ",s_cancelled);
   Print("Partially executed: ",s_partial);
   Print("Fully executed: ",s_filled);
   Print("Rejected: ",s_rejected);
   Print("Expired: ",s_expired);
  }

Este es solo un script sencillo que muestra cómo obtener los detalles de las órdenes registradas en nuestro historial. Incluimos la clase CHistoryOrderInfo y creamos un objeto de la clase.

Ahora utilizamos el objeto para obtener los detalles de las órdenes.

El resultado del script del historial de las órdenes 

 Figura 12. El resultado del script del historial de las órdenes

2.3.2 Obtener las propiedades de una transacción (Historial)

//+------------------------------------------------------------------+
//|  Include ALL classes that will be used                           |
//+------------------------------------------------------------------+
//--- The CDealInfo Class
#include <Trade\DealInfo.mqh>
//+------------------------------------------------------------------+
//|  Create class object                                             |
//+------------------------------------------------------------------+
//--- The CDealInfo Class Object
CDealInfo mydeal;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Get all deals in History and get their details
    int buy=0;
    int sell=0;
    int deal_in=0;
    int deal_out=0;
    ulong d_ticket;
    // Get all history records
    if (HistorySelect(0,TimeCurrent())) 
    {
      // Get total deals in history
      for (int j=HistoryDealsTotal(); j>0; j--)
      {
         // select deals by ticket
         if (d_ticket = HistoryDealGetTicket(j))
         {
          // Set Deal Ticket to work with
          mydeal.Ticket(d_ticket);
          Print("Deal index ", j ," Deal Ticket is: ", mydeal.Ticket() ," !");
          Print("Deal index ", j ," Deal Execution Time is: ", TimeToString(mydeal.Time()) ," !");
          Print("Deal index ", j ," Deal Price is: ", mydeal.Price() ," !");
          Print("Deal index ", j ," Deal Symbol is: ", mydeal.Symbol() ," !");
          Print("Deal index ", j ," Deal Type Description is: ", mydeal.TypeDescription() ," !");
          Print("Deal index ", j ," Deal Magic is: ", mydeal.Magic() ," !");
          Print("Deal index ", j ," Deal Time is: ", mydeal.Time() ," !");
          Print("Deal index ", j ," Deal Initial Volume is: ", mydeal.Volume() ," !");
          Print("Deal index ", j ," Deal Entry Type Description is: ", mydeal.EntryDescription() ," !");
          Print("Deal index ", j ," Deal Profit is: ", mydeal.Profit() ," !");
          //
          if (mydeal.Entry() == DEAL_ENTRY_IN) deal_in++;
          if (mydeal.Entry() == DEAL_ENTRY_OUT) deal_out++;
          if (mydeal.Type() == DEAL_TYPE_BUY) buy++;
          if (mydeal.Type() == DEAL_TYPE_SELL) sell++;
         }
      }
    }
    // Print Summary
    Print("Total Deals in History is :", HistoryDealsTotal(), " !");
    Print("Total Deal Entry IN is : ", deal_in);
    Print("Total Deal Entry OUT is: ", deal_out);
    Print("Total Buy Deal is : ", buy);
    Print("Total Sell Deal is: ", sell);
  }

Este también es un script sencillo que muestra cómo obtener los detalles de la transacciones registradas en nuestro historial.

El resultado del script de las transacciones

Figura 13. El resultado del script del historial de las transacciones


Conclusión

En este artículo, hemos podido analizar las principales funciones de la Librería estándar de las clases de trading y hemos mostrado cómo se pueden utilizar algunas de esta funciones en la escritura de Asesores Expertos que implementan la modificación de una posición, la colocación de una orden pendiente y el borrado y la comprobación del margen antes de colocar una orden.

También hemos mostrado cómo se pueden utilizar en la obtención de los detalles de una orden y una operación. No hemos utilizado todas estas funciones en la escritura de nuestro Asesor Experto, pero según la estrategia de trading que va a utilizar, puede utilizar más o menos funciones que las de este artículo.

Le recomendamos repasar la sección en la que se describen las distintas funciones y ver cómo las puede utilizar en la escritura de su propio EAsesor Experto.

Las Librerías de clases estándar están diseñadas para facilitar la vida tanto a los traders como a los desarrolladores, así que asegúrese de utilizarlas.