MetaTrader 5 herunterladen

Verarbeitung von Ereignissen in MQL5: Unmittelbare Änderung des Zeitraums für den gleitenden Durchschnitt

12 Februar 2016, 12:50
Sceptic Philozoff
0
239

Einleitung

Verarbeitung von Ereignissen in MQL5: Unmittelbare Änderung des Zeitraums für den gleitenden Durchschnitt Dieser kurze Beitrag widmet sich einem der neuen Features von MQL5 der MetaTrader 5 Plattform, die von MetaQuotes Software Corp. entwickelt wurde. Vielleicht kommt dieser Beitrag ein bisschen verspätet (hätte eigentlich im September/Oktober 2009 schon erscheinen sollen - das wäre rechtzeitig gewesen), doch gab es zu diesem Thema noch keine ähnlichen Beiträge. Und zudem gab es damals noch keine solchen Möglichkeiten, Ereignisse in Indikatoren zu verarbeiten.

Also stellen wir uns vor, wir haben irgendeinen Kurs-Indikator auf ein Chart angewendet (in unserem ist es der Gleitender Durchschnitt, MA), und wir wollen seine ausgleichenden Zeitraum ändern. Die MT4 Plattform bot uns dazu die folgenden Optionen:

  • Im MetaEditor kann man Expert-Eingabeparameter (extern) ändern, die für den MA Zeitraum zuständig sind, und dann die Quelldatei erstellen.
  • Ohne zum MetaEditor zu wechseln, kann man direkt im Terminal-Fenster das Dialogfenster Indikator-Eigenschaften öffnen und hier den entsprechenden Eingabeparameter ändern.
  • Man kann auch die Win32 API Library öffnen, den Punkt Funktionen der Benachrichtigung finden und dann den Indikator-Code so optimieren, dass er auf Tastatureingaben reagiert.

Und wir alle wissen ja, dass der Wunsch nach möglichst wenig Anstrengung der größte Treiber für Fortschritt ist. Doch dank der neuen MT5 Plattform, die die Verarbeitung von Indikatoren-Ereignissen, die vom Benutzer initiiert wurden, gestattet, können wir die o.g. Möglichketien alle vergessen und Indikator-Parameter mit einem einzigen Tastendruck verändern. Dieser Beitrag zeigt wie die technische Implementierung dieser Problemlösung funktioniert.

Ausgabenzuweisung und Problem

Der in unserem Beispiel verwendete Indikator-Quellcode kommt zusammen mit dem Client-Terminal. Die unveränderte Quellcode-Datei (Custom Moving Average.mq5) ist am Ende des Beitrags angehängt.

Wir werden hier nicht den Quellcode und seine Veränderungen, verglichen mit seinem MQL4 Original analysieren. An einigen Stellen hat er sich in der Tat erheblich geändert, aber das ist nicht immer sichtbar. Entsprechende Erklärungen in Bezug auf die Restrukturierung des Grundlagenteils der Berechnung findet man in Foren und der Online-Hilfe.

Doch der Hauptteil des Indikator in MQL4 ist dennoch unverändert geblieben. Mindestens 80% aller Änderungen im Code, mit denen das Problem gelöst werden soll, wurden auf Basis der Idee der Rechnerfunktionen des Indikators als die "Black Boxes" gemacht.

Ein Beispiel dessen, was wir erreichen wollen, sieht so aus. Angenommen, wir haben diesen Indikator auf ein Chart angewandt, und er zeigt zu einem bestimmten Moment einen exponentiellen MA (EMA) mit Null Verschiebung und Zeitraum 10. Unser Ziel ist den ausgleichenden Zeitraum eines einfachen MA (SMA) um 3 zu erhöhen (also auf 13) und um 5 Balken nach rechts zu verschieben . Die dazu erforderlichen Handlungen sehen folgendermaßen aus:

  • Mehrmaliges Drücken der TAB Taste zur Änderung des angezeigten MA von exponentiell auf einfach (Änderung des MA-Typs).
  • Dreimaliges Drücken der Bild nach oben Taste links neben dem Zahlenfeld der Tastatur, um den Zeitraum des einfachen MA um 3 zu erhöhen.
  • Fünfmaliges Drücken der Bild nach oben Taste auf dem Zahlenfeld der Tastatur (Taste 8), um den MA um 5 Balken nach rechts zu verschieben.

