Universeller Expert Advisor: Zugang zu Symboleigenschaften (Teil 8)

Vasiliy Sokolov | 24 Juli, 2017


Einleitung

Seit der Veröffentlichung des letzten Teils des Artikels zum Thema CStrategy Trading-Engine ist eine Weile vergangen. Diese Zeit wurde benötigt, um die Entwicklung von CStrategy von einer Hilfsbibliothek bis zu einer funktionsfähigen Engine, die die meisten häufig verwendeten Werkzeuge für die Erstellung einer Handelsstrategie beinhaltet, zu reflektieren. Nach dieser Zeit habe ich die weitere Entwicklung von CStrategy umgedacht. Die praktische Anwendung von CStrategy hat eine Reihe von Nachteilen in den letzten Versionen der Engine an den Tag gebracht. Die Beseitigung dieser Nachteile führte zur Veröffentlichung neuer Artikel der Reihe "Universeller Expert Advisor". In diesem Artikel geht es um die Arbeit mit Handelssymbolen über die objektorientierte Klasse CStrategy. 

Übersicht der Arbeit mit Symbolen in den vorherigen Versionen von CStrategy

Die Handelsumgebung eines Expert Advisors ist umfangreich und vielfältig. Dazu gehören verschiedene Informationen über das Konto, Kursdaten, Funktionen für die Arbeit mit der Zeit und, natürlich, Informationen über Handelssymbole. Die meisten Informationen befinden sich in den Funktionen für die Arbeit mit Handelssymbolen: das Erhalten aktueller Kurse und die Arbeit mit Eigenschaften eines Symbols. In der Regel arbeiten alle Expert Advisors intensiv mit Preisinformationen. Sie berechnen ein Preismuster oder ein Handelssignal anhand Preisdaten und führen Trades basierend auf diesem Muster aus. Für die richtige Bildung einer Handelsanfrage verwenden sie Informationen über die Eigenschaften des aktuellen Symbols: zum Beispiel, das minimale Volumen des Trades oder Freeze Level, den Abstand vom aktuellen Preis, innerhalb dessen die Platzierung von Pending Orders verboten ist.

Selbstverständlich muss diese Information leicht zugänglich sein. War es aber in den vorherigen Versionen von CStrategy auch der Fall? Setzen wir uns mit der Situation auseinander und blicken wir zurück in die Geschichte: beschreiben wir, wie die Arbeit mit einem Handelssymbol früher erfolgte. Im dritten Teil des Artikels wurde ein Modell für den Zugriff auf Kurse über den üblichen Index [] dargestellt. In die Klasse CStrategy wurden mehrere Hilfsklassen COpen, CHigh, CLow, CClose, CVolume und CTime eingebettet, jede von denen den entsprechenden Wert nach dem abgerufenen Index zurückgegeben hat. Dies ermöglichte es, Informationen über den aktuellen Symbol relativ einfach im Code des Expert Advisors zu erhalten. Um den Schlusskurs des aktuellen Balkens herauszufinden, reichte es zu schreiben:

...
double close = Close[0];
...

Der Zugriff auf Kurse im Format OHLC reichte nicht aus, und der Klasse CStrategy wurden die Methoden Ask(), Bid() und Last() zusätzlich hinzugefügt. Nach einiger Zeit reichten auch diese Methoden nicht mehr aus. Es war nötig, weitere Methode ähnlich der FreezeLevel(), die Grundinformationen über das aktuelle Symbol erhalten, hinzuzufügen. Das Volumen der Basisklasse CStrategy begann schnell zuzunehmen. Die Vielzahl der vorhandenen Methoden innerhalb von CStrategy führte zu einem Durcheinander. Aber die richtigen Schwierigkeiten begannen, wenn der Versuch gemacht wurde, mithilfe von CStrategy einen gleichzeitig auf mehreren Symbolen handelnden Expert Advisor zu erstellen. Rein formell ist CStrategy eine Multiwährungs-Engine. Dies bedeutet, dass man mit ihrer Hilfe sowohl mehrere Expert Advisors erstellen kann, die mit verschiedenen Symbolen unabhängig voneinander handeln als auch einen Expert Advisor, der zwei und mehr Symbole handelt. Das Letzte ist nicht so einfach zu implementieren, denn in diesem Fall hätten wir die Klassen von Zeitrahmen neu konfigurieren sollen:

string symbol1 = "EURUSD";
string symbol2 = "GBPUSD";
Close.Symbol(symbol1);
double close_eurusd = Close[0];
Close.Symbol(symbol2);
double close_gbpusd = Close[0];
...

Diese Schwierigkeiten haben uns vor Augen geführt, dass die Informationen über das Symbol für die Implementierung in CStrategy zu umfangreich und vielfältig sind. Die Klasse CStrategy leistet bereits eine aufwändige und komplizierte Arbeit hinsichtlich der Organisation der Reihenfolge von Operationen, und die zusätzlichen Funktionen haben dazu geführt, dass der Code weniger handhabbar wurde. Stattdessen wurde die Entscheidung getroffen, Methoden für die Arbeit mit dem Symbol einer separaten Klasse CSymbol zuzuweisen.

Einführende Informationen zum Objekt WS und zur Klasse CSymbol

