English Русский 中文 Español 日本語 Português 한국어 Français Italiano Türkçe
Elementare Handelssysteme unter Verwendung von Semaphorindikatoren

Elementare Handelssysteme unter Verwendung von Semaphorindikatoren

MetaTrader 5Handelssysteme | 26 Januar 2016, 14:49
811 0
Nikolay Kositsin
Nikolay Kositsin

Einleitung

Bei Semaphor- oder Signalindikatoren handelt es sich um äußerst einfache Signalgeber für den Eintritt in oder den Rückzug aus dem Markt. Erscheint auf dem aktuellen Balken das Signal für einen Abschluss, wird in dem Diagramm für das betreffende Finanzinstrument ein entsprechendes Zeichen abgebildet, das im Weiteren als Bedingung für den Abschluss eines Geschäfts dienen kann.

Es gibt eine große Menge vergleichbarer Indikatoren, das Wesen des ursprünglichen, auf der Grundlage dieser Indikatoren aufgebauten Handelssystems selbst bleibt jedoch absolut unverändert. Daraus erwuchs die Idee, es in der allereinfachsten und allgemeingültigsten Form umzusetzen. Das ermöglicht uns, das gewonnene Ergebnis zukünftig mit nur geringfügigen Anpassungen mit allen vergleichbaren Indikatoren zu verwenden.

Abb. 1. Der Semaphor-Signalindikator ASCtrend

Abb. 1. Der Semaphor-Signalindikator ASCtrend

Abb. 2. Der Indikator ASCtrend. Handelssignal für den Abschluss eines Geschäfts 

Abb. 2. Handelssignal für den Abschluss eines Geschäfts unter Verwendung des Semaphor-Signalindikators ASCtrend


Beispiele typischer Semaphor-Signalindikatoren

Derzeit sind in der Codebasis eine Menge derartiger Indikatoren vorhanden. In diesem Beitrag werde ich lediglich einige Hinweise auf deren Ausgangsressourcen geben:

Neben der Gruppe der Semaphor-Signalindikatoren gibt es auch noch die der Semaphor-Trendindikatoren.

Abb. 3. Handelssignale anhand des geglätteten Indikators Heiken_Ashi_Smoothed 

Abb. 3. Der Semaphor-Trendindikator

 

Abb. 4. Handelssignal für den Abschluss eines Geschäfts unter Verwendung des geglätteten Indikators Heiken_Ashi_Smoothed

Abb. 4. Handelssignal für den Abschluss eines Geschäfts unter Verwendung des geglätteten Indikators Heiken_Ashi_Smoothed

In Handelssystemen, die diese Indikatoren nutzen, ändert sich der Programmcode zum Abrufen dieser Signale leicht, der Code des Expert-Systems selbst bleibt jedoch nahezu unverändert.

Beispiele typischer Semaphor-Signalindikatoren

Die Codebasis enthält mehr als genug dieser Indikatoren. In diesem Beitrag werde ich lediglich einige Hinweise auf deren Ausgangsressourcen geben:

 

Ausgangsdaten zum Aufbau eines Handelssystems

  1. Semaphorindikator mit den Eingangsparametern, die in dem Expert-System vorhanden sein müssen;
  2. Aufstellung weiterer Eingangshandelsparameter für das Expert-System:
    • der Anteil des für den Abschluss eingesetzten Einlagekapitals;
    • die Höhe der Stop Loss- und der Take Profit-Grenze (bei einem Wert von Null sind Pending Orders nicht zu verwenden);
    • der Schwund (höchste zulässige Abweichung des veranschlagten Abschlusskurses von dem tatsächlichen);
    • die Kennziffer des Balkens, von dem die Handelssignale abgerufen werden;
    • die Genehmigung zur Eröffnung „langer“ bzw. „kurzer“ Positionen;
    • die Genehmigung zur zwangsweisen Schließung „langer“ bzw. „kurzer“ Positionen aufgrund von Indikatorsignalen.

Es wäre freilich wesentlich einfacher, die Anweisungen zum Abschluss von Geschäften mithilfe universeller Handelsfunktionen zu erteilen. Diese Funktionen sind jedoch recht vielschichtig, weshalb sie in eine eigene Bibliothek verpackt werden müssen, um den zu erstellenden Programmcode so einfach wie möglich zu gestalten.

Der Programmcode eines Expert-Systems, in dem das Semaphor-Handelssystem umgesetzt wird:

//+------------------------------------------------------------------+
//|                                                 Exp_ASCtrend.mq5 |
//|                             Copyright © 2011,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, Nikolay Kositsin"
#property link      "farria@mail.redcom.ru"
#property version   "1.00"
//+----------------------------------------------+
//| Expert Advisor indicator input parameters    |
//+----------------------------------------------+
input double MM=-0.1;             // Share of a deposit in a deal, negative values - lot size
input int    StopLoss_=1000;      // Stop loss in points
input int    TakeProfit_=2000;    // Take profit in points
input int    Deviation_=10;       // Max. price deviation in points
input bool   BuyPosOpen=true;     // Permission to buy
input bool   SellPosOpen=true;    // Permission to sell
input bool   BuyPosClose=true;    // Permission to exit long positions
input bool   SellPosClose=true;   // Permission to exit short positions
//+----------------------------------------------+
//| ASCtrend indicator input parameters          |
//+----------------------------------------------+
input ENUM_TIMEFRAMES InpInd_Timeframe=PERIOD_H1; // ASCtrend indicator time frame
input int  RISK=4;                               // Risk level
input uint SignalBar=1;                          // Bar index for getting an entry signal
//+----------------------------------------------+

