English Русский 中文 Español 日本語 Português 한국어 Français Italiano Türkçe
3 Methoden zur Beschleunigung von Indikatoren anhand des Beispiels der linearen Regression

3 Methoden zur Beschleunigung von Indikatoren anhand des Beispiels der linearen Regression

MetaTrader 5Indikatoren | 7 April 2016, 14:05
1 173 0
ds2
ds2

Berechnungsgeschwindigkeit

Eine schnelle Berechnung der Indikatoren ist ein äußerst wichtiges Thema. Die Berechnungen können durch verschiedene Methoden beschleunigt werden. Es gibt zahlreiche Beiträge zu diesem Thema.

Wir werden nun 3 weitere Methoden zur Beschleunigung von Berechnungen untersuchen, die teilweise sogar den Code selbst vereinfachen. Alle beschriebenen Methoden sind algorithmisch, das heißt, wir werden nicht die Tiefe der Historie verringern oder zusätzliche Kerne des Prozessors aktivieren. Wir werden die Berechnungsalgorithmen direkt optimieren.



Basisindikator

Der Indikator, der für die Darstellung aller 3 Methoden verwendet wird, ist der Indikator der linearen Regression. Er erstellt auf jedem Balken eine Regressionsfunktion (gemäß der festgelegten Anzahl der letzten Balken) und zeigt, welchen Wert er bei diesem Balken haben sollte. Als Ergebnis erhalten wir eine durchgehende Linie:

So sieht der Indikator im Terminal aus

 

Die Gleichung der linearen Regression sieht so aus:

In unserem Fall ist x die Nummer des Balkens und y der Preis.

Die Verhältnisse der erwähnten Gleichung werden so berechnet:

wobei N die Anzahl der Balken ist, die zur Erstellung der Regressionslinie genutzt werden.

So sehen diese Gleichungen in MQL5 aus (innerhalb des Zyklus für alle Balken der Historie):

            // Finding intermediate values-sums
            Sx  = 0;
            Sy  = 0;
            Sxx = 0;
            Sxy = 0;
            for (int x = 1; x <= LRPeriod; x++)
              {
               double y = price[bar-LRPeriod+x];
               Sx  += x;
               Sy  += y;
               Sxx += x*x;
               Sxy += x*y;
              }

            // Regression ratios
            double a = (LRPeriod * Sxy - Sx * Sy) / (LRPeriod * Sxx - Sx * Sx);
            double b = (Sy - a * Sx) / LRPeriod;

            lrvalue = a*LRPeriod + b;

Der vollständige Code des Indikators ist an diesen Beitrag angehängt. Er enthält auch alle im vorliegenden Beitrag beschriebenen Methoden. Deshalb muss in den Einstellungen des Indikators die Berechnungsmethode "Standard" ausgewählt werden:

Eng_G0-Standard

Einstellungsfenster der Eingabeparameter des Indikators bei der Einrichtung auf dem Diagramm 



Erste Optimierungsmethode. Gleitende Summen

Es gibt zahllose Indikatoren, in denen die Summe der Werte einer bestimmten Abfolge von Balken für jeden Balken berechnet wird. Und diese Abfolge verschiebt sich konstant bei jedem Balken. Das bekannteste Beispiel ist Moving Average (MA). Er berechnet die Summe von N letzten Balken und teilt diesen Wert durch ihre Anzahl.

Ich glaube, nur wenige wissen, dass es eine elegante Art gibt, die Berechnung solcher gleitender Summen deutlich zu beschleunigen. Ich nutze diese Methode schon seit ziemlich langer Zeit in meinen Indikatoren, als ich herausfand, dass sie auch bei herkömmlichen MA-Indikatoren in MetaTrader 4 und 5 verwendet wird. (Dies ist nicht der erste Fall, in dem ich feststelle, dass die MetaTrader-Indikatoren von den Entwicklern ordentlich optimiert wurden. Vor langer Zeit suchte ich nach schnellen ZigZag-Indikatoren und ein herkömmlicher Indikator erwies sich als effektiver als die meisten externen. Im Übrigen liefert der erwähnte Forumsbeitrag auch Optimierungsmethoden für ZigZag, falls jemand sie braucht).

