Adaptive Handelssysteme und ihre Verwendung im MetaTrader 5 Client-Terminal

MetaQuotes | 14 Januar, 2016


Einleitung

Hundertausende Händler weltweit arbeiten mit den von MetaQuotes Software Corp entwickelten Handelsplattformen. Der für diesen Erfolg verantwortliche Schlüsselfaktor ist die technologische Überlegenheit, die auf langjähriger Erfahrung und den besten Software-Lösungen beruht.

Viele Menschen haben bereist neue Chancen kalkuliert, die mit der neuen MQL5 Sprache nun tatsächlich Wirklichkeit werden. Ihre Schlüsselmerkmale sind die hohe Leistungsfähigkeit und die Möglichkeit, einen Objekt-orientierten Ansatz anwenden zu können. Darüber hinaus haben viele Händler, mit der Verfügbarkeit des Strategie-Testers für mehrere Währungen im MetaTrader 5 Client-Terminal, einmalige Tools zur Entwicklung, dem Erlernen und der Anwendung komplexer Handelssysteme an die Hand bekommen.

Der Automated Trading Wettbewerb 2010 beginnt diesen Herbst, und Tausende von, in MQL5 geschriebenen Handels-Roboter, werden daran teilnehmen. Und der Expert Advisor, der während des Wettbewerbs den höchsten Gewinn erzielt, hat gewonnen. Doch welche Strategie wird sich als die wirksamste erweisen?

Der Strategie-Tester des MetaTrader 5 Terminals ermöglicht das Auffinden des besten Parameter-Sets, mit dessen Verwendung das System dann während einet festgelegten Zeitspanne den höchsten Gewinn erwirtschaftet. Doch gilt das auch für Echtzeit-Operationen? Das Konzept des virtuellen Handels mit Hilfe verschiedener Strategien in einem Expert Advisor, war Gegenstand des Beitrags "Contest of Expert Advisors inside an Expert Advisor", der seine Implementierung in MQL4 umfasst. 

In diesem Beitrag werden wir erläutern, dass die Erzeugung und Analyse adaptiver Strategien in MQL5 aufgrund des Einsatzes Objekt-orientierten Programmierens, Klassen zur Arbeit mit Daten und Handelsklassen aus der Standard-Bibliothek erheblich einfacher geworden ist.


1. Adaptive Handelsstrategien

Märkte verändern sich ständig. Handelsstrategien müssen daher den aktuellen Marktbedingungen angepasst werden.

Die Werte der Parameter, die die maximale Profitabilität der Strategie bringen, können ohne Verwendung der Optimierung durch sequentielle Parameterveränderung und Analyse von Testergebnissen gefunden werden. 

Abb. 1 zeigt die Equity-Kurven für 10 Expert Advisors (MA_3,...MA_93), von denen jeder mittels der Strategie der gleitenden Mittelwerte, doch mit unterschiedlichen Zeiträumen (3,13,..93) gehandelt hat. Die Tests wurden bei EURUSD H1 durchgeführt; die Testphase war vom 4. 01. 2010 - 20. 08. 2010.

Abb. 1 Diagramme von Equity-Kurven von 10 Expert Advisors im Account

Abb. 1 Diagramme von Equity-Kurven von 10 Expert Advisors im Account

Wie Sie in Abb. 1 sehen können lieferten die Expert Advisors während ihrer ersten zwei Arbeitswochen alle annähernd gleiche Ergebnisse, doch ihre Gewinne wichen dramatisch voneinander ab. Am Ende der Testphase zeigten die Expert Advisors mit den Zeiträumen 63, 53 und 43 die besten Handelsergebnisse.

Der Markt hat also die besten gewählt. Warum nicht einfach seiner Auswahl folgen? Was wäre, wenn wir alle 10 Strategien in einen einzigen Expert Advisor vereinen, die Möglichkeit des "virtuellen" Handels für jede Strategie zur Verfügung stellen, und periodisch (beispielsweise zu Beginn jedes neuen Bars) die beste Strategie für echtes Handeln und Handel in Übereinstimmung mit Signalen festlegen würden?

Abb. 2 zeigt die Ergebnisse der so erhaltenen adaptiven Strategie. Die Equity-Kurve des Accounts mit adaptivem Handeln ist in Rot dargestellt. Hier ist zu beachten, dass mehr als für die Hälfte des Zeitraum die Form der Equity-Kurve für die adaptive Strategie genau der für die MA_63 Strategie entspricht, die sich am Ende dann als Gewinner herausstellte.

Abb. 2 Equity-Kurven im Account mit der adaptiven Strategie unter Verwendung von Signalen von 10 Handelssystemen

Abb. 2 Equity-Kurven im Account mit der adaptiven Strategie unter Verwendung von Signalen von 10 Handelssystemen

Die Saldo-Kurven haben eine ähnliche Dynamik (Abb. 3):

Abb. 3 Saldo-Kurven im Account mit der adaptiven Strategie unter Verwendung von Signalen von 10 Handelssystemen

Abb. 3 Saldo-Kurven im Account mit der adaptiven Strategie unter Verwendung von Signalen von 10 Handelssystemen

Wenn im Augenblick keine der Strategien profitabel ist, sollten die adaptiven Systeme keine Handels-Operationen ausführen. Abb. 4 zeigt das Beispiel eines solchen Falls (Zeitraum vom 4. - 22. Januar 2010).

Abb. 4 Der Zeitraum endete, als die adaptive Strategie aufhörte, neue Positionen zu eröffnen, da sie keine profitablen Strategien mehr fand

Abb. 4 Der Zeitraum endete, als die adaptive Strategie aufhörte, neue Positionen zu eröffnen, da sie keine profitablen Strategien mehr fand

Beginnend ab Januar 2010 weist die MA_3 Strategie die beste Effektivität auf. Da MA_3 (blau) in diesem Moment den größten Geldbetrag erwirtschaftete, folgt die adaptive Strategie (rot) seinen Signalen. Im Zeitraum vom 08. - 20. Januar brachten alle berücksichtigen Strategien negative Ergebnisse, deshalb eröffnete die adaptive Strategie keine neuen Handelspositionen. 

Wenn alle Strategien negative Ergebnisse liefern, sollte man sich besser vom Handel zurückziehen. Das ist das Schlaueste, denn nur so können Sie nicht profitables Handeln beenden und Ihr Geld schützen.


2. Implementierung der adaptiven Handelsstrategie

In diesem Abschnitt werfen wir einen Blick auf die Struktur der adaptiven Strategie, die einen "virtuellen" Handel mit Hilfe verschiedener Handelsstrategien gleichzeitig ausführt und auf Grundlage ihrer Signale die profitabelste für echtes Handeln wählt. Beachten Sie, dass der Einsatz des Objekt-orientierten Ansatzes die Lösung dieses Problems erheblich erleichtert.

Als Erstes untersuchen wir den Code des adaptiven Expert Advisors, dann sehen wir uns die CAdaptiveStrategy genauer an, in der die Funktionalität des adaptiven Systems implementiert ist und schließlich präsentieren wir noch die Struktur der CSampleStrategy Klasse - der Basisklasse der Handelsstrategien, in der die Funktionalität des virtuellen Handels implementiert ist.

Zudem betrachten wir auch den Code zweier ihrer 'Kinder' - der CStrategyMA- und CStrategyStoch-Klassen, die die Handelsstrategien nach gleitendem Mittelwert und dem stochastischen Oszillator darstellen. Nach der Analyse ihren Struktur, können Sie problemlos Ihre eigenen Klassen schreiben und hinzufügen, die Ihre Strategien umsetzen.

2.1 Code des Expert Advisors

Der Code des Expert Advisors sieht reichlich einfach aus:

//+------------------------------------------------------------------+
//|                                       Adaptive_Expert_Sample.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <CAdaptiveStrategy.mqh>

CAdaptiveStrategy Adaptive_Expert;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(Adaptive_Expert.Expert_OnInit());
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   Adaptive_Expert.Expert_OnDeInit(reason);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   Adaptive_Expert.Expert_OnTick();
  }
//+------------------------------------------------------------------+

Seine ersten drei Zeilen definieren die Eigenschaften des Programms, dann folgt die #include directive, die dem Prä-Prozessor sagt, die CAdaptiveStrategy.mqh Datei mit aufzunehmen. Die spitzen Klammern geben an, dass die Datei aus dem Standard-Directory genommen werden sollte (meist terminal_folder\MQL5\Include).

Die nächste Zeile enthält die Deklarierung des Adaptive_Expert Objekts (Instanz der CAdaptiveStrategy Klasse). Der Code der OnInit, OnDeinit und OnTick Funktionen des Expert Advisors enthält die Aufrufe der entsprechenden Funktionen Expert_OnInit,  Expert_OnDeInit und Expert_OnTick sowie das Adaptive_Expert Objekt.

2.2 Die CAdaptiveStrategy Klasse

Die Klasse des Expert Advisors (CAdaptiveStrategy Klasse) befindet sich in der CAdaptiveStrategy.mqh Datei. Beginnen wir mit dem Miteinschließen von Dateien:

#include <Arrays\ArrayObj.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <CStrategyMA.mqh>
#include <CStrategyStoch.mqh>

Wir schließen die ArrayObj.mqh Datei deshalb mit ein, da wir dann bequemer mit Klassen unterschiedlicher Strategien mittels des Objekts der CArrayObj Klasse arbeiten können. Sie stellt ein dynamisches Array an Zeigern zu den Klasseninstanzen dar, die von der Basisklasse CObject und ihren 'Kindern' hervorgebracht werden. Dieses Objekt ist das m_all_strategies Array und dient als "Aufbewahrungsort" der Handelsstrategien.

Jede Strategie wird als Klasse dargestellt. In unserem Fall haben wir die Dateien mit eingeschlossen, die die CStrategyMA- und CStrategyStoch-Klassen enthalten, die die Handelsstrategien per gleitenden Mittelwerten und per stochastischem Oszillator widerspiegeln.

Zur Anfrage der Eigenschaften aktueller Positionen und zur Durchführung von Handelsoperationen, verwenden wir die CPositionInfo und CTrade Klassen der Standard-Bibliothek, und deshalb schließen wir die PositionInfo.mqh und Trade.mqh Dateien ebenfalls mit ein.

Schauen wir uns die Struktur der CAdaptiveStrategy Klasse mal genauer an.

//+------------------------------------------------------------------+
//| Class CAdaptiveStrategy                                          |
//+------------------------------------------------------------------+
class CAdaptiveStrategy
  {
protected:
   CArrayObj        *m_all_strategies;   // objects of trade strategies

   void              ProceedSignalReal(int state,double trade_volume);
   int               RealPositionDirection();

public:
   // initialization of the adaptive strategy
   int               Expert_OnInit();
   // deinitialization of the adaptive strategy
   int               Expert_OnDeInit(const int reason);
   // check of trade conditions and opening of virtual positions
   void              Expert_OnTick();
  };

Zur Implementierung eines vereinheitlichten Ansatzes für die Objekte der verschiedenen Klassen sind die Handelsstrategien (oder vielmehr die Instanzen ihrer Klassen) im dynamischen m_all_strategies Array (des Typs CArrayObj) gespeichert, der als "Aufbewahrungsort" der Strategie-Klassen dient. Aus diesem Grund wird die Handelsstrategien-Klasse SampleStrategy von der CObject Klasse hervorgebracht.

Die ProceedSignalReal Funktion implementiert die "Synchronisierung" der Richtung und des Volumens der echten Position mit einer gegebenen Richtung und einem gegebenen Volumen:

//+------------------------------------------------------------------+
//| This method is intended for "synchronization" of current         |
//| real trade position with the value of the 'state' state          |
//+------------------------------------------------------------------+
void CAdaptiveStrategy::ProceedSignalReal(int state,double trade_volume)
  {
   CPositionInfo posinfo;
   CTrade trade;

   bool buy_opened=false;
   bool sell_opened=false;

   if(posinfo.Select(_Symbol)) // if there are open positions
     {
      if(posinfo.Type()==POSITION_TYPE_BUY) buy_opened=true;    // a buy position is opened
      if(posinfo.Type()==POSITION_TYPE_SELL) sell_opened=true;  // a sell position is opened

      // if state = 0, then we need to close open positions
      if((state==POSITION_NEUTRAL) && (buy_opened || sell_opened))
        {
         if(!trade.PositionClose(_Symbol,200))
            Print(trade.ResultRetcodeDescription());
        }
      //reverse: closing buy position and opening sell position
      if((state==POSITION_SHORT) && (buy_opened))
        {
         if(!trade.PositionClose(_Symbol,200))
            Print(trade.ResultRetcodeDescription());
         if(!trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,trade_volume,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0))
            Print(trade.ResultRetcodeDescription());
        }
      //reverse: close sell position and open buy position
      if(((state==POSITION_LONG) && (sell_opened)))
        {
         if(!trade.PositionClose(_Symbol,200))
            Print(trade.ResultRetcodeDescription());
         if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,trade_volume,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0))
            Print(trade.ResultRetcodeDescription());
        }
     }
   else // if there are no open positions
     {
      // open a buy position
      if(state==POSITION_LONG)
        {
         if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,0.1,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0))
            Print(trade.ResultRetcodeDescription());
        }
      // open a sell position
      if(state==POSITION_SHORT)
        {
         if(!trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,0.1,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0))
            Print(trade.ResultRetcodeDescription());
        }
     }
  }

Beachten Sie, dass die Arbeit mit den Handelsposition leichter geht, wenn man Handelsklassen verwendet. Zur Anfrage der Eigenschaften der Marktposition und zur Durchführung von Handelsoperationen haben wir die Objekte der CPositionInfo bzw. CTrade Klassen verwendet.

Die RealPositionDirection Funktion verlangt die Parameter der echten offenen Position und liefert ihre Richtung:

//+------------------------------------------------------------------+
//| Returns direction (0,+1,-1) of the current real position         |
//+------------------------------------------------------------------+
int CAdaptiveStrategy::RealPositionDirection()
  {
   int direction=POSITION_NEUTRAL;
   CPositionInfo posinfo;

   if(posinfo.Select(_Symbol)) // if there are open positions
     {
      if(posinfo.Type()==POSITION_TYPE_BUY) direction=POSITION_LONG;    // a buy position is opened
      if(posinfo.Type()==POSITION_TYPE_SELL) direction=POSITION_SHORT;  // a short position is opened
     }
   return(direction);
  }

Sehen wir uns nun die Hauptfunktionen der СAdaptiveStrategy Klasse an.

Los geht's mit der Expert_OnInit: Funktion

