English Русский 中文 Español 日本語 Português
Das Erstellen einer neuen Handelsstrategie und sich die Positionseröffnungen durch Indikatoren bestimmen lassen

Das Erstellen einer neuen Handelsstrategie und sich die Positionseröffnungen durch Indikatoren bestimmen lassen

MetaTrader 5Handelssysteme | 21 Dezember 2017, 08:42
1 359 0
Dmitriy Gizlyk
Dmitriy Gizlyk

Einführung

Es ist bekannt, dass nur 5% der Händler stabile Gewinne auf den Finanzmärkten erzielen, obwohl die alle 100% erreichen wollen. 

Um erfolgreich zu handeln, braucht man eine profitable Handelsstrategie. Themenbezogene Webseiten und Fachliteratur zum Thema Handel beschreiben Hunderte von verschiedenen Handelsstrategien. Eine detaillierte Interpretation der Signale ist für allen Indikatoren erhältlich, aber die Statistik bleibt unverändert: Die 5% sind weder zu 100%, nicht einmal zu 10% geworden. Ideologen des Handels machen die Instabilität des Marktes verantwortlich, was zur Folge hat, dass frühere profitable Strategien auf einmal an Wirksamkeit verlieren.

In meinem vorherigen Artikel habe ich bereits über die Bestimmung der Eröffnungen durch Indikatoren geschrieben und ein Beispiel für die Verbesserung einer bestehenden Strategie gezeigt. Jetzt schlage ich vor, eine individuelle Strategie "auf einem leeren Blatt" und der angegebenen Technologie zu erstellen. Dies wird uns erlauben, die Indikatoren mit einem "ganz neuen Blick" zu betrachten, eigene Muster für Indikatoren zu sammeln und ihre Signale zu überdenken. Die Anwendung der vorgeschlagenen Technologie impliziert einen kreativen Ansatz zur Interpretation der Signale von Indikatoren, der es jedem Benutzer ermöglicht, eine eigene, einzigartige Strategie zu entwickeln.

1. Erstellung eines Modells für Tests und Analysen

Das erste, was wir in einem Handelsterminal sehen, ist eine kontinuierliche Kursentwicklung. Möglicherweise könnten wir, nachdem zu irgendeinem Zeitpunkt eine Position eröffnete wurde, einen Profit erzielen. Aber wie können wir erkennen, wohin und wie stark der Preis sich im nächsten Moment bewegt? Auf diese Frage versuchen Händler mit der technischen und fundamentalen Analysen eine Antwort zu finden. Für die Durchführung der technischen Analyse werden immer wieder die verschiedensten Indikatoren neu erfunden oder verbessert. Die Neuheit liegt hier in der Interpretation dieser Indikatorensignale, die sich von den üblichen unterscheiden können.

Die Methode, die Eröffnung sich von den Indikatoren bestimmen zu lassen, impliziert somit den Vergleich von eröffneten Positionen mit Indikatorwerten. Noch einmal, theoretisch, könnten wir jederzeit Profit erzielen. Auf der Grundlage dieser Eingangsdaten öffnen wir zu Beginn jeder bar zwei bidirektionale Positionen mit den festgelegten Parametern. Dann analysieren wir, wie der Profit jeder Position von den Indikatorwerten abhängt.

Um dieses Problem zu bewältigen, müssen wir ein paar Dinge vorbereiten.

1.1. Erstellen einer Klasse für virtuelle Aufträge

Es wird ein Netting-Konto verwendet. Um bidirektionale Aufträge zu eröffnen, werde ich daher virtuelle Aufträge erstellen, die nicht vom Terminal (je nach Kontoeinstellungen), sondern vom Expert Advisor verfolgt werden. Dazu wird die Klasse CDeal erstellt. Bei der Initialisierung wird einer Klasseninstanz übergeben: Symbolname, Positionstyp, Eröffnungszeit und Preis, sowie StopLoss und TakeProfit. Das Positionsvolumen wird bewusst weggelassen, da es hier nicht von Interesse ist. Das Wichtigste für uns ist die Preisbewegung, deshalb werden Gewinn und Verlust in 'points' anstatt in Geldbeträgen berechnet.

Der Vollständigkeit halber wurde die Klasse mit folgenden Funktionen zum Status versehen:

  • IsClosed — Rückgabe eines booleschen Wertes zurück, je nachdem die Position geschlossen ist oder nicht;
  • Type — Rückgabe des Typs der Position;
  • GetProfit — Rückgabe des Gewinns einer geschlossenen Position (Verluste sind negative Werte);
  • GetTime — Rückgabe der Eröffnungszeit.

class CDeal          :  public CObject
  {
private:
   string               s_Symbol;
   datetime             dt_OpenTime;         // Time of open position
   double               d_OpenPrice;         // Price of opened position
   double               d_SL_Price;          // Stop Loss of position
   double               d_TP_Price;          // Take Profit of position
   ENUM_POSITION_TYPE   e_Direct;            // Direct of opened position
   double               d_ClosePrice;        // Price of close position
   int                  i_Profit;            // Profit of position in pips
//---
   double               d_Point;
   
public:
                     CDeal(string symbol, ENUM_POSITION_TYPE type,datetime time,double open_price,double sl_price, double tp_price);
                    ~CDeal();
   //--- Check status
   bool              IsClosed(void);
   ENUM_POSITION_TYPE Type(void)    {  return e_Direct;    }
   double            GetProfit(void);
   datetime          GetTime(void)  {  return dt_OpenTime;  }
   //---
   void              Tick(void);
  };

Eingehende Ticks werden in der Funktion Tick verarbeitet, die eine Position durch Stop-Loss oder Take-Profit überprüft und ggf. schließt und den kumulierten Gewinn speichert.

void CDeal::Tick(void)
  {
   if(d_ClosePrice>0)
      return;
   double price=0;
   switch(e_Direct)
     {
      case POSITION_TYPE_BUY:
        price=SymbolInfoDouble(s_Symbol,SYMBOL_BID);
        if(d_SL_Price>0 && d_SL_Price>=price)
          {
           d_ClosePrice=price;
           i_Profit=(int)((d_ClosePrice-d_OpenPrice)/d_Point);
          }
        else
          {
           if(d_TP_Price>0 && d_TP_Price<=price)
             {
              d_ClosePrice=price;
              i_Profit=(int)((d_ClosePrice-d_OpenPrice)/d_Point);
             }
          }
        break;
      case POSITION_TYPE_SELL:
        price=SymbolInfoDouble(s_Symbol,SYMBOL_ASK);
        if(d_SL_Price>0 && d_SL_Price<=price)
          {
           d_ClosePrice=price;
           i_Profit=(int)((d_OpenPrice-d_ClosePrice)/d_Point);
          }
        else
          {
           if(d_TP_Price>0 && d_TP_Price>=price)
             {
              d_ClosePrice=price;
              i_Profit=(int)((d_OpenPrice-d_ClosePrice)/d_Point);
             }
          }
        break;
     }
  }

