English Русский 中文 Español 日本語 Português
preview
Techniken des MQL5-Assistenten, die Sie kennen sollten (Teil 03): Shannonsche Entropie

Techniken des MQL5-Assistenten, die Sie kennen sollten (Teil 03): Shannonsche Entropie

MetaTrader 5Tester | 3 Oktober 2022, 11:32
253 0
Stephen Njuki
Stephen Njuki

Einführung

Claude Shannon veröffentlichte 1948 seinen Aufsatz „A mathematical theory of communication“ (Eine mathematische Theorie der Kommunikation), das eine neuartige Idee der Informationsentropie enthielt. Entropie ist ein Begriff aus der Physik. Sie ist ein Maß dafür, inwieweit Teilchen innerhalb eines Objekts aktiv sind. Betrachtet man beispielsweise die drei Zustände von Wasser, nämlich Eis, Flüssigkeit und Dampf, so stellt man fest, dass die kinetische Energie der Teilchen im Dampf am höchsten und im Eis am niedrigsten ist. Das gleiche Konzept wird in der Mathematik über die Wahrscheinlichkeit angewandt. Betrachten Sie die folgenden drei Sätze.

Satz 1: 

Set 1


Satz 2: 

Set 2


Satz 3: 

Set 3


Wenn Sie raten müssten, welche dieser Mengen weist die höchste Entropie auf? 
Wenn Sie sich für die letzte Variante entschieden haben, haben Sie Recht, aber wie können wir diese Antwort überprüfen? Am einfachsten lässt sich diese Frage beantworten, indem man die Anzahl der Möglichkeiten, jede Menge neu zu organisieren, als Entropieschätzung verwendet und dabei ähnliche Farbabschnitte ignoriert. Für die erste Menge gibt es daher nur eine Möglichkeit, sie „neu zu ordnen“. Wenn wir uns jedoch die nachfolgenden Mengen ansehen, nimmt die Anzahl der Permutationen in Bezug auf die Farbe deutlich zu, so dass man argumentieren könnte, dass die letzte Menge die höchste Entropie aufweist. 

Es gibt eine genauere Methode zur Bestimmung der Entropie, die auf Informationen basiert. Wenn jemand willkürlich einen Ball aus dem ersten Satz auswählen würde, bevor er diesen Ball auswählt, was würde er über ihn wissen? Da das Satz nur blaue Kugeln enthält, kann man sicher sein, dass es eine blaue Kugel ist. Man könnte also sagen, ich habe vollständige Informationen darüber, was ich aus Set 1 auswählen werde. Wenn wir die Sets 2 und 3 betrachten, werden unsere Informationen immer unvollständiger. In der Mathematik steht die Entropie daher in umgekehrtem Verhältnis zur Information. Je höher die Entropie ist, desto mehr Unbekannte gibt es.  

Wie lässt sich nun eine Formel zur Berechnung der Entropie herleiten? Betrachtet man die Mengen noch einmal, so ist die Entropie umso höher, je größer die Vielfalt der Kugeltypen innerhalb einer Menge ist. Der empfindlichste Faktor bei der Messung der Informationen, die wir über eine Kugel vor ihrer Auswahl haben, könnte die Wahrscheinlichkeit der Auswahl jeder Kugel in einer Menge sein. Wenn wir also jeden Satz in seiner Gesamtheit betrachten und die Wahrscheinlichkeit der Auswahl von 8 Kugeln ermitteln, wobei jede Farbe so oft ausgewählt wird, wie sie in ihrem Satz vorkommt, da die Auswahl jeder Kugel ein unabhängiges Ereignis ist, dann ist die Wahrscheinlichkeit (und damit die „bekannte Information“) für jeden Satz das Produkt der individuellen Wahrscheinlichkeiten für jede Kugel.  

Satz 1: 

(1,0 x 1,0 x 1,0 x 1,0 x 1,0 x 1,0 x 1,0 x 1,0) = 1,0 


Satz 2: 