Statt sporadischer Methoden wie Ask(), Bid() und Last sowie spezieller Klassen wie CHigh und CLow, ist nun einer Handelsstrategie basierend auf CStrategy ein besonderes Objekt verfügbar - WS auf der Grundlage der Klasse CSymbol. Diese Klasse, die den Bibliotheken von CStrategy gehört, verfügt über eine Reihe von Methoden, die sie der Standardklasse СSymbolInfo ähnlich machen. Das ist aber eine andere Klasse, die nicht nur mit den Eigenschaften des Symbols arbeitet, sondern auch es erlaubt, seine Kurse zu erhalten einschließlich Limit Orders (Markttiefe). Der Name des Objekts "WS" stellt ein Akronym von "Work Symbol" dar, und es ist im Code der Strategie verfügbar. Dieser kurze Name wurde nicht durch Zufall ausgewählt. Während der Arbeit muss man häufig diese oder jene Eigenschaft des Symbols abrufen, deswegen erlaubt das Akronym aus zwei Zeichen dem Code kompakt und ausdrucksvoll zu bleiben. 

Wie wir bereits in den vorherigen Artikeln gesagt haben, initialisiert die CStrategy Trading-Engine eine Reihe von Objekten der internen Umgebung. Der Name des Symbols und der Zeitrahmen werden gespeichert, es werden die Klassen erstellt, die das Eintreffen neuer Ereignisse abfangen (standardmäßig geht es um die Ereignisse "Neuer Tick" und "Neuer Balken"). Es wird das Logging eingestellt, Flags der Arbeitsmodi werden gesetzt. In demselben Moment wird das Objekt WS der Klasse CSymbol initialisiert. Es ist relativ einfach geschaffen. Es beinhaltet zwei interne Felder: Symbol und dessen Zeitrahmen sowie spezielle Objekte für den Zugang zu den Kursen des Symbols. Das Objekt WS wird durch die Methode InitSeries initialisiert. Wenn man das Symbol und die Timeframe des Expert Advisors kennt, ist es ganz einfach, es zu initialisieren:

CStrategy::CStrategy(void)
{
   WS.InitSeries(ExpertSymbol(), Timeframe());
}

Nach der Initialisierung des Objekts kann man Eigenschaften des Symbols erhalten. Um den Hoch des aktuellen Balkens zu erhalten, schreibt man:

double max = WS.High[0];

Das Objekt WS verfügt über eine Reihe von Eigenschaften, dank denen seine Anwendung in den Berechnungen einfach und praktisch ist. Betrachten wir eine häufige Situation, dass man eine BuyStop Order ein wenig oberhalb des Hochs des vorherigen Balkens platzieren muss. Wenn wir auf EURUSD handeln und unsere Stop Order mit einem Abstand von drei fünfstelligen Punkten vom vorherigen Balken platzieren möchten, müssen wir den folgenden Code schreiben:

void CMovingAverage::InitBuy(const MarketEvent &event)
{
   ...
   Trade.BuyStop(1.0, WS.High[1] + WS.StepToPrice(3), WS.Name());
   ...
}

So haben wir innerhalb einer Code-Zeile viele Operationen platziert:

  • Extremum des vorherigen Balkens (WS.High[1]) erhalten;
  • Den Wert eines Punktes mit drei multiplizieren, dadurch erhalten wir einen Kursspielraum in Höhe von drei Punkten (WS.StepToPrice(3));
  • Den erhaltenen Wert (WS.High[1] + WS.StepToPrice(3)) zum Preis des Extremums addieren;
  • Handelsanfrage BuyStop senden, die Auslösungsebene ist der resultierende Preis, als Symbol den Namen des aktuellen Symbols (WS.Name()) angeben.

Die Methode StepToPrice kann sich vom üblichen Bezeichnungssystem in MetaTrader unterscheiden. In den anderen Handelsplattformen ist mit dem Price Step die minimale Preisänderung gemeint. Ihre Entsprechung heißt SYMBOL_TRADE_TICK_SIZE in MetaTrader. Dieser Name ist mit der Größe oder mit dem Preis eines Ticks SYMBOL_TRADE_TICK_VALUE leicht zu verwechseln, deswegen wird ein anderer Name für diesen Parametter in CSymbol verwendet. Aber die meisten anderen Methodennamen CSymbol stimmen mit System-Modifikatoren und Methoden in MQL5 überein, allerdings wie der Beispiel mit StepToPrice zeigt, sind sie nicht immer identisch. Das Hauptziel von CSymbol besteht darin, eine einfache und intuitive Methode zum Erhalten vollständiger Informationen über ein Handelssymbol bereitzustellen.

Struktur der Klasse CSymbol. Vergleichstabelle der Methoden