Nun aber zurück zu den gleitenden Summen. Vergleichen wir die berechneten Summen für zwei benachbarte Balken. Die untere Abbildung demonstriert, dass diese Summen eine beträchtliche Überschneidung haben (dargestellt in Grün). Die berechnete Summe für Balken 0 unterscheidet sich von der Summe für Balken 1 nur dadurch, dass die Summe einen veralteten Balken (roter Balken auf der linken Seite) nicht berücksichtigt, aber einen neuen Balken (blauer Balken auf der rechten Seite) enthält:

Eng_m1

Ausgeschlossene und enthaltene Werte der Summe während einer Verschiebung um einen Balken

 

Deshalb müssen nicht alle erforderlichen Balken erneut summiert werden, wenn die Summe für Balken 0 berechnet wird. Wir können nur die Summe von Balken 1 nehmen, einen Wert abziehen und einen neuen hinzufügen. Es sind nur zwei Rechenoperationen erforderlich. Mithilfe dieser Methode können wir die Berechnung des Indikators deutlich beschleunigen.

Beim Moving Average wird diese Methode routinemäßig eingesetzt, da der Indikator alle Durchschnittswerte in seinem einzigen Puffer aufbewahrt. Und das ist nichts anderes als die Summen geteilt durch N, d. h. die Anzahl der in der Summe enthaltenen Balken. Multiplizieren wir den Wert aus dem Puffer wiederum mit N, können wir leicht eine Summe für jeden beliebigen Balken erhalten und die oben aufgeführte Methode anwenden.

Nun werde ich Ihnen zeigen, wie diese Methode in einem komplizierteren Indikator angewendet wird: lineare Regression. Sie haben bereits gesehen, dass die Gleichungen für die Berechnung von Verhältnissen von Regressionsfunktionen vier Summen enthalten: x, y, x*x, x*y. Die Berechnung dieser Summen muss zwischengespeichert werden. Dafür müssen die Puffer für jede Summe im Indikator zugewiesen werden:

double ExtBufSx[], ExtBufSy[], ExtBufSxx[], ExtBufSxy[];

Der Puffer ist nicht zwangsläufig in einem Diagramm zu sehen. MetaTrader 5 verfügt über einen speziellen Puffertyp für Zwischenberechnungen. Wir werden ihn nutzen, um Puffernummern in OnInit zuzuweisen:

   SetIndexBuffer(1, ExtBufSx,  INDICATOR_CALCULATIONS);
   SetIndexBuffer(2, ExtBufSy,  INDICATOR_CALCULATIONS);
   SetIndexBuffer(3, ExtBufSxx, INDICATOR_CALCULATIONS);
   SetIndexBuffer(4, ExtBufSxy, INDICATOR_CALCULATIONS);

Der Standardcode der Berechnung der linearen Regression wird verändert und sieht nun so aus:

            // (The very first bar was calculated using the standard method)        
        
            // Previous bar
            int prevbar = bar-1;
            
            //--- Calculating new values of intermediate totals 
            //    from the previous bar values
            
            Sx  = ExtBufSx [prevbar]; 
            
            // An old price comes out, a new one comes in
            Sy  = ExtBufSy [prevbar] - price[bar-LRPeriod] + price[bar]; 
            
            Sxx = ExtBufSxx[prevbar];
            
            // All the old prices come out once, a new one comes in with an appropriate weight
            Sxy = ExtBufSxy[prevbar] - ExtBufSy[prevbar] + price[bar]*LRPeriod;
            
            //---

            // Regression ratios (calculated the same way as in the standard method)
            double a = (LRPeriod * Sxy - Sx * Sy) / (LRPeriod * Sxx - Sx * Sx);
            double b = (Sy - a * Sx) / LRPeriod;

            lrvalue = a*LRPeriod + b;

Der vollständige Code des Indikators ist an diesen Beitrag angehängt. In den Einstellungen des Indikators muss die Berechnungsmethode "Moving Totals" ausgewählt werden.