//+------------------------------------------------------------------+
//| Function of initialization of the Adaptive Expert Advisor        |
//+------------------------------------------------------------------+
int CAdaptiveStrategy::Expert_OnInit()
  {
//--- Create array of objects m_all_strategies
//--- we will put our object with strategies in it 
   m_all_strategies=new CArrayObj;
   if(m_all_strategies==NULL)
     {
      Print("Error of creation of the object m_all_strategies"); return(-1);
     }

// create 10 trading strategies CStrategyMA (trading by moving averages)
// initialize them, set parameters
// and add to the m_all_strategies container 
   for(int i=0; i<10; i++)
     {
      CStrategyMA *t_StrategyMA;
      t_StrategyMA=new CStrategyMA;
      if(t_StrategyMA==NULL)
        {
         delete m_all_strategies;
         Print("Error of creation of object of the CStrategyMA type");
         return(-1);
        }
      //set period for each strategy
      int period=3+i*10;
      // initialize strategy
      t_StrategyMA.Initialization(period,true);
      // set details of the strategy
      t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period));
      //t_StrategyMA.Set_Stops(3500,1000);

      //add the object of the strategy to the array of objects m_all_strategies
      m_all_strategies.Add(t_StrategyMA);
     }

   for(int i=0; i<m_all_strategies.Total(); i++)
     {
      CSampleStrategy *t_SampleStrategy;
      t_SampleStrategy=m_all_strategies.At(i);
      Print(i," Strategy name:",t_SampleStrategy.StrategyName(),
              " Strategy ID:",t_SampleStrategy.StrategyID(),
              " Virtual trading:",t_SampleStrategy.IsVirtualTradeAllowed());
     }
//---
   return(0);
  }

Das Set an Handelsstrategien wird in der Expert_OnInit Funktion vorbereitet. Zuerst wird das Objekt des m_all_strategies dynamischen Arrays erzeugt.

In unserem Fall haben wir zehn Instanzen der CStrategyMA-Klasse erzeugt. Jede davon wurde mittels der Initialisierungs-Funktion initialisiert (in unserem Fall hier haben wir unterschiedliche Zeiträume eingerichtet und "virtuelles" Handeln zugelassen).

Dann richteten wir mittels der SetStrategyInfo-Funktion das Finanzinstrument, den Namen der Strategie und einen Kommentar ein.

Ggf. können wir mittels der Set_Stops (TP,SL)-Funktion einen Wert (in Punkten) von Take Profit und Stop Loss angeben, der während des "virtuellen" Handels ausgeführt wird. Diese Zeile versehen wir mit einem Kommentar.

Ist die Strategieklasse erzeugt und angepasst, fügen wir sie dem m_all_strategies Aufbewahrungsort hinzu.

Alle Klassen an Handelsstrategien sollten die CheckTradeConditions()-Funktion besitzen, da sie die Prüfungen der Handelsbedingungen durchführt. In der Klasse der adaptiven Strategie wird diese Funktion zu Beginn jedes neuen Bars aufgerufen, daher ermöglichen wir es den Strategien, die Indikatorenwertezu prüfen und "virtuelle" Handelsoperationen auszuführen.

Anstelle von zehn spezifizierten gleitenden Mittelwerten (3, 13, 23...93) können wir nun Hunderte von gleitenden Mittelwerten (Instanzen der CStrategyMA-Klasse) hinzufügen:

  for(int i=0; i<100; i++)
     {
      CStrategyMA *t_StrategyMA;
      t_StrategyMA=new CStrategyMA;
      if(t_StrategyMA==NULL)
        {
         delete m_all_strategies;
         Print("Error of creation of object of the CStrategyMA type");
         return(-1);
        }
      //set period for each strategy
      int period=3+i*10;
      // initialization of strategy
      t_StrategyMA.Initialization(period,true);
      // set details of the strategy
      t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period));
      //add the object of the strategy to the array of objects m_all_strategies
      m_all_strategies.Add(t_StrategyMA);
     }

Oder wir fügen die Klassen der Strategie hinzu, die nach den Signalen des stochastischen Oszillators arbeitet (Instanzen der CStrategyStoch-Klasse):

  for(int i=0; i<5; i++)
     {
      CStrategyStoch *t_StrategyStoch;
      t_StrategyStoch=new CStrategyStoch;
      if(t_StrategyStoch==NULL)
        {
         delete m_all_strategies;
         printf("Error of creation of object of the CStrategyStoch type");
         return(-1);
        }
      //set period for each strategy
      int Kperiod=2+i*5;
      int Dperiod=2+i*5;
      int Slowing=3+i;
      // initialization of strategy
      t_StrategyStoch.Initialization(Kperiod,Dperiod,Slowing,true);
      // set details of the strategy
      string s=IntegerToString(Kperiod)+"/"+IntegerToString(Dperiod)+"/"+IntegerToString(Slowing);
      t_StrategyStoch.SetStrategyInfo(_Symbol,"[Stoch_"+s+"]",100+i," Stochastic "+s);
      //add the object of the strategy to the array of objects m_all_strategies
      m_all_strategies.Add(t_StrategyStoch);
     }

In unserem Fall enthält der Aufbewahrungsort zehn Strategien des gleitenden Mittelwerts und fünf Strategien des stochastischen Oszillators.

Die Instanzen der Handelsstrategien-Klassen sollten die Kinder der CObject Klasse sein und die CheckTradeConditions() Funktion enthalten. Es ist besser, sie von der CSampleStrategy Klasse zu "erben". Klassen, die Handelsstrategien implementieren, können anders sein und sind zahlenmäßig unbegrenzt.

Die Expert_OnInit Funktion endet mit einer Liste an Strategien, die im m_all_strategies Aufbewahrungsort vorhanden sind. Bitte beachten Sie, dass alle Strategien im Aufbewahrungsort als Kinder der CSampleStrategy Klasse betrachtet werden. Die Klassen der Handelsstrategien CStrategyMA und CStrategyStoch sind ebenfalls ihre Kinder.

Der gleiche 'Trick' wird auch bei der Expert_OnDeInit Funktion angewandt. Im Aufbewahrungsort rufen wir für jede Strategie die SaveVirtualDeals Funktion auf, sie speichert die Historie der ausgeführten virtuellen Abschlüsse.

Als Namen für die Datei, die als ein Parameter übertragen wird, wählen wir den Namen der Strategie. Danach de-initialisieren wir die Strategien durch Aufruf der Deinitialization()-Funktion und löschen den m_all_strategies Aufbewahrungsort:

//+------------------------------------------------------------------+
//| Function of deinitialization the adaptive Expert Advisor         |
//+------------------------------------------------------------------+
int CAdaptiveStrategy::Expert_OnDeInit(const int reason)
  {
   // deinitialize all strategies
   for(int i=0; i<m_all_strategies.Total(); i++)
     {
      CSampleStrategy *t_Strategy;
      t_Strategy=m_all_strategies.At(i);
      t_Strategy.SaveVirtualDeals(t_Strategy.StrategyName()+"_deals.txt");
      t_Strategy.Deinitialization();
     }
   //delete the array of object with strategies 
   delete m_all_strategies;
   return(0);
  }

Wenn Sie nicht über die virtuellen Abschlüsse, die von den Strategien ausgeführt wurden, Bescheid wissen müssen, entfernen Sie die Zeile, wo tStrategy.SaveVirtualDeals aufgerufen wird. Beachten Sie bitte, dass bei der Verwendung des Strategie-Testers die Dateien in das /tester_directory/Files/ Directory abgelegt werden.

Betrachten wir uns die Expert_OnTick Funktion der CAdaptiveStrategy Klasse, die jedes Mal bei einer neuen Preisänderung aufgerufen wird:

//+------------------------------------------------------------------+
//| Function of processing ticks of the adaptive strategy            |
//+------------------------------------------------------------------+
void CAdaptiveStrategy::Expert_OnTick()
  {
   CSampleStrategy *t_Strategy;

   // recalculate the information about positions for all strategies
   for(int i=0; i<m_all_strategies.Total(); i++)
     {
      t_Strategy=m_all_strategies.At(i);
      t_Strategy.UpdatePositionData();
     }

   // the expert advisor should check the conditions of making trade operations only when a new bar comes
   if(IsNewBar()==false) { return; }

   // check trading conditions for all strategies 
   for(int i=0; i<m_all_strategies.Total(); i++)
     {
      t_Strategy=m_all_strategies.At(i);
      t_Strategy.CheckTradeConditions();
     }

   //search for the best position
   //prepare the array performance[] 
   double performance[];
   ArrayResize(performance,m_all_strategies.Total());
   
   //request the current effectiveness for each strategy,
   //each strategy returns it in the Strategyperformance() function
   for(int i=0; i<m_all_strategies.Total(); i++)
     {
      t_Strategy=m_all_strategies.At(i);
      performance[i]=t_Strategy.StrategyPerformance();
     }
   //find the strategy (or rather its index in the m_all_strategies container)
   //with maximum value of Strategyperformance()
   int best_strategy_index=ArrayMaximum(performance,0,WHOLE_ARRAY);

   //this strategy is - t_Strategy
   t_Strategy=m_all_strategies.At(best_strategy_index);
   //request the direction of its current position
   int best_direction=t_Strategy.PositionDirection();

   string s=s+" "+t_Strategy.StrategyName()+" "+DoubleToString(t_Strategy.GetVirtualEquity())+" "+IntegerToString(best_direction);
   Print(TimeCurrent()," TOTAL=",m_all_strategies.Total(),
                       " BEST IND=",best_strategy_index,
                       " BEST STRATEGY="," ",t_Strategy.StrategyName(),
                       " BEST=",performance[best_strategy_index],"  =",
                       " BEST DIRECTION=",best_direction,
                       " Performance=",t_Strategy.StrategyPerformance());

   //if the best strategy has a negative result and doesn't have open positions, it's better to stay away from trading
   if((performance[best_strategy_index]<0) && (RealPositionDirection()==POSITION_NEUTRAL)) {return;}

   if(best_direction!=RealPositionDirection())
     {
      ProceedSignalReal(best_direction,t_Strategy.GetCurrentLotSize());
     }
  }

Ihr Code ist sehr einfach. Jede im Aufbewahrungsort vorhandene Strategie muss das aktuelle finanzielle Ergebnis ihrer virtuellen Positionen mit Hilfe des aktuellen Kurses erneut berechnen können. Dies geschieht durch Aufruf der UpdatePositionData() Funktion. Auch hier rufen wir die Strategien als 'Erben' der CSampleStrategy Klasse auf.

Alle Handels-Operationen werden am Anfang eines neuen Bars ausgeführt (die IsNewBar() Funktion gestattet die Festlegung dieses Moments sowie auch die anderen Methoden zur Prüfung des neuen Bars). In unserem Fall bedeutet das Ende der Herausbildung eines Bars, dass sich alle Daten der vorigen Bars (Kurse und Indikatorwerte) nicht mehr ändern. Daher kann er auf Übereinstimmung mit den Handelsbedingungen analysiert werden. Zudem ermöglichen wir allen Strategien diese Prüfung sowie ihre virtuellen Handelsoperationen auszuführen, indem wir ihre CheckTradeConditions Funktion aufrufen.

Jetzt sollten im m_all_strategies Array die erfolgreichste aller Strategien finden. Dazu haben wir das Performance[] Array verwendet. Die Werte, die von der StrategyPerformance() Funktion jeder Strategie geliefert werden, werden dorthin platziert. Die CSampleStrategy Basisklasse enthält diese Funktion als Differenz der aktuellen Werte des "virtuellen" Equity (Eigenkapitals) und Saldos.

Die Suche nach dem Index der erfolgreichsten Strategie geschieht mittels der ArrayMaximum Funktion. Weist die beste Strategie im Augenblick einen negativen Gewinn aus und enthält sie keine echten offenen Positions, sollte man besser nicht handeln. Deshalb verlassen wir diese Funktion hier jetzt auch (vgl. Abschnitt 1).

Des Weiteren fragen wir die Richtung der virtuellen Position dieser Strategie ab (best_direction). Sollte sie von der aktuellen Richtung der echten Position abweichen, dann wird die aktuelle Richtung der echten Position gemäß der best_direction Richtung korrigiert (mit Hilfe der ProceedSignalReal Funktion).

2.3 Die CSampleStrategy Klasse

Im m_all_strategies Aufbewahrungsort platzierte Strategien wurden als 'Erben' der CSampleStrategy Klasse betrachtet.

Diese Klasse ist die Basis für die Handelsstrategien und enthält die Implementierung des virtuellen Handelns. In diesem Beitrag behandeln wir einen vereinfachten Fall der Implementierung virtuellen Handelns, da Swaps (Tauschgeschäfte) nicht mit berücksichtigt werden. Die Handelsstrategien-Klassen sollten also von der CSampleStrategy Klasse 'geerbt' werden.

So sieht die Struktur dieser Klasse aus.

//+------------------------------------------------------------------+
//|                                              CSampleStrategy.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#include <Object.mqh>

#define POSITION_NEUTRAL   0     // no position
#define POSITION_LONG      1     // long position
#define POSITION_SHORT    -1     // short position

#define SIGNAL_OPEN_LONG    10   // signal to open a long position
#define SIGNAL_OPEN_SHORT  -10   // signal to open a short position
#define SIGNAL_CLOSE_LONG   -1   // signal to close a long position
#define SIGNAL_CLOSE_SHORT   1   // signal to close a short position
//+------------------------------------------------------------------+
//| Structure for storing the parameters of virtual position         |
//+------------------------------------------------------------------+
struct virtual_position
  {
   string            symbol;            // symbol
   int               direction;         // direction of the virtual position (0-no open position,+1 long,-1 short)
   double            volume;            // volume of the position in lots
   double            profit;            // current profit of the virtual position on points
   double            stop_loss;         // Stop Loss of the virtual position
   double            take_profit;       // Take Profit of the virtual position
   datetime          time_open;         // date and time of opening the virtual position
   datetime          time_close;        // date and time of closing the virtual position
   double            price_open;        // open price of the virtual position
   double            price_close;       // close price of the virtual position
   double            price_highest;     // maximum price during the life of the position
   double            price_lowest;      // minimal price during the lift of the position
   double            entry_eff;         // effectiveness of entering
   double            exit_eff;          // effectiveness of exiting
   double            trade_eff;         // effectiveness of deal
  };
