English Русский 中文 Español 日本語 Português
Fuzzy-Logik für eine manuelle Handelsstrategie

Fuzzy-Logik für eine manuelle Handelsstrategie

MetaTrader 4Handel | 26 August 2016, 14:00
1 611 1
Alexander Fedosov
Alexander Fedosov

Einführung

Die rasante Entwicklung der Technologie hat zu einer verstärkten Nutzung automatisierter Handelssysteme in den modernen Währungsmärkten geführt. Dennoch handeln viele Händler weiterhin manuell. Die Vor- und Nachteile der beiden Handelsansätze sind sehr gut bekannt: Dem automatisierten Handel fehlt die Flexibilität gegenüber einem sich ständigen ändernden Markt, der manuelle Handel andererseits könnte durch einen störenden menschlichen Einfluss zu oft viel zu flexibel sein. Tatsächlich sind diese Extrema nur die beiden Seiten der selben Medaille.

In meinem vorheriger Artikel habe ich in Beispielen versucht, die Nachteile eines automatisierten Handels durch die Verwendung der Fuzzy-Logik zu kompensieren, beispielsweise durch das Aufweichen einer übermäßig strengen Formalisierung einer Strategie eines Handelsroboters oder Indikators. Dieser Artikel betrachtet die Möglichkeit die manuelle Handelsstrategie zu verbessern. Der Einsatz modernen Technik wird auch dem manuellen Händler, der immer selbst entscheidet, mehr Vor- als Nachteile bringen.

 

Die Auswahl einer manuellen Strategie mit spezifischen, formalisierten Bedingungen

Viele Händler bevorzugen es heutzutage, selbst die Verantwortung für das Eröffnen und Schließen von Positionen zu übernehmen und das nicht automatisierten Systemen zu überlassen. Sie müssen ihre eigene Handelsstrategie entwickeln, die alle Möglichkeiten des Marktes berücksichtigt. Der müssen sie danach strikt folgen und jedem Impuls aus Angst und Gier widerstehen.

Wir benötigen daher als erstes eine Handelsstrategie. Lassen Sie mich die drei Stufen beschreiben, mit denen wir das erreichen.

  • Stufe №1. Suche und Bestimmung der Instrumente, die unserer Strategie verwendet.
  • Stufe №2. Klare Bedingungen für die Eröffnung einer Marktposition durch den Händler.
  • Stufe №3. Klare Bedingungen für das Schließen einer Position, sei das Ergebnis positiv oder negativ.

Stufe №1.

Als Beispiel habe ich in der ersten Stufe drei Indikatoren für die Handelsstrategie ausgewählt:

  1. Average Directional Movement Index, ADX. Dieser Trend-Indikator zeigt die Stärke des aktuellen Trends.
  2. Relative Vigor Index, RVI Oszillator.
  3. Accelerator Oszillator(AC) Indikator von Bill Williams.

Das Gesamtbild mit den Einstellungen des MQL4 Handelsterminals:

Fig. 1. Gesamtbild der Handelsstrategie

Stufe №2.

Auf der zweiten Stufe entdecken wir, wie wir die Instrumente, die Bedingungen für ihr Funktionieren und ihre Parameter für den Markteinstieg verwenden.

Aber, beginnen wir am Anfang.

  • Unsere erste Indikator ist der ADX. Wie in Fig. 1 zu sehen, ist die Periodenlänge des Indikators 10. Außerdem, wurde ein spezieller Level für die Hauptlinie (grüne Farbe) auf 30 gesetzt. Jeder Wert, der größer oder gleich ist, wird als positives Signal für den Markteintritt gewertet. Es ist erwähnenswert, dass als Kaufsignal dieses Indikator gilt, wenn +DI (grün gestrichelt) größer ist als -DI (rot gestrichelte Linie). Entsprechend wäre ein Verkaufssignal, wenn -DI größer ist als +DI.
  • Der zweite Indikator ist der AC. Hier verwenden wir die Signale wie in der offiziellen Dokumentation beschrieben. Insbesondere, wenn der Wert des Indikators kleiner als 0 ist und auf der analysierten und den beiden vorherigen Bars steigt, ist das ein Kaufsignal. Entsprechend, wenn der der Wert des Indikators über 0 ist und auf der analysierten und den beiden vorherigen Bars fällt, erhalten wir ein Verkaufssignal.
  • Der Dritte Indikator ist der RVI. Setzen wir seine Periodenlänge auf 10. Die Bedingung für Kaufen sei, wenn die Signallinie (dünn, rot) die Hauptlinie (grün) kreuzt. Der Kreuzungspunkt der Linien auf der analysierten Bar muss unter Null liegen. Ähnlich die Bedingung für den Verkauf: Die Signallinie kreuzt die Hauptlinie über Null.
  • Die nächste Bedingung für den Einsatz ist ein stündlicher Zeitrahmen (H1).
  • Die Bedingung einer Positionseröffnung verlangt, dass alle drei ausgewählten Indikatoren das gleiche Signal zeigen.
  • Zum Schluss entscheiden wir über die Größe der Position. Als Beispiel setzen wir: 0,01 Lots, Take-Profit bei 50 Points, Stopp-Loss bei 30 Points.

