English Русский 中文 Deutsch 日本語 Português
Experto comercial universal: Acceso a las propiedades de los instrumentos (parte 8)

Experto comercial universal: Acceso a las propiedades de los instrumentos (parte 8)

MetaTrader 5Ejemplos | 28 agosto 2017, 12:38
1 358 0
Vasiliy Sokolov
Vasiliy Sokolov

Introducción

Ya ha pasado cierto tiempo desde la publicación de la última parte del artículo dedicado al motor comercial CStrategy. Este tiempo ha sido necesario para reflexionar sobre el camino que ha recorrido CStrategy desde una pequeña biblioteca comercial auxiliar hasta convertirse un complejo comercial completo que incluye la mayoría de los instrumentos usados con frecuencia para construir una estrategia comercial completa. Transcurrido este tiempo, ha surgido un nuevo concepto sobre la dirección en la que se debe desarrollar CStrategy más adelante. La aplicación práctica de CStrategy durante este tiempo ha descubierto asimismo varios defectos propios de la última versión del motor. La corrección de estos defectos ha derivado en un nuevo grupo de artículos pertenecientes a la serie "Experto comercial universal". En este octavo artículo se aclarará el trabajo con instrumentos comerciales a través de la clase orientada a objetos CStrategy. 


Vista general del trabajo con el instrumento en las versiones anteriores de CStrategy

El entorno comercial del experto es diverso y voluminoso. Se trata de información variada sobre la cuenta, datos de las cotizaciones, funciones del trabajo con el tiempo y, por supuesto, la información accesible en el terminal sobre los instrumentos comerciales. La mayoría de esta información se centra en las funciones para trabajar con instrumentos comerciales: la obtención de las cotizaciones actuales y el trabajo con las propiedades del instrumento de trabajo. Normalmente, todos los expertos operan de forma muy activa con la información sobre el precio. Calculan sobre la base de los últimos datos un cierto patrón de precio o señal comercial y realizan la transacción basándose en ellos. Para que se forme correctamente la solicitud comercial, también utilizan información sobre las propiedades del actual símbolo de trabajo: por ejemplo, el volumen mínimo de la transacción realizada o el nivel "freeze level", el diapasón del precio actual dentro del cual está prohibido colocar órdenes pendientes.

Está claro que esta información deberá ser de fácil acceso y estar siempre "a mano". Sin embargo, ¿ha resultado esto así en las anteriores ediciones de CStrategy? Vamos a aclarar esto, haciendo una pequeña digresión en la historia: describiremos cómo ha tenido lugar el trabajo con el símbolo comercial anteriormente. En la tercera parte del artículo se propone un sistema de acceso a las cotizaciones a través del indexador [] acostumbrado. En la clase CStrategy se han incluido varias clases auxiliares COpen, CHigh, CLow, CClose, CVolume, CTime, cada una de las cuales ha retornado el resultado correspondiente sobre el índice solicitado. Esto ha permitido obtener con bastante comodidad información sobre el símbolo actual en el código del experto. Por ejemplo, para conocer el precio de cierre de la barra actual, basta con escribir:

...
double close = Close[0];
...

Sin embargo, el acceso a los precios en el formato OHLC ha resultado insuficiente, y la clase CStrategy se ha debido equipar con los métodos adicionales Ask(), Bid(), Last(). Muy pronto estos métodos también resultaron insuficientes. Fue necesario añadir varios métodos más del tipo FreezeLevel(), que obtenían la información principal sobre el instrumento actual. El volumen de la clase básica CStrategy comenzó a crecer a un gran ritmo. La abundancia de métodos accesibles dentro de CStrategy comenzó a provocar confusión. Pero las principales dificultades comenzaron cuando se intentó crear con la ayuda de CStrategy un experto que comerciase en varios instrumentos de forma simultánea. Formalmente, CStrategy es un motor multiinstrumental. Esto significa que con su ayudan se puede crear tanto varios expertos que comercien en diferentes instrumentos independientemente unos de otros, como un experto que comercie en dos o más instrumentos. Sin embargo, esto último no fue tan fácil de conseguir, puesto que en este caso fue necesario reconfigurar sobre la marcha las clases de las series temporales, presentando este u otro símbolo por turnos:

string symbol1 = "EURUSD";
string symbol2 = "GBPUSD";
Close.Symbol(symbol1);
double close_eurusd = Close[0];
Close.Symbol(symbol2);
double close_gbpusd = Close[0];
...

Todas estas dificultades han servido para comprender que la información sobre el instrumento de trabajo es demasiado amplia y variada como para que CStrategy pueda implementarla. La propia clase CStrategy ya ejecuta un trabajo voluminoso y complejo de organización de la secuencia de las acciones comerciales, por lo que armarla con una funcionalidad adicional solo provocaría la reducción del nivel de control sobre el código. En lugar de ello, se ha decido seleccionar un método para trabajar con el instrumento en una clase aparte CSymbol.

Primer contacto con el objeto WS y la clase CSymbol