(0,625 x 0,625 x 0,625 x 0,625 x 0,625 x 0,375 x 0,375 x 0,375) ~ 0,0050 


Satz 3: 

(0,375 x 0,375 x 0,375 x 0,25 x 0,25 x 0,25 x 0,25 x 0,125) ~ 0,000025 


Mit zunehmender Größe und Vielfalt einer Menge werden die Wahrscheinlichkeitswerte zu klein, um mit ihnen arbeiten zu können, weshalb Logarithmen, insbesondere negative Logarithmen dieser Wahrscheinlichkeiten, bei der Messung der Entropie berücksichtigt werden, da sie, wie oben gezeigt, umgekehrt proportional zur bekannten Information ist. Diese Identitätsgleichung ist die Grundlage für die Normalisierung: 


Gleichung_1


Der Logarithmus wird mit dem negativen Wert 1 multipliziert, da der Logarithmus von Zahlen kleiner als 1 negativ ist. Tatsächlich lautet die Entropieformel nach Wikipedia


Gleichung_2


Das ist die Summe der Produkte aus Wahrscheinlichkeiten und ihrem Logarithmus. Um unsere Entropien zu berechnen; 


Satz 1: 

-(8 x 0,125 x log2(1,0)) = 0,0 


Satz 2: 

(-(0,625 x log2(0,625)) - (0,375 x log2(0,375))) ~ 0.9544 


Satz 3: 

(- (0,375 x log2(0,375)) - (2 x 0,25 x log2(0,25)) - (0,125 x log2(0,125))) ~ 1.906 


Es wurde gezeigt, dass die durchschnittliche Anzahl der binären Fragen, die benötigt werden, um die Farbe einer zufällig aus einer Menge ausgewählten Kugel zu bestimmen, die Entropie der Menge ist. Außerdem ist die maximale Entropie für einen Satz von n Werten:

Gleichung_3

Dieser Maximalwert ist nützlich für die Normalisierung der Entropiewerte bei der Erzeugung von Signalen, die zwischen 0,0 und 1,0 liegen. Für einen Händler kann die Entropie des Kursverlaufs als Indikator dafür dienen, ob aus diesem Verlauf ein zuverlässiges Handelssignal verarbeitet werden kann. Aber angenommen, wir würden die Entropie selbst zur Erzeugung von Signalen nutzen? Nehmen wir an, dass die Entropie fallender Balken größer ist als die steigender Balken innerhalb einer bestimmten Anzahl neuer Balken, was auf ein Kaufsignal hindeutet und umgekehrt. Schauen wir uns an, wie dies als Expertensignal für den MQL5-Assistenten kodiert werden kann.


2.0 Erstellen der Klasse

Für diesen Artikel werden wir die Klasse Decision Forest (‚Entscheidungswald‘) aus der MQL5-Bibliothek verwenden. Konkret werden wir die Idee des Random Forest (ein ‚Zufallswald‘ aus unkorrelierten Entscheidungsbäumen) abstrahieren, um die Wirksamkeit unseres Shannon-Entropie-Signals zu untersuchen. In diesem Artikel geht es nicht um Random Forest, sondern um die Shannonsche Entropie. 

Betrachten wir noch einmal die Klasse von Random Forest, da sie die Grundlage für das Modell eines Random Forest ist. Das ist auch gut so, denn Entscheidungswälder sind ziemlich charakteristisch. Wir alle haben schon einmal wissentlich oder unwissentlich einen Entscheidungsbaum verwendet, und daher ist das Konzept an sich nicht ungewöhnlich.

f_d




Schauen wir uns ein Beispiel an, um zu verdeutlichen, wie eine solche Funktion funktioniert.

Angenommen, unser Datensatz besteht aus den oben genannten Preisbalken. Wir haben drei fallende Kerzen und fünf steigende Kerzen (wir nehmen bärische und bullische Märkte als unsere Klassen) und wollen die Klassen anhand ihrer Attribute trennen. Die Attribute sind die Kursrichtung und der Vergleich von Kopf- zu Schwanzlänge, da diese Vorläufer für Richtungsänderungen sein können. Wie können wir dies also tun?