Handelssymbole verfügen in MetaTrader über eine breite Palette von Eigenschaften. Alle Eigenschaften kann man in ganzzahlige, reelle und String-Eigenschaften teilen. Zu den ganzzahligen Eigenschaften gehören logische Eigenschaften (bool), System-Modifikatoren in Form von Aufzählungen (enum), Zeit und Datum (datetime) und ganzzahlige Eigenschaften (int und long). Zu den reellen Eigenschaften gehören verschiedene gebrochene Zahlen (double). Zu den String-Eigenschaften gehören die Eigenschaften, die Strings zurückgeben: Symbolname, Beschreibung des Symbols nach Strings usw. Für das Symbol ist auch eine Reihe von Eigenschaften verfügbar, die für einen bestimmten Marktsegment charakteristisch sind. Für den FORTS-Markt sind zusätzliche Eigenschaften der aktuellen Handelssitzung verfügbar. Für Optionsmärkte sind spezielle einzigartige Eigenschaften verfügbar. Die Klasse CSymbol bestimmt Eigenschaften der aktuellen FORTS-Handelssitzung in einer zusätzlichen internen Klasse SessionInfo. Alle anderen Eigenschaften werden nicht nach Typen geteilt und sind als gleichnamige Methoden so, wie sie sind, vorhanden.

Darüber hinaus beinhaltet die Klasse CSymbol zusätzliche Sammlungen, die den Abruf von Kursen eines Symbols ermöglichen. Für den Zugriff auf die Serien OHLCV werden die Klassen COpen, CHigh, CLow, CClose und CVolume öffentlich deklariert, und für den Zugang zur Markttiefe wird eine besondere Klasse verwendet, CMarketWatch, die in einem separaten Artikel beschrieben wurde: "Das MQL5-Kochbuch: Implementierung Ihrer eigenen Markttiefe". Neben gleichnamigen Methoden und Indexer-Klassen, wie zum Beispiel CClose, beinhaltet die Klasse CSymbol mehrere Methoden, die keine Entsprechungen unter MQL5 Standardfunktionen oder der Klasse SymbolInfo haben. Gehen wir darauf ausführlicher ein.

Available — diese Methode gibt true zurück, wenn das Symbol mit dem angegebenen Namen im Terminal vorhanden ist. Wenn es dieses Symbol nicht gibt, wird false zurückgegeben.

IndexByTime — gibt den Index des Balkens zurück, der der angegebenen Zeit entspricht. Zum Beispiel wird der Variablen index der Wert 1 zugewiesen:

int index = WS.IndexByTime(WS.Time[1]);
// index = 1;

Diese Methode ist sehr praktisch, wenn uns die Zeit bekannt ist, und wenn wir die Nummer des Balkens erhalten möchten, der dieser Zeit entspricht. Nehmen wir an, der Expert Advisor muss eine Position schließen, nachdem er sie während BarsHold Balken gehalten hat. Ein solcher Code könnte wie folgt aussehen:

//+------------------------------------------------------------------+
//| Verwaltung einer Long-Position nach Moving Average      |
//+------------------------------------------------------------------+
void CImpulse::SupportBuy(const MarketEvent &event,CPosition *pos)
{
   int bar_open = WS.IndexByTime(pos.TimeOpen());
   if(bar_open >= BarsHold)
      pos.CloseAtMarket("Exit by time hold");
}

StepToPriceminimale Preisänderung in Punkten des Symbols. Die Bestimmung dieser Methode wurde oben beschrieben.

Die ganze Liste der Methoden CSymbol ist in einer Tabelle unten dargestellt. Das Feld "Beschreibung" beinhaltet eine kurze Beschreibung der Methode. Meistens fällt sie mit der offiziellen Beschreibung der gleichen Eigenschaft des Symbols in der Dokumentation zusammen, aber ich glaube für einige Methoden ist die Beschreibung sogar besser gelungen.

Das Feld "Typ" des Rückgabewertes beinhaltet den Typ, den eine Methode oder Sammlung liefert.

Das Feld "MQL5 Funktion oder System-Identifier" beinhaltet den Namen eines MQL5 System-Identifiers oder einer MQL5 Funktion, die die gleichen Funktionen hat. Wenn eine Systemfunktion angegeben wird, hat sie am Ende des Namens runde Klammern, zum Beispiel: CopyOpen() oder MarketBookGet(). Mit System-Modifikator ist einer der drei Modifikatoren gemeint, der beim Aufruf der Funktionen SymbolInfoInteger, SymbolInfoDouble oder SymbolInfoString angegeben werden muss. Dieser Modifikator muss zu einer der drei Aufzählungen gehören: ENUM_SYMBOL_INFO_INTEGER,  ENUM_SYMBOL_INFO_DOUBLE oder ENUM_SYMBOL_INFO_STRING. Zum Beispiel: wenn der Modifikator SYMBOL_TRADE_STOPS_LEVEL in der Spalte "MQL5 Funktion oder System-Identifizierer" angegeben wurde, bedeutet dies, dass die Funktion SymbolInfoInteger für die Erhaltung dieser Eigenschaft aufgerufen werden muss:

int stop_level = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);

Die Spalte "Name der Methode CSymbol" beinhaltet den Namen der Methode, die für die Rückgabe einer Eigenschaft zuständig ist. Um den Wochentag der Anrechnung von Swap zu erhalten, muss man die folgende Methode aufrufen:

ENUM_DAY_OF_WEEK day = WS.DayOfSwap3x();

Tabelle der Methoden:

Beschreibung Typ des Rückgabewertes Funktion oder System-Identifizierer in MQL5 Name der Methode von CSymbol
 ZUGANG ZU HISTORISCHEN DATEN DES SYMBOLS      
   Erhalten des Eröffnungskurses nach dem angegebenen Index des Balkens mit einem vorgegebenen Zeitrahmen  double  CopyOpen()  Open[]
   Erhalten des Hochkurses nach dem angegebenen Index des Balkens mit einem vorgegebenen Zeitrahmen  double  CopyHigh()  High[]
   Erhalten des Tiefkurses nach dem angegebenen Balkenindex mit einem vorgegebenen Zeitrahmen  double  CopyLow()  Low[]
   Erhalten des Schlusskurses nach dem angegebenen Index des Balkens mit einem vorgegebenen Zeitrahmen  double  CopyClose()  Close[]
   Erhalten des Volumens, das dem Balken mit dem angegebenen Index entspricht  double  CopyVolume()  Volume[]
   Erhalten der Eigenschaften der Markttiefe des Symbols, Zugriff auf Kurse des zweiten Levels (Level II)  MqlBookInfo  MarketBookGet()  MarketBook
 REELLE EIGENSCHAFTEN DES SYMBOLS      
   Zeichen dafür, dass dieses Symbol im Terminal vorhanden ist  bool  Keine Entsprechung  Available
   Anzahl der Balken auf diesem Symbol mit dieser Timeframe  int  Bars()   BarsTotal
   Zeitrahmen des Symbols  ENUM_TIMEFRAMES  Period()  Period
   Zeichen dafür, dass das Symbol in der Marktübersicht ausgewählt wurde  bool  SYMBOL_SELECT  SelectInMarketWatch
   Zeichen für Floating Spread  bool  SYMBOL_SPREAD_FLOAT  SpreadFloat
   Spread in Punkten  int  SYMBOL_SPREAD  Spread
   Minimaler Abstand (in Punkten) vom aktuellen Preis für die Platzierung einer Stop-Order  int  SYMBOL_TRADE_STOPS_LEVEL  StopLevel
   Freeze Level (in Punkten)  int  SYMBOL_TRADE_FREEZE_LEVEL  FreezeLevel
   Flags der erlaubten Modi des Ablaufs einer Order  int  SYMBOL_EXPIRATION_MODE  FlagsExpirationOrders
   Flags der erlaubten Ausführungsmodi einer Order  int  SYMBOL_FILLING_MODE  FlagsExecutionOrders
   Flags der erlaubten Ordertypen  int  SYMBOL_ORDER_MODE  FlagsAllowedOrders
   Gibt den Index des Balkens zurück, dessen Eröffnungskurs dem übergebenen Argument entspricht  int  Keine Entsprechung  IndexByTime
   Berechnungsmethode des Terminkontraktes  ENUM_SYMBOL_CALC_MODE  SYMBOL_TRADE_CALC_MODE  CalcContractType
   Typ der Orderausführung  ENUM_SYMBOL_TRADE_MODE  SYMBOL_TRADE_MODE  ExecuteOrderType
   Modus der Ausführung von Trades  ENUM_SYMBOL_TRADE_EXECUTION  SYMBOL_TRADE_EXEMODE  ExecuteDealsType
   Muster für die Swap-Berechnung  ENUM_SYMBOL_SWAP_MODE  SYMBOL_SWAP_MODE  CalcSwapMode
   Wochentag der Berechnung eines dreifachen Swaps  ENUM_DAY_OF_WEEK  SYMBOL_SWAP_ROLLOVER3DAYS  DayOfSwap3x
   Optionstyp  ENUM_SYMBOL_OPTION_MODE  SYMBOL_OPTION_MODE  OptionType
   Optionsrecht (Call/Put)  ENUM_SYMBOL_OPTION_RIGHT  SYMBOL_OPTION_RIGHT  OptionRight
   Zeit des letzten Kurses  datetime  SYMBOL_TIME  TimeOfLastQuote
   Erster Handelstag für das Symbol (wird gewöhnlich für Futures verwendet)  datetime  SYMBOL_START_TIME  StartDate
   Letzter Handelstag für das Symbol (wird gewöhnlich für Futures verwendet)  datetime  SYMBOL_EXPIRATION_TIME  ExpirationDate
