Optimale Vorgehensweise für Entwicklung und Analyse von Handelssystemen

11 Januar 2021, 13:38
Evgeniy Ilin
0
151

Einführung

Zurzeit wird der Forex-Handel immer populärer, es entstehen ständig neue Signale und Handelssysteme. Dies ist unvermeidlich, da es schon immer viele Menschen gab, die schnell und einfach Geld verdienen wollten. Mit dem Ausbau der Internet-Infrastruktur auf der ganzen Welt, wird dieser Markt nur noch größer. Diese Website ist ein anschauliches Beispiel dafür. Sie enthält das am weitesten entwickelte Finanzsystem mit zahlreichen Funktionen, die es Nutzern ermöglichen, ein Produkt oder eine Dienstleistung zu kaufen, aber auch Geld zu verdienen, indem sie zur Entwicklung der Website beitragen. In diesem Artikel werde ich die Kriterien aufzeigen, die bei der Auswahl von Produkten und Signalen verwendet werden sollten, sowie die Regeln, die bei der Entwicklung und Anwendung Ihrer eigenen Handelssysteme zu beachten sind.

Meine Philosophie

Lassen Sie mich Ihnen ein wenig über meine Motivation und die Prinzipien meiner Herangehensweise an die Konstruktion von Handelssystemen erzählen. Ich habe mehrere verschiedene EAs entwickelt, meist auf MetaTrader 4, obwohl es an der Zeit ist, sich an MetaTrader 5 zu gewöhnen. Einige Systeme sind dann für MetaTrader 5 angepasst worden.

Was die Funktionalität angeht, lässt MetaTrader 5 seinen Vorgänger natürlich weit hinter sich. Ich bin der Meinung, dass man, um den Markt zu verstehen, vor allem Theorie und Praxis miteinander verbinden sollte. MetaTrader 4 bietet die notwendige Praxis gut genug.

Ich versuche, so einfach und schnell wie möglich zu entwickeln, und schaue mir dann das Ergebnis an. Wenn das Ergebnis einem Muster ähnelt, versuche ich, Filter hinzuzufügen, die Signalstärke zu erhöhen und das Ergebnis erneut zu überprüfen. Wenn es sich verbessert, versuche ich, den Prozess zu erforschen und die Gründe für die Verbesserung oder Verschlechterung herauszufinden.

Dabei ist es notwendig, verschiedene und gleichzeitig einfache Systeme zu entwickeln, um eine Art Fließband zu gestalten. Monatelang an einem einzigen System herumzubasteln, in dem Versuch, es perfekt zu machen, ist ein sicherer Weg zum Scheitern. Manche Trader glauben auch, dass es umso besser ist, je mehr Eingänge und andere Komplexitäten das System hat. Eigentlich ist das Gegenteil der Fall.

Einige der EAs, die ich entwickelt habe, enthalten 2000-3000 Codezeilen und liefern keine Ergebnisse, während einige der funktionierenden Codes, die aus 20-50 Zeilen bestehen, in der gesamten Historie über mehrere Währungen hinweg funktionieren. Die Qualität Ihres Marktwissens ist hier der Haupterfolgsfaktor. Talentierte Programmierer sind nicht diejenigen, die in der Lage sind, das komplexeste System zu entwickeln, das man sich vorstellen kann, sondern diejenigen, die ihre Ziele verstehen und wissen, was sie dem System tatsächlich hinzufügen müssen.

Ein weiterer Vorteil dieses Ansatzes ist, dass je einfacher das Ausgabesystem ist, desto einfacher ist es, es zu korrigieren und zu modifizieren. Ein weiterer interessanter Aspekt ist, dass ein EA, den Sie entwickelt haben, eventuell einer völlig anderen Logik folgt, was manchmal Jahre dauert, um ihn zu verstehen.

Danach fängt man an, den Markt zu verstehen, und fast alle Roboter, die man entwickelt, werden so einfach wie möglich, während sie gleichzeitig so profitabel und stabil wie möglich sind. Ich befinde mich derzeit auf genau dieser Ebene. Ich weiß, was funktioniert und was nicht, sowie was die wichtigsten Punkte sind, die man beachten muss. Nachdem wir diese Stufe erreicht haben, erkennen wir, dass 99% der Informationen, die in der Trading-Community kursieren, kompletter Unsinn sind, einschließlich Kerzenmuster und Indikatoren. Einige andere Informationen, wie z.B. Trend und Seitwärtsbewegung, mögen relativ glaubwürdig aussehen, aber der Trick liegt in der Tatsache, dass sie auf verschiedene Arten interpretiert werden können. Wenn Sie also verlieren, können "Handelsexperten" immer sagen, dass Sie etwas übersehen haben oder Ihre Trendlinie falsch gesetzt wurde.

Anstatt Zeit zu verschwenden, sollten wir anfangen, darüber nachzudenken, was den Preis tatsächlich antreibt. Eine weitere notwendige Voraussetzung ist die Kenntnis der Mathematik und die Fähigkeit, diese bei der Analyse von Ergebnissen anzuwenden, sinnvolle Regelmäßigkeiten zu erkennen und die Physik dahinter zu verstehen. All dies kann nur durch die Kombination von Theorie und Praxis erreicht werden. Letztendlich hängt alles von der Anzahl der Handelssysteme ab, die Sie entwickelt und getestet haben. Verwenden Sie nicht den Code von jemand anderem, sondern erstellen Sie Ihren eigenen von Anfang an. Glauben Sie auch nicht, dass Sie in absehbarer Zeit einen heiligen Gral finden können. Ich dachte mehrere Jahre lang, es könnte mir gelingen. Denken heißt nicht wissen.


Signale, EAs und Indikatoren

Alle diese Tools wurden entwickelt, um Forex-Händlern und Abonnenten zu helfen, und jedes von ihnen kann nützlich sein, wenn es richtig eingesetzt wird. In dieser Hinsicht glaube ich, dass es sehr wichtig ist, ein korrektes Verständnis für jedes dieser Werkzeuge separat zu haben, um eine korrekte Sicht der Situation als Ganzes zu bilden. Das Wichtigste ist, zu verstehen, dass jeder Dienst nur ein Werkzeug, aber keine Lösung darstellt. Es ist sehr wichtig zu verstehen, was eigentlich hinter dem Preisschild steckt. Ich persönlich habe schon lange ein Verständnis für diese Fragen entwickelt und glaube, dass es jemandem helfen kann. Ein weiterer Grund ist, dass ich meine Gedanken über die Entwicklung nutzerdefinierter Handelssysteme teilen möchte.

Signale

Signale werden auf Real- und Demokonten gehandelt. Signale ermöglichen die Überwachung des eigenen Handelskontos und der Konten anderer Händler sowie das Abonnieren von Signalen und das Kopieren der Positionen anderer Händler. Persönlich empfehle ich nicht, Signale zu abonnieren, bei denen die durchschnittliche Positionshaltezeit weniger als eine Minute beträgt. Tatsache ist, dass solche kurzen Deals entweder Arbitrage oder Scalper sind. In beiden Fällen sind solche Strategien sehr empfindlich gegenüber Ping, und schon 10 Millisekunden können ausreichen, um eine Position falsch zu eröffnen. Je länger die durchschnittliche Positionsdauer ist, desto weniger unterscheiden sich Ihre Positionen von den ursprünglichen.

Lassen Sie mich im Folgenden Beispiele für schlechte und gute Signale geben:

Sicheres Signal:


Es ist sicher, weil die Eigenkapitalkurve (equity) so nah wie möglich an der Saldenkurve liegt, d.h. es gibt keine langwierigen Positionen, die Positionen werden der Reihe nach geöffnet und geschlossen, es gibt keine Martingale und Grid. Es ist klar, dass das Signal stabil ist. Es ähnelt stark einer geraden Linie und zeichnet sich durch eine relativ geringe Belastung der Einlage und einen hohen Prozentsatz an profitablen Positionen aus.

Das nächste Signal:


Das Signal ist auch recht gut, aber große grüne Abwärtsspitzen zeigen, dass das System aktiv Martingale anwendet. Der Anfang des Tests weist einige Peaks auf, die potentiell den gesamten erwirtschafteten Gewinn zerstören könnten. Es gibt keine Garantie, dass dies nicht wieder passiert. Es kann sich herausstellen, dass das gesamte Depot weggeblasen wird. Trotzdem hat der Markt eine sehr große Auswahl an Signalen, und Sie können recht gute solche Exemplare finden.

Expert Advisors

Niemand wird jemals einen stabilen und profitablen EA auf dem Market veröffentlichen, ohne die Überlegung, dass der Verkauf dieses EAs viel mehr einbringt, als wenn der Entwickler ihn nur benutzt. Eine andere Möglichkeit ist, dass der Entwickler sich des Systems nicht sicher ist und kein Risiko eingehen möchte, indem er große Geldbeträge investiert. Stattdessen handelt er oder sie mit kleinen Beträgen, um die Risiken zu reduzieren. Damit sich der Kauf eines EAs auszahlt, benötigen Sie eine große Ersteinlage. Wenn Sie zum Beispiel einen EA mieten, der von den anfänglichen $100 vermutlich $200 einbringt, erhalten Sie nichts, selbst wenn der EA funktionsfähig bleibt.