Die Preisrichtung scheint ein einfaches Attribut zu sein, da weiß für bärische Kerzen und blau für bullische Kerzen steht. Wir können also die Frage „Fällt der Preis?“ verwenden, um die erste Entscheidung zu treffen. Ein Knotenpunkt in einem Baum ist der Punkt, an dem sich ein Zweig in zwei Teile teilt, die die Kriterien für die Auswahl des Ja- und des Nein-Zweigs erfüllen.

Beim Nein-Zweig (steigende Kerzen) sind die unteren Dochte länger als die oberen, sodass wir hier fertig sind, aber beim Ja-Zweig ist dies nicht der Fall, so dass noch mehr Arbeit zu tun ist. Wenn wir das zweite Attribut verwenden, fragen wir: „Ist obere Docht länger andere?“, um eine zweite Entscheidung zu treffen.

Die beiden Abwärtskerzen mit längeren oberen Dochten werden dem Ja-Zweig zugeordnet und eine Abwärtskerze mit einem längeren unteren Docht wird dem rechten Unterzweig zugeordnet. Dieser Entscheidungsbaum war in der Lage, die beiden Attribute zu verwenden, um die Daten perfekt nach unseren Kriterien aufzuteilen. 

In echten Handelssystemen können Tick-Volumen, Tageszeit und eine Vielzahl anderer Handelsindikatoren zum Aufbau eines umfassenderen Entscheidungsbaums verwendet werden. Nichtsdestotrotz besteht die zentrale Prämisse jeder Frage an einem Knotenpunkt darin, das eine Attribut zu finden, das die obigen Daten in zwei unähnliche Mengen aufteilt (oder klassifiziert), wobei die erstellten Mitglieder jeder Menge ähnlich sind.

Der Random Forest besteht, wie der Name schon sagt, aus einer großen Anzahl von einzelnen Entscheidungsbäumen, die als Gruppe arbeiten. Für jeden Baum des Random Forest wird eine Klassenvorhersage gemacht, und die Klasse mit den meisten Stimmen wird als Vorhersage des Modells ausgewählt. Das Hauptkonzept hinter Random Forest ist leicht zu übersehen, aber es ist sehr wirkungsvoll - die Weisheit der Masse. Bei der Erstellung von Vorhersagen sind unkorrelierte Bäume den einzelnen Bäumen überlegen, unabhängig davon, auf wie vielen Daten die einzelnen Bäume trainiert wurden. Die Krux ist eine geringe Korrelation. Der Grund dafür ist, dass sich die Bäume nach Ton gegenseitig vor ihren individuellen Fehlern schützen (solange sie nicht ständig alle in dieselbe Richtung irren). Damit ein Random Forest funktioniert, muss das Vorhersagesignal besser als der Durchschnitt sein und die Fehler der einzelnen Bäume müssen eine geringe Korrelation zueinander aufweisen.

Wenn Sie zum Beispiel zwei Handelssysteme hätten, bei denen Sie im ersten bis zu eintausend Ein-Dollar-Marge-Aufträge in einem Jahr platzieren können und im anderen nur einen 1000-Dollar-Marge-Auftrag, welches würden Sie vorziehen, wenn Sie eine ähnliche Erwartung hätten? Für die meisten Menschen ist es das erste System, da es dem Händler „mehr Kontrolle“ gibt. 

Auf welche Weise stellen Random-Forest-Algorithmen also sicher, dass das Merkmal jedes einzelnen Baumes nicht zu stark mit dem Merkmal eines der anderen Bäume im Wald korreliert? Es könnte auf zwei Merkmale hinauslaufen:

Bagging

Entscheidungsbäume reagieren sehr empfindlich auf Trainingsdaten, und kleine Änderungen können zu deutlich unterschiedlichen Random Forest führen. Random Forest macht sich dies zunutze, indem jeder Baum während des Ersetzens zufällige Stichproben aus dem Datensatz zieht, was zu unterschiedlichen Bäumen führt. Dieser Prozess wird als Bagging (‚einsacken‘) bezeichnet, eine Abkürzung für Bootstrap-Aggregation.