Formalisieren wir die Bedingungen für ein besseres Verständnis.

Eröffnung einer Kaufposition (Kaufsignal)

  1. Der Wert der grünen Hauptlinie des ADX ist größer oder gleich als 30, und der +DI ist größer als der -DI.
  2. Der Wert des AC steigt auf der aktuellen Bar und ist größer als beide vorherigen Bars, die auch konsistent steigen. Optisch sind es drei grüne Stäbe des Histogramms, wobei jeder Stab kleiner ist als sein Vorgänger, und alle drei im negativen Bereich liegen.
  3. Das RVI-Signal (dünn, rot) kreuzt die Hauptlinie (grün) unter Null und beide steigen.
  4. Wir kaufen 0,01 Lot und platzieren Take-Profit bei 50 Points und Stopp-Loss bei 30 Points.
Eröffnung einer Verkaufposition (Verkaufsignal)
  1. Der Wert der grünen Hauptlinie des ADX ist größer oder gleich als 30, und der +DI ist unter dem -DI.
  2. Der Wert des AC fällt auf der aktuellen Bar und ist kleiner als beide vorherigen Bars, die auch konsistent fallen. Optisch sind es drei rote Stäbe des Histogramms, wobei jeder Stab kleiner als sein Vorgänger ist, und alle drei im positiven Bereich liegen.
  3. Das RVI-Signal (dünn, rot) kreuzt die Hauptlinie (grün) über Null und beide fallen.
  4. Wir verkaufen 0,01 Lot und platzieren Take-Profit bei 50 Points und Stopp-Loss bei 30 Points.

Stufe №3.

Jetzt müssen wir nur noch festlegen, wann wir die Position wieder schließen. Als Bedingung für den Ausstieg, verwenden wir die Preisziele, die wir gesetzt haben: Take-Profit von 50 Points oder Stopp-Loss von 30 Points.

Damit ist unsere Handelsstrategie aufgestellt. Wir verfügen über die Bedingungen zum Öffnen und Schließen der Positionen, wir haben uns unsere Indikatoren ausgewählt und deren Parameter bestimmt und die Positionsgröße sowie die Kursziele definiert. Und schließlich haben wir uns für die Situationen für das Schließen der Positionen entschieden.

Als nächstes überprüfen wir die Handelsstrategie unter realen Bedingungen. Was wir als erstes akzeptieren müssen, ist der Umstand, dass es keine ideale Strategie gibt, die sich langfristig für alle Marktsituationen eignet. Händler, die automatische Systeme verwenden, und jene, die manuell handeln, beobachten gelegentlich, dass ihr System in verschiedenen Situationen unterschiedlich agiert. Auch ist es nicht ungewöhnlich, wenn die Anfangsbedingungen des bereits definierten Handelssystems eigentlich bessere Ergebnisse zeigen könnte.

Zum Beispiel könnte ein Händler mit unserem System bemerken, dass der Take-Profit auch höher gesetzt werden könnte. Das aber nicht, weil er einfach nur mehr haben will, sondern weil er fortgesetzt sein System analysiert und seine Statistik zeigt, dass, nach dem Schließen einer Gewinnposition, der Kurs sich noch eine Zeit lang weiter in der Handelsrichtung bewegt. Es ergibt sich für den Händler daher folgende Frage: Wie verwende ich statistische Daten und Beobachtungen für die Verbesserung des Systems?

 

Die Überwindung der Nachteile einer strengen Formalisierung durch Fuzzy-Logik

Betrachten wir die im System verwendeten Indikatoren aus Sicht der Theorie der Fuzzy-Logik. In meinem vorherigen Artikel habe ich versucht, ihren Hauptvorteil zu erläutern - die Flexibilität, die Teile der Handelsstrategien zu analysieren, die eine strenge Kategorisierung verwenden. Die Fuzzy-Logik verwischte die strenge Grenzen und bietet ein breiteres Bild der Beurteilung und Reaktionen des Systems mit den Randwerten bei seiner Arbeit. Es war auch ein Beispiel für einen anpassungsfähigeren Ansatz der Verwendung des ADX-Indikators. Zunächst wurde strikt zwischen einem schwachen, mittleren und starken Trend unterschieden, um dann diese Kategorisierung aufzuweichen, sodass die Trendstärke nicht mehr strikt an die reinen Indikatorwerte gebunden war.

