English Русский 中文 Español 日本語 Português
Analyse der Grafiken Kontostand/Equity nach Symbolen und nach ORDER_MAGIC von Expert Advisors

Analyse der Grafiken Kontostand/Equity nach Symbolen und nach ORDER_MAGIC von Expert Advisors

MetaTrader 5Statistik und Analyse | 19 Juni 2017, 10:54
833 0
Vladimir Karputov
Vladimir Karputov

Inhalt


Aufgabenstellung

Die Einführung der Hedging-Option in MetaTrader 5 ermöglichte es, gleichzeitig mehrere Expert Advisors auf einem Handelskonto handeln zu lassen. Man kann das Handelskonto im Signal-Service überwachen und Statistik zum Konto erhalten. Für mich blieb eine sehr wichtige Frage offen: wie man den Beitrag jeder Strategie auf den Grafiken Kontostand und Equity veranschaulichen kann.

Denn im Trading ist die Situation möglich, dass eine Strategie profitabel ist und die andere verlustbringend, und die Grafik schwankt dabei um Null. Für diesen Fall ist es hilfreich, die Grafiken des Kontostandes und der Equity für jede Handelsstrategie separat zu zeichnen.


1. Komission. Swap. Profit

Das Endergebnis eines Abschlusses wird durch das Addieren der drei Parameter gebildet:

 Result=Deal commission +Cumulative swap on close+ Deal profit

Diese Eigenschaften werden mithilfe von HistoryDealGetDouble() mit folgenden IDs erhalten:

DEAL_COMMISSION

Deal commission

double

DEAL_SWAP

Cumulative swap on close

double

DEAL_PROFIT

Deal profit

double


Ein Beispiel für das Erhalten der Eigenschaften der Abschlüsse aus der Handelshistorie für einen vorgegebenen Zeitraum im Skript HistoryDealGetTicket.mq5.

Die Ergebnisse des Skripts (Abschlüsse von Typ DEAL_ENTRY_IN wurden gelöscht, denn sie haben kein Finanzergebnis):

...
  4: deal #36774600 at 2017.02.15 10:17:50 Entry out, sell vol: 0.01 comm: 0 swap: 0.02 profit: 1.52 NZDUSD.m (order #47802989, position ID 47770449)
...
12: deal #36798157 at 2017.02.15 16:44:17 Entry out, buy vol: 0.01 comm: 0 swap: -0.01 profit: 2.98 EURUSD.m (order #47827771, position ID 47685190)
13: deal #36798161 at 2017.02.15 16:44:17 Entry out, buy vol: 0.01 comm: 0 swap: -0.02 profit: 5.99 EURUSD.m (order #47827785, position ID 47665575)
14: deal #36798176 at 2017.02.15 16:44:17 Entry out, buy vol: 0.01 comm: 0 swap: -0.02 profit: 5.93 EURUSD.m (order #47827805, position ID 47605603)
15: deal #36798185 at 2017.02.15 16:44:18 Entry out, buy vol: 0.01 comm: 0 swap: -0.03 profit: 5.98 EURUSD.m (order #47827821, position ID 47502789)
16: deal #36798196 at 2017.02.15 16:44:18 Entry out, buy vol: 0.01 comm: 0 swap: -0.03 profit: 8.96 EURUSD.m (order #47827832, position ID 47419515)
17: deal #36798203 at 2017.02.15 16:44:18 Entry out, buy vol: 0.01 comm: 0 swap: -0.06 profit: 8.92 EURUSD.m (order #47827835, position ID 47130461)
18: deal #36798212 at 2017.02.15 16:44:19 Entry out, sell vol: 0.01 comm: 0 swap: -0.48 profit: -21.07 EURUSD.m (order #47827845, position ID 46868574)
...
25: deal #36824799 at 2017.02.15 19:57:57 Entry out, sell vol: 0.01 comm: 0 swap: 0 profit: 2.96 NZDUSD.m (order #47855548, position ID 47817757)
26: deal #36824800 at 2017.02.15 19:57:58 Entry out, sell vol: 0.01 comm: 0 swap: 0 profit: 3.01 NZDUSD.m (order #47855549, position ID 47790966)
27: deal #36824801 at 2017.02.15 19:57:58 Entry out, sell vol: 0.01 comm: 0 swap: 0.02 profit: 3.07 NZDUSD.m (order #47855550, position ID 47777495)
28: deal #36824802 at 2017.02.15 19:57:58 Entry out, sell vol: 0.01 comm: 0 swap: 0.02 profit: 3 NZDUSD.m (order #47855551, position ID 47759307)
29: deal #36824803 at 2017.02.15 19:57:59 Entry out, sell vol: 0.01 comm: 0 swap: 0.02 profit: 1.52 NZDUSD.m (order #47855552, position ID 47682775)
...
33: deal #36832775 at 2017.02.16 00:58:41 Entry out, sell vol: 0.01 comm: 0 swap: 0.05 profit: 2.96 NZDUSD.m (order #47863883, position ID 47826616)
34: deal #36832776 at 2017.02.16 00:58:41 Entry out, sell vol: 0.01 comm: 0 swap: 0.05 profit: 3.05 NZDUSD.m (order #47863884, position ID 47803010)
35: deal #36832777 at 2017.02.16 00:58:41 Entry out, sell vol: 0.01 comm: 0 swap: 0.05 profit: 2.98 NZDUSD.m (order #47863885, position ID 47792294)
36: deal #36832778 at 2017.02.16 00:58:42 Entry out, sell vol: 0.01 comm: 0 swap: 0.07 profit: 2.88 NZDUSD.m (order #47863886, position ID 47713741)
...