Beachten Sie, dass wir beim Bagging die Trainingsdaten nicht in kleinere Sätze aufteilen, sondern anstelle der ursprünglichen Trainingsdaten eine Zufallsstichprobe der Größe N mit einigen Ersetzungen nehmen. Die anfängliche Mengengröße N wird beibehalten. Wenn unsere Trainingsdaten zum Beispiel [U, V, W, X, Y, Z] lauten, könnten wir einem unserer Bäume die folgende Liste [U, U, V, X, X, Z] geben. In beiden Listen wird die Größe N (sechs) beibehalten, und sowohl „U“ als auch „X“ werden in den zufällig ausgewählten Daten wiederholt.


2.0.2 Das Merkmal der Zufälligkeit

In einem Entscheidungsbaum werden bei der Aufteilung des Knotens in der Regel alle möglichen Merkmale berücksichtigt und dasjenige ausgewählt, das den größten Unterschied zwischen den Beobachtungen im linken und im rechten Knoten ergibt. Bei einem Zufallsforst hingegen kann jeder Baum nur aus einer zufälligen Teilmenge von Merkmalen auswählen. Dies führt zu einer größeren Variation innerhalb des Waldes und letztlich zu einer geringeren Korrelation zwischen den Bäumen und einer größeren Diversifizierung.

Gehen wir ein visuelles Beispiel durch - in der obigen Abbildung kann der herkömmliche Entscheidungsbaum (in blau) aus allen vier Merkmalen auswählen, wenn er entscheidet, wie der Knoten zu teilen ist. Er entscheidet sich für Merkmal 1 (schwarz und unterstrichen), da es die Daten in möglichst getrennte Gruppen aufteilt.

Werfen wir nun einen Blick auf unseren Random Forest. Wir werden in diesem Beispiel nur zwei Bäume des Waldes untersuchen. Wenn wir den Random Forest Baum 1 überprüfen, stellen wir fest, dass er nur die (zufällig ausgewählten) Merkmale 2 und 3 für seine Knotenaufteilungsentscheidung berücksichtigen kann. Aus unserem traditionellen Entscheidungsbaum (in blau) wissen wir, dass Merkmal 1 das beste Merkmal für die Aufteilung ist, aber Baum 1 kann Merkmal 1 nicht sehen, sodass er gezwungen ist, sich für Merkmal 2 (schwarz und unterstrichen) zu entscheiden. Baum 2 hingegen kann nur die Merkmale 1 und 3 sehen und ist daher in der Lage, das Merkmal 1 auszuwählen.

In einem Random Forest werden Bäume nicht nur auf Datensätzen trainiert (dank Bagging), sondern verwenden auch eine Vielzahl von Merkmalen, um Entscheidungen zu treffen.



s_d



Bei der Verwendung von Random Forests verarbeiten unsere Experten vergangene Handelsergebnisse und Marktsignale, um eine Kauf- oder Verkaufsentscheidung zu treffen. Um ein Signal und nicht nur einen Test der Entropie zu erhalten, werden wir die Entropie positiver Preisbalken und die Entropie negativer Preisbalken innerhalb eines aktuellen Sets getrennt betrachten. 

Die Erstellung und das Training von Zufallswäldern erfolgt nur bei der Optimierung mit einem einzigen Thread.