Ahora, en lugar de métodos dispersos como Ask(), Bid(), Last y clases especiales como CHigh y CLow, con la estrategia comercial cimentada sobre CStrategy está disponible el objeto especial WS, creado sobre la base de la clase CSymbol. Esta clase, perteneciente al conjunto de bibliotecas CStrategy, dispone de una serie de métodos que la hace semejante a la clase estándar СSymbolInfo. Sin embargo, se trata de otra clase que trabaja solo con las propiedades del instrumento, y que también permite recibir sus cotizaciones, incluyendo la información sobre las solicitudes límite (profundidad de mercado). El nombre del objeto WS es la abreviatura de "Work Symbol", y está disponible directamente en el código de la estrategia. No se ha elegido un nombre así de corto por casualidad. En el proceso de trabajo se necesita con mucha frecuencia recurrir a esta u otra propiedad del instrumento, por eso, la abreviatura de dos símbolos permite al código permanecer compacto y expresivo. 

Como ya se ha dicho en las anteriores partes del artículo, antes de transmitir el control al experto, el motor comercial CStrategy realiza una serie de inicializaciones de los objetos del entorno interno. Se recuerda el nombre del instrumento de trabajo y el marco temporal, se crean las clases que realizan el seguimiento de la llegada de nuevos eventos (por defecto, se trata del nuevo tick y la nueva barra). Se establece el logueo, se colocan las banderas de los modos de trabajo. En este momento se inicializa el objeto WS de la clase CSymbol. Su construcción interna es bastante sencilla. Contiene dos campos internos: el símbolo del instrumento y su marco temporal, además de objetos especiales para acceder a las cotizaciones del instrumento. El propio objeto WS se inicializa con el método InitSeries. Conociendo el símbolo de trabajo y el marco temporal del experto, no será ningún problema inicializarlo:

CStrategy::CStrategy(void)
{
   WS.InitSeries(ExpertSymbol(), Timeframe());
}

Después de que el objeto esté inicializado, con su ayuda se puede obtener la propiedad requerida del instrumento. Por ejemplo, para obtener el precio máximo de la barra actual, basta con escribir lo siguiente:

double max = WS.High[0];

El objeto WS posee una serie adicional de propiedades que hacen su uso en los cálculos directos un recurso muy cómodo y autosuficiente. Vamos a analizar un caso muy extendido, cuando necesitamos una orden BuyStop un poco por encima del precio del máximo de la barra anterior. Supongamos que estamos comerciando con EURUSD y queremos que nuestra orden stop sea colocada a una distancia de tres puntos de cinco dígitos del máximo de la barra anterior, necesitaremos escribir el código siguiente:

void CMovingAverage::InitBuy(const MarketEvent &event)
{
   ...
   Trade.BuyStop(1.0, WS.High[1] + WS.StepToPrice(3), WS.Name());
   ...
}

Así, en una sola línea de código hemos ubicado un gran volumen de acciones:

  • Obtenemos el extremo de la barra anterior (WS.High[1]);
  • El valor de un punto lo hemos multiplicado por tres, obteniendo una distancia de precio de tres puntos (WS.StepToPrice(3));
  • Hemos añadido al precio del extremo la distancia de precio obtenida (WS.High[1] + WS.StepToPrice(3));
  • Hemos enviado una orden comercial BuyStop, cuyo nivel de activación ahora es el precio obtenido, indicando como símbolo el nombre del instrumento actual (WS.Name()).

El método StepToPrice puede parecer demasiado distinto del sistema de denominaciones adoptado en MetaTrader. En otras plataformas comerciales se entiende por price step el cambio mínimo del precio. Su equivalente en MetaTrader se llama SYMBOL_TRADE_TICK_SIZE. Este nombre se puede confundir fácilmente con el tamaño o el precio de un tick SYMBOL_TRADE_TICK_VALUE, por eso en CSymbol se usa otro nombre para este parámetro. Sin embargo, la mayoría de los nombres de los otros métodos CSymbol coincide con los modificadores de sistema y los métodos MQL5, pero, como muestra el ejemplo con StepToPrice, no siempre son idénticos. Y es que el principal objetivo de CSymbol es proporcionar un conjunto comprensible e intuitivo de métodos para obtener información completa sobre el instrumento comercial.

Estructura de la clase CSymbol. Tabla comparativa de métodos

El instrumento comercial en MetaTrader posee un gran conjunto de propiedades. Ante que nada, las propiedades se pueden dividir condicionalmente en propiedades de número entero, reales y de línea. A las propiedades de número entero pertenecen las propiedades lógicas (bool), los modificadores de sistema en forma de enumeraciones (enum), la fecha y la hora (datetime) y propiamente las propiedades de número entero (int y long). A las propiedades de tipo real pertenecen diferentes valores fraccionados (double). Al fin, a las propiedades de línea o cadena (string) pertenecen las propiedades que retornan líneas: el nombre del instrumento, la descripción de línea de un símbolo, etcétera. A fin de cuentas, el instrumento tiene acceso a una serie de propiedades específicas para un determinado segmento de mercado. Así, para el mercado FORTS, están disponibles las propiedades adicionales de la sesión comercial actual. Para los mercados de opciones están disponibles sus propiedades únicas. La clase CSymbol determina las propiedades de la sesión comercial actual de FORTS en la clase interna adicional SessionInfo. El resto de las propiedades no se dividen en clases y están presentes "tal cual" en forma de métodos homónimos.