EIGENSCHAFTEN DER AKTUELLEN HANDELSSITZUNG für MOEX FUTURES

 
   Gesamtzahl der Trades in der aktuellen Handelssitzung  long  SYMBOL_SESSION_DEALS  SymbolInfo.DealsTotal
   Gesamtzahl der Buy Orders im Moment  long  SYMBOL_SESSION_BUY_ORDERS  SymbolInfo.BuyOrdersTotal
   Gesamtzahl der Sell Orders im Moment  long  SYMBOL_SESSION_SELL_ORDERS  SymbolInfo.SellOrdersTotal
   Max.Volumen während der aktuellen Handelssitzung  long  SYMBOL_VOLUMEHIGH  SymbolInfo.HighVolume
   Min. Volumen während der aktuellen Handelssitzung  long  SYMBOL_VOLUMELOW  SymbolInfo.LowVolume
   Max. Bid während des Tages  double  SYMBOL_BIDHIGH  SymbolInfo.BidHigh
   Max. Ask während des Tages  double  SYMBOL_ASKHIGH  SymbolInfo.AskHigh
   Min. Bid während des Tages  double  SYMBOL_BIDLOW  SymbolInfo.BidLow
   Min. Ask während des Tages  double  SYMBOL_ASKLOW  SymbolInfo.AskLow
   Max. Last während des Tages  double  SYMBOL_LASTHIGH  SymbolInfo.LastHigh
   Min. Last während des Tages  double  SYMBOL_LASTLOW  SymbolInfo.LastLow
   Gesamtvolumen der Trades während der aktuellen Handelssitzung  double  SYMBOL_SESSION_VOLUME  SymbolInfo.VolumeTotal
   Gesamtumsatz während der aktuellen Handelssitzung  double  SYMBOL_SESSION_TURNOVER  SymbolInfo.TurnoverTotal
   Gesamtvolumen der offenen Positionen  double  SYMBOL_SESSION_INTEREST  SymbolInfo.OpenInterestTotal
   Gesamtvolumen der Kauforders im Moment  double  SYMBOL_SESSION_BUY_ORDERS_VOLUME  SymbolInfo.BuyOrdersVolume
   Gesamtvolumen der Verkaufsorders im Moment  double  SYMBOL_SESSION_SELL_ORDERS_VOLUME  SymbolInfo.SellOrdersVolume
   Eröffnungskurs der Handelssitzung  double  SYMBOL_SESSION_OPEN  SymbolInfo.PriceSessionOpen
   Schlusskurs der Handelssitzung  double  SYMBOL_SESSION_CLOSE  SymbolInfo.PriceSessionClose
   Gewichteter Durchschnittspreis  double  SYMBOL_SESSION_AW  SymbolInfo.PriceSessionAverage
   Abrechnungskurs während der aktuellen Handelssitzung  double  SYMBOL_SESSION_PRICE_SETTLEMENT  SymbolInfo.PriceSettlement
   Maximal zulässiger Kursänderungsbetrag während einer Handelssitzung  double  SYMBOL_SESSION_PRICE_LIMIT_MAX  SymbolInfo.PriceLimitMax
   Minimal zulässiger Kursänderungsbetrag während einer Handelssitzung  double  SYMBOL_SESSION_PRICE_LIMIT_MIN  SymbolInfo.PriceLimitMin
REELLE EIGENSCHAFTEN DES SYMBOLS       
   Ask — bester Verkaufskurs  double  SYMBOL_ASK  Ask
   Bid — bester Kaufkurs  double  SYMBOL_BID  Bid
   Last — Preis, zu welchem der letzte Trade ausgeführt wurde  double  SYMBOL_LAST  Last
   Wert der minimalen Preisänderung multipliziert mit der übergebenen Anzahl von Price Step  double  Keine Entsprechung  StepToPrice
   Wert eines Punktes (Ticks)  double  SYMBOL_POINT  PriceStep
   Preis eines Punktes (Ticks) in der Kontowährung  double  SYMBOL_TRADE_TICK_VALUE  TickValue
   Basispreis der Option  double  SYMBOL_OPTION_STRIKE  OptionStrike
   Kontraktgröße  double  SYMBOL_TRADE_CONTRACT_SIZE  ContractSize
   Min. Volumen für die Ausführung eines Trades  double  SYMBOL_VOLUME_MIN  VolumeContractMin
   Max. Volumen für die Ausführung eines Trades  double  SYMBOL_VOLUME_MAX  VolumeContractMax
   Minimale Schrittweite der Volumenänderung für den Abschluss eines Trades  double  SYMBOL_VOLUME_STEP  VolumeContractStep
   Maximal zulässiges Gesamtvolumen einer offenen Position und Pending Orders in einer Richtung (Kauf oder Verkauf) für dieses Symbol  double  SYMBOL_VOLUME_LIMIT  VolumeContractLimit
   Swap, der beim Halten einer Long-Position mit dem Volumen von einem Kontrakt gerechnet wird  double  SYMBOL_SWAP_LONG  SwapLong
   Swap, der beim Halten einer Short-Position mit dem Volumen von einem Kontrakt angerechnet wird  double  SYMBOL_SWAP_SHORT  SwapShort
   Margin, die für die Eröffnung einer 1-Lot-Position benötigt wird  double  SYMBOL_MARGIN_INITIAL  MarginInit
   Margin, die für die Erhaltung eines Lots einer offenen Position benötigt wird  double  SYMBOL_MARGIN_MAINTENANCE  MarginMaintenance
   Margin, die für das Halten eines Lot einer abgesicherten Position benötigt wird  double  SYMBOL_MARGIN_HEDGED  MarginHedged
 STRING-EIGENSCHAFTEN DES SYMBOLS      
   Symbolname  string  Symbol()  Name
   Name des Basis-Vermögenswertes für ein abgeleitetes Symbol  string  SYMBOL_BASIS  NameBasisSymbol
   Basiswährung des Symbols  string  SYMBOL_CURRENCY_BASE  NameBasisCurrency
   Währung des Profits  string  SYMBOL_CURRENCY_PROFIT  NameCurrencyProfit
   Währung der Margin  string  SYMBOL_CURRENCY_MARGIN  NameCurrencyMargin
   Quelle des aktuellen Kurses  string  SYMBOL_BANK  NameBank
   String-Beschreibung des Symbols  string  SYMBOL_DESCRIPTION  Description
   Name des Handelssymbols im System der internationalen Identifikationsnummern von Wertpapieren — ISIN  string  SYMBOL_ISIN  NameISIN
   Pfad im Baum der Symbole  string  SYMBOL_PATH  SymbolPath