2.1 Signalklasse für einen Experten

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of'Shannon Entropy'                                |
//| Type=SignalAdvanced                                              |
//| Name=Shannon Entropy                                             |
//| ShortName=SE                                                     |
//| Class=CSignalSE                                                  |
//| Page=signal_se                                                   |
//| Parameter=Reset,bool,false,Reset Training                        |
//| Parameter=Trees,int,50,Trees number                              |
//| Parameter=Regularization,double,0.15,Regularization Threshold    |
//| Parameter=Trainings,int,21,Trainings number                      |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalSE.                                                 |
//| Purpose: Class of generator of trade signals based on            |
//|          the 'Shannon Entropy' signals.                          |
//| Is derived from the CExpertSignal class.                         |
//+------------------------------------------------------------------+
class CSignalSE : public CExpertSignal
   {
      public:
         
         //Decision Forest objects.
         CDecisionForest               DF;                                                   //Decision Forest
         CMatrixDouble                 DF_SIGNAL;                                            //Decision Forest Matrix for inputs and output
         CDFReport                     DF_REPORT;                                            //Decision Forest Report for results
         int                           DF_INFO;                                              //Decision Forest feedback

         double                        m_out_calculations[2], m_in_calculations[__INPUTS];   //Decision Forest calculation arrays

         //--- adjusted parameters
         bool                          m_reset;
         int                           m_trees;
         double                        m_regularization;
         int                           m_trainings;
         //--- methods of setting adjustable parameters
         void                          Reset(bool value){ m_reset=value; }
         void                          Trees(int value){ m_trees=value; }
         void                          Regularization(double value){ m_regularization=value; }
         void                          Trainings(int value){ m_trainings=value; }
         
         //Decision Forest FUZZY system objects
         CMamdaniFuzzySystem           *m_fuzzy;
         
         CFuzzyVariable                *m_in_variables[__INPUTS];
         CFuzzyVariable                *m_out_variable;

         CDictionary_Obj_Double        *m_in_text[__INPUTS];
         CDictionary_Obj_Double        *m_out_text;

         CMamdaniFuzzyRule             *m_rule[__RULES];
         CList                         *m_in_list;

         double                        m_signals[][__INPUTS];
         
         CNormalMembershipFunction     *m_update;
         
         datetime                      m_last_time;
         double                        m_last_signal;
         double                        m_last_condition;

                                       CSignalSE(void);
                                       ~CSignalSE(void);
         //--- method of verification of settings
         virtual bool                  ValidationSettings(void);
         //--- method of creating the indicator and timeseries
         virtual bool                  InitIndicators(CIndicators *indicators);
         //--- methods of checking if the market models are formed
         virtual int                   LongCondition(void);
         virtual int                   ShortCondition(void);

         bool                          m_random;
         bool                          m_read_forest;
         int                           m_samples;

         //--- method of initialization of the oscillator
         bool                          InitSE(CIndicators *indicators);
         
         double                        Data(int Index){ return(Close(StartIndex()+Index)-Close(StartIndex()+Index+1)); }
         
         void                          ReadForest();
         void                          WriteForest();
         
         void                          SignalUpdate(double Signal);
         void                          ResultUpdate(double Result);
         
         double                        Signal(void);
         double                        Result(void);
         
         bool                          IsNewBar(void);
  };

 

2.1.1 Signale

Diese Entropie wird mit dem Index für die Aktualität gewichtet. 

            if(_data>0.0)
            {
               _long_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }
            else if(_data<0.0)
            {
               _short_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }

Und sie wird auch nach der Größe der Preisbalken gewichtet werden.

            if(_data>0.0)
            {
               _long_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }
            else if(_data<0.0)
            {
               _short_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }

Das erzeugte Signal ist die Entropie der negativen Balken minus die Entropie der positiven Balken. Wenn die Entropie der negativen Balken die der positiven Balken übersteigt, haben wir weniger Informationen über die negativen Balken und damit eine Verkaufsposition als über die positiven Balken, die ebenfalls eine Kaufposition bedeuten. Oberflächlich betrachtet scheint es sich um ein „gefährliches“ Trendfolgesystem zu handeln! Aufgrund der Gewichtungen, die oben bei der Berechnung der Entropie vorgenommen wurden, ist dies jedoch nicht unbedingt der Fall.

Die Signale werden aktualisiert, wenn die Kauf- und Verkaufs-Bedingung den Schwellenwert für die Eröffnung überschreitet, da dies bedeutet, dass eine Position eröffnet wird. Dies wird mit einer Zeitschaltuhr geschehen, sodass wir den Assistenten, der den Experten zusammenstellt, entsprechend anpassen werden.

