MetaTrader 5 herunterladen

Der naive Bayes-Klassifikator für die Signale einer Reihe von Indikatoren

7 September 2017, 10:31
Stanislav Korotky
0
212

Ob wir es wollen oder nicht, die Statistik spielt im Handel eine bedeutende Rolle. Ausgehend von fundamentalen Nachrichten voller Zahlen und endend mit den Auswertungen des Handels oder der Testergebnisse, nichts geht ohne statistische Verfahren und Methoden. Gleichzeitig ist die Verwendung statistischer Methoden in den Handelsentscheidungen eine der umstrittensten Thema. Verhält sich der Markt zufällig, sind die Preise stationär, sind statistische Verfahren überhaupt anwendbar? Man könnte unendlich lange streiten. Leicht findet sich Material und Argumente zu jedem Standpunkt mit rein wissenschaftlichen Berechnungen und beeindruckenden Charts im Internet und auch auf den Seiten von MQL5.com. Händler jedoch interessieren sich eher für die praktische Seite — wie funktioniert es im Handelsterminal. Dieser Artikel versucht in einem pragmatischen Ansatz, das Wahrscheinlichkeitsmodell für die Handelsentscheidungen durch die Verwendung einer Reihe von technischen Indikatoren anzuwenden. Wenig Theorie aber viel Praxis.

Die Idee besteht darin, das Potenzial verschiedener Indikatoren aus der Perspektive der Wahrscheinlichkeitstheorie zu beurteilen, und die Möglichkeit zu prüfen, über die Indikatorauswahl den Prozentsatz der Gewinne des Handelssystems zu erhöhen.

Das verlangt das Erstellen eines Rahmens, um die Signale der jeweiligen Indikatoren zu verarbeiten, und einen einfachen Experten für die Tests auf dieser Basis.

Es empfiehlt sich, die standardmäßigen Indikatoren einzubeziehen, obwohl der Rahmen auch Indikatoren der Nutzer berücksichtigen und analysieren kann.

Aber vor dem Entwurf und der Realisation des Algorithmus, ist dennoch ein Priese Theorie notwendig.

Einführung in das Modell der bedingten Wahrscheinlichkeiten

Der Titel des Artikel beruft sich auf den naiven Bayes-Klassifikator. Er basiert auf der bekannten Bayes'schen Formel, die wir jetzt kurz erklären werden. Die Bezeichnung "naive" gründet sich auf die notwendige Annahme, dass die Zufallsvariablen der Formel voneinander unabhängig sind. Die Unabhängigkeit der Indikatoren betrachten wir später, jetzt erst einmal — die nackte Formel.

   (1)

wobei H die Hypothese über den inneren Zustand des Systems ist (in unserem Fall eine Hypothese über den Markt und das Handelssystem), E das beobachtete Ereignis (in unserem Fall die Signale der Indikatoren), und die Wahrscheinlichkeiten, die sie beschreiben:
  • P(H) ist die Wahrscheinlichkeit a priori, bekannt aus früheren Beobachtungen, die Wahrscheinlichkeit des Zustandes von H;
  • P(E) ist die gesamte Wahrscheinlichkeit des Ereignisses E unter Berücksichtigung aller bekannten Hypothesen, von denen einige normalerweise vorhanden sind (es ist zu beachten, dass die Hypothesen disjunkt sind, d.h. zu einem Zeitpunkt gibt es immer nur einen Zustand; es gibt Referenzen und Links, für die, die das Thema vertiefen wollen);
  • P(E|H) ist die Wahrscheinlichkeit des Vorkommens des Ereignisses E, wenn die Hypothese (Zustand) H zutrifft;
  • P(H|E) ist die Wahrscheinlichkeit a posteriori der Hypothese (Zustand) H, wenn das Ereignis beobachtet wird.

Betrachten wir beispielsweise ein einfaches Handelssystem. Solche Zustände des Marktes für die Hypothese H wären Preisbewegungen nach oben (kaufen), nach unten (verkaufen) und seitwärts (warten). Die Signale der Indikatoren, die diese Zustände beschreiben, werden zu unseren Ereignissen E

Für die Signale eines bestimmten Indikators lassen sich mit der rechten Seite der Formel (1) die Wahrscheinlichkeiten leicht aus der Historie ausrechnen, um am Ende den wahrscheinlichsten Zustand des Marktes P(H|E) zu bestimmen.

Die Berechnung erfordert jedoch eine genauere Definition der Hypothese und der Methode für das Erstellen der Statistik, die als Grundlage für die beobachteten Wahrscheinlichkeiten dienen.

Zunächst nehmen wir an, dass der Handel auf der Basis von Bars (nicht den Ticks) durchgeführt wird. Der Handelserfolg kann über den Gewinn, Profitfaktor oder anderen Kennzahlen bestimmt werden. Aber der Einfachheit halber verwenden wir das Verhältnis von Gewinnern zu Verlierern. Das verbindet die Auswertung des Systems direkt mit den Wahrscheinlichkeiten erfolgreicher Positionen (der verwendeten Signale).

Wir beschränken uns auch auf ein Handelssystem ohne Take-Profit und ohne Stopp-Loss und ohne einen nachgezogenen Stopp und verändernden Lotgrößen. All diese Parameter könnten in das Modell integriert werden, aber das würde die Berechnung der Wahrscheinlichkeiten signifikant verkomplizieren, weil alles dann zu einer multidimensionale Verteilung werden würde. Der einzige Parameter des Handelssystem ist die Haltezeit offener Positionen in Bars. Anders ausgedrückt, sobald eine Position in eine Richtung wegen der verwendeten Indikatoren eröffnet wurde, wird sie automatisch nach einer vordefinierten Zeit wieder geschlossen. Dieser Ansatz zeigt recht gut, ob die Hypothese über die Richtung des Marktes richtig oder falsch ist. So kann die Hypothese in ihrer Reinform getestet werden, ohne ohne Sicherung und Aufprallschutz.

Um die Vereinfachung auf die Spitze zu treiben, machen wir zwei weitere radikale Schnitte.

Wie oben erwähnt würden normalerweise "Kaufen", "Verkaufen" und "Warten" als Handleshypothesen verwendet werden. Wenn wir "Warten" weglassen, würde das unsere Berechnung deutlich vereinfachen, ohne im Allgemeinen das System zu verändern. Es könnte sein, dass diese Vereinfachung die Verwendbarkeit negativ verändern könnte, und teilweise ist das wohl so. Wenn man sich jedoch die Menge des immer noch verbleibenden Materials anschaut, das zu lesen ist, werden sie zustimmen, dass es gut ist, zunächst ein arbeitsfähiges Modell zu erstellen, um es später langsam zu erweitern. Diejenige, die ein komplexeres Modell mit der Verteilung der Wahrscheinlichkeitsdichte erstellen wollen, können entsprechenden Arbeiten im Internet finden (auf Englisch z.B. Reasoning Methods for Merging Financial Technical Indicators, das ein hybrides, probabilistisches Entscheidungssystem beschreibt).

Zum Schluss der zweite und abschließende Schnitt durch das Zusammenführen von "Kaufen" und "Verkaufen" in einen Zustand von allgemeinerer Bedeutung — der "Positionseröffnung". Signale unterschiedlicher Richtung eines Indikators werden generell symmetrisch und in gleicher Weise verwendet. Zum Beispiel würde das Signal Überkauft eines Indikators zum "Verkaufen" führen, und das Signal Überverkauft zum "Kaufen".

In anderen Worten, die Hypothese H steht nun für eine erfolgreicher Positionseröffnung, welcher Richtung auch immer ("Kaufen" oder "Verkaufen").

Unter diesen Voraussetzungen können die Wahrscheinlichkeiten der rechten Seite der Formel (1) mit den ausgewählten, historischen Daten wie folgte berechnet werden.


Da auf jeder Bar eine Position eröffnet werden kann — wird eine der beiden Richtungen profitabel sein (der Spread wird vernachlässigt, da D1 als Zeitrahmen hier gewählt worden ist, wie weiter unten detailliert ausgeführt).