Wie wir sehen, können Swap und Profit sowohl das Vorzeichen "+", als auch das Vorzeichen "-" haben. Deswegen wird das Addieren für Swap und Profit in der Formel des Finanzergebnisses verwendet.


2. Berechnung der Equity und des Kontostandes anhand der Historie

Der allgemeine Arbeitsplan sieht wie folgt aus: die Liste "Offene Positionen" zusammenstellen, die Handelshistorie in Abschnitte je 5-15 Minuten aufteilen (dieser Parameter wird später präzisiert). Danach für jeden Abschnitt:

  • nach Ausstieg aus dem Markt suchen. Wenn solche Abschlüsse gefunden wurden, den Wert basierend auf dem Finanzergebnis der Abschlüsse für die Grafiken Kontostand und Equity neu berechnen. Die Liste "Offene Positionen" korrigieren.
  • nach offenen Positionen den Wert für die Equity-Grafik berechnen. 

2.1. Die Liste "Offene Positionen"

Für die Aufzeichnung offener Positionen im ausgewählten Zeitraum wird eine Klasse von Abschlüssen benötigt. Implementieren wir dies in der Klasse CHistoryDeal, in der include-Datei HistoryDeal.mqh:

Methode Wert
TicketDeal Erhält/setzt die Eigenschaft des Abschlusses "Ticket des Abschlusses"
PosIDDeal Erhält/setzt die Eigenschaft des Abschlusses "Position-ID"
SymbolDeal Erhält/setzt die Eigenschaft des Abschlusses "Symbol des Abschlusses"
TypeDeal Erhält setzt die Eigenschaft des Abschlusses "Typ des Abschlusses" aus der Aufzählung ENUM_DEAL_TYPE
EntryDeal Erhält/setzt die Eigenschaft des Abschlusses "Richtung des Abschlusses" aus der Aufzählung ENUM_DEAL_ENTRY
VolumeDeal Erhält/setzt die Eigenschaft des Abschlusses "Volumen des Abschlusses"
PriceDeal Erhält/setzt die Eigenschaft des Abschlusses "Eröffnungspreis des Abschlusses"


2.2. Formel des Floating Profits

Die Formel des Profits entnehmen wir der Beschreibung der Aufzählung ENUM_SYMBOL_CALC_MODE. Dabei muss man immer beachten, in welcher Währung der Profit für dieses Symbol berechnet wird. Die Währung des Profits kann man wie folgt erhalten:

SymbolInfoString(m_name,SYMBOL_CURRENCY_BASE);

  • oder durch das Öffnen der Spezifikation im Terminal:

rts specification

Abb. 1. Spezifikation von RTS-3.17

2.3. Sicherung: ob alle Symbole verfügbar sind

Mögliche Probleme: 

  • ein Symbol aus der Handelshistorie fehlt in der Marktübersicht (Suche in der Gesamtliste der Symbole);
  • die Währung des Profits auf einem Symbol kann nicht in die Währung des Kontos umgerechnet werden, d.h. in der "Marktübersicht" ist das Symbol für die Umrechnung nicht vorhanden.

Für die Erfassung möglicher Fehler wird dem Expert Advisor an der Ebene globaler Variablen des Programms (Wichtig: des Programms, und nicht des Terminals!) ein Array für "mangelhafte" Symbole hinzugefügt. Dazu gehören Symbole, die in der Marktübersicht nicht vorhanden sind, oder für welche die Währung des Profits in die Währung des Kontos nicht umgerechnet werden kann:

string m_arr_defective_symbols[];                        // array for defective symbols