1.2. Erstellen einer Klasse für die Indikatoren

Um die Werte der Indikatoren zu speichern und zu analysieren, habe ich die im vorherigen Artikel beschriebenen Klassen verwendet. Außerdem habe ich hier die Klasse CDealsToIndicators erstellt, die alle Indikatorklassen verallgemeinert. Sie speichert die Arrays der Indikatorklassen und organisiert deren Funktionieren.

class CDealsToIndicators
  {
private:
   CADX              *ADX[];
   CAlligator        *Alligator[];
   COneBufferArray   *OneBuffer[];
   CMACD             *MACD[];
   CStaticOneBuffer  *OneBufferStatic[];
   CStaticMACD       *MACD_Static[];
   CStaticADX        *ADX_Static[];
   CStaticAlligator  *Alligator_Static[];
   
   template<typename T>
   void              CleareArray(T *&array[]);

public:
                     CDealsToIndicators();
                    ~CDealsToIndicators();
   //---
   bool              AddADX(string symbol, ENUM_TIMEFRAMES timeframe, int period, string name);
   bool              AddADX(string symbol, ENUM_TIMEFRAMES timeframe, int period, string name, int &handle);
   bool              AddAlligator(string symbol,ENUM_TIMEFRAMES timeframe,uint jaw_period, uint jaw_shift, uint teeth_period, uint teeth_shift, uint lips_period, uint lips_shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE price, string name);
   bool              AddAlligator(string symbol,ENUM_TIMEFRAMES timeframe,uint jaw_period, uint jaw_shift, uint teeth_period, uint teeth_shift, uint lips_period, uint lips_shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE price, string name, int &handle);
   bool              AddMACD(string symbol, ENUM_TIMEFRAMES timeframe, uint fast_ema, uint slow_ema, uint signal, ENUM_APPLIED_PRICE applied_price, string name);
   bool              AddMACD(string symbol, ENUM_TIMEFRAMES timeframe, uint fast_ema, uint slow_ema, uint signal, ENUM_APPLIED_PRICE applied_price, string name, int &handle);
   bool              AddOneBuffer(int handle, string name);
   //---
   bool              SaveNewValues(long ticket);
   //---
   bool              Static(CArrayObj *deals);
  };

1.3. Erstellen des Expert Advisors für die Tests

Alles ist vorbereitet. Fahren wir fort mit dem Erstellen des EAs, der im Strategietester laufen soll. Zuerst definieren wir die Liste der zu verwendeten Indikator mit ihren Parametern. Beispielsweise wurden folgende Indikatoren ausgewählt:

  • ADX;
  • Alligator;
  • CCI;
  • Chaikin;
  • Force Index;
  • MACD.

Für jeden werden drei Sätze von Parametern für 3 Zeitrahmen erstellt.

Stop-Loss und Take-Profit werden an den ATR gebunden und mittels des Verhältnisses von Gewinn und Risiko ermittelt.

//--- Eingabeparameter
input double            Reward_Risk    =  1.0;
input int               ATR_Period     =  288;
input ENUM_TIMEFRAMES   TimeFrame1     =  PERIOD_M5;
input ENUM_TIMEFRAMES   TimeFrame2     =  PERIOD_H1;
input ENUM_TIMEFRAMES   TimeFrame3     =  PERIOD_D1;
input string            s1                =  "ADX"                ;  //---
input uint              ADX_Period1       =  14                   ;
input uint              ADX_Period2       =  28                   ;
input uint              ADX_Period3       =  56                   ;
input string            s2                =  "Alligator"          ;  //---
input uint              JAW_Period1       =  13                   ;
input uint              JAW_Shift1        =  8                    ;
input uint              TEETH_Period1     =  8                    ;
input uint              TEETH_Shift1      =  5                    ;
input uint              LIPS_Period1      =  5                    ;
input uint              LIPS_Shift1       =  3                    ;
input uint              JAW_Period2       =  26                   ;
input uint              JAW_Shift2        =  16                   ;
input uint              TEETH_Period2     =  16                   ;
input uint              TEETH_Shift2      =  10                   ;
input uint              LIPS_Period2      =  10                   ;
input uint              LIPS_Shift2       =  6                    ;
input uint              JAW_Period3       =  42                   ;
input uint              JAW_Shift3        =  32                   ;
input uint              TEETH_Period3     =  32                   ;
input uint              TEETH_Shift3      =  20                   ;
input uint              LIPS_Period3      =  20                   ;
input uint              LIPS_Shift3       =  12                   ;
input ENUM_MA_METHOD    Alligator_Method  =  MODE_SMMA            ;
input ENUM_APPLIED_PRICE Alligator_Price  =  PRICE_MEDIAN         ;
input string            s5                =  "CCI"                ;  //---
input uint              CCI_Period1       =  14                   ;
input uint              CCI_Period2       =  28                   ;
input uint              CCI_Period3       =  56                   ;
input ENUM_APPLIED_PRICE CCI_Price        =  PRICE_TYPICAL        ;
input string            s6                =  "Chaikin"            ;  //---
input uint              Ch_Fast_Period1   =  3                    ;
input uint              Ch_Slow_Period1   =  14                   ;
input uint              Ch_Fast_Period2   =  6                    ;
input uint              Ch_Slow_Period2   =  28                   ;
input uint              Ch_Fast_Period3   =  12                   ;
input uint              Ch_Slow_Period3   =  56                   ;
input ENUM_MA_METHOD    Ch_Method         =  MODE_EMA             ;
input ENUM_APPLIED_VOLUME Ch_Volume       =  VOLUME_TICK          ;
input string            s7                =  "Force Index"        ;  //---
input uint              Force_Period1     =  14                   ;
input uint              Force_Period2     =  28                   ;
input uint              Force_Period3     =  56                   ;
input ENUM_MA_METHOD    Force_Method      =  MODE_SMA             ;
input ENUM_APPLIED_VOLUME Force_Volume    =  VOLUME_TICK          ;
input string            s8                =  "MACD"               ;  //---
input uint              MACD_Fast1        =  12                   ;
input uint              MACD_Slow1        =  26                   ;
input uint              MACD_Signal1      =  9                    ;
input uint              MACD_Fast2        =  24                   ;
input uint              MACD_Slow2        =  52                   ;
input uint              MACD_Signal2      =  18                   ;
input uint              MACD_Fast3        =  48                   ;
input uint              MACD_Slow3        =  104                  ;
input uint              MACD_Signal3      =  36                   ;
input ENUM_APPLIED_PRICE MACD_Price       =  PRICE_CLOSE          ;