Die erste und offensichtlichste Lösung ist, die OnChartEvent() Funktion in den Indikator-Code einzufügen und den Handler für den Tastendruck zu schreiben. Gemäß der Liste der Veränderungen im MetaTrader 4, baut der Client-Terminal 245  und 246 https://www.mql5.com/en/forum/53/page1/#comment_2655,

MetaTrader 5 Client-Terminal baut 245 und 246

MQL5: Wurde zur Möglichkeit des Ereignis-Handling durch angepasste Indikatoren hinzugefügt, ähnlich wie bei Expert Advisors.

Jetzt bereitet uns die Ergänzung neuer Ereignis-Handler im Indikator keine Probleme mehr. Doch dafür müssen wir seinen Code leicht verändern.

Erstens hat sich in MQL5 der Status der externen Parameter des Indikators verändert: die kann man nicht im Code ändern. Das geht nur im Dialogfeld Eigenschaften im Client-Terminal. Muss man sie jedoch doch einmal dringend dort ändern, kann man diese Einschränkung leicht umgehen: einfach die Werte der externen Parameter in die neuen globalen Variablen des Indikators kopieren und, wenn diese neuen Variablen tatsächlich die externen Parameter des Indikators sind, werden alle Berechnungen ausgeführt. Andererseits verliert man in dem Fall die Umsetzbarkeit der externen Parameter, deren Werte Benutzer nur irreführen können. Wir brauchen diese Parameter jetzt einfach nicht.

Also gibt es keine externen (Eingabe) Parameter im Indikator. Die Variablen, die nun die Funktion der externen Parameter übernehmen sind jetzt die Terminal Globalen Variablen, kurz TGVs. Möchten Sie die TGVs sehen, die für die ehemaligen externen Parameter des Indikators verantwortlich sind, drücken Sie einfach im Terminal F3. Für mich schlicht der einfachste Weg, die Indikatorparameter zu kontrollieren.

Zweitens (und das ist wichtig), bei jeder Änderung der externen Parameter des Indikators müssen wir all seine Werte in der gesamten History neue berechnen, abermals und von Anfang an. Anders ausgedrückt: wir müssen Berechnungen durchführen, die sonst nur beim allerersten Start des Indikators gemacht werden. Die Optimierung der Indikator-Berechnungen bleibt zwar, wird jedoch jetzt etwas subtiler.

Unten stehen einige Teile des Codes der ersten Version des modifizierten Indikators. Der komplette Code findet sich im Anhang dieses Beitrags.

 

"Standardversion": Beschreibung der Änderungen im Standard-Quellcode des Indikators

Externe Parameter sind nicht mehr extern, sondern einfach globale Variablen

Alle externen Parameter des Indikators haben ihren Eingabe-Modifikator verloren. Eigentlich hätte ich sie gar nicht global machen können, doch ich habe das aus Gewohnheit dennoch getan:

int              MA_Period   = 13;
int              MA_Shift    =  0;
ENUM_MA_METHOD   MA_Method   =  0;
int              Updated     =  0;     /// Indicates whether the indicator has updated after changing it's values

Die ersten drei Optionen - der Zeitraum, die Verschiebung und die Art des MA sowie die vierte - Aktualisiert - sind für die Berechnungsoptimierung bei der Veränderung der MA Paramater zuständig. Dies wird einige Zeilen weiter unten erklärt. 

Codes für virtuelle Tasten

Geben Sie nun die Codes für die virtuellen Tasten ein:

#define KEY_UP             38
#define KEY_DOWN           40
#define KEY_NUMLOCK_DOWN   98
#define KEY_NUMLOCK_UP    104
#define KEY_TAB             9

Das sind die Codes für die "Bild nach oben" und "Bild nach unten" Tasten und ähnliche Tasten auf dem Zahlenfeld (Taste "8" und "2"), sowie die TAB-Taste. Die gleichen Codes (mit anderen Namen der VK_XXX Konstanten) gibt es tatsächlich in der Datei <MT5dir>\MQL5\Include\VirtualKeys.mqh, doch in unserem Beispiel habe ich sie nicht angerührt.


Kleine Code-Korrektur in der Funktion, die den linear gewichteten gleitenden Durchschnitt (LWMA) berechnet

Ich habe in der CalculateLWMA() Funktion eine kleine Verbesserung vorgenommen: In der Originalversion war die weightsum Variable mit Hilfe des statischen Modifikators deklariert. Und der einzig naheliegende Grund, warum die Entwickler dies getan haben, war die Notwendigkeit, sie beim ersten Aufruf dieser Funktion vorab berechnen zu können. Im weiteren Code bleibt diese Variable unverändert. Und das ist der Originalcode der Funktion, in dem alle Teile, die mit Berechnung und Verwendung von weightsum zusammenhängen, mit Kommentaren versehen sind:

void CalculateLWMA(int rates_total,int prev_calculated,int begin,const double &price[])
  {
   int              i,limit;
   static int     weightsum;                       // <-- using weightsum
   double               sum;
//--- first calculation or number of bars was changed
   if(prev_calculated==0)                          // <-- using weightsum
     {
      weightsum=0;                                 // <-- using  weightsum
      limit=InpMAPeriod+begin;                     // <-- using weightsum
      //--- set empty value for first limit bars
      for(i=0;i<limit;i++) ExtLineBuffer[i]=0.0;
      //--- calculate first visible value
      double firstValue=0;
      for(i=begin;i<limit;i++)                     // <-- using weightsum
        {
         int k=i-begin+1;                          // <-- using weightsum
         weightsum+=k;                             // <-- using weightsum
         firstValue+=k*price[i];
        }
      firstValue/=(double)weightsum;
      ExtLineBuffer[limit-1]=firstValue;
     }
   else limit=prev_calculated-1;
//--- main loop
   for(i=limit;i<rates_total;i++)
     {
      sum=0;
      for(int j=0;j<InpMAPeriod;j++) sum+=(InpMAPeriod-j)*price[i-j];
      ExtLineBuffer[i]=sum/weightsum;              // <-- using weightsum
      }
//---
  }

Zuvor funktionierte diese Version ziemlich gut, doch als ich "Indikator + Advisor" beide zusammen ablaufen ließ (wird am Ende dieses Beitrags angesprochen), kam es in genau dieser Art MA zu Problemen. Das größte Problem wurde durch die o.g. Umstände verursacht, d.h. weightsum was die statische Variable: diese Variable stieg konstant an, da ja bei jeder spontanen Veränderung des MA Parameters, ihre Neuberechnung von Anfang an notwendig war.

Der einfachste Weg, den weightsum Wert direkt und sofort zu berechnen (ist gleich der Summe aller ganzen Zahlen von 1 bis zum MA Zeitraum - zu diesem Zweck git es eine einfache Formel für die Summe der arithmetischen Progression), und zugleich seinen Status als einen statischen Wert abzulehnen - was ich getan habe. Also anstatt wie vorhin weightsum mit Hilfe des statischen Modifikators zu deklarieren, machen wir das jetzt ohne ihn, initialisieren ihn nur mit dem Wert "korrekt" und entfernen so die ursprüngliche Schleife der "Variablenhäufung".

int weightsum = MA_Period *( MA_Period + 1 ) / 2;

So, jetzt funktioniert alles korrekt.


OnCalculate() Funktion als Handler

Ich musste in der OnCalculate() Funktion eine ganze Menge ändern, und deswegen gebe ich ihren Code hier komplett an.