Aber kommen wir zurück zu unserem System und fragen uns, wie soll uns das alles helfen?

Stellen Sie sich vor, unsere Händler beobachtet den Markt und sieht ein Signal seines ersten Indikators: Der ADX erreicht zum Beispiel die 32. Er markiert dies und wartet auf die Bestätigung durch die beiden anderen Indikatoren. Kurz danach erscheint das Signal des AC, während der ADX auf 40 steigt. Kurz danach kreuzt auch die Signallinie des RVI die Hauptlinie, somit sind alle drei Bedingungen für das Eröffnen einer Position erfüllt. ADX hat steht bereits bei 45. Aber der absoluten Wert des ADX ist in unserem System nicht so wichtig. Die Hauptsache ist, er ist größer als 30. Der Händler, seinen Regeln folgend, eröffnet also eine Position mit 0,01 Lot, Take-Profit bei 50 Points und Stopp-Loss bei 30.

Nun simulieren wir ein anderes Vorgehen. Zu Anfang bleibt alles gleich wie im ersten Fall. ADX=32, das Signal des AC erscheint, und der ADX erreicht jetzt die 40. Jetzt aber, obwohl das Signal des RVI ausbleibt, springt der ADX auf 55 statt den 45. Der Vergleich der beiden beschriebenen Optionen zeigt, dass das zweite Signal stärker ist als vorher, aber unser Händler eröffnet immer noch eine Position mit gleicher Lotgröße und den selben Werten für Take-Profit und Stopp-Loss.

Hier begegnen wir dem ersten Nachteil unserer Strategie. Es wird nur das erscheinen der Signale ausgewertet ohne deren Qualität zu berücksichtigen. Auch wenn wir die Kategorie auswerten und bestimmen können, geht die Genauigkeit in den Randbereichen verloren.

Wie also könnten wir besondere Fälle des ADX und des RVI Indikators verbessern und ihre Parameter mit einer zu eröffnenden Position verbinden? Dafür müssen wir folgendes tun:

  • Bestimmung klarer Kategorien für die Auswertung der Trendstärke (ADX) und des Relative Vigor Index (RVI). Das ist das Eingangssignal, auf dem die weiteren Entscheidungen aufbauen.
  • Bestimmung klarer Kategorien der Ziele unserer Positionen (Take-Profit oder Stopp-Loss in unserer Strategie, obwohl hier auch die Lotgröße bestimmt werden könnte). Das ist das Ausgangssignal, das unsere Position auf dem Markt an die Stärke eines Trends anpasst.
  • Beschreibung der Kategorien der Ein- und Ausgabesignale der Funktionen der unscharfen Mengen (Fuzzy-Sets).
  • Erstellung einer Schnittstelle, die die Empfehlungen für eine Änderung der Position nach der anfänglichen Strategie durch die neuen Bedingungen angezeigt.
  • Erstellung flexibler Konfigurationsänderungen der Zugehörigkeitsfunktionen, die es dem System ermöglichen, falls erforderlich, die Empfehlungen anzupassen.

Um zu beginnen, beschreiben wir die erste Eingangsvariable — den Wert der Trendstärke.

1. Wir bestimmen 4 Kategorien der Trendstärke: klein, mäßig, mittel und hoch. So schaut es dann aus:

Fig. 2. Optische Einteilung der Trendstärke

2. Um die Kategorien der Signalausgabe festzulegen, muss entschieden werden, wie der ADX die Position beeinflussen soll. Normalerweise gilt, je stärker der Trend, desto länger die Dauer. Dem werden wir entsprechen: Abhängig vom ADX im Moment, da alle drei Signale erscheinen, erhöhen wir Take-Profit zwischen 10 - 50 Points.

Deshalb stellen wir die folgenden Kategorien für die Wert der Gewinnziele, die zu den ursprünglichen 50 Points unserer Strategie addiert werden.

  • low_take Kategorie: schwacher Trend, addiere 10 - 20 Points zum Ziel.
  • mod_take Kategorie: mäßiger Trend, addiere 20 - 30 Points zum Ziel.
  • med_take Kategorie: mittlerer Trend, addiere 30 - 40 Points zum Ziel.
  • high_take Kategorie: starker Trend, addiere 40 - 50 Points zum Ziel.