Im Block der globalen Variablen deklarieren wir:

  • Das Array zum Speichern der Klassen der Positionen "Deals",
  • Für die Arbeit mit den Indikatoren die Instanz "IndicatorsStatic",
  • Die Variable für das Handle zum ATR,
  • Zwei Hilfsvariablen für die Zeit der letzten, bearbeiteten Bar (last_bar) und für die letzte geschlossene Position (last_closed_deal). Die letztere wird benötigt um nicht bei jedem Tick erneut durch alle geschlossenen Positionen zu gehen.

In der Funktion OnInit werden diese globalen Variablen und die benötigten Indikatoren initialisiert.

int OnInit()
  {
//---
   last_bar=0;
   last_closed_deal=0;
//---
   Deals =  new CArrayObj();
   if(CheckPointer(Deals)==POINTER_INVALID)
      return INIT_FAILED;
//---
   IndicatorsStatic  =  new CDealsToIndicators();
   if(CheckPointer(IndicatorsStatic)==POINTER_INVALID)
      return INIT_FAILED;
//---
   atr=iATR(_Symbol,TimeFrame1,ATR_Period);
   if(atr==INVALID_HANDLE)
      return INIT_FAILED;
//---
   AddIndicators(TimeFrame1);
   AddIndicators(TimeFrame2);
   AddIndicators(TimeFrame3);
//---
   return(INIT_SUCCEEDED);
  }

Es werden dieselben Sätze der Indikatoren für alle drei Zeitrahmen verwendet. Darum ist es sinnvoll, die Initialisierung der Klassen der Indikatoren von einer eigenen Funktion durchführen zu lassen. Der Zeitrahmen wird als Parameter übergeben.

bool AddIndicators(ENUM_TIMEFRAMES timeframe)
  {
   if(CheckPointer(IndicatorsStatic)==POINTER_INVALID)
     {
      IndicatorsStatic  =  new CDealsToIndicators();
      if(CheckPointer(IndicatorsStatic)==POINTER_INVALID)
         return false;
     }
   string tf_name=StringSubstr(EnumToString(timeframe),7);
   string name="ADX("+IntegerToString(ADX_Period1)+") "+tf_name;
   if(!IndicatorsStatic.AddADX(_Symbol, timeframe, ADX_Period1, name))
      return false;
   name="ADX("+IntegerToString(ADX_Period2)+") "+tf_name;
   if(!IndicatorsStatic.AddADX(_Symbol, timeframe, ADX_Period2, name))
      return false;
   name="ADX("+IntegerToString(ADX_Period3)+") "+tf_name;
   if(!IndicatorsStatic.AddADX(_Symbol, timeframe, ADX_Period3, name))
      return false;
   name="Alligator("+IntegerToString(JAW_Period1)+","+IntegerToString(TEETH_Period1)+","+IntegerToString(LIPS_Period1)+") "+tf_name;
   if(!IndicatorsStatic.AddAlligator(_Symbol, timeframe, JAW_Period1, JAW_Shift1, TEETH_Period1, TEETH_Shift1, LIPS_Period1, LIPS_Shift1, Alligator_Method, Alligator_Price, name))
      return false;
   name="Alligator("+IntegerToString(JAW_Period2)+","+IntegerToString(TEETH_Period2)+","+IntegerToString(LIPS_Period2)+") "+tf_name;
   if(!IndicatorsStatic.AddAlligator(_Symbol, timeframe, JAW_Period2, JAW_Shift2, TEETH_Period2, TEETH_Shift2, LIPS_Period2, LIPS_Shift2, Alligator_Method, Alligator_Price, name))
      return false;
   name="Alligator("+IntegerToString(JAW_Period3)+","+IntegerToString(TEETH_Period3)+","+IntegerToString(LIPS_Period3)+") "+tf_name;
   if(!IndicatorsStatic.AddAlligator(_Symbol, timeframe, JAW_Period3, JAW_Shift3, TEETH_Period3, TEETH_Shift3, LIPS_Period3, LIPS_Shift3, Alligator_Method, Alligator_Price, name))
      return false;
   name="MACD("+IntegerToString(MACD_Fast1)+","+IntegerToString(MACD_Slow1)+","+IntegerToString(MACD_Signal1)+") "+tf_name;
   if(!IndicatorsStatic.AddMACD(_Symbol, timeframe, MACD_Fast1, MACD_Slow1, MACD_Signal1, MACD_Price, name))
      return false;
   name="MACD("+IntegerToString(MACD_Fast2)+","+IntegerToString(MACD_Slow2)+","+IntegerToString(MACD_Signal2)+") "+tf_name;
   if(!IndicatorsStatic.AddMACD(_Symbol, timeframe, MACD_Fast2, MACD_Slow2, MACD_Signal2, MACD_Price, name))
      return false;
   name="MACD("+IntegerToString(MACD_Fast3)+","+IntegerToString(MACD_Slow3)+","+IntegerToString(MACD_Signal3)+") "+tf_name;
   if(!IndicatorsStatic.AddMACD(_Symbol, timeframe, MACD_Fast3, MACD_Slow3, MACD_Signal3, MACD_Price, name))
      return false;
   name="CCI("+IntegerToString(CCI_Period1)+") "+tf_name;
   int handle = iCCI(_Symbol, timeframe, CCI_Period1, CCI_Price);
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   name="CCI("+IntegerToString(CCI_Period2)+") "+tf_name;
   handle = iCCI(_Symbol, timeframe, CCI_Period2, CCI_Price);
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iCCI(_Symbol, timeframe, CCI_Period3, CCI_Price);
   name="CCI("+IntegerToString(CCI_Period3)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iForce(_Symbol, timeframe, Force_Period1, Force_Method, Force_Volume);
   name="Force("+IntegerToString(Force_Period1)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iForce(_Symbol, timeframe, Force_Period2, Force_Method, Force_Volume);
   name="Force("+IntegerToString(Force_Period2)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iForce(_Symbol, timeframe, Force_Period3, Force_Method, Force_Volume);
   name="Force("+IntegerToString(Force_Period3)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   name="CHO("+IntegerToString(Ch_Slow_Period1)+","+IntegerToString(Ch_Fast_Period1)+") "+tf_name;
   handle = iChaikin(_Symbol, timeframe, Ch_Fast_Period1, Ch_Slow_Period1, Ch_Method, Ch_Volume);
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iChaikin(_Symbol, timeframe, Ch_Fast_Period2, Ch_Slow_Period2, Ch_Method, Ch_Volume);
   name="CHO("+IntegerToString(Ch_Slow_Period2)+","+IntegerToString(Ch_Fast_Period2)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iChaikin(_Symbol, timeframe, Ch_Fast_Period3, Ch_Slow_Period3, Ch_Method, Ch_Volume);
   name="CHO("+IntegerToString(Ch_Slow_Period3)+","+IntegerToString(Ch_Fast_Period3)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   return true;
  }

