English Русский 中文 Deutsch 日本語 Português
El enfoque orientado a objetos en MQL

El enfoque orientado a objetos en MQL

MetaTrader 4Sistemas comerciales | 30 marzo 2016, 15:36
1 047 0
---
---

Introducción

Este artículo puede resultar muy interesante para los programadores que sean principiantes o expertos y que trabajan en el entorno MQL. Me gustaría también que lo leyeran los desarrolladores del entorno MQL, ya que las preguntas que se plantean aquí pueden convertirse en proyectos para las futuras implementaciones de MetaTrader y MQL. En cierto modo, se pueden encontrar en este artículo algunos conceptos parecidos a la plantilla de un Asesor Experto universal y el envío de señales de trading en un Asesor Experto universal

Por lo tanto,

En mi opinión como programador, una de las desventajas de MQL es la ausencia del enfoque orientado a objetos en la construcción del modelo del sistema de trading. Los desarrolladores de MQL nos ofrecen dos soluciones: usar las llamadas a funciones externas o usar el parámetro MAGIC para identificar la pertenencia de la orden.

De hecho, la identificación de órdenes no es necesaria cuando opera un sólo sistema en una sola cuenta. Pero no podemos hacer nada sin MAGIC cuando disponemos de un programa capaz de conectar varios sistemas de trading automatizado a una sola cuenta. Incluso cuando se llama a las funciones externas, necesitamos identificar las órdenes. Podemos construir una matriz OrderTicket e identificar únicamente la matriz que pertenece a un sólo sistema de trading, pero teniendo en cuenta que en algunas compañías de borkerage el ticket de la orden cambia con el swap (en realidad se cierra uno y se abre otro). Es por ello que que no podemos hacer nada sin usar MAGIC.

Así que mientras los desarrolladores están ocupados en mejorar el lenguaje MQL haciéndolo más flexible, vamos a tratar de implementar el enfoque orientado a objetos en la construcción de un modelo de trading.

Este es un sistema de trading según mi modelo orientado a objetos. No es universal, pero hasta el momento no veo otros enfoques.


Así que vamos a analizar este modelo.

A). Sistema de señales (SS)

El objeto de este módulo procesa e interpreta las cotizaciones entrantes. En general, el "objeto" del sistema de señales es un conjunto de indicadores, por ejemplo, promedios móviles. Como resultado del procesamiento de las cotizaciones y de los valores de los indicadores, el "objeto" (o semáforo) genera señales para entrar/salir o modificar órdenes, etc.

El semáforo genera la señal y la envía a otro objeto desde el módulo Entrada/Salida (ES).

Configurar el semáforo en MQL es bastante sencillo.

1. Establecer un identificador global mediante #define.

En lugar de definir números consecutivos del tipo 1, 2, 3, 4..., es mejor utilizar 5-10, de modo que podamos usar una señal para varios procesos en el Asesor Experto (ver el segundo módulo).

//+------------------------------------------------------------------+
//|                                                      Signals.mqh |
//|                                 Copyright © 2007 Сергеев Алексей |
//|                                                los@we.kherson.ua |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, Сергеев Алексей "
#property link      "mailto: los@we.kherson.ua"
#property library
 
#define BLACKSYS   10
#define BORCHAN    20
#define ELDER      80
#define ENVELOP    90

2. Después, en la función global de este módulo tenemos que habilitar su procesador.

int CheckSignal(bool bEntry, int SignalID)
{
      switch (SignalID)
      {
                  case BLACKSYS:             return (BlackSys(bEntry)); break;
                  case BORCHAN:              return (BorChan(bEntry)); break;
                  case ELDER:                   return (Elder(bEntry)); break;
                  case ENVELOP:              return (Envelop(bEntry)); break;
                  default:                                     return (-1);
      }
}

3. En el último paso se describen las funciones.

Este es un ejemplo de un procesador de señales de un objeto que hereda las características del indicador Envelope.

int Envelope(bool bEntry)
{
      int MA=21;
      double Deviation=0.6;
      int Mode=MODE_SMA;//0-sma, 1-ema, 2-smma, 3-lwma
      int Price=PRICE_CLOSE;//0-close, 1-open, 2-high, 3-low, 4-median, 5-typic, 6-wieight
      
      double envH0, envL0, m0;
      double envH1, envL1, m1;
      envH0=iEnvelopes(NULL, 0, MA, Mode, 0, Price, Deviation, MODE_UPPER, 0); 
      envL0=iEnvelopes(NULL, 0, MA, Mode, 0, Price, Deviation, MODE_LOWER, 0); 
      envH1=iEnvelopes(NULL, 0, MA, Mode, 0, Price, Deviation, MODE_UPPER, 1); 
      envL1=iEnvelopes(NULL, 0, MA, Mode, 0, Price, Deviation, MODE_LOWER, 1); 
 
      m0 = (Low[0]+High[0])/2;          m1 = (Low[1]+High[1])/2;
      //----- condition for operation execution
      if (bEntry)   //for opening
      {          
                  if (envH0<m0 && envH1<m1) return (OP_SELL);
                  if (envL0>m0 && envL1>m1) return (OP_BUY);
      }
      else //for closing
      {
                  if (envH0<m0 && envH1<m1) return (OP_BUY);
                  if (envL0>m0 && envL1>m1) return (OP_SELL);
      }
 
   return (-1); //no signal
}