Die Reihenfolge der Sicherung (alle Schritte erfolgen in der Funktion SearchDefectiveSymbols):

  1. ein vorläufiges (Hilfs-) Array aus allen in der Marktübersicht vorhandenen Symbolen erstellen;
  2. ein vorläufiges (Hilfs-) Array aus allen Symbolen der Handelshistorie erstellen (in einem vorgegebenen Zeitraum von ... bis ... );
  3. Symbole aus der Handelshistorie in der Marktübersicht suchen. Wenn eines der Symbole nicht gefunden wird, wird es ins Array der "mangelhaften" Symbole eingetragen;
  4. der Marktübersicht die Symbole aus der Historie hinzufügen (anzeigen). Wenn die Operation fehlschlägt, wird das Symbol ins Array der "mangelhaften" Symbole eingetragen;
  5. die Währung des Profits aus den Eigenschaften des Symbols erhalten. Wenn sich die Währung des Profits von der Währung des Kontos unterscheidet, kommen wir zum Unterpunkt 5.1.
    1. Versuchen wir ein Symbol für die Umrechnung in der Marktübersicht zu finden, das der folgenden Formel entspricht "Währung des Kontos"+"Währung des Profits" oder "Währung des Profits"+"Währung des Kontos". Wenn die Operation fehlschlägt, wird das Symbol ins Array der "schlechten" Symbole eingetragen.

Nach der Arbeit der Funktion "SearchDefectiveSymbols" wird ein Array mit den "mangelhaften" Symbolen aus der Handelshistorie erstellt. In den nächsten Berechnungen (bei der Berechnung der Grafik "Kontostand" und "Equity") werden die "mangelhaften" Symbole nicht berücksichtigt.

2.4. Aufrechnung offener und geschlossener Positionen in der Historie

Alle Veränderungen im Kontostand werden im zweidimensionalen Array m_arr_balance_equity angezeigt.

Rufen wir die Historie von "from date" bis "to date" ab (das sind die Eingabeparameter des Expert Advisors) und dividieren sie durch die Anzahl der Schleifen mit einer Dauer von "timer (minutes)". Die Arbeit wird in der Funktion CreateBalanceEquity geführt. Alle Abschlüsse werden in das dynamische Array der Pointer ArrOpenPositions geschrieben. Weiter arbeiten wir mit diesem Array: wir fügen Abschlüsse hinzu und löschen sie.

Je nach dem Parameter "Richtung des Abschlusses" ENUM_DEAL_ENTRYwerden wir die Grafiken Kontostand und Equity auf unterschiedliche Weise berechnen. Wenn Sie das Verhalten des Eröffnens, Schließens, partiellen Schließens oder der Umkehr einer Position auf Hedging- und Netting-Konten prüfen möchten, können Sie das Skript HistorySelect.mq5 starten.

  • ‌DEAL_ENTRY_IN — Einstieg in den Markt. Schreiben wir den Abschluss in das Array "ArrOpenPositions"
  • DEAL_ENTRY_OUT — Ausstieg. Suchen wir nach einem Abschluss vom Typ DEAL_ENTRY_IN mit derselben DEAL_POSITION_ID im Array ArrOpenPositions.
    • wenn die Suche false zurückgegeben hat, tragen wir keine Änderungen in die Grafiken "Kontostand" und "Equity" ein
    • wenn die Suche true geliefert hat, die Volumina (in Lots) vergleichen
      • die Volumina sind gleich — den Abschluss aus dem Array ArrOpenPositions löschen und die Änderungen in die Kontostand-Spalte eintragen (Array "m_arr_balance_equity")
      • das Volumen des Abschlusses aus dem Array ArrOpenPositions ist größer — das Volumen im Array ArrOpenPositions korrigieren und die Änderungen in die Kontostand-Spalte (Array m_arr_balance_equity) eintragen
      • das Volumen des Abschlusses aus dem Array ArrOpenPositions ist kleiner — den Abschluss aus dem Array ArrOpenPositions löschen und Änderungen in der Spalte Kontostand (Array m_arr_balance_equity) eintragen
  • DEAL_ENTRY_INOUT — Umkehr. Suchen wir nach einem Abschluss vom Typ DEAL_ENTRY_IN mit derselben DEAL_POSITION_ID im Array ArrOpenPositions.
    • wenn die Suche false zurückgegeben hat, werden keine Änderungen in die Grafiken Kontostand und Equity eingetragen
    • wenn die Suche true zurückgegeben hat, korrigieren wir das Volumen des Abschlusses im Array ArrOpenPositions sowie den Typ des Abschlusses im Array ArrOpenPositions und tragen die Änderungen in die Kontostand-Spalte ein (Array m_arr_balance_equity)
  • DEAL_ENTRY_OUT_BY — Schließen zur Gegenposition. Suchen wir nach einem Abschluss vom Typ DEAL_ENTRY_IN mit derselben DEAL_POSITION_ID im Array ArrOpenPositions
    • die Volumina sind gleich — den Abschluss aus dem Array ArrOpenPositions löschen und die Änderungen in die Kontostand-Spalte eintragen (Array m_arr_balance_equity)
    • die Volumina unterscheiden sich — das Volumen des Abschlusses im Array ArrOpenPositions korrigieren und die Änderungen in die Kontostand-Spalte eintragen (Array m_arr_balance_equity)