//+------------------------------------------------------------------+
//| Class CSampleStrategy                                            |
//+------------------------------------------------------------------+
class CSampleStrategy: public CObject
  {
protected:
   int               m_strategy_id;            // Strategy ID
   string            m_strategy_symbol;        // Symbol 
   string            m_strategy_name;          // Strategy name
   string            m_strategy_comment;       // Comment

   MqlTick           m_price_last;             // Last price
   MqlRates          m_rates[];                // Array for current quotes
   bool              m_virtual_trade_allowed;  // Flag of allowing virtual trading 
   int               m_current_signal_state;   // Current state of strategy
   double            m_current_trade_volume;   // Number of lots for trading
   double            m_initial_balance;        // Initial balance (set in the constructor, default value is 10000)
   int               m_sl_points;              // Stop Loss
   int               m_tp_points;              // Take Profit

   virtual_position  m_position;               // Virtual position
   virtual_position  m_deals_history[];        // Array of deals
   int               m_virtual_deals_total;    // Total number of deals

   double            m_virtual_balance;           // "Virtual" balance
   double            m_virtual_equity;            // "Virtual" equity
   double            m_virtual_cumulative_profit; // cumulative "virtual" profit
   double            m_virtual_profit;            // profit of the current open "virtual" position

   //checks and closes the virtual position by stop levels if it is necessary
   bool              CheckVirtual_Stops(virtual_position &position);
   // recalculation of position and balance
   void              RecalcPositionProperties(virtual_position &position);
   // recalculation of open virtual position in accordance with the current prices 
   void              Position_RefreshInfo(virtual_position &position);
   // open virtual short position
   void              Position_OpenShort(virtual_position &position);
   // closes virtual short position  
   void              Position_CloseShort(virtual_position &position);
   // opens virtual long position
   void              Position_OpenLong(virtual_position &position);
   // closes the virtual long position
   void              Position_CloseLong(virtual_position &position);
   // closes open virtual position  
   void              Position_CloseOpenedPosition(virtual_position &position);
   // adds closed position to the m_deals_history[] array (history of deals)
   void              AddDealToHistory(virtual_position &position);
   //calculates and returns the recommended volume that will be used in trading
   virtual double    MoneyManagement_CalculateLots(double trade_volume);
public:
   // constructor
   void              CSampleStrategy();
   // destructor
   void             ~CSampleStrategy();

   //returns the current size of virtual balance
   double            GetVirtualBalance() { return(m_virtual_balance); }
   //returns the current size of virtual equity
   double            GetVirtualEquity() { return(m_virtual_equity); }
   //returns the current size of virtual profit of open position
   double            GetVirtualProfit() { return(m_virtual_profit); }

   //sets Stop Loss and Take Profit in points
   void              Set_Stops(int tp,int sl) {m_tp_points=tp; m_sl_points=sl;};
   //sets the current volume in lots
   void              SetLots(double trade_volume) {m_current_trade_volume=trade_volume;};
   //returns the current volume in lots
   double            GetCurrentLots() { return(m_current_trade_volume); }

   // returns strategy name
   string            StrategyName() { return(m_strategy_name); }
   // returns strategy ID
   int               StrategyID() { return(m_strategy_id); }
   // returns the comment of strategy
   string            StrategyComment() { return(m_strategy_comment); }
   // sets the details of strategy (symbol, name and ID of strategy)
   void              SetStrategyInfo(string symbol,string name,int id,string comment);

   // set the flag of virtual trading (allowed or not)
   void              SetVirtualTradeFlag(bool pFlag) { m_virtual_trade_allowed=pFlag; };
   // returns flag of allowing virtual trading
   bool              IsVirtualTradeAllowed() { return(m_virtual_trade_allowed); };

   // returns the current state of strategy
   int               GetSignalState();
   // sets the current state of strategy (changes virtual position if necessary)
   void              SetSignalState(int state);
   // changes virtual position in accordance with the current state 
   void              ProceedSignalState(virtual_position &position);

   // sets the value of cumulative "virtual" profit
   void              SetVirtualCumulativeProfit(double cumulative_profit) { m_virtual_cumulative_profit=cumulative_profit; };

   //returns the effectiveness of strategy ()
   double            StrategyPerformance();

   //updates position data
   void              UpdatePositionData();
   //closes open virtual position
   void              CloseVirtualPosition();
   //returns the direction of the current virtual position
   int               PositionDirection();
   //virtual function of initialization
   virtual int       Initialization() {return(0);};
   //virtual function of checking trade conditions
   virtual bool      CheckTradeConditions() {return(false);};
   //virtual function of deinitialization
   virtual int       Deinitialization() {return(0);};

   //saves virtual deals to a file
   void              SaveVirtualDeals(string file_name);
  };

Wir sparen uns die Analyse seiner detaillierten Beschreibung, da diesbezügliche, zusätzliche Informationen in der CSampleStrategy.mqh Datei vorhanden sind. Dort finden Sie auch die Funktion zur Prüfung des neuen Bars - IsNewBar.


3. Handelsstrategie-Klassen

Dieser Abschnitt widmet sich der Struktur von Handelsstrategie-Klassen, die in einem adaptiven Expert Advisor verwendet werden.

3.1 CStrategyMA-Klasse - Handelsstrategie per gleitenden Mittelwerten

//+------------------------------------------------------------------+
//|                                                  CStrategyMA.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#include <CSampleStrategy.mqh>
//+------------------------------------------------------------------+
//| Class CStrategyMA for implementation of virtual trading          |
//| by the strategy based on moving average                          |
//+------------------------------------------------------------------+
class CStrategyMA : public CSampleStrategy
  {
protected:
   int               m_handle;     // handle of the Moving Average (iMA) indicator
   int               m_period;     // period of the Moving Average indicator
   double            m_values[];   // array for storing values of the indicator
public:
   // initialization of the strategy
   int               Initialization(int period,bool virtual_trade_flag);
   // deinitialization of the strategy
   int               Deinitialization();
   // checking trading conditions and opening virtual positions
   bool              CheckTradeConditions();
  };

Die CStrategyMA-Klasse ist ein Kind der CSampleStrategy Klasse, in der die gesamte Funktionalität des virtuellen Handels implementiert ist.

Der geschützte Bereich enthält interne Variablen, die in der Strategie-Klasse verwendet werden. Sie lauten: m_handle - Identifikator des iMA Indikators, m_period - Zeitraum des gleitenden Mittelwerts, m_values[] - ein Array, das in der CheckTradeConditions Funktion verwendet wird, um die aktuellen Indikatorwerte zu erhalten.

Der public Bereich enthält drei Funktionen, die für die Implementierung der Handelsstrategie zuständig sind.

  1. Das Signal zum Öffnen einer Long Position (SIGNAL_OPEN_LONG)
  2. Das Signal zum Öffnen einer Short Position (SIGNAL_OPEN_SHORT)
  3. Das Signal zum Schließen einer Long Position (SIGNAL_CLOSE_LONG)
  4. Das Signal zum Schließen einer Short Position (SIGNAL_CLOSE_SHORT)
//+------------------------------------------------------------------+
//| Strategy Initialization Method                                   |
//+------------------------------------------------------------------+
int CStrategyMA::Initialization(int period,bool virtual_trade_flag)
  {
   // set period of the moving average
   m_period=period;
   // set specified flag of virtual trading
   SetVirtualTradeFlag(virtual_trade_flag);

   //set indexation of arrays like the one of timeseries
   ArraySetAsSeries(m_rates,true);
   ArraySetAsSeries(m_values,true);
   
   //create handle of the indicator
   m_handle=iMA(_Symbol,_Period,m_period,0,MODE_EMA,PRICE_CLOSE);
   if(m_handle<0)
     {
      Alert("Error of creation of the MA indicator - error number: ",GetLastError(),"!!");
      return(-1);
     }

   return(0);
  }
//+------------------------------------------------------------------+
//| Strategy Deinitialization Method                                 |
//+------------------------------------------------------------------+
int CStrategyMA::Deinitialization()
  {
   Position_CloseOpenedPosition(m_position);
   IndicatorRelease(m_handle);
   return(0);
  };
//+------------------------------------------------------------------+
//| Checking trading conditions and opening virtual positions        |
//+------------------------------------------------------------------+
bool CStrategyMA::CheckTradeConditions()
  {
   RecalcPositionProperties(m_position);
   double p_close;

   // get history data of the last three bars
   if(CopyRates(_Symbol,_Period,0,3,m_rates)<0)
     {
      Alert("Error of copying history data - error:",GetLastError(),"!!");
      return(false);
     }
   // Copy the current price of closing of the previous bar (it is bar 1)
   p_close=m_rates[1].close;  // close price of the previous bar          

   if(CopyBuffer(m_handle,0,0,3,m_values)<0)
     {
      Alert("Error of copying buffers of the Moving Average indicator - error number:",GetLastError());
      return(false);
     }

   // buy condition 1: MA rises
   bool buy_condition_1=(m_values[0]>m_values[1]) && (m_values[1]>m_values[2]);
   // buy condition 2: previous price is greater than the MA
   bool buy_condition_2=(p_close>m_values[1]);

   // sell condition 1: // MA falls
   bool sell_condition_1=(m_values[0]<m_values[1]) && (m_values[1]<m_values[2]);
   // sell condition 2: // previous price is lower than the MA   
   bool sell_condition_2=(p_close<m_values[1]);

   int new_state=0;

   if(buy_condition_1  &&  buy_condition_2) new_state=SIGNAL_OPEN_LONG;
   if(sell_condition_1 && sell_condition_2) new_state=SIGNAL_OPEN_SHORT;

   if((GetSignalState()==SIGNAL_OPEN_SHORT) && (buy_condition_1 || buy_condition_2)) new_state=SIGNAL_CLOSE_SHORT;
   if((GetSignalState()==SIGNAL_OPEN_LONG) && (sell_condition_1 || sell_condition_2)) new_state=SIGNAL_CLOSE_LONG;

   if(GetSignalState()!=new_state)
     {
      SetSignalState(new_state);
     }

   return(true);
  };