De este modo obtenemos un módulo que contiene distintas "señales-objetos".


B). Los objetos del bloque ES hacen un mínimo de tareas:
En primer lugar, interactúan con las "señales-objetos"; obsérvelos. El ciclo de vida y la interacción son los siguientes:
Comprobar el semáforo -> si hay cualquier señal positiva, abrir/cerrar/modificar posiciones -> pasar el control a los objetos en el módulo SP (soporte de posición).
Todos los objetos del módulo ES llevan el prefijo Process..., que determina su comportamiento de manera más exacta.

Por ejemplo:

ProcessAvgLim         //  -  the object processes signals with opening pending limit-orders and positions averaging
ProcessTurn           //  -  the object processes signals with position turning

Cada parte de un sistema de trading debe tener sus propias características (lo sabemos todos y lo usamos en nuestros modelos), tales como el beneficio, el stop-loss y la gestión del dinero, además de otros parámetros implementados en distintas opciones de trailing, etc.

Al implementar estas características he probado con varias opciones y la más satisfactoria en mi opinión es la creación de una matriz de dos dimensiones. Esta es su descripción:

double SysPar[nSignal][11];
 
#define _TP        0 // Profit
#define _NullTP    1 // profit level, after which we set into losslessness 
#define _NullTP2   2 // profit level, after which we set into losslessness 
#define _TS        3 // distance of the trailing stop 
#define _NullSL    4 // level, after achieving which the expected profit is transfered into opening point
#define _SL        5 // level, after achieving which the expected profit is transfered into opening point
#define _dSL       6 // the initial step upon the opening level of the next order in the position support
#define _dStep     7 // The step is increased in .. times upon the level of the next opening 
#define _dLot      8 // In how many times (as compared to the last one) we increase the lot on the next one 
#define _nLot      9 // In how many times (as compared to the initial one) we increase the lot on the next one
 
string SysParName[nSignal];

donde nSignal es el identificador de las "señales-objetos".

Por ejemplo:

SysPar[ENVELOP][_TS] = 40.0;    // distance of the trailing stop 
SysPar[ENVELOP][_NullSL] = 20.0;// level, after achieving which the expected profit is transfered into opening point
SysPar[ENVELOP][_SL] = 70;      // changing stop-loss

Puede incrementar el número de parámetros establecidos en la estructura de esta matriz a su conveniencia.

Así que después de ajustar los parámetros llamamos a la función de procesamiento del semáforo. En otras palabras, interactuamos con el sistema de señales. Esto se hace en mi función favorita start()

void start()
{
      ProcessAvgLim(ENVELOP, ENVELOP, Green, Red);
… …

Como se puede observar en el esquema, tenemos 4 semáforos y 3 observadores en el sistema de trading. Cada semáforo se basa en su propia interpretación de las cotizaciones.

Por ejemplo, el semáforo 1 envía señales al analizar el indicador MACD. Después de recibir estas señales, el observador 1 abre las órdenes en un esquema sencillo ProcessSimple.

Los observadores 2 y 3 son más complicados. Cada uno controla las señales de dos semáforos. Por lo tanto, el enfoque de apertura de órdenes es distinto.

Así que después de establecer los parámetros del observador y conectarlos a un semáforo, tenemos que controlar y mantener las posiciones abiertas.

Los objetos del módulo Soporte de posición (SP) son "responsables" del estado de las órdenes abiertas.


C). En mi opinión, el bloque SP es el más interesante y no menos importante que los semáforos.

Se implementan aquí distintas opciones de trailing, se abren las órdenes pendientes, se implementa también el soporte y la resistencia de las posiciones, el control del beneficio y las perdidas y así sucesivamente. Este SP debe responder adecuadamente a las señales de ES sobre la salida del mercado en el caso de posiciones perdedoras con un mínimo de pérdidas.

Hay una interesante librería de trailing en este sitio Librería de funciones y Asesores Expertos para el trailing / Yury Dzyuban. Se pueden añadir todos los tipos de trailing al sistema fácilmente.