P(E) = Anzahl der Bars mit einem Signal eines Indikators / Gesamtzahl der Bars

P(E|H) = Anzahl der Bars mit einem Signal eines Indikators, das in die profitable Richtung weist / Gesamtzahl der Bars

Die Wahrscheinlichkeit des Signals des jeweiligen Indikators, um eine profitable Position zu eröffnen, kann mit der vereinfachten Formel aus den historischen Daten berechnet werden.

   (2)

wobei Nok die Anzahl der richtigen und Ntotal die Gesamtzahl aller Signale ist.

Der Rahmen zur Berechnung dieser Wahrscheinlichkeiten für jeden Indikator wird etwas später implementiert. Wie wir sehen werden, ist diese Wahrscheinlichkeit normalerweise nahe 0,5 und wir müssen ein bisschen forschen, um jene Bedingungen zu finden, mit denen dieser Wert stabil über 0,5 liegt. Indikatoren aber mit solch hohen Werten sind selten. Die Standardindikatoren, mit denen wir uns hauptsächlich beschäftigen werden, haben Wahrscheinlichkeiten zwischen 0,51 und 0,55. Es ist klar, dass solche Werte zu klein sind, und vielleicht nur das Kapital halten, statt es zu erhöhen.

Um dieses Problem zu lösen, müssen mehrere Indikatoren kombiniert werden. An sich ist dieser Weg nicht neu und wird von den meisten Händlern verwendet. Aber die Wahrscheinlichkeitstheorie erlaubt eine quantitative Analyse der Effizienz der Indikatoren in verschiedenen Kombinationen und eine Bewertung des Potentials.

Formel (1) für den Fall von drei Indikatoren (A, B, C) schaut wie folgt aus:

  (3)

Sie sollte in eine Form umgewandelt werden, die bequem algorithmisch berechnet werden kann. Zum Glück wird die Bayes'sche Theorie in vielen Branchen angewendet, und daher gibt es für unseren Fall bereits fertige Rezepte.

Insbesondere existiert der Naive Bayes'sche Spamfilter. Es gibt keine Notwendigkeit, das tiefschürfend zu studieren. Es sind nur dessen grundlegenden Konzepte relevant. Ein Dokument (z.B. eine Email-Nachricht) wird als Spam gekennzeichnet, wenn es bestimmte, charakteristische Worten enthält. Die allgemeine Häufigkeit des Vorkommens in der Sprache und die Auftrittswahrscheinlichkeit im Spam sind bekannt. Ebenso kennen wir die allgemeinen Wahrscheinlichkeiten der Signale der Indikatoren und Prozentsatz der "Treffer". Mit anderen Worten, um die Theorie zur Spamerkennung für unser Problem zu verwenden, genügt es, die Hypothese "Spam" durch "profitable Position" und das Ereignis "Wort" durch das "Indikatorsignal" zu ersetzen.

Dann kann die Formel (3) mit den Wahrscheinlichkeiten der jeweiligen Indikatoren in folgender Weise erweitert werden (vergleiche mit der Berechnung von oben):

   (4)

Die Wahrscheinlichkeiten P(H|A), P(H|B) und P(H|C) werden mit der Formel (2) für jeden Indikator einzeln berechnet.

Natürlich kann die Formel (4) leicht auf jede Anzahl von Indikatoren erweitert werden. Um zu verstehen, wie die Anzahl der Indikatoren den Wahrscheinlichkeitswert einer richtigen Handelsentscheidung beeinflussen, nehmen wir an, alle Indikator haben dieselben Wahrscheinlichkeitswerte:


Aus der Formel (4) wird:

   (5)

wobei N die zahl der Indikatoren ist.

Der Graph dieser Funktion für verschiedene N zeigt das Bild 1.

Darstellung der gemeinsamen Wahrscheinlichkeit bei einer unterschiedlichen Anzahl von Zufallsvariablen

Fig. 1. Darstellung der gemeinsamen Wahrscheinlichkeit bei einer unterschiedlichen Anzahl von Zufallsvariablen

Ergo, bei p = 0.51 erhalten wir P(3) = 0.53, ist wenig beeindruckend; aber bei p = 0.55 wird P(3) = 0.65, das ist deutlich besser.

Die Unabhängigkeit der Indikatoren

Die oben besprochenen Formeln basieren auf der Annahme der Unabhängigkeit der Zufallsprozesse, in unserem Fall die Signale der Indikatoren. Aber trifft das zu?

Tatsächlich haben aber bestimmte Indikatoren, inklusive der standardmäßigen, vieles gemeinsam. In der Abbildung Figure 2 werden einige mitgelieferte Indikatoren gezeigt.

Gruppen ähnlicher Standardindikatoren

Fig. 2. Gruppen ähnlicher Standardindikatoren

Es ist offensichtlich, dass die Stochastik und der Indikator WPR für dieselbe Periode sich überlagern bzw. im letzten Fenster praktisch ident sind. Dies ist nicht verwunderlich, da ihre Formeln äquivalent sind.

Gleich darüber im Bild zeigen sich die Indikatoren MACD und der Awesome Oszillator als praktisch identisch, korrigiert durch den Mittelwertstyp. Darüber hinaus basieren beide auf einem gleitenden Durchschnitt (MA), sie können nicht ohne ihn ermittelt werden.

RSI, RVI, CCI sind auch stark korrelierend. Es sollte angemerkt werden, dass praktisch alle standardmäßigen Oszillatoren einander sehr ähnlich sind, ihre Korrelationskoeffizienten sind nahe 1.

Weiters gibt es eine bemerkenswerte Koinzidenz der Volatilität zwischen ATR und StdDev im besonderen.

Das muss alles berücksichtigt werden, wenn für das Handelssystem die Indikator ausgewählt werden, da die Ergebnisse von ausgewählten abhängigen Indikatoren viel schlechter sind, als theoretisch zu erwarten.

Übrigens, die gleiche Situation tritt beim Training neuronaler Netzwerke auf. Händler verwenden sie oft, um die Daten beliebig ausgewählter Indikator auszuwerten. Aber die Einspeisung voneinander abhängiger Vektoren reduziert die Effektivität des Trainings deutlich, und verschwendet die Fähigkeiten des Netzwerkes. Das Volumen der analysierten Daten erscheint groß, aber die gewonnenen Informationen sind redundant und bedeutungslos.

Ein korrektes Vorgehen würde die Berechnung der Korrelationen zwischen den Indikatoren verlangen, und zu einer Indikatorauswahl mit den kleinsten paarweisen Werten führen. Das ist ein eigener und großer Forschungsbereich. Interessierte finden weiterführende Artikel im Internet. Hier folgen wir den allgemeinen Ideen auf der Grundlage der oben gemachten Beobachtungen. Zum Beispiel eine Auswahl könnte so aussehen: Stochastic, ATR, AC (Acceleration/Deceleration) oder WPR, Bollinger Bands, Momentum.

Es sollte hier angemerkt werden, dass der Indikator Acceleration/Deceleration (AC) ist im wesentlichen eine Ableitung des Oszillators. Warum ist er dennoch für die Aufnahme in die Gruppe geeignet?

Betrachten wir eine Reihe von Daten (oder einen von ihm abgeleiteten Oszillator) in einer vereinfachten Form, einer zyklischen Oszillation, zum Beispiel Sinus und Kosinus. Die Ableitungen dieser Funktionen sind gleich:

   (6)


Die Korrelation dieser Funktion und ihrer Ableitungen sind Null.

    (7)


Daher ist die Verwendung der ersten Ableitung eines Indikators im Allgemeinen ein guter Kandidat, zu Beurteilung der Unabhängigkeit weiterer Indikatoren.

Die zweite Ableitung andererseits ist ein schlechter Kandidat für diesen Prozess, da die Chancen, eine Replik des Originalsignals zu erhalten, groß sind.

Über die Diskussion über die Unabhängigkeit der Indikatoren lässt sich zusammenfassen sagen, dass es sich die Untersuchung der Redundanz von Indikatoren, berechnet mit verschiedenen Periodenlängen lohnt.