int TimeShiftSec;
//---- declaration of integer variables for the indicators handles
int InpInd_Handle;
//---- declaration of integer variables of the start of data calculation
int min_rates_total;
//+------------------------------------------------------------------+
//| Trading algorithms                                               | 
//+------------------------------------------------------------------+
#include <TradeAlgorithms.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---- getting ASCtrend indicator handle
   InpInd_Handle=iCustom(Symbol(),InpInd_Timeframe,"ASCtrend",RISK);
   if(InpInd_Handle==INVALID_HANDLE) Print(" Failed to get handle of ASCtrend indicator");

//---- initialization of a variable for storing a chart period in seconds  
   TimeShiftSec=PeriodSeconds(InpInd_Timeframe);

//---- initialization of variables of the start of data calculation
   min_rates_total=int(3+RISK*2+SignalBar);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//----
   GlobalVariableDel_(Symbol());
//----
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---- checking the number of bars to be enough for calculation
   if(BarsCalculated(InpInd_Handle)<min_rates_total) return;
   
//---- uploading history for IsNewBar() and SeriesInfoInteger() functions normal operation  
   LoadHistory(TimeCurrent()-PeriodSeconds(InpInd_Timeframe)-1,Symbol(),InpInd_Timeframe);

//---- declaration of local variables
   double DnVelue[1],UpVelue[1];
//---- declaration of static variables
   static bool Recount=true;
   static bool BUY_Open=false,BUY_Close=false;
   static bool SELL_Open=false,SELL_Close=false;
   static datetime UpSignalTime,DnSignalTime;
   static CIsNewBar NB;

//+----------------------------------------------+
//| Searching for deals performing signals       |
//+----------------------------------------------+
   if(!SignalBar || NB.IsNewBar(Symbol(),InpInd_Timeframe) || Recount) // checking for a new bar
     {
      //---- zeroing out trading signals
      BUY_Open=false;
      SELL_Open=false;
      BUY_Close=false;
      SELL_Close=false;
      Recount=false;

      //---- copy newly appeared data into the arrays
      if(CopyBuffer(InpInd_Handle,1,SignalBar,1,UpVelue)<=0) {Recount=true; return;}
      if(CopyBuffer(InpInd_Handle,0,SignalBar,1,DnVelue)<=0) {Recount=true; return;}

      //---- getting buy signals
      if(UpVelue[0] && UpVelue[0]!=EMPTY_VALUE)
        {
         if(BuyPosOpen) BUY_Open=true;
         if(SellPosClose) SELL_Close=true;
         UpSignalTime=datetime(SeriesInfoInteger(Symbol(),InpInd_Timeframe,SERIES_LASTBAR_DATE))+TimeShiftSec;
        }

      //---- getting sell signals
      if(DnVelue[0] && DnVelue[0]!=EMPTY_VALUE)
        {
         if(SellPosOpen) SELL_Open=true;
         if(BuyPosClose) BUY_Close=true;
         DnSignalTime=datetime(SeriesInfoInteger(Symbol(),InpInd_Timeframe,SERIES_LASTBAR_DATE))+TimeShiftSec;
        }

      //---- searching for the last trading direction for getting positions closing signals
      //if(!MQL5InfoInteger(MQL5_TESTING) && !MQL5InfoInteger(MQL5_OPTIMIZATION)) //if execution is set to "Random delay" in the Strategy Tester 
      if((BuyPosOpen && BuyPosClose || SellPosOpen && SellPosClose) && (!BUY_Close && !SELL_Close))
        {
         int Bars_=Bars(Symbol(),InpInd_Timeframe);

         for(int bar=int(SignalBar+1); bar<Bars_; bar++)
           {
            if(SellPosClose)
              {
               if(CopyBuffer(InpInd_Handle,1,bar,1,UpVelue)<=0) {Recount=true; return;}
               if(UpVelue[0]!=0 && UpVelue[0]!=EMPTY_VALUE)
                 {
                  SELL_Close=true;
                  break;
                 }
              }

            if(BuyPosClose)
              {
               if(CopyBuffer(InpInd_Handle,0,bar,1,DnVelue)<=0) {Recount=true; return;}
               if(DnVelue[0]!=0 && DnVelue[0]!=EMPTY_VALUE)
                 {
                  BUY_Close=true;
                  break;
                 }
              }
           }
        }
     }

//+----------------------------------------------+
//| Performing deals                             |
//+----------------------------------------------+
//---- Closing a long position
   BuyPositionClose(BUY_Close,Symbol(),Deviation_);

//---- Closing a short position   
   SellPositionClose(SELL_Close,Symbol(),Deviation_);

//---- Buying
   BuyPositionOpen(BUY_Open,Symbol(),UpSignalTime,MM,0,Deviation_,StopLoss_,TakeProfit_);

//---- Selling
   SellPositionOpen(SELL_Open,Symbol(),DnSignalTime,MM,0,Deviation_,StopLoss_,TakeProfit_);
//----
  }
//+------------------------------------------------------------------+

Der Code für die Umsetzung einer vergleichbaren Vorstellung ist recht einfach und nachvollziehbar zu erstellen, dennoch seien hier einige Einzelheiten präzisiert.

Der Diagrammzeitraum, in dem der Signalindikator und das Expert-System tätig sind, wird in der Eingabevariablen InpInd_Timeframe des Expert-System festgelegt. Auf diese Weise zieht ein Wechsel des Diagramms, in dem das Expert-System angezeigt wird, keine Änderung an diesem Parameter des Expert-Systems nach sich.