Das Konzept ist einfach: auf Grundlage der Indikator-Stati und Kurse, wird die Art des Signals festgelegt. Dann wird der aktuelle Status des virtuellen Handels angefragt (mit Hilfe der GetSignalState Funktion), und, sollten sie nicht übereinstimmen, wird die SetSignalState Funktion zur "Korrektur" der virtuellen Position aufgerufen.

3.2 CStrategyStoch-Klasse - Handelsstrategie per Stochastik

Unten steht der Code der Klasse, die Handel auf Basis einer Überschneidung der Haupt- und Signallinien des iStochastik Oszillators ausführt:

//+------------------------------------------------------------------+
//|                                               CStrategyStoch.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#include <CSampleStrategy.mqh>
//+------------------------------------------------------------------+
//| Class CStrategyStoch for implementation of virtual trading by    |
//| the strategy of intersection of lines of stochastic oscillator   |
//+------------------------------------------------------------------+
class CStrategyStoch : public CSampleStrategy
  {
protected:
   int               m_handle;          // handle of the Stochastic Oscillator (iStochastic)
   int               m_period_k;        // K-period (number of bars for calculations)
   int               m_period_d;        // D-period (period of primary smoothing)
   int               m_period_slowing;  // final smoothing
   double            m_main_line[];     // array for storing indicator values
   double            m_signal_line[];   // array for storing indicator values
public:
   // initialization of strategy
   int               Initialization(int period_k,int period_d,int period_slowing,bool virtual_trade_flag);
   // deinitialization of strategy
   int               Deinitialization();
   // checking trading conditions and opening virtual positions
   bool              CheckTradeConditions();
  };
//+------------------------------------------------------------------+
//| Strategy Initialization Method                                   |
//+------------------------------------------------------------------+
int CStrategyStoch::Initialization(int period_k,int period_d,int period_slowing,bool virtual_trade_flag)
  {
   // Set period of the oscillator
   m_period_k=period_k;
   m_period_d=period_d;
   m_period_slowing=period_slowing;

   // set specified flag of the virtual trading
   SetVirtualTradeFlag(virtual_trade_flag);

   // set indexation of arrays like the one of timeseries
   ArraySetAsSeries(m_rates,true);
   ArraySetAsSeries(m_main_line,true);
   ArraySetAsSeries(m_signal_line,true);

   // create handle of the indicator
   m_handle=iStochastic(_Symbol,_Period,m_period_k,m_period_d,m_period_slowing,MODE_SMA,STO_LOWHIGH);
   if(m_handle<0)
     {
      Alert("Error of creating the Stochastic indicator - error number: ",GetLastError(),"!!");
      return(-1);
     }

   return(0);
  }
//+------------------------------------------------------------------+
//| Strategy Deinitialization Method                                 |
//+------------------------------------------------------------------+
int CStrategyStoch::Deinitialization()
  {
   // close all open positions
   Position_CloseOpenedPosition(m_position);
   // release handle of the indicator
   IndicatorRelease(m_handle);
   return(0);
  };
//+------------------------------------------------------------------+
//| Checking Trading Conditions and Opening Virtual Positions        |
//+------------------------------------------------------------------+
bool CStrategyStoch::CheckTradeConditions()
  {
   // call the functions of recalculation of position parameters
   RecalcPositionProperties(m_position);
   double p_close;

   // get history  data of the last 3 bars 
   if(CopyRates(_Symbol,_Period,0,3,m_rates)<0)
     {
      Alert("Error of copying history data - error:",GetLastError(),"!!");
      return(false);
     }
   // copy the current close price of the previous bar (it is bar 1)
   p_close=m_rates[1].close;  // close price of the previous bar          

   if((CopyBuffer(m_handle,0,0,3,m_main_line)<3) || (CopyBuffer(m_handle,1,0,3,m_signal_line)<3))
     {
      Alert("Error of copying buffers of the Stochastic indicator - error number:",GetLastError());
      return(false);
     }

   // buy condition: crossing the signal line by the main one from bottom up
   bool buy_condition=((m_signal_line[2]<m_main_line[2]) && (m_signal_line[1]>m_main_line[1]));
   // sell condition: crossing the signal line by the main one from top downwards
   bool sell_condition=((m_signal_line[2]>m_main_line[2]) && (m_signal_line[1]<m_main_line[1]));

   int new_state=0;

   if(buy_condition) new_state=SIGNAL_OPEN_LONG;
   if(sell_condition) new_state=SIGNAL_OPEN_SHORT;

   if((GetSignalState()==SIGNAL_OPEN_SHORT) && (buy_condition)) new_state=SIGNAL_CLOSE_SHORT;
   if((GetSignalState()==SIGNAL_OPEN_LONG) && (sell_condition)) new_state=SIGNAL_CLOSE_LONG;

   if(GetSignalState()!=new_state)
     {
      SetSignalState(new_state);
     }

   return(true);
  };

Wie Sie sehen, sind die einzigen Unterschiede zwischen der Struktur der CStrategyStoch-Klasse und der CStrategyMA-Klasse, ihre Initialisierungsfunktion (unterschiedliche Parameter), die Art des verwendeten Indikators und die Handelssignale.

Um daher Ihre Strategien im adaptiven Expert Advisor anwenden zu können, sollten Sie die Form von Klassen diesen Typs neu schreiben und sie im m_all_strategies Aufbewahrungsort ablegen.


4. Analyseergebnisse adaptiver Handelsstrategien

In diesem Abschnitt behandeln wir die verschiedenen Aspekte des praktischen Einsatzes adaptiver Strategien und stellen entspr. Verbesserungsmethoden vor.

4.1 Verbesserung des Systems mit Strategien, die mit inversen Signale arbeiten

Gleitende Mittelwerte sind nicht gut, wenn es keine Trends gibt. Wir haben diese Situation bereits gehabt: In Abb. 3 sehen Sie deutlich, dass es innerhalb des Zeitraums vom 8. - 20. Januar keinen Trend gab, und daher alle 10 Strategien, die gleitende Mittelwerte verwenden, einen virtuellen Verlust einfuhren. Das adaptive System stoppte daraufhin den Handel als Folge einer nicht vorhandenen Strategie mit einem positiven erwirtschafteten Betrag. Kann man so eine negative Auswirkung irgendwie vermeiden?

Fügen wir zu unseren 10 Strategien (MA_3, MA_13, ... MA_93) weitere 10 CStrategyMAinv Klassen hinzu, deren Handelssingale umgekehrt sind (die Bedingungen bleiben unverändert, doch SIGNAL_OPEN_LONG/SIGNAL_OPEN_SHORT und SIGNAL_CLOSE_LONG/SIGNAL_CLOSE_SHORT tauschen ihre Plätze). So haben wir hier, zusätzlich zu 10 Trend-Strategien (Instanzen der CStrategyMA-Klasse), noch weitere 10 Counter-Trend Strategien (Instanzen der CStrategyMAinv Klasse).