int OnCalculate(const int rates_total,
                const int prev_calculated,            /// Mathemat: full recalculation!
                const int begin,                      /// Mathemat: full recalculation!
                const double &price[])
  {
//--- check for bars count
   if(rates_total<MA_Period-1+begin)
      return(0);// not enough bars for calculation
//--- first calculation or number of bars was changed
   if(prev_calculated==0)
      ArrayInitialize(LineBuffer,0);
//--- sets first bar from what index will be draw
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,MA_Period-1+begin);

//--- calculation (Mthmt - optimized by Mathemat)

   if( GlobalVariableGet( "Updated" ) == 1 )
   {
      if(MA_Method==MODE_EMA)  CalculateEMA(       rates_total,prev_calculated,begin,price);
      if(MA_Method==MODE_LWMA) CalculateLWMA_Mthmt(rates_total,prev_calculated,begin,price);
      if(MA_Method==MODE_SMMA) CalculateSmoothedMA(rates_total,prev_calculated,begin,price);
      if(MA_Method==MODE_SMA)  CalculateSimpleMA(  rates_total,prev_calculated,begin,price);
   }
   else
   {
      OnInit( );                 /// Mthmt
      if(MA_Method==MODE_EMA)  CalculateEMA(       rates_total,0,0,price);
      if(MA_Method==MODE_LWMA) CalculateLWMA_Mthmt(rates_total,0,0,price);
      if(MA_Method==MODE_SMMA) CalculateSmoothedMA(rates_total,0,0,price);
      if(MA_Method==MODE_SMA)  CalculateSimpleMA(  rates_total,0,0,price);
      GlobalVariableSet( "Updated", 1 );
      Updated = 1;
   }
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Die primäre Änderung hängt damit zusammen, dass wir ja eine Indikatorberechnung "komplett von Null aus" machen müssen: denn es ist ja klar, dass, wenn der MA Zeitraum durch Tastatureingaben von 13 auf 14 verändert wurde, alle vorherigen Optimierungen seiner Berechnungen nutzlos geworden sind und wir den MA erneut berechnen müssen. Das passiert, wenn die Aktualisierte Variable den Wert 0 besitzt (TGV hat sich durch Drücken des Hotkeys verändert, doch die Preisänderung (Tick), die den Indikator neu zeichnet, ist noch nicht passiert).

Zusätzlich müssen wir jedoch auch zuvor explizit die OnInit() Funktion aufrufen, da wir den Kurznamen des Indikators, der angezeigt wird, wenn der Cursor über der Zeile steht,verändern mussten. Nach der ersten MA-Berechnung wir der Aktualisierte TGV auf 1 gesetzt, was den Weg zur optimierten Indikatorberechnung freimacht - bis man wieder keine Indikatorparameter spontan verändern möchte.


OnChartEvent() Handler

Unten steht ein einfacher Code des OnChartEvent() Handlers:

void OnChartEvent( const int          id,
                   const long    &lparam,
                   const double  &dparam,
                   const string  &sparam )
{
   if( id == CHARTEVENT_KEYDOWN )
      switch( lparam )
      {
         case( KEY_TAB          ):  changeTerminalGlobalVar( "MA_Method",  1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         
         case( KEY_UP           ):  changeTerminalGlobalVar( "MA_Period",  1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         case( KEY_DOWN         ):  changeTerminalGlobalVar( "MA_Period", -1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         
         case( KEY_NUMLOCK_UP   ):  changeTerminalGlobalVar( "MA_Shift",   1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         case( KEY_NUMLOCK_DOWN ):  changeTerminalGlobalVar( "MA_Shift",  -1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
      }
      
      return;
}//+------------------------------------------------------------------+      

Der Handler funktioniert so: Man drückt den Hotkey, dessen virtueller Code festgelegt ist, sodass dann die changeTerminalGlobalVar() Zusatzfunktion gestartet wird und den gewünschten TGV korrekt verändert. Danach wird die Flagge Aktualisiert auf Null zurückgesetzt, und wartet auf die Preisänderung, die OnCalculate() startet und den Indikator "von Anfang an" neu zeichnet.


Zusatzfunktion, die den TGV "korrekt" verändert

Und schließlich der im OnChartEvent() Handler verwendete Code der changeTerminalGlobalVar() Funktion:

void changeTerminalGlobalVar( string name, int dir = 0 )
{
   int var = GlobalVariableGet( name );
   int newparam = var + dir;
   if( name == "MA_Period" )
   {
      if( newparam > 0 )       /// Possible period is valid for MA
      {
         GlobalVariableSet( name, newparam ); 
         MA_Period = newparam;     /// Don't forget to change the global variable    
      }   
      else                       /// we do not change the period, because MA period is equal to 1 minimum
      {   
         GlobalVariableSet( name, 1 );     
         MA_Period = 1;     /// Don't forget to change the global variable 
      }   
   }   
      
   if( name == "MA_Method" )    /// Here when you call the 'dir' it is always equal to 1, the dir value is not important    
   {
      newparam = ( var + 1 ) % 4;
      GlobalVariableSet( name, newparam );  
      MA_Method = newparam;
   }      

   if( name == "MA_Shift" )
   {
      GlobalVariableSet( name, newparam );     
      MA_Shift = newparam;
   }      

   ChartRedraw( );
   return;
}//+------------------------------------------------------------------+

Der Hauptzweck dieser Funktion ist, die korrekte Berechnung neuer MA Parameter unter Berücksichtigung "physikalischer Einschränkungen". Offensichtlich können wir den MA-Zeitraum nicht kleiner als 1 machen, die MA Verschiebung kann zufällig sein, doch der MA-Typ ist die Zahl von 0 - 3, entsprechend einer abhängigen Mitgliedsnummer in der ENUM_MA_METHOD Aufzählung.

 

Prüfung. Funktioniert, kriegt aber nur "einen Dreier". Was tun?

Okay, wenden wir unseren Indikator auf den Chart an und drücken zuerst einmal sporadisch die Hotkeys, die die MA-Parameter verändern. Prima, alles funktioniert korrekt. Doch eines ist unangenehm: die TGVs ändern sich sofort (das kann man durch Aufruf des TGV mit Hilfe der F3 Taste herausfinden), doch die MAs zeichnen sich nicht sofort neu, sondern nur beim Auftreten einer Kursänderung. Bei einer Sitzung bei vollem Tagesgeschäft mit einem aktiven Kursänderungs-Flow bemerkt man die Verzögerung kaum. Doch wenn das nachts passiert, wenn alles ruhig ist, dann warten wir auf die neue Zeichnung durchaus einige Minuten. Also was ist los?

Mn sagt ja, man kriegt nur das zurück was man schreibt. Vor dem Aufbau von 245 in den Indikatoren gab es nur einen "Einstiegspunkt" - die OnCalculate() Funktion. Ich spreche natürlich nicht von den OnInit() und OnDeinit() Funktionen, die die allerersten Berechnungen, Initialisierungen und den Abschluss des Indikators liefern. Jetzt haben wir mehrere Einstiegspunkte und alle sind mit den neuen Timer und ChartEvent Ereignissen verknüpft.

Doch die neuen Handler machen nur das, was sie umfassen und hängen formal nicht mit dem OnCalculate() Handler zusammen. Was machen wir also mit unserem "außerirdischen" OnChartEvent() Handler, damit er "richtig" funktioniert, also die Neuzeichnung des MA sofort erlaubt?

Es gibt hier im Allgemeinen verschieden Möglichkeiten diese Vorassuetzung zu implementieren:

  • "Matryoshka" (OnCalculate() Aufruf innerhalb von OnChartEvent()): den OnCalculate() Funktionsaufruf in seinen Handler einfügen und all seine Parameter vrab füllen. Da der OnChartEvent() Handler bedeutet, mindestens einen der MA-Parameter zu ändern, wirkt sich das auf die ganze History aus, sodass wir ihn erneut "von Null'' berechnen müssen, ohne die Optimierung der Berechnungen.
  • "Künstliche Kursänderung", die die Kontrolle an den Anfang der OnCalculate() Funktion überträgt, die den graphischen Buffer verändert. Offensichtlich gibt es keine "legitimen" Methoden, wie die MT5 Dokumentation zeigt (oder vielleicht habe ich auch nicht gründlich gesucht). Wenn es Sie interessiert, dann suchen Sie doch z. B.nach «API», «PostMessageA» usw. Wir werden diese Variante daher hier nicht berücksichtigen, da nicht sicher ist, dass nicht dokumentierte Features sich nicht eines Tages wieder ändern. Ich habe keine Zweifel, dass es umgesetzt werden kann.

 

"Matryoshka" funktioniert!

Und es zeigt sich, dass wir das Wichtige bereits gemacht haben. Unten steht ein sehr einfacher Code der Funktion. Sie können einfach ihren Aufruf vor dem return Operator des OnChartEvent() Handlers einfügen.

int OnCalculate_Void()
{
   const int rates_total = Bars( _Symbol, PERIOD_CURRENT );
   CopyClose( _Symbol, PERIOD_CURRENT, 0, rates_total, _price );
   OnCalculate( rates_total, 0, 0, _price );
   return( 1 );
}//+------------------------------------------------------------------+

Nach der Erstellung des Indikators und seiner Anwendung auf den Chart, sehen wir, dass der Code generell schnell und unabhängig von ankommenden Kursänderungen funktioniert.

Der Nachteil dieser Implementierung ist, dass exakt die Schlusskurse in das price[] Array kopiert werden. Ggf. kann die CopyClose() Funktion mit dem was wir wollen ersetzt werden, indem im "Einstellungen"-Tab des Dialogfensters der Indikatoreigenschaften "Anwenden auf" eingerichtet wird. Ist der aktuelle Kurs einfach (Open, High, Low, Close), haben wir bereits die entsprechende CopyXXXX() Funktion. Bei komplizierteren Kursen (durchschnittlich, typisch oder gewichtet) müssen wir das Array anders berechnen.

Ich bin mir nicht sicher, ob wir die CopyClose() Funktion, die die ganze History des Arrays kopiert, nicht doch brauchen. Doch andererseits ist diese Funktion schnell genug, wenn die History nicht zu überladen ist. Eine Prüfung des Indikators auf EURUSD H1 mit History vor 1999 (ca. 700.000 Balken) ergab, dass der Indikator mit Berechnungen handelt und keinerlei Verlangsamung zeigt. Bei solchen Histories liegen mögliche Verlangsamungen nicht an der CopyXXXX() Funktion, sondern eher daran, dass man kompliziertere Indikator-Neuberechnungen vom Anfang der History braucht (das ist obligatorisch).


Einige Erkenntnisse und Schlussbemerkung

Was ist nun besser - eine Indikatordateioder das"Indikator + Advisor" Pärchen?

Die Antwort ist gar nicht so einfach. Einerseits ist es gut, wenn man eine Indikatordatei hat, da alle Funktionen, einschließlich Ereignis-Handler, sich an einem Ort befinden.

Andererseits nehmen wir mal an, dass 3 oder 4 Indikatoren zusammen mit einem Expert Advisor auf ein Chart angewandt werden- was gar nicht so selten vorkommt. Und nehmen wir mal weiter an, dass jeder Indikator seinen eigenen Ereignis-Handler hat, zusätzlich zu Standard OnCalculate(). Zur Vermeidung von Verwirrungen bei der Verarbeitung von Ereignissen in diesem "Durcheinander", ist es sinnvoller alle Ereignis-Handler, die nicht in den Indikatoren zugelassen sind, an einem Platz zu haben - dem Expert Advisor.

Lange haben Software-Entwickler dazu tendiert, uns die Möglichkeit der Verarbeitung von Ereignissen im Indikator anzubieten: von den nicht öffentlichen Beta-Versionen 09.09.09 (wo der Indikator als "reine Berechnungs- & mathematische Einheit" angesehen wird und nicht durch irgendwelche Features verunreinigt werden darf, die die Berechnungsgeschwindigkeit hemmen) sind genau 5 Monate vergangen. Und genauso muss die "Reinheit des Gedankens" leiden - und jetzt kommen wirklich einige voll chaotische Programmierer-Spinnereien auf den Markt. Doch die Ausgewogenheit liegt immer zwischen einem reinen, jedoch eingeschränkten Gedanken und einer nicht so sauberen, jedoch leistungsstärkeren Fähigkeit.

Im September/Oktober 2009, als die Herstellungszahl der MT5 Beta-Version noch keine 200 erreicht hatte, habe ich einen Code für das "Expert Adviser + Indikator" Pärchen geschrieben und auch Fehler beseitigt, mit dem man MA-Parameter spontan verwalten konnte - jedoch mit "einem Dreier" als Note: er wurde nur nach Kursänderungseingang aktualisiert, aber nicht sofort. Damals war das Pärchen die einzig mögliche Lösung, und jetzt ist es eher unwahrscheinlich, dass sich noch jemand dafür interessiert.

Damals wusste ich nicht, wie ich die Indikator-Funktionalität auf einen "Zweier" bringen sollte, d.h. so wie in der jüngsten Version präsentiert. Ich freue mich daher jetzt sehr, allen Interessierten jetzt eine bequemere Lösung anbieten zu können.


"Matryoshka" Videovorführung

Im Anhang finden Sie mein Kurzvideo, das zeigt, wie unsere Lösung funktioniert. Die weiche Änderung der MA-Kurve (nur der Zeitraum ändert sich - zuerst wächst er an, dann nimmt er ab) ist irgendwie schon verblüffend. Das ist Matryoshka (ähnlich wie die berühmten russischen Babuschkas).


Solche Tricks sind natürlich nur sinnvoll, wenn die Neuberechnung des Indikators an sich "von Null an" nicht zu viel Zeit in Anspruch nimmt. Der in diesem Indikator enthaltene, einfache MA erfüllt alle Voraussetzungen


Noch ein gerissener Aspekt

Sie erinnern sich, dass die ehemaligen externen Parameter des Indikators jetzt die globalen Variablen des Terminals sind (TGV), die Sie durch Drücken von F3 aufrufen können? Angenommen, Sie haben das Dialogfenster Globale Variablen geöffnet und einen der TGVs geändert (z.B. den MA Zeitraum. Dann rechnen Sie damit, dass diese Veränderung sofort im Indikator auf dem Chart abgebildet wird.

Im Terminal befindet sich aktuell kein Ereignis, das der vom Benutzer durchgeführten Bearbeitung der TGV entspricht (z.B. ChartEvent_GLOBALVAR_ENDEDIT). Ich denke, dass wir auch nicht die TGV-Veränderung im Dialogfenster Globale Variablen deaktivieren können. Deshalb können wir hier nicht mit irgendeinem Ereignis außer der Kursänderung rechnen. Was passiert aber in Echt?

Wenn Sie keine Taste Ihrer Tastatur drücken, dann ist die Aktualisierung selbst bei der nächsten Kursänderung "falsch": die Aktualisierte Variable wurde nicht auf "0" gesetzt und daher wird nur die "optimierte" Berechnung des Indikators ausgeführt (entsprechend dem vorherigen Wert der geänderten TGV). Um hier die Gerechtigkeit wieder herzustellen, kann ich nur zu einem Schritt raten: nach der Bearbeitung von TGV sollten Sie mindestens einmal den Hotkey drücken, der die TGV verändert, Aktualisiert auf "0" setzt und eine komplette Neuberechnung des Indikators in Gang bringt.

Jeder mögliche Benutzer und Entwickler sollte stets daran denken.


Angehängte Dateien: Quellcode und Video

Zu guter Letzt hänge ich die Quellcode-Dateien an. Erklärung:

  1. Custom Moving Average.mq5 - MA-Quellcode-Datei, die bei MT5 mit dabei ist.
  2. MyMA_ind_with_ChartEvent.mq5 - erste Implementierung ("Note 3"): Indikator-Aktualisierungen nur nach ankommender Kursänderung.
  3. MyMA_ind_with_ChartEvent_Matryoshka.mq5 - zweite Version (vielleicht "Note 2"): der Indikator aktualisiert sich sofort, ohne auf die Ankunft einer Kursänderung zu warten.

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

Erzeugung eines Indikators mit graphischen Kontrolloptionen Erzeugung eines Indikators mit graphischen Kontrolloptionen

All diejenigen, die sich mit Stimmungen auf dem Markt auskennen, kennen den MACD Indikator (seiner voller Name lautet Gleitender Durchschnitt Konvergenz/Divergenz) -das leistungsstarke Tool zur Analyse von Kursbewegungen, das von Händlers seit dem ersten Auftauchen von Computer-gestützten Analysemethoden verwendet wird. Dieser Beitrag beschäftigt sich mit möglichen Veränderungen des MACD und ihrer Implementierung in einen Indikator mit der Möglichkeit, zwischen den Veränderungen graphisch hin- und her zu wechseln.

Die Interaktion von MetaTrader 5 und MATLAB Die Interaktion von MetaTrader 5 und MATLAB

Dieser Beitrag beschäftigt sich mit den dEtailös der Interaktion zwischen MetaTrader 5 und dem MatLab Mathematik-Paket. Er erklärt die Mechanismen der Datenkonvertierung, den Entwicklungsprozess einer universellen Library, die mit dem MATLAB-Desktop interagieren kann. Zudem wird auch die Verwendung von DLL erklärt, die durch die MatLab Umgebung erzeugt werden. Dieser Beitrag richtet sich an bereits erfahrene Leser, die C++ und MQL5 kennen.

MQL5: Analyse und Umgang mit Berichten der US-Warenterminhandelsaufsichtsbehörde (US-Warenterminhandelsaufsichtsbehörde , CFTC) in MetaTrader 5 MQL5: Analyse und Umgang mit Berichten der US-Warenterminhandelsaufsichtsbehörde (US-Warenterminhandelsaufsichtsbehörde , CFTC) in MetaTrader 5

In diesem Beitrag entwickeln wir ein Analysetool für CFTC-Berichte. Wir lösen das folgende Problem: Entwicklung eines Indikators mit dem wir die CFTC-Berichtsdaten aus den von der Behörde zur Verfügung gestellten Datendateien ohne Zwischenschritte und Konvertierung direkt verwenden können. Dieser kann darüber hinaus noch für weitere Zwecke genutzt werden: die Daten als einen Indikator zeichnen, mit den Daten in anderen Indikatoren, in den Scripts für die automatische Analyse und im Expert Advisors zur Verwendung in den Handelsstrategien fortfahren.

Praktische Implementierung digitaler Filter in MQL5 für Anfänger Praktische Implementierung digitaler Filter in MQL5 für Anfänger

Der Gedanke einer Filterung digitaler Signale ist in Foren für den Aufbau von Handelssystemen umfassend diskutiert worden. Und es wäre sehr unschlau, keinen Standardcode für digitale Filter in MQL5 zu erzeugen. In diesem Beitrag beschreibt der Autor die Umwandlung des Codes eines einfachen SMA Indikators aus seinem Beitrag "Angepasste Indikatoren in MQL5 für Anfänger" in einen Code für einen komplizierteren und digitalen Filter. Daher ist dieser Beitrag die logische Fortsetzung des vorhergehenden. Außerdem wird hier auch gezeigt, wie man Text im Code ersetzen und Programmierfehler korrigieren kann.