Die in OnTick ausgeführten Operationen können in zwei Blöcke unterteilt werden: Überprüfen der offenen Positionen und Eröffnen neuer Positionen.

Der erste Block der Operationen wird bei jedem Tick ausgeführt. Darin wird für jede offenen Positionen im Array die Funktion Tick ausgeführt. Es wird das Schließen der Position durch Stop-Loss oder Take-Profit geprüft und, falls notwendig, wird eine Position zum aktuellen Kurs, um den Gewinn zu sichern, geschlossen. Um bereits geschlossene Positionen nicht erneut zu überprüfen, wird in der Variable last_closed_deal die Nummer der letzten Position gespeichert, die der ersten, noch offenen Position vorausgeht. 

void OnTick()
  {
//---
   int total=Deals.Total();
   CDeal *deal;
   bool found=false;
   for(int i=last_closed_deal;i<total;i++)
     {
      deal  =  Deals.At(i);
      if(CheckPointer(deal)==POINTER_INVALID)
         continue;
      if(!found)
        {
         if(deal.IsClosed())
           {
            last_closed_deal=i;
            continue;
           }
         else
            found=true;
        }
      deal.Tick();
     }

Der zweite Block beginnt mit der Überprüfung des Auftretens neuer Bars. Bei einer neuen Bar werden die Werte des ATR der gerade geschlossenen Bar abgefragt und die Stop-Loss und Take-Profit entsprechend den eingestellten Parametern angepasst und die virtuellen Positionen eröffnet. Für jede Position speichern wir die Indikatorwerte durch den Aufruf der Funktion SaveNewValues der Klasse für die Arbeit mit Indikatoren.

//---
   datetime cur_bar=(datetime)SeriesInfoInteger(_Symbol,PERIOD_CURRENT,SERIES_LASTBAR_DATE);
   datetime cur_time=TimeCurrent();
   if(cur_bar==last_bar || (cur_time-cur_bar)>10)
      return;
   double atrs[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0)
      return;

   last_bar=cur_bar;
   double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
   double stops=MathMax(2*atrs[0],SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)*_Point);
   double sl=NormalizeDouble(stops,_Digits);
   double tp=NormalizeDouble(Reward_Risk*(stops+ask-bid),_Digits);
   deal  =  new CDeal(_Symbol,POSITION_TYPE_BUY,TimeCurrent(),ask,bid-sl,ask+tp);
   if(CheckPointer(deal)!=POINTER_INVALID)
      if(Deals.Add(deal))
         IndicatorsStatic.SaveNewValues(Deals.Total()-1);
   deal  =  new CDeal(_Symbol,POSITION_TYPE_SELL,TimeCurrent(),bid,ask+sl,bid-tp);
   if(CheckPointer(deal)!=POINTER_INVALID)
      if(Deals.Add(deal))
         IndicatorsStatic.SaveNewValues(Deals.Total()-1);
   return;
  }

In OnTester sammeln wir die Ergebnisse des Testlaufs und erstellen die Diagramme für die Analyse. Dazu wird die Funktion "Static" der Klasse für das Arbeiten mit den Indikatoren auf.

Es sollte nicht vergessen werden, den Speicher in der Funktion OnDeinit wieder freizugeben!

Der vollständige Code des EA und der Klassen findet sich im Anhang.

2. Analyse der Testergebnisse

So, der EA ist erstellt. Definieren wir nun den Zeitraum der Analyse. Bei der Wahl des Zeitraumes sollte berücksichtigt werden, dass sie lang genug sein sollte, um die Objektivität der Analyse zu gewährleisten. Und noch eine Anforderung an den Zeitraum: Es sollte nicht nur Bewegungen in Richtung sondern mehrere geben dazu auch Seitwärtsbewegungen. Dieser Ansatz wird eine Handelsstrategie schaffen, die in Zeiten einer Bewegung Gewinne generieren kann. Im vorliegenden Beispiel wurde für den EURUSD der Zeitraum vom 01.01.2016 bis zum 01.01.2017 analysiert.

TestphaseTestparameter

Da unser Prozess iterativ ist, würde ich nach dem Speichern aller notwendigen Parameter des Test-Experten empfehlen, die Set-Datei der Parameter für die weitere Arbeit zu speichern.

Jede Testphase wird in 2 Durchläufen mit einem Verhältnis von Gewinn/Risiko von 1/1 und 15/1 durchgeführt. Im ersten Durchlauf schätzen wir die Wahrscheinlichkeit einer Richtung der Preisbewegung, und im zweiten Durchlauf - die Kraft der Bewegung.

Der Expert Advisor zeigt viele Diagramme für die Analyse an, daher sind sie nicht vollständig in dem Artikel aufgeführt - alle Berichte befinden sich im Anhang. Hier werde ich nur jene Diagramme zeigen, in denen Entscheidungen über die Verwendung von Indikatoren in der neuen Strategie getroffen wurden.

2.1. Stufe eins

Wie zu erwarten, zeigte die erste Testphase keine eindeutigen profitablen Bereiche. Gleichzeitig sollte man aber auch auf die den Indikator Force Index achten. Im Zeitrahmen von M5 sinkt die Abhängigkeit der Handelsgewinne von den Indikatorwerten gegen Null. Die Bedeutung dieser Beobachtung wird durch die Tatsache belegt, dass dieses Phänomen in analytischen Indikatordiagrammen mit allen für die Prüfung verwendeten Parametern auftritt. Für unser Muster wählen wir Parameter mit dem deutlichstem Charakter (maximaler Drawdown).

Die Analysediagramme des Force Index mit einer Periodenlänge von 56 und dem Zeitrahmen M5

Vergrößern Sie den Maßstab des analysierten Diagramms. Wir sehen einen Effekt dieses Faktors im Bereich von -0,01 bis 0,01. Das beobachtete Phänomen gilt gleichermaßen für Kauf- und Verkaufstransaktionen.

Diese Beobachtung kann durch die fehlende Volatilität des beobachteten Wertebereichs erklärt werden. Wir sehen für unsere Strategie das Verbot der Eröffnung von Positionen in diesem Bereich.

Die Gewinnabhängigkeit des Force Index nahe Null.