Es wird angenommen, dass die Antwort vom Verhältnis der Periodenlängen abhängt. Ein nur kleinen Unterschied bedeutet noch keine Unabhängigkeit der Indikatoren, es ist schon ein deutlicher Unterschied nötig. Das stimmt in Teilen mit klassischen Methoden überein, wie Elders Methode der drei Bildschirme, bei denen sich die Zeitrahmen mindestens um den Faktor 5 unterscheiden, um die Indikator der verschiedenen Zeitperioden zu analysieren.

Es sei noch darauf hingewiesen, dass bei einem betrachteten System, um die Unabhängigkeit festzustellen, nicht die Indikatorwerte verwendet werden, sondern direkt deren Handelssignale. Allerdings sind für Indikatoren gleichen Typs (zum Beispiel Oszillatoren) die Prinzipien, die Handelssignale zu erzeugen, ähnlich. Daher ist eine starke oder schwache Abhängigkeit in einer Zeitreihe äquivalent mit einer starken oder schwachen Abhängigkeit der Handelssignale.

Entwurf

Wir haben uns ausreichend mit der Theorie beschäftigt, kommen wir jetzt dazu, was und wie alles zu programmieren ist.

Die Statistik der Handelssignale der Indikatoren wird durch einen eigenen Experten erstellt. Ein Experte, der auf Basis beliebiger Indikator handelt, muss einen Rahmen (im Wesentlichen eine mqh-Datei) haben, der über seine Eingabeparameter die Indikatoren und die Signalerstellung bestimmt. Es sollte zum Beispiel eine Option geben, mit den Einstellungen zwei gleitenden Durchschnitte mit unterschiedlichen Periodenlängen zu bestimmen, und der die Kauf- und Verkaufssignale dann generiert, wenn der schnelle MA den langsamen kreuzt.

Der EA reagiert und handelt nur auf Basis der Eröffnungspreis der Bars. Das ist kein richtiger Experte, sondern nur ein Werkzeug für die Berechnung der Wahrscheinlichkeiten und dem Testen der Hypothesen. Es ist wichtig, dass dieser Prozess schnell abläuft, denn es gibt unendlich viele Möglichkeiten für die Einstellungen der Indikatoren.

D1 wird als standardmäßiger Arbeitszeitrahmen verwendet. Natürlich steht es ihnen frei auch jeden andere Zeitrahmen zu analysieren. D1 hat aber den kleinsten Anteil zufälligen Rauschens und die Analyse der seit mehreren Jahren bestehenden Regelmäßigkeiten erfüllt die Anforderungen des probabilistischen Ansatzes. Weiters kann der Spread beim Handel von D1 vernachlässigt werden, welches die Nachteile durch das Eliminieren des Zustandes "Warten" des Systems auflöst. Im Intraday-Handel allerdings können diese Annahmen nicht getroffen werden und es müssten die Wahrscheinlichkeiten von weit aus mehr Hypothesen berechnet werden.

Wie bereits erwähnt, eröffnet der EA auf Basis der Signale der Indikatoren die Positionen und schließt sie wieder nach einer vorgegebenen Zeit. Dafür wird ein entsprechender Eingabeparameter definiert. Sein Standardwert beträgt 5 Tage. Das ist die typische Zeitspanne für den Zeitrahmen D1, sie wird in vielen Untersuchungen des Handels auf D1 verwendet.

Der EA mit seinem Rahmen ist für beide Plattformen erstellt, das heißt, Sie können ihn sowohl im MetaTrader 4 und MetaTrader 5 kompilieren und laufen lassen. Diese Eigenschaft wird durch frei verfügbare Header-Dateien ermöglicht, die es erlauben, die MQL API des MetaTrader 4 durch den MetaTrader 5 zu verwenden. Darüber hinaus wird in manchen Fällen eine bedingte Kompilierung verwendet: besondere Teile werden mit den Präprozessor-Direktiven #ifdef __MQL4__ und #ifdef __MQL5__ umklammert.

Umsetzung in MQL

Der Rahmen für die Indikatoren

Ein Überblick über den Rahmen für die Verarbeitung der Signale der Indikatoren beginnt mit der Betrachtung der benötigten Indikatoren. Die offensichtlichste Aufzählung umfasst alle mitgelieferten Indikatoren sowie die Funktion iCustom für benutzerdefinierte Indikatoren. Die Enumeration wird für die Auswahl der Indikatoren über die Eingabeparameter des Rahmens benötigt.

enum IndicatorType
{
  iCustom,

  iAC,
  iAD,
  tADX_period_price,
  tAlligator_jawP_jawS_teethP_teethS_lipsP_lipsS_method_price,
  iAO,
  iATR_period,
  tBands_period_deviation_shift_price,
  iBearsPower_period_price,
  iBullsPower_period_price,
  iBWMFI,
  iCCI_period_price,
  iDeMarker_period,
  tEnvelopes_period_method_shift_price_deviation,
  iForce_period_method_price,
  dFractals,
  dGator_jawP_jawS_teethP_teethS_lipsP_lipsS_method_price,
  fIchimoku_tenkan_kijun_senkou,
  iMomentum_period_price,
  iMFI_period,
  iMA_period_shift_method_price,
  dMACD_fast_slow_signal_price,
  iOBV_price,
  iOsMA_fast_slow_signal_price,
  iRSI_period_price,
  dRVI_period,
  iSAR_step_maximum,
  iStdDev_period_shift_method_price,
  dStochastic_K_D_slowing_method_price,
  iWPR_period

};
Jedem Namen der mitgelieferten Indikatoren werden die Informationen über seine Parameter angehängt. Der erste Buchstabe steht für die Anzahl der verfügbaren Puffer: i — ein Puffer, d — zwei, t — drei. All dies ist nur ein Hinweis für den Benutzer. Wenn er eine falsche Anzahl von Parametern oder den Index eines nicht vorhandenen Puffers angibt, wird der Rahmen im Log eine Fehlermeldung ausgegeben.

Natürlich muss für jeden Indikator in den Eingabeparametern nicht nur seinen Typ angeben werden, sondern auch die aktuellen Parameter als Zeichenkette, der Index des Puffers und der Index der Bar.

Die Werte des Indikators werden für die Erzeugung der Signale verwendet. Theoretisch könnten es eine beliebige Zahl von unterschiedlichen Signalen sein, aber die Hauptvarianten sind in der folgenden Enumeration aufgelistet.

enum SignalCondition
{
  Disabled,
  NotEmptyIndicatorX,
  SignOfValueIndicatorX,
  IndicatorXcrossesIndicatorY,
  IndicatorXcrossesLevelX,
  IndicatorXrelatesToIndicatorY,
  IndicatorXrelatesToLevelX
};
Damit entsteht ein Signal, wenn:
  • Der Indikatorwert nicht leer ist;
  • Der Indikatorwert das erforderliche Vorzeichen (positiv oder negativ) hat;
  • Der Indikator einen anderen kreuzt (es wird hier darauf hingewiesen, dass man bei der Definition des Signals dafür auch zwei Indikatoren definieren kann);
  • Der Indikator ein bestimmtes Niveau kreuzt (hier wird deutlich, dass man ein Möglichkeit haben muss, das Niveau einzugeben);
  • Der Indikator sich relativ zu einem anderen in einer gewünschten Weise zeigt (zum Beispiel darüber oder darunter);
  • Der Indikator sich relativ zu einem gegebenen Niveau in einer gewünschten Weise zeigt;

Das erste Element — 'Disabled' — erlaubt die Deaktivierung aller Bedingungen für die Signalerstellung. Wir werden mehrere identische Gruppen von Eingabeparameter zur Definition der Signale bereitstellen, und jedes Signal wird standardmäßig deaktiviert.

Aus den Namen der vorangegangenen Aufzählungen lässt sich leicht ersehen, dass es notwendig ist, das gewünschte Vorzeichen der Werte und die Position der Zeilen relativ zueinander zu setzen. Eine weitere Aufzählung wird für diesen Zweck hinzugefügt.