Der prognostizierte Gewinn sollte mindestens ein Mehrfaches des EA-Preises betragen. Außerdem sollten Sie bedenken, dass niemand garantieren kann, dass die Leistung des EAs für den notwendigen Zeitraum profitabel bleibt. Die Mehrwährungsfähigkeit ist ein zusätzlicher Vorteil eines EAs. Wenn er zumindest auf mehreren Währungspaaren arbeitet, dann wendet er die Marktphysik an, was die Gewinnchancen stark erhöht. Als Beispiel werde ich die Leistung meines aktuellen Systems und eines der Ergebnisse in der Tabelle in Form eines realen Tests zeigen.

Zuerst werde ich die allgemeine EA-Testtabelle auf den letzten 10 Jahren der Geschichte der Hauptwährungspaare zeigen:


Alle diese Ergebnisse wurden durch die Verwendung einer einzigen Set-Datei ohne Anpassungen für ein bestimmtes Währungspaar und ohne Optimierung erzielt.

Unten sehen Sie eine der in der Tabelle angegebenen Optionen:


Diese Option bestätigt, dass es sich nicht nur um eine zufällige Tabelle handelt. Außerdem demonstriert sie die Ergebnisse, die mit einem automatisierten Handelssystem erzielt werden können. Es ist ziemlich schwierig, solche EAs auf dem Markt zu finden, deshalb habe ich mich entschieden, meine eigenen Ergebnisse zu zeigen. Dies ist mein EA, den ich noch nicht veröffentlicht habe. Im Handel wurde die konstante Losgröße von 1 verwendet.

Indikatoren

Meine Einstellung zu Indikatoren ist eher negativ. Ich glaube, sie sind eher für den manuellen Handel geeignet. Es ist zwar möglich, sie in einen Code zu integrieren, aber sie arbeiten extrem langsam und stellen in der Regel einen leicht veränderten Kurs dar. Dies ist natürlich, wenn der Indikator im Kursfenster gezeichnet wird. Was die Indikatoren in einem separaten Fenster betrifft, so berechnen sie meist eine Funktion oder führen wiederkehrende Berechnungen durch, d.h. die folgenden Werte werden aus den vorherigen berechnet. In beiden Fällen ist die Effizienz dieser Tools stark eingeschränkt.

Sie sollten sich nie auf ein Signal sich kreuzender Indikatoren verlassen. Dies ist nur ein psychologisches Moment und nichts weiter. Ich denke, dass die nützlichsten Indikatoren diejenigen sind, die die Marktgeometrie (Muster) erkennen. Sie sollten ein solides Signal haben. Wie auch immer, ein Händler sollte immer die endgültige Entscheidung treffen, ob er einem Muster folgt oder nicht.

Wenn es möglich gewesen wäre, einen Indikator zu entwickeln, der Einstiegspunkte korrekt erkennt, dann wäre ein EA, der darauf basiert, schon längst erstellt worden. Alle von mir getesteten Indikatoren (auch die von mir entwickelten) zeigen keine Einstiegspunkte an. EAs, die auf ihnen basieren, erwiesen sich als nutzlos. Sie dienen meist als Hilfsmittel zur Klärung und, ehrlich gesagt, der Beruhigung von Händlern. Händler wollen sowohl beim Einstieg als auch beim Ausstieg sicher bleiben.

Unten sehen Sie ein Beispiel für meinen Indikator:


Der Indikator veranschaulicht einen nicht-standardmäßigen Ansatz. Er definiert einfache mathematische Funktionen, sucht nach ihnen im Chart und benachrichtigt Sie, wenn sie entdeckt werden. Auch dieser Indikator ist nur ein Hilfsmittel, um Ihre Zeit zu sparen. Diese Indikatoren können im manuellen Handel nützlich sein, aber die endgültige Entscheidung liegt immer bei Ihnen.

Nach dem kurzen Ausflug in weitere Funktionen des Investierens und Handelns ist es an der Zeit, für ein tieferes Verständnis einen Blick auf das Testen und die Entwicklung in Bezug auf die Mathematik zu werfen.

Mathematik hinter einer optimalen Suche

Wenn das ultimative Ziel der Entwicklung darin besteht, eine Anzahl n von Systemen zu erhalten, die unsere Anforderungen erfüllen, dann ist die erste Frage, wie komplex das System sein sollte, um die Effizienz unserer Arbeit zu maximieren. Hier ist die Effizienz die Wahrscheinlichkeit, dass der anfängliche Prototyp innerhalb der von mir definierten Prototypkriterien liegt. Mit anderen Worten, der Prototyp sollte bereits in der Anfangsphase bestimmte Parameter liefern, während man an einem bestimmten Paar oder mehreren Paaren arbeitet. Persönlich betrachte ich die Mehrwährungsfähigkeit immer als ein zwingendes Kriterium. Im Endeffekt läuft alles auf eine Art Abhängigkeit hinaus, die nicht zuverlässig bestimmt werden kann, die aber durch Experimente grob ausgelotet werden kann:

  • Ps=Ps(L)

wobei L eine Anzahl der Zeilen des Arbeitscode ist. Mit anderen Worten: Die Wahrscheinlichkeit, dass die ersten Parameter des erstellten Systems im akzeptablen Bereich liegen, hängt direkt von der Menge des von uns geschriebenen Codes ab. Sie denken vielleicht, dass je mehr Zeilen das System hat, desto besser, aber das ist nicht immer der Fall. Beachten Sie Folgendes:

  • T=K*L

Je mehr Zeilen, desto mehr braucht man, um die Entwicklung abzuschließen. Aber unsere oberste Priorität ist nicht die Anzahl der Codezeilen, sondern ihre Effizienz und wie viele funktionierende Systeme wir in einer Zeiteinheit entwickeln können. Dieser Parameter beeinflusst alle anderen:

  • E= Ps/T
  • E --> Max

Mit anderen Worten: Wir sollten den Parameter E auf alle möglichen Arten maximieren. Die beiden wichtigsten Möglichkeiten sind die Verbesserung der Qualität des Marktwissens und das Finden der optimalen Prototyp-Codegröße. Die Festlegung der Prototypgröße, sowie die Marktkenntnis und die Fähigkeit, diese anzuwenden, ergeben einen bestimmten E0. Er kann als Indikator für Ihre Effizienz verwendet werden. Außerdem erhalten wir eine durchschnittliche Zeit, die für die Entwicklung eines Systems benötigt wird.

Auf die Entwicklung folgt immer das Testen und Modifizieren. Auch diese Prozesse haben ihre eigene Wahrscheinlichkeit. In unserem Fall ist es die Wahrscheinlichkeit einer erfolgreichen Modifikation+Optimierung. Das eine ist untrennbar mit dem anderen verbunden. Ohne Testen sind Korrekturen und Modifikationen nicht möglich. Folglich läuft alles auf mehrere sich wiederholende Zyklen von "Testen-Analysieren-Modifizieren" hinaus. Als Ergebnis verwerfen wir entweder das System oder verbessern es und behalten es für uns selbst zur Anwendung oder zum Verkauf.

Denken Sie auch daran, dass die Optimierung Ihrer Vorgehensweise bei der Entwicklung und den ersten Tests keine Garantie dafür ist, dass Sie mindestens ein solches System finden werden. Alles, worauf Sie sich verlassen können, ist die maximale Chance, das gewünschte Ergebnis zu erhalten, und Sie müssen wissen, wie viel Zeit Sie für die Entwicklung und die ersten Tests haben. Unter Verwendung der Bernoulli-Gleichung können wir wie folgt schreiben: 

  • Pa=Sum(m0...m...n)[C(n,m)*Pow(Ps ,m)*Pow(1-Ps ,n-m)]
  • m0 — minimale Anzahl von zufriedenstellenden Prototypen
  • Pa — Wahrscheinlichkeit, mindestens "m0" oder mehr aus "n" Entwicklungszyklen zu erhalten
  • n — maximal verfügbare Anzahl von Zyklen der Suche nach funktionierenden Prototypen

Ich verwende die Summe in der Gleichung, da ich auch mit jenen Optionen zufrieden bin, bei denen sich die Anzahl der zufriedenstellenden Prototypen als größer erweist, als ich brauche. Die Gleichung, die ich später aufstellen werde, wendet die gleiche Idee an.

Achten Sie darauf, dass Sie Ihre Fähigkeiten hier nicht überschätzen. Erwarten Sie auch nicht viele gute Prototypen. Selbst wenn Sie welche finden, kann niemand garantieren, dass sie so funktionieren, wie Sie es wollen. Sie können mit vielen einfachen Prototypen rechnen, oder Sie können mit komplexeren rechnen. Die Wahl liegt bei Ihnen. Ich verlasse mich auf einfache.

Beim Modifizieren und Testen gibt es auch Parameter, die maximiert werden können und sollten. Ich beginne mit der Wahrscheinlichkeit, eine akzeptable Option im Testschema zu finden. Der gesamte Prozess des Findens akzeptabler Ergebnisse aus dem anfänglich ausgewählten Prototyp geht schließlich in einen einzigen Test-, Änderungs- und Optimierungsprozess über. Es ist ein Batch-Prozess, der mit der Bernoulli-Gleichung beschrieben werden kann:

  • Pf= Sum(1...m...n)[C(n,m)*Pow(Po,m)*Pow(1-Po,n-m)]
  • Po — Wahrscheinlichkeit, ein akzeptables Ergebnis während einer Iteration zu erhalten
  • n — maximal verfügbare Anzahl von Suchzyklen