//+------------------------------------------------------------------+
//| "Timer" event handler function                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(PositionSelect(Symbol()) && Signal_ThresholdClose<=fabs(filter0.m_last_condition))
     {
      filter0.ResultUpdate(filter0.Result());
     }
   //
   if(!PositionSelect(Symbol()) && Signal_ThresholdOpen<=fabs(filter0.m_last_condition))
     {
      filter0.SignalUpdate(filter0.m_last_signal);
     }
   ExtExpert.OnTimer();
  }

Die Quellfunktion in der Klasse wird, wie bereits erwähnt, nur bei der Optimierung ausgeführt.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+  
void CSignalSE::SignalUpdate(double Signal)
   {
      if(MQLInfoInteger(MQL_OPTIMIZATION))
      {
         m_samples++;
         DF_SIGNAL.Resize(m_samples,__INPUTS+2);
         
         for(int i=0;i<__INPUTS;i++)
         {
            DF_SIGNAL[m_samples-1].Set(i,m_signals[0][i]);
         }
         //
         DF_SIGNAL[m_samples-1].Set(__INPUTS,Signal);
         DF_SIGNAL[m_samples-1].Set(__INPUTS+1,1-Signal);    
      }
   }

 

2.1.2 Ergebnisse

Die Ergebnisse basieren auf dem Gewinn der letzten geschlossenen Position.  

      if(HistorySelect(0,m_symbol.Time()))
      {
         int _deals=HistoryDealsTotal();
         
         for(int d=_deals-1;d>=0;d--)
         {
            ulong _deal_ticket=HistoryDealGetTicket(d);
            if(HistoryDealSelect(_deal_ticket))
            {
               if(HistoryDealGetInteger(_deal_ticket,DEAL_ENTRY)==DEAL_ENTRY_OUT)
               {
                  _result=HistoryDealGetDouble(_deal_ticket,DEAL_PROFIT);
                  break;
               }
            }
         }
      }
   
      return(_result);

Und sie werden aktualisiert, wenn die Kauf- und Verkaufs-Bedingung den Schwellenwert für das Schließen überschreitet, da dies bedeutet, dass eine Position geschlossen wird. Auch dies geschieht, wie oben beschrieben, über einen Zeitgeber, wobei die Klassenfunktion die Entscheidungswalddateien nur bei der Optimierung aktualisiert.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+  
void CSignalSE::ResultUpdate(double Result)
   {
      if(MQLInfoInteger(MQL_OPTIMIZATION))
      {
         int _err;
         if(Result<0.0) 
         {
            double _odds = MathRandomUniform(0,1,_err);
            //
            DF_SIGNAL[m_samples-1].Set(__INPUTS,_odds);
            DF_SIGNAL[m_samples-1].Set(__INPUTS+1,1-_odds);
         }
      }
   }


2.1.3 Erstellen eines Forest

Der Wald wird bei jedem Tick geschrieben, bevor er gelesen wird, also ändern wir den Assistenten, der den Experten zusammenstellt, um dies zu berücksichtigen. 

//+------------------------------------------------------------------+
//| "Tick" event handler function                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!signal_se.m_read_forest) signal_se.WriteForest();
   
   ExtExpert.OnTick();
  }


2.1.4 Lesen des Forest

Der Wald wird am Ende eines Testerdurchlaufs vom Tester gelesen, daher ändern wir den Assistenten, der den Experten zusammenstellt, um dies zu berücksichtigen. 

//+------------------------------------------------------------------+
//| "Tester" event handler function                                  |
//+------------------------------------------------------------------+  
double OnTester()
   {
    signal_se.ReadForest();
    return(0.0);
   }


2.2 Die Klasse Expert Money