Übernehmen wir diesen Filter in unseren EA. Dazu ergänzen wir als erstes eine globale Variable für das Handle dieses Indikators.

int                  force;

Da der Indikator, den wir als Filter benötigen, bereits im Expert Advisor verwendet wird, starten wir ihn nicht mehr auf dem Chart. Wir weisen einfach das Handle unserer globale Variablen in der Funktion AddIndicators zu. Vergessen wir aber nicht, dass diese Funktion dreimal aufgerufen wird, um die Indikatoren in verschiedenen Zeitrahmen zu initialisieren. Daher müssen wir vor der Zuweisung des Handles des Indikators die Übereinstimmung der Zeitrahmen überprüfen.

   handle = iForce(_Symbol, timeframe, Force_Period3, Force_Method, Force_Volume);
   if(timeframe==TimeFrame1)
      force=handle;

Fügen wir nun den Filter direkt zur Funktion OnTick hinzu. Es darf nicht vergessen werden, dass die Daten in der Funktion zum Erstellen eines analytischen Diagramms gerundet wurden. Daher müssen wir beim Filtern der Positionen auch die Indikatorwerte runden.

   double atrs[];
   double force_data[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0 || CopyBuffer(force,0,1,1,force_data)<=0)
      return;      // Some error of load indicator's data

   last_bar=cur_bar;
   double d_Step=_Point*1000;
   if(MathAbs(NormalizeDouble(force_data[0]/d_Step,0)*d_Step)<=0.01)
      return;    // Filtered by Force Index

Der vollständige Code des EAs findet sich im Anhang des Artikels.

Nach dem Hinzufügen des Filters zum Expert Advisor führen wir die zweite Testphase durch. Vergessen wir vor dem Test nicht, die zuvor gespeicherten Einstellungen zu laden.

2.2. Stufe zwei

Nachdem ich den Expert Advisor erneut getestet habe, habe ich auf den MACD-Indikator geachtet. Die profitable Zonen zeigen sich auf dem Chart.

Das Diagramm der Gewinnabhängigkeit vom Histogramm des MACD.

In der Grafik mit einem Verhältnis von Gewinn und Risiko von 15/1 sind diese Zonen ausgeprägter, was auf ein Signalpotential in diesen Bereichen hinweisen kann.

Das Diagramm der Gewinnabhängigkeit des Histogramms des MACD (Gewinn/Risiko = 15/1)

Diesen Filter sollten wir dem Code unseres Expert Advisors hinzufügen. Das Verfahren zum Hinzufügen dieses Filters ist ähnlich, wie es in der ersten Stufe beschrieben wurde.

Mit der globalen Variablen:

int                  macd;

Und der Funktion AddIndicators:

   name="MACD("+IntegerToString(MACD_Fast2)+","+IntegerToString(MACD_Slow2)+","+IntegerToString(MACD_Signal2)+") "+tf_name;
   if(timeframe==TimeFrame1)
     {
      if(!IndicatorsStatic.AddMACD(_Symbol, timeframe, MACD_Fast2, MACD_Slow2, MACD_Signal2, MACD_Price, name, macd))
         return false;
     }
   else
     {
      if(!IndicatorsStatic.AddMACD(_Symbol, timeframe, MACD_Fast2, MACD_Slow2, MACD_Signal2, MACD_Price, name))
         return false;
     }

In der Funktion OnTick:

   double macd_data[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0 || CopyBuffer(force,0,1,1,force_data)<=0 || CopyBuffer(macd,0,1,1,macd_data)<=0)
      return;

und

   double macd_Step=_Point*50;
   macd_data[0]=NormalizeDouble(macd_data[0]/macd_Step,0)*macd_Step;
   if(macd_data[0]>=0.0015 && macd_data[0]<=0.0035)
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_BUY,TimeCurrent(),ask,bid-sl,ask+tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }
   if(macd_data[0]<=(-0.0015) && macd_data[0]>=(-0.0035))
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_SELL,TimeCurrent(),bid,ask+sl,bid-tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }

Nachdem Sie den Filter hinzugefügt haben, wechseln Sie zur dritten Stufe.

2.3. Stufe drei

In der dritten Stufe wandte ich mich dem Chaikin-Oszillator zu. Auf den analytischen Diagrammen des Oszillators im Zeitrahmen D1 sehen wir einen Gewinnanstieg bei Kaufposition, wenn die Werte fallen und bei steigenden Werten steigt auch der Gewinn der Verkaufspositionen.

Die Gewinnabhängigkeit des Chaikin-Oszillators

Die Beobachtungen bestätigen sich auch im Diagramm mit einen Gewinn/Risiko-Verhältnis von 15/1.

Die Gewinnabhängigkeit des Chaikin-Oszillators.

Fügen wir unsere Beobachtungen zum Code unseres EAs.

Mit der globalen Variablen:

int                  cho;

Und der Funktion AddIndicators:

   handle = iChaikin(_Symbol, timeframe, Ch_Fast_Period2, Ch_Slow_Period2, Ch_Method, Ch_Volume);
   name="CHO("+IntegerToString(Ch_Slow_Period2)+","+IntegerToString(Ch_Fast_Period2)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   if(timeframe==TimeFrame3)
      cho=handle;

In der Funktion OnTick:

   double cho_data[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0 || CopyBuffer(force,0,1,1,force_data)<=0 || CopyBuffer(macd,0,1,1,macd_data)<=0
      || CopyBuffer(cho,0,1,2,cho_data)<2)
      return;

und

   if(macd_data[0]>=0.0015 && macd_data[0]<=0.0035 && (cho_data[1]-cho_data[0])<0)
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_BUY,TimeCurrent(),ask,bid-sl,ask+tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }
   if(macd_data[0]<=(-0.0015) && macd_data[0]>=(-0.0035) && (cho_data[1]-cho_data[0])>0)
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_SELL,TimeCurrent(),bid,ask+sl,bid-tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }

Kommen wir nun zur nächsten Stufe.

2.4. Stufe vier

Nach erneuten Tests des EAs drängte sich wieder der Zeitrahmen D1 in den Vordergrund. Diesmal aber der Indikator CCI. Seine analytischen Diagramme zeigten ein Gewinnwachstum bei Verkaufsposition, wenn die Indikatorwerte fallen und und ein Gewinnwachstum der Kaufposition, wenn sie steigen. Dieser Trend kann in in allen drei Testperioden beobachtet werden, der maximale Gewinn wurde jedoch mit der Periodenlänge 14, dem Standard dieses Oszillators, erreicht.

Die Gewinnabhängigkeit des CCI.