Ich gehe davon aus, dass wir mindestens ein zufriedenstellendes Ereignis benötigen, während wir nach akzeptablen Ergebnissen suchen. Mit anderen Worten, wir haben eine bestimmte Zeit für das Testen und die Überarbeitung, was sich letztlich in der Anzahl der verfügbaren Iterationen (Test oder Änderung) niederschlägt, um im Prototyp etwas mehr zu finden als das ursprüngliche Ergebnis, und dieses Ergebnis sollte uns gefallen. Pf zu bekommen ist nicht zwingend notwendig, da die rationelle Nutzung der Zeit wichtiger ist:

  • Ef= Pf/m
  • Ef--> Max

In der jetzigen Phase ist es wichtig, das Gleichgewicht zwischen Bearbeiten und Testen zu halten und zu definieren, wie sich ein bestimmter Parameter auf das Endergebnis auswirkt und ob es sinnvoll ist, weitere Tests durchzuführen. Tests und Verbesserungen nehmen immer ungefähr die gleiche Zeit in Anspruch, daher ist "m" eine Anzahl von Tests, die Sie mit Ihrer Intuition oder Erfahrung selbst definieren sollten. Es gibt hier keine spezifischen Richtlinien oder Empfehlungen. Natürlich ist es möglich, sich an den Standardalgorithmus zu halten, bei dem man "n" Zyklen durchführt und dann die Ergebnisse sieht, aber in vielen Fällen ist es möglich, die Anzahl der Iterationen zu reduzieren und z. B. das System in der Anfangsphase zu verwerfen oder umgekehrt zu entscheiden, dass es effizient und flexibel ist. Ich versuche immer, mich an diesen speziellen Ansatz zu halten, weil er Zeit spart. Zeit ist das Wertvollste, was wir haben. Basierend auf den bisherigen Erkenntnissen können wir ein vollständigeres und allgemeineres Maß für die Entwicklungseffizienz erstellen, wenn wir besprechen, dass Sie im Durchschnitt "m" Tests anstelle der vollen "n" Tests verwenden:

  • ET= ( Ps*Pf)/(TSumm)
  • TSumm = T + m*Tm
  • Tm — durchschnittliche Zykluszeit (testen-modifizieren-optimieren)

Da die Ereignisse der Wahrscheinlichkeiten Pf und Ps inkonsistent sind, haben wir das Recht, einen neuen Ereignisraum zu vergleichen, in dem ein neues Ereignis den Prototyp findet. Auf den Vergleich folgt dann eine erfolgreiche Verbesserung, was im Grunde bedeutet, dass ein akzeptables Handelssystem gefunden wurde. Daher multiplizieren wir die Wahrscheinlichkeiten, um die Wahrscheinlichkeit für ein bestimmtes Ereignis zu erhalten.

Wir wissen aber auch, dass jede gefundene Option die Prototyp-Entwicklungszeit "T" und die Verbesserungszeit "m*Tm" benötigt. Je mehr die Erfolgswahrscheinlichkeit auf einen vollen Entwicklungszyklus bezogen ist, desto effektiver ist der Ansatz. In vielerlei Hinsicht hängt die endgültige Zeit von der Testzeit ab. Ursprünglich habe ich Roboter auf Tickbasis erstellt, aber ich empfehle jedem, balkenbasierte Prototypen zu entwickeln. Erstens wird das Ihre Tests um ein Vielfaches beschleunigen, und zweitens kommen Sie von den Ticks weg und verschwenden keine Zeit für Tests mit echten Ticks, was Ihre Entwicklung erheblich beschleunigt. Jetzt ist es an der Zeit, die wichtigsten Strategiekriterien zu analysieren.

Wichtigste Strategieparameter

Es gibt bestimmte quantitative Werte zur Bewertung der Qualität der Strategie, die ihre bestimmten Parameter widerspiegeln. Einige Werte sind wichtiger als andere, aber im Allgemeinen sind sie in der Lage, alles über die Strategie zu sagen. Es gibt die folgenden quantitativen Strategieparameter:

  • Gewinnerwartung
  • Profit Faktor
  • Absoluter Drawdown
  • Relativer Drawdown
  • Maximaler Drawdown
  • Erholungsfaktor
  • Prozentsatz der profitablen Positionen

Gewinnerwartung

Die Gewinnerwartung (expected payoff) ist der wichtigste Parameter eines jeden EA oder manuellen Handelssystems. Wenn Sie keine anständige Gewinnerwartung haben, haben Sie keine Chance auf Erfolg, außer in Fällen von reinem Glück. Die Gewinnerwartung kann auf zwei Arten erfolgen: in Punkten oder in Depotwährung.

  • M_Points=( Sum(1,n)(PrPoints[i]) - Sum(1,n)(LsPoints[i]) )/n
  • M=( Sum(1,n)(Pr[i]) - Sum(1,n)(Ls[i]) )/n

wobei:

  • PrPoints[i] — wenn die i-te Position profitabel ist, dann ist dies der Gewinnbetrag in Punkten
  • LsPunkte[i] — wenn die i-te Position verlustbringend ist, dann ist dies der Verlustbetrag in Punkten
  • Pr[i] — wenn die i-te Position profitabel ist, dann ist dies der Gewinnbetrag in der Kontowährung
  • Ls[i] — wenn die i-te Position verlustbringend ist, dann ist dies der Verlustbetrag in der Kontowährung
  • n — Anzahl der Positionen

Alle Werte, die ich hier beschreibe, charakterisieren eine Strategie nicht mit 100%iger Genauigkeit, denn um sie genau zu bestimmen, ist es notwendig, dass n gegen unendlich tendiert. Aber selbst bei einer moderaten Anzahl von Deals können alle diese Werte mit einem sehr hohen Grad an Zuverlässigkeit viel über die Strategie aussagen.

Um die Rentabilität der Strategie zu gewährleisten, sollte der Wert größer als Null sein. Gleichzeitig sollten wir im Auge behalten, dass ein Teil des Gewinns durch Spread, Kommission und Swap vermindert wird.

  • PrPoints[i]=PrPoints_0[i] - (SpreadOpen[i]/2 + SpreadClose[i]/2) - (OrderComission[i]/OrderLots[i])/TickValue + (OrderSwap[i]/OrderLots[i])/TickValue
  • Pr[i]=Pr_0[i] - (SpreadOpen[i]/2 + SpreadClose[i]/2)*OrderLots[i])*TickValue - OrderComission[i] + OrderSwap[i]

TickValue muss hier besonders erwähnt werden. Dies ist der Preis eines Punktes, vorausgesetzt, wir verwenden das Lot von 1. Dieser Wert ist für alle Währungspaare unterschiedlich und wird so genommen, dass die minimale Preisänderung die ganze Zahl TickValue ergibt. In der Tat ist dies der wichtigste Parameter der Strategie, da der Spread im Wesentlichen ein Teil der Gewinnerwartung ist, der an den Broker geht. Deshalb sollten wir ihm die größte Aufmerksamkeit schenken. Wenn die Gewinnerwartung den Spread nur geringfügig übersteigt, spielen alle anderen Strategieparameter keine Rolle.

Profit Faktor

Der Profit Faktor ist der zweitwichtigste Parameter Ihrer Strategie. Wenn Sie eine gute Gewinnerwartung erhalten haben, ist dies der nächste Parameter, auf den Sie sich konzentrieren sollten, da er die Qualität Ihres Signals oder, mit anderen Worten, die Qualität der Prognose widerspiegelt. Je größer der Gesamtgewinn aus Ihren Positionen und je kleiner ihr Gesamtverlust, desto größer ist der Wert des Parameters.

  • PrFactor = Sum(1,n)(Pr[i]) / Sum(1,n)(Ls[i])

Wie wir sehen, kann der Gewinnfaktor nicht berechnet werden, wenn der Nenner der Gleichung gegen Null geht, oder, formal gesehen, kann angenommen werden, dass dies die Grenze ist, wenn der Nenner vom positiven Teil des Arguments gegen Null tendiert. Der Grenzwert ist plus unendlich. Das bedeutet, wenn es keine unprofitablen Positionen gibt, geht dieser Indikator gegen unendlich, und wenn es keine profitablen Positionen gibt, geht der Indikator gegen 0. Der Wertebereich ist also [0,+unendlich]. Der Durchschnittswert ist 1. Alles, was darüber liegt, ist profitabel, alles, was darunter liegt, ist verlustbringend.

Die nächsten beiden Parameter spiegeln das Gleiche wider, aber auf leicht unterschiedliche Weise.

Maximaler Drawdown

Der maximale Drawdown ist die maximale Differenz zwischen zwei benachbarten Hochs und Tiefs des Eigenkapitals, wenn wir annehmen, dass ein Hoch zuerst kommt. Wenn wir die Höchstpreise des Arrays als PriceExtremum[i] festlegen, dann ist der maximale Drawdown:

  • MaximumDrawdown = MaxOf( PriceExtremum[i+1]- PriceExtremum[i] )

Wenn Sie zwei oder mehr Strategien mit demselben Endgewinn haben, wählen Sie diejenige mit dem geringsten maximalen Drawdown. Danach spiegelt der nächste Parameter das wider, ohne dass Sie diese Annahme treffen müssen:

Erholungsfaktor

Dieser Parameter (recovery factor) ist fast identisch mit dem vorherigen, außer dass der Gewinn in der Gleichung vorhanden ist:

  • Erholungsfaktor = TotalProfit/MaximumDrawdown