enum UpZeroDown
{
  EqualOrNone,
  UpSideOrAboveOrPositve,
  DownSideOrBelowOrNegative,
  NotEqual
};
EqualOrNone erlaubt die Prüfungen:
  • Ist es ein leerer Wert in Kombination mit SignOfValueIndicatorX
  • Ist er gleich einem Niveau in Kombination mit IndicatorXrelatesToLevelX

UpSideOrAboveOrPositve erlaubt die Prüfung:

  • Kreuzt er aufwärts mit IndicatorXcrossesIndicatorY
  • Ist es ein positiver Wert mit SignOfValueIndicatorX
  • Kreuzt er aufwärts mit IndicatorXcrossesLevelX
  • Indikatorwerte steigen in aufeinanderfolgenden Bars mit IndikatorXRelatesToIndicatorY, wenn X und Y denselben Indikator bezeichnen
  • Position von X über Y mit IndicatorXrelatesToIndicatorY, wenn X und Y verschiedene Indikatoren bezeichnen
  • Position eines Indikators über einem Niveau mit IndicatorXrelatesToLevelX

DownSideOrBelowOrNegative erlaubt die Prüfungen:

  • Kreuzt er abwärts mit IndicatorXcrossesIndicatorY
  • Ist er negativ mit SignOfValueIndicatorX
  • Kreuzt er abwärts mit IndicatorXcrossesLevelX
  • Indikatorwerte fallen in aufeinanderfolgenden Bars mit IndicatorXrelatesToIndicatorY, wenn X und Y denselben Indikator bezeichnen
  • Position von X unter Y mit IndicatorXrelatesToIndicatorY, wenn X und Y verschiedene Indikatoren bezeichnen
  • Position eines Indikators unter einem Niveau mit IndicatorXrelatesToLevelX

NotEqual erlaubt die Prüfungen:

  • Ist er ungleich einem Niveau (Wert) mit IndicatorXrelatesToLevelX

Wenn ein Signal ausgelöst wurde, muss es verarbeitet werden. Dafür definieren wir folgende Enumeration.

enum SignalType
{
  Alert,
  Buy,
  Sell,
  CloseBuy,
  CloseSell,
  CloseAll,
  BuyAndCloseSell,
  SellAndCloseBuy,
  ModifyStopLoss,
  ModifyTakeProfit,
  ProceedToNextCondition
};
Hier sind die wichtigsten Aktionen für die Signalverarbeitung: Benachrichtigung, Kaufen, Verkaufen, Schließen aller offenen Positionen (Kaufen, Verkauf oder beides), Positionsumkehr von Verkauf zu Kauf, Positionsumkehr von Kauf zu Verkauf, Ändern von Stopp-Loss oder Take-Profit, und auch den Übergang zur nächsten Bedingung (Signal) überprüfen. Der letzte Punkt erlaubt die Verkettung der Signalprüfungen (z.B.die Überprüfung, ob der Hauptpuffer die Signallinie überquert hat, und wenn ja, ob er sich oberhalb oder unterhalb eines bestimmten Niveaus befand).

Man erkennt, dass die Liste der Aktionen keine Platzierung von schwebenden Aufträgen (pending orders) enthält. Das läge außerhalb des Rahmens dieser Arbeit. Interessierte können den Rahmen erweitern.

Mit all diesen Enumeration können bestimmte Gruppen von Attributen beschrieben werden, mit denen die Einstellungen der zu verwendenden Indikatoren bestimmt werden. Eine Gruppe schaut wie folgt aus:

input IndicatorType Indicator1Selector = iCustom; // ·     Selector
input string Indicator1Name = ""; // ·     Name
input string Parameter1List = "" /*1.0,value:t,value:t*/; // ·     Parameters
input string Indicator1Buffer = ""; // ·     Buffer
input int Indicator1Bar = 1; // ·     Bar
Dem Parameter Indicator1Name wird der Name des Nutzerindikators zugewiesen, wenn Indicator1Selector auf iCustom gesetzt wurde.

Der Parameter Parameter1List erlaubt die Einstellungen die Parameter des Indikator als Komma getrennte Zeichenkette zu übergeben. Der Typ eines jeden Eingabeparameters wird automatisch erkannt, zum Beispiel: 11.0 — double, 11 — int, 2015.01.01 20:00 — datetime, true/false — bool, "text" — string. Bestimmte Parameter (wie verschiedene Arten gleitender Durchschnitte oder Preise) können nicht als eine Zahl übergeben werden, sondern nur über eine Zeichenkette ohne Anführungszeichen (sma, ema, smma, lwma, close, open, high, low, median, typical, weighted, lowhigh, closeclose).

Indicator1Buffer ist der Index oder Name eines Puffers ohne Anführungszeichen. Unterstützte Puffernamen sind: main, signal, upper, lower, jaw, teeth, lips, tenkan, kijun, senkouA, senkouB, chikou, +di, -di.

Indicator1Bar — Index der Bar, standardmäßig 1.

Sobald alle Indikatoren definiert sind, können sie als Grundlage für die Signalbildung dienen, d.h. Bedingungen für auslösende Ereignisse. Jedes Signal ist durch ein Gruppe von Eingabeparameter definiert.

input string __SIGNAL_A = "";
input SignalCondition ConditionA = Disabled; // ·     Condition A
input string IndicatorA1 = ""; // ·     Indicator X for signal A
input string IndicatorA2 = ""; // ·     Indicator Y for signal A
input double LevelA1 = 0; // ·     Level X for signal A
input double LevelA2 = 0; // ·     Level Y for signal A
input UpZeroDown DirectionA = EqualOrNone; // ·     Direction or sign A
input SignalType ExecutionA = Alert; // ·     Action A
Man kann für jedes Signal einen Identifikator mit dem Parameter __SIGNAL__ benennen.

'Condition' wählt die Bedingung für die Überprüfung des Signals. Als nächstes bestimmen Sie ein oder zwei Indikatoren und einen oder zwei Werte verschiedener Niveaus (das zweite Niveau ist für die Zukunft reserviert und wird in diesem Experiment nicht verwendet). Die Indikatoren der Parameter von 'Indicator' sind entweder die Nummern der korrespondierenden Gruppe von Attributen oder der Prototyp eines Indikators in der Form:

indicatorName@buffer(param1,param2,...)[bar]

Dieses Eingabeformat ermöglicht eine schnelle Ermittlung des verwendeten Indikators ohne dessen detaillierte Beschreibung über die Attributgruppe. Zum Beispiel,

iMA@0(1,0,sma,high)[1]

gibt bei jeder aktuellen Bar des arbeitenden Experten das Hoch der Bar mit dem Index 1 zurück (die letzte vollständige Bar, deren Hoch bekannt ist).

So können Indikatoren sowohl in dedizierten Attributgruppen (zur späteren Referenz durch die Nummer der Signale) als auch direkt in den Signalen im Parameter 'Indikator' (X oder Y) bestimmt werden. Die erste Methode ist praktisch, wenn der gleiche Indikator in verschiedenen Signalen oder als X und Y innerhalb eines Signals verwendet werden soll.

Der Parameter' Direction' gibt die Richtung oder das Vorzeichen des Wertes zum Auslösen einer Bedingung an. Beim Auslösen des Signals wird die entsprechende Aktion gemäß 'Execution' ausgeführt.

Als nächstes folgen die Beispiele zur Bestimmung von Indikatoren und Signalen auf deren Basis.

Im Rahmen ist aktuell definiert, dass ein Indikator nicht mehr als 20 Parameter haben darf, die maximale Anzahl der dedizierten Gruppen mit Indikatorattributen ist 6 (aber wie bereits gesagt, Indikatoren können zusätzlich direkt im Signal gesetzt werden), und höchstens 6 Signale. All dies kann im Quelltext geändert werden. Die Datei IndicatN.mqh ist am Ende dem Artikels beigefügt.

Diese Datei implementiert zusätzlich mehrere Klassen, die die gesamte Logik für das Parsen der Indikatorparameter, den Aufruf, die Überprüfung der Bedingungen und die Rückgabe der Prüfergebnisse an das aufrufende Programm (den Experten) enthalten.

