English Русский 中文 Español 日本語 Português
Testen der Muster, die beim Handel mit Körben von Währungspaaren auftreten. Teil I

Testen der Muster, die beim Handel mit Körben von Währungspaaren auftreten. Teil I

MetaTrader 5Handel | 21 August 2017, 16:19
515 0
Andrei Novichkov
Andrei Novichkov

Einleitung

In den vorherigen Artikeln über den Handel mit Körben von Währungskörben beschäftigten wir uns mit dem Handelsprinzip selbst, mit Tools der technischen Analyse und Mustern, die man mithilfe dieser Tools erkennen kann. Natürlich kann man nach solchen Methoden nicht arbeiten, ohne einzelne Parameter der Muster zu bestätigen. Man muss, zum Beispiel, konkrete Werte festlegen, wo die Levels für Überkauft/Überverkauft liegen müssen. Hier und weiter werden wir die Parameter der erkannten Muster herausfinden und versuchen, Empfehlungen für Trader hinsichtlich des Handels zu erarbeiten.

Tools der Untersuchung

Für die Arbeit werden wir den Indikator "vereinigter WPR" verwenden, den wir vorher entwickelt haben. In der vorherigen Artikelreihe wurde er mehrmals verwendet, und gerade mit diesem Indikator haben wir die meisten Muster erkannt.

Um den Chart des Indikators ein wenig zu glätten, erhöhen wir die WPR-Periode von vierzehn (14) auf zwanzig (20). Dies erlaubt es uns, den Chart "gerade zu machen" ohne Einbußen der Anzeigequalität.

Wir werden drei Zeitrahmen untersuchen: D1, H4 und H1. Ergebnisse in den anderen Perioden können Sie erhalten, wenn Sie die in diesem Artikel beschriebenen Methoden verwenden. 

Die Basisbegriffe und Grundlagen der Methoden wurden hier dargelegt.

Muster zur Untersuchung

Fangen wir mit dem Muster 3 an, das hier beschrieben wurde. Das Muster ist nicht besonders kompliziert, seine Entsprechung für einzelne Währungspaare ist längst bekannt. Für den Handel mit Körben von Währungspaaren wird es wie folgt verwendet:

Der Trader erhält ein Signal für den Einstieg mit allen Korbpaaren unter der Bedingung, dass der Level für Überkauft von oben nach unten oder der Level für Überverkauft von unten nach oben durch die Grafik des Indikators des vereinigten WPR nach dem Schließen der Kerze durchbrochen wurde.

Es stellt sich die Frage: wo befinden sich diese Levels für Überkauft/Überverkauft? Die Antwort auf diese Frage ist für den Standardindikator WPR auf einem Währungspaar bekannt:

  • Level für Überkauft: - 20%
  • Level für Überverkauft: - 80%

Das ist der Ausgangspunkt für unsere Untersuchungen. Verwenden wir diese Daten, um die Position der Levels für einen vereinigten WPR zu definieren. Die Ergebnisse werden wir nicht nur bei der Prüfung des zu betrachtenden Musters nutzen, sondern auch in den anderen (gleichen) Fällen. Die angewandte Methodik wird auch nützlich sein.

Damit die Grafik des Indikators einen der Levels durchbricht, muss dieser davor entweder oberhalb des Levels für Überkauft oder unterhalb des Levels für Überverkauft liegen. Schauen wir anhand der Historie, wie viele potentielle Einstiege uns der Markt bietet. An dieser Stelle werden wir keine Expert Advisors verwenden, sondern nehmen wir die vorher entwickelten Indikatoren testIndexZig-Zag1.mq5 und testWPReur.mq5. Wir werden Daten je nach dem Inhalt des Korbs in testWPReur.mq5 einfügen. Den Quellcode des Indikators testIndexZig-Zag1.mq5 vereinfachen wir ein bisschen, denn der Mindestwert und Höchstwert des Indikators sind uns bereits bekannt (von 100% bis -100%):

#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 6
#property indicator_plots   3
//--- plot High
#property indicator_label1  "High"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Low
#property indicator_label2  "Low"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrGreen
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot ZigZag
#property indicator_label3  "ZigZag"
#property indicator_type3   DRAW_SECTION
#property indicator_color3  clrRed
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- plot Direction
#property indicator_label4  "Direction"
#property indicator_type4   DRAW_LINE
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1
//--- plot LastHighBar
#property indicator_label5  "LastHighBar"
#property indicator_type5   DRAW_LINE
#property indicator_style5  STYLE_SOLID
#property indicator_width5  1
//--- plot LastLowBar
#property indicator_label6  "LastLowBar"
#property indicator_type6   DRAW_LINE
#property indicator_style6  STYLE_SOLID
#property indicator_width6  1

#include <ZigZag\CSorceData.mqh>
#include <ZigZag\CZZDirection.mqh>
#include <ZigZag\CZZDraw.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum EDirection
  {
   Dir_NBars=0,
   Dir_CCI=1
  };
//--- input parameters
input EDirection  DirSelect=Dir_NBars;
input int                  CCIPeriod   =  14;
input ENUM_APPLIED_PRICE   CCIPrice    =  PRICE_TYPICAL;
input int                  ZZPeriod=14;

string               name;

CZZDirection*dir;
CZZDraw*zz;

//--- indicator buffers
double         HighBuffer[];
double         LowBuffer[];
double         ZigZagBuffer[];
double         DirectionBuffer[];
double         LastHighBarBuffer[];
double         LastLowBarBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int h;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   switch(DirSelect)
     {
      case Dir_NBars:
         dir=new CNBars(ZZPeriod);
         break;
      case Dir_CCI:
         dir=new CCCIDir(CCIPeriod,CCIPrice);
         break;
     }
   if(!dir.CheckHandle())
     {
      Alert("Fehler beim Laden des Indikators 2");
      return(INIT_FAILED);
     }
   zz=new CSimpleDraw();