Ich glaube, dieser Parameter ist aussagekräftiger. Je höher der Erholungsfaktor, desto stabiler ist die Strategie. Zum Beispiel, je höher der Parameter ist, desto mehr eignet sich eine Strategie für die Verwendung von Martingale, weil die Folge von Verlusten kleiner wird und wir können anfangen, das Lot im Falle von Verlusten zu erhöhen, ohne Angst zu haben, die Einlage zu verlieren.

Prozentsatz der profitablen Positionen

Dieser Parameter ist nur dann relevant, wenn der Wert einer durchschnittlich profitablen Position sehr nahe am Wert einer durchschnittlich verlustreichen Position liegt oder diesem entspricht. Wir sind an das Niveau von 50 % gewöhnt. Alle Werte, die diesen Wert überschreiten, zeigen an, dass die Strategie profitabel ist, andernfalls ist sie verlustbringend. Ich persönlich empfehle die Verwendung von 60%. Ich glaube, dass dieses Niveau ziemlich wichtig ist, besonders für ein manuelles Handelssystem, da dieser Parameter jeden Händler stark beeinflusst. Aber dieser Parameter sagt nichts über den Gewinnfaktor aus. Außerdem ist dieser Parameter nicht immer informativ.

  • WinPercent= (100*NProfit)/(NProfit + NLoss)

Absoluter Drawdown

Dieser Parameter ist wichtig für den Fall, dass Ihre Strategie eine hohe Belastung Ihrer Einlage impliziert oder die Saldenkurve nicht einer geraden Linie ähnelt, sondern eher einem chaotischen Durcheinander mit nur einer leichten Neigung zum Gewinn, oder zumindest, wenn es einige Voraussetzungen dafür in der Zukunft gibt. Es mag jemandem so vorkommen, als ob der absolute Drawdown die Mindesteinlage angeben kann, die uns vor dem Ruin bewahrt, aber das ist eine Illusion, und ich würde niemandem raten, sich an diese Idee zu halten. Dieser Wert ist gleich der Differenz zwischen dem Anfangssaldo und dem untersten Punkt auf der Saldenkurve innerhalb des getesteten oder gehandelten Segments:

  • AbsoluteDrawdown = StartBalance - MinimumBalance
Relativer Drawdown

Ich denke, dieser Parameter ist aussagekräftiger als die Profitabilität oder Stabilität eines Handelssystems, da er den Gesamtgewinn bespricht. Der Unterschied ist ungefähr derselbe wie zwischen dem maximalen Drawdown und dem Erholungsfaktor:

  • 100*AbsoluterDrawdown/EndProfit

Der Wert wird in Prozent gemessen und zeigt, wie sehr der absolute Drawdown den Endgewinn beeinflusst. Die Aussagekraft dieses Faktors ist ebenfalls sehr begrenzt. Je kleiner der Wert ist, desto besser ist die Strategie.

Andere Strategieparameter

Nachfolgend sind einige weniger wichtige Strategieparameter aufgeführt. Sie sollten jedoch nicht unterschätzt werden

  • Maximaler Gewinn
  • Maximaler Verlust
  • Durchschnittlicher Gewinn
  • Durchschnittlicher Verlust
  • Maximum aufeinanderfolgende Gewinner
  • Maximum aufeinanderfolgende Verluste
  • Durchschnitt der aufeinanderfolgenden Gewinner
  • Durchschnitt der aufeinanderfolgende Verluste

Maximaler Gewinn

Eine Position mit dem maximalen Gewinn. Dieser Parameter kann entweder in der Kontowährung oder in Punkten angegeben werden. Es hängt alles davon ab, warum wir den Parameter brauchen. Seine Bedeutung ist eher abstrakt. Dasselbe kann man über den nächsten Parameter sagen.

Maximaler Verlust

Eine Position mit maximalem Verlust.

Durchschnittlicher Gewinn

Die Summe der Gewinne aller Positionen geteilt durch die Anzahl der Positionen. Dieser Parameter ist nur dann aussagekräftig, wenn die Gewinnerwartung und der Gewinnfaktor positiv sind.

  • MiddleProfit= Sum(Pr[i])/n;

Durchschnittlicher Verlust

Die Summe der Verluste aller Positionen geteilt durch die Anzahl der Positionen:

  • MiddleLoss= Sum(Ls[i])/n;

Maximum aufeinanderfolgende Gewinner

Dieser Parameter ist ziemlich nützlich, denn wenn er von oben her begrenzt ist, dann ist er perfekt für die Verwendung eines umgekehrten Martingals. Je kleiner die Anzahl der aufeinanderfolgenden Gewinne ist, desto besser für das umgekehrte Martingal.

Maximum aufeinanderfolgende Verluste

Im Gegensatz zum vorherigen Parameter ermöglicht die Begrenzung des aktuellen Wertes die Verwendung der direkten Martingale. Wenn Sie es irgendwie schaffen, diesen Wert für jedes Signal zu begrenzen, dann werden Sie in der Lage sein, schnell und sicher Geld mit der Martingale zu verdienen, ohne Angst zu haben, Ihre Einlage zu verlieren.

Durchschnitt der aufeinanderfolgenden Gewinner

Der Parameter ist fast identisch mit dem Prozentsatz der Gewinnpositionen. Tatsächlich spiegelt er fast denselben Indikator des Handelssystems auf eine etwas andere Weise wider.

  • MiddleWins= Sum(Wins[i])/n

wobei Wins[i] eine Länge einer bestimmten Halbwelle ist. Wenn wir die gesamte Saldenkurve in steigende und fallende Segmente unterteilen und die steigenden Segmente hervorheben und die Anzahl der Positionen in ihnen sowie die Anzahl der steigenden Halbwellen (n) berechnen, wird es möglich sein, den Parameter selbst zu berechnen, der nichts anderes als das arithmetische Mittel bestimmter Halbwellen ist.

Durchschnitt der aufeinanderfolgende Verluste

Der gleiche Parameter wie oben. Der einzige Unterschied ist, dass er negative Halbwellen berücksichtigt:

  • MiddleLosses= Sum(Loss[i])/n

Meine Ergänzungen

Ich glaube, es gibt noch einen weiteren Parameter, der eine vollständigere Strategieauswertung ermöglicht:

  • Der lineare Faktor.

Er spiegelt die Abweichung der Saldenkurve von der geraden Linie wider, die den Anfang und das Ende der Saldenkurve verbindet. Je mehr die Saldenkurve wie eine gerade Linie aussieht, wenn man mit einem festen Lot handelt, desto besser ist das System. Dies gibt eine höhere Chance auf eine hohe Effizienz in der Zukunft. Dieser Parameter ist besonders beim Handel mit einem festen Lot nützlich. Die Marktvolatilität ändert sich ständig, was bedeutet, dass sich auch die durchschnittliche Kerzengröße (die gesamte Marktdynamik) ändert. Wenn wir dies verstehen, dann können wir sagen, warum die Gewinnerwartung einiger Strategien am Ende des Tests abnimmt oder umgekehrt der Graph sehr gekrümmt ist, was keine Garantie dafür gibt, dass der Neigungswinkel und damit die Gewinnerwartung stabil bleibt.

  • LinearFactor = MaxDeviation/EndBalance
  • MaxDeviaton = Max(MathAbs(Balance[i]-AverageLine))
  • AverageLine=StartBalance+K*i
  • K=(EndBalance-StartBalance)/n
  • n - Anzahl der Positionen im Test

Der Grund für das Fehlen solcher Parameter in den Strategietestern von MetaTrader 4 und MetaTrader 5 ist sehr einfach. Um solche Parameter zu berechnen, brauchen Sie immer zwei Durchläufe, da sie den endgültigen Gewinn kennzeichnen. Je niedriger der Parameter ist, desto besser ist die Strategie. Wenn Sie möchten, können Sie ihn in % messen.

Das Bild unten bietet eine Erklärung:


Auf welche Indikatoren sollte man sich konzentrieren, wenn man ein System testet oder überarbeitet?

Ich glaube, es gibt nur ein paar grundlegende Systemparameter, auf die man sich konzentrieren sollte:

  • Gewinnerwartung in Punkten
  • Gewinnfaktor oder sein Äquivalent
  • Maximaler Drawdown
  • Maximum aufeinanderfolgende Verluste
  • Der lineare Faktor.

Andere Parameter sind sehr schwer als zusätzliche Information über ein System oder einen Markt zu verwenden. Auf jeden Fall habe ich noch keine Algorithmen gefunden, die sie anwenden können, und es gibt auch keine Voraussetzungen für ihre Verwendung. Ich glaube, es macht keinen Sinn, Dinge zu verkomplizieren, die viel einfacher sind, als sie scheinen. Dies bringt nur Verwirrung und lenkt von den eigentlich wichtigen Dingen ab.

Ich werde versuchen, die Auswahl dieser Kriterien so einfach wie möglich zu beschreiben:

Damit die Strategie profitabel ist, muss die Gewinnerwartung in Punkten größer sein als Spread+Kommission+Swap, gemessen in Punkten. Die Gewinnerwartung sollte möglichst das Doppelte des Durchschnitts von Spread+Kommission+Swap betragen. Dann werden wir die Verluste kompensieren und einen Gewinn erhalten, der größer oder gleich dem Parametermodul ist.

Nachdem wir von der Rentabilität der Strategie überzeugt sind, sollten wir uns um die Prognosequalität kümmern, d.h. um den Gewinnfaktor. Je mehr der Indikator eins überschreitet, desto besser ist die Prognosequalität. Je besser die Prognosequalität ist, desto größer ist der Einfluss der Parameter auf alle übrigen. Wäre es möglich gewesen, die Gewinnerwartung zu vernachlässigen, wäre der Gewinnfaktor der wichtigste Parameter gewesen. Er beeinflusst alle anderen Parameter direkt oder indirekt.