Die zur Ermittlung des Auftauchens eines neuen Balkens erforderliche Funktion IsNewBar() wird als in der Datei TradeAlgorithms.mqh untergebrachte Klasse umgesetzt. Eine derartige Umsetzung ermöglicht die problemlose Verwendung einer beliebigen Anzahl derartiger Funktionen im Code, wobei für jede von ihnen eine eigene Variable des Typs „static CIsNewBar“ festgelegt wird.

Die Variablen UpSignalTime und DnSignalTime dienen zur Speicherung und Weitergabe der Zeit, nach deren Ablauf der nächste Abschluss nach dem jeweils gegenwärtigen erfolgen darf, an die Handelsfunktionen. In der aktuellen Situation erfolgt auf diese Weise das Verbot des Abschlusses mehrerer Geschäfte in einer Richtung in ein und demselben Balken (bei Abschluss eines Geschäftes speichert die Handelsfunktion den Zeitpunkt der Schließung des aktuellen Balkens und führt bis zum Erreichen dieses Zeitpunktes keine weiteren Geschäfte in dieser Richtung ab).

Der Codeblock „Nach der letzten Handelsrichtung suchen, um Signale für das Schließen einer Position zu empfangen“ in der Funktion OnTick() ist zur Erzeugung von Signalen für die Schließung von Positionen auf Balken ohne Handelssignale erforderlich. Beim üblichen Einsatz eines Expert-Systems werden diese nicht benötigt, aber bei einer Unterbrechung der Internetverbindung ist es gut möglich, dass ein neu entstehendes Handelssignal verpasst wird. Eine Handelsposition rückwirkend zu eröffnen, dürfte kaum zweckmäßig sein, deshalb sollte man sie wenigstens schließen.

Verwendung eines Handelssystems mit anderen Semaphor-Signalindikatoren

Jetzt sind, sofern sich die Notwendigkeit zur Verwendung die Codes mit einem anderen Semaphor-Signalindikator ergeben sollte, folgende Arbeitsschritte auszuführen:

  1. die Eingabe aller erforderlichen Parameter des neuen Indikators in die Eingangsparameter des Expert-Systems anstelle derjenigen seines Vorgängers;
  2. die Änderung des Codes für den Abruf des Indikator-Handles in dem Block OnInit();
  3. die Festlegung der Kennziffern für die Indikatorpuffer zur Speicherung der Handelssignale für den Kauf und den Verkauf sowie ihre entsprechende Eingabe im Block OnTick() in die Aufrufe für die Funktion CopyBuffer(). In diesem Fall kommen bei uns die Puffer Null und Eins des Indikators zum Einsatz;
  4. die Änderung der Bereitstellung der Variablen für den Beginn der Datenberechnung (min_rates_total) in dem Expert-System in Übereinstimmung mit dem Programmcode des Indikators;
  5. die Änderung des Blocks „Nach der letzten Handelsrichtung suchen, um Signale für das Schließen einer Position zu empfangen“ in der Funktion OnTick() in Übereinstimmung mit dem Programmcode des Indikators. 

Verwendung eines Handelssystems mit anderen Semaphor-Trendindikatoren

Zur Verwendung dieses Handelssystems mit einem Semaphor-Trendindikator wurde der Code des Expert-Systems im Block zur Ermittlung der Signale für Vorgänge der Funktion OnTick() ein wenig modifiziert. Bei einem Expert-System auf der Grundlage des Indikators FiboCandles sieht die Code folgendermaßen aus:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---- checking the number of bars to be enough for calculation
   if(BarsCalculated(InpInd_Handle)<min_rates_total) return;
   
//---- uploading history for IsNewBar() and SeriesInfoInteger() functions  
   LoadHistory(TimeCurrent()-PeriodSeconds(InpInd_Timeframe)-1,Symbol(),InpInd_Timeframe);

//---- declaration of local variables
   double TrendVelue[2];
//---- declaration of static variables
   static bool Recount=true;
   static bool BUY_Open=false,BUY_Close=false;
   static bool SELL_Open=false,SELL_Close=false;
   static datetime UpSignalTime,DnSignalTime;
   static CIsNewBar NB;

//+----------------------------------------------+
//| Searching for deals performing signals       |
//+----------------------------------------------+
   if(!SignalBar || NB.IsNewBar(Symbol(),InpInd_Timeframe) || Recount) // checking for a new bar
     {
      //---- zeroing out trading signals
      BUY_Open=false;
      SELL_Open=false;
      BUY_Close=false;
      SELL_Close=false;
      Recount=false;

      //---- copy the newly obtained data into the arrays
      if(CopyBuffer(InpInd_Handle,4,SignalBar,2,TrendVelue)<=0) {Recount=true; return;}

      //---- getting buy signals
      if(TrendVelue[0]==1 && TrendVelue[1]==0)
        {
         if(BuyPosOpen) BUY_Open=true;
         if(SellPosClose)SELL_Close=true;
         UpSignalTime=datetime(SeriesInfoInteger(Symbol(),InpInd_Timeframe,SERIES_LASTBAR_DATE))+TimeShiftSec;
        }

      //---- getting sell signals
      if(TrendVelue[0]==0 && TrendVelue[1]==1)
        {
         if(SellPosOpen) SELL_Open=true;
         if(BuyPosClose) BUY_Close=true;
         DnSignalTime=datetime(SeriesInfoInteger(Symbol(),InpInd_Timeframe,SERIES_LASTBAR_DATE))+TimeShiftSec;
        }

      //---- searching for the last trading direction for getting positions closing signals
      //if(!MQL5InfoInteger(MQL5_TESTING) && !MQL5InfoInteger(MQL5_OPTIMIZATION)) //if execution is set to "Random delay" in the Strategy Tester 
        {
         if(SellPosOpen && SellPosClose  &&  TrendVelue[1]==0) SELL_Close=true;
         if(BuyPosOpen  &&  BuyPosClose  &&  TrendVelue[1]==1) BUY_Close=true;
        }
     }