Verwendung mehrerer Symbole gleichzeitig

Da CSymbol eine einfache Klasse darstellt, kann man unbegrenzt viele Objekte diese Klasse innerhalb des Expert Advisors erstellen. Das Objekt WS stellt nur eines dieser Objekte dar, das vorher durch die CStrategy Trading-Engine erstellt wurde, und das auf das aktuelle Symbol und auf den Zeitrahmen des Expert Advisors hinweist. Der Expert Advisor selbst kann ein zusätzliches Symbol erstellen, der Zugriff auf jedes andere Symbol bietet. Nehmen wir an, der Expert Advisor handelt am Terminmarkt der Moskauer Börse und verfolgt gleichzeitig zwei Symbole — Si und Brent. In seinem Code kann man zwei CSymbol Objekte platzieren und diese Si und Brent benennen:

//+------------------------------------------------------------------+
//|                                                EventListener.mqh |
//|           Copyright 2017, Vasiliy Sokolov, St-Petersburg, Russia |
//|                                https://www.mql5.com/de/users/c-4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Vasiliy Sokolov."
#property link      "https://www.mql5.com/de/users/c-4"
#include <Strategy\Strategy.mqh>

//+-------------------------------------------------------------------------------+
//| Das Template für eine Strategie, die mit zwei Symbolen gleichzeitig arbeitet  |
//+-------------------------------------------------------------------------------+
class CIntRate : public CStrategy
  {
   CSymbol           Si;         // Rubel-Dollar
   CSymbol           Brent;      // Öl
public:
   virtual void      OnEvent(const MarketEvent& event);
   virtual bool      OnInit();
  };
//+------------------------------------------------------------------+
//| Initialisiert die Symbole Öl und Rubel                           |
//+------------------------------------------------------------------+
bool CIntRate::OnInit(void)
  {
   Si.InitSeries("Si Splice", Timeframe());
   Brent.InitSeries("BR Splice", Timeframe());
   return true;
  }

//+------------------------------------------------------------------+
//| Ölpreis in Rubel                                                 |
//+------------------------------------------------------------------+
void CIntRate::OnEvent(const MarketEvent &event)
  {
   double brent_in_rub = Brent.Last()*Si.Last()/Si.ContractSize();
  }

//+------------------------------------------------------------------+

Dieser Code des Expert Advisors erhält die letzten Kurse der Öl- und Rubel-Futures und berechnet die bekannte Formel des Ölpreises in Rubel. Da ein Si Terminkontrakt gleich 1000$ ist, muss man das Ergebnis zusätzlich durch die Größe eines Terminkontrakts teilen. Da aber alle Eigenschaften in der Klasse CSymbol vereinigt sind, ist das eine einfache Operation. Der restliche Code ist auch einfach und bündig. Wichtig ist nicht zu vergessen, die Objekte Si und Brent beim Starten des Expert Advisors in der Methode OnInit zu initialisieren.

Zeichnung des Profils des Zinssatzes mithilfe von CSymbol

Das letzte Anwendungsbeispiel von CSymbol ist ein wenig komplizierter aber auch interessanter. Es ist bekannt, dass Futures mit einem Contango in Hinsicht auf den Basis-Vermögenswert gehandelt werden. Dies ist damit verbunden, dass der Preis für die Ware in der Zukunft teurer sein wird als der aktuelle Preis. Diese Differenz bestimmt den Zinssatz für eine Ware oder ein Vermögenswert auf dem Markt. Betrachten wir ein Beispiel mit dem Future Rubel/Dollar. Als ich den Artikel schrieb, machte sein Preis 56.2875 Rubel pro 1 Dollar aus, und der Preis des nächsten Terminkontraktes Si-6.17 belief sich auf 56682 Rubel pro 1000$ oder 56,682 Rubel pro 1 Dollar. D.h. die Differenz zwischen dem Preis und dem Preis in 30 Tagen (zum 16.05.2017, Si-6.17 verfällt in genau 30 Tagen) beträgt 0,395 Rubel oder 39,5 Kopeken. Der Rubel wertet also laut dem Markt ab und sinkt auf 39,5 Kopeken, was 0.7% von seinem aktuellen Preis ausmacht. Es ist leicht zu berechnen, dass die Inflation in 12 Monaten laut dem Markt 8,42% betragen wird. Das ist aber die Inflationsrate, die nur für den nächsten Future berechnet wurde. Wenn man Si-6.17 durch Si-9.17 ersetzt, fällt die Inflationsrate niedriger aus und beläuft sich auf 7.8% im Jahr. Wenn wir alle Si Futures mit dem Basispreis des Vermögenswertes vergleichen, können wir das Profil des Zinssatzes erhalten. Dieses Profil wird als Tabelle dargestellt, die die Erwartungen der Investoren je nach Zeit zeigt. Wir können, zum Beispiel, den Zinssatz für die nächsten 30, 100, 200, 300, 400 und 500 Tagen herausfinden.