3. Als nächstes beschreiben wir die Bedingungen der Zugehörigkeitsfunktionen der Theorie der unscharfen Mengen (siehe oben). Die vier Trendkategorien sind wie folgt::


Fig. 3. Beschreibung von vier Trendkategorien der Fuzzy-Logik

Wie Fig. 3 zeigt, wurde jede Kategorie durch eine Zugehörigkeitsfunktionen bestimmt: schwacher und starker Trend durch Trapezfunktionen und die Kategorien mäßiger und mittlerer Trend durch trianguläre Funktionen.

Definieren wir nun dasselbe für den RVI.

1. Setzen wir die Kategorien für den Relative Vigor Index. Es werden vier: schwach, mittel, hoch und höher. So schaut es dann aus:

Fig. 4. Optische Einteilung des Relative Vigor Index nach Kategorien

2. Beschreiben wir jetzt die mit den Zugehörigkeitsfunktionen eingeführten Kategorien. Trapezfunktionen werden für die Kategorien schwach und höher verwendet, und trianguläre Funktionen für die Kategorien mittel und hoch .


Fig. 5. Beschreibung der Kategorien des RVI-Index'

Wie gehabt bestimmen wir die Kategorien für die Werte der Gewinnziele: erste und vierte Kategorie (10-20 und 40-50 Points) mittels Trapezfunktionen, und für die zwei verbliebenen (20-30 und 30-40 Points) — durch triangulären Funktionen. So schaut dann dieses Umsetzung aus.


Fig. 6. Kategorisierunsfunktionen der Gewinnziel

 

Implementierung der Anzeige der Empfehlungen für die Positionsänderungen

Für die Anzeige wählen wir vier Parameter aus:

  • ADX-Wert. Aber nur, wenn er das Kriterium erfüllt — 30 oder mehr.
  • RVI-Wert. Aber nur, wenn er größer als 0,1 (Verkaufsignal), oder kleiner -0,1 (Kaufsignal).
  • Die empfohlene Anzahl von Points, die zum Anfangsgewinnziel von 50 addiert werden.
  • Take-Profit Wert im Format der Preise des Handelssymbol (Anfangsgewinnziels plus der empfohlene Veränderung).

Die vollständige Umsetzung der Handelsstrategie schaut dann so aus (Fig.6).

Fig. 7. Die vollständige Umsetzung der Handelsstrategie mit den Einstellungen

Schauen wir uns nun die Umsetzung an mit den Möglichkeiten von MQL4 und der FuzzyNet Bibliothek.

Wir analysieren und implementieren den logischen Hauptteil dieser Informationsanzeige mit MQL4.

//+------------------------------------------------------------------+
//| FuzzyNet Panel                                                   |
//+------------------------------------------------------------------+
#property copyright "Alexander Fedosov"
#property version "1.0"
#property strict
#property link "https://www.mql5.com/ru/users/alex2356/"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Green
//+------------------------------------------------------------------+
//| Connecting libraries                                             |
//+------------------------------------------------------------------+
#include <Math\FuzzyNet\MamdaniFuzzySystem.mqh>

Wir definieren die Anfangseigenschaften und laden die Bibliothek der Fuzzy-Logik. Wir setzen die Bedingungen für eine Anzeige im Chartfenster. Wir definieren einen Indikatorpuffer mit seiner Farbe (grün) als Pfeilsymbol-Indikator für die analysierte Bar.

//--- Input parameters
input string  p1="==== Parameters ====";
input int fontSize=15;
input int adx_period=10;
input int rvi_period=10;
input int num_bar=0;
input int Screen_corner=4;
input color label_clr=Red;
input color textColor=Black;

Schauen wir uns jetzt den ersten Block der Eingabeparameter im Detail an. Er verfügt über folgende Elemente:

  • fontSize — Schriftgröße des Textes (empf. zwischen 8 — 15).
  • adx_period — Periodenlänge des ADX Indikators.
  • num_bar — Anzahl der Bars für die Berechnung durch das System.
  • Screen_corner — Ecke der Anzeige.
  • label_clr — Textfarbe der Namen.
  • textColor — Textfarbe der Werte.

Der zweite Block der Eingabeparameter der Fuzzy-Logik beinhaltet die meisten Parameter der Zugehörigkeitsfunktionen aller Eingabeparameter (ADX-Trendstärke, RVI-Index) und Ausgabeparameter (empf. Points für die Gewinnziele).