Um insbesondere die Anweisungen zur Notwendigkeit, eine bestimmte Aktion aus der oben erwähnten Enumeration von SignalType auszuführen, weiterzugeben, wird ein einfaches öffentliches TradeSignal verwendet, das ein Boolesches Feld enthält, das den Elementen der Enumeration entspricht.

class TradeSignals
{
  public:
    bool alert;
    bool buy;
    bool sell;
    bool buyExit;
    bool sellExit;
    bool ModifySL;
    bool ModifyTP;
    
    int index;
    double value;
    
    string message;
  
    TradeSignals(): alert(false), buy(false), sell(false), buyExit(false), sellExit(false), ModifySL(false), ModifyTP(false), value(EMPTY_VALUE), message(""){}
};
Wenn die Voraussetzungen erfüllt sind, wird den Funktionen true übergeben. Wenn zum Beispiel die Aktion CloseAll gewählt wurde, werden im Objekt TradeSignals die Flags für buyExit und sellExit entsprechend gesetzt.

Die Variable 'index' enthält die Seriennummer der ausgelösten Bedingung.

Die Variable 'value' kann verwendet werden, um einen benutzerdefinierten Wert zu übergeben, zum Beispiel: einen neuen Stopp-Loss, erhalten von Indikator.

Schlussendlich kann der Nutzer die Variable 'message' dazu benutzen, die Situation zu beschreiben.

Die Details zur Umsetzung in allen Klassen finden Sie im Quellcode. Verwendet werden die zusätzlichen Header-Dateien fmtprnt2.mqh (formatierte Ausgabe im Log) und RubbArray.mqh ("rubber"-Array), die ebenfalls angehängt sind.

Die Header-Datei IndicatN.mqh für den Rahmen sollte mit der Anweisung #include in den Quellcode des Experten geladen werden. Die Gruppe der Eingabeparameter mit den Attributen der Indikatoren ist daher nach der Kompilierung im Dialog zu den Einstellung des EA zu sehen:

Die Einstellungen der Indikatoren

Fig. 3. Die Einstellungen der Indikatoren

und mit den Definitionen zu den Signalen:

Einstellungen der Handelssignale

Fig. 4. Einstellungen der Handelssignale

Das Bildschirmfoto zeigt die bereits voreingestellten Werte. Sie werden detaillierter betrachtet, sobald wir zum Konzept des EA übergehen und mit der Konfiguration spezifischer Handelsstrategien beginnen. Zu beachten ist auch hier, dass es beim Setzen der Indikatorattribute möglich ist, beliebige numerische Parameter durch Ausdrücke vom Typ =var1, =var2 usw. bis 9 zu ersetzen. Sie beziehen sich auf die speziellen Eingabeparameter des Rahmens mit gleichen Namen (var1, var2, etc.), für die Optimierung. Der Eintrag:

iMACD@main(=var4,=var5,=var6,open)[0]

bedeutet zum Beispiel, dass die Eingabeparameter var4, var5 bzw. var6 die Parameter für den schnellen, langsamen gleitenden Durchschnitt und der Signallinie des MACD optimiert werden können. Und auch wenn die Optimierung deaktiviert ist, werden während eines einzelnen Testlaufs die Werte der entsprechenden Attribute eines Indikators aus den angegebenen Eingabeparametern des Rahmens gelesen.

Test-Experte

Um das Programmieren zu erleichtern, lassen Sie uns alle Trade-Funktionen in eine spezielle Klasse und und die in eine eigene Headerdatei Expert0.mqh verschieben. Da nur ganz einfache Handelssysteme getestet werden sollen, erlaubt die Klasse nur das Öffnen und Schließen von Positionen.

So werden alle Routineoperationen mit Indikatoren und solche, die sich auf den Handel beziehen, in Headerdateien verschoben.

#include <IndicatN.mqh>
#include <Expert0.mqh>
Die Datei indstats.mq4 selbst hat nur ein paar Codezeilen und eine einfache Logik.

Da der Nutzer nachdem er die Erweiterung auf mq5 geändert hat, den EA im MetaTrader 5 kompilieren und laufen lassen soll, ergänzen wir die Headerdatei, um den Code der neuen Umgebung anzupassen.

#ifdef __MQL5__
  #include <MarketMQL4.mqh>
  #include <ind4to5.mqh>
  #include <mt4orders.mqh>
#endif

Betrachten wir jetzt die Eingabeparameter des Experten.

input int ConsistentSignalNumber = 1;
input int Magic = 0;
input float Lot = 0.01f;
input int TradeDuration = 1;

  

'Magic' und 'Lot' sind erforderlich für das Erstellen des Objekts des Experten aus der Datei Expert0.mqh.

Expert e(Magic, Lot);

Der Parameter ConsistentSignalNumber enthält, um die Robustheit zu erhöhen, die Anzahl der zu kombinierenden Handelssignale.

Der Parameter TradeDuration bestimmt die Anzahl der Bars, die eine Position offengehalten werden soll. Wie bereits erwähnt, werden die Positionen entsprechend den Signalen eröffnet und nach 5 Bars, d.h. Tagen, da der Zeitrahmen D1 verwendet wird, wieder geschlossen.

Die Funktion OnInit initialisiert den Rahmen der Indikatoren.

int OnInit()
{
  return IndicatN::handleInit();
}

In der Funktion OnTick wird die Eröffnung der Bars kontrolliert.

void OnTick()
{
  static datetime lastBar;
  
  if(lastBar != Time[0])
  {
    const RubbArray<TradeSignals> *ts = IndicatN::handleStart();
    ...
    lastBar = Time[0];
  }
}

  

Währenddessen sich eine neue Bar bildet, werden alle Indikator und die zugehörigen Bedingungen durch den wiederholten Aufruf des Rahmens überprüft. Die Ergebnisse in einem Array der ausgelösten Signale — die TradeSignals-Objekte.

Jetzt ist es an der Zeit die Erhebung der Statistiken zu besprechen.

Jede Bedingung (Ereignis) des Rahmens, sobald sie erfüllt wurde, erstellt standardmäßig ein Signal mit dem' Alert'-Flag. Damit zählen wir die Signale der Indikatoren zu berechnen, sowie die Anzahl der realisierten Zustände des Systems, d.h. die Fälle (Bars), beim Kauf oder Verkauf erfolgreich waren.

Zur Berechnung der Statistiken werden die Arrays ausgefüllt.

int bars = 0; // total count of bars/samples
int bull = 0, bear = 0; // number of bars/samples per trade type
int buy[MAX_SIGNAL_NUM] = {0}, sell[MAX_SIGNAL_NUM] = {0};  // unconditional signals arrays
int buyOnBull[MAX_SIGNAL_NUM] = {0}, sellOnBear[MAX_SIGNAL_NUM] = {0}; // conditional (successful) signals arrays
Da unser Handel sich an den Bars orientiert, könnte sich jede Bar eine neue Position für die Dauer der 5 folgenden Bars eröffnen. Jedes dieser Segmente ist durch einen Anstieg oder Rückgang der Kurse gekennzeichnet und wird als 'bullisch' bzw. 'bearisch' bezeichnet.

Alle Kauf- und Verkaufssignale werden in den Arrays 'buy' und 'sell' zusammengefasst. Ist ein entsprechendes Signal 'bullish' oder 'bearish' des Segments, wird es je nach Typ auch im Array buyOnBull oder sellOnBear aufsummiert.