Nachdem eine geeignete Rentabilität erreicht wurde, ist es an der Zeit, über den maximalen Drawdown nachzudenken. Dieser Parameter definiert den minimalen Ersteinlage, die erforderlich ist, um die maximale Rentabilität in der aktuellen Kontostandsphase zu gewährleisten. Basierend auf dem maximalen Drawdown können wir die Ersteinlage so wählen, dass der maximale jährliche Gewinnprozentsatz gewährleistet ist, ohne dass wir uns um den Verlust unserer Einlage sorgen müssen. Wenn wir sicher sind, dass die maximalen aufeinanderfolgenden Verluste oder der maximale Drawdown extreme Werte haben, ist es möglich, Martingale im Signal anzuwenden, ohne Angst vor einem Stop-Out zu haben.

Der lineare Faktor stellt sicher, dass es sich um eine Regelmäßigkeit und nicht um ein zufälliges Ergebnis handelt. Je mehr der Graph einer geraden Linie ähnelt, desto wahrscheinlicher ist es, dass es sich um eine echte Regelmäßigkeit oder ein Marktmerkmal handelt.

Die Testzeit ist auch einer der unterschätzten Parameter. Je länger das getestete Segment ist und je ähnlicher die Rentabilitätsergebnisse sind, desto höher ist die Wahrscheinlichkeit, dass das System ein globales Muster widerspiegelt und nicht irgendein Zufallsergebnis.

Saldo und Eigenkapital

Dieses Thema ist sehr wichtig für Anfänger, die den Unterschied zwischen diesen Werten nicht kennen. Das Eigenkapital (equity) ist der aktuelle schwebende Gewinn, während der Saldo (balance) der aktuelle realisierte Gewinn ist. Händler schauen oft auf die Saldenkurve und nicht auf das Eigenkapital. In guten Handelssystemen befindet sich das Eigenkapital so nah wie möglich an der Saldenkurve. Dies deutet darauf hin, dass die Strategie kein Grid, Martingal oder Pyramiding anwendet. Ich will damit nicht andeuten, dass diese Methoden nicht funktionieren, aber sie benötigen ein gutes Signal. Ich gehe in meinen früheren Artikeln mehr darauf ein. Im MetaTrader 5-Strategietester und auf der MQL5-Website wird die Saldenkurve in Dunkelblau angezeigt, während die Eigenkapitalkurve grün dargestellt wird. Je näher die Eigenkapitalkurve an der Saldenkurve liegt, desto sicherer ist die Strategie, vorausgesetzt, dass beide Linien nach oben gehen. 

Echte Handelssystem-Parameter und Durchführbarkeit

Ich betrachte diese Angelegenheit auf der Grundlage meiner Praxis und der von mir entwickelten realen Handelssysteme. Ich möchte Sie vor Investitionen in Signale oder EAs schützen, die nur ein schönes Bild zeigen und sonst nichts. Meiner bescheidenen Erfahrung nach haben Systeme, die weniger als 10 Jahre getestet wurden, ein erhöhtes Risiko, in einem Verlust zu enden. Dies gilt noch mehr, wenn ein getesteter Abschnitt zwei Jahre oder weniger beträgt.

Meine Erfahrung sagt mir, dass ein System, das in der Lage ist, während seiner gesamten Historie mit Gewinn zu handeln, eine Gewinnerwartung von etwa 5-50 Punkten hat, während der Gewinnfaktor im Bereich von 1,05-3,0 liegt. Ich mag den M5-Zeitrahmen sehr, da alle funktionierenden Systeme, die ich erstellt habe, mit diesem Zeitrahmen arbeiten, und Sie können sie auch auf M1 laufen lassen, wenn Sie wollen. Dies ist auch ein sehr guter Chart, wahrscheinlich weil er die kleinsten Balken mit der höchsten Datenmenge pro Zeiteinheit enthält ( High[i],Low[i],Close[i],Open[i] ). Diese Balkenpunkte sind tatsächlich gespeicherte echte Ticks. Je kürzer die Chart-Periode ist, desto mehr echte Ticks werden innerhalb von Kerzen gespeichert. Für viele Systeme ist dies bei der Überprüfung eines Systems im Tester von großer Bedeutung, es sei denn, Sie verwenden echte Ticks in Ihrem Test.

Ich persönlich verwende nie echte Ticks. Alle meine EAs basieren auf Schlusskursen der Balken und ich muss mir keine Gedanken über die künstliche Erzeugung von Ticks machen, da der Schlusskurs des Balkens immer ein echter Tick ist. Der durchschnittliche Gewinnfaktor meiner Systeme liegt bei etwa 1,2, während die Gewinnerwartung bei etwa 15 Punkten liegt, weil ich ziemlich kleine Zeitrahmen verwende. Es ist viel schwieriger, etwas zu finden, das mit hohen Zeitrahmen funktioniert. Sie können die Gewinnerwartung erhöhen, aber nicht den Profitfaktor.

Viele Verkäufer behaupten, dass die EA-Optimierung vorrangig ist und geben eine bestimmte voraussichtliche Zeit vor einer erneuten Optimierung an. Lassen Sie sich von solchen Aussagen nicht täuschen, da es unmöglich ist, die Zeit der Arbeit des EAs in der Zukunft mit irgendwelchen Mitteln vorherzusagen. Ich rate Ihnen auch, das Wort "Optimierung" zu vergessen, bis Sie gelernt haben, wie man dieses Tool benutzt. Sie sind in der Lage, alles zu optimieren, um das gewünschte Ergebnis zu erhalten, aber höchstwahrscheinlich wird es das Ergebnis von Zufälligkeiten sein. Die Optimierung erfordert eine gründliche Herangehensweise. Ich verwende dieses Tool so gut wie gar nicht und prüfe stattdessen alles manuell. Das menschliche Gehirn ist ein viel effizienteres System als eine stumpfe Aufzählung von Parametern.

Wie man das System richtig testet

Ich verwende den folgenden Ansatz, um sowohl meine eigenen als auch fremde Systeme zu testen (obwohl ich in 99% der Fälle meine eigenen Systeme teste):

Für den ersten Test wähle ich immer das letzte Jahr des aktuellen Datums, oder etwas mehr. Wenn mir die Testergebnisse gefallen, nehme ich ein paar weitere Segmente. Denken Sie daran, dass eine umfassende Analyse ein Segment von mindestens 10 Jahren erfordert. Ein 20-Jahres-Segment ist besser.

Wenn das erste und das letzte Jahr gut sind, nehmen Sie ein paar Segmente näher an der Mitte. Wenn die Ergebnisse dort ebenfalls akzeptabel sind, testen Sie alle 10 Jahre und bewerten Sie die Saldenkurve und das Eigenkapital. Wenn sie einer geraden Linie ähneln, verdient das System Ihre Aufmerksamkeit. Diese Vorgehensweise hat ein einziges Ziel - Zeit zu sparen und die Qualität der resultierenden Systeme zu maximieren.

Nach der Durchführung der Analyse ist es an der Zeit, weitere Maßnahmen zu bestimmen. Um das Vertrauen in das System noch weiter zu stärken, sollte es an mehreren anderen Währungspaaren getestet werden. Wenn es dort zumindest einen Teil seiner Effizienz beibehält, dann basiert es auf der Marktphysik und kann verbessert werden. Überprüfen Sie die wichtigsten Systemparameter nacheinander und bestimmen Sie, wie sie das Ergebnis beeinflussen. In den meisten Fällen stellt sich heraus, dass der Einfluss eines bestimmten Parameters fast völlig unabhängig von einem anderen ist.

Nachdem Sie die beste Performance erreicht haben, ist es an der Zeit, das System auf einem Demokonto zu testen. Wenn das System auf einem Demokonto ein akzeptables Ergebnis zeigt, dann kann es auf einem echten Konto ausprobiert werden. Ein weiterer Vorteil ist, dass sich das Ergebnis auf einem Demokonto nicht vom realen unterscheidet, vorausgesetzt, der Broker ist kompetent. Ich persönlich empfehle Alp***. Ich glaube, Sie sind in der Lage, die fehlenden Buchstaben einzufügen. Die historischen Daten dieses Brokers sind nicht verfälscht. Ich empfehle nicht, Tick-Roboter zu testen, da es dort keine Garantien gibt. Verwenden Sie nur EAs, die auf Eröffnungs- oder Schlusskursen der Balken basieren.

Parameter der Balken

Um ein richtiges Verständnis eines Kurses zu bekommen, müssen wir den Balken oder die Kerze definieren und die Daten, die er enthält, sowie die Daten, die wir aufgrund des Aussehens des Balkens oder der Kerze erhalten können. Balken (Kerze) ist ein Tick-Historien-Segment mit einer festen Länge, das nicht alle Ticks speichert, sondern Open, Close, High und Low Ticks, sowie die Eröffnungszeit des Balkens, die in datetime ausgegeben wird. Dies ist die Anzahl der Sekunden, die seit dem 1. Januar 1970 vergangen sind. Es gibt sechs Werte innerhalb eines Balkens:

  • Close[]
  • Open[]
  • Low[]
  • High[]
  • Time[]
  • Volume[]