Lo que es más, en la clase CSymbol se contienen colecciones adicionales que hacen posible recurrir a las cotizaciones del instrumento. Así, para acceder a las series OHLCV se han definido públicamente las clases COpen, CHigh, CLow, CClose, CVolume, y para acceder a la profundidad de mercado, se usa la clase especial CMarketWatch, cuya descripción detallada está disponible en el artículo: "Recetas MQL5 - Escribiendo nuestra propia profundidad de mercado". Aparte de los métodos homónimos y las clases-indexadores como CClose, la clase CSymbol contiene varios métodos que no disponen de análogos obvios en las funciones estándar de MQL5 o en la clase SymbolInfo. Los describiremos con más detalle.

Available — este método retorna true, si el instrumento con el nombre indicado existe en el terminal. Si tal instrumento no existe, retorna false.

IndexByTime — retorna el índice de la barra que corresponde a la hora indicada. Por ejemplo, a la variable index en el código siguiente se le asignará el valor 1:

int index = WS.IndexByTime(WS.Time[1]);
// index = 1;

Este método es cómodo de usar si conocemos la hora y queremos obtener el número de la barra que corresponde a esta hora. Supongamos que el experto comercial debe cerrar la posición tras haberla mantenido durante BarsHold barras. Entonces el código que hace esto tendrá el aspecto siguiente:

//+------------------------------------------------------------------+
//| Acompaña con una posición larga según la media móvil Moving      |
//+------------------------------------------------------------------+
void CImpulse::SupportBuy(const MarketEvent &event,CPosition *pos)
{
   int bar_open = WS.IndexByTime(pos.TimeOpen());
   if(bar_open >= BarsHold)
      pos.CloseAtMarket("Exit by time hold");
}

StepToPricevalor del cambio mínimo del precio, expresado en puntos del instrumento. Más arriba se ha escrito con más detalle sobre las tareas de este método.

La lista completa de los métodos CSymbol se muestra en el recuadro unificado de abajo. En el campo "Descripción" se da una breve descripción del método. En la mayoría de los casos, coincide con la descripción oficial de la propiedad análoga del instrumento en el apartado correspondiente de la documentación, sin embargo, para algunos métodos se da, a mi juicio, una descripción más acertada de sus posibilidades.

El campo "Tipo" del valor retornado muestra, propiamente, el tipo retornado por un método o colección.

El campo "función o indentificador de sistema MQL5" contiene el nombre del identificador de sistema o función MQL5 que ejecuta funciones análogas. Si se indica una función de sistema, al final de su nombre se ponen paréntesis, por ejemplo, CopyOpen() o MarketBookGet(). Se entiende por identificador de sistema uno de los tres modificadores que se debe indicar al llamar las funciones SymbolInfoInteger, SymbolInfoDouble o SymbolInfoString. Este identificador debe pertenecer a uno de las tres enumeraciones de sistema correspondientes: ENUM_SYMBOL_INFO_INTEGER,  ENUM_SYMBOL_INFO_DOUBLE o ENUM_SYMBOL_INFO_STRING. Por ejemplo, si en la columna "función o indentificador de sistema MQL5" se indica el modificador SYMBOL_TRADE_STOPS_LEVEL, esto significa que para obtener esta propiedad es necesario llamar la función SymbolInfoInteger:

int stop_level = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);

La columna "Nombre del método CSymbol" contiene propiamente el nombre del método responsable de retornar la propiedad correspondiente. Por ejemplo, para obtener el día de la semana cuando se carga el swap triple, es necesario llamar el método:

ENUM_DAY_OF_WEEK day = WS.DayOfSwap3x();

Y bien, aquí tenemos el recuadro de métodos:

Descripción Tipo de valor retornado Función o indentificador de sistema MQL5 Nombre del método CSymbol
 ACCESO A LAS COTIZACIONES HISTÓRICAS DEL INSTRUMENTO      
   Obtiene el precio de apertura según el índice de la barra dado, con el marco temporal preestablecido para el instrumento  double  CopyOpen()  Open[]
   Obtiene el precio del máximo según el índice de la barra dado, con el marco temporal preestablecido para el instrumento  double  CopyHigh()  High[]
   Obtiene el precio del mínimo según el índice de la barra dado, con el marco temporal preestablecido para el instrumento  double  CopyLow()  Low[]
   Obtiene el precio de cierre según el índice de la barra dado, con el marco temporal preestablecido para el instrumento  double  CopyClose()  Close[]
   Obtiene el volumen correspondiente a la barra con el índice dado  double  CopyVolume()  Volume[]
   Obtiene las propiedades de la profundidad de mercado del instrumento dado, acceso a las cotizaciones de segundo nivel  MqlBookInfo  MarketBookGet()  MarketBook
 PROPIEDADES DE NÚMERO ENTERO DEL INSTRUMENTO      
   Señal de que este instrumento está presente en el terminal  bool  No hay análogos  Available
   Número de barras de este símbolo y marco temporal  int  Bars()   BarsTotal
   Marco temporal del instrumento  ENUM_TIMEFRAMES  Period()  Period
   Señal de que el símbolo está seleccionado en Market Watch  bool  SYMBOL_SELECT  SelectInMarketWatch
   Señal de spread flotante  bool  SYMBOL_SPREAD_FLOAT  SpreadFloat
   Tamaño del spread en puntos  int  SYMBOL_SPREAD  Spread
   Distancia mínima en puntos con respecto al precio actual de cierre para colocar el Stop Loss  int  SYMBOL_TRADE_STOPS_LEVEL  StopLevel
   Distancia de congelación de las operaciones comerciales (en puntos)  int  SYMBOL_TRADE_FREEZE_LEVEL  FreezeLevel
   Banderas de los modos permitidos de expiración de la orden  int  SYMBOL_EXPIRATION_MODE  FlagsExpirationOrders
   Banderas de los modos permitidos de ejecución de la orden  int  SYMBOL_FILLING_MODE  FlagsExecutionOrders
   Banderas de los tipos de orden permitidos  int  SYMBOL_ORDER_MODE  FlagsAllowedOrders
   Retorna el índice de la barra cuya hora de apertura corresponde al argumento transmitido  int  No hay análogos  IndexByTime
   Método de cálculo del coste del contrato  ENUM_SYMBOL_CALC_MODE  SYMBOL_TRADE_CALC_MODE  CalcContractType
   Tipo de ejecución de las órdenes  ENUM_SYMBOL_TRADE_MODE  SYMBOL_TRADE_MODE  ExecuteOrderType
   Modo de ejecución de las transacciones  ENUM_SYMBOL_TRADE_EXECUTION  SYMBOL_TRADE_EXEMODE  ExecuteDealsType
   Modelo de cálculo del swap  ENUM_SYMBOL_SWAP_MODE  SYMBOL_SWAP_MODE  CalcSwapMode
   Día de la semana para la carga del swap triple  ENUM_DAY_OF_WEEK  SYMBOL_SWAP_ROLLOVER3DAYS  DayOfSwap3x
   Tipo de opción  ENUM_SYMBOL_OPTION_MODE  SYMBOL_OPTION_MODE  OptionType
   Derecho de opción (Call/Put)  ENUM_SYMBOL_OPTION_RIGHT  SYMBOL_OPTION_RIGHT  OptionRight
   Hora de la última cotización  datetime  SYMBOL_TIME  TimeOfLastQuote
   Hora de comienzo de las transacciones del instrumento (normalmente se usa para los futuros)  datetime  SYMBOL_START_TIME  StartDate
   Hora de finalización de las transacciones del instrumento (normalmente se usa para los futuros)  datetime  SYMBOL_EXPIRATION_TIME  ExpirationDate
PROPIEDADES DE LA ACTUAL SESIÓN COMERCIAL DE LOS INSTRUMENTOS DE FUTUROS MOEX

 
   Número de transacciones en la sesión actual  long  SYMBOL_SESSION_DEALS  SymbolInfo.DealsTotal
   Número total de órdenes de compra en el momento actual  long  SYMBOL_SESSION_BUY_ORDERS  SymbolInfo.BuyOrdersTotal
   Número total de órdenes de venta en el momento actual  long  SYMBOL_SESSION_SELL_ORDERS  SymbolInfo.SellOrdersTotal
   Volumen máximo durante la sesión comercial actual  long  SYMBOL_VOLUMEHIGH  SymbolInfo.HighVolume
   Volumen mínimo durante la sesión comercial actual  long  SYMBOL_VOLUMELOW  SymbolInfo.LowVolume
   Bid máximo del día  double  SYMBOL_BIDHIGH  SymbolInfo.BidHigh
   Ask máximo del día  double  SYMBOL_ASKHIGH  SymbolInfo.AskHigh
   Bid mínimo del día  double  SYMBOL_BIDLOW  SymbolInfo.BidLow
   Ask mínimo del día  double  SYMBOL_ASKLOW  SymbolInfo.AskLow
   Last máximo del día  double  SYMBOL_LASTHIGH  SymbolInfo.LastHigh
   Last mínimo del día  double  SYMBOL_LASTLOW  SymbolInfo.LastLow
   Volumen total de transacciones de la sesión actual  double  SYMBOL_SESSION_VOLUME  SymbolInfo.VolumeTotal
   Circulación total en la sesión actual  double  SYMBOL_SESSION_TURNOVER  SymbolInfo.TurnoverTotal
   Volumen total de las posiciones abiertas  double  SYMBOL_SESSION_INTEREST  SymbolInfo.OpenInterestTotal
   Volumen total de las órdenes de compra en el momento actual  double  SYMBOL_SESSION_BUY_ORDERS_VOLUME  SymbolInfo.BuyOrdersVolume
   Volumen total de órdenes de venta en el momento actual  double  SYMBOL_SESSION_SELL_ORDERS_VOLUME  SymbolInfo.SellOrdersVolume
   Precio de apertura de la sesión  double  SYMBOL_SESSION_OPEN  SymbolInfo.PriceSessionOpen
   Precio de cierre de la sesión  double  SYMBOL_SESSION_CLOSE  SymbolInfo.PriceSessionClose
   Precio medio ponderado de la sesión  double  SYMBOL_SESSION_AW  SymbolInfo.PriceSessionAverage
   Precio de entrega de la sesión actual  double  SYMBOL_SESSION_PRICE_SETTLEMENT  SymbolInfo.PriceSettlement
   Valor máximo aceptable del precio para la sesión  double  SYMBOL_SESSION_PRICE_LIMIT_MAX  SymbolInfo.PriceLimitMax
   Valor mínimo aceptable del precio para la sesión  double  SYMBOL_SESSION_PRICE_LIMIT_MIN  SymbolInfo.PriceLimitMin
