MetaTrader 5 herunterladen

Der Objekt-Ansatz in MQL

9 Februar 2016, 07:20
o_o
0
485

Einführung

Dieser Artikel wird in erster Linie für alle Programmierer von Interesse sein – sowohl Neueinsteiger als auch Profis, die mit der MQL-Umgebung arbeiten. Darüber hinaus wäre es sinnvoll, wenn dieser Artikel von den Entwicklern und Planern der MQL-Umgebung gelesen werden würde, weil hierin nämlich einige Fragen thematisiert werden, die vielleicht in die künftigen Implementierungen von MetaTrader und MQL miteinbezogen werden könnten. Teilweise können ähnliche Ideen in den folgenden Artikeln gefunden werden: Universal Expert Advisor Template und Sending Trading Signals in a Universal Expert Advisor

Also,

Einer der Nachteile von MQL, wenn Sie mich als Programmierer fragen würden, besteht in der Absenz des Objekt-Prinzips zur Konstruktion des Modells des Handelssystems. Die Entwickler von MQL bieten uns hierfür zwei Lösungsansätze an: Der Aufruf von externen Funktionen, oder die Benutzung des Ordnungsparameters MAGIC für die Identifizierung der korrekten Reihenfolge.

Tatsächlich benötigen wir keine Identifizierungsmaßnahmen, falls nur ein System auf einem Konto läuft. Aber wenn uns das Programm die Möglichkeit dazu gibt, ein Konto mit mehreren automatisierten Handelssystemen zu verbinden, dann können wir dies nicht ohne die Hilfe von MAGIC tun. Selbst wenn wir externe Funktionen aufrufen, dann müssen wir diese näher bestimmen. Natürlich können wir hierzu ein Datenfeld OrderTicket einfügen und festlegen, dass dieses Datenfeld zu einem bestimmten Handelssystem gehört. Aber wie wir bereits wissen, ist es bei einigen Handelsfirmen so, dass sich das Orderticket im Falle von Swaps ändert (tatsächlich wird hierbei eines geschlossen, und ein anderes geöffnet). Das ist auch der Grund dafür, weshalb wir nicht ohne die Hilfe von MAGIC auskommen.

Während also die Entwickler emsig daran arbeiten, die Programmiersprache MQL weiter zu verbessern, um sie noch flexibler zu gestalten, so möchten wir versuchen, bereits jetzt den Objekt-Ansatz zu implementieren, um damit unser Handelsmodell aufzubauen.

Dies ist ein Handelssystem, das mit meinem Objekt-Modell übereinstimmt. Natürlich ist es nicht universell – aber bis jetzt sehe ich einfach keine anderen realisierbaren Vorgehensweisen.


Lassen Sie uns also einmal dieses Modell analysieren.

A). Signal-System (SS).

Der Sinn und Zweck dieses Moduls besteht darin, eingehende Preise zu empfangen und zu interpretieren. Normalerweise ist das " Objekt " des Signalsystems der Einsatz von Indikatoren, beispielsweise gleitende Durchschnitte. Als Ergebnis der Verarbeitung von Preisen und Indikatorenwerten produziert " das Objekt " (oder der Zeichenträger ) verschiedene Signale zum Einstieg/Ausstieg, für Modifikationen von Orders etc.

Der Zeichenträger formt seine Signale und sendet sie zu einem anderen Objekt aus dem Modul Einstieg/Ausstieg (EE).

Das Setzen des Zeichenträgers in MQL gestaltet sich recht einfach.

1. Definition eines globalen Identifizierungsmerkmals mithilfe von #define.

Es ist besser, nicht auf konsekutive Zahlen wie etwa 1, 2, 3, 4... zurückzugreifen, sondern in Schritten von 5-10 vorzugehen, sodass wir in einem Expert Advisor ein Signal für mehrere Prozesse benutzen können (siehe zweites Modul).

