![Der Objekt-Ansatz in MQL](https://c.mql5.com/i/articles/overlay.png)
Der Objekt-Ansatz in MQL
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.
![](https://c.mql5.com/2/15/1.png)
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);
… …
![](https://c.mql5.com/2/15/2.png)
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:
![](https://c.mql5.com/2/15/3.png)
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 system … int 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 Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1499
![Der Indikator Taichi - Eine simple Methode zur Formalisierung der Werte von Ichimoku Kinko Hyo.](https://c.mql5.com/2/15/509_25.gif)
![So können Sie Ihre eigenen Optimierungskriterien implementieren](https://c.mql5.com/2/14/460_29.jpg)
![Die Anzeige eines Nachrichtenkalenders](https://c.mql5.com/2/15/520_12.gif)
![MQL4 Sprache für Einsteiger. Einführung](https://c.mql5.com/2/14/404_19.gif)
![MQL5 - Sprache von Handelsstrategien, eingebaut ins Kundenterminal MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.