PROPIEDADES REALES DEL INSTRUMENTO       
   Ask — mejor oferta de compra  double  SYMBOL_ASK  Ask
   Bid — mejor oferta de venta  double  SYMBOL_BID  Bid
   Precio al que se ha realizado la última transacción  double  SYMBOL_LAST  Last
   Valor del cambio mínimo de precio, multiplicado por el número transmitido de saltos del precio  double  No hay análogos  StepToPrice
   Valor de un punto (tick)  double  SYMBOL_POINT  PriceStep
   Coste de un punto (tick), expresado en la divisa del depósito  double  SYMBOL_TRADE_TICK_VALUE  TickValue
   Precio de ejecución de la opción  double  SYMBOL_OPTION_STRIKE  OptionStrike
   Tamaño del contrato comercial  double  SYMBOL_TRADE_CONTRACT_SIZE  ContractSize
   Volumen mínimo para la ejecución de la transacción  double  SYMBOL_VOLUME_MIN  VolumeContractMin
   Volumen máximo para la ejecución de la transacción  double  SYMBOL_VOLUME_MAX  VolumeContractMax
   Salto mínimo de cambio del volumen para la ejecución de la transacción  double  SYMBOL_VOLUME_STEP  VolumeContractStep
   Volumen conjunto máximo permitido de posición abierta y órdenes pendientes en una dirección para el símbolo dado (compra o venta)  double  SYMBOL_VOLUME_LIMIT  VolumeContractLimit
   Valor del swap cargado al mantener una posición larga con un volumen de un contrato  double  SYMBOL_SWAP_LONG  SwapLong
   Valor del swap cargado al mantener una posición corta con un volumen de un contrato  double  SYMBOL_SWAP_SHORT  SwapShort
   Margen necesario para abrir una posición con un tamaño de un lote  double  SYMBOL_MARGIN_INITIAL  MarginInit
   Margen necesario para mantener un lote de una posición abierta  double  SYMBOL_MARGIN_MAINTENANCE  MarginMaintenance
   Margen necesario para mantener un lote de una posición cubierta  double  SYMBOL_MARGIN_HEDGED  MarginHedged
 PROPIEDADES DE LÍNEA DEL INSTRUMENTO      
   Nombre del instrumento  string  Symbol()  Name
   Nombre del activo básico para un instrumento derivado  string  SYMBOL_BASIS  NameBasisSymbol
   Divisa básica del instrumento  string  SYMBOL_CURRENCY_BASE  NameBasisCurrency
   Divisa del beneficio  string  SYMBOL_CURRENCY_PROFIT  NameCurrencyProfit
   Divisa en la que se calcula el margen  string  SYMBOL_CURRENCY_MARGIN  NameCurrencyMargin
   Fuente de la cotización actual  string  SYMBOL_BANK  NameBank
   Descripción de línea del símbolo  string  SYMBOL_DESCRIPTION  Description
   Nombre del símbolo comercial en el sistema internacional de números de identificación de valores ISIN  string  SYMBOL_ISIN  NameISIN
   Ruta en el árbol de símbolos  string  SYMBOL_PATH  SymbolPath

Uso de varios instrumentos simultáneamente

Puesto que CSymbol es una clase normal, se puede crear un número ilimitado de objetos de esta clase dentro de su experto. El objeto WS es solo uno de estos objetos, creado de antemano por el motor CStrategy, y que además indica el símbolo de trabajo actual y el marco temporal. Nada impide al propio experto crear un símbolo adicional que proporcione acceso a cualquier otro instrumento. Supongamos que nuestro experto comercia en la sección urgente de la bolsa de Moscú y simultáneamente realiza el seguimiento de dos instrumentos Si y Brent. Entonces, en su código se pueden ubicar dos símbolos CSymbol, llamándolos respectivamente Si y Brent:

//+------------------------------------------------------------------+
//|                                                EventListener.mqh |
//|           Copyright 2017, Vasiliy Sokolov, St-Petersburg, Russia |
//|                                https://www.mql5.com/ru/users/c-4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Vasiliy Sokolov."
#property link      "https://www.mql5.com/ru/users/c-4"
#include <Strategy\Strategy.mqh>

//+------------------------------------------------------------------------------+
//| Plantilla de la estrategia que trabaja con dos instrumentos simultáneamente  |
//+------------------------------------------------------------------------------+
class CIntRate : public CStrategy
  {
   CSymbol           Si;         // Rublo-dólar
   CSymbol           Brent;      // Petróleo
public:
   virtual void      OnEvent(const MarketEvent& event);
   virtual bool      OnInit();
  };
//+------------------------------------------------------------------+
//| Inicializa los instrumentos petróleo y rublo                     |
//+------------------------------------------------------------------+
bool CIntRate::OnInit(void)
  {
   Si.InitSeries("Si Splice", Timeframe());
   Brent.InitSeries("BR Splice", Timeframe());
   return true;
  }

//+------------------------------------------------------------------+
//| Coste del petróleo expresado en rublos                           |
//+------------------------------------------------------------------+
void CIntRate::OnEvent(const MarketEvent &event)
  {
   double brent_in_rub = Brent.Last()*Si.Last()/Si.ContractSize();
  }

//+------------------------------------------------------------------+

Este código del experto recibe los últimos precios de los futuros actuales del petróleo y el rublo y calcula la fórmula conocida del coste del petróleo expresado en rublos. Puesto que un contrado de futuros de Si es igual a 1000$, tendremos que dividir adicionalmente el resultado por el tamaño de un contrato. Sin embargo, gracias a que todas las propiedades del instrumento están reunidas en una clase única de CSymbol, se trata de una operación sencilla. El resto del código es también simple y expresivo. Lo más importante es no olvidar inicializar los objetos Si y Brent en el momento de inicio del experto, en el método OnInit.


Construyendo el perfil de la tasa de interés con la ayuda de CSymbol

El último ejemplo del uso de CSymbol, que estamos analizando, será un poco más complejo, pero también más interesante. Ya se sabe que los contratos de futuros se negocian con un cierto contango con respecto al activo básico. Esto está relacionado con el hecho de que el precio de una mercancía en el futuro normalmente es mayor que el precio actual. En esencia, esta diferencia determina la tasa de interés de mercado para una mercancía o un activo. Vamos a analizar un ejemplo con un futuro rublo/dólar. Su precio actual al momento de escribirse estas líneas era de 56.2875 rublos por 1 dólar, y el precio del contrato de futuros más cercano de Si-6.17 era de 56682 rublos por 1000$ o 56,682 rublos por 1 dólar. Es decir, la diferencia entre el precio actual y el precio dentro de 30 días (al 16.05.2017 Si-6.17 expira dentro de 30 días) constituye 0,395 rublos, o 39,5 kópeks. Es decir, en 1 mes, en opinión del mercado, el rublo se devaluará en 39,5 kópeks, lo que constituye un 0.7% de su precio actual. No resulata complicado calcular que en 12 meses de inflación, en opinión del mercado, constituirá un 8,42%. Pero esto sería el nivel de inflación calculado solo para el futuro más cercano. Si en lugar de Si-6.17, ponemos Si-9.17, la inflación será inferior y constituirá un 7.8% de interés. De esta forma, comparando todos los futuros Si con el precio básico del activo, podremos obtener el perfil de la tasa de interés. Este perfil tendrá el aspecto de un recuadro que mostrará la esperanza de los inversores dependiendo del tiempo. Por ejemplo, conocemos el interés para los próximos 30, 100, 200, 300, 400 y 500 días.

Para calcular estos valores, tenemos que utilizar activamente las diversas propiedades de los instrumentos, y también manipular la propia lista de estos instrumentos. Este es el aspecto que tiene la tarea del cálculo del perfil de la tasa de interés por puntos.

  1. El experto se carga en cualquier instrumento de futuros. Analiza el nombre del instrumento y carga todos los futuros relacionados con él.
  2. Cada futuro cargado supone un objeto CSymbol, que se ubica en la lista de instrumentos.
  3. En el momento de llegada del tick, el experto trabaja con la colección de instrumentos. Para cada instrumento se encuentra su símbolo básico.
  4. Se lleva a cabo el cálculo de la diferencia entre el instrumento elegido y el precio de su símbolo básico. Esta diferencia se convierte a tanto por ciento, y después se transforma en equivalente anual: para ello, se tiene en cuenta el tiempo de vida restante del contrato de futuros.
  5. La diferencia obtenida se muestra en el panel en forma de líneas en un recuadro. Cada línea tiene la forma: "Nombre del futuro — Número de días hasta la expiración — tasa de interés".