//+----------------------------------------------+
//| Performing deals                             |
//+----------------------------------------------+
//---- Closing a long position
   BuyPositionClose(BUY_Close,Symbol(),Deviation_);

//---- Closing a short position   
   SellPositionClose(SELL_Close,Symbol(),Deviation_);

//---- Buying
   BuyPositionOpen(BUY_Open,Symbol(),UpSignalTime,MM,0,Deviation_,StopLoss_,TakeProfit_);

//---- Selling
   SellPositionOpen(SELL_Open,Symbol(),DnSignalTime,MM,0,Deviation_,StopLoss_,TakeProfit_);
//----
  }

In diesem Fall stammen die Handelssignale aus lediglich einem Indikatorpuffer, nämlich dem mit den Farben (er beinhaltet die Kennziffern für die Farben), dessen Daten nur zwei Werte annehmen können: „0“ bei einem wachsenden und „1“ bei einem schrumpfenden Markt. Der Code im Block „Nach der letzten Handelsrichtung suchen, um Signale für das Schließen einer Position zu empfangen“ wurde in diesem Beispiel äußerst einfach gehalten, um die Trendrichtung auf jedem Balken möglichst unmittelbar aus der entsprechenden Zelle des Indikatorpuffers abfragen zu können.

In dem Block „Abschluss von Geschäften“ kommen zunächst die Funktionen zum Schließen von Positionen und danach sofort die zum Eröffnen. Wäre es andersherum, so würden sich bei einer Prüfung im Modus „Nur Eröffnungskurse“ die Abschlüsse auf einem Balken nur schließen lassen, aber sie könnten nicht gleichzeitig eröffnet werden. Folglich würden wir ein ernstlich gestörtes Bild des Handels erhalten.


Prüfung des Handelssystems

Bevor wir zu der Prüfung des Handelssystems kommen, müssen wir ein nicht ganz unwesentliches Detail präzisieren. Dabei geht es darum, dass das Expert-System, wenn die Eingabevariable SignalBar den Wert Null hat, auf dem jeweils aktuellen Balken Signale für den Abschluss von Geschäften erhalten wird. Das von dem aktuellen Balken ausgesandte Signal ist jedoch keine belastbare Bedingung für einen Austausch des auf dem vorherigen Balken aktiven Trends gegen eben dieses. Die Signale auf dem aktuellen Balken können erscheinen und verschwinden, aber der Trend auf diese verschwundenen Signale zu kann auch nach deren Verschwinden noch recht lange anhalten. Davon kann man sich leicht überzeugen, wenn man das Expert-System bei jeder Kursänderung mit eingeschalteter grafischer Darstellung und der Variablen SignalBar mit dem Wert Null prüft. Die grafische Darstellung der Tätigkeit des Indikators ASCtrend ist in diesem Fall ein mehr als anschaulicher Beleg für diesen Umstand.

Auch hier ist lediglich der Modus „Jede Kursänderung“ (Every Tick) zur Optimierung des Expert-Systems durch den Empfang des Signals von dem aktuellen Balken geeignet, während bei Signalen von anderen, bereits geschlossenen Balken sogar der Modus „Nur Eröffnungskurse“ vollkommen ausreicht. Dadurch werden die Verhaltensanalysevorgänge des Handelssystems ohne ernsthafte Einbußen bei der Analysequalität um ein Vielfaches beschleunigt.

Folglich ist es ratsam, sich der Prüfung und Optimierung derartiger Handelssysteme unter Verwendung der Signale von dem aktuellen Balken zu enthalten!

Also prüfen wir unser Expert-System mit den Standardparametern für das Währungspaar EUR/USD in dem Zeitraum von Jahresbeginn bis Anfang Dezember:

Abb. 5. Prüfergebnis des Expert-Systems Exp_ASCtrend mit Standardparametern auf EUR/USD H1 

Abb. 5. Prüfergebnis des Expert-Systems Exp_ASCtrend mit Standardparametern auf EUR/USD H1 

Nach einer geringfügigen Änderung der Einstellungen des Expert-Systems in dem Prüfprogramm Strategy Tester ist es nicht schwer, die erfolgreichste Parameterkombination für das Expert-System angesichts der vorhandenen Verlaufsdaten auszuwählen.

 Abb. 6. Prüfergebnis des Expert-Systems Exp_ASCtrend nach der Optimierung mithilfe verbesserter Parameter auf EUR/USD H1

Abb. 6. Prüfergebnis des Expert-Systems Exp_ASCtrend nach der Optimierung mithilfe verbesserter Parameter auf EUR/USD H1 

Der Vorgang zur Verbesserung dieses Handelssystems weist keinerlei Besonderheiten auf, deshalb verweise ich zu seinen Einzelheiten lediglich auf den diesen gewidmeten Beitrag: „MQL5: Leitfaden zum Testen und Optimieren von Expert Advisors in MQL5“.

Selbstverständlich wäre es naiv, von einem derartigen elementaren Handelssystem herausragende Ergebnisse zu erwarten. Dennoch ist es absolut möglich, einen hinlänglich zufriedenstellenden Handel zu erreichen, wenn man ein vergleichbares halbautomatisches System sachkundig einsetzt und es regelmäßig auf das aktuelle Marktgeschehen abstimmt.