Para facilitar la percepción, todos los objetos de soporte empiezan con el prefijo Trailing...

Su esquema es el siguiente:


Se lleva a cabo el envío del control de llamadas entre el observador y el trailing en la misma función start()

void start()
{
      ProcessSimple(MACD, MACD, Black, Plum); TrailingSimple(MACD, Black, Plum);
      ProcessAvgLim(ENVELOPE, ENVELOPE, Green, Red);  TrailingAvgLim(ENVELOPE, Green, Red);
}

Esto fue un ejemplo del enfoque orientado a objetos para la construcción de un sistema. Lo puede utilizar quien quiera.

Una vez más, me gustaría pedir a los desarrolladores de MQL que amplíen las opciones que ofrece el lenguaje. Este es un ejemplo de implementación de clases de objetos en el lenguaje C++.

struct SystemParam
{
    double TP;        // profit
    double NullTP;    // profit level, after which we set into losslessness 
    double NullTP2;   // profit level, after which we set into losslessness a set of one-direction orders
    double TS;        // distance of the trailing stop 
    double NullSL;    // loss level, at which we transfer the expected profit into losslessness
    double SL;        // stop-loss
    double dSL;       // a step upon the opening level of the next order for the position support
    double dStep;     // In how many times we increase the step upon the opening level of the next order
    double dLot;      // In how many times we increase the lot on the next order
}
 
 
class MTS 
{
    public:
    string m_NameTS;    // system name (for making comments for the order)
    int m_SignalID;     // identifier of trading signals (for semaphore inquiry)
 
    long int Tickets[1000];    // array of order tickets, selected upon m_SignalID (MAGIC)
 
    SystemParam SysPar;    // Trading system parameters
    color ClrBuy;         // color for indicating BUY order
    color ClrSell;        // color for indicating SELL order
 
    // Initialization
    void MyMTS ();            // standard function that sets initial values of the system
    void MyMTS (int aSignalID, int nProcessMode, int nTrailingMode); // standard function 
                                    // that sets initial values of the system
    
    
    // Implementation
    int CheckSignal();     //function of checking state of market signals
 
    // Processing
    int m_nProcessMode;          // identifier of observation mode
    int m_nTrailingMode;         // identifier of trailing mode
    void Process();         // EE function - processing CheckSignal()
    void Trailing();        // PS function - order trailing
 
    // Special functions
    bool CreatTicketArray(int dir);    // creating an array of tickets, selected upon m_SignalID (MAGIC) 
                    // and desired type dir: buy, sell, buylim, buystop, sellim, sellstop
    bool ArrangeOrderBy(int iSort);  // arranging array Tickets upon the parameter (date, profit, price...)
 
};
 
…
 
MTS MyTS; // our trading systemint init()  
{   
…
    MyTS.m_SignalID = SIGNAL_MACD; // our system is based on MACD signals
    MyTS.m_NameTS = "MACD";
    MyTS.SysPar.TP = 500;    
    MyTS.SysPar.NullTP = 20;
    MyTS.SysPar.TS = 50;
    MyTS.SysPar.SL = 1000;
 
    MyTS.SetProcess (MODE_AVGLIM);
    MyTS.SetTrailing (MODE_AVGLIM);
…
}
 
void start()
{
…
    MyTS.Process ();        
    MyTS.Trailing ();
…
}
 
…
 
void MTS::Process()
{
…
    int Signal = CheckSignal(true, m_SignalID); //calling the global function of signal processing
    if (Signal == -1) return; // if no signal, do nothing
    
//----- for buying
    if(Signal == OP_BUY)
    {    
    }
 
    if(Signal == OP_SELL)
    {    
    }
…
}
 
…
// global processor of semaphores
 
int CheckSignal(bool bEntry, int SignalID)
{
    switch (SignalID)
    {
        case ELDER:    return (Elder(bEntry)); break;
        case ENVELOP:    return (Envelop(bEntry)); break;
        case LAGUER:    return (Laguer(bEntry)); break;
        case MACD:    return (Macd(bEntry)); break;
        …
    }
}
 