Der folgende Code in OnTick füllt die Felder aus.

    const RubbArray<TradeSignals> *ts = IndicatN::handleStart();
    bool up = false, down = false;
    int buySignalCount = 0, sellSignalCount = 0;
    
    for(int i = 0; i < ts.size(); i++)
    {
      // alerts are used to collect statistics
      if(ts[i].alert)
      {
        // while setting up events, enumerated by i,
        // hypothesis H_xxx should come first, before signals S_xxx,
        // because we assign up or down marks here
        if(IndicatN::GetSignal(ts[i].index) == "H_BULL")
        {
          bull++;
          buy[ts[i].index]++;
          up = true;
        }
        else if(IndicatN::GetSignal(ts[i].index) == "H_BEAR")
        {
          bear++;
          sell[ts[i].index]++;
          down = true;
        }
        else if(StringFind(IndicatN::GetSignal(ts[i].index), "S_BUY") == 0)
        {
          buy[ts[i].index]++;
          if(up)
          {
            if(PrintDetails) Print("buyOk ", IndicatN::GetSignal(ts[i].index));
            buyOnBull[ts[i].index]++;
          }
        }
        else if(StringFind(IndicatN::GetSignal(ts[i].index), "S_SELL") == 0)
        {
          sell[ts[i].index]++;
          if(down)
          {
            if(PrintDetails) Print("sellOk ", IndicatN::GetSignal(ts[i].index));
            sellOnBear[ts[i].index]++;
          }
        }
        
        if(PrintDetails) Print(ts[i].message);
      }
    }
Nach Erhalt des Arrays mit den ausgelösten Signalen, iterieren wir über seine Elemente in einer Schleife. Ein aktiviertes 'alert' führt zur Erstellung der Statistiken.

Bevor wir den Code genauer analysieren, lassen Sie uns eine spezielle Konvention zur Benennung der Signale (Ereignisse) einführen. Hypothesen darüber, ob der Markt steigt oder fällt, werden mit den Identifikatoren H_BULL und H_BEAR gekennzeichnet. Diese Ereignisse müssen zunächst durch die Eingabeparameter des Rahmens definiert werden, bevor andere Ereignisse (Indikatorsignale) ausgelöst werden. Dies ist erforderlich, um anhand der bestätigten Hypothesen - die booleschen Variablen 'up' und 'down' - die entsprechenden Merkmale zu setzen.

Die Signale der Indikatoren müssen Identifikatoren haben, die mit S_BUY oder S_SELL beginnen.

Wie man sehen kann, wird sein Identifikator durch den Aufruf der Funktion GetSignal mittels eines Verweises auf den Index des aktivierten Ereignisse ts[i].index ermittelt. Falls Hypothesen erfüllt sind, werden die allgemeinen Zähler der Segmente für 'bullish' und 'bearish' aktualisiert. Bei der Signalgenerierung wird für jeden Signaltyp ihre Gesamtzahl gezählt, sowie der Index ihres Erfolgs, d.h. die Anzahl der Übereinstimmungen mit den aktuellen Hypothesen.

Bedenken Sie, dass die Hypothese von entweder H_BULL oder H_BEAR auf jedem Balken wahr ist.

Abgesehen von der Erhebung der Statistiken, sollte der EA den Handel mit Signalen unterstützen. Zu diesem Zweck wird in der Schleife zusätzlich eine Prüfung von der Flags 'buy' und 'sell' durchgeführt.

      if(ts[i].buy)
      {
        buySignalCount++;
      }
      else
      if(ts[i].sell)
      {
        sellSignalCount++;
      }
Die Handelsfunktionen werden nach der Schleife implementiert. Zu allererst werden offenen Positionen (wenn es sie gibt) nach der angegebenen Laufzeit geschlossen.
    if(e.getLastOrderBar() >= TradeDuration)
    {
      e.closeMarketOrders();
    }

  

Dann wird ge- oder verkauft, je nach den entsprechenden Signalen.

    if(buySignalCount >= ConsistentSignalNumber
    && sellSignalCount >= ConsistentSignalNumber)
    {
      Print("Signal collision");
    }
    else
    if(buySignalCount >= ConsistentSignalNumber)
    {
      e.closeMarketOrders(e.mask(OP_SELL));
      
      if(e.getOrderCount(e.mask(OP_BUY)) == 0)
      {
        e.placeMarketOrder(OP_BUY);
      }
    }
    else
    if(sellSignalCount >= ConsistentSignalNumber)
    {
      e.closeMarketOrders(e.mask(OP_BUY));
      
      if(e.getOrderCount(e.mask(OP_SELL)) == 0)
      {
        e.placeMarketOrder(OP_SELL);
      }
    }
Wenn sich Kauf- und Verkaufssignale widersprechen, wird ein solcher Zustand übersprungen. Wenn die Anzahl der Kauf- und Verkaufssignale gleich oder größer als die vordefinierte Zahl von ConsistentSignalNumber ist, wird die entsprechende Position eröffnet.

Es sollte darauf hingewiesen werden, dass eine Einstellung des Wertes für ConsistentSignalNumber kleiner als die Anzahl der konfigurierten Signale, das Testen des Handelssystems in einem Modus erlaubt, der alle oder die meisten Strategien kombiniert. Im normalen Betriebsmodus verwendet der EA Schnittpunkte, keine Gleichheit, da ConsistentSignalNumber genau gleich der Anzahl der Signale sein muss, um gemeinsame Ereignisse zu finden. Wenn beispielsweise 3 Signale konfiguriert und ConsistentSignalNumber auf 3 eingestellt sind, wird der Handel nur dann durchgeführt, wenn alle drei Ereignisse gleichzeitig auftreten. Wenn ConsistentSignalNumber gleich 1 ist, werden Positionen eröffnet, wenn eines (mindestens eines) von 3 Signalen empfangen wird.

Die Funktion OnDeinit gibt die erhobenen Statistiken über Alerts oder die Historie der Aufträge im Log aus.

Der vollständige Quellcode des Experten befindet sich in der Datei indstats.mq4.

Einstellungen der Handelssignale

Alle anderen Signale müssen gegen die beiden Hypothesen zum Kaufen oder Verkaufen geprüft werden. Dafür müssen die Signale H_BULL und H_BEAR und deren Kennzeichen konfiguriert werden.

Um die Preise eine Bar zu erhalten, verwenden Sie den iMA Indikator mit einer Periode von 1. In der Gruppe __INDICATOR_1 definieren Sie:

Selector = iMA_period_shift_method_price

Parameters = 1,0,sma,open

Buffer = 0

Bar = 0

Setzen Sie in der Gruppe __INDICATOR_2 ähnliche Einstellungen außer der Nummer der Bar: Sie sollte auf 5 gesetzt werden, die Anzahl der Bars, die dem Parameter TradeDuration zugewiesen wurde.

Der Experte handelt also nicht im Modus Statistikerhebung. Stattdessen analysiert er die Kursänderung zwischen dem 5. und 0. Bar sowie die Indikatorsignale im 5. oder 6. Bar, je nach Preistyp: Bei Indikatoren, die auf Basis der Eröffnungspreis arbeiten, können es die Werte der 5., für alle anderen - ab der 6. Bar. Im Modus zum Erheben von Statistiken ist die 5. Bar eine virtuelle, aktuelle Bar, und alle nachfolgenden Bars geben Aufschluss über die "zukünftige" Erfüllung der Hypothesen über den Aufwärts- oder Abwärtstrend.

Es sollte darauf hingewiesen werden, dass im Handelsmodus die Signale der Bar 0 (wenn der Indikator auf den Eröffnungspreisen basiert) oder Bar 1 (andernfalls) genommen werden. Wenn der Experte nicht mit den Eröffnungspreisen arbeitet, sondern mit den Ticks, müsste man die Indikatorwerte der Bar 0 überprüfen.

Das Vorhandensein dieser beiden Modi - Statistikerhebung und Handel - macht es notwendig, verschiedene Parametersätze zu erstellen, die sich in der Anzahl der zu bearbeitenden Bars unterscheiden. Wir beginnen mit den Einstellungen zum Erheben von Statistiken und wandeln diese dann einfach in die für den Handelsmodus um.

Diese beiden Kopien des MA-Indikators werden für die Konfiguration der Hypothesen verwendet. inder Gruppe __SIGNAL_A, tragen wir ein:

__SIGNAL_A = H_BULL
Bedingung = IndicatorXrelatesToIndicatorY Indikator X = 1 Indikator Y = 2 Richtung oder Vorzeichen = UpSideOrAboveOrPositve Aktion = Alert