Beispielsweise zeigt das Diagramm EUR/USD H12 für 2011 von Januar bis Mai einen aufsteigenden Trend, dessen Ermittlung in der Frühphase seines Entstehens keiner besonderen Anstrengung bedurfte:

Abb. 7. Diagramm EUR/USD H12 (Januar/Mai 2011)

Abb. 7. Diagramm EUR/USD H12 (Januar/Mai 2011)

Es wäre interessant, das Expert-System in diesem Zeitraum mit den Standardparametern zu prüfen und dabei die Möglichkeit einzuschließen, nur Käufe zu tätigen, und dabei nur 5 % der Einlage (MM = 0,05) einzusetzen. Hier haben wir das Ergebnis der Prüfung des Expert-Systems mit diesen Parametern in einem Stundendiagramm (H1):

Abb. 8. Prüfergebnis des Expert-Systems Exp_ASCtrend mit Standardparametern auf EUR/USD H1 für Januar/Mai 2011 (nur „long“ Positionen, MM = 0,05) 

Abb. 8. Prüfergebnis des Expert-Systems Exp_ASCtrend mit Standardparametern auf EUR/USD H1 für Januar/Mai 2011 (nur „long“ Positionen, MM = 0,05)

Natürlich liegt die gesamte Verantwortung für die Auswahl der Handelsrichtung bei einem solchen Herangehen auf den Schultern des Händlers. Wenn wir jedoch bedenken, dass dies besser mithilfe von Diagrammen für größere Zeiträume geschieht, dürften sich dabei eigentlich keine besonderen Schwierigkeiten ergeben.


Umgestaltung des Handelsmoduls zur Verwendung mit einem anderen Indikator

Damit könnte dieser Punkt auch schon abgehakt sein, bestünde nicht in dem Bearbeitungsprogramm MetaEditor die Möglichkeit zur Erstellung von Expert-Systemen auf der Grundlage vorgefertigter Handelsmodule. Allein die Erstellung dieser Module lediglich anhand des von mir oben vorgestellten Materials ist recht umfangreich und erfordert eine gesonderte Betrachtung. Deswegen werde ich in diesem Beitrag bei den bereits beschriebenen Handelsmodulen bleiben, die den von mir vorgeschlagenen Handelssystemen vollkommen entsprechen. Und erst im Anschluss daran werde ich mich mit den Einzelheiten der Umgestaltung dieser Module entsprechend den einzelnen Signalindikatoren befassen, wobei ich von der überflüssigen Vertiefung der Betrachtung dieses Vorgangs absehen werde.

Wir setzen voraus, dass bereits eine Sammlung der Handelsmodule für Semaphor-Signalsysteme (MySignals.zip) vorhanden ist, und lediglich ein vergleichbares Modul für irgendeinen beliebigen Indikator angelegt werden soll. Nehmen wir den Indikator BykovTrendSignal.mq5, einen typischen Semaphor-Signalindikator. Zunächst einmal müssten wir in dieser Sammlung (Indicators.zip) den mit diesem Indikator am ehesten vergleichbaren Indikator ausfindig machen. Mithilfe der grafischen Darstellung ermitteln wir, dass es sich bei dem in diesem Beitrag als erstem behandelten Indikator (ASCtrend) um denjenigen handelt, der ihm am ähnlichsten ist.  Für die Umgestaltung verwenden wir deshalb das Handelsmodul eben dieses Indikators.

Der zu verwendende Indikator selbst erscheint im Programmcode unter der Bezeichnung „BykovTrend“ und weist folgende Eingangsparameter auf:

//+----------------------------------------------+
//| Indicator input parameters                   |
//+----------------------------------------------+
input int RISK=3;
input int SSP=9;
//+----------------------------------------------+

Und wir benötigen die Kennziffern der Indikatorpuffer mit den Signalen für den Abschluss von Geschäften. In unserem Fall sind das: die „0“ für Verkaufssignale und die „1“ bei Kaufsignalen.

Jetzt, da wir wissen, welches Modul wir für die Umgestaltung verwenden müssen, kopieren wir dieses Modul unter dem Dateinamen BykovTrendSignal.mqh in den Ordner \MQL5\Include\Expert\Signal\MySignals\ und öffnen es anschließend in dem Bearbeitungsprogramm MetaEditor. In dem verwendeten Code taucht immer wieder der Ausdruck „ASCtrend“ (die Bezeichnung des vorhergehenden Indikators) auf. Er muss durch die Bezeichnung für den neuen Indikator, „BykovTrend“, ersetzt werden. Dazu drücken wir gleichzeitig die Tasten „Strg“ (Ctrl) und „H“ und nehmen den erforderlichen Austausch vor:

 Austausch der Indikatorbezeichnung im Code des Handelsmoduls

Abb. 9. Austausch der Indikatorbezeichnung im Code des Handelsmoduls

Jetzt kommen wir zum mühsamsten Teil der Arbeit. Wir müssen im Code des Handelsmoduls alles austauschen, was die Eingangsparameter betrifft. Das Vorgehen ähnelt weitgehend dem in dem Artikel „Der MQL5-Assistent: Erstellung eines Modules mit Handelssignalen“ dargestellten.

Zunächst müssten einige Änderungen in dem Kommentarblock zur Beschreibung der Klasse der Handelssignale für den MQL5-Assistenten vorgenommen werden:

//+----------------------------------------------------------------------+
//| Description of the class                                             |
//| Title=The signals based on BykovTrend indicator                      |
//| Type=SignalAdvanced                                                  |
//| Name=BykovTrend                                                      |
//| Class=CBykovTrendSignal                                              |
//| Page=                                                                |
//| Parameter=BuyPosOpen,bool,true,Permission to buy                     |
//| Parameter=SellPosOpen,bool,true,Permission to sell                   |
//| Parameter=BuyPosClose,bool,true,Permission to exit a long position   |
//| Parameter=SellPosClose,bool,true,Permission to exit a short position |
//| Parameter=Ind_Timeframe,ENUM_TIMEFRAMES,PERIOD_H1,Timeframe          |
//| Parameter=RISK,int,4,Risk level                                      |
//| Parameter=SSP,int,9,SSP                                              |
//| Parameter=SignalBar,uint,1,Bar index for entry signal                |
//+----------------------------------------------------------------------+
//--- wizard description end
//+----------------------------------------------------------------------+
//| CBykovTrendSignal class.                                             |
//| Purpose: Class of generator of trade signals based on                |
//| BykovTrend indicator https://www.mql5.com/ru/code/497/.               |
//|             Is derived from the CExpertSignal class.                 |
//+----------------------------------------------------------------------+

Beide Indikatoren enthalten ein und dieselbe Eingangsvariable RISK, die deshalb an Ort und Stelle bleiben kann, ihr voreingestellter Wert ist in diesen Indikatoren jedoch jeweils ein anderer. Grundsätzlich ist dieser Unterschied bei den Werten der RISK-Variablen nicht ausschlaggebend und kann bestehen bleiben. Es wurde ein Kommentarzeile bezüglich der Variablen SSP hinzugefügt:

//| Parameter=SSP,int,9,SSP                                    |

Und in der Codebasis wurde der Verweis auf den Indikator geändert:

//| Purpose: Class of generator of trade signals based on      |
//| BykovTrend values https://www.mql5.com/ru/code/497/.        |

Jetzt muss alles, was die Änderungen der Eingangsvariablen betrifft, auch in der Beschreibung der Klasse der Handelssignale CBykovTrendSignal selbst wiedergegeben werden. Bei uns erscheint eine Zeile mit der Deklaration einer neuen globalen Variablen der Klasse m_SSP mit folgenden Einstellungsparametern:

   uint              m_SSP;              // SSP

 sowie eine Zeile mit der Deklaration einer neuen Methode zur Festlegung der Einstellungsparameter für SSP():

   void               SSP(uint value)                         { m_SSP=value;              } 

Alles, was die Eingangsvariable RISK in dem von uns angelegten Handelssignalmodul betrifft, ist identisch mit dem ursprünglichen Modul, weshalb in diesem sowie in den übrigen Codeblöcken des Handelsmoduls keine Änderungen erforderlich sind.

Kommen wir jetzt zum Konstruktor der Klasse CBykovTrendSignal::CBykovTrendSignal(). In diesem Block müssen wir die Bereitstellung der neuen Variablen ergänzen:

   m_SSP=4;

In dem Block CBykovTrendSignal::ValidationSettings() zur Prüfung der Einstellungsparameter ist die neue Variable auf ihre Richtigkeit zu überprüfen:

   if(m_SSP<=0)
     {
      printf(__FUNCTION__+": SSP must be above zero");
      return(false);
     }

Anschließend können wir uns dem Block zur Bereitstellung des Indikators BykovTrend zuwenden: BykovTrendSignal::InitBykovTrend(). Der neue Indikator verfügt über eine abweichende Anzahl von Eingangsvariablen, weshalb die Dimension des deklarierten Datenfeldes für die Eingangsparameter ebenfalls eine andere ist:

//--- setting the indicator parameters
   MqlParam parameters[3];

In dem hier vorliegenden Fall benötigen wir eine Dimension für die Speicherbezeichnung, den „string name“, des Indikators sowie zwei weitere für seine Eingangsparameter.

Nun müssen wir unter Angabe der Art der darin zu speichernden Variablen eine neue Zelle des Datenfeldes für die Eingabeparameter bereitstellen:

   parameters[2].type=TYPE_INT;
   parameters[2].integer_value=m_SSP;

 Anschließend ändern wir in diesem Block die Anzahl der Eingangsparameter im Aufruf zur Bereitstellung des Indikators auf 3:

//--- object initialization   
   if(!m_indicator.Create(m_symbol.Name(),m_Ind_Timeframe,IND_CUSTOM,3,parameters))

Die Anzahl der Anzeigepuffer im Indikator bleibt unverändert bei zwei, weshalb in unserem Fall an der Zeile zur Bereitstellung der Anzahl der Indikatorpuffer keinerlei Änderungsbedarf besteht:

//--- number of buffers
   if(!m_indicator.NumBuffers(2))  return(false);

Die Indikatoren ASCtrend und BykovTrend verfügen jeweils über zwei Indikatorpuffer, wobei die Zweckbestimmung der Puffer absolut identisch ist. Der Puffer „Null“ dient zur Zwischenspeicherung der Verkaufssignale, während der Puffer mit der Kennziffer „1“ die Kaufsignale aufnimmt. Folglich muss in den Codeblöcken der Funktionen CBykovTrendSignal::LongCondition() und CBykovTrendSignal::ShortCondition() zur Ausgabe von Handelssignalen nichts geändert werden, und wir können die Umgestaltung des Moduls mit den Handelsmodulen als abgeschlossen betrachten.