Como podemos ver por la descripción, el algoritmo no resulta en realidad tan sencillo como podría parecer. Sin embargo, gracias al motor CStrategy y al objeto CSymbol, reduciremos sustancialmente la complejidad del cálculo para el experto. Nuestro código se implementará en forma de experto, sin embargo, el propio experto no ejecutará ninguna acción comercial. En lugar de ello, simplemente mostrará el valor de las tasas de interés en el panel. Vamos a ver el código resultante:

//+------------------------------------------------------------------+
//|                                                EventListener.mqh |
//|           Copyright 2017, Vasiliy Sokolov, St-Petersburg, Russia |
//|                                https://www.mql5.com/ru/users/c-4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Vasiliy Sokolov."
#property link      "https://www.mql5.com/ru/users/c-4"
#include <Strategy\Strategy.mqh>
#include <Arrays\ArrayObj.mqh>
#include "Panel.mqh"

//+------------------------------------------------------------------+
//| Perfil de la tasa de interés                                     |
//+------------------------------------------------------------------+
class CIntRate : public CStrategy
  {
   CArrayObj         Symbols;    // Lista de símbolos
   CPercentPanel     Panel;      // Panel de dibujado de las tasas de interés
   double            BaseRate(CSymbol* fut);
public:
   virtual void      OnEvent(const MarketEvent& event);
   virtual bool      OnInit();
  };
//+------------------------------------------------------------------------------+
//| Añade los futuros necesarios para calcular el perfil de la tasa de interés   |
//+------------------------------------------------------------------------------+
bool CIntRate::OnInit(void)
  {
   string basis = WS.NameBasisSymbol();
   for(int i = 0; i < SymbolsTotal(false); i++)
   {
      string name = SymbolName(i, false);
      int index = StringFind(name, basis, 0);
      if(index != 0)
         continue;
      CSymbol* Fut = new CSymbol(name, Timeframe());
      if(Fut.ExpirationDate() == 0 || Fut.ExpirationDate() < TimeCurrent())
      {
         delete Fut;
         continue;
      }
      string text = "Add new symbol " + Fut.Name() + " in symbols list";
      CMessage* msg = new CMessage(MESSAGE_INFO, __FUNCTION__, text);
      Log.AddMessage(msg);
      Symbols.Add(Fut);
   }
   string text = "Total add symbols " + (string)Symbols.Total();
   CMessage* msg = new CMessage(MESSAGE_INFO, __FUNCTION__, text);
   Log.AddMessage(msg);
   if(Symbols.Total() > 0)
   {
      Panel.Show();
   }
   return true;
  }

//+------------------------------------------------------------------+
//| Calcula el perfil y lo muestra en un recuadro                    |
//+------------------------------------------------------------------+
void CIntRate::OnEvent(const MarketEvent &event)
  {
   double sec_one_day = 60*60*24;   //86 400
   for(int i = 0; i < Symbols.Total(); i++)
   {
      CSymbol* Fut = Symbols.At(i);
      double brate = BaseRate(Fut);
      double days = (Fut.ExpirationDate()-TimeCurrent())/sec_one_day;
      if(Fut.Last() == 0.0)
         continue;
      double per = (Fut.Last() - brate)/brate*100.0;
      double per_in_year = per/days*365;
      Panel.SetLine(i, Fut.NameBasisSymbol() + " " + DoubleToString(days, 0) + " Days:", DoubleToString(per_in_year, 2)+"%");
   }

  }
//+------------------------------------------------------------------+
//| Retorna la cotización spot del futuro                            |
//+------------------------------------------------------------------+
double CIntRate::BaseRate(CSymbol* fut)
{
   string name = fut.NameBasisSymbol();
   if(StringFind(name, "Si", 0) == 0)
      return SymbolInfoDouble("USDRUB_TOD", SYMBOL_LAST)*fut.ContractSize();
   return SymbolInfoDouble(name, SYMBOL_LAST)*fut.ContractSize();
}
//+------------------------------------------------------------------+

La funcionalidad principal se ha implementado en OnInit. Recibe el nombre del símbolo básico a través de WS.NameBasisSymbol() y, tras comprobar todos los instrumentos, encuentra todos los futuros que se correspondan con el símbolo básico dado.  Cada futuro semejante se forma en el objeto CSymbol y se ubica en la lista de símbolos CArrayObj. Sin embargo, se hace una comprobación preliminar sobre si este futuro es válido, y si su tiempo de expiración se encuentra en el futuro, significará que se trata precisamente del futuro que necesitamos.

En el método OnEvent se hace propiamente el cálculo de la tasa de interés para cada futuro ubicado en la colección  Symbols. Se calcula el número de días hasta la expiración, delta entre el futuro y el precio del swap. La diferencia de precios se transforma en tanto por ciento, y el tanto por ciento se normaliza de acuerdo con el rendimiento anual. El valor obtenido se introduce en el recuadro Panel (método SetLine).