Um diese Werte zu berechnen, müssen wir anscheinend verschiedene Eigenschaften der Symbole verwenden sowie die Liste der Symbole manipulieren. Die Aufgabenstellung für die Berechnung des Profils des Zinssatzes sieht wie folgt aus.

  1. Der Expert Advisor wird auf jedem Futures-Symbol gestartet. Er analysiert den Namen des Symbols und lädt die mit ihm verbundenen Futures.
  2. Jeder geladene Future stellt ein CSymbol Objekt dar, dass in der Liste der Symbole platziert wird.
  3. Im Moment des Eintreffens eines neuen Ticks durchläuft der Expert Advisor die Sammlung der Symbole. Für jedes Symbol wird sein Basis-Symbol gefunden.
  4. Es wird die Differenz zwischen dem Preis des ausgewählten Symbols und dem Preis des Basis-Symbols berechnet. Diese Differenz wird in Prozent umgerechnet und danach in den jährlichen Gegenwert umgewandelt. Dafür wird die Restlaufzeit des Futures berücksichtigt.
  5. Die erhaltene Differenz wird als eine Tabellenzeile auf das Panel ausgegeben. Jede Zeile sieht wie folgt aus: "Name des Futures — Anzahl der Tage bis zum Verfallstag — Zinssatz".

Aus der Beschreibung folgt, dass der Algorithmus nicht so einfach ist, wie er scheint. Aber mithilfe der CStrategy Engine und des Objekts CSymbol können wir den Rechenaufwand für den Expert Advisor wesentlich reduzieren. Unser Code wird als ein Expert Advisor implementiert, der Expert Advisor selbst wird aber keine Operationen ausführen. Stattdessen wird er einfach Zinssätze auf das Panel ausgeben. Betrachten wir den resultierenden Code:

//+------------------------------------------------------------------+
//|                                                EventListener.mqh |
//|           Copyright 2017, Vasiliy Sokolov, St-Petersburg, Russia |
//|                                https://www.mql5.com/de/users/c-4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Vasiliy Sokolov."
#property link      "https://www.mql5.com/de/users/c-4"
#include <Strategy\Strategy.mqh>
#include <Arrays\ArrayObj.mqh>
#include "Panel.mqh"

//+------------------------------------------------------------------+
//| Profil des Zinssatzes                                            |
//+------------------------------------------------------------------+
class CIntRate : public CStrategy
  {
   CArrayObj         Symbols;    // Liste der Symbole
   CPercentPanel     Panel;      // Panel der Zeichnung der Zinssätze
   double            BaseRate(CSymbol* fut);
public:
   virtual void      OnEvent(const MarketEvent& event);
   virtual bool      OnInit();
  };
//+----------------------------------------------------------------------------------+
//| Fügt die benötigten Futures für die Berechnung des Profils des Zinssatzes hinzu  |
//+----------------------------------------------------------------------------------+
bool CIntRate::OnInit(void)
  {
   string basis = WS.NameBasisSymbol();
   for(int i = 0; i < SymbolsTotal(false); i++)
   {
      string name = SymbolName(i, false);
      int index = StringFind(name, basis, 0);
      if(index != 0)
         continue;
      CSymbol* Fut = new CSymbol(name, Timeframe());
      if(Fut.ExpirationDate() == 0 || Fut.ExpirationDate() < TimeCurrent())
      {
         delete Fut;
         continue;
      }
      string text = "Add new symbol " + Fut.Name() + " in symbols list";
      CMessage* msg = new CMessage(MESSAGE_INFO, __FUNCTION__, text);
      Log.AddMessage(msg);
      Symbols.Add(Fut);
   }
   string text = "Total add symbols " + (string)Symbols.Total();
   CMessage* msg = new CMessage(MESSAGE_INFO, __FUNCTION__, text);
   Log.AddMessage(msg);
   if(Symbols.Total() > 0)
   {
      Panel.Show();
   }
   return true;
  }

//+------------------------------------------------------------------+
//| Berechnet das Profil und gibt es in die Tabelle aus              |
//+------------------------------------------------------------------+
void CIntRate::OnEvent(const MarketEvent &event)
  {
   double sec_one_day = 60*60*24;   //86 400
   for(int i = 0; i < Symbols.Total(); i++)
   {
      CSymbol* Fut = Symbols.At(i);
      double brate = BaseRate(Fut);
      double days = (Fut.ExpirationDate()-TimeCurrent())/sec_one_day;
      if(Fut.Last() == 0.0)
         continue;
      double per = (Fut.Last() - brate)/brate*100.0;
      double per_in_year = per/days*365;
      Panel.SetLine(i, Fut.NameBasisSymbol() + " " + DoubleToString(days, 0) + " Days:", DoubleToString(per_in_year, 2)+"%");
   }

  }