Die ersten vier Werte sind die vier im Balken gespeicherten Ticks, gefolgt von der Öffnungszeit des Balkens und dem Volumen. Das Volumen ist die Anzahl der Ticks, die in den Balken passen. Die Preisdaten sind am wichtigsten, aber vergessen Sie nicht die Zeit und das Volumen. Wenn Sie mit diesen Daten richtig umgehen können, sind Sie in der Lage, gute Signale zu finden. Balken und Kerzen bedeuten das Gleiche. Der einzige Unterschied ist die grafische Darstellung der gleichen Werte:


Es gibt verschiedene Methoden, Balken und Kerzen zu analysieren. Ich empfehle nicht, sie zu rigoros anzuwenden, da es sich nur um grafische Daten handelt. Sie können nur in Verbindung mit Indikatoren und anderen Analysemethoden hilfreich sein.

Schreiben und Testen eines einfachen volumenbasierten EA

Betrachten wir die Entwicklung eines EA, der Volumen und Zeitkorridore als zusätzliche Marktdaten und Handelsbeschränkung verwendet. Volumenspitzen erlauben uns, wichtige Entscheidungen der Marktteilnehmer zu erkennen. Die Möglichkeit, die Betriebszeit des EA-Servers zu begrenzen, erlaubt es, Bereiche zu erkennen, in denen die Volumina von großer Bedeutung sind. Lassen Sie uns den EA schreiben und mehrere Tests und vollständige Analysen durchführen, um Schlussfolgerungen über das System zu ziehen. Das System selbst wird nur benötigt, um sich mit den Marktparametern zu beschäftigen und ihre Beziehungen zu untersuchen. Das System wird in erster Linie benötigt, um zu zeigen, dass jeder Balkenparameter sein eigenes Gewicht hat und zur Gesamtqualität des Systems beiträgt. Der EA selbst ist an den Artikel angehängt, so dass jeder in der Lage ist, ihn zu verwenden und bei Bedarf zu modifizieren.

Beginnen wir mit den bekannten Bibliotheken für die Arbeit mit Positionen:

#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
CPositionInfo  m_position=CPositionInfo();// trade position object
CTrade         m_trade=CTrade();          // trading object

Sie werden hauptsächlich zur Vereinfachung des Codes benötigt. Ich glaube, ich brauche ihre Funktionsweisen nicht zu erklären. Auf der Website finden Sie viele Daten zu diesem Thema.

Als Nächstes definieren wir die nummerierte Liste, um die Betriebsarten umschalten zu können:

enum MODE_CALCULATE
   {
   MODE_1=0,
   MODE_2=1,
   MODE_3=2,
   MODE_4=3
   };

Dies geschieht in der Erwartung, dass es mehrere Modi geben wird, um die effektivste Marktgleichung zu bestimmen. Am Anfang sollte es einige allgemeine Ideen darüber geben, welche Physik wir ausnutzen wollen, aber wir wissen nicht, welche Gleichung für unseren Fall am effektivsten sein wird. Im aktuellen EA habe ich vier Gleichungsvarianten implementiert. Wir werden sehen, welche der Varianten den Markt am besten beschreibt. Es macht keinen Sinn, zu viele Varianten zu erstellen. Wenn unsere Vermutung richtig ist, werden wir das sicherlich sehen. Ich erstelle normalerweise nicht mehr als vier Modi.

Als Nächstes definieren wir die Eingaben und ihre Ziele:

input MODE_CALCULATE MODEE=MODE_1;//Mode
input int TradeHour=0;//Start Trading Hour
input int TradeMinute=1;//Start Trading Minute
input int TradeHourEnd=23;//End Trading Hour
input int TradeMinuteEnd=59;//End Trading Minute

input bool bWriteValuesE=false;//Log
input int CandlesE=50;//Bars To Analyse
input int Signal=200;//Signal Power
input int PercentE=52;//Percent Signals To One Side

input bool bInvert=false;//Trade Invert

input int SLE=3000;//Stop Loss Points
input int TPE=3000;//Take Profit Points
input double Lot=0.01;//Lot

input int MagicF=15670867;//Magic

Nach der Betriebsart folgt der Block mit vier Parametern, die den Zeitkorridor des Servers beschreiben, innerhalb dessen wir Positionen (oder eine Handelssitzung) öffnen. So seltsam es erscheinen mag, dieser Wert definiert eine Menge. Als Nächstes folgt der Block der Betriebsparameter, der die wichtigsten Systemvariablen beschreibt. Wenn nötig, können Sie in das Protokoll die Daten über die aktuellen Zustände der verfolgten Werte schreiben, um die Eingaben beim Umschalten der Modi anpassen zu können.

Als Nächstes folgt das Marktsegment in Balken, das wir analysieren werden. Alle Kerzen, die tiefer in der Historie liegen, werden bei der Berechnung nicht berücksichtigt. Als Nächstes kommt die Signalstärke mit unterschiedlichen Skalen für jeden Modus. Deshalb brauchen wir das Protokoll. Die letzte Komponente ist ein zusätzliches Signal-Kontrollelement. Es kann vorkommen, dass das Signal groß ist, aber es macht keinen Sinn, seine Stärke einzustellen, ohne den prozentualen Anteil des größten Teils des Signals im Verhältnis zu allen Signalen zu kennen. Die letzten Variablen erlauben uns, den Handel zu invertieren, den Stop-Loss und den Take-Profit einzustellen, sowie das Handelsvolumen und die magische Anzahl aller Orders zu definieren.

Fügen Sie die folgenden Funktionen hinzu, um die Werte aller vordefinierten Arrays schnell und bequem zu berechnen:

MqlTick LastTick;//the last tick

double High[];
double Low[];
double Close[];
double Open[];
datetime Time[];
long Volume[];

void DimensionAllMQL5Values()//prepare the arrays
   {
   ArrayResize(Time,CandlesE,0);
   ArrayResize(High,CandlesE,0);
   ArrayResize(Close,CandlesE,0);
   ArrayResize(Open,CandlesE,0);   
   ArrayResize(Low,CandlesE,0);
   ArrayResize(Volume,CandlesE,0);
   }

void CalcAllMQL5Values()//recalculate the arrays
   {
   ArraySetAsSeries(High,false);                        
   ArraySetAsSeries(Low,false);                              
   ArraySetAsSeries(Close,false);                        
   ArraySetAsSeries(Open,false);                                 
   ArraySetAsSeries(Time,false); 
   ArraySetAsSeries(Volume,false);                                   
   CopyHigh(_Symbol,_Period,0,CandlesE,High);
   CopyLow(_Symbol,_Period,0,CandlesE,Low);
   CopyClose(_Symbol,_Period,0,CandlesE,Close);
   CopyOpen(_Symbol,_Period,0,CandlesE,Open);
   CopyTime(_Symbol,_Period,0,CandlesE,Time);
   CopyTickVolume(_Symbol,_Period,0,CandlesE,Volume);
   ArraySetAsSeries(High,true);                        
   ArraySetAsSeries(Low,true);
   ArraySetAsSeries(Close,true);                        
   ArraySetAsSeries(Open,true);                                 
   ArraySetAsSeries(Time,true);
   ArraySetAsSeries(Volume,true);
   }

Diese Funktionen habe ich bereits in den vorherigen Artikeln erwähnt, wenn auch in verkürzter Form. Außerdem gibt es hier noch die Variable LastTick, die die Werte aller Parameter des letzten vom Server angekommenen Ticks speichern soll. Sie werden benötigt, um auf die Arrays zuzugreifen, genau wie in MQL4.

Die Hauptvariablen und die Logik sind in 'static class' untergebracht:

class TickBox
   {
   public:
   static int BarsUp;
   static int BarsDown;
   static double PowerUp;
   static double PowerDown;
   static double PercentUp;
   static double PercentDown;
   static double PercentPowerUp;
   static double PercentPowerDown;

   static void CalculateAll(MODE_CALCULATE MODE0)//calculate all the necessary parameters
      {
      BarsUp=0;
      BarsDown=0;
      PercentUp=0.0;
      PercentDown=0.0;
      PowerUp=0.0;
      PowerDown=0.0;
      if ( MODE0 == MODE_1 )
         {
         for ( int i=0; i<CandlesE; i++ )
            {
            if ( Open[i] < Close[i] )
               {
               BarsUp++;
               PowerUp+=(MathAbs(Open[i] - Close[i])/(High[i] - Low[i]))*Volume[i];
               } 
            if ( Open[i] > Close[i] )
               {
               BarsDown++;
               PowerDown+=(MathAbs(Open[i] - Close[i])/(High[i] - Low[i]))*Volume[i];
               } 
            }
         }
         
      if ( MODE0 == MODE_2 )
         {
         for ( int i=0; i<CandlesE; i++ )
            {
            if ( Open[i] < Close[i] )
               {
               BarsUp++;
               PowerUp+=(MathAbs(Open[i] - Close[i])/_Point)*Volume[i];
               } 
            if ( Open[i] > Close[i] )
               {
               BarsDown++;
               PowerDown+=(MathAbs(Open[i] - Close[i])/-_Point)*Volume[i];
               } 
            }
         }
         
      if ( MODE0 == MODE_3 )
         {
         for ( int i=0; i<CandlesE; i++ )
            {
            if ( Open[i] < Close[i] )
               {
               BarsUp++;
               PowerUp+=(double(CandlesE-i)/double(CandlesE))*(MathAbs(Open[i] - Close[i])/_Point)*Volume[i];
               } 
            if ( Open[i] > Close[i] )
               {
               BarsDown++;
               PowerDown+=(double(CandlesE-i)/double(CandlesE))*(MathAbs(Open[i] - Close[i])/_Point)*Volume[i];
               } 
            }
         }
         
      if ( MODE0 == MODE_4 )
         {
         for ( int i=0; i<CandlesE; i++ )
            {
            if ( Open[i] < Close[i] )
               {
               BarsUp++;
               PowerUp+=(double(CandlesE-i)/double(CandlesE))*(MathAbs(Open[i] - Close[i])/(High[i] - Low[i]))*Volume[i];
               } 
            if ( Open[i] > Close[i] )
               {
               BarsDown++;
               PowerDown+=(double(CandlesE-i)/double(CandlesE))*(MathAbs(Open[i] - Close[i])/(High[i] - Low[i]))*Volume[i];
               } 
            }
         }
         
      if ( BarsUp > 0 && BarsDown > 0 )
         {
         PercentUp=(double(BarsUp)/double(BarsUp+BarsDown))*100.0;
         PercentDown=(double(BarsDown)/double(BarsUp+BarsDown))*100.0;
         PercentPowerUp=(double(PowerUp)/double(PowerUp+PowerDown))*100.0;
         PercentPowerDown=(double(PowerDown)/double(PowerUp+PowerDown))*100.0;
         }         
      }
   };
   int TickBox::BarsUp=0;
   int TickBox::BarsDown=0;
   double TickBox::PowerUp=0;
   double TickBox::PowerDown=0;   
   double TickBox::PercentUp=0;
   double TickBox::PercentDown=0;
   double TickBox::PercentPowerUp=0;
   double TickBox::PercentPowerDown=0;