// calling a certain semaphore
int Macd(bool bEntry)
{
    double MACDOpen=3;
    double MACDClose=2;
    double MA=26;
    int MODE_MA    = MODE_EMA; // method of the calculation of averages
    int PRICE_MA   = PRICE_CLOSE; // method of the calculation of averages
    int PERIOD     = PERIOD_H1; // the period to work with
 
    //parameters of averages
    double MacdCur, MacdPre, SignalCur;
    double SignalPre, MaCur, MaPre;
 
    //---- get the value
    MacdCur=iMACD(NULL,0,8,17,9,PRICE_MA,MODE_MAIN,0);   MacdPre=iMACD(NULL,0,8,17,9,PRICE_MA,MODE_MAIN,1);
    SignalCur=iMACD(NULL,0,8,17,9,PRICE_MA,MODE_SIGNAL,0);   SignalPre=iMACD(NULL,0,8,17,9,PRICE_MA,MODE_SIGNAL,1);
    MaCur=iMA(NULL,0,MA,0,MODE_MA,PRICE_MA,0);   MaPre=iMA(NULL,0,MA,0,MODE_MA,PRICE_MA,1);
 
    //----- condition for the operation execution
    if (bEntry)   //for buying bEntry==true
    {     
        if(MacdCur<0 && MacdCur>SignalCur && MacdPre<SignalPre && MathAbs(MacdCur)>(MACDOpen*Point) && MaCur>MaPre) 
         return (OP_BUY);
        if(MacdCur>0 && MacdCur<SignalCur && MacdPre>SignalPre && MacdCur>(MACDOpen*Point) && MaCur<MaPre) 
         return (OP_SELL);
    }
    else //for closing bEntry==false
    {    
        if(MacdCur>0 && MacdCur<SignalCur && MacdPre>SignalPre && MacdCur>(MACDClose*Point)) 
         return (OP_BUY);
        if(MacdCur>0 && MacdCur<SignalCur && MacdPre>SignalPre && MacdCur>(MACDOpen*Point) && MaCur<MaPre) 
         return (OP_BUY);
 
        if(MacdCur<0 && MacdCur>SignalCur && MacdPre<SignalPre && MathAbs(MacdCur)>(MACDClose*Point))  
         return (OP_SELL);
        if(MacdCur<0 && MacdCur>SignalCur && MacdPre<SignalPre && MathAbs(MacdCur)>(MACDOpen*Point) && MaCur>MaPre) 
         return (OP_SELL);
    }
 
    return (-1); //no signal
}

La lógica del sistema en el lenguaje MQL no sería muy distinta. Todas las funciones se vuelven globales. Y para distinguir las órdenes de un sistema de trading de las órdenes de otro sistema tendremos que añadir el parámetro SignalID (es decir, MAGIC) en todas las funciones que trabajan con órdenes.

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

Archivos adjuntos |
Signals.mqh (30.61 KB)
TradeSystem.mq4 (17.78 KB)
Traling.mqh (21.5 KB)
Lenguaje MQL4 para principiantes. Indicadores personalizados (Primera parte) Lenguaje MQL4 para principiantes. Indicadores personalizados (Primera parte)
Este es el cuarto artículo de la serie "El lenguaje MQL4 para Principiantes". Hoy vamos a aprender a escribir indicadores personalizados. Vamos a familiarizarnos con la clasificación de las funciones del indicador, veremos cómo estas características influyen en el indicador, aprenderemos nuevas funciones y la optimización y finalmente, vamos a escribir nuestros propios indicadores. Además, al final del artículo podrá encontrar consejos sobre el estilo de programación. Si este es el primer artículo "para principiantes" que está leyendo, quizá sería mejor que leyera los anteriores. Además, asegúrese de que ha entendido correctamente el material anterior, porque en este artículo no se explican los conceptos básicos.
Cómo implementar sus propios criterios de optimización Cómo implementar sus propios criterios de optimización
En este artículo veremos la implementación de los criterios del beneficio/disminución de fondos, con los resultados resumidos en un archivo desarrollado para el Asesor Experto Moving Average (Promedio móvil).
Indicador Taichi - un sencillo método para interpretar los valores de Ichimoku Kinko Hyo. Indicador Taichi - un sencillo método para interpretar los valores de Ichimoku Kinko Hyo.
¿Es difícil interpretar las señales Ichimoku? Este artículo presenta algunos principios para interpretar los valores y señales de Ichimoku Kinko Hyo. Para la visualización de su funcionamiento el autor escogió el par de divisas EURUSD en base a sus propias preferencias. Sin embargo, se puede usar el indicador con cualquier par de divisas.
Lenguaje MQL4 para principiantes. Los indicadores técnicos y las funciones integradas Lenguaje MQL4 para principiantes. Los indicadores técnicos y las funciones integradas
Este es el tercer artículo de la serie "El lenguaje MQL4 para principiantes". Vamos a aprender a utilizar las funciones incorporadas en MQL4 y las funciones para trabajar con los indicadores técnicos. Estas últimas serán de vital importancia para el desarrollo posterior de sus propios Asesores Expertos e indicadores. Además, veremos un ejemplo sencillo sobre cómo hacer el seguimiento de las señales de trading para entrar al mercado, o para que nos entendamos, cómo utilizar correctamente los indicadores. Al final del artículo, aprenderá algo nuevo e interesante sobre el propio lenguaje.