//+------------------------------------------------------------------+
//| Gibt den Spotkurs des Futures zurück                             |
//+------------------------------------------------------------------+
double CIntRate::BaseRate(CSymbol* fut)
{
   string name = fut.NameBasisSymbol();
   if(StringFind(name, "Si", 0) == 0)
      return SymbolInfoDouble("USDRUB_TOD", SYMBOL_LAST)*fut.ContractSize();
   return SymbolInfoDouble(name, SYMBOL_LAST)*fut.ContractSize();
}
//+------------------------------------------------------------------+

Die wichtigsten Funktionen beinhaltet die Methode OnInit. Sie erhält den Namen eines Basis-Symbols über WS.NameBasisSymbol(), durchläuft alle Symbole und legt alle Futures fest, die dem Basis-Symbol entsprechen. Jeder Future wird ins Objekt CSymbol umgewandelt und in die Liste der Symbole CArrayObj platziert. Aber zuerst wird überprüft, ob dieser Future gültig ist, und wenn sein Verfallstag in der Zukunft liegt, dann ist es der Future, den wir brauchen.

In der Methode OnEvent wird der Zinssatz für jeden Futures berechnet, der in der Sammlung "Symbols" platziert ist. Es wird die Anzahl der Tage bis zum Verfallstag, das Delta zwischen dem Future und dem Spotpreis berechnet. Die Differenz zwischen den Preisen wird in Prozent umgerechnet, und das Prozent wird entsprechend der jährlichen Rendite normiert. Der erhaltene Wert wird in die Tabelle Panel (Methode SetLine) eingetragen.

Die Tabelle selbst ist ganz einfach und basiert auf dem gleichen Set grafischer Klassen, wie das CStrategy Panel, das zusammen mit dem Expert Advisor erscheint. Der Code der grafischen Komponente des Expert Advisors ist unten angeführt:

//+------------------------------------------------------------------+
//|                                                        Panel.mqh |
//|                                 Copyright 2017, Vasiliy Sokolov. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Vasiliy Sokolov."
#property link      "https://www.mql5.com"
#include <Panel\ElChart.mqh>

class CPercentPanel : public CElChart
{
private:
   CArrayObj  m_fields;
   CArrayObj  m_values;
public:
   
   CPercentPanel(void);
   void SetLine(int index, string field, string value);
};
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPercentPanel::CPercentPanel(void) : CElChart(OBJ_RECTANGLE_LABEL)
{
   Width(200);
   Height(200);
}
//+------------------------------------------------------------------+
//| Setzt die Linie                                                  |
//+------------------------------------------------------------------+
void CPercentPanel::SetLine(int index,string field,string value)
{
   if(m_fields.Total() <= index)
   {
      CElChart* sfield = new CElChart(OBJ_LABEL);
      sfield.XCoord(XCoord()+10);
      sfield.YCoord(YCoord()+21*index+10);
      sfield.Text(field);
      m_fields.Add(sfield);
      m_elements.Add(sfield);
      
      CElChart* svalue = new CElChart(OBJ_LABEL);
      svalue.YCoord(YCoord()+21*index+10);
      svalue.XCoord(XCoord()+132);
      svalue.Text(value);
      svalue.TextColor(clrGreen);
      m_values.Add(svalue);
      m_elements.Add(svalue);
      if(IsShowed())
      {
         sfield.Show();
         svalue.Show();
      }
      Height(m_fields.Total()*20 + m_fields.Total()*2 + 10);
   }
   else
   {
      CElChart* el = m_fields.At(index);
      el.Text(field);
      el = m_values.At(index);
      el.Text(value);
   }
   ChartRedraw();
}

Nachdem dieser Expert Advisor kompiliert und auf einem der Charts des Si Futures gestartet wird, erscheint die folgende Tabelle:

Profil des Zinssatzes Rubel/Dollar als Tabelle

Wie man anhand der Tabelle sieht, sind die Zinssätze quasi auf allen Timeframes gleich und belaufen sich auf 7% jährlich. Einen höheren Zinssatz weist der nächste Future auf. 

Wichtiger Hinweis: vor dem Start des Experten vergewissern Sie sich, dass die Kurse aller benötigten Futures verfügbar sind und im Voraus geladen wurden. Andernfalls kann das Ergebnis unbestimmt sein.

Fazit

Wir haben die neue Klasse CSymbol im Rahmen der Klassen CStrategy betrachtet. Dank dieser Klasse ist es einfacher geworden, mit Symbolen zu arbeiten und ihre Eigenschaften zu erhalten. Dank CSymbol haben wir einen interessanten und unkonventionellen Indikator des Profils des Zinssatzes erstellt. Dieses Beispiel ist sehr repräsentativ. Es wurde eine Vielzahl von Eigenschaften aus CSymbol Objekten erhalten, und die Berechnung war nicht so kompliziert. Der Expert Advisor arbeitete gleichzeitig mit sechs Symbolen, dadurch wurde aber sein Code nicht länger. Da CStrategy von CObject abgeleitet wird, ist es einfach, Instanzen dieser Klasse in Standardsammlungen zu platzieren. Dadurch wird die Datenverarbeitung basierend auf dieser Klasse skalierbar und universell. Darüber hinaus wies CStrategy der CSymbol Klasse untypische Funktionen zu, dank denen die CStrategy Klasse leichter geworden ist und sich besser verwalten lässt.