Das Diagramm zur Analyse nach dem Test mit dem Verhältnis Gewinn/Risiko = 15/1 bestätigt unsere Beobachtung.

Die Gewinnabhängigkeit des CCI.

Fügen wir diese Beobachtung auch zum Code unseres EAs.

Mit der globalen Variablen:

int                  cci;

Und der Funktion AddIndicators:

   name="CCI("+IntegerToString(CCI_Period1)+") "+tf_name;
   int handle = iCCI(_Symbol, timeframe, CCI_Period1, CCI_Price);
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   if(timeframe==TimeFrame3)
      cci=handle;

In der Funktion OnTick:

   double cci_data[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0 || CopyBuffer(force,0,1,1,force_data)<=0 || CopyBuffer(macd,0,1,1,macd_data)<=0
      || CopyBuffer(cho,0,1,2,cho_data)<2 || CopyBuffer(cci,0,1,2,cci_data)<2)
      return;

und

   if(macd_data[0]>=0.0015 && macd_data[0]<=0.0035 && (cho_data[1]-cho_data[0])<0 && (cci_data[1]-cci_data[0])>0)
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_BUY,TimeCurrent(),ask,bid-sl,ask+tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }
   if(macd_data[0]<=(-0.0015) && macd_data[0]>=(-0.0035) && (cho_data[1]-cho_data[0])>0 && (cci_data[1]-cci_data[0])<0)
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_SELL,TimeCurrent(),bid,ask+sl,bid-tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }

Der vollständige Code der EAs aus allen Stufen findet sich im Anhang des Artikels.

3. Erstellen und Testen des Expert Advisors für ausgewählte Signale

Perfektion kennt keine Grenzen, man kann immer noch tiefer analysieren und noch mehr Filter hinzufügen, um den Profitfaktor der Strategie noch weiter zu erhöhen. Aber ich glaube, dass die vier vorgestellten Stufen für eine Demonstration der Technologie ausreichen. Im nächsten Schritt erstellen wir einen einfachen EA zur Überprüfung unserer Strategie im Tester. Dies wird es uns ermöglichen, den Gewinn und die Drawdowns unserer Strategie zu beurteilen, sowie die Schwankungen der Salden niedrig zu halten.

In der Strategie verwendeten wir vier Indikatoren, um eine Entscheidung über den Handel zu treffen, und den ATR, um Stop-Loss und Take-Profit zu setzen. Folglich sollten wir in den Eingabeparametern alle Variablen auflisten, die die Indikatoren benötigen. In diesem Stadium werden wir kein Geldmanagement durchführen, alle Positionen erhalten dasselbe, konstante Volumen.

//--- Eingabeparameter
input double            Lot               =  0.1                  ;
input double            Reward_Risk       =  15.0                 ;
input ENUM_TIMEFRAMES   ATR_TimeFrame     =  PERIOD_M5            ;
input int               ATR_Period        =  288                  ;
input string            s1                =  "CCI"                ;  //---
input ENUM_TIMEFRAMES   CCI_TimeFrame     =  PERIOD_D1            ;
input uint              CCI_Period        =  14                   ;
input ENUM_APPLIED_PRICE CCI_Price        =  PRICE_TYPICAL        ;
input string            s2                =  "Chaikin"            ;  //---
input ENUM_TIMEFRAMES   Ch_TimeFrame      =  PERIOD_D1            ;
input uint              Ch_Fast_Period    =  6                    ;
input uint              Ch_Slow_Period    =  28                   ;
input ENUM_MA_METHOD    Ch_Method         =  MODE_EMA             ;
input ENUM_APPLIED_VOLUME Ch_Volume       =  VOLUME_TICK          ;
input string            s3                =  "Force Index"        ;  //---
input ENUM_TIMEFRAMES   Force_TimeFrame   =  PERIOD_M5            ;
input uint              Force_Period      =  56                   ;
input ENUM_MA_METHOD    Force_Method      =  MODE_SMA             ;
input ENUM_APPLIED_VOLUME Force_Volume    =  VOLUME_TICK          ;
input string            s4                =  "MACD"               ;  //---
input ENUM_TIMEFRAMES   MACD_TimeFrame    =  PERIOD_M5            ;
input uint              MACD_Fast         =  12                   ;
input uint              MACD_Slow         =  26                   ;
input uint              MACD_Signal       =  9                    ;
input ENUM_APPLIED_PRICE MACD_Price       =  PRICE_CLOSE          ;

Als globale Variable deklarieren wir:

  • eine Instanz der Klasse für die Durchführung des Handels,
  • Variablen zur Speicherung der Handles zu den verwendeten Indikatoren,
  • Hilfsvariablen zum Speichern der Daten der zuletzt bearbeiteten Bar und der letzten Position,
  • Variablen zum Speichern des größten und des kleinsten Zeitrahmens.

In der Funktion OnInit werden die Indikatoren und die Variablen initialisiert.

int OnInit()
  {
//---
   last_bar=0;
   last_deal=0;
//---
   atr=iATR(_Symbol,ATR_TimeFrame,ATR_Period);
   if(atr==INVALID_HANDLE)
      return INIT_FAILED;
//---
   force=iForce(_Symbol,Force_TimeFrame,Force_Period,Force_Method,Force_Volume);
   if(force==INVALID_HANDLE)
      return INIT_FAILED;
//---
   macd=iMACD(_Symbol,MACD_TimeFrame,MACD_Fast,MACD_Slow,MACD_Signal,MACD_Price);
   if(macd==INVALID_HANDLE)
      return INIT_FAILED;
//---
   cho=iChaikin(_Symbol,Ch_TimeFrame,Ch_Fast_Period,Ch_Slow_Period,Ch_Method,Ch_Volume);
   if(cho==INVALID_HANDLE)
      return INIT_FAILED;
//---
   cci=iCCI(_Symbol,CCI_TimeFrame,CCI_Period,CCI_Price);
   if(cci==INVALID_HANDLE)
      return INIT_FAILED;
//---
   MaxPeriod=fmax(Force_TimeFrame,MACD_TimeFrame);
   MaxPeriod=fmax(MaxPeriod,Ch_TimeFrame);
   MaxPeriod=fmax(MaxPeriod,CCI_TimeFrame);
   MinPeriod=fmin(Force_TimeFrame,MACD_TimeFrame);
   MinPeriod=fmin(MinPeriod,Ch_TimeFrame);
   MinPeriod=fmin(MinPeriod,CCI_TimeFrame);
//---
   return(INIT_SUCCEEDED);
  }

In der Funktion OnDeinit werden die verwendeten Indikatoren wieder gelöscht.