input string  p2="==== Fuzzy Logic Parameters ====";
//--- ADX
input double in_term1a = 20;
input double in_term1b = 30;
input double in_term1c = 40;
input double in_term1d = 45;
input double in_term2a = 40;
input double in_term2b = 50;
input double in_term2c = 60;
input double in_term3a = 50;
input double in_term3b = 60;
input double in_term3c = 70;
input double in_term4a = 60;
input double in_term4b = 70;
input double in_term4c = 100;
input double in_term4d = 120;
//--- RVI
input double in_term1a1 = -0.25;
input double in_term1b1 = 0.1;
input double in_term1c1 = 0.15;
input double in_term1d1 = 0.25;
input double in_term2a1 = 0.15;
input double in_term2b1 = 0.25;
input double in_term2c1 = 0.35;
input double in_term3a1 = 0.25;
input double in_term3b1 = 0.35;
input double in_term3c1 = 0.45;
input double in_term4a1 = 0.4;
input double in_term4b1 = 0.45;
input double in_term4c1 = 1;
input double in_term4d1 = 1.2;
//--- Output
input double out_term1a = 5;
input double out_term1b = 10;
input double out_term1c = 15;
input double out_term1d = 22.5;
input double out_term2a = 17.5;
input double out_term2b = 25;
input double out_term2c = 32.5;
input double out_term3a = 27.5;
input double out_term3b = 35;
input double out_term3c = 42.5;
input double out_term4a = 37.5;
input double out_term4b = 45;
input double out_term4c = 50;
input double out_term4d = 60;
input double min_tp = 10;
input double max_tp = 50;


Im nächsten Block deklarieren wir die Variablen, die Namen in der Anzeige, die Daten der Vorlage für die Anzeige (Größe, Ort, Schrift usw.), und wir bestimmen die Parameter der Darstellung von jedem Element auf Basis der aktuellen Bar (der Pfeil unserem Fall).

int scaleX=55,scaleY=25,offsetX=35;
//--- Der Array mit den Namen des Indikators
string signalName[]={"ADX_val:","RVI_val:","TP_plus:","TP_prc:"};
double adx,adx_di_minus,adx_di_plus,rvi,rvi_sig,mdm;
double Buffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(fontSize>15 || fontSize<8)
     {
      Print("ERROR: Incorrect fontSize. Must be 8-15.");
      Alert("ERROR: Incorrect fontSize. Must be 8-15.");
      return(0);
     }
   if(Screen_corner>4 || Screen_corner<1)
     {
      Print("ERROR: Incorrect Screen_corner. Must be 1-4.");
      Alert("ERROR: Incorrect Screen_corner. Must be 1-4.");
      return(0);
     }
//---
   SetIndexStyle(0,DRAW_ARROW,EMPTY,1);
   SetIndexArrow(0,234);
   SetIndexBuffer(0,Buffer);
   ArrayInitialize(Buffer,0.0);
//---
   for(int y=0;y<4;y++)
     {
      ObjectCreate("lb_ind_nm"+string(y),OBJ_LABEL,0,0,0,0,0);
      //--- Änderung der Ecke    
      ObjectSet("lb_ind_nm"+string(y),OBJPROP_SELECTABLE,false);
      ObjectSet("lb_ind_nm"+string(y),OBJPROP_CORNER,Screen_corner);
      ObjectSet("lb_ind_nm"+string(y),OBJPROP_XDISTANCE,offsetX-30);
      ObjectSet("lb_ind_nm"+string(y),OBJPROP_YDISTANCE,y*scaleY+20);
      ObjectSetText("lb_ind_nm"+string(y),signalName[y],fontSize,"Tahoma",label_clr);
     }
//---
   for(int y=0;y<4;y++)
     {
      ObjectCreate("lb_ind0"+string(y),OBJ_LABEL,0,0,0,0,0);
      //--- Änderung der Ecke
      ObjectSet("lb_ind0"+string(y),OBJPROP_SELECTABLE,false);
      ObjectSet("lb_ind0"+string(y),OBJPROP_CORNER,Screen_corner);
      ObjectSet("lb_ind0"+string(y),OBJPROP_XDISTANCE,scaleX+offsetX);
      ObjectSet("lb_ind0"+string(y),OBJPROP_YDISTANCE,y*scaleY+20);
      ObjectSetText("lb_ind0"+string(y),"",fontSize,"Tahoma",textColor);
     }
   return(INIT_SUCCEEDED);
  }


Schauen wir nun auf den Hauptblock der Signalverarbeitung der Indikatoren ADX und RVI.