Die Gruppe __SIGNAL_B wird ähnlich konfiguriert, bis auf die Richtung:

__SIGNAL_B = H_BEAR
Richtung oder Vorzeichen = DownSideOrBelowOrNegative

Um das probabilistische Modell des Handels zu testen, werden 3 Strategien auf Basis der Standardindikatoren verwendet:

  • Stochastic
  • MACD
  • BollingerBands

Es sollte vorher darauf hingewiesen werden, dass die Parameter aller Indikatoren optimiert wurden, wobei einige von ihnen bewusst als Verweise auf die Eingabeparameter var1, var2 usw. belassen wurden, um diese Eigenschaft des Rahmens zu demonstrieren. Um die positiven Ergebnisse auf den Daten Ihres Providers wiederherzustellen, muss wahrscheinlich jede Strategie neu optimiert werden.

Die Strategie auf Basis der Stochastik lautet kaufen, wenn der Indikator das Niveau 20 nach oben kreuzt, und verkaufen, wenn er das Niveau 80 nach unten kreuzt. Dafür definieren wir die Gruppe __INDICATOR_3:

Selector = dStochastic_K_D_slowing_method_price
Parameters = 14,3,3,sma,lowhigh Buffer = main Bar = 6

Da der Indikator Hoch- und Tiefstpreise verwendet werden, ist es notwendig, die Bar mit dem Index 6 zu nehmen - der letzten vollständigen Bar vor der Bar 5, wo der virtuelle Handel beginnt, falls ein Signal ausgelöst wird.

Die Kauf- und Verkaufssignale werden entsprechend des Stochastik-Indikators korrigiert. Gruppe für das Kaufen:

__SIGNAL_C = S_BUY stochastic
Condition = IndicatorXcrossesLevelX Level X = 20 Direction or sign = UpSideOrAboveOrPositve

Gruppe für das Verkaufen:

__SIGNAL_D = S_SELL stochastic
Condition = IndicatorXcrossesLevelX Level X = 80 Direction or sign = DownSideOrBelowOrNegative

Die Strategie auf Basis des MACD lautet kaufen, wenn die Hauptlinie die Signallinie nach oben kreuzt, und verkaufen, wenn sie sie nach unten kreuzt.

Konfigurieren der Gruppe des Indikators __INDICATOR_4:

Selector = dMACD_fast_slow_signal_price
Parameters = =var4,=var5,=var6,open Buffer = signal Bar = 5

Die Periodenlängen für 'fast', 'slow', 'signal' werden von den Parametern var4, var5, var6, gelesen, bereit für die Optimierung. Die Einstellungen sind aktuell 6, 21, 6. Es wird die Bar mit dem Index 5 verwendet, da der Indikator auf Basis der Eröffnungskurse arbeitet.

Da die Anzahl der Gruppen für die Konfiguration der Indikatoren begrenzt ist, wird der Puffer von 'main' direkt in den Signalen definiert. Gruppe für das Kaufen:

__SIGNAL_E = S_BUY macd
Condition = IndicatorXcrossesIndicatorY Indicator X = iMACD@main(=var4,=var5,=var6,open)[5] Indicator Y = 4 Direction or sign = UpSideOrAboveOrPositve

Gruppe für das Verkaufen: 

__SIGNAL_F = S_SELL macd
Condition = IndicatorXcrossesIndicatorY Indicator X = iMACD@main(=var4,=var5,=var6,open)[5] Indicator Y = 4 Direction or sign = DownSideOrBelowOrNegative

Die Strategie auf Basis der BollingerBands lautet kaufen, wenn das Hoch der vorherigen Bar die um 2 Bars nach rechts verschobene obere Linie des Indikators durchbricht, und verkaufen, wenn das Tief der vorherigen Bar die um 2 Bars nach rechts verschobene untere Linie des Indikator durchbricht. Unten sind die Einstellungen der beiden Linien des Indikators.

__INDICATOR_5:

Selector = tBands_period_deviation_shift_price

Parameters = =var1,=var2,2,typical
Buffer = upper Bar = 5

__INDICATOR_6:

Selector = tBands_period_deviation_shift_price
Parameters = =var1,=var2,2,typical Buffer = lower Bar = 5

Periodenlänge und Versatz sind in den Parametern var1 und var2 mit 7 bzw. 1 definiert. Bar 5 kann in beiden Fällen verwendet werden, trotz des Preistyps von 'typical', weil die Indikatorlinien um 2 Balken nach rechts versetzt sind, d.h. sie werden tatsächlich auf Basis von Daten in der Vergangenheit berechnet.

Die Gruppen für die Einstellungen der Signale sehen schließlich wie folgt aus.

__SIGNAL_G = S_BUY bands
Condition = IndicatorXcrossesIndicatorY Indicator X = iMA@0(1,0,sma,high)[6] Indicator Y = 5 Direction or sign = UpSideOrAboveOrPositve
__SIGNAL_H = S_SELL bands
Condition = IndicatorXcrossesIndicatorY Indicator X = iMA@0(1,0,sma,low)[6] Indicator Y = 6 Direction or sign = DownSideOrBelowOrNegative

Alle Einstellungen sind am Ende des Artikels in Form der .set-Dateien angehängt.

Ergebnisse

Die Statistik der Indikatoren

Zur Berechnung der Wahrscheinlichkeiten wird die Statistik für den Zeitraum 2014.01.01.01-2017.01.01 des EURUSD-D1-Paares verwendet. Die Einstellungen für den Modus des EAs zur Erhebung der Statistik sind in der Datei indstats-stats-all.set enthalten.

Die gesammelten Daten werden im Log ausgegeben. Hier ist ein Beispiel:

: bars=778
: bull=328 bear=449
:    buy:    328      0     30      0     50      0     58      0 
:  buyOk:      0      0     18      0     29      0     30      0 
:   sell:      0    449      0     22      0     49      0     67 
: sellOk:      0      0      0     14      0     28      0     41 
: totals:   0.00   0.00   0.60   0.64   0.58   0.57   0.52   0.61 
: Stats by name:
:  macd=0.576 [57/99]
:  bands=0.568 [71/125]
:  stochastic=0.615 [32/52]

Die Gesamtzahl der Bars beträgt 778, von denen 328 erfolgreiche 5-tägiges Kaufpositionen und 449 erfolgreiche 5-tägiges Verkaufspositionen waren. Die ersten 2 Spalten enthalten die Anzahl der Hypothesen - die gleichen 2 Zahlen, und die nächsten Spaltenpaare beziehen sich auf die entsprechenden Handelsstrategien, von denen jede durch eine Spalte für Kaufpositionen und eine Spalte für Verkaufspositionen repräsentiert wird. Beispielsweise erzeugte eine Strategie auf Basis der Stochastik 30 Kaufsignale, von denen 18 profitabel waren, und 22 Verkaufssignale, von denen 14 profitabel waren. Summieren Sie die Gesamtzahl der erfolgreichen Signale zusammen und dividieren Sie sie durch die Anzahl der erzeugten Signale, so ergibt sich für jeden von ihnen ein Effizienzwert (Erfolgswahrscheinlichkeit basierend auf historischen Daten).

  • Stochastic — 0.615
  • MACD — 0.576
  • Bands — 0.568

Handelstest

Um sicherzugehen, dass die Statistik korrekt ermittelt wird, muss der EA im Handelsmodus gestartet werden. Dafür ändern Sie den Index der Bar in den Einstellungen von 5 auf 0 und 6 auf 1. Zusätzlich sollten die Handelsstrategien nacheinander aktiviert werden, indem der Parameter Action auf Kaufen und Verkaufen anstatt auf Alarm gesetzt wird. Um z.B.den Handel auf Basis der Stochastik zu überprüfen, ersetzen Sie den Wert des Parameters Action von Alert auf Buy in der Gruppe __SIGNAL_C (S_BUY stochastic) und von Alert auf Sell in der Gruppe __SIGNAL_D (S_SELL stochastic).

Die entsprechenden Einstellungen aller 3 Strategien befinden sich in den Dateien indstats-trade-stoch.set, indstats-trade-macd.set bzw. indstats-trade-bands.set.