In diesem Artikel befassen wir uns auch mit der Erstellung einer nutzerdefinierten Positionsgrößenklasse, die mit dem Assistenten verwendet werden kann. Wir nehmen die Klasse „Money Size Optimized“ und ändern sie, um die Positionsgrößen auf der Grundlage der Shannon-Entropie zu normalisieren. Unsere neue Schnittstelle wird wie folgt aussehen: 

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trading with 'Shannon Entropy' optimized trade volume      |
//| Type=Money                                                       |
//| Name=SE                                                          |
//| Class=CMoneySE                                                   |
//| Page=money_se                                                    |
//| Parameter=ScaleFactor,int,3,Scale factor                         |
//| Parameter=Percent,double,10.0,Percent                            |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CMoneySE.                                                  |
//| Purpose: Class of money management with 'Shannon Entropy' optimized volume.          |
//|              Derives from class CExpertMoney.                    |
//+------------------------------------------------------------------+
class CMoneySE : public CExpertMoney
  {
protected:
   int               m_scale_factor;

public:
   double            m_absolute_condition;
   
                     CMoneySE(void);
                    ~CMoneySE(void);
   //---
   void              ScaleFactor(int scale_factor) { m_scale_factor=scale_factor; }
   void              AbsoluteCondition(double absolute_condition) { m_absolute_condition=absolute_condition; }
   virtual bool      ValidationSettings(void);
   //---
   virtual double    CheckOpenLong(double price,double sl);
   virtual double    CheckOpenShort(double price,double sl);

protected:
   double            Optimize(double lots);
  };

 Die Variable „m_absolute_condition“ ist der absolute Wert der Ganzzahl(en), die von den Funktionen „LongCondition“ und „ShortCondition“ zurückgegeben werden. Da es sich um einen normalisierten Wert handelt, können wir seine Größe zur Proportionierung unserer Positionsgröße verwenden. Diese Variable wird von der Signalklasse an die Geldklasse weitergegeben, und zwar über Änderungen am vom Assistenten zusammengestellten Experten.

//+------------------------------------------------------------------+
//| Global expert object                                             |
//+------------------------------------------------------------------+
CExpert ExtExpert;
CSignalSE *signal_se;
CMoneySE *money_se;

Und in der Funktion OnTick()

//+------------------------------------------------------------------+
//| "Tick" event handler function                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!signal_se.m_read_forest) signal_se.WriteForest();
   
   money_se.AbsoluteCondition(fabs(signal_se.m_last_condition));
   
   ExtExpert.OnTick();
  }

Die wichtigsten Änderungen werden in der Funktion „Optimize“ unten vorgenommen: 

//+------------------------------------------------------------------+
//| Optimizing lot size for open.                                    |
//+------------------------------------------------------------------+
double CMoneySE::Optimize(double lots)
  {
   double lot=lots;
   
      //--- normalize lot size based on magnitude of condition
      lot*=(20*m_scale_factor/fmax(20.0,((100.0-m_absolute_condition)/100.0)*20.0*m_scale_factor*m_scale_factor));
      
      //--- reduce lot based on number of losses orders without a break
      if(m_scale_factor>0)
      {
         //--- select history for access
         HistorySelect(0,TimeCurrent());
         //---
         int       orders=HistoryDealsTotal();  // total history deals
         int       losses=0;                    // number of consequent losing orders
         CDealInfo deal;
         //---
         for(int i=orders-1;i>=0;i--)
         {
            deal.Ticket(HistoryDealGetTicket(i));
            if(deal.Ticket()==0)
            {
               Print("CMoneySE::Optimize: HistoryDealGetTicket failed, no trade history");
               break;
            }
            //--- check symbol
            if(deal.Symbol()!=m_symbol.Name())
               continue;
            //--- check profit
            double profit=deal.Profit();
            if(profit>0.0)
               break;
            if(profit<0.0)
               losses++;
         }
         //---
         if(losses>1){
         lot*=m_scale_factor;
         lot/=(losses+m_scale_factor);
         lot=NormalizeDouble(lot,2);}
      }
      //--- normalize and check limits
      double stepvol=m_symbol.LotsStep();
      lot=stepvol*NormalizeDouble(lot/stepvol,0);
      //---
      double minvol=m_symbol.LotsMin();
      if(lot<minvol){ lot=minvol; }
      //---
      double maxvol=m_symbol.LotsMax();
      if(lot>maxvol){ lot=maxvol; }
//---
   return(lot);
  }

 