void OnDeinit(const int reason)
  {
//---
   if(atr!=INVALID_HANDLE)
      IndicatorRelease(atr);
//---
   if(force==INVALID_HANDLE)
      IndicatorRelease(force);
//---
   if(macd==INVALID_HANDLE)
      IndicatorRelease(macd);
//---
   if(cho==INVALID_HANDLE)
      IndicatorRelease(cho);
//---
   if(cci==INVALID_HANDLE)
      IndicatorRelease(cci);
  }

Das Wesentliche geschieht in OnTick. Zu Beginn der Funktion wird die Eröffnung einer neuen Bar überprüft. Eine neue Position wird erst beim Erscheinen einer neuen Bar im kleinsten Zeitrahmen (ich begrenzt auf 10 Sekunden nach der Eröffnung der Bar) eröffnet, und nur, wenn keine Position innerhalb der aktuellen Bar durch den maximalen Zeitrahmen geöffnet wurde. Dadurch wird nur eine Position je Signal eröffnet.

void OnTick()
  {
//---
   datetime cur_bar=(datetime)SeriesInfoInteger(_Symbol,MinPeriod,SERIES_LASTBAR_DATE);
   datetime cur_max=(datetime)SeriesInfoInteger(_Symbol,MaxPeriod,SERIES_LASTBAR_DATE);
   datetime cur_time=TimeCurrent();
   if(cur_bar<=last_bar || (cur_time-cur_bar)>10 || cur_max<=last_deal)
      return;

Als nächstes erhalten wir die Daten der verwendeten Indikatoren. Im Falle eines Fehlers beim Abrufen von Daten von mindestens einem der Indikatoren, wird die Funktion verlassen.

   last_bar=cur_bar;
   double atrs[];
   double force_data[];
   double macd_data[];
   double cho_data[];
   double cci_data[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0 || CopyBuffer(force,0,1,1,force_data)<=0 || CopyBuffer(macd,0,1,1,macd_data)<=0
      || CopyBuffer(cho,0,1,2,cho_data)<2 || CopyBuffer(cci,0,1,2,cci_data)<2)
     {
      return;
     }

Dann prüfen wir entsprechend unserer Strategie den Wert des Force Index. Wenn der Filter die Situation verwirft, wird die Funktion verlassen bis eine neue Bar erscheint.

   double force_Step=_Point*1000;
   if(MathAbs(NormalizeDouble(force_data[0]/force_Step,0)*force_Step)<=0.01)
      return;

Der nächste Schritt besteht darin, das Signal zu überprüfen, um eine Kaufposition zu öffnen. Wenn ein positives Signal vorliegt, wird geprüft, ob bereits eine offene Position vorliegt. Wenn ja und es signalisiert einen Verkauf, wird es geschlossen. Wenn eine Kaufposition bereits geöffnet wurde, die sich in einem Verlust befindet, dann wird das Signal ignoriert und die Funktion verlassen.

Danach werden die Parameter der neuen Position berechnet und der Auftrag abgeschickt.

Ähnliche Operationen werden für eine Verkaufsposition durchgeführt.

   double macd_Step=_Point*50;
   macd_data[0]=NormalizeDouble(macd_data[0]/macd_Step,0)*macd_Step;
   if(macd_data[0]>=0.0015 && macd_data[0]<=0.0035 && (cho_data[1]-cho_data[0])<0 && (cci_data[1]-cci_data[0])>0)
     {
      if(PositionSelect(_Symbol))
        {
         switch((int)PositionGetInteger(POSITION_TYPE))
           {
            case POSITION_TYPE_BUY:
              if(PositionGetDouble(POSITION_PROFIT)<=0)
                 return;
              break;
            case POSITION_TYPE_SELL:
              Trade.PositionClose(_Symbol);
              break;
           }
        }
      last_deal=cur_max;
      double stops=MathMax(2*atrs[0],SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)*_Point);
      double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
      double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
      double sl=NormalizeDouble(stops,_Digits);
      double tp=NormalizeDouble(Reward_Risk*(stops+ask-bid),_Digits);
      double SL=NormalizeDouble(bid-sl,_Digits);
      double TP=NormalizeDouble(ask+tp,_Digits);
      if(!Trade.Buy(Lot,_Symbol,ask,SL,TP,"New Strategy"))
         Print("Error of open BUY ORDER "+Trade.ResultComment());
     }
   if(macd_data[0]<=(-0.0015) && macd_data[0]>=(-0.0035) && (cho_data[1]-cho_data[0])>0 && (cci_data[1]-cci_data[0])<0)
     {
      if(PositionSelect(_Symbol))
        {
         switch((int)PositionGetInteger(POSITION_TYPE))
           {
            case POSITION_TYPE_SELL:
              if(PositionGetDouble(POSITION_PROFIT)<=0)
                 return;
              break;
            case POSITION_TYPE_BUY:
              Trade.PositionClose(_Symbol);
              break;
           }
        }
      last_deal=cur_max;
      double stops=MathMax(2*atrs[0],SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)*_Point);
      double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
      double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
      double sl=NormalizeDouble(stops,_Digits);
      double tp=NormalizeDouble(Reward_Risk*(stops+ask-bid),_Digits);
      double SL=NormalizeDouble(ask+sl,_Digits);
      double TP=NormalizeDouble(bid-tp,_Digits);
      if(!Trade.Sell(Lot,_Symbol,bid,SL,TP,"New Strategy"))
         Print("Error of open SELL ORDER "+Trade.ResultComment());
     }
   return;
  }

Der vollständige Code des EA findet sich im Anhang.

Nach der Vorbereitung des EAs können wir unsere Strategie testen. Um eine "Anpassung der Strategie an den Zeitraum" zu vermeiden, verlängern wir den Testzeitraum: Die Strategie wird vom 01.01.2015 bis zum 01.01.2017 getestet. Das Anfangskapital beträgt 10.000 USD, das konstante Volumen 1 Lot.

Testen der Strategie. 

Gemäß den Testergebnissen erzielt der Berater einen Gewinn von 74,8% bei maximalen Salden-Drawdown von 12,4% und einem Eigenkapital von 23,8%. Insgesamt wurden 44 Positionen eröffnet (22 Kauf- und 22 Verkaufsposition). Der Anteil der profitablen Positionen beträgt 18,2% und ist für Kauf und Verkauf gleich. Solch ein geringer Prozentsatz von profitablen Positionen ist auf die Verwendung eines hohen Verhältnisses von Gewinn zu Risiko (15: 1) zurückzuführen und lässt Raum für eine weitere Verbesserung der Strategie.

Testergebnisse der Strategie.

Schlussfolgerung

