
Adaptive Handelssysteme und ihre Verwendung im MetaTrader 5 Client-Terminal
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
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
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
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
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.
- Funktion Initialization. Hier wird die Strategie initialisiert. Wenn Sie Indikatoren erzeugen müssen, dann hier.
- Funktion Deinitialization. Hier wird die Strategie de-initialisiert. Indikator-Identifikatoren werden hier freigegeben.
- Funktion СheckTradeConditions. Hier prüft die Strategie die Handelsbedingungen und erzeugt Handelssignale, die für virtuellen Handel verwendet werden. Zur Ausführung virtueller Handels-Operationen wird die SetSignalState Funktion der übergeordneten CStrategy Klasse aufgerufen - und eines von vier der folgenden Handelssignale wird an sie übertragen:
- Das Signal zum Öffnen einer Long Position (SIGNAL_OPEN_LONG)
- Das Signal zum Öffnen einer Short Position (SIGNAL_OPEN_SHORT)
- Das Signal zum Schließen einer Long Position (SIGNAL_CLOSE_LONG)
- 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" 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
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
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. 9 zeigt die Equity-Kurven aller Strategien
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
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.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/143





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.