2.5. Wie man Floating Profit (Equity) berechnet

Man muss im ganzen Array ArrOpenPositions suchen und Floating Profit nach allen Abschlüssen in diesem Array berechnen. Wenn der Abschluss im Array ArrOpenPositions ist, verfügen wir über die folgenden Daten zu jedem Abschluss. Wir benötigen:

  • Symbol
  • Typ (BUY or SELL)
  • Volumen
  • Preis (zu welchem der Abschluss eröffnet wurde),

sowie das Enddatum, nach welchem die Handelshiostorie abgerufen wurde. Es fehlen nur die Preise für das Enddatum auf dem Symbol des Abschlusses, bis welchem die Handelshistorie abgerufen wurde. Den Preis erhalten wir mithilfe von CopyTicks in CalculationFloatingProfit. Die Formel des Profits entnehmen wir der Aufzählung ENUM_SYMBOL_CALC_MODE

Bei der Profilierung hat sich ergeben, dass die Methode CopyTicks viel Zeit in Anspruch nimmt, besonders wenn es mehrere Abschlüsse auf einem Symbol im Arrray CalculationFloatingProfit gibt. In solchen Fällen kommt es dazu, dass dieselben Daten mehrmals abgerufen werden: das Symbol ist gleich und das Datum ist auch gleich. Für die Beschleunigung wurde Caching der Ergebnisse der CopyTicks eingeführt. 