Die zweite Methode. Vereinfachung

Diese Methode wird Mathematikliebhabern gefallen. In komplizierten Gleichungen können oft Fragmente gefunden werden, die sich als die rechten Teile anderer bekannter Gleichungen herausstellen. Dies gibt uns die Möglichkeit, diese Fragmente durch ihre linken Teile zu ersetzen (die für gewöhnlich nur aus einer Variable bestehen). In anderen Worten: Wir können eine komplizierte Gleichung vereinfachen. Und es kann sich herausstellen, dass einige Elemente dieser vereinfachten Gleichung bereits als Indikatoren umgesetzt wurden. In diesem Fall kann der Code des Indikators, der diese Gleichung enthält, seinerseits deutlich vereinfacht werden.

Als Resultat erhalten wir mindestens einen platzsparenderen und einfacheren Code. In einigen Fällen kann er auch schneller sein, sofern die Geschwindigkeit der im Code umgesetzten Indikatoren gut optimiert ist.

Es hat sich herausgestellt, dass die Gleichung der linearen Regression ebenfalls vereinfacht werden und ihre Berechnung durch die Initialisierung mehrerer Standardindikatoren in MetaTrader 5 ersetzt werden kann. Viele ihrer Elemente werden im Indikator Moving Average in seinen unterschiedlichen Berechnungsmodi berechnet:

  • die Summe y ist in Simple Moving Average vorhanden:

  • die Summe x*y ist in Linear Weighted Moving Average vorhanden:

Beachten Sie, dass die Gleichung für LWMA nur dann wahr ist, wenn wir die an der Regression beteiligten Balken von 1 bis N in aufsteigender Reihenfolge von der Vergangenheit zur Zukunft hin nummerieren:

Eng_m2

Konventionelle Nummerierung der Balken für die Regression für die Nutzung des LWMA-Indikators 

 

Deshalb muss in allen anderen Gleichungen die gleiche Nummerierung angewandt werden.

Weiter mit der Methode:

  • die Summe x ist nichts weiter als die Summe der Zahlenreihe (1 + 2 + ... + N), die durch die folgende Gleichung ersetzt werden kann:

  • die Summe x*x wird gemäß einer anderen Gleichung vereinfacht:

  • um ein Diagramm des Indikators zu erstellen, müssen wir den Wert der Regressionsgleichung nur für ihren letzten Balken errechnen, in dem x gleich N ist, d. h. die Gleichung der Regressionsfunktion kann durch den folgenden besonderen Fall ersetzt werden:

Somit ermöglichen es uns die letzten fünf Gleichungen, Ersetzungen für alle Variablen in den Gleichungen zur Verhältnisberechnung a und b und in der Regressionsgleichung selbst zu erhalten. Nach der Fertigstellung all dieser Ersetzungen erhalten wir eine brandneue Gleichung für die Berechnung des Regressionswerts. Sie besteht nur aus den Werten des Indikators Moving Average und der Zahl N. Nach der Kürzung ihrer Elemente erhalten wir eine elegante Gleichung:

Diese Gleichung ersetzt alle Berechnungen, die im Basisindikator der linearen Regression durchgeführt wurden. Es ist klar zu sehen, dass der Code des Indikators mit dieser Gleichung viel platzsparender sein wird. Im Kapitel "Vergleich der Geschwindigkeiten" werden wir herausfinden, ob der Code auch schneller arbeitet.

Angegebener Teil des Indikators:

            double SMA [1];
            double LWMA[1];
            CopyBuffer(h_SMA,  0, rates_total-bar, 1, SMA);            
            CopyBuffer(h_LWMA, 0, rates_total-bar, 1, LWMA);

            lrvalue = 3*LWMA[0] - 2*SMA[0];

Die Indikatoren LWMA und SMA werden vorab in OnInit erstellt:

      h_SMA  = iMA(NULL, 0, LRPeriod, 0, MODE_SMA,  PRICE_CLOSE);
      h_LWMA = iMA(NULL, 0, LRPeriod, 0, MODE_LWMA, PRICE_CLOSE);