//--- indicator buffers mapping
   SetIndexBuffer(0,HighBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,LowBuffer,INDICATOR_DATA);
   SetIndexBuffer(2,ZigZagBuffer,INDICATOR_DATA);
   SetIndexBuffer(3,DirectionBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,LastHighBarBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,LastLowBarBuffer,INDICATOR_CALCULATIONS);
   name = _Symbol + TimeFrameToShortString(Period()) + ".txt";
   h=FileOpen(name,FILE_CSV|FILE_WRITE|FILE_ANSI,',');
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

   if(CheckPointer(dir)==POINTER_DYNAMIC)
     {
      delete(dir);
     }
   if(CheckPointer(zz)==POINTER_DYNAMIC)
     {
      delete(zz);
     }
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int ind=0;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[]
                )
  {
   int start;

   if(prev_calculated==0)
     {
      start=0;
     }
   else
     {
      start=prev_calculated-1;
     }

   for(int i=start;i<rates_total;i++)
     {
      HighBuffer[i]=price[i];
      LowBuffer[i]=price[i];
     }

   int rv;
   rv=dir.Calculate(rates_total,
                    prev_calculated,
                    HighBuffer,
                    LowBuffer,
                    DirectionBuffer);
   if(rv==0)return(0);
   zz.Calculate(rates_total,
                prev_calculated,
                HighBuffer,
                LowBuffer,
                DirectionBuffer,
                LastHighBarBuffer,
                LastLowBarBuffer,
                ZigZagBuffer);

   if(ind<= 10) ind++;
   if(ind == 10)
     {
      double mx=100,mn=-100;
      double lg;
      lg=mx-mn;
      lg/=100;
      double levels[100];
      int    count[100];
      ArrayInitialize(count,0);
      for(int i=1; i<101; i++) levels[i-1]=NormalizeDouble(lg*i + mn,_Digits);
      for(int i=0;i<rates_total;i++)
        {
         if(ZigZagBuffer[i]==0 || ZigZagBuffer[i]==EMPTY_VALUE) continue;
         else 
           {
            for(int j=0; j<100; j++) 
              {
               if(ZigZagBuffer[i]<levels[j]) 
                 {
                  count[j]++;
                  break;
                 }
              }
           }
        }
      for(int i=0; i<100; i++)
        {
         FileWrite(h,i,levels[i],count[i]);
        }
      FileClose(h);
      Print("Work complete: ",name);
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+


string TimeFrameToShortString(ENUM_TIMEFRAMES period)
{
   switch (period )
   {
      case PERIOD_M1:  return ("M1");
      case PERIOD_M2:  return ("M2");
      case PERIOD_M3:  return ("M3");
      case PERIOD_M4:  return ("M4");
      case PERIOD_M5:  return ("M5");
      case PERIOD_M6:  return ("M6");
      case PERIOD_M10: return ("M10");
      case PERIOD_M12: return ("M12");
      case PERIOD_M15: return ("M15");
      case PERIOD_M20: return ("M20");
      case PERIOD_M30: return ("M30");
      case PERIOD_H1:  return ("H1");
      case PERIOD_H2:  return ("H2");
      case PERIOD_H3:  return ("H3");
      case PERIOD_H4:  return ("H4");
      case PERIOD_H6:  return ("H6");
      case PERIOD_H8:  return ("H8");
      case PERIOD_H12: return ("H12");
      case PERIOD_D1:  return ("D1");
      case PERIOD_W1:  return ("W1");
      case PERIOD_MN1: return ("MN1");
   }
   return ("");
} 

Wie wir bereits erwähnt haben, wurde der Code dieses Indikators von unserem werten Kollegen Dmitry Fedoseev in diesem Artikel entwickelt und der Community freundlicherweise zur Verfügung gestellt. Die beiden erwähnten Indikatoren kann man in der angehängten Zip-Datei test.zip finden. Wir haben nun alle notwendigen Werkzeuge für die weitere Untersuchung.

Mögliche Anzahl der Trades

Der Bereich des vereinigten WPR schwankt von -100% bis +100%, deswegen nehmen wir an, dass der Level für Überkauft bei +60%, und der Level für Überverkauft bei -60% liegt, was dem Standardwert entspricht. Finden wir heraus, wie viele Male die Grafik des Indikators den Level für Überkauft/Überverkauft überschritten hat. Verwenden wir dafür die hier beschriebene Methode:

  • Ziehen wir den Indikator testIndexZig-Zag1.mq5 auf den Chart des vereinigten WPR (testWPReur.mq5). Unser Ziel ist, die Anzahl der Extrema festzulegen, die den Level von +70% und +80%, oder -70% und -80% überschreiten, wie auf dem Bild unten. Bitte achten Sie auf die Problemzone, die mit dem blauen Rechteck markiert ist. Zwar noch werden solche Extrema bei den Berechnungen berücksichtigt, aber später werden wir versuchen, solche auszufiltern:

  • Der Indikator testIndexZig-Zag1.mq5 teilt den Bereich des Indikators testWPReur.mq5 in die Intervalle je 1% und zählt, wie viele Extrema es in jedem Intervall gibt. Die Ergebnisse werden in eine Datei ausgegeben. Wiederholen wir die Berechnung für alle ausgewählten Zeitrahmen. Dann ändern wir die Daten je nach Inhalt des Korbs in testWPReur.mq5 und wir setzen die Arbeit mit dem weiteren Währungskorb fort.

Die erhaltenen Daten sind in einer Tabelle nach allen Währungskörben und nach allen ausgewählten Zeitrahmen dargestellt. Ein Fragment dieser Tabelle zum EUR-Korb ist unten dargestellt. Erläutern wir die Bezeichnungen in den Zeilen und Spalten dieser Tabelle:

  • Num. — Nummer.
  • Indicator — Wert des Indikators in Prozent. Zum Beispiel bedeutet die Zeile mit dem Wert -96 ein Interval von -96% bis -98% des vereinigten WPR.
  • EUR — drei Spalten mit der Anzahl der Extrema im ausgewählten Zeitrahmen. In der bereits erwähnten Zeile Num.1, mit dem Wert des Indikators des vereinigten WPR von 96% bis 98%, ist es angegeben, dass die folgende Anzahl der Extrema in diesem Bereich gefunden wurde: in D1 - Null, in H4 und H1 jeweils eins.
  • History Depth — die Markttiefe, die für die Berechnungen zur Verfügung steht.
  • Trade count (80%) — Gesamtzahl potentieller Einstiege nach jedem Zeitrahmen. Zum Beispiel: für den EUR-Korb gab es 83 potentielle Einstige im H4-Zeitrahmen, d.h. der Indikator hatte 83-mal 80% überschritten (hatte Extrema), oder war kleiner als -80%.
  • Trade count (70%) — das Gleiche, aber wenn der vereinigten WPR gleich 70% ist.
  • Trade total (80%) — Gesamtzahl potentieller Einstiege mit allen Körben und allen Zeitrahmen, wenn der vereinigte WPR gleich 80% ist.
  • Trade total (70%) — das Gleiche für 70%.


EUR ----
Num. Indicator Timeframe ----
D1 H4 H1 ----
0 -98 2 3 4 ----
1 -96 0 1 1 ----
2 -94 0 0 1 ----
3 -92 0 3 3 ----
4 -90 1 4 5 ----
5 -88 3 4 10 ----
6 -86 1 2 7 ----
7 -84 2 8 7 ----
8 -82 1 8 21 ----
9 -80 4 6 22 ----
---- ---- ---- ---- ---- ----
95 92 0 2 6 ----
96 94 0 1 4 ----
97 96 0 0 3 ----
98 98 0 3 0 ----
99 100 0 0 0 ----
History Depth 2000.11.09 2005.04.12 2006.01.17 ----





----
Trade count (80%) 25 83 165 ----
Trade count (70%) 45 207 449 ----












Trade total (80%) 3793


Trade total (70%) 7885


Die Tabelle ist im Anhang in der Zip-Datei Pair.zip zu finden.

Die zwei letzten Zeilen der Tabelle beinhalten die gesuchten Werte. Das ist eine relativ große Anzahl der potenziellen Einstiege in den Markt, auch unter Berücksichtigung, dass einige Signale ausgefiltert werden. Aus diesem Grund lassen wir die Levels für Überkauft/Überverkauft da, wo sie waren. Man muss immer im Hinterkopf behalten, dass alle gefundenen (und bereits vorhandenen) Werte rein theoretisch sind und geändert werden können.

Form des Musters

Definieren wir die Form des Musters, nach welcher der Trader in den Markt einsteigen kann.

  • Der Trader verkauft einen Korb, wenn der vereinigte WPR Indikator den Level für Überkauft von +60% von oben nach unten durchkreuzt. Dabei ist der Wert des Indikators beim Schließen der Kerze nicht kleiner als +50%. Der Rückgang der Indikatorlinie muss von einem Wert erfolgen, der nicht kleiner als +70% ist. Die zweite Variante für diesen Punkt ist +80% und höher, und für den überkauften Level ist das +70%.
  • Der Kauf eines Währungskorbs ist gleich dem beschriebenen Fall.

Alle drei Muster, die auf dem Bild oben markiert sind, erfüllen diese Bedingungen. Wir bekommen ein deutliches, gut erkennbares "schönes" Muster mit Zahlen und Bedingungen, die sich als Algorithmus beschreiben lassen.

Das heißt, weiter benötigen wir einen Expert Advisor.

Expert Advisor für das Testen des Musters

Zunächst einmal setzen wir und mit dem Kauf / Verkauf eines Korbes auseinander. In diesem Artikel geht es um Transaktionen mit Währungskörben und es ist eine Tabelle mit praktischen Empfehlungen zu jedem Korb dargestellt. Davon lassen wir uns leiten. Diesen Prinzip werden wir im Code des Expert Advisors verwenden.

Zeigen wir noch einmal, welche Muster wir ermitteln werden:

Gesuchtes Muster
Kein Muster



Nehmen wir an, der überkaufte / überverkaufte Level kann sich im Bereich 60% - 70% bewegen. Prüfen wir ihn hinsichtlich der Anzahl von Trades im Muster, Dauer von Trades, des Rückgangs und potentiellen Profits. Wir haben kein Ziel gesetzt, einen stabilen Profit vom Expert Advisor zu erhalten — dafür ist es noch zu früh. Unser Ziel ist es, den ersten Schritt auf dem Weg zur Definition der Form des Musters zu machen. Deswegen veröffentlichen wir auch keine Standardberichte des Testers, denn für uns ist es irrelevant, ob der Expert Advisor Verluste oder Profite bringt, und die Information, die wir brauchen, ist nicht in Standardberichten enthalten. Besonders intensiv werden wir uns mit der Anzeige der erhaltenen Ergebnissen auseinandersetzen.

Wir beginnen die Analyse mit dem USD-Währungskorb, und platzieren den folgenden Expert Advisor auf dem Währungspaar EURUSD auf den vorher ausgewählten Zeitrahmen:

//+------------------------------------------------------------------+
//|                                                   testBasket.mq5 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- input parameters

#include <Trade\\Trade.mqh>


#define LG 7

input int SELLPROFIT =   0;
input int SELL1LIMIT =  70;
input int SELL2FROM  =  60;
input int SELL2TO    =  50;

input int BUYPROFIT  =   0;
input int BUY1LIMIT  = -70;
input int BUY2FROM   = -60;
input int BUY2TO     = -50;

input int WPR=20;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum BSTATE 
  {
   BCLOSE = 0,
   BBUY   = 1,
   BSELL  = 2
  };

string pair[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY"};
bool bDirect[]={false,false,false,false,true,true,true};
datetime TimeParam[3];

double dWpr[3];
ulong  Ticket[LG];
double TradeResult[LG];
double TradeCurrency;
double Drw;
string sLog;

double TradeTotalResult[LG];
double TradeTotalCurrency;
int    iTradeCount;
double mDrw;

int h1[LG];
BSTATE bstate;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetValue1(int shift)
  {
   double dBuf[1];
   double res=0.0;
   for(int i=0; i<LG; i++)
     {
      CopyBuffer(h1[i],0,shift,1,dBuf);
      if(bDirect[i]==true)
         res+=dBuf[0];
      else
         res+=-(dBuf[0]+100);
     }//end for (int i = 0; i < iCount; i++)      
   res=res/LG;
   return (NormalizeDouble((res + 50) * 2, _Digits) );
  }

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int lh;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   EventSetTimer(1);

   for(int i=0; i<LG; i++)
     {
      h1[i]=iWPR(pair[i],0,WPR);
     }
   bstate=BCLOSE;

   ArrayInitialize(TradeTotalResult,0);
   ArrayInitialize(dWpr,EMPTY_VALUE);
   TradeTotalCurrency=0;
   iTradeCount=0;
   mDrw=1000000;

   lh=INVALID_HANDLE;
   string lname = _Symbol + "_" + TimeFrameToShortString(Period() );
   string t1, t = lname;
   int i=0;
   for(;;) 
     {
      t+=".html";
      long lg=FileFindFirst(t,t1);
      if(lg==INVALID_HANDLE) 
        {
         lh= FileOpen(t,FILE_WRITE | FILE_TXT | FILE_ANSI);
         Print("CREATE ",t);
         break;
        }
      FileFindClose(lg);
      t=lname+"_"+IntegerToString(i++);
     }

   FileWriteString(lh,"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n");
   FileWriteString(lh,"<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
   FileWriteString(lh,"<head>\r\n");
   FileWriteString(lh,"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\r\n");
   FileWriteString(lh,"<title>"+lname+"</title>\r\n");
   FileWriteString(lh,"</head>\r\n<body>\r\n");
   FileWriteString(lh,"<H2>"+_Symbol+" "+TimeFrameToShortString(Period())+"</H2>\r\n");
   FileWriteString(lh,"<H3>Pattern Params:</H3>\r\n");
   FileWriteString(lh,"<table width=\"100%\" cellspacing=\"0\" cellpadding=\"5\">\r\n");
   FileWriteString(lh,"<thead>\r\n<tr>\r\n<th>BUY</th>\r\n<th>SELL</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr>\r\n");
   t=StringFormat("Point 1: %d Point 2 from: %d to: %d Close at: %d",BUY1LIMIT,BUY2FROM,BUY2TO,BUYPROFIT);
   FileWriteString(lh,"<td style=\"text-align:center;\">\r\n<ul>\r\n<li>"+t+"</li>\r\n</ul>\r\n</td>\r\n");
   t=StringFormat("Point 1: %d Point 2 from: %d to: %d Close at: %d",SELL1LIMIT,SELL2FROM,SELL2TO,SELLPROFIT);
   FileWriteString(lh,"<td style=\"text-align:center;\">\r\n<ul>\r\n<li>"+t+"</li>\r\n</ul>\r\n</td>\r\n");
   FileWriteString(lh,"</tr>\r\n</tbody>\r\n</table>\r\n");
   FileWriteString(lh,"<H2>"+"Tester Result"+"</H2>\r\n");
   FileWriteString(lh,"<table border=\"1\" width=\"100%\" cellspacing=\"0\" cellpadding=\"5\">\r\n");
   FileWriteString(lh,"<thead>\r\n<th>Num.</th>\r\n<th>Type</th>\r\n<th>WPR(P1/P2)</th>\r\n<th>Time(Begin/End/Length)</th>\r\n<th>Drawdown/<br/>Profit</th>\r\n<th>Pair Profit</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n");

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void PushWpr(double wpr) 
  {
   dWpr[2] = dWpr[1]; dWpr[1] = dWpr[0];
   dWpr[0] = wpr;
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Stat() 
  {

   double d=0;
   for(int i=0; i<LG; i++) 
     {
      PositionSelectByTicket(Ticket[i]);
      d+=PositionGetDouble(POSITION_PROFIT);
     }
   if(d<Drw) Drw=d;
   if(Drw<mDrw) 
     {
      mDrw=Drw;
      TimeParam[2]=TimeCurrent();
     }
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(bstate!=BCLOSE) 
     {
      Stat();
     }
   if(IsNewCandle()) 
     {
      double res=GetValue1(0);
      PushWpr(res);
      if(dWpr[1]!=EMPTY_VALUE) 
        {
         if(bstate==BBUY && (dWpr[0]>=BUYPROFIT )) 
           {
            CloseAllPos();
            bstate=BCLOSE;
           }
         if(bstate==BSELL && (dWpr[0]<=SELLPROFIT )) 
           {
            CloseAllPos();
            bstate=BCLOSE;
           }
         if(bstate==BCLOSE && dWpr[0]<=SELL2FROM && dWpr[0]>=SELL2TO && dWpr[1]>=SELL1LIMIT) 
           {
            EnterSell(0.01);
            bstate=BSELL;
            TimeParam[0]=TimeCurrent();
            TradeCurrency=0;
            Drw=1000000;
            iTradeCount++;
            sLog=StringFormat("<tr>\r\n<td>%d</td>\r\n<td>SELL</td>\r\n<td>%.2f/<br/>%.2f</td>\r\n<td>%s/<br/>",iTradeCount,dWpr[1],dWpr[0],TimeToString(TimeCurrent()));
            return;
           }
         if(bstate==BCLOSE && dWpr[0]>=BUY2FROM && dWpr[0]<=BUY2TO && dWpr[1]<=BUY1LIMIT) 
           {
            EnterBuy(0.01);
            bstate=BBUY;
            TimeParam[0]=TimeCurrent();
            TradeCurrency=0;
            Drw=1000000;
            iTradeCount++;
            sLog=StringFormat("<tr>\r\n<td>%d</td>\r\n<td>BUY</td>\r\n<td>%.2f/<br/>%.2f</td>\r\n<td>%s/<br/>",iTradeCount,dWpr[1],dWpr[0],TimeToString(TimeCurrent()));
            return;
           }
        }//if (stc.Pick(1) != EMPTY_VALUE)
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseAllPos() 
  {

   CTrade Trade;
   Trade.LogLevel(LOG_LEVEL_NO);

   TimeParam[1]=TimeCurrent();
   string p="<td>";
   for(int i=0; i<LG; i++) 
     {
      TradeResult[i]=PositionGetDouble(POSITION_PROFIT)+PositionGetDouble(POSITION_SWAP);
      p+=StringFormat("%s = %.2f<br/>",pair[i],TradeResult[i]);
      TradeCurrency       += TradeResult[i];
      TradeTotalResult[i] += TradeResult[i];
      Trade.PositionClose(Ticket[i]);
     }
   p+="</td>\r\n";
   TradeTotalCurrency+=TradeCurrency;
   sLog += StringFormat("%s/<br/>%s</td>\r\n<td>%.2f/<br/>%.2f</td>\r\n",TimeToString(TimeParam[1]), TimeIntervalToStr(TimeParam[0], TimeParam[1]), Drw, TradeCurrency );
   sLog += p;
   FileWriteString(lh,sLog);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void EnterBuy(double lot) 
  {

   CTrade Trade;
   Trade.LogLevel(LOG_LEVEL_NO);

   for(int i=0; i<LG; i++) 
     {
      if(bDirect[i]) 
        { //send buy
         Trade.Buy(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
      else 
        { //send sell
         Trade.Sell(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void EnterSell(double lot) 
  {

   CTrade Trade;
   Trade.LogLevel(LOG_LEVEL_NO);

   for(int i=0; i<LG; i++) 
     {
      if(bDirect[i]) 
        { //send sell
         Trade.Sell(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
      else 
        { //send buy
         Trade.Buy(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
     }
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();

   FileWriteString(lh,"</tbody>\r\n</table>\r\n");
   FileWriteString(lh,"<H2>Total Result</H2>\r\n");
   FileWriteString(lh,"<table border=\"1\" width=\"100%\" cellspacing=\"0\" cellpadding=\"5\">\r\n");
   FileWriteString(lh,"<thead>\r\n<tr>\r\n<th>Deal's<br/>Count</th>\r\n<th>Profit</th>\r\n<th>Max.Drawdown</th>\r\n<th>Pair's Profit</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n");
   string p = StringFormat("<tr><td>%d</td>\r\n<td>%.2f</td>\r\n<td>%.2f at<br/>%s</td>\r\n<td>",iTradeCount,TradeTotalCurrency,mDrw,TimeToString(TimeParam[2]));
   for(int i=0; i<LG; i++)
     {
      if(h1[i]!=INVALID_HANDLE) IndicatorRelease(h1[i]);
      p+=StringFormat("%s = %.2f<br/>",pair[i],TradeTotalResult[i]);
     }
   p+="</td>\r\n</tr>\r\n";
   FileWriteString(lh,p);
   FileWriteString(lh,"</tbody>\r\n</table>\r\n");
   FileWrite(lh,"</body>\r\n</html>"); //End log
   FileClose(lh);
  }
//+------------------------------------------------------------------+

bool IsNewCandle() 
  {

   static int candle=-1;

   int t1=0;
   switch(_Period)
     {
      case PERIOD_H1:  t1 = Hour();   break;
      case PERIOD_H4:  t1 = Hour4();  break;
      case PERIOD_D1:  t1 = Day();    break;
     }
   if(t1!=candle) {candle=t1; return(true);}
   return (false);
  }
int Hour4(){return((int)Hour()/4);}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Day()
  {
   MqlDateTime tm;
   TimeCurrent(tm);
   return(tm.day);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Hour()
  {
   MqlDateTime tm;
   TimeCurrent(tm);
   return(tm.hour);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string TimeIntervalToStr(datetime dt1,datetime dt2) 
  {
   string tm;
   if(dt1 >= dt2)   tm = TimeToString(dt1 - dt2);
   else tm = TimeToString(dt2 - dt1,TIME_DATE|TIME_MINUTES|TIME_SECONDS);
   string ta[],ta1[];
   StringSplit(tm,StringGetCharacter(" ",0),ta);
   StringSplit(ta[0],StringGetCharacter(".",0),ta1);
   ta1[0] = IntegerToString( StringToInteger(ta1[0]) - 1970);
   ta1[1] = IntegerToString( StringToInteger(ta1[1]) - 1);
   ta1[2] = IntegerToString( StringToInteger(ta1[2]) - 1);
   return (ta1[0] + "." + ta1[1] + "." + ta1[2] + " " + ta[1]);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string TimeFrameToShortString(ENUM_TIMEFRAMES period)
  {
   switch(period)
     {
      case PERIOD_H1:  return ("H1");
      case PERIOD_H4:  return ("H4");
      case PERIOD_D1:  return ("D1");
     }
   return ("");
  }
//+------------------------------------------------------------------+

Die erste Version des Expert Advisors für das Testen ist auch in der angehängten Datei testBasket.mq5 zu finden. Im Algorithmus selbst gibt es nichts Besonderes, besonders ausführlich wurden die Formen des Berichts betrachtet. Erläutern wir die Eingabeparameter des Expert Advisors:

  • SELLPROFIT. Wenn der Indikator des vereinigten WPR diesen Wert erreicht, schließen wir alle Positionen, die für den Verkauf des Korbs eröffnet wurden. Standardmäßig ist dieser Wert gleich 0%.
  • SELL1LIMIT. Das ist der Mindestwert des vereinigten WPR für den Punkt 1 (s. das Bild oben) für die Identifikation des Musters für den Verkauf des Korbs. Standardmäßig 70%.
  • SELL2FROM. Höchstwert des vereinigten WPR für den Punkt 2 für die Erkennung des Musters für den Verkauf des Korbs. Standardmäßig 60%, das ist der Level für Überkauft.
  • SELL2TO. Mindestwert des vereinigten WPR für den Punkt 2 für die abschließende Identifikation des Musters für den Verkauf des Korbs. Standardmäßig 50%.
  • BUYPROFIT. Wenn der Indikator des vereinigten WPR diesen Wert erreicht, schließen wir alle Positionen, die für den Kauf des Korbs eröffnet wurden. Standardmäßig 0%.
  • BUY1LIMIT. Höchstwert des vereinigten WPR für den Punkt 1 für den Anfang der Identifikation des Musters für den Kauf des Korbs. Standardmäßig -70%.
  • BUY2FROM. Mindestwert des vereinigten WPR für den Punkt 2 für die Erkennung des Patterns des Kaufs des Korbs. Standardmäßig -60%, das ist der Level für Überverkauft.
  • UY2TO. Der maximale Wert des vereinigten WPR für den Punkt 2 für die abschließende Identifikaton des Musters für den Kauf des Korbs. Standardmäßig -50%.
  • WPR. Periode des Standardindikators WPR. Standardmäßig 20.

Danach testen wir den Expert Advisor im Strategietester, beginnend mit Januar 2016. Das ausgewählte Testdatum hängt von der Historie ab. Wir werden zwei Formen des Musters analysieren. Die erste wurde oben beschrieben und wird standardmäßig gesetzt. Die zweite ist hinsichtlich der ersten wie folgt verschoben:

  • SELLPROFIT. Wenn der Indikator des vereinigten WPR diesen Wert erreicht, schließen wir alle Positionen, die für den Verkauf des Korbs eröffnet wurden. Dieser Wert ist gleich 0%.
  • SELL1LIMIT. Das ist der Mindestwert des vereinigten WPR für den Punkt 1 (s. das Bild oben) für die Identifikation des Musters für den Verkauf des Korbs. Dieser Wert ist gleich 80%.
  • SELL2FROM. Höchstwert des vereinigten WPR für den Punkt 2 für die Erkennung des Musters für den Verkauf des Korbs. Dieser Wert ist gleich 70%, der Level für Überkauft.
  • SELL2TO. Mindestwert des vereinigten WPR für den Punkt 2 für die abschließende Identifikation des Musters für den Verkauf des Korbs. Dieser Wert ist gleich 50%.
  • BUYPROFIT. Wenn der Indikator des vereinigten WPR diesen Wert erreicht, schließen wir alle Positionen, die für den Kauf des Korbs eröffnet wurden. Dieser Wert ist gleich 0%.
  • BUY1LIMIT. Höchstwert des vereinigten WPR für den Punkt 1 für den Anfang der Identifikation des Musters für den Kauf des Korbs. Dieser Wert ist gleich -80%.
  • BUY2FROM. Mindestwert des vereinigten WPR für den Punkt 2 für die Erkennung des Patterns des Kaufs des Korbs. Dieser Wert ist gleich -70%, der Level für Überverkauft.
  • UY2TO. Der maximale Wert des vereinigten WPR für den Punkt 2 für die abschließende Identifikaton des Musters für den Kauf des Korbs. Dieser Wert ist gleich -50%.

Das Ergebnis — Berichte im HTML-Format.

Berichtsform des Expert Advisors

Es ist nicht kompliziert, die Berichte des Expert Advisors zu lesen. Betrachten wir die Struktur der Berichte anhand eines Berichts zum EUR-Korb.

Die erste Zeile ist die Überschrift mit den Namen des Chats und des Zeitrahmens, auf welchem der Expert Advisor lief.

Danach folgen die Parameter des Musters, mit welchen der Expert Advisor separat für den Kauf und Verkauf arbeitete: Point 1 — die Position des Punktes 1: SELL1LIMIT (BUY1LIMIT). Point 2 from: ... to: ... —  die Position des Punktes 2: SELL2FROM (BUY2FROM) und SELL2TO (BUY2TO). Close at — Position des Schlusspunktes des Musters SELLPROFIT (BUYPROFIT):

EURUSD H4

Pattern Params:

BUY SELL
  • Point 1: -80 Point 2 from: -70 to: -50 Close at: 0
  • Point 1: 80 Point 2 from: 70 to: 50 Close at: 0

Weiter folgt die Tabelle "Tester Result" mit Details zu jedem Trade während der Testperiode wie folgt:

  • Num. — Nummer
  • Type — Typ des Abschlusses: Verkauf oder Kauf des Korbs
  • WPR(P1/P2) — Daten des vereinigten WPR im Format Punkt 1 / Punkt 2, basierend auf welchen der Einstieg in den Markt erfolgt
  • Time(Begin/End/Length) — Informationen über die Zeit: Zeit des Einstiegs / Zeit des Ausstiegs / Dauer des Abschlusses
  • Drawdown/Profit — maximaler Rückgang während des Trades / Profit insgesamt. Die Daten sind in der Kontowährung.
  • Pair Profit — Profit nach einzelnen Paaren, aus welchen der Währungskorb besteht. Die Daten sind in der Kontowährung.

Hier ist ein Fragment dieser Tabelle. Man kann sehen, dass der erste Abschluss acht Stunden dauerte und 16.34 USD Verluste gebracht hat. Die EURUSD-Order wurde mit einem Verlust von 2.55 USD geschlossen:

Num. Type WPR(P1/P2) Time(Begin/End/Length) Drawdown/
Profit
Pair Profit
1 SELL 86.26/
67.15
2016.03.23 20:00/
2016.03.24 04:00/
0.0.0 08:00:00
-21.70/
-16.34
EURUSD = -2.55
GBPUSD = -1.58
AUDUSD = -2.02
NZDUSD = -3.66
USDCAD = -2.15
USDCHF = -2.97
USDJPY = -1.41


Als letzte folgt die Tabelle "Total Result" mit summierten Daten nach der Testperiode:

  • Deal's Count — Anzahl der Abschlüsse innerhalb der ganzen Testperiode.
  • Profit — der erhaltene Profit für die ganze Testperiode. Die Daten sind in der Kontowährung.
  • Max.Drawdown — maximaler Rückgang und in welchem Moment er festgestellt wurde. Daten in Kontowährung und Datum.
  • Pair's Profit — Gesamtprofit nach jedem Währungspaar, aus welchen der Währungskorb besteht. Die Daten sind in der Kontowährung.

Hier ist die Tabelle aus einem Bericht:

Deal's
Count
Profit Max.Drawdown Pair's Profit
22 189.06 -52.37 at
2016.05.02 19:53
EURUSD = 52.43
GBPUSD = 24.50
AUDUSD = 45.88
NZDUSD = 13.94
USDCAD = 15.73
USDCHF = 12.26
USDJPY = 24.32


Die Berichte befinden sich in der angehängten Zip-Datei DocUSD.zip.

Es fällt sofort auf, dass es unerwartet wenige Abschlüsse in D1 gibt. Es gibt aber auch erfolgversprechende Signale:

  • In H4 und H1 erzielte der Expert Advisor positive Ergebnisse, und dafür mussten wir nichts tun.

Basierend auf diesem Material kann man bereits die ersten Schlussfolgerungen ziehen, die man später korrigieren kann wenn nötig.

  1. Das Muster lässt ganz selten im Tageszeitrahmen erkennen. Höchstwahrscheinlich bleibt diese Tendenz auch in älteren Zeitrahmen erhalten.
  2. Der Level für Überkauft liegt im Bereich 60% — 70%, der Level für Überverkauft befindet sich im Bereich -60% — -70%. Oberhalb von 70% und unterhalb von -70% gibt es wenige Abschlüsse. Damit das Muster in diesem Fall erkannt werden kann, muss der Punkt 1 über 90%, oder unter -90% liegen, und das ist ein relativ seltener Fall. Unterhalb von 60% und oberhalb von -60% liegt der Punkt 2 bei 40% oder -40% und nähert sich an den Bereich einer potentiellen Seitwärtsbewegung. Für diesen Bereich sind noch eine hohe Volatilität in den Werten des Indikators und als Folge viele falsche Signale für den Einstieg charakteristisch.

Modifizieren wir den Expert Advisor und setzen wir mit dem nächstem Währungskorb fort — NZD. Nehmen wir Änderungen in der Form des Berichts vor, und zwar geben wir den Wert eines "positiven Rückgangs" aus. Erläutern wir diesen Begriff. Der Korb wird weder nach einem konkreten Profitwert, noch nach gesetzten Levels geschlossen, sondern nach den Werten des Indikators. Die Orders, die zum Order-Korb gehören, können bis zum Moment des Schließens Rückgang haben, dessen Größe der Expert Advisor verfolgt. Diese Orders können auch im Profit sein, der nicht festgelegt wird, weil der Indikator den notwendigen Wert für das Schließen noch nicht erreicht hat. Diesen Wert bezeichnen wir als einen "Positiven Rückgang", und seine Höchstwerte werden in den Bericht ausgegeben. Jetzt wissen wir, wie groß der Profit sein könnte, wieweit der Korb "im Plus war".

Fügen wir diesen Wert in die vorletzte Spalte der Tabelle "Tester Result" hinzu. Die Spalte, die "Drawdown/Profit" hieß, wird nun Drawdown/+Drawdown/Profit heißen, und die Daten in jeder Zelle der Spalte sind wie folgt: Rückgang / Positiver Rückgang / Profit. Alle Daten werden in der Kontowährung angegeben.

Darüber hinaus zeigen wir den maximalen Wert des positiven Rückgangs in der Tabelle "Total Result" an. Führen wir eine zusätzliche Spalte, die vorletzte Spalte "Max.+Drawdown", ein, und zeigen wir den maximalen positiven Rückgang für die ganze Testperiode und wann dieser Rückgang festgestellt wurde in dieser Spalte an.

Der Quellcodes dieser nächsten Version des Expert Advisors ist in der angehängten Datei testBasket1.mq5 zu finden.

Die Berichte zum NZD-Korb befinden sich in der Zip-Datei DocNZD.zip. Wir haben die folgenden Schlussfolgerungen gezogen:

  • Die Vermutung über die Position der Levels für Überkauft/Überverkauft hat sich bestätigt. Der Zip-Datei wurde der Bericht NZDUSD_H1_1.html mit den Levels hinzugefügt, die nah am potenziellen Anfang der Seitwärtsbewegung mit einer großen Anzahl falscher Signale zum Einstieg liegen. Die Darstellung der Folgen ist anschaulich.
  • Es hat sich als richtig erwiesen, dass im D1-Zeitrahmen nach diesem Muster sehr wenige Abschlüsse gibt.
  • Wir haben ein enttäuschendes Ergebnis auf dem Zeitrahmen H1 erhalten. Man kann vermuten, dass sich das Rauschen des Zeitrahmens nach dem Rauschen aller Währunspaaren des Korbes summiert, und als Ergebnis erhalten wir falsche Signale.

Schließen wir die Untersuchung ab, indem wir die restlichen Devisen des Korbs verwenden: AUD, EUR, GBP, CAD, JPY, CHF. Berichte zu diesen Währungspaaren kann man in der angehängten Zip-Datei Doc.zip finden. Es ist Zeit, Schlussfolgerungen zu ziehen:

Schlussfolgerungen

  • Der Level für Überkauft liegt tatsächlich im Bereich von 60% bis 70%, und der Level für Überverkauft — zwischen -60% und -70%. Davon zeugen sowohl die erhaltenen Berichte, als auch die Position des entsprechenden Levels auf dem Standardindikator WPR.
  • Die Prüfung wurde anhand drei Zeitrahmen und aller acht bekannten Währungskörbe durchgeführt. Es wurden zwei Formen des Ausbruchsmusters der überkauften / überverkauften Linien untersucht:
    1. Der Punkt 1 des Musters liegt oberhalb von 80%. Der Level für Überverkauft — bei 70%. Der Punkt 2 — zwischen 70% und 50%. Der Korb wird geschlossen, wenn der Indikator ≤ 0% ist. Hier ist eine Form des Musters für den Einstieg in den Verkauf des Korbs angeführt. Die Form für den Einstieg in Kauf ist gleich, mit dem Vorzeichen "-".
    2. Der Punkt 1 des Musters liegt oberhalb von 70%. Der Level für Überverkauft — bei 60%. Der Punkt 2 — zwischen 60% und 50%. Der Korb wird geschlossen, wenn der Indikator ≤ 0% ist. Hier ist eine Form des Musters für den Einstieg in den Verkauf des Korbs angeführt. Die Form für den Einstieg in Buy ist gleich, mit dem Vorzeichen "-".
  • Es ist noch einmal zu betonen, dass es sehr wenige Trades im D1-Zeitrahmen gibt, in diesem Artikel werden wir diesen Zeitrahmen nicht mehr verwenden. Entnehmen wir den Tabellen "Total Result" aller Berichte die Daten und stellen wir Tabellen für andere Zeitrahmen basierend auf diesen Daten zusammen. In den Tabellen sind die Ergebnisse des Expert Advisors in der Kontowährung für jeden Währungskorb und für beide Formen des Musters dargestellt, die im vorherigen Punkt beschrieben wurden:

     

    H1-Zeitrahmen
      AUD EUR USD GBP NZD CAD CHF JPY
    Muster 1 -590 90 -37 -991 -141 -80 -118 -514
    Muster 2 -259 -67 328 -714 -352 -446 -118 -272

     

    H4-Zeitrahmen
      AUD EUR USD GBP NZD CAD CHF JPY
    Muster 1 286 -72 189 -400 104 60 -209 120
    Muster 2 -208 25 40 80 172 10 -69 -176

     

    Schauen wir uns das traurige Ergebnis des Expert Advisors auf dem H1-Zeitrahmen an. Wahrscheinlich ist das die Folge des Rauschens der Währungspaare auf diesem Zeitrahmen.
  • Auf dem H4-Zeitrahmen haben wir ein gutes Ergebnis bekommen. Weiter werden wir uns mit diesem Zeitrahmen besonders intensiv auseinandersetzen.

Die erhaltenen Ergebnisse erlauben uns nicht, eine begründete Auswahl zwischen zwei Formen eines Musters zu treffen, deswegen werden wir mit den beiden arbeiten. Meiner Meinung nach sieht die zweite Form aussichtsreicher aus, das ist aber subjektiv. Treffen wir diese Entscheidung später.

Sollte die Arbeit mit dem H1-Zeitrahmen abgeschlossen werden? Auf keinem Fall! Nicht umsonst haben wir den "positiven Rückgang" in den Bericht eingeführt. Wenn wir uns diese Daten und die Daten nach dem gewöhnlichen Rückgang anschauen, können wir sehen:

  • Die ursprüngliche Idee über das Schließen eines Korbes nach den Werten des vereinigten WPR (wenn sein Wert Null erreicht) ist nicht ausreichend. Die Aufgabe der Begrenzung von Verlusten wurde auch nicht gelöst. Da wir mit einem Orderkorb zu tun haben, wäre es logisch, Stop-Loss und Trailing Stop in der Kontowährung zu setzen. Dies hätte es erlaubt, wenn man Profit hat, nicht direkt ins Minus zu gehen, und von der anderen Seite, diesen "Minus" vernünftig zu begrenzen. Solche Methodik könnte zum Summand des positiven Ergebnisses in H1 werden und die Profitabilität in H4 erhöhen. Momentan steht das nicht auf unserem Programm, aber als technische Lösung wird das in der Zukunft nützlich sein.

Fazit

Die erste Testphase der Muster ist abgeschlossen. Wir müssen über die erhaltenen Ergebnisse reflektieren. In der weiteren Arbeit werden wir basierend auf den erhaltenen Daten die Filterung von Signalen und zusätzliche Signale von den anderen bekannten Mustern betrachten. Dies erlaubt es uns, nicht nur neue Informationen zu gewinnen, sondern auch die erhaltenen zu ergänzen.

Die im Artikel verwendeten Programme:

 # Name
Typ
 Beschreibung
1 Pair.zip Zip-Datei
Die Ergebnisse der Berechnung der Anzahl potentieller Abschlüsse nach allen Korbwährungen in den drei ausgewählten Zeitrahmen.
2
testBasket.mq5 Expert Advisor
Expert Advisor für das Testen.
3
DocUSD.zip Zip-Datei Berichte über die Ausführung des Expert Advisors testBasket.mq5 mit dem USD-Korb im HTML-Format.
 4 DocNZD.zip Zip-Datei Berichte im HTML-Format zur Arbeit des Expert Advisors testBasket1.mq5 mit dem NZD-Korb.
5
testBasket1.mq5 Expert Advisor Expert Advisor für das Testen - nächste Version.
 6  Doc.zip Zip-Datei
Berichte im HTML-Format zur Arbeit des Expert Advisors testBasket1.mq5 mit den anderen Körben.
7 test.zip
 Zip-Datei  Zip-Datei mit den Indikatoren testIndexZig-Zag1.mq5 und testWPReur.mq5



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

Beigefügte Dateien |
testBasket.mq5 (26.57 KB)
DocUSD.zip (14.3 KB)
DocNZD.zip (27.8 KB)
testBasket1.mq5 (27.74 KB)
Doc.zip (99.72 KB)
test.zip (3.81 KB)
Pair.zip (7.92 KB)
Graphisches Interface XI: Gezeichnete Steuerelemente (build 14.2) Graphisches Interface XI: Gezeichnete Steuerelemente (build 14.2)
In der neuen Version der Bibliothek werden alle Steuerelemente als eigenständige Grafikobjekte des Typs OBJ_BITMAP_LABEL gezeichnet. Der Code wird auch weiterhin optimiert: die Änderungen in den Kernklassen werden beschrieben.
Graphische Interfaces XI: Überarbeitung des Bibliothekscodes (build 14.1) Graphische Interfaces XI: Überarbeitung des Bibliothekscodes (build 14.1)
Wenn die Bibliothek wächst, muss ihr Programmcode wiederholt optimiert werden, um die Größe zu verringern. Die Version der in diesem Artikel beschriebenen Bibliothek ist nun auch in Teilen objektorientiert. Dadurch ist der Code leichter zu verstehen. Mit der detaillierten Beschreibung der letzten Änderungen kann der Leser auf Basis dieser Bibliothek seine eigenen Ziele umsetzen.
Wir schreiben eine Scalping-Markttiefe aufgrund der graphischen Bibliothek CGraphic Wir schreiben eine Scalping-Markttiefe aufgrund der graphischen Bibliothek CGraphic
Im Artikel wird die grundlegende Funktional einer Scalping-Markttiefe erstellt. Es wird ein Ticks-Chart aufgrund der graphischen Bibliothek CGraphic erstellt und es wird mit einer Anfragen-Tabelle integriert. Mit Hilfe der beschriebenen Markttiefe kann man einen mächtigen Helfer für einen kurzfristigen Handel erstellen.
Flaggenformation Flaggenformation
Der Artikel befasst sich mit den Formationen Flagge, Wimpel, Keil, rechteckige Formation, Fallendes Dreieck und Steigendes Dreieck. Es werden ihre Ähnlichkeiten und Unterschiede analysiert sowie Indikatoren für deren Erkennung auf dem Chart und ein Tester-Indikator für eine schnelle Einschätzung der Effizienz erstellt.