Abb. 5 zeigt das Ergebnis der Anwendung des adaptiven Systems aus 20 Strategien.

Abb. 5. Equity-Diagramme im Account der adaptiven Strategie unter Verwendung von 20 Handelssignalen: 10 gleitende Mittelwerte CAdaptiveMA und 10 "spiegelverkehrte" AdaptiveMAinv

Abb. 5 Equity-Diagramme im Account der adaptiven Strategie unter Verwendung von 20 Handelssignalen: 10 gleitende Mittelwerte CAdaptiveMA und 10 "spiegelverkehrte" CAdaptiveMAinv

Wie Sie in Abb. 5 sehen, ermöglichte das Befolgen der CAdaptiveMAinv Strategien dem Expert Advisor in dem Zeitraum, als alle CAdaptiveMA-Strategien nur Negativergebnisse brachten, unerwünschte Inanspruchnahme gleich zu Beginn des Handels zu vermeiden.

Abb. 6 Zeitraum in der die adaptive Strategie die Signale der "Counter-Trend" CAdaptiveMAinv Strategien verwendete

Abb. 6 Zeitraum in der die adaptive Strategie die Signale der "Counter-Trend"CAdaptiveMAinv Strategien verwendete

Diese Vorgehensweise mag nicht akzeptabel erscheinen, da bei der Anwendung der Counter-Trend Strategie der Verlust des Depots nur eine Frage der Zeit ist. In unserem Fall jedoch sind wir nicht auf eine einzige Strategie beschränkt. Der Markt weiß besser, welche Strategien im Augenblick effektiv sind.

Die Stärke bei adaptiven Systemen ist, dass der Markt selbst vorschlägt, welche Strategie angewendet werden sollte und vor allem wann.

Das schafft die Möglichkeit, sich etwas von der Logik der Strategien weg zu bewegen - ist eine Strategie effektiv, spielt es keine Rolle, wie sie funktioniert. Der adaptive Ansatz arbeitet daher mit dem einzigen Erfolgskriterium einer Strategie - ihrer Wirkung.

4.2 Lohnt es sich Signale der schlechtesten Strategie umzukehren?

Der oben dargestellte Trick der Umkehrung führt natürlich zu der Überlegung über die eventuelle Möglichkeit, die Signale der schlechtesten Strategie zu nutzen. Wenn eine Strategie nicht profitabel ist (und darin noch mit Abstand die schlechteste), könnten wir dann nicht einen Gewinn erhalten, wenn wir genau umgekehrt vorgehen?

Können wir eine Verluststrategie in eine Gewinnstrategie umwandeln, indem wir einfach eines ihre Signale verändern? Um diese Frage zu beantworten, müssen wir ArrayMaximum mit ArrayMinimum in der Expert_OnTick()Funktion der CAdaptiveStrategy Klasse tauschen und auch die Richtungsveränderung durch Multiplikation der BestDirection Variable mit -1 implementieren.

Zusätzlich müssen wir die Einschränkung des virtuellen Handels im Falle negativer Wirkung mit einem Kommentar versehen (da wir ja jetzt das Ergebnis der schlechtesten Strategie analysieren wollen):

//if((Performance[BestStrategyIndex]<0) && (RealPositionDirection()==0)) {return;}

Abb. 7 zeigt das Equity-Diagramm des adaptiven Expert Advisors, der die umgedrehten Signale der schlechtesten Strategie verwendet:

Abb. 7 Equity-Diagramme in den Accounts der 10 Strategien und das adaptive System, das die umgedrehten Signale der schlechtesten Systems verwendet

Abb. 7 Equity-Diagramme in den Accounts der 10 Strategien und das adaptive System, das die umgedrehten Signale der schlechtesten Systems verwendet

In diesem Fall war die meiste Zeit über die am wenigsten erfolgreiche Strategie diejenige, die auf der Überschneidung des gleitenden Mittelwerts mit Zeitraum 3 (MA_3) basierte. Wie Sie in Abb. 7 ablesen können, besteht die umgekehrte Korrelation zwischen MA_3 (blau gefärbt) und der adaptiven Strategie (rot gefärbt), doch das finanzielle Ergebnis des adaptiven System ist nicht wirklich toll.

Die Signale der schlechtesten Strategie zu kopieren (und umzukehren), führt zu keiner Verbesserung der Handelseffektivität.

4.2 Warum der Haufen gleitender Mittelwerte nicht so wirkungsvoll ist, wie es zunächst aussieht

Anstelle von 10 gleitenden Mittelwerten können Sie unglaublich viele davon verwenden, indem Sie noch weitere Hundert CStrategyMA Strategien mit unterschiedlichen Zeiträumen in den m_all_strategies Aufbewahrungsort platzieren.

Dazu muss der Code in der CAdaptiveStrategy Klasse leicht verändert werden:

   for(int i=0; i<100; i++)
     {
      CStrategyMA *t_StrategyMA;
      t_StrategyMA=new CStrategyMA;
      if(t_StrategyMA==NULL)
        {
         delete m_all_strategies;
         Print("Error of creation of object of the CStrategyMA type");
         return(-1);
        }
      //set period for each strategy
      int period=3+i*10;
      // initialization of strategy
      t_StrategyMA.Initialization(period,true);
      // set details of the strategy
      t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period));
      //add the object of the strategy to the array of objects m_all_strategies
      m_all_strategies.Add(t_StrategyMA);
     }

Hierbei sollten Sie jedoch wissen, dass sich eng nebeneinander liegende, gleitende Mittelwerte automatisch überschneiden, der Führer sich ständig ändert und das adaptive System seine Stati ebenfalls andauernd verändert und Positions häufiger als notwendig öffnet/schließt. Die Folge davon ist, dass die Charakteristika des adaptiven Systems schwammiger werden. Sie können sich davon selbst überzeugen, indem Sie die statistischen Charakteristika des Systems miteinander vergleichen (der "Ergebnisse"-Tab des Strategie-Testers).

Es ist weitaus besser, dass ein adaptives System auf vielen Strategien mit engen Parametern beruht.


5. Was man bedenken sollte

Der Aufbewahrungsort m_all_strategies kann Tausende Instanzen vorgeschlagener Strategien haben. Sie können sogar alle Strategien mit unterschiedlichen Parametern hinzufügen. Doch wenn Sie den Automated Trading Wettbewerb 2010 gewinnen wollen, müssen Sie ein fortgeschrittenes System zur Geldverwaltung entwickeln. Erinnern Sie sich daran, dass wir das Handelsvolumen = 0,1 Posten zum Test vor historischen Daten (und im Code der Klassen) verwendet haben.

5.1 Wie man die Profitabilität des adaptiven Expert Advisors erhöht

Die CSampleStrategy Klasse besitzt die virtuelle Funktion MoneyManagement_CalculateLots:

//+------------------------------------------------------------------+
//| The function returns the recommended volume for a strategy       |
//| Current volume is passed to it as a parameter                    |
//| Volume can be set depending on:                                  |
//| current m_virtual_balance and m_virtual_equity                   |
//| current statistics of deals (located in m_deals_history)         |
//| or any other thing you want                                      |
//| If a strategy doesn't require change of volume                   |
//| you can return the passed value of volume:  return(trade_volume);|
//+------------------------------------------------------------------+ 
double CSampleStrategy::MoneyManagement_CalculateLots(double trade_volume)
  {
   //return what we've got 
   return(trade_volume);
  }

Zur Verwaltung des Volumens für den Handel können Sie die statistische Information über die Ergebnisse und Charakteritika der virtuellen Abschlüsse verwenden, die im m_deals_history[] Array aufgezeichnet ist.