Der vollständige Code findet sich in den Dateien im Anhang zu diesem Beitrag. In den Einstellungen des Indikators muss die Berechnungsmethode "Simplification" ausgewählt werden.

Beachten Sie, dass wir mit dieser Methode Indikatoren genutzt haben, die im Terminal eingebaut sind, d. h. die Funktion iMA mit der Auswahl der geeigneten Glättungsmethoden wurde anstelle von iCustom verwendet. Das ist ein wichtiger Faktor, weil eingebaute Indikatoren theoretisch sehr schnell arbeiten sollten. Ins Terminal sind einige weitere Standardindikatoren eingebaut (sie werden durch Funktionen mit dem Präfix "i" erstellt, beispielsweise iMA). Bei der Vereinfachungsmethode ist es am besten, die Gleichungen auf diese Indikatoren zu vereinfachen.



Die dritte Methode. Annäherung

Die Idee hinter dieser Methode ist, dass "schwere" Indikatoren, die in einem Expert Advisor verwendet werden, durch viel schnellere ersetzt werden können, die erforderliche Werte annähernd berechnen. Mithilfe dieser Methode können Sie Ihre Strategie schneller testen. Immerhin ist die Genauigkeit von Prognosen in der Debugging-Phase nicht so wichtig.

Außerdem kann diese Methode mit einer funktionierenden Strategie angewendet werden, um die Parameter grob zu optimieren. So können effektive Wertbereiche der Parameter schnell gefunden werden. Anschließend können sie zur Feinabstimmung durch "schwere" Indikatoren verarbeitet werden.

Nebenbei kann sich herausstellen, dass eine annähernde Berechnung bereits ausreicht, damit eine Strategie ordentlich funktioniert. In diesem Fall kann ein "leichter" Indikator auch im realen Handel genutzt werden.

Für die lineare Regression lässt sich eine schnelle Gleichung entwickeln, deren Ergebnis der Regression ähnlich ist. Beispielsweise können wir Regressionsbalken in zwei Gruppen aufteilen, den Durchschnittswert für beide Gruppen berechnen, eine Linie durch diese zwei Durchschnittspunkte ziehen und den Wert der Linie beim letzten Balken definieren:

Eng_Points

Die Punkte wurden in zwei Gruppen – links und rechts – eingeteilt und die Berechnungen durchgeführt

 

Eine solche Berechnung enthält weniger Rechenoperationen als eine Regression. So werden die Berechnungen beschleunigt.

           // The interval midpoint
           int HalfPeriod = (int) MathRound(LRPeriod/2);
           
           // Average price of the first half
           double s1 = 0;
           for (int i = 0; i < HalfPeriod; i++)
              s1 += price[bar-i];
           s1 /= HalfPeriod;
              
           // Average price of the second half
           double s2 = 0;
           for (int i = HalfPeriod; i < LRPeriod; i++)
              s2 += price[bar-i];
           s2 /= (LRPeriod-HalfPeriod);
           
           // Price excess by one bar
           double k = (s1-s2)/(LRPeriod/2);
           
           // Extrapolated price at the last bar
           lrvalue = s1 + k * (HalfPeriod-1)/2;

Der vollständige Code des Indikators ist an diesen Beitrag angehängt. In den Einstellungen des Indikators muss die Berechnungsmethode "Approximating" ausgewählt werden.

Analysieren wir nun, wie nahe die Annäherung am Original liegt. Dazu müssen wir Indikatoren mit Standard- und annähernder Berechnung auf einem Diagramm einrichten. Wir müssen auch alle weiteren Indikatoren hinzufügen, die bekannterweise der Regression ähnlich sind. Dennoch muss auch irgendein Trend mithilfe vergangener Balken berechnet werden. Moving Average ist dafür gut geeignet (ich habe LWMA verwendet, nicht SMA, da er dem Regressionsdiagramm viel ähnlicher ist). Anhand des Vergleichs mit ihm können wir beurteilen, ob wir eine gute Annäherung haben. Ich denke, sie ist gut:

Eng_G3

 Die rote Linie ist näher an der blauen als an der grünen. Das bedeutet, dass der Annäherungsalgorithmus gut ist