Alle ihre Funktionen und Variablen sind statisch. Das Erzeugen von Instanzen ist nicht vorgesehen, da wir sie nicht benötigen. Die gesamte Berechnung wird in einer einzigen Funktion in der Klasse durchgeführt. Sie definiert die Anzahl der Auf- und Abwärts-Balken, sowie ähnliche Komponenten der Signalstärke, die in einer gemeinsamen Variablen aufsummiert werden. Alle vier Gleichungen für jeden Modus sind in dieser Funktion implementiert.

Die ersten beiden Gleichungsvarianten sind ohne Dämpfung bis zum äußersten Ende des analysierten Bereichs implementiert, die nächsten beiden sind eine exakte Kopie, implementieren jedoch eine Dämpfung. In diesem Fall ist die Abschwächung linear. Sie können jederzeit eine andere Dämpfung vornehmen, aber der Einfachheit halber ist es besser, zunächst diejenige auszuprobieren, die den geringsten Rechenaufwand erfordert.

Für jede Kerze wird ein elementarer Term berechnet, der zur Gesamtsumme beiträgt. Die erste Gleichungsvariante berücksichtigt, dass das gesamte in der Kerze vorhandene Volumen ein Signal in die eine oder andere Richtung ist. Außerdem wird berücksichtigt, wie nah die letzte Bewegung an der einzigen ist. Je größer die Dochte am unteren und oberen Ende der Kerze im Verhältnis zur Schlussbewegung sind, desto geringer ist das Volumengewicht. Falls gewünscht, können Sie andere Verhältnisse herstellen.

Die zweite Gleichungsvariante berechnet die gesamte Kerzenbewegung in Punkten. Das Vorzeichen hängt von der Kerzenbewegungsrichtung ab. Außerdem wird der Wert mit dem Volumen multipliziert, daher betrachten wir das Volumen als ein Gewichtsverhältnis, das zeigt, wie zuverlässig die Bewegung des Balkens ist. Der Rest der Variablen berechnet den Prozentsatz der Balken, die nach oben oder unten gegangen sind, sowie den Prozentsatz für das Signal selbst.

Als Nächstes beschreiben wir die Hauptfunktion, in der wir Positionen öffnen und schließen sollen:

void Trade()
   {
   SymbolInfoTick(Symbol(),LastTick);
   MqlDateTime tm;
   TimeToStruct(LastTick.time,tm);
   int MinuteEquivalent=tm.hour*60+tm.min;
   int BorderMinuteStartTrade=HourCorrect(TradeHour)*60+MinuteCorrect(TradeMinute);
   int BorderMinuteEndTrade=HourCorrect(TradeHourEnd)*60+MinuteCorrect(TradeMinuteEnd);
   if ( MathAbs(TickBox::BarsUp-TickBox::BarsDown) >= 1.0 && TickBox::PercentPowerUp >= 50.0 )
      {
      if ( !bInvert ) ClosePosition(POSITION_TYPE_BUY);
      else ClosePosition(POSITION_TYPE_SELL);
      }
      
   if ( MathAbs(TickBox::BarsUp-TickBox::BarsDown) >= 1.0 && TickBox::PercentPowerDown >= 50.0 )
      {
      if ( !bInvert ) ClosePosition(POSITION_TYPE_SELL);
      else ClosePosition(POSITION_TYPE_BUY);
      }
      
     if ( BorderMinuteStartTrade > BorderMinuteEndTrade )
        {
        if ( PositionsTotal() == 0 && !(MinuteEquivalent>=BorderMinuteEndTrade && MinuteEquivalent<= BorderMinuteStartTrade) )
           {
           if ( MathAbs(TickBox::BarsUp-TickBox::BarsDown) >= Signal && TickBox::PercentPowerUp >= PercentE )
              {
              if ( !bInvert ) m_trade.Sell(Lot,_Symbol,LastTick.ask,LastTick.ask+double(SLE)*_Point,LastTick.bid-double(TPE)*_Point);
              else m_trade.Buy(Lot,_Symbol,LastTick.ask,LastTick.bid-double(SLE)*_Point,LastTick.ask+double(TPE)*_Point);
              }
      
           if ( MathAbs(TickBox::BarsUp-TickBox::BarsDown) >= Signal && TickBox::PercentPowerDown >= PercentE )
              {
              if ( !bInvert ) m_trade.Buy(Lot,_Symbol,LastTick.ask,LastTick.bid-double(SLE)*_Point,LastTick.ask+double(TPE)*_Point);
              else m_trade.Sell(Lot,_Symbol,LastTick.ask,LastTick.ask+double(SLE)*_Point,LastTick.bid-double(TPE)*_Point);
              }
           }        
        }
     if ( PositionsTotal() == 0 && BorderMinuteStartTrade <= BorderMinuteEndTrade )
        {
        if ( MinuteEquivalent>=BorderMinuteStartTrade && MinuteEquivalent<= BorderMinuteEndTrade )
           {
           if ( MathAbs(TickBox::BarsUp-TickBox::BarsDown) >= Signal && TickBox::PercentPowerUp >= PercentE )
              {
              if ( !bInvert ) m_trade.Sell(Lot,_Symbol,LastTick.ask,LastTick.ask+double(SLE)*_Point,LastTick.bid-double(TPE)*_Point);
              else m_trade.Buy(Lot,_Symbol,LastTick.ask,LastTick.bid-double(SLE)*_Point,LastTick.ask+double(TPE)*_Point);
              }
      
           if ( MathAbs(TickBox::BarsUp-TickBox::BarsDown) >= Signal && TickBox::PercentPowerDown >= PercentE )
              {
              if ( !bInvert ) m_trade.Buy(Lot,_Symbol,LastTick.ask,LastTick.bid-double(SLE)*_Point,LastTick.ask+double(TPE)*_Point);
              else m_trade.Sell(Lot,_Symbol,LastTick.ask,LastTick.ask+double(SLE)*_Point,LastTick.bid-double(TPE)*_Point);
              }
           }        
        }
   }

Positionen werden auf der Grundlage einer Signalstärke und deren Qualität, gemessen in Prozent, geöffnet und geschlossen, wenn es zumindest den geringsten Hinweis auf eine Signaländerung gibt.

Die folgende Funktion wird verwendet, um nur eine in eine bestimmte Richtung geöffnete Position zu schließen. Das ist einfach.

void ClosePosition(ENUM_POSITION_TYPE Direction)//close a position by a symbol
   {
   bool ord;
   ord=PositionSelect(Symbol());
   if ( ord && int(PositionGetInteger(POSITION_MAGIC)) == MagicF  && Direction == ENUM_POSITION_TYPE(PositionGetInteger(POSITION_TYPE)) )
      {
      if(m_position.SelectByIndex(0)) m_trade.PositionClose(m_position.Ticket());          
      }
   }

Als Nächstes werden die wichtigsten Ereignisse und die Funktion zum Arbeiten mit Balken beschrieben:

int OnInit()
  {
  m_trade.SetExpertMagicNumber(MagicF);//set the magic number for positions
  DimensionAllMQL5Values();//prepare the predefined arrays
  return(INIT_SUCCEEDED);
  }

datetime Time0;
datetime TimeX[1];
bool bNewBar()
   {
   CopyTime(_Symbol,_Period,0,1,TimeX);
   if ( Time0 < TimeX[0] )
      {
      if (Time0 != 0)
         {
         Time0=TimeX[0];
         return true;
         }
      else
         {
         Time0=TimeX[0];
         return false;
         }
      }
   else return false;
   }