Hier stehen die Bedingungen unter denen die Indikatoren ihre Kauf- und Verkauf-Signale berechnen. Stimmen sie überein, werden die Werte mittels der Funktion mamdani(double t, double v) ausgewertet und angezeigt. Das Ganze hat folgende Form: Die aktuellen Indikatorwerte zeigen, wenn wir ein Kauf- oder Verkaufsignal erhalten; empfohlener Take-Profit (in Points und als numerischer Wert).

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   Buffer[num_bar]=High[num_bar]+20*_Point;
   adx=NormalizeDouble(iADX(_Symbol,PERIOD_CURRENT,adx_period,PRICE_CLOSE,MODE_MAIN,num_bar),_Digits);
   adx_di_plus=NormalizeDouble(iADX(_Symbol,PERIOD_CURRENT,adx_period,PRICE_CLOSE,MODE_PLUSDI,num_bar),_Digits);
   adx_di_minus=NormalizeDouble(iADX(_Symbol,PERIOD_CURRENT,adx_period,PRICE_CLOSE,MODE_MINUSDI,num_bar),_Digits);
//---
   rvi=NormalizeDouble(iRVI(_Symbol,PERIOD_CURRENT,rvi_period,MODE_MAIN,num_bar),_Digits);
   rvi_sig=NormalizeDouble(iRVI(_Symbol,PERIOD_CURRENT,rvi_period,MODE_SIGNAL,num_bar),_Digits);