//+------------------------------------------------------------------+
//|                                                      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. In der globalen Funktion dieses Moduls sollten wir dann diesen Verarbeitungsvorgang aktivieren.

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. Der letzte Schritt besteht in der Beschreibung der Funktionen.

Hier ist ein Beispiel für die Verarbeitung von Signalen eines Objektes, welches die Funktionen des Indikators Envelope vererbt bekommen hat.

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
}

Auf diese Weise erhalten wir ein Modul, welches die verschiedenen Objekt-Signale enthält.


B). Die Objekte des Blocks EE haben minimale Aufgaben:
Zuerst interagieren diese Objekte mit den Objekt-Signalen – behalten Sie diese im Auge. Die Lebensspanne und Interaktion gestaltet sich wie folgt :
Überprüfung des Zeichenträgers-> falls es irgendwelche positiven Signale gibt, werden Positionen eröffnet/geschlossen/verändert -> Die Zuteilung von Kontrollfunktionen an Objekte im Modul PS.
Alle Objekte im Modul EE verfügen über einen Präfix-Prozess…, der das Verhalten der Module näher bestimmt.

Ein Beispiel:

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

Jedes Variante einer Handelssystemklasse (wir alle verstehen das und benutzen es in unseren Modulen) muss ihre eigenen individuellen Charakteristika besitzen, wie etwa Gewinn oder Verlustbegrenzung, ihre eigene Kapitalverwaltung, sowie weitere zusätzliche Parameter, die in verschiedenen angehängten Varianten implementiert werden etc.

Bei der Implementierung dieser Funktion habe ich versucht, mehrere Varianten dieses Ansatzes durchzuspielen, und die für das System von MQL passende Variante besteht meiner Meinung nach darin, einen zweidimensionalen Zeichenträger einzurichten. Nachfolgend lesen Sie seine Beschreibung:

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];

wobei nSignal der Identifikation der Objekt-Signale dient.

Ein Beispiel :

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

Je nach Belieben können Sie die Anzahl der eingestellten Parameter bei dieser Zeichenträger-Struktur verändern.

Nachdem wir also die Parameter eingestellt haben, rufen wir die Funktionen der Zeichenträger-Verarbeitung auf. Oder um es in anderen Worten zu sagen, wir interagieren mit dem Signal-System . Dies wird mithilfe meiner favorisierten Funktion start()
durchgeführt.

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

Wie aus dem Schema ersichtlich wird, haben wir in dem Handelssystem vier registrierte Zeichenträger und drei Beobachter. Der Träger basiert auf seiner eigenen Variante der Preisinterpretation.

Beispielsweise sendet der Zeichenträger 1 Signale aufgrund der Analyse des Indikators MACD. Beobachter 1 seinerseits eröffnet, nachdem er diese Signale erhalten hat, Orders nach einem simplen Schema ProcessSimple.

Die Beobachter 2 und 3 sind etwas schwieriger. Jeder einzelne davon kontrolliert die Signale von zwei Zeichenträgern. Und konsequenterweise gestaltet sich der Ansatz zur Ordereröffnung dadurch etwas anders

Nachdem wir also die Parameter des Beobachters gesetzt haben und ihm einen Zeichenträger zugeordnet haben, müssen wir nun die Eröffnung von Positionen kontrollieren und nachverfolgen.

" Verantwortlich " für den Zustand von eröffneten Orders sind die Objekte des Moduls Position Support (PS).


C). Block PS ist meiner Meinung nach die interessanteste von ihnen, und sie ist nicht weniger bedeutsam als die Zeichenträger.

Hierbei werden verschiedene Nachverfolgungsvarianten implementiert: Eröffnung anstehender Orders, Positionsunterstützung und Festsetzung, Kontrolle des erzielten Gewinns und Verlustes usw. Solch ein PS sollte adäquat auf EE-Signale reagieren, was das Verlassen des Marktes im Falle verlustbringender Positionen anbelangt – und zwar mit einem minimalen Verlust.