Generell unterscheiden sich alle Semaphorindikatoren, weshalb diese Blöcke bei unterschiedlichen Indikatoren erheblich voneinander abweichen können. Das Handelsmodulearchiv MySignals.zip sowie das entsprechende Indikatorarchiv Indicators.zip beinhalten eine ausreichende Menge an Beispielen für unterschiedliche Verfahren zum Anlegen von Indikatoren. Wenn man sich mit ihnen ein wenig vertraut gemacht hat, findet man sich mühelos in den Einzelheiten dieses Austauschvorgangs und den möglichen Codevarianten zu diesem Zweck zurecht.

Jetzt möchte ich unsere Aufmerksamkeit auf die Eingangsvariable Ind_Timeframe des Handelssignalmoduls konzentrieren. Mithilfe dieser Variablen wird der zeitliche Rahmen, innerhalb dessen er tätig ist, in den Indikator geladen. Das erstellte Expert-System selbst arbeitet jedoch in dem Zeitraum, dem es zugewiesen wurde. Damit das Modul ordnungsgemäß funktioniert, darf der Zeitraum der Eingangsvariablen Ind_Timeframe also niemals größer sein als der Zeitraum des Diagramms, in dem das Expert-System ausgeführt wird.

Abschließend möchte ich noch auf eine Besonderheit bei der Programmierung von Handelssignalmodulen hinweisen. Mitunter enthält der Code des ursprünglichen Indikators als Varianten für die Eingangsvariablen des Moduls benutzerdefinierte Aufzählungen. So erweist zum Beispiel bei dem Indikator Candles_Smoothed die benutzerdefinierte Aufzählung Smooth_Method als Spielart der Variablen MA_SMethod:

//+-----------------------------------+
//|  Declaration of enumerations      |
//+-----------------------------------+
enum Smooth_Method
  {
   MODE_SMA_,  // SMA
   MODE_EMA_,  // EMA
   MODE_SMMA_, // SMMA
   MODE_LWMA_, // LWMA
   MODE_JJMA,  // JJMA
   MODE_JurX,  // JurX
   MODE_ParMA, // ParMA
   MODE_T3,    // T3
   MODE_VIDYA, // VIDYA
   MODE_AMA,   // AMA
  }; */
//+----------------------------------------------+
//| Indicator input parameters                   |
//+----------------------------------------------+
input Smooth_Method MA_SMethod=MODE_LWMA; // Smoothing method
input int MA_Length=30;                   // Smoothing depth                    
input int MA_Phase=100;                   // Smoothing parameter
                                          // for JJMA varying within the range -100 ... +100,
                                          // for VIDIA it is a CMO period, for AMA it is a slow average period
//+----------------------------------------------+

In einer solchen Situation müssen diese Eingangsvariablen und alles im Handelssignalmodul (Candles_SmoothedSignal.mqh) mit ihnen Verbundene in Variablen der Art „int“ bzw. „uint“ umgewandelt werden. Und zur Vereinfachung der Handhabung dieser Eingangsvariablen im Rahmen des Codes des bereits erstellten Expert-Systems müssen die Deklaration der benutzerdefinierten Aufzählungen bis zu den Eingangsparametern des Expert-Systems rückgängig gemacht und die benötigten Eingangsvariablen (des Expert-Systems ExpM_Candles_Smoothed) ausgetauscht werden:

//+------------------------------------------------------------------+
//|  Declaration of enumerations                                     |
//+------------------------------------------------------------------+
enum Smooth_Method
  {
   MODE_SMA_,  // SMA
   MODE_EMA_,  // EMA
   MODE_SMMA_, // SMMA
   MODE_LWMA_, // LWMA
   MODE_JJMA,  // JJMA
   MODE_JurX,  // JurX
   MODE_ParMA, // ParMA
   MODE_T3,    // T3
   MODE_VIDYA, // VIDYA
   MODE_AMA,   // AMA
  };
//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
//--- inputs for expert
input string          Expert_Title         ="Candles_Smoothed"; // Document name
ulong                 Expert_MagicNumber   =29976;              // 
bool                  Expert_EveryTick     =false;              // 
//--- inputs for main signal
input int             Signal_ThresholdOpen =40;                 // Signal threshold value to open [0...100]
input int             Signal_ThresholdClose=20;                 // Signal threshold value to close [0...100]
input double          Signal_PriceLevel    =0.0;                // Price level to execute a deal
input double          Signal_StopLevel     =50.0;               // Stop Loss level (in points)
input double          Signal_TakeLevel     =50.0;               // Take Profit level (in points)
input int             Signal_Expiration    =1;                  // Expiration of pending orders (in bars)
input bool            Signal__BuyPosOpen   =true;               // Candles_Smoothed() Permission to buy
input bool            Signal__SellPosOpen  =true;               // Candles_Smoothed() Permission to sell
input bool            Signal__BuyPosClose  =true;               // Candles_Smoothed() Permission to exit a long position
input bool            Signal__SellPosClose =true;               // Candles_Smoothed() Permission to exit a short position
input ENUM_TIMEFRAMES Signal__Ind_Timeframe=PERIOD_H1;            // Candles_Smoothed() Timeframe
input Smooth_Method   Signal__MA_SMethod   =4;                  // Candles_Smoothed() Smoothing method (1 - 10)
input uint            Signal__MA_Length    =30;                 // Candles_Smoothed() Smoothing depth
input uint            Signal__MA_Phase     =100;                // Candles_Smoothed() Smoothing parameter
input uint            Signal__SignalBar    =1;                  // Candles_Smoothed() Bar index for the entry signal
input double          Signal__Weight       =1.0;                // Candles_Smoothed() Weight [0...1.0]
//--- inputs for money
input double          Money_FixLot_Percent =10.0;               // Percent
input double          Money_FixLot_Lots    =0.1;                // Fixed volume