Der Artikel demonstriert die Methode zur Erstellung von Handelsstrategien "auf einem leeren Blatt" unter Verwendung einer Methode, die die Positionsöffnung von Indikatoren bestimmen lässt. Die daraus resultierende Strategie ist in der Lage, über einen längeren Zeitraum Gewinne zu erwirtschaften, was durch Tests während drei jährigen Testperiode bewiesen wird. Ungeachtet der Tatsache, dass hier nur die Indikatoren aus dem Standardpaket des MetaTraders verwendet wurden, sind die Signale für die Eröffnung von Positionen weit entfernt von denen, die in der Literatur für getroffene Indikatoren beschrieben werden. Die vorgeschlagene Technologie ermöglicht die Verwendung von weiteren Indikatoren in Handelsstrategien, sie ist nicht durch die verwendeten Indikatoren begrenzt. Sie können beliebige, eigene Indikatoren und Varianten zur Beurteilung der Qualität ihrer Signale verwenden.

Referenzen

  1. Die Eröffnung durch Indikatoren bestimmen lassen
  2. Diagramme in HTML

Die Programm dieses Artikels:

#
 Name
Typ 
Beschreibung 
  New_Strategy_Gizlyk.zip    
1 NewStrategy1.mq5  EA  Der EA der Stufe eins der Strategie
 2 NewStrategy2.mq5   EA Der EA der Stufe zwei der Strategie
 3 NewStrategy3.mq5   EA  Der EA der Stufe drei der Strategie 
 4 NewStrategy4.mq5   EA
 Der EA der Stufe vier der Strategie 
 5 NewStrategy_Final.mq5  EA
 Der EA für den Strategietester
6 DealsToIndicators.mqh  Klassenbibliothek  Die Klasse für die Klassen der Indikatoren
7 Deal.mqh   Klassenbibliothek  Die Klasse zum Sichern der Informationen der Positionen
8 Value.mqh   Klassenbibliothek  Die Klasse zum Sichern die Werte der Indikatorpuffer
9 OneBufferArray.mqh  Klassenbibliothek  Die Klasse zum Sichern der Werte der Ein-Puffer-Indikatoren
10 StaticOneBuffer.mqh  Klassenbibliothek  Die Klasse zum Sammeln und Analysieren der Ein-Puffer-Indikatoren
11 ADXValue.mqh  Klassenbibliothek  Die Klasse zum Speichern der Werte des ADX
12 ADX.mqh  Klassenbibliothek  Die Klasse zum Speichern historischen Daten des ADX
13 StaticADX.mqh  Klassenbibliothek  Die Klasse zum Sammeln und Analysieren der Statistik des ADX
14 AlligatorValue.mqh  Klassenbibliothek  Die Klasse zum Speichern der Werte des Alligators
15 Alligator.mqh  Klassenbibliothek  Die Klasse zum Speichern historischen Daten des Alligators
16 StaticAlligator.mqh  Klassenbibliothek  Die Klasse zum Sammeln und Analysieren der Statistik des Alligators
17 MACDValue.mqh  Klassenbibliothek  Die Klasse zum Speichern der Werte des MACD
18 MACD.mqh  Klassenbibliothek  Die Klasse zum Speichern historischen Daten des MACD
19 StaticMACD.mqh  Klassenbibliothek  Die Klasse zum Sammeln und Analysieren der Statistik des MACD
   Common.zip    
20  NewStrategy1_Report_1to1_2016-17.html  Internetseite  Diagramm zur Analyse der ersten Stufe der Strategie, Gewinn/Risiko = 1/1
21  NewStrategy1_Report_15to1_2016-17.html  Internetseite  Diagramm zur Analyse der ersten Stufe der Strategie, Gewinn/Risiko = 15/1
22  NewStrategy2_Report_1to1_2016-17.html   Internetseite  Diagramm zur Analyse der zweiten Stufe der Strategie, Gewinn/Risiko = 1/1
23  NewStrategy2_Report_15to1_2016-17.html  Internetseite  Diagramm zur Analyse der zweiten Stufe der Strategie, Gewinn/Risiko = 15/1
24  NewStrategy3_Report_1to1_2016-17.html   Internetseite  Diagramm zur Analyse der dritten Stufe der Strategie, Gewinn/Risiko = 1/1
25  NewStrategy3_Report_15to1_2016-17.html   Internetseite  Diagramm zur Analyse der dritten Stufe der Strategie, Gewinn/Risiko = 15/1
26  NewStrategy4_Report_1to1_2016-17.html   Internetseite  Diagramm zur Analyse der vierten Stufe der Strategie, Gewinn/Risiko = 1/1
27  NewStrategy4_Report_15to1_2016-17.html   Internetseite  Diagramm zur Analyse der vierten Stufe der Strategie, Gewinn/Risiko = 15/1
28  NewStrategy_Final_Report.html  Internetseite  Bericht mit dem Testergebnis der Strategie


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

Beigefügte Dateien |
Common.zip (1455.62 KB)
Nachthandel während der asiatischen Handelszeit: wie man im Plus bleibt Nachthandel während der asiatischen Handelszeit: wie man im Plus bleibt
Der Artikel beschäftigt sich mit dem Begriff des Nachthandels, Handelsstrategien und deren Implementierung in MQL5. Es wurden Tests durchgeführt und Schlussfolgerungen gezogen.
Die Eröffnung durch Indikatoren bestimmen lassen Die Eröffnung durch Indikatoren bestimmen lassen
Im Leben eines Händlers gibt es verschiedene Situationen. Häufig wünschen wir uns, die Strategie von geschlossen, erfolgreichen Positionen fortzusetzen, während wir versuchen, die der Verlust bringenden Positionen weiterzuentwickeln und zu verbessern. In beiden Fällen vergleichen wir Positionen mit bekannten Indikatoren. Dieser Artikel schlägt die Methoden eines Batch-Vergleichs von Positionen mit einer Reihe von Indikatoren vor.
Handeln nach den Ebenen von DiNapoli Handeln nach den Ebenen von DiNapoli
Der Artikel beschäftigt sich mit der Möglichkeit, mit einem Expert Advisor und den Standardelementen aus MQL5 die DiNapoli-Ebenen zu handeln. Es wird die Leistungsfähigkeit getestet und die Ergebnisse besprochen.
Verwendung des Kalman-Filters für die Prognose der Preisrichtung Verwendung des Kalman-Filters für die Prognose der Preisrichtung
Für einen erfolgreichen Handel benötigen wir fast immer Indikatoren, die die Hauptpreisbewegung vom Hintergrundrauschen trennen können. In diesem Artikel betrachten wir einen der vielversprechendsten digitalen Filter, den Kalman-Filter. Der Artikel beschreibt, wie Sie den Filter zeichnen und verwenden können.