Es gibt eine interessante Datenbank von Nachverfolgungen auf dieser Seite Library of Functions and Expert Advisors for trailing / Yury Dzyuban. Alle Typen der Nachverfolgung lassen sich ganz einfach an das System anhängen.

Zur Vereinfachung starten alle unterstützenden Objekte mit dem Präfix Trailing…

Dies funktioniert nach dem folgenden Schema:


Der Aufruf und die Übertragung der Kontrolle von einem Beobachter zur Nachverfolgung funktioniert in derselben Art und Weise mit der gleichen Funktion start()

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

Dies war lediglich ein Beispiel einer Variante des Objekt-Ansatzes zum Aufbau eines Systems. Für all jene, die es vielleicht benutzen möchten.

Und noch einmal möchte ich gerne die Entwickler von MQL darum bitten, die Optionen, welche ihre Programmiersprache bietet, zu erweitern. Als ein Beispiel präsentiere ich hier eine Variante der Implementierung von Objektklassen in der Programmiersprache 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
}

Die Systemlogik in der Programmiersprache MQL würde sich gar nicht so unterschiedlich darstellen: Alle Funktionen werden global. Und zur Unterscheidung von Orders eines Handelssystems von den Orders von einem anderen Handelssystem benötigen wir dann einen zusätzlichen Parameter, nämlich SignalID (zum Beispiel MAGIC) in allen Funktionen, die mit Orders arbeiten.


Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/1499

Beigefügte Dateien |
Signals.mqh (30.61 KB)
TradeSystem.mq4 (17.78 KB)
Traling.mqh (21.5 KB)
So können Sie Ihre eigenen Optimierungskriterien implementieren So können Sie Ihre eigenen Optimierungskriterien implementieren

In diesem Artikel finden Sie ein Beispiel für die Optimierung nach dem Kriterium Gewinn/Kreditinanspruchnahme, wobei die Resultate in einer Datei zusammengefasst werden, die für die Verwendung mit einem standardisierten "Expert Advisor" - dem Gleitenden Durchschnitt - geeignet ist.

MQL4 Sprache für Einsteiger. Einführung MQL4 Sprache für Einsteiger. Einführung

Diese Artikelreihe ist für Trader gedacht, die nichts über Programmierung wissen, aber den Wunsch haben MQL4 so schnell wie möglich mit minimal aufgewendeter Zeit und Anstrengung zu lernen. Wenn Sie Angst vor solchen Begriffen wie "Objektorientierung" oder "dreidimensionale Arrays" haben, ist dieser Artikel das was Sie brauchen. Die Lektionen sind für ein maximal schnelles Ergebnis entworfen. Darüber hinaus werden die Informationen in verständlicher Form geliefert. Wie werden nicht zu tief in die Theorie gehen, aber Sie werden den praktischen Nutzen bereits ab der ersten Lektion gewinnen.

Der Indikator Taichi - Eine simple Methode zur Formalisierung der Werte von Ichimoku Kinko Hyo. Der Indikator Taichi - Eine simple Methode zur Formalisierung der Werte von Ichimoku Kinko Hyo.

Finden Sie, dass es schwierig ist, Ichimoku-Signale zu interpretieren? Dieser Artikel stellt einige Prinzipien vor, mit deren Hilfe man bestimmte Werte und Signal von Ichimoku Kinko Hyo standardisieren kann. Zur Visualisierung ihrer Benutzung hat sich der Autor für das Währungspaar EURUSD entschieden, was allein seinen eigenen Präferenzen geschuldet ist. Natürlich kann dieser Indikator in Verbindung mit jedem beliebigen Währungspaar eingesetzt werden.

Die Anzeige eines Nachrichtenkalenders Die Anzeige eines Nachrichtenkalenders

Dieser Artikel enthält eine Anleitung dazu, wie man einen einfachen und praktischen Indikator erstellt, der in einem Arbeitsbereich die wichtigsten ökonomischen Ereignisse von externen Internetquellen anzeigt.