Im vorliegenden Fall ist das mithilfe der Eingangsvariablen Signal__MA_SMethod geschehen.

Das Verstehen des Vorgehens bei der Umgestaltung des Codes kann erheblich beschleunigt werden, wenn man in dem Bearbeitungsprogramm beide Codevarianten (ASCtrendSignal.mqh und BykovTrendSignal.mqh) gleichzeitig öffnet (die eine links, die andere rechts), und den Code in beiden aufmerksam vergleicht.

Fazit

In dem, diesem Beitrag als Anlage beigefügten Archiv Experts.zip habe ich eine mehr als ausreichende Anzahl von Expert-Systemen auf der Grundlage von Semaphor-Handelssystemen zusammengestellt, damit auch Neulinge auf dem Gebiet der Programmierung von Expert-Systemen sich mit den Feinheiten der Programmierung vergleichbarer Codes zurechtfinden oder wenigstens grundlegend mit fertigen Expert-Systemen auf der Grundlage einigermaßen geläufiger Indikatoren arbeiten können.

Für alle, die sich als Grundlage für die Erstellung eigener Handelssysteme für die Möglichkeiten eines Handelsstrategiegenerators entschieden haben, werden alle hier vorgeschlagenen Expert-Systeme zusätzlich als Handelsmodule präsentiert. Diese Module befinden sich in dem Archiv MySignals.zip, die auf ihrer Grundlage erstellten Handelssysteme dagegen im Archiv Expertsez.zip. Die in den Expert-Systemen verwendeten Indikatoren befinden sich in dem Archiv Indicators.zip. Die Pfade zum Entpacken der Dateien sind:

  • Experts.zip: „\MQL5\Experts\“;
  • Expertsez.zip: „\MQL5\Experts\“; 
  • MySignals.zip: „\MQL5\Include\Expert\Signal\MySignals\“; 
  • Indicators.zip: „\MQL5\Indicators“;
  • SmoothAlgorithms.mqh: „\Include\“;
  • TradeAlgorithms.mqh: „\Include\“.

Zum gleichzeitigen Erstellen aller Dateien müssen wir das Bearbeitungsprogramm MetaEditor nach dem Entpacken neu starten, das Symbol MQL5 mit der rechten Maustaste anklicken und anschließend in dem angezeigten Kontextmenü den Befehl „Erstellen“ (Compile) auswählen.

Die Datei SmoothAlgorithms.mqh ist zum Erstellen einiger Indikatoren aus dem Archiv Indicators.zip erforderlich, während die Datei TradeAlgorithms.mqh zur Erstellung aller Expert-Systeme aus dem Archiv Experts.zip benötigt wird.

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/358

Beigefügte Dateien |
expertsez.zip (31.51 KB)
mysignals.zip (44.08 KB)
indicators.zip (39.15 KB)
experts.zip (34.67 KB)
In 6 Schritten zum eigenen automatischen Handelssystem! In 6 Schritten zum eigenen automatischen Handelssystem!
Wenn Sie nicht wissen, wie Handelsklassen aufgebaut sind, und Wörter wie „objektorientierte Programmierung“ (OOP) Sie verunsichern, ist dieser Beitrag genau das Richtige für Sie. Denn Sie müssen wirklich nicht alle Einzelheiten kennen, um Ihr eigenes Handelssignalmodul zu programmieren, sondern lediglich ein paar einfache Regeln befolgen. Alle weitere erledigt der MQL5-Assistent für Sie, und am Ende haben Sie ein einsatzbereites automatisches Handelssystem, einen Expert Advisor!
Objektorientierter Ansatz zum Aufbau von Panels mit mehreren Timeframes und Währungen Objektorientierter Ansatz zum Aufbau von Panels mit mehreren Timeframes und Währungen
In diesem Beitrag wird die Nutzung der objektorientierten Programmierung zum Erstellen von Panels mit mehreren Timeframes und Währungen für MetaTrader 5 beschrieben. Das Hauptziel ist der Aufbau eines universell einsatzfähigen Panels, das für die Darstellung verschiedener Arten von Daten genutzt werden kann – beispielsweise Preise, Preisänderungen, Indikatorwerte oder benutzerdefinierte Kauf-/Verkaufsbedingungen –, ohne den Code des Panels selbst verändern zu müssen.
MetaTrader 5 - Jenseits aller Vorstellungen! MetaTrader 5 - Jenseits aller Vorstellungen!
Die Plattform MetaTrader 5 wurde aus dem nichts entwickelt und übertrifft ihre Vorgänger natürlich bei Weitem. Die neue Handelsplattform bietet unbegrenzte Möglichkeiten für den Handel auf allen Finanzmärkten. Darüber hinaus wird ihr Funktionsumfang ständig erweitert, um immer mehr nützliche Instrumente und eine immer größere Benutzerfreundlichkeit zu bieten. Deshalb ist es nicht ganz einfach, all die zahlreichen Vorzüge von MetaTrader 5 aufzuzählen. Wir haben uns bemüht, sie in einem Artikel kurz darzustellen, und waren überrascht, dass der Beitrag alles andere als kurz geraten ist.
Grundlagen der objektorientierten Programmierung Grundlagen der objektorientierten Programmierung
Sie müssen nicht unbedingt wissen, was Polymorphismus, Kapselung usw. im Zusammenhang mit objektorientierter Programmierung (OOP) sind... Sie können diese Funktionen einfach nutzen. Dieser Beitrag behandelt die Grundlagen der OOP mit praktischen Beispielen.