Wenn Sie das Volumen erhöhen (z.B. verdoppeln, falls die letzten virtuellen Abschlüsse in m_deals_history[] profitabel sind) oder reduzieren müssen, sollten Sie die gelieferten Werte entsprechend auch verändern.

5.2 Verwendung der Abschlüsse-Statistik zur Berechnung der Strategie-Leistung

Die Funktion StrategyPerformance(), die in der CSampleStrategy Klasse implementiert ist, dient zur Berechnung der Strategie-Leistung.

//+-----------------------------------------------------------------------+
//| Function StrategyPerformance - the function of strategy effectiveness |
//+-----------------------------------------------------------------------+ 
double CSampleStrategy::StrategyPerformance()
  {
   //returns effectiveness of a strategy
   //in this case it's the difference between the amount
   //of equity at the moment and the initial balance, 
   //i.e. the amount of assets earned by the strategy
   double performance=(m_virtual_equity-m_initial_balance);
   return(performance);
  }

Die Effektivitätsformel einer Strategie kann komplexer sein, und z.B. die Effektivität des Einstiegs, Ausstiegs sowie Effektivität der Abschlüsse, Gewinne, Inanspruchnahme usw. enthalten.

Die Berechnung der Effektivität des Einstiegs, Ausstiegs und der Effektivität der Abschlüsse (die entry_eff, exit_eff und trade_eff Struktur-Felder des m_deals_history[] Arrays) wird während des virtuellen Handels automatisch ausgeführt (vgl. die CSampeStrategy Klasse). Die statistische Information kann zur Erstellung Ihrer eigenen, komplexeren Strategie-Effektivitätsgrade verwendet werden.

So können Sie z.B. als ein Merkmal für Effektivität den Gewinn der letzten drei Abschlüsse verwenden (dazu das pos_Profit Feld aus dem Archiv der Abschlüsse m_deals_history[] verwenden):

double CSampleStrategy::StrategyPerformance()
  {
  //if there are deals, multiply this value by the result of three last deals
   if(m_virtual_deals_total>0)
     {
      int avdeals=MathRound(MathMin(3,m_virtual_deals_total));
      double sumprofit=0;
      for(int j=0; j<avdeals; j++)
        {
         sumprofit+=m_deals_history[m_virtual_deals_total-1-j].profit;
        }
      double performance=sumprofit/avdeals;
     }
     return(performance);

  }

Wollen Sie diese Funktion verändern, machen Sie das bitte nur in der CSampleStrategy Klasse, denn sie muss für alle Handelsstrategien des adaptiven Systems immer die gleiche sein. Sie sollten dabei jedoch nicht vergessen, dass die Differenz zwischen Equity (Eigenkaptial) und Balance (Saldo) auch ein guter Effektivitätfaktor ist.

5.3 Verwendung von Take Profit und Stop Loss

Die Effektivität von Handelssystemen können Sie auch durch das Einrichten von festen Stop-Levels verändern (dies geschieht durch Aufruf der Set_Stops Funktion; sie gestattet das Einrichten von Stop-Levels in Punkten für virtuelles Handeln). Sind alle Levels angegeben, erfolgt das Schließen virtueller Positions automatisch. Diese Funktion ist in der CSampleStrategy Klasse implementiert.

In unserem Beispiel (vgl. 2.2 'die Funktion der Klassen gleitender Mittelwerte), ist die Funktion für das Einrichten von Stop-Levels kommentiert.

5.4 Periodisches Nullen kumulativen virtuellen Gewinns

Der adaptive Ansatz birgt die gleichen Nachteile wie auch herkömmliche Strategien. Denn wenn die führende Strategie Minus zu machen beginnt, dann gilt das auch für das adaptive System. Aus diesem Grund muss man manchmal die Arbeitsergebnisse aller Strategien "nullen" und all ihre virtuellen Positions schließen. 

Dazu sind die folgenden Funktionen in der CSampleStrategy Klasse implementiert:

// sets a value for cumulative "virtual profit"
 void              SetVirtualCumulativeProfit(double cumulative_profit) { m_virtual_cumulative_profit=cumulative_perofit; };
//closes an open virtual position
 void              CloseVirtualPosition();

CheckPoint dieser Art kann von Zeit zu Zeit verwendet werden, z.B. nach jeden N Bars.

5.5 Erwarten Sie keine Wunder

Das adaptive System ist kein heiliger Gral - das sollten Sie stets vor Augen haben (USDJPY H1, 4. 01. 2010 - 20. 08. 2010):

Abb. 8 Saldo- und Equity-Kurven des adaptiven Systems unter Verwendung der Signale der besten der 10 Strategien (USDJPY H1)

Abb. 8 Saldo- und Equity-Kurven des adaptiven Systems unter Verwendung der Signale der besten der 10 Strategien (USDJPY H1)

Abb. 9 zeigt die Equity-Kurven aller Strategien

Abb. 9 Equity-Kurven im Account mit dem adaptiven System auf Grundlage von 10 Strategien (USDJPY H1)

Abb. 9 Equity-Kurven im Account mit dem adaptiven System auf Grundlage von 10 Strategien (USDJPY H1)

Gibt es im adaptiven System keine profitablen Strategien, sollte man die Finger davon lassen - viel zu ineffektiv. Arbeiten Sie lieber mit profitablen Strategien.

An dieser Stelle sollten wir uns noch etwas Wichtiges und Interessantes ansehen: Achten Sie darauf, wie sich die adaptive Strategie ganz zu Anfang des Handels verhält:

Abb. 10 Equity-Kurven im Account mit 10 Strategien der adaptiven Strategie

Abb. 10 Equity-Kurven im Account mit 10 Strategien der adaptiven Strategie

Zuerst hatten alle Strategien negative Ergebnisse und die adaptive Strategie stoppte den Handel. Dann begann sie zwischen Strategien mit einem positiven Ergebnis hin- und herzuwechseln, und schließlich wurden alle Strategien wieder nicht profitabel.

Zu Beginn weisen alle Strategien das gleiche Saldo aus. Und es dauert eine Weile, bis die eine oder andere Strategie die 'Führung' übernimmt. Daher ist es ratsam in der adaptiven Strategie eine Beschränkung einzurichten, um Handel an den ersten Bars zu vermeiden. Dazu müssen Sie die Expert_OnTick Funktion der CAdaptiveStrategy Klasse mit einer Variable ergänzen, deren Wert sich bei jedem Erscheinen eines neuen Bars erhöht.

Bevor der Markt nicht die beste Strategie gewählt hat, sollten Sie von echtem Handel Abstand nehmen.


Fazit

In diesem Beitrag haben wir uns ein Beispiel des adaptiven Systems angesehen, das aus vilen Strategien besteht, von denen jede ihre eigenen "virtuellen" Handels-Operationen durchführt. Echter Handel wird gemäß den Signalen der im Augenblick profitabelsten Strategie ausgeführt.

Dank des Einsatzes des Objekt-orientierten Ansatzes, der Klassen zur Arbeit mit Daten und den Handelsklassen der Standard-Bibliothek, scheint die System-Architektur einfach und aufrüstbar. Jetzt können Sie die adaptiven Systeme, die Hunderte von Handelsstrategien umfassen, problemlos selbst erzeugen und analysieren.

P.S. Für eine bequeme Analyse des Verhaltens von adaptiven Systemen, ist die Debug-Version der CSampleStrategy Klasse angehängt das adaptive-systems-mql5-sources-debug-en.zip Archiv). Der Unterschied dieser Version liegt in der Erzeugung von Textdateien während ihrer Arbeit. Sie enthalten Zusammenfassungen der Dynamiken der Änderungen von virtuellem Balance/Equity (Saldo/Eigenkapital) der im System mit eingeschlossenen Strategien.