void OnTick()
  {
  if ( bNewBar())//work by bars
     {
     CalcAllMQL5Values();
     TickBox::CalculateAll(MODEE);
     if (bWriteValuesE)
        {
        Print("% Sit in buy = ",TickBox::PercentUp);
        Print("% Sit in sell = ",TickBox::PercentDown);
        Print("Signal = ",MathAbs(TickBox::BarsDown-TickBox::BarsUp));
        Print("% Resistance = ",TickBox::PercentPowerUp);
        Print("% Support = ",TickBox::PercentPowerDown);        
        Print("***************************************************************************");
        }
     Trade();
     } 
  }

Wenn wir den EA starten, müssen wir das Array vorbereiten und seine Größe sowie die magische Zahl für Positionen festlegen. Danach beschreiben wir die Prädikatsfunktion, um die Änderung des Balkens zu erkennen und die Variablen, die für ihre Arbeit benötigt werden. Danach beschreiben wir das Haupt-Tick-Ereignis und berechnen die Werte der vordefinierten Arrays neu, gefolgt von der Berechnung der Systemparameter, sowie fügen den Block hinzu, um die Hauptsystemparameter in das Protokoll zu schreiben, wenn die Funktion aktiviert ist. Natürlich können Sie es auch anders machen, wenn Sie wollen. Die Hauptsache ist, dass alles einfach und klar ist.

Die Idee hinter dem EA ist, dass jeder Balken zum aktuellen Bild beiträgt. Bedenken Sie, dass es unmöglich ist, durch zwei-drei Balken auch nur annähernd zu bestimmen, was als nächstes passiert. Jeder Balken trägt zum endgültigen Signal bei, aber ihre Gewichtung ist aufgrund der Marktphysik unterschiedlich. Als Nächstes werde ich mehr darauf eingehen.

Testen des EAs

Lassen Sie uns den EA testen und versuchen, vielversprechende Eigenschaften zu erkennen. Ich beginne mit dem letzten Jahr und verwende EURUSD M5. Beim Durchgehen der Betriebsarten innerhalb der 10-jährigen Historie, sowie der Verwendung verschiedener Zeitkorridore, habe ich folgendes akzeptables Ergebnis gefunden. Das zum Testen des EA verwendete Set ist unten angehängt. Meinen eigenen Regeln für die Analyse von Systemen folgend, habe ich abwechselnd sowohl die Betriebsmodi als auch das Zeitintervall des Servers geändert. Als Ergebnis habe ich die folgenden Parameter in etwa 30-60 Minuten ermittelt.

Unten ist der Test für das letzte Jahr:


Als Nächstes habe ich das erste Jahr auf einem 10-Jahres-Segment getestet:


Die Grafik ist nicht so gut wie auf dem nahen Segment, aber die letzte Bewegung ist immer noch vorhanden. Es scheint, dass auch hier alles funktioniert.

Danach habe ich die Mitte des Segments genommen und geprüft, wie sich das System dort verhält:


Wie wir sehen können, gibt es auch hier Anzeichen für ein globales Muster, und wir müssen nur noch das gesamte Intervall testen und sehen, wie es im globalen Maßstab aussieht:


Der Graph ist bei weitem nicht perfekt, aber wir können die Arbeitssegmente sehen. Wir können auch versuchen, Filter einzuführen oder eine Tiefenoptimierung durchzuführen. Die Wahl eines bestimmten Tools ist immer optional. Wenn wir einen Test mit anderen Paaren durchführen, wird das Ergebnis wahrscheinlich anders ausfallen, aber nach einem gewissen Zeitaufwand werden wir höchstwahrscheinlich die optimalen Parameter für mehrere Paare gleichzeitig finden. Wenn wir es schaffen, die Physik zu begreifen und zu verstärken, dann werden die Ergebnisse noch größer sein.

Selbst in seiner jetzigen Form lieferte der Roboter akzeptable Ergebnisse. Es gab nur sehr wenige Deals, aber der EA arbeitete auf mehreren Währungen. Selbst der einfachste Code kann als mächtige Basis für die Entwicklung einer Idee dienen. Einige Systeme können sogar ohne Modifikationen verwendet werden.

Es wäre natürlich schön, die Mehrwährungsfähigkeit zu erhalten, aber das wird durch mehr Arbeit und aktive Modifikationen erreicht. Ich werde das in diesem Artikel nicht tun und überlasse diese Aufgabe dem Leser. Verbringen Sie nicht zu viel Zeit mit dem System und versuchen Sie nicht, alles aus ihm herauszuquetschen. Wenn es funktioniert, werden Sie das fast sofort sehen. Wenn das Ergebnis nicht sichtbar ist, dann ist es besser, Schlussfolgerungen zu ziehen und umzudenken. Manchmal ist es möglich, etwas zu korrigieren, aber das ist nicht immer der Fall.

Sie können es immer noch testen, aber es ist offensichtlich, dass absolut alle Balken-Parameter das Ergebnis auf unterschiedliche Weise beeinflussen, und es gibt extreme Parameterwerte mit unterschiedlichen Kombinationen bei verschiedenen Paaren. Es gibt auch extreme Werte, die gleichzeitig für alle Paare funktionieren, aber sie zu finden, braucht Zeit und Übung. Die MQL4-Version ist auch an den Artikel angehängt.

Schlussfolgerung

Scheuen Sie sich nicht, Ihren Code selbst zu schreiben und zu testen. Lassen Sie sich auch nicht dadurch entmutigen, dass Ihr System zu einfach aussieht (scheinbar einfache Systeme sind meist die, die tatsächlich funktionieren). Je komplexer das System ist, desto mehr Freiheitsgrade hat es und desto mehr Eingaben und unvorhersehbare Möglichkeiten bietet es. Vermeiden Sie Komplexität in Ihrem Code so weit wie möglich und halten Sie ihn so einfach wie möglich.

Außerdem gilt: Je komplexer das System ist, desto länger müssen Sie es testen. Entwickeln Sie keine Systeme, die auf gar nichts basieren. Glauben Sie nicht denen, die sagen: "Ich habe 30 Transaktionen durchgeführt. Jetzt sollte alles funktionieren". Dies ist ein unprofessioneller Ansatz. Schreiben Sie vor allem keine Systeme, die auf irgendwelchen Indikatoren basieren. Das ist das Dümmste, was Sie als Entwickler tun können.

Generell sollten Sie sich darüber klar werden, wie viel Zeit Sie bereit sind, für die Entwicklung aufzuwenden. Sie sollten ein Ziel und einen akzeptablen Zeitrahmen haben. Eventuell können Sie Ihr Ziel eingrenzen, um es realistischer zu machen, aber Sie sollten trotzdem eines haben.

Ich habe viele langjährige Community-Mitglieder gesehen, die Tausende von Indikatoren auf dem Chart gesetzt haben, um zu versuchen, etwas zu sehen. Das ist der Weg ins Nirgendwo. Zuerst müssen Sie feststellen, ob Sie ein bestimmtes Ergebnis erzielen wollen oder ob das Trading nur Ihr Hobby ist. Ich glaube, es gibt viel interessantere Hobbys da draußen, als jahrelang langweilige Kurscharts anzuschauen. Forex ist ein schwarzes Loch. Wenn Sie darin steckenbleiben, werden Sie nie wieder zurückkehren.

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

Praktische Anwendung von neuronalen Netzen im Handel. Python (Teil I) Praktische Anwendung von neuronalen Netzen im Handel. Python (Teil I)

In diesem Artikel werden wir die schrittweise Implementierung eines Handelssystems analysieren, das auf der Programmierung von tiefen neuronalen Netzen in Python basiert. Dies wird unter Verwendung der von Google entwickelten TensorFlow-Bibliothek für maschinelles Lernen durchgeführt. Außerdem werden wir die Keras-Bibliothek zur Beschreibung von neuronalen Netzen verwenden.

Zeitreihen in der Bibliothek DoEasy (Teil 55): Die Kollektionsklasse der Indikatoren Zeitreihen in der Bibliothek DoEasy (Teil 55): Die Kollektionsklasse der Indikatoren

Der Artikel setzt die Entwicklung von Objektklassen für die Indikatoren und deren Kollektionen fort. Für jedes Indikatorobjekt erstellen wir seine Beschreibung und die richtige Kollektionsklasse für die fehlerfreie Speicherung und das Abrufen von Indikatorobjekten aus der Kollektionsliste.

Zeitreihen in der Bibliothek DoEasy (Teil 56): Nutzerdefiniertes Indikatorobjekt, das die Daten von Indikatorobjekten aus der Kollektion holt Zeitreihen in der Bibliothek DoEasy (Teil 56): Nutzerdefiniertes Indikatorobjekt, das die Daten von Indikatorobjekten aus der Kollektion holt

In dem Artikel wird das Erstellen des nutzerdefinierten Indikatorobjekts für die Verwendung in EAs erklärt. Lassen Sie uns die Bibliotheksklassen leicht verbessern und Methoden hinzufügen, um Daten von Indikatorobjekten in EAs zu erhalten.

Neuronale Netze leicht gemacht (Teil 6): Experimentieren mit der Lernrate des neuronalen Netzwerks Neuronale Netze leicht gemacht (Teil 6): Experimentieren mit der Lernrate des neuronalen Netzwerks

Wir haben zuvor verschiedene Arten von neuronalen Netzen zusammen mit ihren Implementierungen betrachtet. In allen Fällen wurden die neuronalen Netze mit der Gradientenverfahren trainiert, für die wir eine Lernrate wählen müssen. In diesem Artikel möchte ich anhand von Beispielen zeigen, wie wichtig eine richtig gewählte Rate ist und welchen Einfluss sie auf das Training des neuronalen Netzes hat.