Wenn Sie den EA 3 mal mit diesen Parametersätzen laufen lassen, erhalten Sie 3 Logs mit Zusammenfassungen der Handelsaktivitäten. Die Statistiken sind ganz am Ende. Beispielsweise erhält man für die Stochastik folgende Zeile:

: Buys: 18/29 0.62 Sells: 14/22 0.64 Total: 0.63
Diese Zahlen zeigen die realen Positionen: 18 von 29 Käufe sind profitabel, 14 von 22 Verkäufe sind profitabel, die gesamte Effizienz des Signals beträgt 0,63.

Die Ergebnisse der Strategien auf Basis des MACD und der BollingerBands sind unten angegeben.

: Buys: 29/49 0.59 Sells: 28/49 0.57 Total: 0.58
: Buys: 29/51 0.57 Sells: 34/59 0.58 Totals: 0.57
Lassen Sie uns die Werte aller Strategien in einer Liste zusammenfassen.
  • Stochastic — 0.63
  • MACD — 0.58
  • Bands — 0.57

Man sieht hier eine fast vollständige Übereinstimmung mit der Theorie aus dem vorigen Unterabschnitt. Der geringe Unterschied erklärt sich dadurch, dass sich die Handelssignale überschneiden können, wenn sie innerhalb von 5 Bars liegen, eine sich wiederholende Position wird in diesem Fall nicht eröffnet.

Selbstverständlich ist es möglich, die Handelsergebnisse für jede Strategie einzeln zu analysieren.

Bericht über die Strategie auf der Grundlage der Stochastik

Fig. 5. Bericht über die Strategie auf der Grundlage der Stochastik


Bericht über die Strategie auf der Grundlage des MACD

Fig. 6. Bericht über die Strategie auf der Grundlage des MACD


Bericht über die Strategie auf der Grundlage der BollingerBands

Fig. 7. Bericht über die Strategie auf der Grundlage der BollingerBands

Die theoretische Wahrscheinlichkeit, dass bei der Eröffnung eine Position gemäß den übereinstimmenden Signalen aller drei Indikatoren erfolgreich ist, wird mit der Formel (4) berechnet.

P(H|ABC) = 0.63 * 0.58 * 0.57 / (0.63 * 0.58 * 0.57 + 0.37 * 0.42 * 0.43) = 0.208278 / (0.208278 + 0.066822) = 0.208278 / 0.2751 = 0.757

Um diese Situation zu testen, müssen wir alle drei Signale berücksichtigen und den Wert des Parameters ConsistentSignalNumber von 1 auf 3 ändern. Die entsprechenden Einstellungen befinden sich in der Datei indstats-trade-all.set file.

Nach den Ergebnissen des Testers liegt die gesamte Effizienz eines solchen Systems jetzt bei tatsächlichen 0.75:

: Buys: 4/7 0.57 Sells: 5/5 1.00 Total: 0.75
Hier ist das Testergebnis:

Bericht über die Kombination der Strategien mit 3 Indikatoren

Fig. 8. Bericht über die Kombination der Strategien mit 3 Indikatoren

Nachfolgend finden Sie eine Tabelle der Handelsergebnisse für jeden der Indikatoren getrennt und für ihre Überlagerung.


Profit,$ PF N DD,$
Stochastic 204 2.36 51 41
MACD 159 1.39 98 76
Bands 132 1.29 110 64
Total 68 3.18 12 30

Wie man sieht, wird eine Erhöhung der Erfolgswahrscheinlichkeit durch weniger häufige, aber genauere Eingaben erreicht. Die Anzahl der Positionen und der Gesamtgewinn gingen zurück, obwohl der Profit-Faktor und der maximale Drawdown sich um mindestens 35% verbesserten, in einigen Fällen sogar mehr als doppelt so hoch waren.

Schlussfolgerung

Der Artikel befasst sich mit der einfachsten Version eines probabilistischen Ansatzes zur Entscheidungsfindung im Handel auf der Grundlage von Indikatorsignalen. Mit Hilfe eines speziellen Experten wurde gezeigt, dass die theoretischen Berechnungen zur Erhöhung der Wahrscheinlichkeit von erfolgreichen Abschlüssen mit Hilfe der Bayes'schen Formel den in der Praxis erzielten Ergebnissen entsprechen.

Da die Signalgenerierung diskret erfolgt, stimmen die Signale verschiedener Indikatoren unter Umständen nicht überein. Es könnte sich ergeben, dass die Kombination der Indikatoren keine gemeinsamen Signale mehr liefert, die von allen Indikatoren gemeinsam unterstützt werden. Eine der möglichen Lösungen für dieses Problem ist die Einführung einer zeitlichen Toleranz zwischen den Signalen.

In einem allgemeineren Fall ist es möglich, die Wahrscheinlichkeitsdichte der Umsetzung von Handelshypothesen in Abhängigkeit vom Zustand der Indikatoren (und nicht von den Signalen) zu berechnen. Beispielsweise gibt der anhand eines bestimmten Wertes des Oszillators ermittelte Überkaufs- oder Überverkaufswert den Prozentsatz (Wahrscheinlichkeit) der erfolgreichen Einträge an. Darüber hinaus hängt die Wahrscheinlichkeit eines erfolgreichen Handels natürlich auch von den gewählten Parametern für Stopp-Loss, Take-Profit, einer Berechnung der Lotgrößen und vielen anderen Parametern eines Systems ab. All dies kann unter dem Gesichtspunkt der Wahrscheinlichkeitstheorie analysiert und für genauere, aber auch komplexere Berechnungen von Handelsentscheidungen verwendet werden.

Die beigefügten Dateien:

  • indstats.mq4 (also indstats.mq5) — Expert Advisor.
  • common-includes.zip — Archiv mit den Headerdateien.
  • additional-mt5-includes.zip — Archiv mit zusätzlichen Headerdateien für MetaTrader 5.
  • instats-tester-sets.zip — Archiv mit den Einstellungen in den Set-Dateien.

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

Beigefügte Dateien |
indstats.mq4 (15.63 KB)
common-includes.zip (17.46 KB)
Walk-Forward-Optimierung in MetaTrader 5 - mit eigenen Händen Walk-Forward-Optimierung in MetaTrader 5 - mit eigenen Händen

Im Artikel werden verschiedene Herangehensweisen betrachtet, die es erlauben, eine Walk-Forward-Optimierung mithilfe des eingebauten Testers und Hilfsbibliotheken in MQL genau zu emulieren.

TradeObjects: die Automatisierung des Handels aufgrund der graphischen Objekte in MetaTrader TradeObjects: die Automatisierung des Handels aufgrund der graphischen Objekte in MetaTrader

Im Artikel wird eine einfache Erstellungsmethode eines automatischen Handelssystems nach der linearen Markierung des Charts betrachtet. Es wird ein fertiger Experte angeboten, der die Standardeigenschaften der Objekte MetaTrader 4 und 5 verwendet, und der auch Haupt-Handelsoperationen unterstützt.

Tiefe neuronale Netzwerke (Teil I). Datenaufbereitung Tiefe neuronale Netzwerke (Teil I). Datenaufbereitung

Diese Artikelserie setzt das Thema "Tiefe neuronale Netzwerke" (DNN) fort, die in der letzten Zeit in vielen angewandten Bereichen einschließlich Trading verwendet werden. Es werden neue Themenbereiche betrachtet; anhand praktischer Experimente werden neue Methoden und Ideen geprüft. Der erste Artikel dieser Serie beschäftigt sich mit der Datenaufbereitung für DNN.

Erstellen und Testen benutzerdefinierter Symbole im MetaTrader 5 Erstellen und Testen benutzerdefinierter Symbole im MetaTrader 5

Das Erstellen von benutzerdefinierten Symbolen verschiebt die Grenzen der Entwicklung von Handelssystemen und der Finanzmarktanalyse. Jetzt können Händler Charts erstellen und Handelsstrategien mit einer unbegrenzten Anzahl von Finanzinstrumenten testen.