//---   
   if(adx>30 && adx_di_plus>adx_di_minus && rvi>rvi_sig && rvi<-0.1)
     {
      mdm=MathCeil(mamdani(adx,MathAbs(rvi)));
      ObjectSetText("lb_ind00","buy_signal: "+DoubleToString(adx,_Digits),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind01","buy_signal: "+DoubleToString(rvi,_Digits),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind02",DoubleToString(mdm,0),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind03",DoubleToString(tp_prc(mdm),_Digits),fontSize,"Tahoma",textColor);
     }
   else if(adx>30 && adx_di_plus<adx_di_minus && rvi<rvi_sig && rvi>0.1)
     {
      mdm=MathCeil(mamdani(adx,rvi));
      ObjectSetText("lb_ind00","sell_signal: "+DoubleToString(adx,_Digits),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind01","sell_signal: "+DoubleToString(rvi,_Digits),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind02",DoubleToString(mdm,0),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind03",DoubleToString(tp_prc(mdm),_Digits),fontSize,"Tahoma",textColor);
     }
   else
     {
      ObjectSetText("lb_ind00","no_signal",fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind01","no_signal",fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind02"," - ",fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind03"," - ",fontSize,"Tahoma",textColor);
     }
   return(rates_total);
  }


Die Funktion erstellt das Fuzzy-Logik-System. Es wartet auf die beiden Indikatorsignale — Trend und Vigor (beide bestehen jew. den 4 Termen der Zugehörigkeitsfunktionen), und erzeugt ein ausgehendes Signal. Ebenfalls Teil des Systems sind vier Regeln der Ein- und Ausgangssignale.

//+------------------------------------------------------------------+
//| Funktion erstellt und berechnet die Fuzzy-Logik des Systems      |
//+------------------------------------------------------------------+
double mamdani(double t,double v)
  {
   double res=0;
//--- Mamdani Fuzzy System  
   MamdaniFuzzySystem *fsSignal=new MamdaniFuzzySystem();
//--- Create input variables for the system
   FuzzyVariable *fsTrend=new FuzzyVariable("trend",30.0,100.0);
   FuzzyVariable *fsVigor=new FuzzyVariable("vigor",0.1,1.0);
//--- ADX
   fsTrend.Terms().Add(new FuzzyTerm("low", new TrapezoidMembershipFunction(in_term1a, in_term1b, in_term1c, in_term1d)));
   fsTrend.Terms().Add(new FuzzyTerm("moderate", new TriangularMembershipFunction(in_term2a, in_term2b, in_term2c)));
   fsTrend.Terms().Add(new FuzzyTerm("medium", new TriangularMembershipFunction(in_term3a, in_term3b, in_term3c)));
   fsTrend.Terms().Add(new FuzzyTerm("high",new TrapezoidMembershipFunction(in_term4a, in_term4b, in_term4c, in_term4d)));
   fsSignal.Input().Add(fsTrend);
//--- RVI
   fsVigor.Terms().Add(new FuzzyTerm("low", new TrapezoidMembershipFunction(in_term1a1, in_term1b1, in_term1c1, in_term1d1)));
   fsVigor.Terms().Add(new FuzzyTerm("medium", new TriangularMembershipFunction(in_term2a1, in_term2b1, in_term2c1)));
   fsVigor.Terms().Add(new FuzzyTerm("high", new TriangularMembershipFunction(in_term3a1, in_term3b1, in_term3c1)));
   fsVigor.Terms().Add(new FuzzyTerm("higher",new TrapezoidMembershipFunction(in_term4a1, in_term4b1, in_term4c1, in_term4d1)));
   fsSignal.Input().Add(fsVigor);
//--- Create Output
   FuzzyVariable *fvSignal=new FuzzyVariable("signal",min_tp,max_tp);
   fvSignal.Terms().Add(new FuzzyTerm("low_take", new TrapezoidMembershipFunction(out_term1a, out_term1b, out_term1c, out_term1d)));
   fvSignal.Terms().Add(new FuzzyTerm("mod_take", new TriangularMembershipFunction(out_term2a, out_term2b, out_term2c)));
   fvSignal.Terms().Add(new FuzzyTerm("med_take", new TriangularMembershipFunction(out_term3a, out_term3b, out_term3c)));
   fvSignal.Terms().Add(new FuzzyTerm("high_take", new TrapezoidMembershipFunction(out_term4a, out_term4b, out_term4c, out_term4d)));
   fsSignal.Output().Add(fvSignal);
//--- Create four Mamdani fuzzy rule
   MamdaniFuzzyRule *rule1 = fsSignal.ParseRule("if (trend is low) and (vigor is low) then signal is low_take");
   MamdaniFuzzyRule *rule2 = fsSignal.ParseRule("if (trend is moderate) and (vigor is medium) then signal is mod_take");
   MamdaniFuzzyRule *rule3 = fsSignal.ParseRule("if (trend is medium) and (vigor is high) then signal is med_take");
   MamdaniFuzzyRule *rule4 = fsSignal.ParseRule("if (trend is high) and (vigor is higher) then signal is high_take");
//--- Add four Mamdani fuzzy rule in system
   fsSignal.Rules().Add(rule1);
   fsSignal.Rules().Add(rule2);
   fsSignal.Rules().Add(rule3);
   fsSignal.Rules().Add(rule4);
//--- Set input value
   CList *in=new CList;
   Dictionary_Obj_Double *p_od_adx=new Dictionary_Obj_Double;
   Dictionary_Obj_Double *p_od_rvi=new Dictionary_Obj_Double;
   p_od_adx.SetAll(fsTrend,t);
   p_od_rvi.SetAll(fsVigor,v);
   in.Add(p_od_adx);
   in.Add(p_od_rvi);
//--- Get result
   CList *result;
   Dictionary_Obj_Double *p_od_out;
   result=fsSignal.Calculate(in);
   p_od_out=result.GetNodeAtIndex(0);
   res=NormalizeDouble(p_od_out.Value(),_Digits);
//---
   delete in;
   delete result;
   delete fsSignal;
   return res;
  }


Kommen wir nun zum letzten Block — "Hilfsfunktionen". Die Erste — tp_prc(double take) konvertiert den Wert von Take-Profit in Points in einen numerischen Wert im Format der Preise des Handelssymbols. Die zweite retourniert die Anzahl der Stellen des Handelssymbols.

//+------------------------------------------------------------------+
//| Funktion zur Bestimmung der Gewinnziele                          |
//+------------------------------------------------------------------+
double tp_prc(double take)
  {
   int tip;
   double opr,tp;
   take+=50;
   adx_di_plus=NormalizeDouble(iADX(_Symbol,PERIOD_CURRENT,adx_period,PRICE_CLOSE,MODE_PLUSDI,num_bar),_Digits);
   adx_di_minus=NormalizeDouble(iADX(_Symbol,PERIOD_CURRENT,adx_period,PRICE_CLOSE,MODE_MINUSDI,num_bar),_Digits);
//---
   if(adx_di_plus>adx_di_minus)
      tip=0;
   else if(adx_di_plus<adx_di_minus)
      tip=1;
//---
   switch(tip)
     {
      case 0:
         opr=Ask;
         break;
      case 1:
         opr=Bid;
         break;
     }
   if(MathMod(tip,2.0)==0.0)
     {
      tp=opr+take*Dig()*_Point;
     }
   else
     {
      tp=opr-take*Dig()*_Point;
     }
   return(tp);
  }
//+------------------------------------------------------------------+
//| Funktion, die die Zahl der Dezimalstelle liefert                 |
//+------------------------------------------------------------------+
int Dig()
  {
   return((_Digits==5 || _Digits==3 || _Digits==1)?10:1);
  }
//+------------------------------------------------------------------+

Ich möchte Sie noch besonders darauf hinweisen, dass auf die Richtigkeit der Einstellungen und die wiederholte Überprüfung der Korrektheit der Parameter der Fuzzy-Logik während des Testens zu achten ist. Ich empfehle auf ihren ursprünglichen grafischen Darstellungen Fig. 3, 5, 6 zu bauen, denn inkorrekte Werte können Fehler verursachen und zu einem falschen Verhalten des ganzen Systems führen. Seien Sie vorsichtig!

 

Schlussfolgerung

Fassen wir zusammen, was wie gelernt haben.

  • Im ersten Teil erstellten wir eine manuelle Handelsstrategie mit Fuzzy-Logik auf Basis einer strengen Formalisierung der Regeln dieser Strategie. Geprüft in den Stufen №1. — №3.
  • Dann erkannten wir, wo die strengen Formalisierungen der Kategorisierungen zu einem Nachteil wurden. In unserm Beispiel konnte ein Teil in der Strategie identifiziert werden, durch den für uns ein Markteintritt nicht genug Flexibilität hatte.
  • Weiters wurden klare Kategorien unter der Verwendung der unscharfen Mengen beschrieben, die so flexibler wurden. Jetzt, in der erweiterten Version, existiert nicht mehr nur ein Entweder-Oder, sondern graduelle Zugehörigkeiten.
  • Diese Strategie wurde durch einen Indikator, einer Textanzeige und einem Alarm realisiert. In diesem Artikel wurde die Anzeige in MQL4 realisiert.
Wir haben die Möglichkeit der Verbesserung der manuellen Handelsstrategie unter Verwendung der Theorie unscharfer Mengen betrachtet. Das Beispiel konnte uns detailliert zeigen, wie eine existierende Handelsstrategie durch die Fuzzy-Logik modifiziert und ergänzt wurde, um bestimmte Mängel zubeseitigen.

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

Beigefügte Dateien |
fuzzy_panel.mq4 (23.67 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (1)
Mike Redmer
Mike Redmer | 21 Sept. 2016 in 18:06
MetaQuotes Software Corp.:

Neuer Artikel Fuzzy-Logik für eine manuelle Handelsstrategie :

Autor: Alexander Fedosov

Hello Alexander,

i downloaded and installed your example, but did not get this running. the ADX and RVI do not have a signal. Do you have any suggestions?

Thanks

 Mike 

Universal Expert Advisor: Das Event-Modell und der Trading-Strategie Prototyp (Part 2) Universal Expert Advisor: Das Event-Modell und der Trading-Strategie Prototyp (Part 2)
Dieser Artikel führt die Serie der Publikationen eines universellen Expert-Advisors fort. Dieser Teil beschreibt ausführlich das originale Event-Modell, welches auf einer zentralisierten Datenverarbeitung basiert und bestimmt die Struktur der Basisklasse CStrategy dieser Trading-Engine.
Grafische Interfaces VII: Die Tabellen Controls (Kapitel 1) Grafische Interfaces VII: Die Tabellen Controls (Kapitel 1)
Der siebte Teil der Serie über die grafischen Interfaces des Metatraders, handelt von drei Tabellen-Typen: Text-Label, Edit-Box und gerenderte Tabellen. Ein weiteres Control, welches sehr oft gebraucht wird, ist das Tab, womit es Ihnen möglich ist, Gruppen von anderen Controls anzuzeigen und zu verstecken und somit sehr effektive und platzsparende Interfaces für ihre MQL Anwendung programmieren zu können.
Schutz vor Falschauslöser bei Handelsroboter Schutz vor Falschauslöser bei Handelsroboter
Die Rentabilität von Handelssystemen ist nicht nur durch die Logik und die Präzision der Analyse der Dynamik der Handelssymbole bestimmt, sondern auch durch die Qualität des Algorithmus' dieser Logik. Falsche Auslöser sind typisch für eine niedrige Qualität der eigentliche Logik eines Handelsroboters. Die Wege zur Lösung dieses speziellen Problems ist Thema dieses Artikels.
Welche Überprüfungen der Handelsroboter vor der Veröffentlichung in Market bestehen soll Welche Überprüfungen der Handelsroboter vor der Veröffentlichung in Market bestehen soll
Alle Markets Produkte vor der Veröffentlichung bestehen eine obligatorische vorläufige Überprüfung, um eine Standarte Qualität zu haben. In diesem Artikel werden wir von den häufigsten Fehlern erzählen, die die Hersteller in den Handelsrobotern und den technischen Indikatoren machen. Auch werden wir zeigen, wie man sein Produkt vor der Sendung in Market selbständig überprüfen soll.