MQL5-Assistent

Wir werden zwei Expert Advisors zusammenstellen, einen nur mit der von uns erstellten Signalklasse und einem Mindesthandelsvolumen für die Geldverwaltung, und den zweiten mit der von uns erstellten Signal- und Geldverwaltungsklasse.


4.0 Strategietester

Die Optimierung für den ersten Experten ergibt einen Gewinnfaktor von 2,89 und eine Sharpe Ratio von 4,87 gegenüber einem Gewinnfaktor von 3,65 und einer Sharpe Ratio von 5,79 bei der Optimierung des zweiten Experten.

 

Erster Bericht

 

s_r

 

Erste Kapitalkurve


s_c

 

Zweiter Bericht

 

m_r

 

Zweite Kapitalkurve

 

m_c


5.0 Schlussfolgerung

Die beigefügten Experten wurden auf Basis von Eröffnungskursen des 4-Stunden-Zeitrahmens für ideale Take-Profit- und Stop-Loss-Levels optimiert, d.h. Sie können diese Ergebnisse nicht auf einem Live-Konto oder sogar im Strategietester in jedem Tick-Modus replizieren. Darum ging es in dem Artikel nicht. Anstatt zu versuchen, einen Gral zu beschreiben, den jeder wiederholen könnte, soll diese Reihe von Artikeln versuchen, verschiedene Ideen, die weiter angepasst werden müssten, sodass damit jeder Händler sein eigenes Glück versuchen kann. Die Märkte sind insgesamt noch zu stark korreliert, weshalb die Suche nach hoher Volatilität von Vorteil sein kann. Danke fürs Lesen.

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/11487

Beigefügte Dateien |
expert_se.mq5 (7.48 KB)
se.mq5 (7.75 KB)
SignalSE.mqh (24.84 KB)
MoneySE.mqh (6.55 KB)
Matrix- und Vektoroperationen in MQL5 Matrix- und Vektoroperationen in MQL5
Matrizen und Vektoren wurden in MQL5 für effiziente Operationen mit mathematischen Berechnungen eingeführt. Die neuen Typen bieten integrierte Methoden zur Erstellung von prägnantem und verständlichem Code, der der mathematischen Notation nahe kommt. Arrays bieten umfangreiche Möglichkeiten, aber es gibt viele Fälle, in denen Matrizen viel effizienter sind.
Neuronale Netze leicht gemacht (Teil 20): Autoencoder Neuronale Netze leicht gemacht (Teil 20): Autoencoder
Wir untersuchen weiterhin Modelle und Algorithmen für unüberwachtes Lernen. Einige Leser haben vielleicht Fragen zur Relevanz der jüngsten Veröffentlichungen zum Thema neuronale Netze. In diesem neuen Artikel befassen wir uns wieder mit neuronalen Netzen.
Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 22): Neues Auftragssystems (V) Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 22): Neues Auftragssystems (V)
Heute werden wir die Entwicklung des neuen Auftragssystems fortsetzen. Es ist nicht einfach, ein neues System einzuführen, da wir häufig auf Probleme stoßen, die den Prozess erheblich erschweren. Wenn diese Probleme auftreten, müssen wir innehalten und die Richtung, in die wir uns bewegen, neu analysieren.
DoEasy. Steuerung (Teil 10): WinForms-Objekte - Animieren der Nutzeroberfläche DoEasy. Steuerung (Teil 10): WinForms-Objekte - Animieren der Nutzeroberfläche
Nun ist es an der Zeit, die grafische Oberfläche zu animieren, indem die Funktionsweise für die Interaktion von Objekten mit Nutzern und Objekten implementiert wird. Die neue Funktionsweise wird auch notwendig sein, damit komplexere Objekte korrekt funktionieren.