Vergleich der Geschwindigkeiten

Die Anzeige des Logs kann in den Parametern des Indikators eingeschaltet werden:

Eng_True

Einrichtung des Indikators für die Beurteilung der Geschwindigkeit des Ausführung

In diesem Fall wird der Indikator alle erforderlichen Daten für die Beurteilung der Geschwindigkeit im Meldungslogbuch des Expert Advisors anzeigen: die Zeit des Beginns der Ereignisverarbeitung OnInit() und das Ende von OnCalculate(). Ich werde erklären, warum die Geschwindigkeit anhand dieser zwei Werte beurteilt werden muss. Der OnInit()-Agent wird bei fast allen Methoden quasi sofort ausgeführt und OnCalculate() beginnt bei fast allen Methoden gleich nach OnInit(). Die einzige Ausnahme bildet eine Vereinfachungsmethode, bei der die Indikatoren SMA und LWMA in OnInit() erstellt werden. Bei dieser (und nur bei dieser!) Methode gibt es eine Verzögerung zwischen dem Ende von OnInit() und dem Beginn von OnCalculate():

Eng_log

Durch den Indikator angezeigter Ausführungslog im Experts-Logbuch des Terminals 

 

Das bedeutet, dass diese Verzögerung durch die neu erstellten SMA und LWMA verursacht wird, die zu dieser Zeit irgendwelche Berechnungen ausführten. Die Dauer dieser Berechnungen muss ebenfalls berücksichtigt werden, deshalb beurteilen wir die gesamte Zeit "ohne Unterbrechungen", also ab der Initialisierung des Regressionsindikators bis zum Ende seiner Berechnungen.

Um den Unterschied zwischen den Geschwindigkeiten verschiedener Methoden genauer zu erkennen, werden alle Beurteilungen mithilfe eines großen Daten-Arrays angestellt: M1-Timeframe mit maximal zugänglicher Tiefe der Historie. Das sind mehr als 4 Millionen Balken. Jede Methode wird zweimal beurteilt: mit 20 und 2000 Balken in der Regression.

Die Ergebnisse sehen so aus:

Eng_Duration 1

Eng_Duration 2
 

Wie Sie sehen können, zeigten alle drei Optimierungsmethoden eine mindestens zweifache Erhöhung der Geschwindigkeit im Vergleich mit der Standardmethode zur Berechnung der Regression. Nach der Erhöhung der Menge der Balken in der Regression zeigten die Methoden gleitende Summen und Vereinfachung fantastische Geschwindigkeiten. Sie arbeiteten hunderte Male schneller als die Standardmethoden!

Ich sollte anmerken, dass die Berechnungsdauer dieser zwei Methoden nahezu unverändert blieb. Dies lässt sich einfach erklären: Ganz egal, wie viele Balken genutzt wurden, um eine Regression zu erschaffen, werden nur 2 Handlungen in der Methode der gleitenden Summen ausgeführt – ein alter Balken geht und ein neuer kommt. Es gibt keine Zyklen, die von der Länge der Regression abhängig sind. Somit wird die Ausführungsdauer der Methode im Vergleich zu 20 Balken auch dann nur unwesentlich steigen, wenn die Regression 20000 oder 200000 Balken umfasst.

Die Vereinfachungsmethode nutzt in ihrer Gleichung den Moving Average in verschiedenen Modi. Wie ich bereits angemerkt habe, lässt sich dieser Indikator durch die Methode der gleitenden Summen leicht optimieren und wird von den Entwicklern des Terminals angewendet. Es ist kein Wunder, dass die Ausführungsdauer der Vereinfachungsmethode sich auch dann nicht ändert, wenn die Länge der Regression steigt.

Die Methode der gleitenden Summen hat sich als schnellste Berechnungsmethode in unserem Experiment erwiesen.

 



Fazit