El propio recuadro está construido de una forma bastante sencilla y se basa en el mismo complejo de clases gráficas que el panel CStrategy que aparece junto con el experto. El código del componente gráfico del experto se muestra más abajo:

//+------------------------------------------------------------------+
//|                                                        Panel.mqh |
//|                                 Copyright 2017, Vasiliy Sokolov. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Vasiliy Sokolov."
#property link      "https://www.mql5.com"
#include <Panel\ElChart.mqh>

class CPercentPanel : public CElChart
{
private:
   CArrayObj  m_fields;
   CArrayObj  m_values;
public:
   
   CPercentPanel(void);
   void SetLine(int index, string field, string value);
};
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPercentPanel::CPercentPanel(void) : CElChart(OBJ_RECTANGLE_LABEL)
{
   Width(200);
   Height(200);
}
//+------------------------------------------------------------------+
//| Establece la línea                                               |
//+------------------------------------------------------------------+
void CPercentPanel::SetLine(int index,string field,string value)
{
   if(m_fields.Total() <= index)
   {
      CElChart* sfield = new CElChart(OBJ_LABEL);
      sfield.XCoord(XCoord()+10);
      sfield.YCoord(YCoord()+21*index+10);
      sfield.Text(field);
      m_fields.Add(sfield);
      m_elements.Add(sfield);
      
      CElChart* svalue = new CElChart(OBJ_LABEL);
      svalue.YCoord(YCoord()+21*index+10);
      svalue.XCoord(XCoord()+132);
      svalue.Text(value);
      svalue.TextColor(clrGreen);
      m_values.Add(svalue);
      m_elements.Add(svalue);
      if(IsShowed())
      {
         sfield.Show();
         svalue.Show();
      }
      Height(m_fields.Total()*20 + m_fields.Total()*2 + 10);
   }
   else
   {
      CElChart* el = m_fields.At(index);
      el.Text(field);
      el = m_values.At(index);
      el.Text(value);
   }
   ChartRedraw();
}

Después de que este experto sea compilado e iniciado en uno de los gráficos del contrato de futuros Si, deberá aparecer un recuadro así:

Perfil de la tasa de interés Rublo/Dólar en forma de recuadro

Como podemos ver por el recuadro, las tasas de interés en prácticamente todas las secciones temporales son iguales y están un poco por encima del 7% anual. El futuro más cercano muestra una tasa de interés un poco superior. 

Un observación importante: antes de iniciar el experto en el gráfico, asegúrese de que las cotizaciones de todos los futuros necesarios están disponibles y han sido cargadas con anterioridad. En caso contrario, el resultado puede ser indeterminado.

Conclusión

Hemos analizado la nueva clase CSymbol incluida en las clases de CStrategy. Gracias a esta clase, resulta más sencillo trabajar con los instrumentos comerciales, obteniendo varias propiedades de los mismos. Gracias a CSymbol, hemos construido un indicador bastante interesante y revelador del perfil de la tasa de interés.  Este ejemplo es muy representativo. Hemos obtenido con facilidad multitud de propiedades de los objetos CSymbol, y el propio cálculo no ha resultado tan complicado. El experto ha manipulado simultáneamente seis instrumentos, sin embargo, el código no ha aumentado por ello. Gracias a que CStrategy se hereda de CObject, los ejemplares de esta clase son fáciles de ubicar en las colecciones estándar, haciendo el procesamiento de datos bastante escalable y universal. Además, CStrategy ha delegado en CSymbol la funcionalidad menos propia de ella, gracias a lo cual, la propia clase CStrategy es ahora más ligera y manejable.


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

Archivos adjuntos |
El patrón Bandera El patrón Bandera
En el artículo se estudiarán los patrones de Bandera, Banderín, Cuña, Formación en Rectángulo, Triángulo decreciente, Triángulo creciente. Se analizarán sus semejanzas y diferencias, se crearán indicadores para su búsqueda en el gráfico y un indicador-probador para evaluar rápidamente su efectividad.
Asesor Experto multiplataforma: Gestión de capital (money management) Asesor Experto multiplataforma: Gestión de capital (money management)
En este artículo se analiza la implementación de la gestión de capital (money management) en el Asesor Experto multiplataforma. Las clases de la gestión de capital se encargan del cálculo del tamaño del lote que el Asesor Experto usará para entrar en la siguiente operación.
Asesor Experto multiplataforma: Filtros temporales Asesor Experto multiplataforma: Filtros temporales
En este artículo se analiza la implementación de diferentes métodos de la filtración temporal en el Asesor Experto multiplataforma. Las clases de los filtros temporales se ocupan de verificar la correspondencia de un determinado momento de tiempo a un determinado período definido en los ajustes.
Patrones disponibles al comerciar con cestas de divisas. Parte III Patrones disponibles al comerciar con cestas de divisas. Parte III
Este es el artículo final dedicado a los patrones que aparecen al comerciar con cestas de parejas de divisas. Se han analizado varios indicadores combinados de tendencia, así como la aplicación de las construcciones gráficas habituales.