//--- caching results "CopyTicks"
   static string arr_name[];
   static double arr_ask[];
   static double arr_bid[];
   static datetime prev_time=0;
   int number=-1;
   if(time>prev_time)
     {
      prev_time=time;
      ArrayFree(arr_name);
      ArrayFree(arr_ask);
      ArrayFree(arr_bid);
     }
   found=false;
   size=ArraySize(arr_name);
   if(size>0)
      for(int i=0;i<size;i++)
        {
         if(name==arr_name[i])
           {
            number=i;
            found=true;
            break;
           }
        }
   if(found)
     {
      ArrayResize(ticks_array,1);
      ticks_array[0].ask=arr_ask[number];
      ticks_array[0].bid=arr_bid[number];
     }
   else
     {
      //---
      int copy_ticks=-1;
      int count=0;
      while(copy_ticks==-1 && count<5)
        {
         copy_ticks=CopyTicks(name,ticks_array,COPY_TICKS_INFO,1000*(ulong)time,1);
         //if(copy_ticks==-1)

Die Ergebnisse bid und ask werden in lokalen Arrays gespeichert: wenn Ticks in diesem Zeitraum für das Symbol bereits erhalten wurden, werden sie den lokalen Arrays entnommen. Dieser Ansatz erlaubte es uns, sich um das 10-15-fache zu beschleunigen. 


3. Integration des Expert Advisors ins Panel der Dialoge

Nun wenn die Basis des Expert Advisors funktionsfähig ist, kann man ihm mit einem etwas benutzerfreundlicheres Interface ausstatten. Aus dem Titel des Artikels "Analyse der Grafiken Kontostand/Equity nach Symbolen und nach ORDER_MAGIC von Expert Advisros" folgt, dass man mehrere Filterungsmöglichkeiten einkalkulieren muss:

  • alle Symbole/ein oder mehrere ausgewählte Symbole anzeigen;
  • nach allen Magic Numbers anzeigen/nur nach einem oder nach mehreren ausgewählten Symbolen anzeigen.

Für die Erfassung aller Symbole haben wir bereits das Array m_arr_all_trade_symbols. Es wurde an der globalen Ebene deklariert. Wir müssen ein weiteres Array, m_arr_all_magics, für alle Magic Numbers einführen. Modifizieren wir dafür die Funktion FillArrayTradeSymbols: nun wird auch das Array m_arr_all_magics in der Funktion ausgefüllt.

3.1. Erscheinungsbild des Panels der Dialoge

panel

Abb. 2. Erscheinungsbild des Panels

Nach der Erstellung der Arrays für "mangelhafte" Symbole, alle Handelssymbole und Magic Numbers werden zwei Listen im Panel ausgefüllt (Elemete basierend auf der Klasse CComboBox): die Liste links beinhaltet alle Symbole, die Liste rechts — alle Magic Numbers. In den Listen steht an erster Stelle die Auswahl aller Symbole und aller Magic Numbers:

panel combo box

Abb. 3. Dropdown-Listen

Die Logik des Experten des Panels: nach und erst nach dem Klick auf "Start" wird überprüft, was in den zwei Dropdown-Listen ausgewählt wurde. Je nach ausgewählten Parameter werden in den Listen die Grafiken Kontostand/Equity basierend auf der Handelshistorie gezeichnet.

3.2. Interaktion mit dem Panel

Ich glaube, die Übertragung des ganzen Codes des Expert Advisors in die Klasse des Panels (APHDialog.mqh) zu viel Zeit in Anspruch nimmt. Eine alternative Lösung wäre, der Klasse des Panels interne Variablen m_ready, m_symbol und m_magic hinzuzufügen:

//+------------------------------------------------------------------+
//| Class CAPHDialog                                                 |
//| Usage: main dialog of the Controls application                   |
//+------------------------------------------------------------------+
class CAPHDialog : public CAppDialog
  {
private:
   CLabel            m_label_symbols;                 // the label object
   CComboBox         m_combo_box_symbols;             // the combo boxp object
   CLabel            m_label_magics;                  // the label object
   CComboBox         m_combo_box_magics;              // the combo box object
   CButton           m_button_start;                  // the button object
   //---
   bool              m_ready;                         // true -> you can build graphics
   string            m_symbol;
   ulong             m_magic;

public:

Die Entscheidung über den Status der Variablen m_ready wird bei der Verarbeitung des Klicks auf Start getroffen:

//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CAPHDialog::OnClickButtonStart(void)
  {
   if(m_combo_box_symbols.Select()!=" " && m_combo_box_magics.Select()!=" ")
      m_ready=true;
   else
      m_ready=false;
//Comment(__FUNCTION__+" ButtonStartclick"+"\n"+
//        "Symbols: "+"\""+m_combo_box_symbols.Select()+"\""+"\n"+
//        "Magic: "+"\""+m_combo_box_magics.Select()+"\""+"\n"+
//        "m_ready: "+IntegerToString(m_ready));
  }

Bitte achten Sie auf die hervorgehobene Zeile: direkt nach der Erstellung und Ausfüllung der Dropdown-Listen (bei uns sind das die Elemente m_combo_box_symbols und m_combo_box_magics) wird ein Element mit dem Wert " " in die Listen gesetzt, also die Leerstelle.

Die Entscheidung über den Status der Variablen m_symbol und m_magic wird bei der Verarbeitung des Klicks auf der entsprechenden Dropdown-Liste getroffen:

//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CAPHDialog::OnChangeComboBoxSymbols(void)
  {
//Comment(__FUNCTION__+" \""+m_combo_box_symbols.Select()+"\"");
   if(m_combo_box_symbols.Select()=="All symbols")
      m_symbol="";
   else
      m_symbol=m_combo_box_symbols.Select();
  }
//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CAPHDialog::OnChangeComboBoxMagics(void)
  {
//Comment(__FUNCTION__+" \""+m_combo_box_magics.Select()+"\"");
   if(m_combo_box_magics.Select()=="All magics")
      m_magic=-1;
   else
      m_magic=StringToInteger(m_combo_box_magics.Select());
  }

Auf diese Weise werden nach dem Klick auf "Start" drei Variablen ausgefüllt: m_ready, m_symbol und m_magic. Es bleibt nur zu erfinden, wie den Expert Advisor darüber zu benachrichtigen, dass die Parameter auf dem Panel ausgewählt wurden. Die Lösung ist ganz einfach: Timer mit einem Intervall von 3 Sekunden im Expert Advisor starten, der die Daten abrufen wird. Dafür schreiben wir die Methode CPHDialog::IsReady im Panel.

//+------------------------------------------------------------------+
//| On the panel there are chosen parameters                         |
//+------------------------------------------------------------------+
bool CAPHDialog::IsReady(string &symbol,ulong &magic)
  {
   if(m_ready)
     {
      symbol=m_symbol;
      magic=m_magic;
      m_ready=false;
      return(true);
     }
   else
      return(false);
  }

In dieser Methode schreiben wir den Wert der internen Variablen in die Variablen, die nach der Referenz übergeben wurden, und setzen die interne Variable m_ready zurück.

3.3. Kleine Korrektur: die ausgewählte Magic Number berücksichtigen

Die Auswahl der Abschlüsse erfolgt nach vorgegebenen Bedingungen: nach einem Symbol oder nach allen Symbolen und nach einer Magic Number oder nach allen Magic Numbers in GetHistory:

//--- for all deals 
   for(int i=0;i<deals;i++)
     {
      deal_ticket          = HistoryDealGetTicket(i);
      deal_position_ID     = HistoryDealGetInteger(deal_ticket,DEAL_POSITION_ID);
      deal_symbol          = HistoryDealGetString(deal_ticket,DEAL_SYMBOL);
      deal_type            = (ENUM_DEAL_TYPE)HistoryDealGetInteger(deal_ticket,DEAL_TYPE);
      deal_entry           = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY);
      deal_volume          = HistoryDealGetDouble(deal_ticket,DEAL_VOLUME);
      deal_price           = HistoryDealGetDouble(deal_ticket,DEAL_PRICE);
      deal_commission      = HistoryDealGetDouble(deal_ticket,DEAL_COMMISSION);
      deal_swap            = HistoryDealGetDouble(deal_ticket,DEAL_SWAP);
      deal_profit          = HistoryDealGetDouble(deal_ticket,DEAL_PROFIT);
      deal_magic           = HistoryDealGetInteger(deal_ticket,DEAL_MAGIC);
      if(sSymbol!="")
         if(deal_symbol!=sSymbol)
            continue;
      if(uMagic!=ULONG_MAX)
         if(deal_magic!=uMagic)
            continue;
      //--- onle BUY or SELL

Bitte beachten Sie, für die Variable uMagic bedeutet der Wert ULONG_MAX "Alle Magic Numbers", und für die Variable sSymbol bedeutet "" "Alle Symbole".

Das Video zeigt, wie Kontostand und Floating Profit basierend auf der Handelshistorie gezeichnet werden (zuerst für alle Symbole, dann nur für ein Symbol):


Das Video


4. Grafiken der Verteilung von MFE und MAE

Für jede offene Position während ihrer Lebensdauer werden die Werte des maximalen Profits (MFE) und maximalen Verlustes (MAE) gespeichert. Diese Werte charakterisieren jede geschlossene Position durch die Werte des maximalen nicht erschöpften Potentials und des maximalen zugelassenen Risikos. Auf den Verteilungsgrafiken MFE/Profit und MAE/Profit entspricht jeder Position ein Punkt, horizontal sehen wir den Wert des erhaltenen Profits/Verlustes, vertikal — die Werte des potentiellen Profits (MFE) und potentiellen Verlustes (MAE).

4.1. Berechnungsprinzip von MFE und MAE

An der globalen Ebene werden zwei Arrays deklariert: m_arr_pos_id für Positionen und m_arr_mfe_mae für MFE, Finanzergebnis und MAE: 

long   m_arr_pos_id[];
double m_arr_mfe_mae[][3];  // [][0] - mfe, [][1] - final financial result,[][2] - mae

Weiter werden auf Basis des Arrays m_arr_mfe_mae die Grafiken der Verteilung von MFE und MAE.

Die Arrays m_arr_pos_id für Positionen und m_arr_mfe_mae für mfe haben immer die gleiche Größe in der ersten Dimension. Daraus folgt, dass einer Position mit dem Index "i" (m_arr_pos_id[i]) immer m_arr_mfe_mae[i][][][] entsprechen wird. Die Größen der Arrays werden in GetHistory definiert:

         if(deal_symbol=="")
            DebugBreak();
         ArrOpenPositions.Add(HistoryDeal);
         //--- mfe, mae
         int size=ArraySize(m_arr_pos_id);
         ArrayResize(m_arr_pos_id,size+1,10);
         ArrayResize(m_arr_mfe_mae,size+1,10);
         m_arr_pos_id[size]=deal_position_ID;
         // [][0] - mfe, [][1] - final financial result,[][2] - mae
         m_arr_mfe_mae[size][0]=0.0;
         m_arr_mfe_mae[size][1]=0.0;
         m_arr_mfe_mae[size][2]=0.0;
         continue;
        }
      //--- 
      if(deal_entry==DEAL_ENTRY_OUT)

Die Funktion, die für die Erfassung des maximalen Profits und maximalen Verlustes für jede Position zuständig ist:

//+------------------------------------------------------------------+
//| Add Result Mfe Mae                                               |
//+------------------------------------------------------------------+
void AddResultMfeMae(const long pos_id,const double floating_profit,const double financial_result)
  {
// [][0] - mfe (profit), [][1] - final financial result,[][2] - mae (loss)
//--- search pos_id
   int position=-1;
   int size=ArraySize(m_arr_pos_id);
   for(int i=0;i<size;i++)
      if(m_arr_pos_id[i]==pos_id)
        {
         position=i;
         break;
        }
   if(position==-1)
      return;

//---
   if(floating_profit==0.0)
      return;

   if(floating_profit>0.0) // profit
     {
      if(m_arr_mfe_mae[position][0]<floating_profit)
         m_arr_mfe_mae[position][0]=floating_profit;
     }
   else // loss
     {
      if(m_arr_mfe_mae[position][2]>floating_profit)
         m_arr_mfe_mae[position][2]=floating_profit;
     }
   m_arr_mfe_mae[position][1]=financial_result;
  }

Hier gilt die Regel: man muss alle drei Parameter übergeben. D.h. wenn unsere virtuelle Position immer noch in der Liste offener Positionen ArrOpenPositions vorhanden ist und ihr Floating Profit -20.2 ausmacht, wird der Aufruf wie folgt aussehen:

    AddResultMfeMae(pos_id,-20.2,0.0);

wenn unsere virtuelle Position noch auf der Liste der offenen Positionen ArrOpenPositions steht, und der Floating Profit gleich "+5.81" ist, wird der Aufruf wie folgt aussehen:

    AddResultMfeMae(pos_id,5.81,0.0);

und wenn unsere Position aus der Liste der offenen Positionen ArrOpenPositions gelöscht wurde und ihr Handelsergebnis gleich -3.06 ist, wird der Aufruf wie folgt aussehen:

    AddResultMfeMae(pos_id,0.0,-3.06);

Das heißt, wenn es Floating Profit gibt, ist das Finanzergebnis gleich Null, wenn die Position geschlossen wird, ist der Floating Profit gleich Null.

4.2. Verarbeitung von Positionen

  • ‌DEAL_ENTRY_IN - Einstieg in den Markt. Schreiben wir den Abschluss ins Array ArrOpenPositions. Erstellen wir ein neues Element in den Arrays m_arr_pos_id und m_arr_mfe_mae
  • DEAL_ENTRY_OUT - Ausstieg. Suchen wir nach einem Abschluss vom Typ DEAL_ENTRY_IN mit derselben DEAL_POSITION_ID im Array ArrOpenPositions
    • wenn die Suche false zurückgegeben hat, werden keine Änderungen in die Grafiken Kontostand und Equity eingetragen
    • wenn die Suche true geliefert hat, die Volumina (in Lots) vergleichen
      • die Volumina sind gleich - den Abschluss aus dem Array ArrOpenPositions löschen und die Änderungen in die Kontostand-Spalte ins Array m_arr_balance_equity eintragen. Ins Array m_arr_mfe_mae schreiben wir [Floating Profit 0.0][Finanzergebnis].
      • das Volumen des Abschlusses aus dem Array ArrOpenPositions ist größer - das Volumen des Abschlusses im Array ArrOpenPositions korrigieren und die Änderungen in die Kontostand-Spalte ins Array m_arr_balance_equity eintragen. Ins Array  m_arr_mfe_mae schreiben wir [Floating Profit 0.0][Finanzergebnis].
      • das Volumen des Abschlusses aus dem Array ArrOpenPositionsist kleiner - den Abschluss aus dem Array ArrOpenPositions löschen und die Änderungen in die Kontostand-Spalte ins Array m_arr_balance_equity eintragen. Ins Array m_arr_mfe_mae schreiben wir [Floating Profit 0.0][Finanzergebnis].
  • DEAL_ENTRY_INOUT - Umkehr. Suchen wir nach einem Abschluss vom Typ DEAL_ENTRY_IN mit derselben DEAL_POSITION_ID im Array ArrOpenPositions
    • wenn die Suche false zurückgegeben hat, werden keine Änderungen in die Grafiken Kontostand und Equity eingetragen
    • wenn die Suche true zurückgegeben hat - das Volumen des Abschlusses im Array ArrOpenPositions korrigieren, den Typ des Abschlusses im Array ArrOpenPositions korrigieren und die Änderungen in die Kontostand-Spalte ins Array m_arr_balance_equity eintragen. Ins Array m_arr_mfe_mae schreiben wir [Floating Profit 0.0][Finanzergebnis].
  • DEAL_ENTRY_OUT_BY - Schließen zur Gegenposition. Suchen wir nach einem Abschluss vom Typ DEAL_ENTRY_IN mit derselben DEAL_POSITION_ID im Array ArrOpenPositions  
    • die Volumina sind gleich - den Abschluss aus dem Array ArrOpenPositions löschen und die Veränderungen in die Kontostand-Spalte ins Array m_arr_balance_equity eintragen. Ins Array m_arr_mfe_mae schreiben wir [Floating Profit 0.0][Finanzergebnis].
    • die Volumina unterscheiden sich - das Volumen des Abschlusses im Array ArrOpenPositions korrigieren und die Änderungen in die Kontostand-Spalte ins Array m_arr_balance_equity eintragen. Ins Array m_arr_mfe_mae schreiben wir [Floating Profit 0.0][Finanzergebnis].

Wenn der Floating Profit in GetHistory neu berechnet werden muss, schreiben wir für jede Position [Floating Profit][Finanzergebnis 0.0] ins Array m_arr_mfe_mae.

4.3. Modifizierung des Panels

Für die Anzeige der Grafik Kontostand / Equity sowie MFE und MAE wird das Panel ein bisschen modifiziert:

panel 2

Abb. 4. Modifizierung des Panels

Die Grafiken MFE (maximaler Profit) und MAE (maximaler Verlust) werden nach zwei Koordinaten gebildet: X-Koordinate, die Koordinate des Endergebnisses der Position, und Y-Koordinate - jeweils der MFE- oder MAE-Wert.

MFE

Abb. 5. MFE

MAE

Abb. 6. MAE


Fazit

Nun kann man sich auf Hedge-Konten, bei einem gleichzeitigen Handel mehrerer Expert Advisors, die Statistik des Kontostandes nach jedem Symbol und jeder Magic Number anschauen. Das heißt, man kann den Beitrag jedes Expert Advisors (ORDER_MAGIC) zum Kontostand und den Rückgang jedes konkreten Expert Advisors visuell einschätzen.

Die im Artikel verwendeten Programme:

#
 Name
Typ
Beschreibung
1
HistoryDeal.mqh Bibliothek  Klasse der Aufrechnung offener Positionen im ausgewählten Bereich
2
HistoryDealGetTicket.mq5 Expert Advisor  Beispiel für das Erhalten der Abschlüsse aus der Handelshistorie in einem vorgegebenen Zeitraum
3
APHDialog.mqh Bibliothek  Klasse des Dialog-Panels im Expert Advisor
4
Accounting_positions_on_history.mq5 Expert Advisor  Expert Advisor - basierend auf dem Artikel
5
MQL5.zip Zip-Datei  Zip-Datei mit dem Expert Advisor und seinen include-Dateien.


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

Beigefügte Dateien |
HistoryDeal.mqh (6.66 KB)
APHDialog.mqh (28.62 KB)
MQL5.zip (26.34 KB)
Erstellung der Dokumentation basierend auf Quellcodes von MQL5 Erstellung der Dokumentation basierend auf Quellcodes von MQL5
Der Artikel beschäftigt sich mit der Erstellung der Dokumentation zu einem Code in MQL5 und beginnt mit der Automatisierung der Platzierung von Tags. Weiter wird die Arbeit mit dem Programm Doxygen beschrieben, ihre Konfiguration und das Erhalten von Ergebnissen in verschiedenen Formaten: in HTML, HtmlHelp und in PDF.
Das Beispiel eines Indikators, der die Linien Unterstützung / Widerstands zeichnet Das Beispiel eines Indikators, der die Linien Unterstützung / Widerstands zeichnet
Im Artikel wird das Realisierungsbeispiel des Indikators für den Aufbau der Linien Unterstützung/Widerstands aufgrund der formalisierten Bedingungen aufgeführt. Sie haben die Möglichkeit, den Indikator zu verwenden, aber verstehen auch nebenbei, wie einfach es ist, das zu realisieren. Nun können Sie selbst die Bedingungen für den Aufbau der Linien formulieren, die Sie nötig finden, dabei den Code des Indikators nach Ihren Wünschen ein wenig ändern.
Die benutzerdefinierten Indikatoren und die Informationsgrafik in CCanvas Die benutzerdefinierten Indikatoren und die Informationsgrafik in CCanvas
Im Artikel werden die neuen Arten der Indikatoren mit einer komplizierteren strukturellen Realisierung betrachtet. Es werden der Aufbau der pseudoräumlichen Typen der Indikatoren und die Erstellung einer dynamisch ändernden Informationsgrafik beschrieben.
Cross-Platform Expert Advisor: Signale Cross-Platform Expert Advisor: Signale
Dieser Artikel beschreibt die Klassen CSignal und CSignals, die in Cross-Plattform Expert Advisor verwendet werden. Es werden die Unterschiede zwischen MQL4 und MQL5 untersucht, wie sie jeweils auf bestimmte Daten zum Ermitteln eines Handelssignals zugreifen, um einen Code zu schreiben, der für beide Kompiler kompatible ist.