Einige Händler sitzen nur still und warten auf das Ende einer weiteren Optimierung der Parameter ihrer Handelssysteme in ihren Testern. Doch es gibt auch Händler, die schon zu dieser Zeit Handel treiben und Geld verdienen. Durch die Berechnungsgeschwindigkeiten, die man dank der beschriebenen Methoden erhält, wird verdeutlicht, warum diese Gruppen von Händlern so unterschiedlich sind und warum es so wichtig ist, auf die Qualität der Handelsalgorithmen zu achten.

Es macht keinen Unterschied, ob Sie die Programme für das Terminal selbst schreiben oder sie bei Drittprogrammierern in Auftrag geben (zum Beispiel über "Aufträge"). Sie erhalten in jedem Fall nicht nur funktionierende Indikatoren und Strategien, sondern auch schnelle, sofern Sie bereit sind, gewisse Anstrengungen zu unternehmen oder etwas Geld auszugeben.

Wenn Sie irgendeine Methode zur Algorithmusbeschleunigung nutzen, erhalten Sie einen Geschwindigkeitsvorteil um das Zehn- bis Hundertfache der Standardalgorithmen. Das bedeutet, dass Sie beispielsweise die Parameter Ihrer Handelsstrategien in einem Tester hundert Mal schneller optimieren können, und zwar sorgfältiger und häufiger. Natürlich steigen damit auch die Einkünfte aus Ihrem Handel.

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

Beigefügte Dateien |
Statistische Verteilungen von Wahrscheinlichkeiten in MQL5 Statistische Verteilungen von Wahrscheinlichkeiten in MQL5
Dieser Beitrag behandelt Verteilungen von Wahrscheinlichkeiten (normal, lognormal, binomial, logistisch, Cauchy-Verteilung, Studentsche t-Verteilung, Laplace-Verteilung, Poisson-Verteilung, Secans-Hyperbolicus-Verteilung, Beta- und Gamma-Verteilung) zuf&auml;lliger Statistiken in der angewandten Statistik. Er nennt ebenfalls Klassen f&uuml;r den Umgang mit diesen Verteilungen.
Filtern von Signalen auf Basis statistischer Daten von Preiskorrelationen Filtern von Signalen auf Basis statistischer Daten von Preiskorrelationen
Gibt es irgendeine Korrelation zwischen dem Verhalten des Preises in der Vergangenheit und seinen zukünftigen Trends? Warum legt der Preis heute die gleichen Merkmale an den Tag wie bei seinen gestrigen Bewegungen? Können die Statistiken zum Prognostizieren der Preisdynamiken genutzt werden? Es gibt eine Antwort und sie ist positiv. Wenn Sie Zweifel haben, ist dieser Beitrag genau das Richtige für Sie. Ich werde Ihnen erzählen, wie ein funktionierender Filter für ein Handelssystem in MQL5 erstellt wird, und ein interessantes Muster in Preisveränderungen offenlegen.
Tracing, Debugging und strukturelle Analyse von Quellcodes Tracing, Debugging und strukturelle Analyse von Quellcodes
Die gesamte Problematik der Erstellung einer Struktur eines auszuführenden Codes und dessen Tracing lässt sich ohne ernsthafte Schwierigkeiten lösen. Diese Möglichkeit trat mit MetaTrader 5 dank einer neuen Funktion der MQL5-Sprache in Erscheinung: der automatischen Erstellung von Variablen eines komplexen Datentyps (Strukturen und Klassen) und deren Beseitigung beim Verlassen des lokalen Umfelds. Dieser Beitrag beschreibt die Methoden und liefert ein vorgefertigtes Tool.
Universeller Expert Advisor: Handelsmodi von Strategien (Teil 1) Universeller Expert Advisor: Handelsmodi von Strategien (Teil 1)
Jeder Entwickler von Expert Advisors, ungeachtet seiner Programmierfähigkeiten, wird mit den gleichen Aufgaben und algorithmischen Problemen konfrontiert, die für einen sicheren Handelsprozess auf diese oder jene Weise gelöst werden müssen. Dieser Beitrag beschreibt die Möglichkeiten der 'Trading-Engine' CStrategy, die die Lösung dieser Aufgaben übernehmen und dem Nutzer geeignete Mechanismen zur Beschreibung seiner Handelsidee anbieten kann.