Nachrichtenhandel leicht gemacht (Teil 2): Risikomanagement
Einführung
Eine kurze Auffrischung des vorherigen Artikels aus der Reihe „Nachrichtenhandel leicht gemacht“. In Teil 1 haben wir uns mit dem Konzept der Sommerzeit und den verschiedenen Versionen für die verschiedenen Länder beschäftigt, die ihre Zeitzonen im Laufe eines Geschäftsjahres um eine Stunde vor- oder zurückstellen. Dadurch ändern sich die Handelszeiten für die entsprechenden Makler, die die Sommerzeit nutzen. Die Gründe für die Einrichtung einer Datenbank und die Vorteile wurden angesprochen. Es wurde eine Datenbank erstellt, um die Nachrichtenereignisse aus dem MQL5-Wirtschaftskalender zu speichern, wobei die Zeitdaten der Ereignisse nachträglich geändert wurden, um den Sommerzeitplan des Maklers für ein genaues Backtesting in der Zukunft widerzuspiegeln. In den Projektdateien wurde ein SQL-Skriptergebnis im Excel-Format für alle einmaligen Ereignisse bereitgestellt, die über den MQL5-Kalender für alle verschiedenen Länder zugänglich sind.
In diesem Artikel werden wir jedoch einige Änderungen an unserem vorherigen Code aus Teil 1 vornehmen. Erstens wird die bisherige Nachrichten-/Kalenderdatenbank durch die Implementierung von Vererbung in den bestehenden Code und den kommenden neuen Code in etwas Nützlicheres und Praktischeres umgewandelt. Darüber hinaus werden wir uns mit dem Risikomanagement befassen und verschiedene Risikoprofile erstellen, aus denen Nutzer mit unterschiedlicher Risikobereitschaft oder Präferenz wählen können.
Vererbung
Was ist Vererbung?
Vererbung ist ein grundlegendes Konzept der objektorientierten Programmierung (OOP), das es einer neuen Klasse (Unterklasse oder abgeleitete Klasse genannt) ermöglicht, Eigenschaften und Verhaltensweisen (Felder und Methoden) von einer bestehenden Klasse (Oberklasse oder Basisklasse genannt) zu erben. Dieser Mechanismus bietet eine Möglichkeit, eine neue Klasse zu erstellen, indem das Verhalten einer bestehenden Klasse erweitert oder geändert wird, was die Wiederverwendung von Code und die Schaffung einer logischeren und hierarchischeren Klassenstruktur fördert.
Was ist der Zweck der Vererbung?
Die Vererbung ermöglicht die Wiederverwendung von bestehendem Code. Indem sie von einer Basisklasse erbt, kann eine Unterklasse vorhandene Methoden und Felder nutzen, ohne sie neu schreiben zu müssen. Dies verringert die Redundanz und macht den Code leichter wartbar. Vererbung hilft bei der Organisation von Code in einer hierarchischen Struktur, die leichter zu verstehen und zu verwalten ist. Klassen können auf der Grundlage gemeinsamer Attribute und Verhaltensweisen gruppiert werden, was zu einer klaren und logischen Organisation der Codebasis führt. Die Vererbung ist eng mit dem Polymorphismus verbunden, der es ermöglicht, Objekte verschiedener Klassen als Objekte einer gemeinsamen Oberklasse zu behandeln. Dies ist besonders nützlich für die Implementierung von flexiblem und erweiterbarem Code. So kann eine Funktion beispielsweise auf Objekte verschiedener Klassen wirken, solange sie von derselben Basisklasse erben, was eine dynamische Methodenbindung und einen allgemeineren Code ermöglicht.
Die Vererbung ermöglicht die Erweiterung der Funktionsweisen bestehender Klassen. Unterklassen können neue Methoden und Felder hinzufügen oder bestehende überschreiben, um bestimmte Verhaltensweisen einzuführen, ohne die ursprüngliche Klasse zu verändern. Dies fördert das Prinzip der Offenheit und Geschlossenheit, bei dem Klassen offen für Erweiterungen, aber geschlossen für Änderungen sind. Die Vererbung unterstützt die Kapselung, indem sie es einer Unterklasse ermöglicht, auf die geschützten und öffentlichen Mitglieder einer Oberklasse zuzugreifen, während die Implementierungsdetails privat bleiben. Dadurch wird eine klare Trennung zwischen der Schnittstelle und der Implementierung gewährleistet, was die Modularität erhöht und das Risiko unbeabsichtigter Wechselwirkungen verringert.
Was sind Zugangsmodifikatoren?
Zugriffsmodifikatoren sind Schlüsselwörter in objektorientierten Programmiersprachen, die die Zugänglichkeit von Klassen, Methoden/Funktionen und anderen Mitgliedern festlegen. Sie kontrollieren die Sichtbarkeit und Zugänglichkeit dieser Elemente von verschiedenen Teilen des Codes aus und erzwingen so eine Kapselung und schützen die Integrität der Daten.
Arten von Zugangsmodifikatoren
- Public (Öffentlich)
- Privat
- Protected (Geschützt)
1. Public (Öffentlich)
Ziel: Um eine Klasse, Funktion oder Variable für die Verwendung in anderen Klassen oder Programmen verfügbar zu machen.
2. Privat
Ziel: Um den Zugriff auf die Mitglieder einer Klasse zu beschränken und so die Integrität der Daten zu schützen.
3. Protected (Geschützt)
Ziel: Um Unterklassen die Möglichkeit zu geben, zu erben und auf die Mitglieder zuzugreifen, während der Zugriff von Objekten der Klasse weiterhin eingeschränkt wird.
Vererbung Beispiel in Bezug auf MQL5
Wir erstellen zunächst ein UML-Klassendiagramm für das Beispiel, um die Klassen und ihre Beziehungen und Attribute zu visualisieren.
Die Klassen UnitedStates und Switzerland werden jeweils beide nur von der Klasse NewsData abgeleitet:
class NewsData { private://Properties are only accessible from this class string Country;//Private variable struct EventDetails//Private structure { int EventID; string EventName; datetime EventDate; }; protected: //-- Protected Array Only accessible from this class and its children EventDetails News[]; //-- Proctected virtual void Function(to be expanded on via child classes) virtual void SetNews(); //-- Protected Function Only accessible from this class and its children void SetCountry(string myCountry) {Country=myCountry;} public: void GetNews()//Public function to display 'News' array details { PrintFormat("+---------- %s ----------+",Country); for(uint i=0;i<News.Size();i++) { Print("ID: ",News[i].EventID," Name: ",News[i].EventName," Date: ",News[i].EventDate); } } NewsData(void) {}//Class constructor ~NewsData(void) {ArrayFree(News);}//Class destructor }; //+------------------------------------------------------------------+ //|(Subclass/Child) for 'NewsData' | //+------------------------------------------------------------------+ class UnitedStates:private NewsData //private inheritance from NewsData, //'UnitedStates' class's objects and children //will not have access to 'NewsData' class's properties { private: virtual void SetNews()//private Function only Accessible in 'UnitedStates' class { ArrayResize(News,News.Size()+1,News.Size()+2); News[News.Size()-1].EventID = 1; News[News.Size()-1].EventName = "NFP(Non-Farm Payrolls)"; News[News.Size()-1].EventDate = D'2024.01.03 14:00:00'; } public: void myNews()//public Function accessible via class's object { SetCountry("United States");//Calling function from 'NewsData' GetNews();//Calling Function from private inherited class 'NewsData' } UnitedStates(void) {SetNews();}//Class constructor }; //+------------------------------------------------------------------+ //|(Subclass/Child) for 'NewsData' | //+------------------------------------------------------------------+ class Switzerland: public NewsData //public inheritance from NewsData { public: virtual void SetNews()//Public Function to set News data { ArrayResize(News,News.Size()+1,News.Size()+2);//Adjusting News structure array's size News[News.Size()-1].EventID = 0;//Setting event id to '0' News[News.Size()-1].EventName = "Interest Rate Decision";//Assigning event name News[News.Size()-1].EventDate = D'2024.01.06 10:00:00';//Assigning event date } Switzerland(void) {SetCountry("Switerland"); SetNews();}//Class construct };
In diesem Beispiel:
Die (übergeordnete/Basis-/Super-) Klasse wäre NewsData und alle privaten Deklarationen wären nur für diese Klasse zugänglich. Die privaten Deklarationen sind für die Objekte und Kinder der Klasse unzugänglich. Während die geschützten Deklarationen sowohl für die Klasse als auch für ihre Kinder zugänglich sind. Alle öffentlichen Deklarationen sind für die Klasse, ihre Kinder und Objekte zugänglich.
Erreichbarkeitstabelle für NewsData:
Eigenschaften der Klasse | Klasse | Kinder | Objekte |
---|---|---|---|
Variabel: Country(Private) | ✔ | ✘ | ✘ |
Struktur: EventDetails(Private) | ✔ | ✘ | ✘ |
Variabel: Nachrichten(Geschützt) | ✔ | ✔ | ✘ |
Funktion: SetNews(Protected) | ✔ | ✔ | ✘ |
Funktion: SetCountry(Protected) | ✔ | ✔ | ✘ |
Funktion: GetNews(Public) | ✔ | ✔ | ✔ |
Konstruktor: NewsData(Public) | ✔ | ✘ | ✘ |
Destructor: ~NewsData(Public) | ✔ | ✘ | ✘ |
class NewsData { private://Properties are only accessible from this class string Country;//Private variable struct EventDetails//Private structure { int EventID; string EventName; datetime EventDate; }; protected: //-- Protected Array Only accessible from this class and its children EventDetails News[]; //-- Proctected virtual void Function(to be expanded on via child classes) virtual void SetNews(); //-- Protected Function Only accessible from this class and its children void SetCountry(string myCountry) {Country=myCountry;} public: void GetNews()//Public function to display 'News' array details { PrintFormat("+---------- %s ----------+",Country); for(uint i=0;i<News.Size();i++) { Print("ID: ",News[i].EventID," Name: ",News[i].EventName," Date: ",News[i].EventDate); } } NewsData(void) {}//Class constructor ~NewsData(void) {ArrayFree(News);}//Class destructor };
Sichtbare Eigenschaften des NewsData-Objekts:
Ergebnis der Funktion GetNews von NewsData:
Die Vererbung ist bei den beiden übrigen Klassen implementiert:
In der (untergeordneten/abgeleiteten) Klasse UnitedStates erbt sie die übergeordnete Klasse (NewsData) privat.
Das bedeutet, dass die Unterklasse (UnitedStates) auf die geschützten und öffentlichen Eigenschaften der übergeordneten Klasse (NewsData) zugreifen kann, aber die untergeordneten Objekte der Klasse UnitedStates und ihre Objekte haben keinen Zugriff auf die Eigenschaften der übergeordneten Klasse (NewsData). Wäre der Zugriffsmodifikator „protected“, hätte die abgeleitete Klasse UnitedStates Zugriff sowohl auf die „protected“ und die „public“ Eigenschaften der Elternklassen (NewsData), aber die Objekte der abgeleiteten Klasse (UnitedStates) hätten keinen Zugriff auf die der Elternklasse.
Erreichbarkeitstabelle für die UnitedStates:
Eigenschaften der Klasse | Klasse | Kinder | Objekte |
---|---|---|---|
Vererbung(Privat) Variable: Country(Private) | ✘ | ✘ | ✘ |
Vererbung(Privat) Struktur: EventDetails(Private) | ✘ | ✘ | ✘ |
Vererbung(Privat) Variable: Nachrichten(Geschützt) | ✔ | ✘ | ✘ |
Vererbung(Privat) Funktion: SetNews(Protected) | ✔ | ✘ | ✘ |
Vererbung(Privat) Funktion: SetCountry(Protected) | ✔ | ✘ | ✘ |
Vererbung(Privat) Funktion: GetNews(Public) | ✔ | ✘ | ✘ |
Vererbung(Privat) Konstrukteur: NewsData(Public) | ✘ | ✘ | ✘ |
Vererbung(Privat) Destruktor: ~NewsData(Public) | ✘ | ✘ | ✘ |
Funktion: SetNews(Privat) | ✔ | ✘ | ✘ |
Function: myNews(Public) | ✔ | ✔ | ✔ |
Konstruktor: UnitedStates(Public) | ✔ | ✘ | ✘ |
class UnitedStates:private NewsData //private inheritance from NewsData, //'UnitedStates' class's objects and children //will not have access to 'NewsData' class's properties { private: virtual void SetNews()//private Function only Accessible in 'UnitedStates' class { ArrayResize(News,News.Size()+1,News.Size()+2); News[News.Size()-1].EventID = 1; News[News.Size()-1].EventName = "NFP(Non-Farm Payrolls)"; News[News.Size()-1].EventDate = D'2024.01.03 14:00:00'; } public: void myNews()//public Function accessible via class's object { SetCountry("United States");//Calling function from 'NewsData' GetNews();//Calling Function from private inherited class 'NewsData' } UnitedStates(void) {SetNews();}//Class constructor };
Sichtbare Eigenschaften aus dem UnitedStates-Objekt:
Es entsteht ein Kompilierfehler, wenn versucht wird, auf die Funktion GetNews zuzugreifen, die von NewsData abgeleitet wurde. Dies verhindert, dass das Objekt UnitedStates auf diese Funktion zugreifen kann.
In der (Kind-/Unter-/abgeleiteten) Klasse Switzerland.
Der Zugriffsmodifikator für die Vererbung ist öffentlich (public). Dadurch haben die Kinder der Unterklasse (Switzerland) Zugriff auf die „public“ und „protected“ Eigenschaften der Oberklasse (NewsData), während die Objekte der Klasse Switzerland nur Zugriff auf die „public“ Eigenschaften aller verwandten Klassen haben.
Erreichbarkeitstabelle für die Switzerland:
Eigenschaften der Klasse | Klasse | Kinder | Objekte |
---|---|---|---|
Vererbung(Public) Variable: Country(Private) | ✘ | ✘ | ✘ |
Vererbung(Öffentlich) Struktur: EventDetails(Private) | ✘ | ✘ | ✘ |
Vererbung(Public) Variable: Nachrichten(Geschützt) | ✔ | ✔ | ✘ |
Vererbung(Public) Funktion: SetNews(Protected) | ✔ | ✔ | ✘ |
Vererbung(Public) Funktion: SetCountry(Protected) | ✔ | ✔ | ✘ |
Vererbung(Public) Funktion: GetNews(Public) | ✔ | ✔ | ✔ |
Vererbung(Public) Konstrukteur: NewsData(Public) | ✘ | ✘ | ✘ |
Vererbung(Public) Destruktor: ~NewsData(Public) | ✘ | ✘ | ✘ |
Funktion: SetNews(Public) | ✔ | ✔ | ✔ |
Konstruktor: Switzerland(Public) | ✔ | ✘ | ✘ |
class Switzerland: public NewsData //public inheritance from NewsData { public: virtual void SetNews()//Public Function to set News data { ArrayResize(News,News.Size()+1,News.Size()+2);//Adjusting News structure array's size News[News.Size()-1].EventID = 0;//Setting event id to '0' News[News.Size()-1].EventName = "Interest Rate Decision";//Assigning event name News[News.Size()-1].EventDate = D'2024.01.06 10:00:00';//Assigning event date } Switzerland(void) {SetCountry("Switerland"); SetNews();}//Class construct };
Sichtbare Eigenschaften des Objekts Switzerland:
Ergebnisse:
Die Klassen für die Sommerzeit
In Nachrichtenhandel leicht gemacht (Teil 1):
UML-Klassendiagramm
Projektdateien:
Im vorherigen Code hatten wir drei Klassen für die Sommerzeit, nämlich:
- CDaylightSparen_AU
- CDaylightSavings_UK
- CDaylightSavings_US
In Teil 2:
UML-Klassendiagramm
Projektdateien:
Wegen der Sommerzeit erstellen wir folgende Klassen statt:
- CDaylightSavings
- CDaylightSparen_AU
- CDaylightSavings_UK
- CDaylightSavings_US
Warum eine weitere Klasse für die Sommerzeit?
Im Code der vorherigen Klassen gab es viele Wiederholungen zwischen den Klassen, d. h. es wurde im Wesentlichen derselbe Code für verschiedene Werte in einer Liste noch einmal geschrieben. Anstatt diese Wiederholung bei ähnlichen Klassen vorzunehmen, werden wir alle Gemeinsamkeiten in einer separaten Klasse zusammenfassen und die gemeinsamen Merkmale an die verschiedenen Sommerzeitklassen vererben.
Was sind virtuelle Funktionen?
In der objektorientierten Programmierung (OOP) ist eine virtuelle Funktion eine Mitgliedsfunktion in einer Basisklasse, die in einer abgeleiteten Klasse überschrieben werden kann. Wenn eine Funktion als virtuell deklariert wird, ermöglicht sie Polymorphismus, sodass die abgeleitete Klasse eine spezifische Implementierung der Funktion bereitstellen kann, die über einen Zeiger oder eine Referenz der Basisklasse aufgerufen werden kann.
Zweck?
- Polymorphismus: Virtuelle Funktionen ermöglichen einen dynamischen Polymorphismus (zur Laufzeit). Das bedeutet, dass die Methode, die ausgeführt wird, zur Laufzeit auf der Grundlage des tatsächlichen Typs des referenzierten Objekts und nicht des Typs der Referenz oder des Zeigers bestimmt wird.
- Flexibilität: Sie ermöglichen flexibleren und wiederverwendbaren Code, indem sie abgeleiteten Klassen erlauben, das Verhalten der Basisklasse zu ändern oder zu erweitern.
- Entkopplung: Virtuelle Funktionen helfen bei der Entkopplung des Codes, indem sie die Schnittstelle von der Implementierung trennen, was es einfacher macht, die Implementierung zu ändern, ohne den Code zu beeinflussen, der die Schnittstelle der Basisklasse verwendet.
Die Klasse CDaylightSavings
In dieser Klasse werden alle Gemeinsamkeiten der vorherigen Codes in einer Klasse zusammengefasst und wir werden einige virtuelle Funktionen deklarieren, um die verschiedenen Listen für den jeweiligen Sommerzeitplan zu initialisieren.
Die Klasse CDaylightSavings ist einmalig von der Klasse CObject abgeleitet.
Die Klasse CDaylightSavings hat bindet diese Klassen ein:
- CArrayObj
- CTimeManagement
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include <Object.mqh> #include <Arrays\ArrayObj.mqh> #include "../TimeManagement.mqh" //+------------------------------------------------------------------+ //|DaylightSavings class | //+------------------------------------------------------------------+ class CDaylightSavings: public CObject { protected: CTimeManagement Time; CDaylightSavings(datetime startdate,datetime enddate); CObject *List() { return savings;}//Gets the list of Daylightsavings time datetime StartDate; datetime EndDate; CArrayObj *savings; CArrayObj *getSavings; CDaylightSavings *dayLight; virtual void SetDaylightSavings_UK();//Initialize UK Daylight Savings Dates into List virtual void SetDaylightSavings_US();//Initialize US Daylight Savings Dates into List virtual void SetDaylightSavings_AU();//Initialize AU Daylight Savings Dates into List public: CDaylightSavings(void); ~CDaylightSavings(void); bool isDaylightSavings(datetime Date);//This function checks if a given date falls within Daylight Savings Time. bool DaylightSavings(int Year,datetime &startDate,datetime &endDate);//Check if DaylightSavings Dates are available for a certain Year string adjustDaylightSavings(datetime EventDate);//Will adjust the date's timezone depending on DaylightSavings }; //+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CDaylightSavings::CDaylightSavings(void) { } //+------------------------------------------------------------------+ //|Initialize variables | //+------------------------------------------------------------------+ CDaylightSavings::CDaylightSavings(datetime startdate,datetime enddate) { StartDate = startdate;//Assign class's global variable StartDate value from parameter variable startdate EndDate = enddate;//Assign class's global variable EndDate value from parameter variable enddate } //+------------------------------------------------------------------+ //|checks if a given date falls within Daylight Savings Time | //+------------------------------------------------------------------+ bool CDaylightSavings::isDaylightSavings(datetime Date) { // Initialize a list to store daylight savings periods. getSavings = List(); // Iterate through all the periods in the list. for(int i=0; i<getSavings.Total(); i++) { // Access the current daylight savings period. dayLight = getSavings.At(i); // Check if the given date is within the current daylight savings period. if(Time.DateIsInRange(dayLight.StartDate,dayLight.EndDate,Date)) { // If yes, return true indicating it is daylight savings time. return true; } } // If no period matches, return false indicating it is not daylight savings time. return false; } //+------------------------------------------------------------------+ //|Check if DaylightSavings Dates are available for a certain Year | //+------------------------------------------------------------------+ bool CDaylightSavings::DaylightSavings(int Year,datetime &startDate,datetime &endDate) { // Initialize a list to store daylight savings periods. getSavings = List(); bool startDateDetected=false,endDateDetected=false; // Iterate through all the periods in the list. for(int i=0; i<getSavings.Total(); i++) { dayLight = getSavings.At(i); if(Year==Time.ReturnYear(dayLight.StartDate))//Check if a certain year's date is available within the DaylightSavings start dates in the List { startDate = dayLight.StartDate; startDateDetected = true; } if(Year==Time.ReturnYear(dayLight.EndDate))//Check if a certain year's date is available within the DaylightSavings end dates in the List { endDate = dayLight.EndDate; endDateDetected = true; } if(startDateDetected&&endDateDetected)//Check if both DaylightSavings start and end dates are found for a certain Year { return true; } } startDate = D'1970.01.01 00:00:00';//Set a default start date if no DaylightSaving date is found endDate = D'1970.01.01 00:00:00';//Set a default end date if no DaylightSaving date is found return false; } //+------------------------------------------------------------------+ //|Will adjust the date's timezone depending on DaylightSavings | //+------------------------------------------------------------------+ string CDaylightSavings::adjustDaylightSavings(datetime EventDate) { if(isDaylightSavings(TimeTradeServer()))//Check if the current tradeserver time is already within the DaylightSavings Period { if(isDaylightSavings(EventDate))//Checks if the event time is during daylight savings { return TimeToString(EventDate);//normal event time } else { return TimeToString((datetime)(EventDate-Time.HoursS()));//event time minus an hour for DST } } else { if(isDaylightSavings(EventDate))//Checks if the event time is during daylight savings { return TimeToString((datetime)(Time.HoursS()+EventDate));//event time plus an hour for DST } else { return TimeToString(EventDate);//normal event time } } } //+------------------------------------------------------------------+ //|Destructor | //+------------------------------------------------------------------+ CDaylightSavings::~CDaylightSavings(void) { delete savings;//Delete CArrayObj Pointer delete dayLight;//Delete CDaylightSavings Pointer delete getSavings;//Delete CArrayObj Pointer } //+------------------------------------------------------------------+
Die Klasse CDaylightSavings_AU
In dieser Klasse erweitern wir die virtuelle void-Methode SetDaylightSavings_AU und fügen den Sommerzeitplan für Australien hinzu.
Die Daten der australischen Sommerzeit wurden hier veröffentlicht.
Die Klasse CDaylightSavings_AU hat eine mehrstufige Vererbung von Klassen:
- CDaylightSavings
- CObject
Die Klasse CDaylightSavings_AU besitzt eine hierarchische Vererbung der Klassen:
- CDaylightSavings
- CArrayObj
- CTimeManagement
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include "DaylightSavings.mqh" //+------------------------------------------------------------------+ //|DaylightSavings_AU class | //+------------------------------------------------------------------+ class CDaylightSavings_AU: public CDaylightSavings { public: CDaylightSavings_AU(void); }; //+------------------------------------------------------------------+ //|Set Daylight Savings Schedule for Australia | //+------------------------------------------------------------------+ void CDaylightSavings::SetDaylightSavings_AU() { savings = new CArrayObj(); //Daylight savings dates to readjust dates in the database for accurate testing in the strategy tester savings.Add(new CDaylightSavings(D'2006.10.29 03:00:00',D'2007.03.25 02:00:00')); savings.Add(new CDaylightSavings(D'2007.10.28 03:00:00',D'2008.04.06 02:00:00')); savings.Add(new CDaylightSavings(D'2008.10.05 03:00:00',D'2009.04.05 02:00:00')); savings.Add(new CDaylightSavings(D'2009.10.04 03:00:00',D'2010.04.04 02:00:00')); savings.Add(new CDaylightSavings(D'2010.10.03 03:00:00',D'2011.04.03 02:00:00')); savings.Add(new CDaylightSavings(D'2011.10.02 03:00:00',D'2012.04.01 02:00:00')); savings.Add(new CDaylightSavings(D'2012.10.07 03:00:00',D'2013.04.07 02:00:00')); savings.Add(new CDaylightSavings(D'2013.10.06 03:00:00',D'2014.04.06 02:00:00')); savings.Add(new CDaylightSavings(D'2014.10.05 03:00:00',D'2015.04.05 02:00:00')); savings.Add(new CDaylightSavings(D'2015.10.04 03:00:00',D'2016.04.03 02:00:00')); savings.Add(new CDaylightSavings(D'2016.10.02 03:00:00',D'2017.04.02 02:00:00')); savings.Add(new CDaylightSavings(D'2017.10.01 03:00:00',D'2018.04.01 02:00:00')); savings.Add(new CDaylightSavings(D'2018.10.07 03:00:00',D'2019.04.07 02:00:00')); savings.Add(new CDaylightSavings(D'2019.10.06 03:00:00',D'2020.04.05 02:00:00')); savings.Add(new CDaylightSavings(D'2020.10.04 03:00:00',D'2021.04.04 02:00:00')); savings.Add(new CDaylightSavings(D'2021.10.03 03:00:00',D'2022.04.03 02:00:00')); savings.Add(new CDaylightSavings(D'2022.10.02 03:00:00',D'2023.04.02 02:00:00')); savings.Add(new CDaylightSavings(D'2023.10.01 03:00:00',D'2024.04.07 02:00:00')); savings.Add(new CDaylightSavings(D'2024.10.06 03:00:00',D'2025.04.06 02:00:00')); savings.Add(new CDaylightSavings(D'2025.10.05 03:00:00',D'2026.04.05 02:00:00')); savings.Add(new CDaylightSavings(D'2026.10.04 03:00:00',D'2027.04.04 02:00:00')); savings.Add(new CDaylightSavings(D'2027.10.03 03:00:00',D'2028.04.02 02:00:00')); savings.Add(new CDaylightSavings(D'2028.10.01 03:00:00',D'2029.04.01 02:00:00')); } //+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CDaylightSavings_AU::CDaylightSavings_AU(void) { SetDaylightSavings_AU(); } //+------------------------------------------------------------------+
Die Klasse CDaylightSavings_UK
In dieser Klasse erweitern wir die virtuelle void-Methode SetDaylightSavings_UK und fügen den Sommerzeitplan für Europa hinzu.
Die Daten für die Sommerzeit im Vereinigten Königreich wurden hier veröffentlicht.
Die Klasse CDaylightSavings_UK hat eine mehrstufige Vererbung von Klassen:
- CDaylightSavings
- CObject
Die Klasse CDaylightSavings_UK besitzt eine hierarchische Vererbung der Klassen:
- CDaylightSavings
- CArrayObj
- CTimeManagement
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include "DaylightSavings.mqh" //+------------------------------------------------------------------+ //|DaylightSavings_UK class | //+------------------------------------------------------------------+ class CDaylightSavings_UK: public CDaylightSavings { public: CDaylightSavings_UK(void); }; //+------------------------------------------------------------------+ //|Set Daylight Savings Schedule for Europe | //+------------------------------------------------------------------+ void CDaylightSavings::SetDaylightSavings_UK() { savings = new CArrayObj(); //Daylight savings dates to readjust dates in the database for accurate testing in the strategy tester savings.Add(new CDaylightSavings(D'2007.03.25 02:00:00',D'2007.10.28 01:00:00')); savings.Add(new CDaylightSavings(D'2008.03.30 02:00:00',D'2008.10.26 01:00:00')); savings.Add(new CDaylightSavings(D'2009.03.29 02:00:00',D'2009.10.25 01:00:00')); savings.Add(new CDaylightSavings(D'2010.03.28 02:00:00',D'2010.10.31 01:00:00')); savings.Add(new CDaylightSavings(D'2011.03.27 02:00:00',D'2011.10.30 01:00:00')); savings.Add(new CDaylightSavings(D'2012.03.25 02:00:00',D'2012.10.28 01:00:00')); savings.Add(new CDaylightSavings(D'2013.03.31 02:00:00',D'2013.10.27 01:00:00')); savings.Add(new CDaylightSavings(D'2014.03.30 02:00:00',D'2014.10.26 01:00:00')); savings.Add(new CDaylightSavings(D'2015.03.29 02:00:00',D'2015.10.25 01:00:00')); savings.Add(new CDaylightSavings(D'2016.03.27 02:00:00',D'2016.10.30 01:00:00')); savings.Add(new CDaylightSavings(D'2017.03.26 02:00:00',D'2017.10.29 01:00:00')); savings.Add(new CDaylightSavings(D'2018.03.25 02:00:00',D'2018.10.28 01:00:00')); savings.Add(new CDaylightSavings(D'2019.03.31 02:00:00',D'2019.10.27 01:00:00')); savings.Add(new CDaylightSavings(D'2020.03.29 02:00:00',D'2020.10.25 01:00:00')); savings.Add(new CDaylightSavings(D'2021.03.28 02:00:00',D'2021.10.31 01:00:00')); savings.Add(new CDaylightSavings(D'2022.03.27 02:00:00',D'2022.10.30 01:00:00')); savings.Add(new CDaylightSavings(D'2023.03.26 02:00:00',D'2023.10.29 01:00:00')); savings.Add(new CDaylightSavings(D'2024.03.31 02:00:00',D'2024.10.27 01:00:00')); savings.Add(new CDaylightSavings(D'2025.03.30 02:00:00',D'2025.10.26 01:00:00')); savings.Add(new CDaylightSavings(D'2026.03.29 02:00:00',D'2026.10.25 01:00:00')); savings.Add(new CDaylightSavings(D'2027.03.28 02:00:00',D'2027.10.31 01:00:00')); savings.Add(new CDaylightSavings(D'2028.03.26 02:00:00',D'2028.10.29 01:00:00')); savings.Add(new CDaylightSavings(D'2029.03.25 02:00:00',D'2029.10.28 01:00:00')); } //+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CDaylightSavings_UK::CDaylightSavings_UK(void) { SetDaylightSavings_UK(); } //+------------------------------------------------------------------+
CDaylightSavings_US Klasse
In dieser Klasse erweitern wir die virtuelle void-Methode SetDaylightSavings_US und fügen die Tabelle der Sommerzeiten der Vereinigten Staaten hinzu.
Die Daten für die Sommerzeit in den Vereinigten Staaten wurden hier veröffentlicht.
Die Klasse CDaylightSavings_US hat eine mehrstufige Vererbung von Klassen:
- CDaylightSavings
- CObject
Die Klasse CDaylightSavings_US besitzt eine hierarchische Vererbung von Klassen:
- CDaylightSavings
- CArrayObj
- CTimeManagement
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include "DaylightSavings.mqh" //+------------------------------------------------------------------+ //|DaylightSavings_US Class | //+------------------------------------------------------------------+ class CDaylightSavings_US: public CDaylightSavings { public: CDaylightSavings_US(void); }; //+------------------------------------------------------------------+ //|Set Daylight Savings Schedule for the United States | //+------------------------------------------------------------------+ void CDaylightSavings::SetDaylightSavings_US() { savings = new CArrayObj(); //Daylight savings dates to readjust dates in the database for accurate testing in the strategy tester savings.Add(new CDaylightSavings(D'2007.03.11 03:00:00',D'2007.11.04 01:00:00')); savings.Add(new CDaylightSavings(D'2008.03.09 03:00:00',D'2008.11.02 01:00:00')); savings.Add(new CDaylightSavings(D'2009.03.08 03:00:00',D'2009.11.01 01:00:00')); savings.Add(new CDaylightSavings(D'2010.03.14 03:00:00',D'2010.11.07 01:00:00')); savings.Add(new CDaylightSavings(D'2011.03.13 03:00:00',D'2011.11.06 01:00:00')); savings.Add(new CDaylightSavings(D'2012.03.11 03:00:00',D'2012.11.04 01:00:00')); savings.Add(new CDaylightSavings(D'2013.03.10 03:00:00',D'2013.11.03 01:00:00')); savings.Add(new CDaylightSavings(D'2014.03.09 03:00:00',D'2014.11.02 01:00:00')); savings.Add(new CDaylightSavings(D'2015.03.08 03:00:00',D'2015.11.01 01:00:00')); savings.Add(new CDaylightSavings(D'2016.03.13 03:00:00',D'2016.11.06 01:00:00')); savings.Add(new CDaylightSavings(D'2017.03.12 03:00:00',D'2017.11.05 01:00:00')); savings.Add(new CDaylightSavings(D'2018.03.11 03:00:00',D'2018.11.04 01:00:00')); savings.Add(new CDaylightSavings(D'2019.03.10 03:00:00',D'2019.11.03 01:00:00')); savings.Add(new CDaylightSavings(D'2020.03.08 03:00:00',D'2020.11.01 01:00:00')); savings.Add(new CDaylightSavings(D'2021.03.14 03:00:00',D'2021.11.07 01:00:00')); savings.Add(new CDaylightSavings(D'2022.03.13 03:00:00',D'2022.11.06 01:00:00')); savings.Add(new CDaylightSavings(D'2023.03.12 03:00:00',D'2023.11.05 01:00:00')); savings.Add(new CDaylightSavings(D'2024.03.10 03:00:00',D'2024.11.03 01:00:00')); savings.Add(new CDaylightSavings(D'2025.03.09 03:00:00',D'2025.11.02 01:00:00')); savings.Add(new CDaylightSavings(D'2026.03.08 03:00:00',D'2026.11.01 01:00:00')); savings.Add(new CDaylightSavings(D'2027.03.14 03:00:00',D'2027.11.07 01:00:00')); savings.Add(new CDaylightSavings(D'2028.03.12 03:00:00',D'2028.11.05 01:00:00')); savings.Add(new CDaylightSavings(D'2029.03.11 03:00:00',D'2029.11.04 01:00:00')); } //+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CDaylightSavings_US::CDaylightSavings_US(void) { SetDaylightSavings_US(); } //+------------------------------------------------------------------+
Klasse der Symbol-Eigenschaften
In dieser Klasse werden wir ein Symbol festlegen, von dem wir Daten abrufen möchten. Diese Klasse bietet uns eine einfache und schnelle Methode, um Symboleigenschaften innerhalb anderer Klassen zu erhalten und somit Redundanz in unserem Code zu vermeiden.
Wir wählen eine Kombination aus abrufbaren Eigenschaften aus. Die Liste könnte erweitert werden, sieht aber erst einmal wie folgt aus:
- Ask Price (Briefkurs)
- Bid Price (Geldkurs)
- Contract Size (Kontraktgröße)
- Minimum Volume (Mindestvolumen)
- Maximum Volume (Höchstvolumen)
- Volume Step (Volumenschritt)
- Volume Limit (Volumenlimit)
- Spread (Spreizung)
- Stops Level (Stopppreis)
- Freeze Level (Freeze-Level)
- Symbol's Time (Symbolzeit)
- Symbol's Normalized Price (Normalisierter Symbolpreis)
- Symbol's Digits (Dezimalstellen des Symbols)
- Punkt des Symbols (Punktwert des Symbols)
- Symbol's Trade Mode (Handelsmodus des Symbols)
- Sum of Symbol's Orders' Volume (Summe des Ordervolumens des Symbols)
- Sum of Symbol's Positions' Volume (Positionsvolumens des Symbols)
- Symbol's Currency Base (Basiswährung des Symbols)
- Symbol's Currency Profit (Gewinnwährung des Symbols)
- Symbol's Currency Margin (Währungsmarge des Symbols)
- Symbol's Custom status (nutzerdefinierter Status des Symbols)
- Symbol's Background color (Hintergrundfarbe des Symbols)
Die Klasse CSymbolProperties wurde von der Klasse CSymbolInfo übernommen.
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include <Trade/SymbolInfo.mqh> //+------------------------------------------------------------------+ //|SymbolProperties class | //+------------------------------------------------------------------+ class CSymbolProperties { private: double ASK;//Store Ask Price double BID;//Store Bid Price double LOTSMIN;//Store Minimum Lotsize double LOTSMAX;//Store Maximum Lotsize double LOTSSTEP;//Store Lotsize Step double LOTSLIMIT;//Store Lotsize Limit(Maximum sum of Volume) long SPREAD;//Store Spread value long STOPLEVEL;//Store Stop level long FREEZELEVEL;//Store Freeze level long TIME;//Store time long DIGITS;//Store Digits double POINT;//Store Point double ORDERSVOLUME;//Store Orders volume double POSITIONSVOLUME;//Store Positions volume long CUSTOM;//Store if Symbol is Custom long BACKGROUND_CLR;//Store Symbol's background color protected: CSymbolInfo CSymbol;//Creating class CSymbolInfo's Object bool SetSymbolName(string SYMBOL) { //-- If Symbol's name was successfully set. if(!CSymbol.Name((SYMBOL==NULL)?Symbol():SYMBOL)) { Print("Invalid Symbol: ",SYMBOL); return false; } return true; } //-- Retrieve Symbol's name string GetSymbolName() { return CSymbol.Name(); } public: CSymbolProperties(void);//Constructor double Ask(string SYMBOL=NULL);//Retrieve Ask Price double Bid(string SYMBOL=NULL);//Retrieve Bid Price double ContractSize(string SYMBOL=NULL);//Retrieve Contract Size double LotsMin(string SYMBOL=NULL);//Retrieve Min Volume double LotsMax(string SYMBOL=NULL);//Retrieve Max Volume double LotsStep(string SYMBOL=NULL);//Retrieve Volume Step double LotsLimit(string SYMBOL=NULL);//Retrieve Volume Limit int Spread(string SYMBOL=NULL);//Retrieve Spread int StopLevel(string SYMBOL=NULL);//Retrieve Stop Level int FreezeLevel(string SYMBOL=NULL);//Retrieve Freeze Level datetime Time(string SYMBOL=NULL);//Retrieve Symbol's Time //-- Normalize Price double NormalizePrice(const double price,string SYMBOL=NULL); int Digits(string SYMBOL=NULL);//Retrieve Symbol's Digits double Point(string SYMBOL=NULL);//Retrieve Symbol's Point ENUM_SYMBOL_TRADE_MODE TradeMode(string SYMBOL=NULL);//Retrieve Symbol's Trade Mode double OrdersVolume(string SYMBOL=NULL);//Retrieve Symbol's Orders Volume double PositionsVolume(string SYMBOL=NULL);//Retrieve Symbol's Positions Volume string CurrencyBase(string SYMBOL=NULL);//Retrieve Symbol's Currency Base string CurrencyProfit(string SYMBOL=NULL);//Retrieve Symbol's Currency Profit string CurrencyMargin(string SYMBOL=NULL);//Retrieve Symbol's Currency Margin bool Custom(string SYMBOL=NULL);//Retrieve Symbol's Custom status color SymbolBackground(string SYMBOL=NULL,bool allow_black=false);//Retrieve Symbol's Background color }; //+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ //Initializing Variables CSymbolProperties::CSymbolProperties(void):ASK(0.0),BID(0.0), LOTSMIN(0.0),LOTSMAX(0.0), LOTSSTEP(0.0),LOTSLIMIT(0.0),DIGITS(0), SPREAD(0),STOPLEVEL(0),ORDERSVOLUME(0.0), FREEZELEVEL(0),TIME(0),POINT(0.0),POSITIONSVOLUME(0.0), CUSTOM(0),BACKGROUND_CLR(0) { } //+------------------------------------------------------------------+ //|Retrieve Ask Price | //+------------------------------------------------------------------+ double CSymbolProperties::Ask(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_ASK,ASK)) { return ASK; } } Print("Unable to retrieve Symbol's Ask Price"); return 0.0; } //+------------------------------------------------------------------+ //|Retrieve Bid Price | //+------------------------------------------------------------------+ double CSymbolProperties::Bid(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_BID,BID)) { return BID; } } Print("Unable to retrieve Symbol's Bid Price"); return 0.0; } //+------------------------------------------------------------------+ //|Retrieve Contract Size | //+------------------------------------------------------------------+ double CSymbolProperties::ContractSize(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()) { return CSymbol.ContractSize(); } } Print("Unable to retrieve Symbol's Contract size"); return 0.0; } //+------------------------------------------------------------------+ //|Retrieve Min Volume | //+------------------------------------------------------------------+ double CSymbolProperties::LotsMin(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_VOLUME_MIN,LOTSMIN)) { return LOTSMIN; } } Print("Unable to retrieve Symbol's LotsMin"); return 0.0; } //+------------------------------------------------------------------+ //|Retrieve Max Volume | //+------------------------------------------------------------------+ double CSymbolProperties::LotsMax(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_VOLUME_MAX,LOTSMAX)) { return LOTSMAX; } } Print("Unable to retrieve Symbol's LotsMax"); return 0.0; } //+------------------------------------------------------------------+ //|Retrieve Volume Step | //+------------------------------------------------------------------+ double CSymbolProperties::LotsStep(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_VOLUME_STEP,LOTSSTEP)) { return LOTSSTEP; } } Print("Unable to retrieve Symbol's LotsStep"); return 0.0; } //+------------------------------------------------------------------+ //|Retrieve Volume Limit | //+------------------------------------------------------------------+ double CSymbolProperties::LotsLimit(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_VOLUME_LIMIT,LOTSLIMIT)) { return LOTSLIMIT; } } Print("Unable to retrieve Symbol's LotsLimit"); return 0.0; } //+------------------------------------------------------------------+ //|Retrieve Spread | //+------------------------------------------------------------------+ int CSymbolProperties::Spread(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_SPREAD,SPREAD)) { return int(SPREAD); } } Print("Unable to retrieve Symbol's Spread"); return 0; } //+------------------------------------------------------------------+ //|Retrieve Stop Level | //+------------------------------------------------------------------+ int CSymbolProperties::StopLevel(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_TRADE_STOPS_LEVEL,STOPLEVEL)) { return int(STOPLEVEL); } } Print("Unable to retrieve Symbol's StopLevel"); return 0; } //+------------------------------------------------------------------+ //|Retrieve Freeze Level | //+------------------------------------------------------------------+ int CSymbolProperties::FreezeLevel(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_TRADE_FREEZE_LEVEL,FREEZELEVEL)) { return int(FREEZELEVEL); } } Print("Unable to retrieve Symbol's FreezeLevel"); return 0; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Time | //+------------------------------------------------------------------+ datetime CSymbolProperties::Time(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_TIME,TIME)) { return datetime(TIME); } } Print("Unable to retrieve Symbol's Time"); TIME=0; return datetime(TIME); } //+------------------------------------------------------------------+ //|Normalize Price | //+------------------------------------------------------------------+ double CSymbolProperties::NormalizePrice(const double price,string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()&&CSymbol.RefreshRates()) { return CSymbol.NormalizePrice(price); } } Print("Unable to Normalize Symbol's Price"); return price; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Digits | //+------------------------------------------------------------------+ int CSymbolProperties::Digits(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_DIGITS,DIGITS)) { return int(DIGITS); } } Print("Unable to retrieve Symbol's Digits"); return 0; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Point | //+------------------------------------------------------------------+ double CSymbolProperties::Point(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_POINT,POINT)) { return POINT; } } Print("Unable to retrieve Symbol's Point"); return 0.0; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Trade Mode | //+------------------------------------------------------------------+ ENUM_SYMBOL_TRADE_MODE CSymbolProperties::TradeMode(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()) { return CSymbol.TradeMode(); } } Print("Unable to retrieve Symbol's TradeMode"); return SYMBOL_TRADE_MODE_DISABLED; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Orders Volume | //+------------------------------------------------------------------+ double CSymbolProperties::OrdersVolume(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { for(int i=0; i<OrdersTotal(); i++) { if(OrderSelect(OrderGetTicket(i))) { if(OrderGetString(ORDER_SYMBOL)==GetSymbolName()) { ORDERSVOLUME+=OrderGetDouble(ORDER_VOLUME_CURRENT); } } } } else { Print("Unable to retrieve Symbol's OrdersVolume"); return 0.0; } return ORDERSVOLUME; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Positions Volume | //+------------------------------------------------------------------+ double CSymbolProperties::PositionsVolume(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { for(int i=0; i<PositionsTotal(); i++) { if(PositionGetTicket(i)>0) { if(PositionGetString(POSITION_SYMBOL)==GetSymbolName()) { POSITIONSVOLUME+=PositionGetDouble(POSITION_VOLUME); } } } } else { Print("Unable to retrieve Symbol's PositionsVolume"); return 0.0; } return POSITIONSVOLUME; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Currency Base | //+------------------------------------------------------------------+ string CSymbolProperties::CurrencyBase(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()) { return CSymbol.CurrencyBase(); } } Print("Unable to retrieve Symbol's CurrencyBase"); return ""; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Currency Profit | //+------------------------------------------------------------------+ string CSymbolProperties::CurrencyProfit(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()) { return CSymbol.CurrencyProfit(); } } Print("Unable to retrieve Symbol's CurrencyProfit"); return ""; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Currency Margin | //+------------------------------------------------------------------+ string CSymbolProperties::CurrencyMargin(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()) { return CSymbol.CurrencyMargin(); } } Print("Unable to retrieve Symbol's CurrencyMargin"); return ""; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Custom status | //+------------------------------------------------------------------+ bool CSymbolProperties::Custom(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_CUSTOM,CUSTOM)) { return bool(CUSTOM); } } Print("Unable to retrieve if Symbol is Custom"); return false; } //+------------------------------------------------------------------+ //|Retrieve Symbol's Background color | //+------------------------------------------------------------------+ color CSymbolProperties::SymbolBackground(string SYMBOL=NULL,bool allow_black=false) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_BACKGROUND_COLOR,BACKGROUND_CLR)) { /*Avoid any Symbol black background color */ BACKGROUND_CLR = ((ColorToString(color(BACKGROUND_CLR))=="0,0,0"|| color(BACKGROUND_CLR)==clrBlack)&&!allow_black)? long(StringToColor("236,236,236")):BACKGROUND_CLR; return color(BACKGROUND_CLR); } } Print("Unable to retrieve Symbol's Background color"); return color(StringToColor("236,236,236"));//Retrieve a lightish gray color } //+------------------------------------------------------------------+
Im nachfolgenden Konstruktor der Klasse initialisieren wir die zuvor deklarierten Variablen, wie z. B. die Double-Variable ASK, und weisen ASK den Wert 0.0 zu, da wir den Ask-Preis für das Symbol noch nicht kennen.
//Initializing Variables CSymbolProperties::CSymbolProperties(void):ASK(0.0),BID(0.0), LOTSMIN(0.0),LOTSMAX(0.0), LOTSSTEP(0.0),LOTSLIMIT(0.0),DIGITS(0), SPREAD(0),STOPLEVEL(0),ORDERSVOLUME(0.0), FREEZELEVEL(0),TIME(0),POINT(0.0),POSITIONSVOLUME(0.0), CUSTOM(0),BACKGROUND_CLR(0) { }
Im folgenden Code gehen wir die einzelnen Schritte durch, um schließlich den Briefkurs des Symbols abzurufen.
1. Zunächst haben wir einen optionalen Parameter, mit dem wir entscheiden können, ob wir den Namen des Symbols in die Variable SYMBOL eingeben oder bearbeiten wollen.
2. Dann setzen wir den Namen des Symbols auf den Parameterwert. Wenn der Parameterwert immer noch der Standardwert NULL ist, gehen wir davon aus, dass wir die Eigenschaften des Symbols für das Symbol des aktuellen Charts benötigen - Symbol().
3. Wenn wir den Namen des Symbols nicht finden können, geben wir eine Fehlermeldung aus, um den Nutzer darüber zu informieren, dass der Briefkurs (Ask) des Symbols nicht abgerufen werden kann, und geben 0,0 zurück.
4. Sobald wir den Namen des Symbols festlegen konnten, werden wir den Briefkurs für dieses spezifische Symbol abrufen und den Wert zurückgeben.
double CSymbolProperties::Ask(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL)) { if(CSymbol.InfoDouble(SYMBOL_ASK,ASK)) { return ASK; } } Print("Unable to retrieve Symbol's Ask Price"); return 0.0; }
bool SetSymbolName(string SYMBOL)
{
//-- If Symbol's name was successfully set.
if(!CSymbol.Name((SYMBOL==NULL)?Symbol():SYMBOL))
{
Print("Invalid Symbol: ",SYMBOL);
return false;
}
return true;
}
Die folgende Funktion ruft den Geldkurs (Bid) des Symbols auf der Grundlage der Variablen SYMBOL ab.
double CSymbolProperties::Bid(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_BID,BID)) { return BID; } } Print("Unable to retrieve Symbol's Bid Price"); return 0.0; }
Mit der folgenden Funktion wird die Vertragsgröße des Symbols abgerufen. Die Kontraktgröße eines Symbols wirkt sich auf den Händler aus, da eine höhere Kontraktgröße das Risiko bei den einzelnen Handelsgeschäften erhöht. Eine geringere Kontraktgröße hingegen verringert das Risiko für den Handel einer Person.
double CSymbolProperties::ContractSize(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()) { return CSymbol.ContractSize(); } } Print("Unable to retrieve Symbol's Contract size"); return 0.0; }
Die nachstehende Funktion ruft die minimal zulässige Losgröße/Volumen des Symbols ab. Das bedeutet, dass der Händler keine Position mit einer geringeren Losgröße als der Mindestgröße eröffnen kann.
double CSymbolProperties::LotsMin(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_VOLUME_MIN,LOTSMIN)) { return LOTSMIN; } } Print("Unable to retrieve Symbol's LotsMin"); return 0.0; }
Die nachstehende Funktion ruft die maximal zulässige Losgröße/das maximal zulässige Volumen des Symbols ab. Dies bedeutet, dass der Händler keine Position mit einer höheren Losgröße/einem höheren Volumen als der Höchstgrenze eröffnen darf, aber er kann mehrere Positionen eröffnen, die sich zu einer höheren Losgröße/einem höheren Volumen als der Höchstgrenze summieren können, je nach dem Volumenlimit des Brokers und dem Auftragslimit des Kontos.
double CSymbolProperties::LotsMax(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_VOLUME_MAX,LOTSMAX)) { return LOTSMAX; } } Print("Unable to retrieve Symbol's LotsMax"); return 0.0; }
Die nachstehende Funktion ruft die Schrittweite für Volumen bzw. Losgröße des Symbols ab. Das bedeutet, dass das kleinstmögliche Losgrößenintervall diesem Wert hat. Wenn z.B. der „volume step“ 1 ist, kann der Händler keine Losgröße/Volumen von 1,5 wählen.
double CSymbolProperties::LotsStep(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_VOLUME_STEP,LOTSSTEP)) { return LOTSSTEP; } } Print("Unable to retrieve Symbol's LotsStep"); return 0.0; }
Mit der nachstehenden Funktion wird die Volumen-/Losgrößengrenze des Symbols abgerufen. Dies ist die Summe der Volumina/Losgrößen, die platziert werden können, bevor Beschränkungen für das Konto des Händlers für das spezifische Symbol eingeführt werden.
double CSymbolProperties::LotsLimit(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_VOLUME_LIMIT,LOTSLIMIT)) { return LOTSLIMIT; } } Print("Unable to retrieve Symbol's LotsLimit"); return 0.0; }
Mit der folgenden Funktion wird die Spreizung (Spread) des Symbols abgerufen. Sie wirkt sich auf die Händler aus, denn je höher sie ist, desto weniger profitabel wird der Händler sein. Je nach „Spread“ könnte eine Strategie profitabel sein oder nicht, natürlich gibt es viele verschiedene Umstände, die eine Strategie unprofitabel machen könnten, aber der Spread des Symbols könnte ein wichtiger Umstand sein. Spreads sind im Wesentlichen eine Form von Einkommen für Ihren Broker, man könnte sie als die Steuer des Brokers für dieses Symbol betrachten.
int CSymbolProperties::Spread(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_SPREAD,SPREAD)) { return int(SPREAD); } } Print("Unable to retrieve Symbol's Spread"); return 0; }
Die nachstehende Funktion ruft die Stopp-Level des Symbols ab. Hierbei handelt es sich um eine Beschränkung des Mindestabstands zwischen einem Eröffnungskurs und einem „Stop-Loss“ oder „Take-Profit“ sowie des Mindestabstands zwischen dem aktuellen Kurs Ask oder Bid und dem Eröffnungskurs einer Order.
int CSymbolProperties::StopLevel(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_TRADE_STOPS_LEVEL,STOPLEVEL)) { return int(STOPLEVEL); } } Print("Unable to retrieve Symbol's StopLevel"); return 0; }
Mit der folgenden Funktion wird das „Freeze“-Level des Symbols abgerufen. Dies ist die Mindestdistanz Eröffnungskurs vom aktuellen Kurs, damit der Handel ausgeführt werden kann (wenn Sie den betreffenden Handel mit Gewinn oder Verlust schließen können).
int CSymbolProperties::FreezeLevel(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_TRADE_FREEZE_LEVEL,FREEZELEVEL)) { return int(FREEZELEVEL); } } Print("Unable to retrieve Symbol's FreezeLevel"); return 0; }
Mit der folgenden Funktion wird die Zeit des Symbols abgerufen.
datetime CSymbolProperties::Time(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_TIME,TIME)) { return datetime(TIME); } } Print("Unable to retrieve Symbol's Time"); TIME=0; return datetime(TIME); }
Mit der folgenden Funktion wird versucht, einen Preis für ein bestimmtes Symbol zu normalisieren.
Wenn der Briefkurs (Ask) für EURUSD beispielsweise bei 1,07735 liegt und Sie versuchen, zum Kurs von 1,077351 zu kaufen. Es kann zu einer Fehlermeldung wie „invalid price“ kommen, da die Anzahl der Dezimalstellen die zulässige Anzahl von z. B. 5 Stellen übersteigt. Diese Funktion wandelt den 6-stelligen Preis in einen 5-stelligen um und normalisiert so den Preis.
double CSymbolProperties::NormalizePrice(const double price,string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()&&CSymbol.RefreshRates()) { return CSymbol.NormalizePrice(price); } } Print("Unable to Normalize Symbol's Price"); return price; }
Mit der folgenden Funktion werden die Ziffern des Symbols abgerufen. Die Ziffern werden als Dezimalstellen des Symbolpreises dargestellt.
int CSymbolProperties::Digits(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_DIGITS,DIGITS)) { return int(DIGITS); } } Print("Unable to retrieve Symbol's Digits"); return 0; }
Mit der folgenden Funktion wird der Punktwert (point) des Symbols abgerufen.
double CSymbolProperties::Point(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoDouble(SYMBOL_POINT,POINT)) { return POINT; } } Print("Unable to retrieve Symbol's Point"); return 0.0; }
Mit der folgenden Funktion wird der Handelsmodus des Symbols abgerufen.
ENUM_SYMBOL_TRADE_MODE CSymbolProperties::TradeMode(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()) { return CSymbol.TradeMode(); } } Print("Unable to retrieve Symbol's TradeMode"); return SYMBOL_TRADE_MODE_DISABLED; }
Die nachstehende Funktion ermittelt die Summe der Volumina/Losgrößen der Aufträge des Symbols.
double CSymbolProperties::OrdersVolume(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { for(int i=0; i<OrdersTotal(); i++) { if(OrderSelect(OrderGetTicket(i))) { if(OrderGetString(ORDER_SYMBOL)==GetSymbolName()) { ORDERSVOLUME+=OrderGetDouble(ORDER_VOLUME_CURRENT); } } } } else { Print("Unable to retrieve Symbol's OrdersVolume"); return 0.0; } return ORDERSVOLUME; }
Die nachstehende Funktion ermittelt die Summe der Volumina/Losgrößen der Positionen des Symbols.
double CSymbolProperties::PositionsVolume(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { for(int i=0; i<PositionsTotal(); i++) { if(PositionGetTicket(i)>0) { if(PositionGetString(POSITION_SYMBOL)==GetSymbolName()) { POSITIONSVOLUME+=PositionGetDouble(POSITION_VOLUME); } } } } else { Print("Unable to retrieve Symbol's PositionsVolume"); return 0.0; } return POSITIONSVOLUME; }
Mit der folgenden Funktion wird die Basiswährung des Symbols abgerufen.
string CSymbolProperties::CurrencyBase(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()) { return CSymbol.CurrencyBase(); } } Print("Unable to retrieve Symbol's CurrencyBase"); return ""; }
Mit der folgenden Funktion wird die Gewinnwährung des Symbols abgerufen.
string CSymbolProperties::CurrencyProfit(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()) { return CSymbol.CurrencyProfit(); } } Print("Unable to retrieve Symbol's CurrencyProfit"); return ""; }
Mit der nachstehenden Funktion wird die Währung der Marge des Symbols abgerufen.
string CSymbolProperties::CurrencyMargin(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.Refresh()) { return CSymbol.CurrencyMargin(); } } Print("Unable to retrieve Symbol's CurrencyMargin"); return ""; }
Mit der folgenden Funktion wird ein boolescher Wert abgerufen, der angibt, ob ein Symbol nutzerdefiniert ist oder nicht.
bool CSymbolProperties::Custom(string SYMBOL=NULL) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_CUSTOM,CUSTOM)) { return bool(CUSTOM); } } Print("Unable to retrieve if Symbol is Custom"); return false; }
Mit der folgenden Funktion wird die Hintergrundfarbe des Symbols abgerufen. Dies liegt daran, dass wir die Hintergrundfarbe des Symbols verwenden werden, um die Hintergrundfarbe des Charts später festzulegen, und wir wollen eine schwarze Farbe abrufen, da andere Elemente unseres Charts schwarz sein werden. Wenn wir die schwarze Farbe zulassen würden, würde das Chart aufgrund des zu erwartenden Formats ablenken und unleserlich werden.
Beispiel für ein Chart mit schwarzem Hintergrund und unserem neuen Chartformat, das später eingeführt werden soll.
color CSymbolProperties::SymbolBackground(string SYMBOL=NULL,bool allow_black=false) { if(SetSymbolName(SYMBOL))//Set Symbol { if(CSymbol.InfoInteger(SYMBOL_BACKGROUND_COLOR,BACKGROUND_CLR)) { /*Avoid any Symbol black background color */ BACKGROUND_CLR = ((ColorToString(color(BACKGROUND_CLR))=="0,0,0"|| color(BACKGROUND_CLR)==clrBlack)&&!allow_black)? long(StringToColor("236,236,236")):BACKGROUND_CLR; return color(BACKGROUND_CLR); } } Print("Unable to retrieve Symbol's Background color"); return color(StringToColor("236,236,236"));//Retrieve a lightish gray color }
Klasse für das Zeitmanagement
In diesem Kurs werde ich die neuen Funktionen hervorheben, die zur Funktionalität der Klasse hinzugefügt wurden. Der Zweck dieser Klasse ist es, Zeitdaten zu manipulieren oder mit ihnen zu interagieren.
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //|TimeManagement class | //+------------------------------------------------------------------+ class CTimeManagement { private: MqlDateTime today;//private variable MqlDateTime timeFormat;//private variable public: //-- Checks if a date is within two other dates bool DateIsInRange(datetime FirstTime,datetime SecondTime,datetime compareTime); //-- Check if two dates(Start&End) are within CompareStart & CompareEnd bool DateIsInRange(datetime Start,datetime End,datetime CompareStart,datetime CompareEnd); bool DateisToday(datetime TimeRepresented);//Checks if a date is within the current day int SecondsS(int multiple=1);//Returns seconds int MinutesS(int multiple=1);//Returns Minutes in seconds int HoursS(int multiple=1);//Returns Hours in seconds int DaysS(int multiple=1);//Returns Days in seconds int WeeksS(int multiple=1);//Returns Weeks in seconds int MonthsS(int multiple=1);//Returns Months in seconds int YearsS(int multiple=1);//Returns Years in seconds int ReturnYear(datetime time);//Returns the Year for a specific date int ReturnMonth(datetime time);//Returns the Month for a specific date int ReturnDay(datetime time);//Returns the Day for a specific date //-- Will return a datetime type of a date with an subtraction offset in seconds datetime TimeMinusOffset(datetime standardtime,int timeoffset); //-- Will return a datetime type of a date with an addition offset in seconds datetime TimePlusOffset(datetime standardtime,int timeoffset); }; //+------------------------------------------------------------------+ //|Checks if a date is within two other dates | //+------------------------------------------------------------------+ bool CTimeManagement::DateIsInRange(datetime FirstTime,datetime SecondTime,datetime compareTime) { return(FirstTime<=compareTime&&SecondTime>compareTime); } //+------------------------------------------------------------------+ //|Check if two dates(Start&End) are within CompareStart & CompareEnd| //+------------------------------------------------------------------+ bool CTimeManagement::DateIsInRange(datetime Start,datetime End,datetime CompareStart,datetime CompareEnd) { return(Start<=CompareStart&&CompareEnd<End); } //+------------------------------------------------------------------+ //|Checks if a date is within the current day | //+------------------------------------------------------------------+ bool CTimeManagement::DateisToday(datetime TimeRepresented) { MqlDateTime TiM; TimeToStruct(TimeRepresented,TiM); TimeCurrent(today); return(TiM.year==today.year&&TiM.mon==today.mon&&TiM.day==today.day); } //+------------------------------------------------------------------+ //|Returns seconds | //+------------------------------------------------------------------+ int CTimeManagement::SecondsS(int multiple=1) { return (1*multiple); } //+------------------------------------------------------------------+ //|Returns Minutes in seconds | //+------------------------------------------------------------------+ int CTimeManagement::MinutesS(int multiple=1) { return (SecondsS(60)*multiple); } //+------------------------------------------------------------------+ //|Returns Hours in seconds | //+------------------------------------------------------------------+ int CTimeManagement::HoursS(int multiple=1) { return (MinutesS(60)*multiple); } //+------------------------------------------------------------------+ //|Returns Days in seconds | //+------------------------------------------------------------------+ int CTimeManagement::DaysS(int multiple=1) { return (HoursS(24)*multiple); } //+------------------------------------------------------------------+ //|Returns Weeks in seconds | //+------------------------------------------------------------------+ int CTimeManagement::WeeksS(int multiple=1) { return (DaysS(7)*multiple); } //+------------------------------------------------------------------+ //|Returns Months in seconds | //+------------------------------------------------------------------+ int CTimeManagement::MonthsS(int multiple=1) { return (WeeksS(4)*multiple); } //+------------------------------------------------------------------+ //|Returns Years in seconds | //+------------------------------------------------------------------+ int CTimeManagement::YearsS(int multiple=1) { return (MonthsS(12)*multiple); } //+------------------------------------------------------------------+ //|Returns the Year for a specific date | //+------------------------------------------------------------------+ int CTimeManagement::ReturnYear(datetime time) { TimeToStruct(time,timeFormat); return timeFormat.year; } //+------------------------------------------------------------------+ //|Returns the Month for a specific date | //+------------------------------------------------------------------+ int CTimeManagement::ReturnMonth(datetime time) { TimeToStruct(time,timeFormat); return timeFormat.mon; } //+------------------------------------------------------------------+ //|Returns the Day for a specific date | //+------------------------------------------------------------------+ int CTimeManagement::ReturnDay(datetime time) { TimeToStruct(time,timeFormat); return timeFormat.day; } //+------------------------------------------------------------------+ //|Will return a datetime type of a date with an subtraction offset | //|in seconds | //+------------------------------------------------------------------+ datetime CTimeManagement::TimeMinusOffset(datetime standardtime,int timeoffset) { standardtime-=timeoffset; return standardtime; } //+------------------------------------------------------------------+ //|Will return a datetime type of a date with an addition offset | //|in seconds | //+------------------------------------------------------------------+ datetime CTimeManagement::TimePlusOffset(datetime standardtime,int timeoffset) { standardtime+=timeoffset; return standardtime; } //+------------------------------------------------------------------+
Klasse der Chart-Eigenschaften
Der Zweck der Chart-Eigenschaften besteht darin, die Konfiguration des Charts zu speichern, bevor wir das Layout des Charts ändern. Sobald der Experte aus dem Chart entfernt wird, stellt der Destruktor der Klasse den Zustand der Konfiguration des Charts wieder her, den wir vor den Änderungen am Chart hatten.
Änderungen am Chart sind für die Funktionalität der Experten nicht erforderlich, aber es ist visuell ansprechend, ein Chart zu haben, das nicht nur grün und schwarz ist (Standarddiagramm-Layout) und bei dem es schwierig sein kann, die Preise im Chart oder die Handelsniveaus zu erkennen, wenn die Handelsgeschäfte platziert werden.
CChartProperties wird einmalig von der Klasse CSymbolProperties abgeleitet.
CChartProperties verfügt über eine hierarchische Vererbung der Klassen:
- CSymbolProperties
- CSymbolInfo
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include "SymbolProperties.mqh" //+------------------------------------------------------------------+ //|ChartProperties class | //+------------------------------------------------------------------+ class CChartProperties : public CSymbolProperties { private: struct ChartFormat { ulong CHART_MODE;//Chart Candle Mode ulong CHART_COLOR_BACKGROUND;//Chart Background Color ulong CHART_COLOR_FOREGROUND;//Chart Foreground Color ulong CHART_COLOR_CHART_LINE;//Chart Line Color ulong CHART_COLOR_CANDLE_BEAR;//Chart Bear Candle Color ulong CHART_COLOR_CHART_DOWN;//Chart Down Candle Color ulong CHART_COLOR_CANDLE_BULL;//Chart Bull Candle Color ulong CHART_COLOR_CHART_UP;//Chart Up Candle Color ulong CHART_COLOR_ASK;//Chart Ask Color ulong CHART_COLOR_BID;//Chart Bid Color ulong CHART_COLOR_STOP_LEVEL;//Chart Stoplevel Color ulong CHART_SHOW_PERIOD_SEP;//Chart Show Period Separator ulong CHART_SCALE;//Chart Scale ulong CHART_FOREGROUND;//Chart Show Foreground ulong CHART_SHOW_ASK_LINE;//Chart Show Ask Line ulong CHART_SHOW_BID_LINE;//Chart Show Bid Line ulong CHART_SHOW_TRADE_LEVELS;//Chart Show Trade Levels ulong CHART_SHOW_OHLC;//Chart Show Open-High-Low-Close ulong CHART_SHOW_GRID;//Chart Show Grid ulong CHART_SHOW_VOLUMES;//Chart Show Volumes ulong CHART_AUTOSCROLL;//Chart Auto Scroll double CHART_SHIFT_SIZE;//Chart Shift Size ulong CHART_SHIFT;//Chart Shift ulong CHART_SHOW_ONE_CLICK;//Chart One Click Trading }; ulong ChartConfig[65];//Array To Store Chart Properties void ChartSet();//Apply Chart format void ChartConfigure();//Set Chart Values ChartFormat Chart;//Variable of type ChartFormat public: CChartProperties(void);//Constructor ~CChartProperties(void);//Destructor void ChartRefresh() {ChartConfigure();} }; //+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CChartProperties::CChartProperties(void)//Class Constructor { for(int i=0;i<65;i++)//Iterating through ENUM_CHART_PROPERTY_INTEGER Elements { ChartGetInteger(0,(ENUM_CHART_PROPERTY_INTEGER)i,0,ChartConfig[i]);//Storing Chart values into ChartConfig array } ChartConfigure(); } //+------------------------------------------------------------------+ //|Destructor | //+------------------------------------------------------------------+ CChartProperties::~CChartProperties(void) { for(int i=0;i<65;i++)//Iterating through ENUM_CHART_PROPERTY_INTEGER Elements { ChartSetInteger(0,(ENUM_CHART_PROPERTY_INTEGER)i,0,ChartConfig[i]);//Restoring Chart values from ChartConfig array } } //+------------------------------------------------------------------+ //|Set Chart Properties | //+------------------------------------------------------------------+ void CChartProperties::ChartSet() { ChartSetInteger(0,CHART_MODE,Chart.CHART_MODE);//Set Chart Candle Mode ChartSetInteger(0,CHART_COLOR_BACKGROUND,Chart.CHART_COLOR_BACKGROUND);//Set Chart Background Color ChartSetInteger(0,CHART_COLOR_FOREGROUND,Chart.CHART_COLOR_FOREGROUND);//Set Chart Foreground Color ChartSetInteger(0,CHART_COLOR_CHART_LINE,Chart.CHART_COLOR_CHART_LINE);//Set Chart Line Color ChartSetInteger(0,CHART_COLOR_CANDLE_BEAR,Chart.CHART_COLOR_CANDLE_BEAR);//Set Chart Bear Candle Color ChartSetInteger(0,CHART_COLOR_CHART_DOWN,Chart.CHART_COLOR_CHART_DOWN);//Set Chart Down Candle Color ChartSetInteger(0,CHART_COLOR_CANDLE_BULL,Chart.CHART_COLOR_CANDLE_BULL);//Set Chart Bull Candle Color ChartSetInteger(0,CHART_COLOR_CHART_UP,Chart.CHART_COLOR_CHART_UP);//Set Chart Up Candle Color ChartSetInteger(0,CHART_COLOR_ASK,Chart.CHART_COLOR_ASK);//Set Chart Ask Color ChartSetInteger(0,CHART_COLOR_BID,Chart.CHART_COLOR_BID);//Set Chart Bid Color ChartSetInteger(0,CHART_COLOR_STOP_LEVEL,Chart.CHART_COLOR_STOP_LEVEL);//Set Chart Stop Level Color ChartSetInteger(0,CHART_FOREGROUND,Chart.CHART_FOREGROUND);//Set if Chart is in Foreground Visibility ChartSetInteger(0,CHART_SHOW_ASK_LINE,Chart.CHART_SHOW_ASK_LINE);//Set Chart Ask Line Visibility ChartSetInteger(0,CHART_SHOW_BID_LINE,Chart.CHART_SHOW_BID_LINE);//Set Chart Bid Line Visibility ChartSetInteger(0,CHART_SHOW_PERIOD_SEP,Chart.CHART_SHOW_PERIOD_SEP);//Set Chart Period Separator Visibility ChartSetInteger(0,CHART_SHOW_TRADE_LEVELS,Chart.CHART_SHOW_TRADE_LEVELS);//Set Chart Trade Levels Visibility ChartSetInteger(0,CHART_SHOW_OHLC,Chart.CHART_SHOW_OHLC);//Set Chart Open-High-Low-Close Visibility ChartSetInteger(0,CHART_SHOW_GRID,Chart.CHART_SHOW_GRID);//Set Chart Grid Visibility ChartSetInteger(0,CHART_SHOW_VOLUMES,Chart.CHART_SHOW_VOLUMES);//Set Chart Volumes Visibility ChartSetInteger(0,CHART_SCALE,Chart.CHART_SCALE);//Set Chart Scale Value ChartSetInteger(0,CHART_AUTOSCROLL,Chart.CHART_AUTOSCROLL);//Set Chart Auto Scroll Option ChartSetDouble(0,CHART_SHIFT_SIZE,Chart.CHART_SHIFT_SIZE);//Set Chart Shift Size Value ChartSetInteger(0,CHART_SHIFT,Chart.CHART_SHIFT);//Set Chart Shift Option ChartSetInteger(0,CHART_SHOW_ONE_CLICK,Chart.CHART_SHOW_ONE_CLICK);//Set Chart One Click Trading } //+------------------------------------------------------------------+ //|Initialize Chart Properties | //+------------------------------------------------------------------+ void CChartProperties::ChartConfigure(void) { Chart.CHART_MODE=(ulong)CHART_CANDLES;//Assigning Chart Mode of CHART_CANDLES Chart.CHART_COLOR_BACKGROUND=ulong(SymbolBackground());//Assigning Chart Background Color of Symbol's Background color Chart.CHART_COLOR_FOREGROUND=(ulong)clrBlack;//Assigning Chart Foreground Color of clrBalck(Black color) Chart.CHART_COLOR_CHART_LINE=(ulong)clrBlack;//Assigning Chart Line Color of clrBlack(Black color) Chart.CHART_COLOR_CANDLE_BEAR=(ulong)clrBlack;//Assigning Chart Bear Candle Color of clrBlack(Black color) Chart.CHART_COLOR_CHART_DOWN=(ulong)clrBlack;//Assigning Chart Down Candle Color of clrBlack(Black color) Chart.CHART_COLOR_CANDLE_BULL=(ulong)clrWhite;//Assigning Chart Bull Candle Color of clrWhite(White color) Chart.CHART_COLOR_CHART_UP=(ulong)clrBlack;//Assigning Chart Up Candle Color of clrBlack(Black color) Chart.CHART_COLOR_ASK=(ulong)clrBlack;//Assigning Chart Ask Color of clrBlack(Black color) Chart.CHART_COLOR_BID=(ulong)clrBlack;//Assigning Chart Bid Color of clrBlack(Black color) Chart.CHART_COLOR_STOP_LEVEL=(ulong)clrBlack;//Assigning Chart Stop Level Color of clrBlack(Black color) Chart.CHART_FOREGROUND=(ulong)false;//Assigning Chart Foreground Boolean Value of 'false' Chart.CHART_SHOW_ASK_LINE=(ulong)true;//Assigning Chart Ask Line Boolean Value of 'true' Chart.CHART_SHOW_BID_LINE=(ulong)true;//Assigning Chart Bid Line Boolean Value of 'true' Chart.CHART_SHOW_PERIOD_SEP=(ulong)true;//Assigning Chart Period Separator Boolean Value of 'true' Chart.CHART_SHOW_TRADE_LEVELS=(ulong)true;//Assigning Chart Trade Levels Boolean Value of 'true' Chart.CHART_SHOW_OHLC=(ulong)false;//Assigning Chart Open-High-Low-Close Boolean Value of 'false' Chart.CHART_SHOW_GRID=(ulong)false;//Assigning Chart Grid Boolean Value of 'false' Chart.CHART_SHOW_VOLUMES=(ulong)false;//Assigning Chart Volumes Boolean Value of 'false' Chart.CHART_SCALE=(ulong)3;//Assigning Chart Scale Boolean Value of '3' Chart.CHART_AUTOSCROLL=(ulong)true;//Assigning Chart Auto Scroll Boolean Value of 'true' Chart.CHART_SHIFT_SIZE=30;//Assigning Chart Shift Size Value of '30' Chart.CHART_SHIFT=(ulong)true;//Assigning Chart Shift Boolean Value of 'true' Chart.CHART_SHOW_ONE_CLICK=ulong(false);//Assigning Chart One Click Trading a value of 'false' ChartSet();//Calling Function to set chart format } //+------------------------------------------------------------------+
In der Struktur ChartFormat, die wir deklariert haben, speichern wir verschiedene Chartvariablen, die wir auf dem aktuellen Chart, auf dem sich der Experte befindet, ändern werden.
struct ChartFormat { ulong CHART_MODE;//Chart Candle Mode ulong CHART_COLOR_BACKGROUND;//Chart Background Color ulong CHART_COLOR_FOREGROUND;//Chart Foreground Color ulong CHART_COLOR_CHART_LINE;//Chart Line Color ulong CHART_COLOR_CANDLE_BEAR;//Chart Bear Candle Color ulong CHART_COLOR_CHART_DOWN;//Chart Down Candle Color ulong CHART_COLOR_CANDLE_BULL;//Chart Bull Candle Color ulong CHART_COLOR_CHART_UP;//Chart Up Candle Color ulong CHART_COLOR_ASK;//Chart Ask Color ulong CHART_COLOR_BID;//Chart Bid Color ulong CHART_COLOR_STOP_LEVEL;//Chart Stoplevel Color ulong CHART_SHOW_PERIOD_SEP;//Chart Show Period Separator ulong CHART_SCALE;//Chart Scale ulong CHART_FOREGROUND;//Chart Show Foreground ulong CHART_SHOW_ASK_LINE;//Chart Show Ask Line ulong CHART_SHOW_BID_LINE;//Chart Show Bid Line ulong CHART_SHOW_TRADE_LEVELS;//Chart Show Trade Levels ulong CHART_SHOW_OHLC;//Chart Show Open-High-Low-Close ulong CHART_SHOW_GRID;//Chart Show Grid ulong CHART_SHOW_VOLUMES;//Chart Show Volumes ulong CHART_AUTOSCROLL;//Chart Auto Scroll double CHART_SHIFT_SIZE;//Chart Shift Size ulong CHART_SHIFT;//Chart Shift ulong CHART_SHOW_ONE_CLICK;//Chart One Click Trading };
Das ChartConfig-Array speichert alle Charteigenschaften, bevor wir Änderungen am Chart vornehmen.
ulong ChartConfig[65];//Array To Store Chart Properties
In der Funktion SetBackground erhalten wir die Hintergrundfarbe der Marktübersicht des aktuellen Symbols:
und setzen Sie die Hintergrundfarbe des aktuellen Charts auf diese Farbe:
Im Konstruktor der Klasse werden alle Charteigenschaften vom Typ Integer ermittelt und im Array ChartConfig gespeichert.
CChartProperties::CChartProperties(void)//Class Constructor { for(int i=0;i<65;i++)//Iterating through ENUM_CHART_PROPERTY_INTEGER Elements { ChartGetInteger(0,(ENUM_CHART_PROPERTY_INTEGER)i,0,ChartConfig[i]);//Storing Chart values into ChartConfig array } ChartConfigure(); }
Wir initialisieren auch die Variable Chart, die vom Typ ChartFormat ist, wie bereits erwähnt, und geben ihr in der Funktion ChartConfigure die entsprechenden Werte, um das Chart nach unseren Wünschen zu gestalten.
void CChartProperties::ChartConfigure(void) { Chart.CHART_MODE=(ulong)CHART_CANDLES;//Assigning Chart Mode of CHART_CANDLES Chart.CHART_COLOR_BACKGROUND=ulong(SymbolBackground());//Assigning Chart Background Color of Symbol's Background color Chart.CHART_COLOR_FOREGROUND=(ulong)clrBlack;//Assigning Chart Foreground Color of clrBalck(Black color) Chart.CHART_COLOR_CHART_LINE=(ulong)clrBlack;//Assigning Chart Line Color of clrBlack(Black color) Chart.CHART_COLOR_CANDLE_BEAR=(ulong)clrBlack;//Assigning Chart Bear Candle Color of clrBlack(Black color) Chart.CHART_COLOR_CHART_DOWN=(ulong)clrBlack;//Assigning Chart Down Candle Color of clrBlack(Black color) Chart.CHART_COLOR_CANDLE_BULL=(ulong)clrWhite;//Assigning Chart Bull Candle Color of clrWhite(White color) Chart.CHART_COLOR_CHART_UP=(ulong)clrBlack;//Assigning Chart Up Candle Color of clrBlack(Black color) Chart.CHART_COLOR_ASK=(ulong)clrBlack;//Assigning Chart Ask Color of clrBlack(Black color) Chart.CHART_COLOR_BID=(ulong)clrBlack;//Assigning Chart Bid Color of clrBlack(Black color) Chart.CHART_COLOR_STOP_LEVEL=(ulong)clrBlack;//Assigning Chart Stop Level Color of clrBlack(Black color) Chart.CHART_FOREGROUND=(ulong)false;//Assigning Chart Foreground Boolean Value of 'false' Chart.CHART_SHOW_ASK_LINE=(ulong)true;//Assigning Chart Ask Line Boolean Value of 'true' Chart.CHART_SHOW_BID_LINE=(ulong)true;//Assigning Chart Bid Line Boolean Value of 'true' Chart.CHART_SHOW_PERIOD_SEP=(ulong)true;//Assigning Chart Period Separator Boolean Value of 'true' Chart.CHART_SHOW_TRADE_LEVELS=(ulong)true;//Assigning Chart Trade Levels Boolean Value of 'true' Chart.CHART_SHOW_OHLC=(ulong)false;//Assigning Chart Open-High-Low-Close Boolean Value of 'false' Chart.CHART_SHOW_GRID=(ulong)false;//Assigning Chart Grid Boolean Value of 'false' Chart.CHART_SHOW_VOLUMES=(ulong)false;//Assigning Chart Volumes Boolean Value of 'false' Chart.CHART_SCALE=(ulong)3;//Assigning Chart Scale Boolean Value of '3' Chart.CHART_AUTOSCROLL=(ulong)true;//Assigning Chart Auto Scroll Boolean Value of 'true' Chart.CHART_SHIFT_SIZE=30;//Assigning Chart Shift Size Value of '30' Chart.CHART_SHIFT=(ulong)true;//Assigning Chart Shift Boolean Value of 'true' Chart.CHART_SHOW_ONE_CLICK=ulong(false);//Assigning Chart One Click Trading a value of 'false' ChartSet();//Calling Function to set chart format }
In der Funktion ChartSet werden die Werte der ausgewählten Charteigenschaften aus der Variablen Chart vom Strukturtyp ChartFormat gesetzt.
void CChartProperties::ChartSet() { ChartSetInteger(0,CHART_MODE,Chart.CHART_MODE);//Set Chart Candle Mode ChartSetInteger(0,CHART_COLOR_BACKGROUND,Chart.CHART_COLOR_BACKGROUND);//Set Chart Background Color ChartSetInteger(0,CHART_COLOR_FOREGROUND,Chart.CHART_COLOR_FOREGROUND);//Set Chart Foreground Color ChartSetInteger(0,CHART_COLOR_CHART_LINE,Chart.CHART_COLOR_CHART_LINE);//Set Chart Line Color ChartSetInteger(0,CHART_COLOR_CANDLE_BEAR,Chart.CHART_COLOR_CANDLE_BEAR);//Set Chart Bear Candle Color ChartSetInteger(0,CHART_COLOR_CHART_DOWN,Chart.CHART_COLOR_CHART_DOWN);//Set Chart Down Candle Color ChartSetInteger(0,CHART_COLOR_CANDLE_BULL,Chart.CHART_COLOR_CANDLE_BULL);//Set Chart Bull Candle Color ChartSetInteger(0,CHART_COLOR_CHART_UP,Chart.CHART_COLOR_CHART_UP);//Set Chart Up Candle Color ChartSetInteger(0,CHART_COLOR_ASK,Chart.CHART_COLOR_ASK);//Set Chart Ask Color ChartSetInteger(0,CHART_COLOR_BID,Chart.CHART_COLOR_BID);//Set Chart Bid Color ChartSetInteger(0,CHART_COLOR_STOP_LEVEL,Chart.CHART_COLOR_STOP_LEVEL);//Set Chart Stop Level Color ChartSetInteger(0,CHART_FOREGROUND,Chart.CHART_FOREGROUND);//Set if Chart is in Foreground Visibility ChartSetInteger(0,CHART_SHOW_ASK_LINE,Chart.CHART_SHOW_ASK_LINE);//Set Chart Ask Line Visibility ChartSetInteger(0,CHART_SHOW_BID_LINE,Chart.CHART_SHOW_BID_LINE);//Set Chart Bid Line Visibility ChartSetInteger(0,CHART_SHOW_PERIOD_SEP,Chart.CHART_SHOW_PERIOD_SEP);//Set Chart Period Separator Visibility ChartSetInteger(0,CHART_SHOW_TRADE_LEVELS,Chart.CHART_SHOW_TRADE_LEVELS);//Set Chart Trade Levels Visibility ChartSetInteger(0,CHART_SHOW_OHLC,Chart.CHART_SHOW_OHLC);//Set Chart Open-High-Low-Close Visibility ChartSetInteger(0,CHART_SHOW_GRID,Chart.CHART_SHOW_GRID);//Set Chart Grid Visibility ChartSetInteger(0,CHART_SHOW_VOLUMES,Chart.CHART_SHOW_VOLUMES);//Set Chart Volumes Visibility ChartSetInteger(0,CHART_SCALE,Chart.CHART_SCALE);//Set Chart Scale Value ChartSetInteger(0,CHART_AUTOSCROLL,Chart.CHART_AUTOSCROLL);//Set Chart Auto Scroll Option ChartSetDouble(0,CHART_SHIFT_SIZE,Chart.CHART_SHIFT_SIZE);//Set Chart Shift Size Value ChartSetInteger(0,CHART_SHIFT,Chart.CHART_SHIFT);//Set Chart Shift Option ChartSetInteger(0,CHART_SHOW_ONE_CLICK,Chart.CHART_SHOW_ONE_CLICK);//Set Chart One Click Trading }
Im Destruktor werden die Integer-Werte des vorherigen Charts wiederhergestellt.
CChartProperties::~CChartProperties(void) { for(int i=0;i<65;i++)//Iterating through ENUM_CHART_PROPERTY_INTEGER Elements { ChartSetInteger(0,(ENUM_CHART_PROPERTY_INTEGER)i,0,ChartConfig[i]);//Restoring Chart values from ChartConfig array } }
Klasse der Kerzeneigenschaften
CCandleProperties hat eine mehrstufige Vererbung von Klassen:
- CChartProperties
- CSymbolProperties
CCandleProperties bindet die Klasse CTimeManagement ein.
CCandleProperties besitzt eine hierarchische Vererbung der Klassen:
- CSymbolProperties
- CSymbolInfo
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include "TimeManagement.mqh" #include "ChartProperties.mqh" //+------------------------------------------------------------------+ //|CandleProperties class | //+------------------------------------------------------------------+ class CCandleProperties : public CChartProperties { private: CTimeManagement Time; public: double Open(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Open-Price double Close(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Close-Price double High(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle High-Price double Low(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Low-Price bool IsLargerThanPreviousAndNext(datetime CandleTime,int Offset,string SYMBOL);//Determine if one candle is larger than two others }; //+------------------------------------------------------------------+ //|Retrieve Candle Open-Price | //+------------------------------------------------------------------+ double CCandleProperties::Open(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL) { return (SetSymbolName(SYMBOL))?iOpen(GetSymbolName(),Period,CandleIndex):0;//return candle open price } //+------------------------------------------------------------------+ //|Retrieve Candle Close-Price | //+------------------------------------------------------------------+ double CCandleProperties::Close(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL) { return (SetSymbolName(SYMBOL))?iClose(GetSymbolName(),Period,CandleIndex):0;//return candle close price } //+------------------------------------------------------------------+ //|Retrieve Candle High-Price | //+------------------------------------------------------------------+ double CCandleProperties::High(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL) { return (SetSymbolName(SYMBOL))?iHigh(GetSymbolName(),Period,CandleIndex):0;//return candle high price } //+------------------------------------------------------------------+ //|Retrieve Candle Low-Price | //+------------------------------------------------------------------+ double CCandleProperties::Low(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL) { return (SetSymbolName(SYMBOL))?iLow(GetSymbolName(),Period,CandleIndex):0;//return candle low price } //+------------------------------------------------------------------+ //|Determine if one candle is larger than two others | //+------------------------------------------------------------------+ bool CCandleProperties::IsLargerThanPreviousAndNext(datetime CandleTime,int Offset,string SYMBOL) { int CandleIndex = iBarShift(SYMBOL,PERIOD_M15,CandleTime);//Assign candle index of candletime //--Assign candle index of candletime minus time offset int CandleIndexMinusOffset = iBarShift(SYMBOL,PERIOD_M15,Time.TimeMinusOffset(CandleTime,Offset)); //--Assign candle index of candletime plus time offset int CandleIndexPlusOffset = iBarShift(SYMBOL,PERIOD_M15,Time.TimePlusOffset(CandleTime,Offset)); //--Assign height of M15 candletime in pips double CandleHeight = High(CandleIndex,PERIOD_M15,SYMBOL)-Low(CandleIndex,PERIOD_M15,SYMBOL); //--Assign height of M15 candletime minus offset in Pips double CandleHeightMinusOffset = High(CandleIndexMinusOffset,PERIOD_M15,SYMBOL)-Low(CandleIndexMinusOffset,PERIOD_M15,SYMBOL); //--Assign height of M15 candletime plus offset in Pips double CandleHeightPlusOffset = High(CandleIndexPlusOffset,PERIOD_M15,SYMBOL)-Low(CandleIndexPlusOffset,PERIOD_M15,SYMBOL); //--Determine if candletime height is greater than candletime height minus offset and candletime height plus offset if(CandleHeight>CandleHeightMinusOffset&&CandleHeight>CandleHeightPlusOffset) { return true;//Candletime is likely when the news event occured } return false;//Candletime is unlikely when the real news data was released } //+------------------------------------------------------------------+
Klasse der Objekteigenschaften
Diese Klasse ist für das Erstellen und Löschen von Chartobjekten zuständig.
CObjectProperties hat eine mehrstufige Vererbung von Klassen:
- CChartProperties
- CSymbolProperties
- CSymbolProperties
- CSymbolInfo
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include "ChartProperties.mqh" //+------------------------------------------------------------------+ //|ObjectProperties class | //+------------------------------------------------------------------+ class CObjectProperties:public CChartProperties { private: //Simple chart objects structure struct ObjStruct { long ChartId; string Name; } Objects[];//ObjStruct variable array //-- Add chart object to Objects array void AddObj(long chart_id,string name) { ArrayResize(Objects,Objects.Size()+1,Objects.Size()+2); Objects[Objects.Size()-1].ChartId=chart_id; Objects[Objects.Size()-1].Name=name; } public: CObjectProperties(void) {}//Class constructor //-- Create Rectangle chart object void Square(long chart_ID,string name,int x_coord,int y_coord,int width,int height,ENUM_ANCHOR_POINT Anchor); //-- Create text chart object void TextObj(long chartID,string name,string text,int x_coord,int y_coord, ENUM_BASE_CORNER Corner=CORNER_LEFT_UPPER,int fontsize=10); //-- Create Event object void EventObj(long chartID,string name,string description,datetime eventdate); //-- Class destructor removes all chart objects created previously ~CObjectProperties(void) { for(uint i=0;i<Objects.Size();i++) { ObjectDelete(Objects[i].ChartId,Objects[i].Name); } } }; //+------------------------------------------------------------------+ //|Create Rectangle chart object | //+------------------------------------------------------------------+ void CObjectProperties::Square(long chart_ID,string name,int x_coord,int y_coord,int width,int height,ENUM_ANCHOR_POINT Anchor) { const int sub_window=0; // subwindow index const int x=x_coord; // X coordinate const int y=y_coord; // Y coordinate const color back_clr=clrBlack; // background color const ENUM_BORDER_TYPE border=BORDER_SUNKEN; // border type const color clr=clrRed; // flat border color (Flat) const ENUM_LINE_STYLE style=STYLE_SOLID; // flat border style const int line_width=0; // flat border width const bool back=false; // in the background const bool selection=false; // highlight to move const bool hidden=true; // hidden in the object list ObjectDelete(chart_ID,name);//Delete previous object with the same name and chart id if(ObjectCreate(chart_ID,name,OBJ_RECTANGLE_LABEL,sub_window,0,0))//create rectangle object label { AddObj(chart_ID,name);//Add object to array ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);//Set x Distance/coordinate ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);//Set y Distance/coordinate ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width);//Set object's width/x-size ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height);//Set object's height/y-size ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr);//Set object's background color ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_TYPE,border);//Set object's border type ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,Anchor);//Set objects anchor point ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);//Set object's color ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);//Set object's style ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,line_width);//Set object's flat border width ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);//Set if object is in foreground or not ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);//Set if object is selectable/dragable ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);//Set if object is Selected ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);//Set if object is hidden in object list ChartRedraw(chart_ID); } else { Print("Failed to create object: ",name); } } //+------------------------------------------------------------------+ //|Create text chart object | //+------------------------------------------------------------------+ void CObjectProperties::TextObj(long chartID,string name,string text,int x_coord,int y_coord, ENUM_BASE_CORNER Corner=CORNER_LEFT_UPPER,int fontsize=10) { ObjectDelete(chartID,name);//Delete previous object with the same name and chart id if(ObjectCreate(chartID,name,OBJ_LABEL,0,0,0))//Create object label { AddObj(chartID,name);//Add object to array ObjectSetInteger(chartID,name,OBJPROP_XDISTANCE,x_coord);//Set x Distance/coordinate ObjectSetInteger(chartID,name,OBJPROP_YDISTANCE,y_coord);//Set y Distance/coordinate ObjectSetInteger(chartID,name,OBJPROP_CORNER,Corner);//Set object's corner anchor ObjectSetString(chartID,name,OBJPROP_TEXT,text);//Set object's text ObjectSetInteger(chartID,name,OBJPROP_COLOR,SymbolBackground());//Set object's color ObjectSetInteger(chartID,name,OBJPROP_FONTSIZE,fontsize);//Set object's font-size } else { Print("Failed to create object: ",name); } } //+------------------------------------------------------------------+ //|Create Event object | //+------------------------------------------------------------------+ void CObjectProperties::EventObj(long chartID,string name,string description,datetime eventdate) { ObjectDelete(chartID,name);//Delete previous object with the same name and chart id if(ObjectCreate(chartID,name,OBJ_EVENT,0,eventdate,0))//Create object event { AddObj(chartID,name);//Add object to array ObjectSetString(chartID,name,OBJPROP_TEXT,description);//Set object's text ObjectSetInteger(chartID,name,OBJPROP_COLOR,clrBlack);//Set object's color } else { Print("Failed to create object: ",name); } } //+------------------------------------------------------------------
Die Array-Variable Objects speichert alle Chartobjekte, die in dieser Klasse CObjectProperties erstellt wurden.
struct ObjStruct { long ChartId; string Name; } Objects[];//ObjStruct variable array
Die Funktion AddObj fügt die Chart-ID und den Objektnamen des Chartobjekts in das Array Objects ein.
//-- Add chart object to Objects array void AddObj(long chart_id,string name) { ArrayResize(Objects,Objects.Size()+1,Objects.Size()+2); Objects[Objects.Size()-1].ChartId=chart_id; Objects[Objects.Size()-1].Name=name; }
Die Funktion Quadrat hat die Aufgabe, ein Rechteck-Objekt mit bestimmten Eigenschaften zu erstellen, um eine individuelle Anpassung zu ermöglichen.
void CObjectProperties::Square(long chart_ID,string name,int x_coord,int y_coord,int width,int height,ENUM_ANCHOR_POINT Anchor) { const int sub_window=0; // subwindow index const int x=x_coord; // X coordinate const int y=y_coord; // Y coordinate const color back_clr=clrBlack; // background color const ENUM_BORDER_TYPE border=BORDER_SUNKEN; // border type const color clr=clrRed; // flat border color (Flat) const ENUM_LINE_STYLE style=STYLE_SOLID; // flat border style const int line_width=0; // flat border width const bool back=false; // in the background const bool selection=false; // highlight to move const bool hidden=true; // hidden in the object list ObjectDelete(chart_ID,name);//Delete previous object with the same name and chart id if(ObjectCreate(chart_ID,name,OBJ_RECTANGLE_LABEL,sub_window,0,0))//create rectangle object label { AddObj(chart_ID,name);//Add object to array ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);//Set x Distance/coordinate ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);//Set y Distance/coordinate ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width);//Set object's width/x-size ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height);//Set object's height/y-size ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr);//Set object's background color ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_TYPE,border);//Set object's border type ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,Anchor);//Set objects anchor point ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);//Set object's color ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);//Set object's style ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,line_width);//Set object's flat border width ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);//Set if object is in foreground or not ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);//Set if object is selectable/dragable ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);//Set if object is Selected ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);//Set if object is hidden in object list ChartRedraw(chart_ID); } else { Print("Failed to create object: ",name); } }
Die Funktion TextObj erstellt Textobjekte auf dem Chart.
void CObjectProperties::TextObj(long chartID,string name,string text,int x_coord,int y_coord, ENUM_BASE_CORNER Corner=CORNER_LEFT_UPPER,int fontsize=10) { ObjectDelete(chartID,name);//Delete previous object with the same name and chart id if(ObjectCreate(chartID,name,OBJ_LABEL,0,0,0))//Create object label { AddObj(chartID,name);//Add object to array ObjectSetInteger(chartID,name,OBJPROP_XDISTANCE,x_coord);//Set x Distance/coordinate ObjectSetInteger(chartID,name,OBJPROP_YDISTANCE,y_coord);//Set y Distance/coordinate ObjectSetInteger(chartID,name,OBJPROP_CORNER,Corner);//Set object's corner anchor ObjectSetString(chartID,name,OBJPROP_TEXT,text);//Set object's text ObjectSetInteger(chartID,name,OBJPROP_COLOR,SymbolBackground());//Set object's color ObjectSetInteger(chartID,name,OBJPROP_FONTSIZE,fontsize);//Set object's font-size } else { Print("Failed to create object: ",name); } }
Die Funktion EventObj erstellt Ereignisobjekte im Chart, um die wirtschaftlichen Ereignisse anzuzeigen, die eingetreten sind oder eintreten werden.
void CObjectProperties::EventObj(long chartID,string name,string description,datetime eventdate) { ObjectDelete(chartID,name);//Delete previous object with the same name and chart id if(ObjectCreate(chartID,name,OBJ_EVENT,0,eventdate,0))//Create object event { AddObj(chartID,name);//Add object to array ObjectSetString(chartID,name,OBJPROP_TEXT,description);//Set object's text ObjectSetInteger(chartID,name,OBJPROP_COLOR,clrBlack);//Set object's color } else { Print("Failed to create object: ",name); } }
Die Klasse der Nachrichten
Kalendertabellen in Teil 1:
In unserer früheren Datenbank aus Teil 1 war die Dateigröße enorm und die Speicherung aller Nachrichtendaten in der Datenbank ziemlich langsam. Dies liegt daran, dass die Nachrichtendaten ineffizient gespeichert werden. Die größte Ursache für die Dateigröße und die träge Leistung ist die wiederholte Speicherung ähnlicher Daten.
Die Tabellen:
- Data_AU
- Data_None
- Data_UK
- Data_US
Wir speichern die gleichen Nachrichtendaten mit unterschiedlichen Zeitdaten.
Neues Design:
Kalenderinhalte in Teil 2:
Anstatt immer wieder dieselben Ereignisdaten mit unterschiedlichen Zeiten zu speichern. Wir werden eine einzelne Tabelle erstellen, um alle Nachrichtenereignisdaten mit dem Namen MQL5Calendar zu speichern. Und um die unterschiedlichen Zeitdaten zwischen den einzelnen Sommerzeitplänen zu speichern, werden wir eine weitere Tabelle mit dem Namen TimeSchedule anlegen. Mit diesem Layout wird die Dateigröße im Vergleich zur vorherigen Kalenderdatenbank um mehr als die Hälfte reduziert und die Leistung erhöht.
Im neuen Datenbankdesign werden wir diese Inhalte haben:
- AutoDST Table
- Calendar_AU View
- Calendar_NONE View
- Calendar_UK View
- Calendar_US View
- MQL5Calendar Table
- Record Table
- TimeSchedule Table
- OnlyOne_AutoDST Trigger
- OnlyOne_Record Trigger
Wir werden die Tabellen aus der vorherigen Datenbank normalisieren, diese Tabellen sind Data_AU, Data_None, Data_UK und Data_US.
Was bedeutet die Normalisierung einer Datenbank?
Die Datenbanknormalisierung ist ein Prozess im Datenbankdesign, der dazu dient, eine Datenbank in Tabellen und Spalten zu organisieren, um Redundanzen und Abhängigkeiten zu minimieren. Die Hauptziele sind die Beseitigung redundanter Daten (z. B. Speicherung derselben Daten in mehr als einer Tabelle) und die Sicherstellung sinnvoller Datenabhängigkeiten (Speicherung nur verwandter Daten in einer Tabelle). Dieses Verfahren führt zu einer Reihe von Tabellen, die leichter zu pflegen sind und das Risiko von Datenanomalien verringern.
Wir werden auch Trigger erstellen, um sicherzustellen, dass nur ein Datensatz in den Tabellen AutoDST und Record gespeichert wird. Zusätzlich werden wir Ansichten für jeden Sommerzeitplan erstellen, um die Nachrichtenereignisse des letzten aktualisierten Tages anzuzeigen. Idealerweise kann man so leicht herausfinden, welche Nachrichtenereignisse aktuell sind, ohne wiederholt Abfragen in den Tabellen mit Tausenden von Einträgen durchführen zu müssen.
Okay, was ist ein Trigger?
Ein Trigger in SQLite ist eine spezielle Art von gespeicherter Prozedur, die automatisch eine bestimmte Menge von Aktionen als Reaktion auf bestimmte Ereignisse in einer bestimmten Tabelle ausführt. Diese Ereignisse können Einfügungen, Aktualisierungen oder Löschungen von Zeilen in der Tabelle sein.
Was ist ein „View“ (Ansicht)?
Ein View in SQLite ist eine virtuelle Tabelle, die auf der Ergebnismenge einer SELECT-Abfrage basiert. Im Gegensatz zu einer Tabelle werden in einem View keine Daten physisch gespeichert. Stattdessen bietet sie eine Möglichkeit, Daten aus einer oder mehreren Tabellen in einer bestimmten Struktur oder einem bestimmten Format darzustellen, was häufig komplexe Abfragen vereinfacht und die Datensicherheit erhöht.
Bevor wir damit beginnen, neue Tabellen zu erstellen und die ohnehin schon große Datenbank noch weiter zu vergrößern. Wir brauchen eine Möglichkeit zu wissen, welche Tabellen wir löschen und welche wir behalten sollen. Eine einfache Lösung wäre, nach jeder Tabelle zu suchen, von der wir wissen, dass sie in unserer vorherigen Datenbank existiert, also auch Data_AU und andere. Aber wir können nicht einfach hart codieren, welche Tabellen wir aus unserem Speicher löschen sollen, unser Programm muss die Tabellen, die wir nicht mehr brauchen, selbst finden. Dazu müssen wir prüfen, welche Tabellen in unserer Datenbank vorhanden sind, und die Tabellen durchgehen, die wir löschen wollen, und die Tabellen überspringen, die wir behalten wollen.
In SQLite gibt es eine Tabelle namens SQLITE_MASTER/SQLITE_SCHEMA, in der die Metadaten der Datenbank gespeichert werden, einschließlich Informationen über alle Objekte in der Datenbank und die zu ihrer Definition verwendete SQL. Es ist der wichtigste Systemkatalog in SQLite. Die nachstehende Abfrage dient dazu, alle Informationen aus der Datenbank abzurufen.
SELECT * FROM SQLITE_MASTER;
Datenbank-Ausgabe:
type name tbl_name rootpage sql table Data_None Data_None 2 CREATE TABLE Data_None(ID INT NOT NULL,EVENTID INT NOT NULL,COUNTRY STRING NOT NULL,EVENTNAME STRING NOT NULL,EVENTTYPE STRING NOT NULL,EVENTIMPORTANCE STRING NOT NULL,EVENTDATE STRING NOT NULL,EVENTCURRENCY STRING NOT NULL,EVENTCODE STRING NOT NULL,EVENTSECTOR STRING NOT NULL,EVENTFORECAST STRING NOT NULL,EVENTPREVALUE STRING NOT NULL,EVENTIMPACT STRING NOT NULL,EVENTFREQUENCY STRING NOT NULL,PRIMARY KEY(ID)) index sqlite_autoindex_Data_None_1 Data_None 3 table Data_US Data_US 4 CREATE TABLE Data_US(ID INT NOT NULL,EVENTID INT NOT NULL,COUNTRY STRING NOT NULL,EVENTNAME STRING NOT NULL,EVENTTYPE STRING NOT NULL,EVENTIMPORTANCE STRING NOT NULL,EVENTDATE STRING NOT NULL,EVENTCURRENCY STRING NOT NULL,EVENTCODE STRING NOT NULL,EVENTSECTOR STRING NOT NULL,EVENTFORECAST STRING NOT NULL,EVENTPREVALUE STRING NOT NULL,EVENTIMPACT STRING NOT NULL,EVENTFREQUENCY STRING NOT NULL,PRIMARY KEY(ID)) index sqlite_autoindex_Data_US_1 Data_US 5 table Data_UK Data_UK 6 CREATE TABLE Data_UK(ID INT NOT NULL,EVENTID INT NOT NULL,COUNTRY STRING NOT NULL,EVENTNAME STRING NOT NULL,EVENTTYPE STRING NOT NULL,EVENTIMPORTANCE STRING NOT NULL,EVENTDATE STRING NOT NULL,EVENTCURRENCY STRING NOT NULL,EVENTCODE STRING NOT NULL,EVENTSECTOR STRING NOT NULL,EVENTFORECAST STRING NOT NULL,EVENTPREVALUE STRING NOT NULL,EVENTIMPACT STRING NOT NULL,EVENTFREQUENCY STRING NOT NULL,PRIMARY KEY(ID)) index sqlite_autoindex_Data_UK_1 Data_UK 7 table Data_AU Data_AU 8 CREATE TABLE Data_AU(ID INT NOT NULL,EVENTID INT NOT NULL,COUNTRY STRING NOT NULL,EVENTNAME STRING NOT NULL,EVENTTYPE STRING NOT NULL,EVENTIMPORTANCE STRING NOT NULL,EVENTDATE STRING NOT NULL,EVENTCURRENCY STRING NOT NULL,EVENTCODE STRING NOT NULL,EVENTSECTOR STRING NOT NULL,EVENTFORECAST STRING NOT NULL,EVENTPREVALUE STRING NOT NULL,EVENTIMPACT STRING NOT NULL,EVENTFREQUENCY STRING NOT NULL,PRIMARY KEY(ID)) index sqlite_autoindex_Data_AU_1 Data_AU 9 table Records Records 38774 CREATE TABLE Records(RECORDEDTIME INT NOT NULL) table AutoDST AutoDST 38775 CREATE TABLE AutoDST(DST STRING NOT NULL)
Wie in der Datenbankausgabe zu sehen ist, gibt es einen so genannten Index, den wir vorher nicht erstellt haben.
Was ist ein Index?
Ein Index in SQLite ist ein Datenbankobjekt, das eine Möglichkeit bietet, die Leistung von Abfrageoperationen zu verbessern, indem es einen schnelleren Abruf von Datensätzen aus einer Tabelle ermöglicht. Indizes sind besonders nützlich, um Such-, Sortier- und Verknüpfungsoperationen zu beschleunigen, indem sie eine sortierte Datenstruktur (in der Regel ein B-Baum) erstellen, die es der Datenbankmaschine ermöglicht, Zeilen schneller zu finden.
Warum wurde der Index erstellt, wenn wir ihn nicht vorher erstellt haben?
Wenn eine Tabelle in SQLite einen Primärschlüssel hat, wird automatisch ein Index für diese bestimmte Tabelle erstellt.
In unserer Datenbankausgabe haben wir nun endlich alle Objekte und Metadaten in der Datenbank, wir können nun die Tabellen finden, die nicht mehr benötigt werden und sie löschen. Dazu erstellen wir ein Array mit den benötigten Tabellen und den SQL-Anweisungen, mit denen diese Tabellen erstellt werden, damit wir sie mit der Datenbankausgabe vergleichen und die nicht übereinstimmenden entfernen können.
CNews hat eine mehrstufige Vererbung von Klassen:
- CCandleProperties
- CChartProperties
- CSymbolProperties
CNews bindet Klassen ein:
- CDaylightSavings_UK
- CDaylightSavings_US
- CDaylightSparen_AU
CNews hat einen Eintrag in der Header-Datei CommonVariables.mqh
CNews besitzt eine hierarchische Vererbung von Klassen:
- CSymbolProperties
- CSymbolInfo
- CCandleProperties
- CTimeManagement
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include "CommonVariables.mqh" #include "DayLightSavings/DaylightSavings_UK.mqh" #include "DayLightSavings/DaylightSavings_US.mqh" #include "DayLightSavings/DaylightSavings_AU.mqh" #include "CandleProperties.mqh" //+------------------------------------------------------------------+ //|News class | //+------------------------------------------------------------------+ class CNews : private CCandleProperties { //Private Declarations Only accessable by this class/header file private: //-- To keep track of what is in our database enum CalendarComponents { AutoDST_Table,//AutoDST Table CalendarAU_View,//View for DST_AU CalendarNONE_View,//View for DST_NONE CalendarUK_View,//View for DST_UK CalendarUS_View,//View for DST_US Record_Table,// Record Table TimeSchedule_Table,//TimeSchedule Table MQL5Calendar_Table,//MQL5Calendar Table AutoDST_Trigger,//Table Trigger for AutoDST Record_Trigger//Table Trigger for Record }; //-- structure to retrieve all the objects in the database struct SQLiteMaster { string type;//will store object's type string name;//will store object's name string tbl_name;//will store table name int rootpage;//will store rootpage string sql;//Will store the sql create statement } DBContents[];//Array of type SQLiteMaster //-- MQL5CalendarContents inherits from SQLiteMaster structure struct MQL5CalendarContents:SQLiteMaster { CalendarComponents Content; string insert;//Will store the sql insert statement } CalendarContents[10];//Array to Store objects in our database CTimeManagement Time;//TimeManagement Object declaration CDaylightSavings_UK Savings_UK;//DaylightSavings Object for the UK and EU CDaylightSavings_US Savings_US;//DaylightSavings Object for the US CDaylightSavings_AU Savings_AU;//DaylightSavings Object for the AU bool AutoDetectDST(DST_type &dstType);//Function will determine Broker DST DST_type DSTType;//variable of DST_type enumeration declared in the CommonVariables class/header file bool InsertIntoTables(int db,Calendar &Evalues[]);//Function for inserting Economic Data in to a database's table void CreateAutoDST(int db);//Function for creating and inserting Recommend DST for the Broker into a table bool CreateCalendarTable(int db,bool &tableExists);//Function for creating a table in a database bool CreateTimeTable(int db,bool &tableExists);//Function for creating a table in a database void CreateCalendarViews(int db);//Function for creating a view in a database void CreateRecordTable(int db);//Creates a table to store the record of when last the Calendar database was updated/created bool UpdateRecords();//Checks if the main Calendar database needs an update or not void EconomicDetails(Calendar &NewsTime[]);//Gets values from the MQL5 economic Calendar string DropRequest;//Variable for dropping tables in the database //-- Function for retrieving the MQL5CalendarContents structure for the enumartion type CalendarComponents MQL5CalendarContents CalendarStruct(CalendarComponents Content) { MQL5CalendarContents Calendar; for(uint i=0;i<CalendarContents.Size();i++) { if(CalendarContents[i].Content==Content) { return CalendarContents[i]; } } return Calendar; } //Public declarations accessable via a class's Object public: CNews(void); ~CNews(void);//Deletes a text file created when the Calendar database is being worked on void CreateEconomicDatabase();//Creates the Calendar database for a specific Broker datetime GetLatestNewsDate();//Gets the lastest/newest date in the Calendar database }; //+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CNews::CNews(void):DropRequest("PRAGMA foreign_keys = OFF; " "PRAGMA secure_delete = ON; " "Drop %s IF EXISTS %s; " "Vacuum; " "PRAGMA foreign_keys = ON;")//Sql drop statement { //-- initializing properties for the AutoDST table CalendarContents[0].Content = AutoDST_Table; CalendarContents[0].name = "AutoDST"; CalendarContents[0].sql = "CREATE TABLE AutoDST(DST TEXT NOT NULL DEFAULT 'DST_NONE')STRICT;"; CalendarContents[0].tbl_name = "AutoDST"; CalendarContents[0].type = "table"; CalendarContents[0].insert = "INSERT INTO 'AutoDST'(DST) VALUES ('%s');"; string views[] = {"UK","US","AU","NONE"}; string view_sql = "CREATE VIEW IF NOT EXISTS Calendar_%s " "AS " "SELECT C.Eventid,C.Eventname,C.Country,T.DST_%s as Time,C.EventCurrency,C.Eventcode from MQL5Calendar C,Record R " "Inner join TimeSchedule T on C.ID=T.ID " "Where DATE(REPLACE(T.DST_%s,'.','-'))=R.Date " "Order by T.DST_%s Asc;"; //-- Sql statements for creating the table views for(uint i=1;i<=views.Size();i++) { CalendarContents[i].Content = (CalendarComponents)i; CalendarContents[i].name = StringFormat("Calendar_%s",views[i-1]); CalendarContents[i].sql = StringFormat(view_sql,views[i-1],views[i-1],views[i-1],views[i-1]); CalendarContents[i].tbl_name = StringFormat("Calendar_%s",views[i-1]); CalendarContents[i].type = "view"; } //-- initializing properties for the Record table CalendarContents[5].Content = Record_Table; CalendarContents[5].name = "Record"; CalendarContents[5].sql = "CREATE TABLE Record(Date TEXT NOT NULL)STRICT;"; CalendarContents[5].tbl_name="Record"; CalendarContents[5].type = "table"; CalendarContents[5].insert = "INSERT INTO 'Record'(Date) VALUES (Date(REPLACE('%s','.','-')));"; //-- initializing properties for the TimeSchedule table CalendarContents[6].Content = TimeSchedule_Table; CalendarContents[6].name = "TimeSchedule"; CalendarContents[6].sql = "CREATE TABLE TimeSchedule(ID INT NOT NULL,DST_UK TEXT NOT NULL,DST_US TEXT NOT NULL," "DST_AU TEXT NOT NULL,DST_NONE TEXT NOT NULL,FOREIGN KEY (ID) REFERENCES MQL5Calendar (ID))STRICT;"; CalendarContents[6].tbl_name="TimeSchedule"; CalendarContents[6].type = "table"; CalendarContents[6].insert = "INSERT INTO 'TimeSchedule'(ID,DST_UK,DST_US,DST_AU,DST_NONE) " "VALUES (%d,'%s','%s', '%s', '%s');"; //-- initializing properties for the MQL5Calendar table CalendarContents[7].Content = MQL5Calendar_Table; CalendarContents[7].name = "MQL5Calendar"; CalendarContents[7].sql = "CREATE TABLE MQL5Calendar(ID INT NOT NULL,EVENTID INT NOT NULL,COUNTRY TEXT NOT NULL," "EVENTNAME TEXT NOT NULL,EVENTTYPE TEXT NOT NULL,EVENTIMPORTANCE TEXT NOT NULL," "EVENTCURRENCY TEXT NOT NULL,EVENTCODE TEXT NOT NULL,EVENTSECTOR TEXT NOT NULL," "EVENTFORECAST TEXT NOT NULL,EVENTPREVALUE TEXT NOT NULL,EVENTIMPACT TEXT NOT NULL," "EVENTFREQUENCY TEXT NOT NULL,PRIMARY KEY(ID))STRICT;"; CalendarContents[7].tbl_name="MQL5Calendar"; CalendarContents[7].type = "table"; CalendarContents[7].insert = "INSERT INTO 'MQL5Calendar'(ID,EVENTID,COUNTRY,EVENTNAME,EVENTTYPE,EVENTIMPORTANCE,EVENTCURRENCY,EVENTCODE," "EVENTSECTOR,EVENTFORECAST,EVENTPREVALUE,EVENTIMPACT,EVENTFREQUENCY) " "VALUES (%d,%d,'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s');"; //-- Sql statement for creating the AutoDST table's trigger CalendarContents[8].Content = AutoDST_Trigger; CalendarContents[8].name = "OnlyOne_AutoDST"; CalendarContents[8].sql = "CREATE TRIGGER IF NOT EXISTS OnlyOne_AutoDST " "BEFORE INSERT ON AutoDST " "BEGIN " "Delete from AutoDST; " "END;"; CalendarContents[8].tbl_name="AutoDST"; CalendarContents[8].type = "trigger"; //-- Sql statement for creating the Record table's trigger CalendarContents[9].Content = Record_Trigger; CalendarContents[9].name = "OnlyOne_Record"; CalendarContents[9].sql = "CREATE TRIGGER IF NOT EXISTS OnlyOne_Record " "BEFORE INSERT ON Record " "BEGIN " "Delete from Record; " "END;"; CalendarContents[9].tbl_name="Record"; CalendarContents[9].type = "trigger"; } //+------------------------------------------------------------------+ //|Destructor | //+------------------------------------------------------------------+ CNews::~CNews(void) { if(FileIsExist(NEWS_TEXT_FILE,FILE_COMMON))//Check if the news database open text file exists { FileDelete(NEWS_TEXT_FILE,FILE_COMMON); } } //+------------------------------------------------------------------+ //|Gets values from the MQL5 economic Calendar | //+------------------------------------------------------------------+ void CNews::EconomicDetails(Calendar &NewsTime[]) { int Size=0;//to keep track of the size of the events in the NewsTime array MqlCalendarCountry countries[]; string Country_code=""; for(int i=0,count=CalendarCountries(countries); i<count; i++) { MqlCalendarValue values[]; datetime date_from=0;//Get date from the beginning datetime date_to=(datetime)(Time.MonthsS()+iTime(Symbol(),PERIOD_D1,0));//Date of the next month from the current day if(CalendarValueHistory(values,date_from,date_to,countries[i].code)) { for(int x=0; x<(int)ArraySize(values); x++) { MqlCalendarEvent event; ulong event_id=values[x].event_id;//Get the event id if(CalendarEventById(event_id,event)) { ArrayResize(NewsTime,Size+1,Size+2);//Readjust the size of the array to +1 of the array size StringReplace(event.name,"'","");//Removing or replacing single quotes(') from event name with an empty string NewsTime[Size].CountryName = countries[i].name;//storing the country's name from the specific event NewsTime[Size].EventName = event.name;//storing the event's name NewsTime[Size].EventType = EnumToString(event.type);//storing the event type from (ENUM_CALENDAR_EVENT_TYPE) to a string //-- storing the event importance from (ENUM_CALENDAR_EVENT_IMPORTANCE) to a string NewsTime[Size].EventImportance = EnumToString(event.importance); NewsTime[Size].EventId = event.id;//storing the event id NewsTime[Size].EventDate = TimeToString(values[x].time);//storing normal event time NewsTime[Size].EventCurrency = countries[i].currency;//storing event currency NewsTime[Size].EventCode = countries[i].code;//storing event code NewsTime[Size].EventSector = EnumToString(event.sector);//storing event sector from (ENUM_CALENDAR_EVENT_SECTOR) to a string if(values[x].HasForecastValue())//Checks if the event has a forecast value { NewsTime[Size].EventForecast = (string)values[x].forecast_value;//storing the forecast value into a string } else { NewsTime[Size].EventForecast = "None";//storing 'None' as the forecast value } if(values[x].HasPreviousValue())//Checks if the event has a previous value { NewsTime[Size].EventPreval = (string)values[x].prev_value;//storing the previous value into a string } else { NewsTime[Size].EventPreval = "None";//storing 'None' as the previous value } //-- storing the event impact from (ENUM_CALENDAR_EVENT_IMPACT) to a string NewsTime[Size].EventImpact = EnumToString(values[x].impact_type); //-- storing the event frequency from (ENUM_CALENDAR_EVENT_FREQUENCY) to a string NewsTime[Size].EventFrequency = EnumToString(event.frequency); Size++;//incrementing the Calendar array NewsTime } } } } } //+------------------------------------------------------------------+ //|Checks if the main Calendar database needs an update or not | //+------------------------------------------------------------------+ bool CNews::UpdateRecords() { //initialize variable to true bool perform_update=true; //--- open/create //-- try to open database Calendar int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE| DATABASE_OPEN_COMMON); if(db==INVALID_HANDLE)//Checks if the database was able to be opened { //if opening the database failed if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if the database Calendar exists in the common folder { return perform_update;//Returns true when the database was failed to be opened and the file doesn't exist in the common folder } } int MasterRequest = DatabasePrepare(db,"select * from sqlite_master where type<>'index';"); if(MasterRequest==INVALID_HANDLE) { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); } else { SQLiteMaster ReadContents; //Assigning values from the sql query into DBContents array for(int i=0; DatabaseReadBind(MasterRequest,ReadContents); i++) { ArrayResize(DBContents,i+1,i+2); DBContents[i].type = ReadContents.type; DBContents[i].name = ReadContents.name; DBContents[i].tbl_name = ReadContents.tbl_name; DBContents[i].rootpage = ReadContents.rootpage; /*Check if the end of the sql string has a character ';' if not add this character to the string*/ DBContents[i].sql = (StringFind(ReadContents.sql,";",StringLen(ReadContents.sql)-1)== (StringLen(ReadContents.sql)-1))?ReadContents.sql:ReadContents.sql+";";; } uint contents_exists = 0; for(uint i=0;i<DBContents.Size();i++) { bool isCalendarContents = false; for(uint x=0;x<CalendarContents.Size();x++) { /*Store Sql query from CalendarContents without string ' IF NOT EXISTS'*/ string CalendarSql=CalendarContents[x].sql; StringReplace(CalendarSql," IF NOT EXISTS",""); //-- Check if the Db object is in our list if(DBContents[i].name==CalendarContents[x].name&& (DBContents[i].sql==CalendarSql|| DBContents[i].sql==CalendarContents[x].sql)&& CalendarContents[x].type==DBContents[i].type&& CalendarContents[x].tbl_name==DBContents[i].tbl_name) { contents_exists++; isCalendarContents = true; } } if(!isCalendarContents) { //-- Print DBcontent's name if it does not match with CalendarContents PrintFormat("DBContent: %s is not needed!",DBContents[i].name); //-- We will drop the table if it is not neccessary DatabaseExecute(db,StringFormat(DropRequest,DBContents[i].type,DBContents[i].name)); Print("Attempting To Clean Database..."); } } /*If not all the CalendarContents exist in the Calendar Database before an update */ if(contents_exists!=CalendarContents.Size()) { return perform_update; } } if(!DatabaseTableExists(db,CalendarStruct(Record_Table).name))//If the database table 'Record' doesn't exist { DatabaseClose(db); return perform_update; } //-- Sql query to determine the lastest or maximum date recorded /* If the last recorded date data in the 'Record' table is not equal to the current day, perform an update! */ string request_text=StringFormat("SELECT Date FROM %s where Date=Date(REPLACE('%s','.','-'))", CalendarStruct(Record_Table).name,TimeToString(TimeTradeServer())); int request=DatabasePrepare(db,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); DatabaseClose(db); return perform_update; } if(DatabaseRead(request))//Will be true if there are results from the sql query/request { DatabaseFinalize(request);//Removes a request created in DatabasePrepare() DatabaseClose(db);//Closes the database perform_update=false; return perform_update; } else { DatabaseFinalize(request);//Removes a request created in DatabasePrepare() DatabaseClose(db);//Closes the database return perform_update; } } //+------------------------------------------------------------------+ //|Creates the Calendar database for a specific Broker | //+------------------------------------------------------------------+ void CNews::CreateEconomicDatabase() { if(FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Check if the database exists { if(!UpdateRecords())//Check if the database is up to date { return;//will terminate execution of the rest of the code below } } if(FileIsExist(NEWS_TEXT_FILE,FILE_COMMON))//Check if the database is open { return;//will terminate execution of the rest of the code below } Calendar Evalues[];//Creating a Calendar array variable bool failed=false,tableExists=false; int file=INVALID_HANDLE; //--- open/create the database 'Calendar' //-- will try to open/create in the common folder int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE| DATABASE_OPEN_COMMON); if(db==INVALID_HANDLE)//Checks if the database 'Calendar' failed to open/create { Print("DB: ",NEWS_DATABASE_FILE, " open failed with code ", GetLastError()); return;//will terminate execution of the rest of the code below } else { //-- try to create a text file 'NewsDatabaseOpen' in common folder file=FileOpen(NEWS_TEXT_FILE,FILE_WRITE|FILE_ANSI|FILE_TXT|FILE_COMMON); if(file==INVALID_HANDLE) { DatabaseClose(db);//Closes the database 'Calendar' if the News text file failed to be created return;//will terminate execution of the rest of the code below } } DatabaseTransactionBegin(db);//Starts transaction execution Print("Please wait..."); //-- attempt to create the MQL5Calendar and TimeSchedule tables if(!CreateCalendarTable(db,tableExists)||!CreateTimeTable(db,tableExists)) { FileClose(file);//Closing the file 'NewsDatabaseOpen.txt' FileDelete(NEWS_TEXT_FILE,FILE_COMMON);//Deleting the file 'NewsDatabaseOpen.txt' return;//will terminate execution of the rest of the code below } EconomicDetails(Evalues);//Retrieving the data from the Economic Calendar if(tableExists)//Checks if there is an existing table within the Calendar Database { //if there is an existing table we will notify the user that we are updating the table. PrintFormat("Updating %s",NEWS_DATABASE_FILE); } else { //if there isn't an existing table we will notify the user that we about to create one PrintFormat("Creating %s",NEWS_DATABASE_FILE); } //-- attempt to insert economic event data into the calendar tables if(!InsertIntoTables(db,Evalues)) { //-- Will assign true if inserting economic vaules failed in the MQL5Calendar and TimeSchedule tables failed=true; } if(failed) { //--- roll back all transactions and unlock the database DatabaseTransactionRollback(db); PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError()); FileClose(file);//Close the text file 'NEWS_TEXT_FILE' FileDelete(NEWS_TEXT_FILE,FILE_COMMON);//Delete the text file, as we are reverted/rolled-back the database ArrayRemove(Evalues,0,WHOLE_ARRAY);//Removes the values in the array } else { CreateCalendarViews(db); CreateRecordTable(db);//Will create the 'Record' table and insert the current time CreateAutoDST(db);//Will create the 'AutoDST' table and insert the broker's DST schedule FileClose(file);//Close the text file 'NEWS_TEXT_FILE' FileDelete(NEWS_TEXT_FILE,FILE_COMMON);//Delete the text file, as we are about to close the database ArrayRemove(Evalues,0,WHOLE_ARRAY);//Removes the values in the array if(tableExists) { //Let the user/trader know that the database was updated PrintFormat("%s Updated",NEWS_DATABASE_FILE); } else { //Let the user/trader know that the database was created PrintFormat("%s Created",NEWS_DATABASE_FILE); } } //--- all transactions have been performed successfully - record changes and unlock the database DatabaseTransactionCommit(db); DatabaseClose(db);//Close the database } //+------------------------------------------------------------------+ //|Function for creating a table in a database | //+------------------------------------------------------------------+ bool CNews::CreateCalendarTable(int db,bool &tableExists) { //-- Checks if a table 'MQL5Calendar' exists if(DatabaseTableExists(db,CalendarStruct(MQL5Calendar_Table).name)) { tableExists=true;//Assigns true to tableExists variable //-- Checks if a table 'TimeSchedule' exists in the database 'Calendar' if(DatabaseTableExists(db,CalendarStruct(TimeSchedule_Table).name)) { //-- We will drop the table if the table already exists if(!DatabaseExecute(db,StringFormat("Drop Table %s",CalendarStruct(TimeSchedule_Table).name))) { //If the table failed to be dropped/deleted PrintFormat("Failed to drop table %s with code %d",CalendarStruct(TimeSchedule_Table).name,GetLastError()); DatabaseClose(db);//Close the database return false;//will terminate execution of the rest of the code below and return false, when the table cannot be dropped } } //--We will drop the table if the table already exists if(!DatabaseExecute(db,StringFormat("Drop Table %s",CalendarStruct(MQL5Calendar_Table).name))) { //If the table failed to be dropped/deleted PrintFormat("Failed to drop table %s with code %d",CalendarStruct(MQL5Calendar_Table).name,GetLastError()); DatabaseClose(db);//Close the database return false;//will terminate execution of the rest of the code below and return false, when the table cannot be dropped } } //-- If the database table 'MQL5Calendar' doesn't exist if(!DatabaseTableExists(db,CalendarStruct(MQL5Calendar_Table).name)) { //--- create the table 'MQL5Calendar' if(!DatabaseExecute(db,CalendarStruct(MQL5Calendar_Table).sql))//Checks if the table was successfully created { Print("DB: create the Calendar table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return false;//Function returns false if creating the table failed } } return true;//Function returns true if creating the table was successful } //+------------------------------------------------------------------+ //|Function for creating a table in a database | //+------------------------------------------------------------------+ bool CNews::CreateTimeTable(int db,bool &tableExists) { //-- If the database table 'TimeSchedule' doesn't exist if(!DatabaseTableExists(db,CalendarStruct(TimeSchedule_Table).name)) { //--- create the table 'TimeSchedule' if(!DatabaseExecute(db,CalendarStruct(TimeSchedule_Table).sql))//Checks if the table was successfully created { Print("DB: create the Calendar table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return false;//Function returns false if creating the table failed } } return true;//Function returns true if creating the table was successful } //+------------------------------------------------------------------+ //|Function for creating views in a database | //+------------------------------------------------------------------+ void CNews::CreateCalendarViews(int db) { for(uint i=1;i<=4;i++) { if(!DatabaseExecute(db,CalendarStruct((CalendarComponents)i).sql))//Checks if the view was successfully created { Print("DB: create the Calendar view failed with code ", GetLastError()); } } } //+------------------------------------------------------------------+ //|Function for inserting Economic Data in to a database's table | //+------------------------------------------------------------------+ bool CNews::InsertIntoTables(int db,Calendar &Evalues[]) { for(uint i=0; i<Evalues.Size(); i++)//Looping through all the Economic Events { string request_insert_into_calendar = StringFormat(CalendarStruct(MQL5Calendar_Table).insert, i, Evalues[i].EventId, Evalues[i].CountryName, Evalues[i].EventName, Evalues[i].EventType, Evalues[i].EventImportance, Evalues[i].EventCurrency, Evalues[i].EventCode, Evalues[i].EventSector, Evalues[i].EventForecast, Evalues[i].EventPreval, Evalues[i].EventImpact, Evalues[i].EventFrequency);//Inserting all the columns for each event record if(DatabaseExecute(db,request_insert_into_calendar))//Check if insert query into calendar was successful { string request_insert_into_time = StringFormat(CalendarStruct(TimeSchedule_Table).insert, i, //-- Economic EventDate adjusted for UK DST(Daylight Savings Time) Savings_UK.adjustDaylightSavings(StringToTime(Evalues[i].EventDate)), //-- Economic EventDate adjusted for US DST(Daylight Savings Time) Savings_US.adjustDaylightSavings(StringToTime(Evalues[i].EventDate)), //-- Economic EventDate adjusted for AU DST(Daylight Savings Time) Savings_AU.adjustDaylightSavings(StringToTime(Evalues[i].EventDate)), Evalues[i].EventDate//normal Economic EventDate );//Inserting all the columns for each event record if(!DatabaseExecute(db,request_insert_into_time)) { Print(GetLastError()); //-- Will print the sql query to check for any errors or possible defaults in the query/request Print(request_insert_into_time); return false;//Will end the loop and return false, as values failed to be inserted into the table } } else { Print(GetLastError()); //-- Will print the sql query to check for any errors or possible defaults in the query/request Print(request_insert_into_calendar); return false;//Will end the loop and return false, as values failed to be inserted into the table } } return true;//Will return true, all values were inserted into the table successfully } //+------------------------------------------------------------------+ //|Creates a table to store the record of when last the Calendar | //|database was updated/created | //+------------------------------------------------------------------+ void CNews::CreateRecordTable(int db) { bool failed=false; if(!DatabaseTableExists(db,CalendarStruct(Record_Table).name))//Checks if the table 'Record' exists in the databse 'Calendar' { //--- create the table if(!DatabaseExecute(db,CalendarStruct(Record_Table).sql))//Will attempt to create the table 'Record' { Print("DB: create the Records table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return;//Exits the function if creating the table failed } else//If Table was created Successfully then Create Trigger { DatabaseExecute(db,CalendarStruct(Record_Trigger).sql); } } else { DatabaseExecute(db,CalendarStruct(Record_Trigger).sql); } //Sql query/request to insert the current time into the 'Date' column in the table 'Record' string request_text=StringFormat(CalendarStruct(Record_Table).insert,TimeToString(TimeTradeServer())); if(!DatabaseExecute(db, request_text))//Will attempt to run this sql request/query { Print(GetLastError()); PrintFormat(CalendarStruct(Record_Table).insert,TimeToString(TimeTradeServer())); failed=true;//assign true if the request failed } if(failed) { //--- roll back all transactions and unlock the database DatabaseTransactionRollback(db); PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError()); } } //+------------------------------------------------------------------+ //|Function for creating and inserting Recommend DST for the Broker | //|into a table | //+------------------------------------------------------------------+ void CNews::CreateAutoDST(int db) { bool failed=false;//boolean variable if(!AutoDetectDST(DSTType))//Check if AutoDetectDST went through all the right procedures { return;//will terminate execution of the rest of the code below } if(!DatabaseTableExists(db,CalendarStruct(AutoDST_Table).name))//Checks if the table 'AutoDST' exists in the databse 'Calendar' { //--- create the table AutoDST if(!DatabaseExecute(db,CalendarStruct(AutoDST_Table).sql))//Will attempt to create the table 'AutoDST' { Print("DB: create the AutoDST table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return;//Exits the function if creating the table failed } else//If Table was created Successfully then Create Trigger { DatabaseExecute(db,CalendarStruct(AutoDST_Trigger).sql); } } else { //Create trigger if AutoDST table exists DatabaseExecute(db,CalendarStruct(AutoDST_Trigger).sql); } //Sql query/request to insert the recommend DST for the Broker using the DSTType variable to determine which string data to insert string request_text=StringFormat(CalendarStruct(AutoDST_Table).insert,EnumToString(DSTType)); if(!DatabaseExecute(db, request_text))//Will attempt to run this sql request/query { Print(GetLastError()); PrintFormat(CalendarStruct(AutoDST_Table).insert,EnumToString(DSTType));//Will print the sql query if failed failed=true;//assign true if the request failed } if(failed) { //--- roll back all transactions and unlock the database DatabaseTransactionRollback(db); PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError()); } } //+------------------------------------------------------------------+ //|Gets the latest/newest date in the Calendar database | //+------------------------------------------------------------------+ datetime CNews::GetLatestNewsDate() { //--- open the database 'Calendar' in the common folder int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READONLY|DATABASE_OPEN_COMMON); if(db==INVALID_HANDLE)//Checks if 'Calendar' failed to be opened { if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if 'Calendar' database exists { Print("Could not find Database!"); return 0;//Will return the earliest date which is 1970.01.01 00:00:00 } } string latest_record="1970.01.01";//string variable with the first/earliest possible date in MQL5 //Sql query to determine the lastest or maximum recorded time from which the database was updated. string request_text="SELECT REPLACE(Date,'-','.') FROM 'Record'"; int request=DatabasePrepare(db,request_text); if(request==INVALID_HANDLE) { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); DatabaseClose(db);//Close Database return 0; } if(DatabaseRead(request))//Will read the one record in the 'Record' table { //-- Will assign the first column(column 0) value to the variable 'latest_record' if(!DatabaseColumnText(request,0,latest_record)) { Print("DatabaseRead() failed with code ", GetLastError()); DatabaseFinalize(request);//Finalize request DatabaseClose(db);//Closes the database 'Calendar' return D'1970.01.01';//Will end the for loop and will return the earliest date which is 1970.01.01 00:00:00 } } DatabaseFinalize(request); DatabaseClose(db);//Closes the database 'Calendar' return (datetime)latest_record;//Returns the string latest_record converted to datetime } //+------------------------------------------------------------------+ //|Function will determine Broker DST | //+------------------------------------------------------------------+ bool CNews::AutoDetectDST(DST_type &dstType) { MqlCalendarValue values[];//Single array of MqlCalendarValue type string eventtime[];//Single string array variable to store NFP(Nonfarm Payrolls) dates for the 'United States' from the previous year //-- Will store the previous year into an integer int lastyear = Time.ReturnYear(Time.TimeMinusOffset(iTime(Symbol(),PERIOD_CURRENT,0),Time.YearsS())); //-- Will store the start date for the previous year datetime lastyearstart = StringToTime(StringFormat("%s.01.01 00:00:00",(string)lastyear)); //-- Will store the end date for the previous year datetime lastyearend = StringToTime(StringFormat("%s.12.31 23:59:59",(string)lastyear)); //-- Getting last year's calendar values for CountryCode = 'US' if(CalendarValueHistory(values,lastyearstart,lastyearend,"US")) { for(int x=0; x<(int)ArraySize(values); x++) { if(values[x].event_id==840030016)//Get only NFP Event Dates { ArrayResize(eventtime,eventtime.Size()+1,eventtime.Size()+2);//Increasing the size of eventtime array by 1 eventtime[eventtime.Size()-1] = TimeToString(values[x].time);//Storing the dates in an array of type string } } } //-- datetime variables to store the broker's timezone shift(change) datetime ShiftStart=D'1970.01.01 00:00:00',ShiftEnd=D'1970.01.01 00:00:00'; string EURUSD="";//String variables declarations for working with EURUSD bool EurusdIsFound=false;//Boolean variables declarations for working with EURUSD for(int i=0;i<SymbolsTotal(true);i++)//Will loop through all the Symbols inside the Market Watch { string SymName = SymbolName(i,true);//Assign the Symbol Name of index 'i' from the list of Symbols inside the Market Watch //-- Check if the Symbol outside the Market Watch has a SYMBOL_CURRENCY_BASE of EUR //-- and a SYMBOL_CURRENCY_PROFIT of USD, and this Symbol is not a Custom Symbol(Is not from the broker) if(((CurrencyBase(SymName)=="EUR"&&CurrencyProfit(SymName)=="USD")|| (StringFind(SymName,"EUR")>-1&&CurrencyProfit(SymName)=="USD"))&&!Custom(SymName)) { EURUSD = SymName;//Assigning the name of the EURUSD Symbol found inside the Market Watch EurusdIsFound = true;//EURUSD Symbol was found in the Trading Terminal for your Broker break;//Will end the for loop } } if(!EurusdIsFound)//Check if EURUSD Symbol was already Found in the Market Watch { for(int i=0; i<SymbolsTotal(false); i++)//Will loop through all the available Symbols outside the Market Watch { string SymName = SymbolName(i,false);//Assign the Symbol Name of index 'i' from the list of Symbols outside the Market Watch //-- Check if the Symbol outside the Market Watch has a SYMBOL_CURRENCY_BASE of EUR //-- and a SYMBOL_CURRENCY_PROFIT of USD, and this Symbol is not a Custom Symbol(Is not from the broker) if(((CurrencyBase(SymName)=="EUR"&&CurrencyProfit(SymName)=="USD")|| (StringFind(SymName,"EUR")>-1&&CurrencyProfit(SymName)=="USD"))&&!Custom(SymName)) { EURUSD = SymName;//Assigning the name of the EURUSD Symbol found outside the Market Watch EurusdIsFound = true;//EURUSD Symbol was found in the Trading Terminal for your Broker break;//Will end the for loop } } } if(!EurusdIsFound)//Check if EURUSD Symbol was Found in the Trading Terminal for your Broker { Print("Cannot Find EURUSD!"); Print("Cannot Create Database!"); Print("Server DST Cannot be Detected!"); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } struct DST { bool result; datetime date; } previousresult,currentresult; bool timeIsShifted;//Boolean variable declaration will be used to determine if the broker changes it's timezone for(uint i=0;i<eventtime.Size();i++) { //-- Store the result of if the eventdate is the larger candlestick currentresult.result = IsLargerThanPreviousAndNext((datetime)eventtime[i],Time.HoursS(),EURUSD); currentresult.date = (datetime)eventtime[i];//Store the eventdate from eventtime[i] //-- Check if there is a difference between the previous result and the current result timeIsShifted = ((currentresult.result!=previousresult.result&&i>0)?true:false); //-- Check if the Larger candle has shifted from the previous event date to the current event date in eventtime[i] array if(timeIsShifted) { if(ShiftStart==D'1970.01.01 00:00:00')//Check if the ShiftStart variable has not been assigned a relevant value yet { ShiftStart=currentresult.date;//Store the eventdate for when the timeshift began } ShiftEnd=previousresult.date;//Store the eventdate timeshift } previousresult.result = currentresult.result;//Store the previous result of if the eventdate is the larger candlestick previousresult.date = currentresult.date;//Store the eventdate from eventtime[i] } //-- Check if the ShiftStart variable has not been assigned a relevant value and the eventdates are more than zero if(ShiftStart==D'1970.01.01 00:00:00'&&eventtime.Size()>0) { Print("Broker ServerTime unchanged!"); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } datetime DaylightStart,DaylightEnd;//Datetime variables declarations for start and end dates for DaylightSavings if(Savings_AU.DaylightSavings(lastyear,DaylightStart,DaylightEnd)) { if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd)) { Print("Broker ServerTime Adjusted For AU DST"); dstType = DST_AU;//Assigning enumeration value AU_DST, Broker has AU DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } } else { Print("Something went wrong!"); Print("Cannot Find Daylight-Savings Date For AU"); Print("Year: %d Cannot Be Found!",lastyear); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } if(Savings_UK.DaylightSavings(lastyear,DaylightStart,DaylightEnd)) { if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd)) { Print("Broker ServerTime Adjusted For UK DST"); dstType = DST_UK;//Assigning enumeration value UK_DST, Broker has UK/EU DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } } else { Print("Something went wrong!"); Print("Cannot Find Daylight-Savings Date For UK"); Print("Year: %d Cannot Be Found!",lastyear); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } if(Savings_US.DaylightSavings(lastyear,DaylightStart,DaylightEnd)) { if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd)) { Print("Broker ServerTime Adjusted For US DST"); dstType = DST_US;//Assigning enumeration value US_DST, Broker has US DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } } else { Print("Something went wrong!"); Print("Cannot Find Daylight-Savings Date For US"); Print("Year: %d Cannot Be Found!",lastyear); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } Print("Cannot Detect Broker ServerTime Configuration!"); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } //+------------------------------------------------------------------+
Wir werden jeder Komponente in unserem gewünschten Datenbankdesign einen Enumerationswert geben, als eine Form der Identität.
enum CalendarComponents { AutoDST_Table,//AutoDST Table CalendarAU_View,//View for DST_AU CalendarNONE_View,//View for DST_NONE CalendarUK_View,//View for DST_UK CalendarUS_View,//View for DST_US Record_Table,// Record Table TimeSchedule_Table,//TimeSchedule Table MQL5Calendar_Table,//MQL5Calendar Table AutoDST_Trigger,//Table Trigger for AutoDST Record_Trigger//Table Trigger for Record };
Die Struktur SQLiteMaster dient dazu, die Eigenschaften des aktuellen Datenbankobjekts wie Typ, Name usw. zu speichern. So können wir alle Objekte im Array DBContents kontrollieren.
//-- structure to retrieve all the objects in the database struct SQLiteMaster { string type;//will store object type string name;//will store object's name string tbl_name;//will store table name int rootpage;//will store rootpage string sql;//Will store the sql create statement } DBContents[];//Array of type SQLiteMaster
In der Struktur MQL5CalendarContents werden wir eine zusätzliche Eigenschaft speichern, nämlich die Variablen Content und Insert.
Unsere String-Variable insert wird die SQL-Einfügeanweisungen für unsere SQL-Objekte speichern. Die Variable CalendarComponents Content speichert den Enumerationswert für unser SQL-Objekt als Identitätsmerkmal, sodass wir wissen, um welches SQL-Objekt es sich handelt, sobald alle Objekteigenschaften im Array der Struktur CalendarContents gespeichert sind.
//-- MQL5CalendarContents inherits from SQLiteMaster structure struct MQL5CalendarContents:SQLiteMaster { CalendarComponents Content; string insert;//Will store the sql insert statement } CalendarContents[10];//Array to Store objects in our database
Die Funktion CalendarStruct gibt den Wert der Struktur MQL5CalendarContents zurück, wenn der Parameter Content gleich dem Aufzählungswert in der Variablen Content in der Array-Struktur CalendarContents ist.
//-- Function for retrieving the MQL5CalendarContents structure for the enumartion type CalendarComponents MQL5CalendarContents CalendarStruct(CalendarComponents Content) { MQL5CalendarContents Calendar; for(uint i=0;i<CalendarContents.Size();i++) { if(CalendarContents[i].Content==Content) { return CalendarContents[i]; } } return Calendar; }
Die String-Variable DropRequest ist für das Löschen von Datenbankobjekten zuständig, die wir nicht mehr benötigen oder wollen. In der SQL-Abfrage verwenden wir die PRAGMA-Anweisungen.
Was ist eine PRAGMA-Anweisung?
Eine PRAGMA-Anweisung in SQLite ist ein spezieller Befehl, der verwendet wird, um die Funktionsweise der SQLite-Bibliothek zu ändern oder den internen Zustand der Datenbank-Engine abzufragen. PRAGMAs sind nicht Teil des Standard-SQL, sondern sind spezifisch für SQLite. Sie bieten die Möglichkeit, verschiedene Umgebungseinstellungen und das Verhalten der Datenbank zu steuern.
Welchen Zweck erfüllen die PRAGMA-Anweisungen?
- Konfiguration: Mit PRAGMA-Anweisungen können Sie die Datenbankumgebung konfigurieren, z. B. Fremdschlüssel-Beschränkungen aktivieren oder deaktivieren, den Journalmodus einstellen oder die Parameter für die Speichernutzung anpassen.
- Diagnostik: Sie können verwendet werden, um Informationen über die Datenbank abzurufen, z. B. um die Integrität der Datenbank zu prüfen, die aktuellen Einstellungen abzurufen oder den Status der SQLite-Engine anzuzeigen.
- Optimization: PRAGMAs helfen bei der Optimierung der Datenbankleistung durch die Einstellung von Parametern wie Cache-Größe, Sperrmodus und synchrone Einstellungen.
- Maintenance: Sie sind nützlich für Wartungsaufgaben wie den Neuaufbau von Indizes, die Analyse von Tabellen und die Verwaltung der Auto-Vakuum-Einstellung.
In unserer ersten PRAGMA-Anweisung deaktivieren wir alle Fremdschlüssel-Beschränkungen, die uns daran hindern würden, eine Tabelle mit Fremdschlüssel-Beschränkungen zu löschen.
In unserer zweiten PRAGMA-Anweisung aktivieren wir secure_delete, das steuert, ob gelöschte Inhalte vor dem Entfernen aus der Datenbankdatei gelöscht werden oder nicht. In diesem Fall überschreibt die Datenbank gelöschte Inhalte nur dann mit Nullen, wenn dies nicht zu einer Erhöhung der E/A-Menge führt.
In der dritten Anweisung wird das SQL-Objekt gelöscht, falls es existiert. Anschließend verwenden wir den Befehl Vacuum, der die Datenbankdatei neu erstellt und sie auf ein Minimum an Speicherplatz reduziert. Dieser Prozess kann dazu beitragen, die Leistung der Datenbank zu optimieren und ungenutzten Speicherplatz zurückzugewinnen.
Schließlich werden wir die Fremdschlüssel-Beschränkungen wieder aktivieren.
CNews::CNews(void):DropRequest("PRAGMA foreign_keys = OFF; " "PRAGMA secure_delete = ON; " "Drop %s IF EXISTS %s; " "Vacuum; " "PRAGMA foreign_keys = ON;")//Sql drop statement
Wir werden die Eigenschaften für unsere AutoDST-Tabelle im ersten Index des CalendarContents-Arrays speichern. Hier weisen wir in der Variable Content einen Enumerationswert von AutoDST_Table zu.
Wir weisen dann den Namen, den Tabellennamen, den Typ und die Einfügeanweisung zu. In der SQL-Anweisung zur Erstellung der Tabelle geben wir der Spalte „DST“ den Standardwert „DST_NONE“ und beenden die Anweisung mit dem Schlüsselwort „STRICT“.
Das Schlüsselwort STRICT erzwingt, dass die in eine Spalte eingefügten Daten dem deklarierten Typ dieser Spalte entsprechen müssen. Dies sorgt für mehr Vorhersehbarkeit und Konsistenz bei der Art der gespeicherten Daten.
Ohne das Schlüsselwort STRICT kann praktisch jeder Datentyp in die Tabelle eingefügt werden, und der Datentyp der deklarierten Spalte wird eher als Empfehlung denn als Anforderung behandelt.
//-- initializing properties for the AutoDST table CalendarContents[0].Content = AutoDST_Table; CalendarContents[0].name = "AutoDST"; CalendarContents[0].sql = "CREATE TABLE AutoDST(DST TEXT NOT NULL DEFAULT 'DST_NONE')STRICT;"; CalendarContents[0].tbl_name = "AutoDST"; CalendarContents[0].type = "table"; CalendarContents[0].insert = "INSERT INTO 'AutoDST'(DST) VALUES ('%s');";
Wir werden nun die Eigenschaften der Kalenderansichten für UK, US, AU und NONE initialisieren.
In der Variable view_sql speichern wir unsere SQL-Anweisung zur Erstellung der einzelnen Ansichten. In unserer SQL-Anweisung wählen wir Eventid, Eventname, Country, EventCurrency und Eventcode aus der Tabelle MQL5Calendar aus.
ID EVENTID COUNTRY EVENTNAME EVENTTYPE EVENTIMPORTANCE EVENTCURRENCY EVENTCODE EVENTSECTOR EVENTFORECAST EVENTPREVALUE EVENTIMPACT EVENTFREQUENCY 18742 999020002 European Union Eurogroup Meeting CALENDAR_TYPE_EVENT CALENDAR_IMPORTANCE_MODERATE EUR EU CALENDAR_SECTOR_GOVERNMENT None None CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 18746 999010020 European Union ECB Executive Board Member Lane Speech CALENDAR_TYPE_EVENT CALENDAR_IMPORTANCE_MODERATE EUR EU CALENDAR_SECTOR_MONEY None None CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 34896 392010004 Japan Coincident Index CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW JPY JP CALENDAR_SECTOR_BUSINESS 113900000 113900000 CALENDAR_IMPACT_NEGATIVE CALENDAR_FREQUENCY_MONTH 34897 392010005 Japan Leading Index CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW JPY JP CALENDAR_SECTOR_BUSINESS 111400000 111400000 CALENDAR_IMPACT_POSITIVE CALENDAR_FREQUENCY_MONTH 34898 392010011 Japan Coincident Index m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW JPY JP CALENDAR_SECTOR_BUSINESS None 2400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 34899 392010012 Japan Leading Index m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW JPY JP CALENDAR_SECTOR_BUSINESS None -700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 55462 156010014 China Industrial Profit YTD y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW CNY CN CALENDAR_SECTOR_BUSINESS None 4300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 72568 276030001 Germany Ifo Business Expectations CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE EUR DE CALENDAR_SECTOR_BUSINESS 92000000 89900000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 72569 276030002 Germany Ifo Current Business Situation CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE EUR DE CALENDAR_SECTOR_BUSINESS 88800000 88900000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 72570 276030003 Germany Ifo Business Climate CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_HIGH EUR DE CALENDAR_SECTOR_BUSINESS 89900000 89400000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 72571 276050007 Germany Bbk Executive Board Member Mauderer Speech CALENDAR_TYPE_EVENT CALENDAR_IMPORTANCE_MODERATE EUR DE CALENDAR_SECTOR_MONEY None None CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 78850 250020001 France 3-Month BTF Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW EUR FR CALENDAR_SECTOR_MARKET None 3746000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 78851 250020002 France 6-Month BTF Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW EUR FR CALENDAR_SECTOR_MARKET None 3657000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 78852 250020003 France 12-Month BTF Auction CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW EUR FR CALENDAR_SECTOR_MARKET None 3467000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 84771 76020007 Brazil BCB Bank Lending m/m CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW BRL BR CALENDAR_SECTOR_MONEY 400000 1200000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 84772 76020001 Brazil BCB Focus Market Report CALENDAR_TYPE_EVENT CALENDAR_IMPORTANCE_MODERATE BRL BR CALENDAR_SECTOR_MONEY None None CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 94938 344020004 Hong Kong Exports y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW HKD HK CALENDAR_SECTOR_TRADE 18100000 4700000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 94939 344020005 Hong Kong Imports y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW HKD HK CALENDAR_SECTOR_TRADE 15000000 5300000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 94940 344020006 Hong Kong Trade Balance CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE HKD HK CALENDAR_SECTOR_TRADE -29054000 -45000000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 102731 578020001 Norway Unemployment Rate CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_MODERATE NOK NO CALENDAR_SECTOR_JOBS 3700000 4000000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 102732 578020020 Norway General Public Domestic Loan Debt y/y CALENDAR_TYPE_INDICATOR CALENDAR_IMPORTANCE_LOW NOK NO CALENDAR_SECTOR_MONEY 3300000 3500000 CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_MONTH 147163 840031004 United States Memorial Day CALENDAR_TYPE_HOLIDAY CALENDAR_IMPORTANCE_NONE USD US CALENDAR_SECTOR_HOLIDAYS None None CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE 162245 826090005 United Kingdom Spring Bank Holiday CALENDAR_TYPE_HOLIDAY CALENDAR_IMPORTANCE_NONE GBP GB CALENDAR_SECTOR_HOLIDAYS None None CALENDAR_IMPACT_NA CALENDAR_FREQUENCY_NONE
Anschließend wählen wir die Spalte DST für den entsprechenden Zeitplan aus TimeSchedule.
ID DST_UK DST_US DST_AU DST_NONE 18742 2024.05.27 02:00 2024.05.27 02:00 2024.05.27 02:00 2024.05.27 02:00 18746 2024.05.27 14:00 2024.05.27 14:00 2024.05.27 14:00 2024.05.27 14:00 34896 2024.05.27 07:00 2024.05.27 07:00 2024.05.27 07:00 2024.05.27 07:00 34897 2024.05.27 07:00 2024.05.27 07:00 2024.05.27 07:00 2024.05.27 07:00 34898 2024.05.27 07:00 2024.05.27 07:00 2024.05.27 07:00 2024.05.27 07:00 34899 2024.05.27 07:00 2024.05.27 07:00 2024.05.27 07:00 2024.05.27 07:00 55462 2024.05.27 03:30 2024.05.27 03:30 2024.05.27 03:30 2024.05.27 03:30 72568 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 72569 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 72570 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 72571 2024.05.27 15:30 2024.05.27 15:30 2024.05.27 15:30 2024.05.27 15:30 78850 2024.05.27 14:50 2024.05.27 14:50 2024.05.27 14:50 2024.05.27 14:50 78851 2024.05.27 14:50 2024.05.27 14:50 2024.05.27 14:50 2024.05.27 14:50 78852 2024.05.27 14:50 2024.05.27 14:50 2024.05.27 14:50 2024.05.27 14:50 84771 2024.05.27 13:30 2024.05.27 13:30 2024.05.27 13:30 2024.05.27 13:30 84772 2024.05.27 13:30 2024.05.27 13:30 2024.05.27 13:30 2024.05.27 13:30 94938 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 94939 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 94940 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 2024.05.27 10:30 102731 2024.05.27 08:00 2024.05.27 08:00 2024.05.27 08:00 2024.05.27 08:00 102732 2024.05.27 08:00 2024.05.27 08:00 2024.05.27 08:00 2024.05.27 08:00 147163 2024.05.27 02:00 2024.05.27 02:00 2024.05.27 02:00 2024.05.27 02:00 162245 2024.05.27 02:00 2024.05.27 02:00 2024.05.27 02:00 2024.05.27 02:00
Und verbinden Sie die beiden Tabellen MQL5Calendar und TimeSchedule mit der gleichen ID.
Wir filtern diese Liste nach dem Datum aus der Tabelle Datensatz.
Date 27-05-2024
Sobald wir die Ergebnisse der Abfrage erhalten haben, werden die Ergebnisse in aufsteigender Reihenfolge nach der jeweiligen Sommerzeit von TimeSchedule sortiert.
string views[] = {"UK","US","AU","NONE"}; string view_sql = "CREATE VIEW IF NOT EXISTS Calendar_%s " "AS " "SELECT C.Eventid,C.Eventname,C.Country,T.DST_%s as Time,C.EventCurrency,C.Eventcode from MQL5Calendar C,Record R " "Inner join TimeSchedule T on C.ID=T.ID " "Where DATE(REPLACE(T.DST_%s,'.','-'))=R.Date " "Order by T.DST_%s Asc;"; //-- Sql statements for creating the table views for(uint i=1;i<=views.Size();i++) { CalendarContents[i].Content = (CalendarComponents)i; CalendarContents[i].name = StringFormat("Calendar_%s",views[i-1]); CalendarContents[i].sql = StringFormat(view_sql,views[i-1],views[i-1],views[i-1],views[i-1]); CalendarContents[i].tbl_name = StringFormat("Calendar_%s",views[i-1]); CalendarContents[i].type = "view"; }
Schauen wir uns eine der „Views“ an und sehen, was das Abfrageergebnis ergibt:
SELECT * FROM 'Calendar_UK';
Ausgabe:
EVENTID EVENTNAME COUNTRY Time EVENTCURRENCY EVENTCODE 999020002 Eurogroup Meeting European Union 2024.05.27 02:00 EUR EU 840031004 Memorial Day United States 2024.05.27 02:00 USD US 826090005 Spring Bank Holiday United Kingdom 2024.05.27 02:00 GBP GB 156010014 Industrial Profit YTD y/y China 2024.05.27 03:30 CNY CN 392010004 Coincident Index Japan 2024.05.27 07:00 JPY JP 392010005 Leading Index Japan 2024.05.27 07:00 JPY JP 392010011 Coincident Index m/m Japan 2024.05.27 07:00 JPY JP 392010012 Leading Index m/m Japan 2024.05.27 07:00 JPY JP 578020001 Unemployment Rate Norway 2024.05.27 08:00 NOK NO 578020020 General Public Domestic Loan Debt y/y Norway 2024.05.27 08:00 NOK NO 276030001 Ifo Business Expectations Germany 2024.05.27 10:30 EUR DE 276030002 Ifo Current Business Situation Germany 2024.05.27 10:30 EUR DE 276030003 Ifo Business Climate Germany 2024.05.27 10:30 EUR DE 344020004 Exports y/y Hong Kong 2024.05.27 10:30 HKD HK 344020005 Imports y/y Hong Kong 2024.05.27 10:30 HKD HK 344020006 Trade Balance Hong Kong 2024.05.27 10:30 HKD HK 76020007 BCB Bank Lending m/m Brazil 2024.05.27 13:30 BRL BR 76020001 BCB Focus Market Report Brazil 2024.05.27 13:30 BRL BR 999010020 ECB Executive Board Member Lane Speech European Union 2024.05.27 14:00 EUR EU 250020001 3-Month BTF Auction France 2024.05.27 14:50 EUR FR 250020002 6-Month BTF Auction France 2024.05.27 14:50 EUR FR 250020003 12-Month BTF Auction France 2024.05.27 14:50 EUR FR 276050007 Bbk Executive Board Member Mauderer Speech Germany 2024.05.27 15:30 EUR DE
Technisch gesehen haben wir eine neue Tabelle mit dem Namen Record. Diese Tabelle wird unsere vorherige Tabelle Records ersetzen, da wir jetzt nur noch einen Datensatz speichern werden. Unsere Tabelle wird den Datentyp TEXT und den Spaltennamen „Date“ haben, der nicht mit der Funktion Date in SQLite verwechselt werden sollte.
//-- initializing properties for the Record table CalendarContents[5].Content = Record_Table; CalendarContents[5].name = "Record"; CalendarContents[5].sql = "CREATE TABLE Record(Date TEXT NOT NULL)STRICT;"; CalendarContents[5].tbl_name="Record"; CalendarContents[5].type = "table"; CalendarContents[5].insert = "INSERT INTO 'Record'(Date) VALUES (Date(REPLACE('%s','.','-')));";
Unsere TimeSchedule-Tabelle speichert alle Zeitdaten der einzelnen Ereignisse und verwendet den Fremdschlüssel „ID“, um die Tabelle mit der MQL5Calendar-Tabelle zu verknüpfen (eine Beziehung zu erstellen).
//-- initializing properties for the TimeSchedule table CalendarContents[6].Content = TimeSchedule_Table; CalendarContents[6].name = "TimeSchedule"; CalendarContents[6].sql = "CREATE TABLE TimeSchedule(ID INT NOT NULL,DST_UK TEXT NOT NULL,DST_US TEXT NOT NULL," "DST_AU TEXT NOT NULL,DST_NONE TEXT NOT NULL,FOREIGN KEY (ID) REFERENCES MQL5Calendar (ID))STRICT;"; CalendarContents[6].tbl_name="TimeSchedule"; CalendarContents[6].type = "table"; CalendarContents[6].insert = "INSERT INTO 'TimeSchedule'(ID,DST_UK,DST_US,DST_AU,DST_NONE) " "VALUES (%d,'%s','%s', '%s', '%s');";
Die Tabelle MQL5Calendar hat einen Primärschlüssel namens „ID“, der für jeden Datensatz eines Nachrichtenereignisses in der Tabelle eindeutig ist.
//-- initializing properties for the MQL5Calendar table CalendarContents[7].Content = MQL5Calendar_Table; CalendarContents[7].name = "MQL5Calendar"; CalendarContents[7].sql = "CREATE TABLE MQL5Calendar(ID INT NOT NULL,EVENTID INT NOT NULL,COUNTRY TEXT NOT NULL," "EVENTNAME TEXT NOT NULL,EVENTTYPE TEXT NOT NULL,EVENTIMPORTANCE TEXT NOT NULL," "EVENTCURRENCY TEXT NOT NULL,EVENTCODE TEXT NOT NULL,EVENTSECTOR TEXT NOT NULL," "EVENTFORECAST TEXT NOT NULL,EVENTPREVALUE TEXT NOT NULL,EVENTIMPACT TEXT NOT NULL," "EVENTFREQUENCY TEXT NOT NULL,PRIMARY KEY(ID))STRICT;"; CalendarContents[7].tbl_name="MQL5Calendar"; CalendarContents[7].type = "table"; CalendarContents[7].insert = "INSERT INTO 'MQL5Calendar'(ID,EVENTID,COUNTRY,EVENTNAME,EVENTTYPE,EVENTIMPORTANCE,EVENTCURRENCY,EVENTCODE," "EVENTSECTOR,EVENTFORECAST,EVENTPREVALUE,EVENTIMPACT,EVENTFREQUENCY) " "VALUES (%d,%d,'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s');";
Wir erstellen einen Trigger namens OnlyOne_AutoDST. Der Trigger wird ausgelöst, wenn wir versuchen, einen Wert in die AutoDST einzufügen und alle Datensätze aus der AutoDST zu löschen , bevor wir einen neuen Datensatz einfügen.
//-- Sql statement for creating the AutoDST table's trigger CalendarContents[8].Content = AutoDST_Trigger; CalendarContents[8].name = "OnlyOne_AutoDST"; CalendarContents[8].sql = "CREATE TRIGGER IF NOT EXISTS OnlyOne_AutoDST " "BEFORE INSERT ON AutoDST " "BEGIN " "Delete from AutoDST; " "END;"; CalendarContents[8].tbl_name="AutoDST"; CalendarContents[8].type = "trigger";
Dasselbe gilt für OnlyOne_Record, aber dieser Trigger bezieht sich auf die Tabelle Record.
//-- Sql statement for creating the Record table's trigger CalendarContents[9].Content = Record_Trigger; CalendarContents[9].name = "OnlyOne_Record"; CalendarContents[9].sql = "CREATE TRIGGER IF NOT EXISTS OnlyOne_Record " "BEFORE INSERT ON Record " "BEGIN " "Delete from Record; " "END;"; CalendarContents[9].tbl_name="Record"; CalendarContents[9].type = "trigger";
In unserer Funktion UpdateRecords werden wir nun feststellen, ob unsere Kalenderdatenbank eine Aktualisierung benötigt.
Die Änderungen dieser Funktion gegenüber der vorherigen in Teil 1 sind folgende:
1. Wir lesen alle Objekte, die keine Indizes in der Datenbank sind, mit der SQL-Abfrage „select * from sqlite_master where type<>'index';“.
2. Wir speichern alle Attribute des Objekts im Array DBContents, und wenn am Ende der SQL-Anweisung kein Semikolon vorhanden ist, fügen wir eines hinzu.
3. Wir werden die in unserer Datenbank gefundenen Objekte mit den Objekten vergleichen, die wir in unserem Array CalendarContents initialisieren. Wir werden „IF NOT EXISTS“ aus der CalendarContents sql entfernen.
4. Wenn wir keine Übereinstimmung zwischen DBContents und CalendarContents finden, werden wir das Objekt im DBcontents-Index löschen.
5. Wenn die Übereinstimmungen des SQL-Objekts nicht mit der Größe von CalendarContents übereinstimmen, wird eine Aktualisierung durchgeführt.
bool CNews::UpdateRecords() { //initialize variable to true bool perform_update=true; //--- open/create //-- try to open database Calendar int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE| DATABASE_OPEN_COMMON); if(db==INVALID_HANDLE)//Checks if the database was able to be opened { //if opening the database failed if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if the database Calendar exists in the common folder { return perform_update;//Returns true when the database was failed to be opened and the file doesn't exist in the common folder } } int MasterRequest = DatabasePrepare(db,"select * from sqlite_master where type<>'index';"); if(MasterRequest==INVALID_HANDLE) { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); } else { SQLiteMaster ReadContents; //Assigning values from the sql query into DBContents array for(int i=0; DatabaseReadBind(MasterRequest,ReadContents); i++) { ArrayResize(DBContents,i+1,i+2); DBContents[i].type = ReadContents.type; DBContents[i].name = ReadContents.name; DBContents[i].tbl_name = ReadContents.tbl_name; DBContents[i].rootpage = ReadContents.rootpage; /*Check if the end of the sql string has a character ';' if not add this character to the string*/ DBContents[i].sql = (StringFind(ReadContents.sql,";",StringLen(ReadContents.sql)-1)== (StringLen(ReadContents.sql)-1))?ReadContents.sql:ReadContents.sql+";";; } uint contents_exists = 0; for(uint i=0;i<DBContents.Size();i++) { bool isCalendarContents = false; for(uint x=0;x<CalendarContents.Size();x++) { /*Store Sql query from CalendarContents without string ' IF NOT EXISTS'*/ string CalendarSql=CalendarContents[x].sql; StringReplace(CalendarSql," IF NOT EXISTS",""); //-- Check if the Db object is in our list if(DBContents[i].name==CalendarContents[x].name&& (DBContents[i].sql==CalendarSql|| DBContents[i].sql==CalendarContents[x].sql)&& CalendarContents[x].type==DBContents[i].type&& CalendarContents[x].tbl_name==DBContents[i].tbl_name) { contents_exists++; isCalendarContents = true; } } if(!isCalendarContents) { //-- Print DBcontent's name if it does not match with CalendarContents PrintFormat("DBContent: %s is not needed!",DBContents[i].name); //-- We will drop the table if it is not neccessary DatabaseExecute(db,StringFormat(DropRequest,DBContents[i].type,DBContents[i].name)); Print("Attempting To Clean Database..."); } } /*If not all the CalendarContents exist in the Calendar Database before an update */ if(contents_exists!=CalendarContents.Size()) { return perform_update; } } if(!DatabaseTableExists(db,CalendarStruct(Record_Table).name))//If the database table 'Record' doesn't exist { DatabaseClose(db); return perform_update; } //-- Sql query to determine the lastest or maximum date recorded /* If the last recorded date data in the 'Record' table is not equal to the current day, perform an update! */ string request_text=StringFormat("SELECT Date FROM %s where Date=Date(REPLACE('%s','.','-'))", CalendarStruct(Record_Table).name,TimeToString(TimeTradeServer())); int request=DatabasePrepare(db,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); DatabaseClose(db); return perform_update; } if(DatabaseRead(request))//Will be true if there are results from the sql query/request { DatabaseFinalize(request);//Removes a request created in DatabasePrepare() DatabaseClose(db);//Closes the database perform_update=false; return perform_update; } else { DatabaseFinalize(request);//Removes a request created in DatabasePrepare() DatabaseClose(db);//Closes the database return perform_update; } }
In der Funktion CreateCalendarTable wird geprüft, ob die Tabelle MQL5Calendar bereits in der Kalenderdatenbank vorhanden ist. Außerdem wird geprüft, ob die Tabelle TimeSchedule bereits vorhanden ist und versucht, jede Tabelle zu löschen, wenn sie vorhanden ist. Da TimeSchedule MQL5Calendar benötigt, können wir MQL5Calendar nicht löschen, ohne TimeSchedule vorher zu löschen.
Sobald MQL5Calendar nicht existiert, erstellen wir seine Tabelle.
bool CNews::CreateCalendarTable(int db,bool &tableExists) { //-- Checks if a table 'MQL5Calendar' exists if(DatabaseTableExists(db,CalendarStruct(MQL5Calendar_Table).name)) { tableExists=true;//Assigns true to tableExists variable //-- Checks if a table 'TimeSchedule' exists in the database 'Calendar' if(DatabaseTableExists(db,CalendarStruct(TimeSchedule_Table).name)) { //-- We will drop the table if the table already exists if(!DatabaseExecute(db,StringFormat("Drop Table %s",CalendarStruct(TimeSchedule_Table).name))) { //If the table failed to be dropped/deleted PrintFormat("Failed to drop table %s with code %d",CalendarStruct(TimeSchedule_Table).name,GetLastError()); DatabaseClose(db);//Close the database return false;//will terminate execution of the rest of the code below and return false, when the table cannot be dropped } } //--We will drop the table if the table already exists if(!DatabaseExecute(db,StringFormat("Drop Table %s",CalendarStruct(MQL5Calendar_Table).name))) { //If the table failed to be dropped/deleted PrintFormat("Failed to drop table %s with code %d",CalendarStruct(MQL5Calendar_Table).name,GetLastError()); DatabaseClose(db);//Close the database return false;//will terminate execution of the rest of the code below and return false, when the table cannot be dropped } } //-- If the database table 'MQL5Calendar' doesn't exist if(!DatabaseTableExists(db,CalendarStruct(MQL5Calendar_Table).name)) { //--- create the table 'MQL5Calendar' if(!DatabaseExecute(db,CalendarStruct(MQL5Calendar_Table).sql))//Checks if the table was successfully created { Print("DB: create the Calendar table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return false;//Function returns false if creating the table failed } } return true;//Function returns true if creating the table was successful }
In der Funktion CreateTimeTable wird überprüft, ob die Tabelle in der Kalenderdatenbank vorhanden ist, wenn nicht, wird sie erstellt.
bool CNews::CreateTimeTable(int db,bool &tableExists) { //-- If the database table 'TimeSchedule' doesn't exist if(!DatabaseTableExists(db,CalendarStruct(TimeSchedule_Table).name)) { //--- create the table 'TimeSchedule' if(!DatabaseExecute(db,CalendarStruct(TimeSchedule_Table).sql))//Checks if the table was successfully created { Print("DB: create the Calendar table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return false;//Function returns false if creating the table failed } } return true;//Function returns true if creating the table was successful }
In der Funktion CreateCalendarViews erstellen wir alle Ansichten, indem wir CalendarComponents verwenden, um die Identität (Aufzählungswert) für jede Ansicht zu finden und sie zu erstellen.
void CNews::CreateCalendarViews(int db) { for(uint i=1;i<=4;i++) { if(!DatabaseExecute(db,CalendarStruct((CalendarComponents)i).sql))//Checks if the view was successfully created { Print("DB: create the Calendar view failed with code ", GetLastError()); } } }
In der Funktion InsertIntoTables fügen wir jeden Datensatz aus dem Evalues-Array in die MQL5Calendar-Tabelle bzw. die TimeSchedule-Tabelle ein. Die Veranstaltungstermine werden an die verschiedenen Sommerzeitpläne in TimeSchedule angepasst.
bool CNews::InsertIntoTables(int db,Calendar &Evalues[]) { for(uint i=0; i<Evalues.Size(); i++)//Looping through all the Economic Events { string request_insert_into_calendar = StringFormat(CalendarStruct(MQL5Calendar_Table).insert, i, Evalues[i].EventId, Evalues[i].CountryName, Evalues[i].EventName, Evalues[i].EventType, Evalues[i].EventImportance, Evalues[i].EventCurrency, Evalues[i].EventCode, Evalues[i].EventSector, Evalues[i].EventForecast, Evalues[i].EventPreval, Evalues[i].EventImpact, Evalues[i].EventFrequency);//Inserting all the columns for each event record if(DatabaseExecute(db,request_insert_into_calendar))//Check if insert query into calendar was successful { string request_insert_into_time = StringFormat(CalendarStruct(TimeSchedule_Table).insert, i, //-- Economic EventDate adjusted for UK DST(Daylight Savings Time) Savings_UK.adjustDaylightSavings(StringToTime(Evalues[i].EventDate)), //-- Economic EventDate adjusted for US DST(Daylight Savings Time) Savings_US.adjustDaylightSavings(StringToTime(Evalues[i].EventDate)), //-- Economic EventDate adjusted for AU DST(Daylight Savings Time) Savings_AU.adjustDaylightSavings(StringToTime(Evalues[i].EventDate)), Evalues[i].EventDate//normal Economic EventDate );//Inserting all the columns for each event record if(!DatabaseExecute(db,request_insert_into_time)) { Print(GetLastError()); //-- Will print the sql query to check for any errors or possible defaults in the query/request Print(request_insert_into_time); return false;//Will end the loop and return false, as values failed to be inserted into the table } } else { Print(GetLastError()); //-- Will print the sql query to check for any errors or possible defaults in the query/request Print(request_insert_into_calendar); return false;//Will end the loop and return false, as values failed to be inserted into the table } } return true;//Will return true, all values were inserted into the table successfully }
In der Funktion CreateRecordTable wird geprüft, ob die Tabelle Record bereits existiert, wenn nicht, wird die Tabelle erstellt. Sobald die Datensatztabelle existiert, erstellen wir den Trigger für sie. Geben Sie dann das Datum des aktuellen Servers ein.
Warum TimeTradeServer anstelle von TimeCurrent verwenden?
Wenn wir TimeCurrent verwenden, erhalten wir die Zeitdaten für das aktuelle Chartsymbol und die Symbolzeiten können voneinander abweichen, da die Zeitdaten bei jedem neuen Tick aktualisiert werden. Dies ist potenziell problematisch, wenn die Symbole nicht dieselben Handelszeiten haben und wenn das aktuelle Chartsymbol geschlossen sein könnte, was bedeutet, dass keine neuen Ticks empfangen werden, weshalb TimeCurrent ein Datum zurückgeben könnte, das einen Tag oder mehr hinter dem tatsächlichen Datum liegt. TimeTradeServer hingegen wird unabhängig von der Art des Symbols ständig aktualisiert.
void CNews::CreateRecordTable(int db) { bool failed=false; if(!DatabaseTableExists(db,CalendarStruct(Record_Table).name))//Checks if the table 'Record' exists in the databse 'Calendar' { //--- create the table if(!DatabaseExecute(db,CalendarStruct(Record_Table).sql))//Will attempt to create the table 'Record' { Print("DB: create the Records table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return;//Exits the function if creating the table failed } else//If Table was created Successfully then Create Trigger { DatabaseExecute(db,CalendarStruct(Record_Trigger).sql); } } else { DatabaseExecute(db,CalendarStruct(Record_Trigger).sql); } //Sql query/request to insert the current time into the 'Date' column in the table 'Record' string request_text=StringFormat(CalendarStruct(Record_Table).insert,TimeToString(TimeTradeServer())); if(!DatabaseExecute(db, request_text))//Will attempt to run this sql request/query { Print(GetLastError()); PrintFormat(CalendarStruct(Record_Table).insert,TimeToString(TimeTradeServer())); failed=true;//assign true if the request failed } if(failed) { //--- roll back all transactions and unlock the database DatabaseTransactionRollback(db); PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError()); } }In der Funktion CreateAutoDST prüfen wir den Sommerzeitplan des Brokers. Wenn wir den Sommerzeitplan erfolgreich erhalten haben, prüfen wir, ob die AutoDST-Tabelle in der Kalenderdatenbank existiert. Wenn die AutoDST-Tabelle nicht existiert, wird sie erstellt. Sobald die AutoDST-Tabelle existiert, erstellen wir ihren Trigger und versuchen, den aus einer Enumeration in eine Zeichenfolge umgewandelten Sommerzeitplan einzufügen.
void CNews::CreateAutoDST(int db) { bool failed=false;//boolean variable if(!AutoDetectDST(DSTType))//Check if AutoDetectDST went through all the right procedures { return;//will terminate execution of the rest of the code below } if(!DatabaseTableExists(db,CalendarStruct(AutoDST_Table).name))//Checks if the table 'AutoDST' exists in the databse 'Calendar' { //--- create the table AutoDST if(!DatabaseExecute(db,CalendarStruct(AutoDST_Table).sql))//Will attempt to create the table 'AutoDST' { Print("DB: create the AutoDST table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return;//Exits the function if creating the table failed } else//If Table was created Successfully then Create Trigger { DatabaseExecute(db,CalendarStruct(AutoDST_Trigger).sql); } } else { //Create trigger if AutoDST table exists DatabaseExecute(db,CalendarStruct(AutoDST_Trigger).sql); } //Sql query/request to insert the recommend DST for the Broker using the DSTType variable to determine which string data to insert string request_text=StringFormat(CalendarStruct(AutoDST_Table).insert,EnumToString(DSTType)); if(!DatabaseExecute(db, request_text))//Will attempt to run this sql request/query { Print(GetLastError()); PrintFormat(CalendarStruct(AutoDST_Table).insert,EnumToString(DSTType));//Will print the sql query if failed failed=true;//assign true if the request failed } if(failed) { //--- roll back all transactions and unlock the database DatabaseTransactionRollback(db); PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError()); } }
Klasse Risikomanagement
Das Risikomanagement ist ein entscheidender Bestandteil des erfolgreichen Handels. Das primäre Ziel des Risikomanagements ist der Schutz des Handelskapitals. Ohne Kapital kann ein Händler nicht weiter handeln. Die Umsetzung von Strategien zur Verlustbegrenzung sorgt dafür, dass Händler länger auf dem Markt bleiben können, was ihnen mehr Möglichkeiten bietet, sich von Rückschlägen zu erholen und eine Gesamtrentabilität zu erzielen. In diesem Fall bieten wir dem Nutzer verschiedene Risikoprofile zur Auswahl an, um die am besten geeignete Option zu finden.
Haftungsausschluss: Ich werde die Begriffe Los, Losgröße und Volumen synonym verwenden. Betrachten Sie sie im Zusammenhang mit dem Risikomanagement als dasselbe.
Liste der Risikoprofile
- Minimale Losgröße
- Maximale Losgröße
- Prozentsatz des Saldos
- Prozentsatz der freien Marge
- Risiko in Betrag per Saldo
- Risiko in Höhe der freien Marge
- Losgröße per Saldo
- Losgröße per freiem Marge
- Nutzerdefinierte Losgröße
- Prozentsatz des Risikos
Mindestgröße der Losgröße:
Bei dieser Risikooption wird die minimal zulässige Losgröße für das aktuelle Symbol verwendet.
Maximale Losgröße:
Bei dieser Risikooption wird die maximal zulässige Losgröße für das aktuelle Symbol verwendet.
Prozentsatz des Saldos:
Bei dieser Risiko-Option erhalten wir zunächst den Risikobetrag.
amount_of_risk = Balance*Percent;
Nehmen wir an, der Prozentsatz sei 5 % und der Kontostand betrage 10.000.
amount_of_risk = 10000*(5/100); amount_of_risk = 500;
Wir benötigen dann einen Eröffnungskurs und einen Schlusskurs, um das Mindestrisiko für den jeweiligen Handel zu berechnen, wenn wir die Mindestlosgröße verwenden.
OrderCalcProfit(ORDER_TYPE,Symbol(),Minimum_lotsize,OpenPrice,ClosePrice,Minimum_risk);
Sobald das Mindestrisiko zurückgegeben wurde, wird die folgende Gleichung verwendet, um die erforderliche Losgröße für den Risikobetrag zu ermitteln
required_lotsize = (amount_of_risk/Minimum_risk)*Minimum_lotsize;
Minimum_risk = 100 und Minimum_lotsize = 0,1;
required_lotsize = (500/100)*0.1; required_lotsize = 5*0.1; required_lotsize = 0.5;
Prozentsatz der freien Marge:
Diese Risikooption ähnelt dem Prozentsatz des Saldos. Die Vorteile dieser Risikooption kommen jedoch zum Tragen, wenn auf dem Konto des Händlers offene Geschäfte vorhanden sind.
Beim Prozentsatz vom Saldo hingegen bleibt das Risiko unabhängig von den offenen Handelsgeschäften gleich, solange der Saldo gleich bleibt. Mit dem Prozentsatz der freien Marge ändert sich das Risiko, wenn der Gewinn der offenen Handelsgeschäfte schwankt. Dadurch ergibt sich eine genauere Risikoberechnung für den aktuellen Kontostand.
Risiko in Höhe des Saldos:
Bei dieser Risikooption müssen wir zunächst den zwischen dem Risiko im Betrag (dem Divisor) und dem Saldo (der Dividende) ermitteln.
risk = Balance/Risk_in_Amount;
Wir lassen dann Balance = 10.000 und Risk_in_Amount = 800;
In diesem Fall wollen wir grundsätzlich 800 $ pro Handelsgeschäft für jede 10.000 $ auf dem Konto des Händlers riskieren.
risk = 10000/800; risk = 12.5;
Wir teilen dann das Risiko durch den aktuellen Kontostand, um unseren Risikobetrag zu erhalten.
amount_of_risk = AccountBalance/risk;
Es sei AccountBalance = 5000;
amount_of_risk = 5000/12.5; amount_of_risk = 400;
Jetzt wissen wir, dass der Händler 400 Dollar für diesen speziellen Handel riskieren möchte.
Risiko in Höhe der freien Marge:
Diese Risikooption ähnelt dem Risiko im Betrag pro Saldo, wir werden nur ein anderes Beispiel durchgehen.
risk = FreeMargin/Risk_in_Amount;
Es sei FreeMargin = 150 und Risk_in_Amount = 1;
In diesem Fall riskieren wir $1 für jede $150 von FreeMargin.
risk = 150/1; risk = 150; amount_of_risk = AccountFreeMargin/risk; //-- Let AccountFreeMargin = 750 amount_of_risk = 750/150; amount_of_risk = 5;
Nachdem wir den Risikobetrag ermittelt haben, berechnen wir die erforderliche Losgröße für diesen spezifischen Handel, um das Risiko von 5 Dollar zu decken.
Losgröße per Saldo:
Bei dieser Risiko-Option gibt der Händler die Lot-Größe an, die er für einen bestimmten Kontostand riskieren möchte.
required_lotsize = (AccountBalance/Balance)*lotsize;
Dabei ist AccountBalance der tatsächliche Kontostand des Händlers, Balance und Lotsize sind Eingabewerte, die vom Händler bereitgestellt werden.
Es seien AccountBalance = 10.000 und Balance = 350 und lotsize = 0,01
In diesem Fall möchte der Händler 0,01 Lots für je 350 Dollar auf seinem Konto riskieren.
required_lotsize = (10000/350)*0.01; required_lotsize = 0.285;
Die erforderliche Lotsize ist 0,285, der tatsächliche Wert ist viel größer. Nehmen wir an, dass der Volumenschritt für das spezifische Symbol, mit dem wir einen Handel eröffnen wollen, 0,01 beträgt. Der Versuch, einen Handel mit einer Losgröße von 0,285 zu eröffnen, wenn der Volumenschritt 0,01 beträgt, führt zu einem Fehler.
Um dies zu verhindern, werden wir die Losgröße normalisieren, d. h. wir formatieren die Losgröße entsprechend dem Volumenschritt.
required_lotsize = Volume_Step*MathFloor(0.285/Volume_Step); requred_lotsize = 0.01*MathFloor(0.285/0.01); required_lotsize = 0.01*MathFloor(28.5); required_lotsize = 0.01*28; required_lotsize = 0.28;
Losgröße per freier Marge:
Diese Risikooption ist ähnlich wie die Losgröße pro Saldo, wir werden ein weiteres Beispiel geben.
required_lotsize = (AccountFreeMargin/FreeMargin)*lotsize;
Es seien AccountFreeMargin = 134.560 und FreeMargin = 1622 und lot-size = 0,0056
In diesem Fall:
required_lotsize = (134560/1622)*0.0056; required_lotsize = 0.464;
Nehmen wir an, dass der Volumenschritt 0,02 beträgt.
Wir werden required_lotsize in Übereinstimmung mit Volume step normalisieren.
//-- normalize for Volume Step required_lotsize = Volume_Step*MathFloor(0.464/Volume_Step); requred_lotsize = 0.02*MathFloor(0.464/0.02); required_lotsize = 0.02*MathFloor(23.2); required_lotsize = 0.02*23; required_lotsize = 0.46;
Nutzerdefinierte Losgröße:
Bei dieser Risikooption wird die vom Händler angegebene Losgröße verwendet.
Prozentsatz des Risikos:
Bei dieser Risikooption wird der Prozentsatz des maximal zulässigen Risikos für das aktuelle Symbol berechnet, wobei die Anforderungen an die freie Marge und die Marge für das spezifische Symbol verwendet werden.
Die Klasse CRiskManagement hat eine mehrstufige Vererbung von Klassen:
- CSymbolProperties
- CChartProperties
Die Klasse CRiskManagement wurde von der Klasse CAccountInfo eingebunden.
Die Klasse CRiskManagement besitzt eine hierarchische Vererbung von Klassen:
- CSymbolProperties
- CSymbolInfo
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include "ChartProperties.mqh" #include <Trade/AccountInfo.mqh> CAccountInfo Account; //-- Enumeration declaration for Risk options enum RiskOptions { MINIMUM_LOT,//MINIMUM LOTSIZE MAXIMUM_LOT,//MAXIMUM LOTSIZE PERCENTAGE_OF_BALANCE,//PERCENTAGE OF BALANCE PERCENTAGE_OF_FREEMARGIN,//PERCENTAGE OF FREE-MARGIN AMOUNT_PER_BALANCE,//AMOUNT PER BALANCE AMOUNT_PER_FREEMARGIN,//AMOUNT PER FREE-MARGIN LOTSIZE_PER_BALANCE,//LOTSIZE PER BALANCE LOTSIZE_PER_FREEMARGIN,//LOTSIZE PER FREE-MARGIN CUSTOM_LOT,//CUSTOM LOTSIZE PERCENTAGE_OF_MAXRISK//PERCENTAGE OF MAX-RISK } RiskProfileOption;//variable for Risk options //-- Enumeration declaration for Risk floor enum RiskFloor { RiskFloorMin,//MINIMUM LOTSIZE RiskFloorMax,//MAX-RISK RiskFloorNone//NONE } RiskFloorOption;//variable for Risk floor //-- Enumeration declaration for Risk ceiling(Maximum allowable risk in terms of lot-size) enum RiskCeil { RiskCeilMax,//MAX LOTSIZE RiskCeilMax2,//MAX LOTSIZE(x2) RiskCeilMax3,//MAX LOTSIZE(x3) RiskCeilMax4,//MAX LOTSIZE(x4) RiskCeilMax5,//MAX LOTSIZE(x5) } RiskCeilOption;//variable for Risk ceiling //-- Structure declaration for Risk options (AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN) struct RISK_AMOUNT { double RiskAmountBoF;//store Balance or Free-Margin double RiskAmount;//store risk amount } Risk_Profile_2;//variable for Risk options (AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN) //-- Structure declaration for Risk options (LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN) struct RISK_LOT { double RiskLotBoF;//store Balance or Free-Margin double RiskLot;//store lot-size } Risk_Profile_3;//variable for Risk options (LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN) double RiskFloorPercentage;//variable for RiskFloorMax double Risk_Profile_1;//variable for Risk options (PERCENTAGE OF BALANCE and PERCENTAGE OF FREE-MARGIN) double Risk_Profile_4;//variable for Risk option (CUSTOM LOTSIZE) double Risk_Profile_5;//variable for Risk option (PERCENTAGE OF MAX-RISK) //+------------------------------------------------------------------+ //|RiskManagement class | //+------------------------------------------------------------------+ class CRiskManagement : public CChartProperties { private: double Medium;//variable to store actual Account (Balance or Free-Margin) double RiskAmount,MinimumAmount; double Lots;//variable to store Lot-size to open trade const double max_percent;//variable to store percentage for Maximum risk //-- enumeration for dealing with account balance/free-margin enum RiskMedium { BALANCE, MARGIN }; //-- calculations for Risk options (PERCENTAGE OF BALANCE and PERCENTAGE OF FREE-MARGIN) double RiskProfile1(const RiskMedium R_Medium); //-- calculations for Risk options (AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN) double RiskProfile2(const RiskMedium R_Medium); //-- calculations for Risk options (LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN) double RiskProfile3(const RiskMedium R_Medium); //-- calculations for Maximum allowable Risk double MaxRisk(const double percent); //-- Store Trade's Open-price double OpenPrice; //-- Store Trade's Close-price double ClosePrice; //-- Store Ordertype between (ORDER_TYPE_BUY or ORDER_TYPE_SELL) for risk calaculations ENUM_ORDER_TYPE ORDERTYPE; //-- Set Medium variable value void SetMedium(const RiskMedium R_Medium) {Medium = (R_Medium==BALANCE)?Account.Balance():Account.FreeMargin();} //-- Get Minimum Risk for a Trade using Minimum Lot-size bool GetMinimumRisk() { return OrderCalcProfit(ORDERTYPE,Symbol(),LotsMin(),OpenPrice,ClosePrice,MinimumAmount); } //-- Retrieve Risk amount based on Risk inputs double GetRisk(double Amount) { if(!GetMinimumRisk()||Amount==0) return 0.0; return ((Amount/MinimumAmount)*LotsMin()); } protected: //-- Application of Lot-size limits void ValidateLotsize(double &Lotsize); //-- Set ORDERTYPE variable to (ORDER_TYPE_BUY or ORDER_TYPE_SELL) respectively void SetOrderType(ENUM_ORDER_TYPE Type) { if(Type==ORDER_TYPE_BUY||Type==ORDER_TYPE_BUY_LIMIT||Type==ORDER_TYPE_BUY_STOP) { ORDERTYPE = ORDER_TYPE_BUY; } else if(Type==ORDER_TYPE_SELL||Type==ORDER_TYPE_SELL_LIMIT||Type==ORDER_TYPE_SELL_STOP) { ORDERTYPE = ORDER_TYPE_SELL; } } public: CRiskManagement();//Class's constructor //-- Retrieve user's Risk option string GetRiskOption() { switch(RiskProfileOption) { case MINIMUM_LOT://MINIMUM LOTSIZE - Risk Option return "MINIMUM LOTSIZE"; break; case MAXIMUM_LOT://MAXIMUM LOTSIZE - Risk Option return "MAXIMUM LOTSIZE"; break; case PERCENTAGE_OF_BALANCE://PERCENTAGE OF BALANCE - Risk Option return "PERCENTAGE OF BALANCE"; break; case PERCENTAGE_OF_FREEMARGIN://PERCENTAGE OF FREE-MARGIN - Risk Option return "PERCENTAGE OF FREE-MARGIN"; break; case AMOUNT_PER_BALANCE://AMOUNT PER BALANCE - Risk Option return "AMOUNT PER BALANCE"; break; case AMOUNT_PER_FREEMARGIN://AMOUNT PER FREE-MARGIN - Risk Option return "AMOUNT PER FREE-MARGIN"; break; case LOTSIZE_PER_BALANCE://LOTSIZE PER BALANCE - Risk Option return "LOTSIZE PER BALANCE"; break; case LOTSIZE_PER_FREEMARGIN://LOTSIZE PER FREE-MARGIN - Risk Option return "LOTSIZE PER FREE-MARGIN"; break; case CUSTOM_LOT://CUSTOM LOTSIZE - Risk Option return "CUSTOM LOTSIZE"; break; case PERCENTAGE_OF_MAXRISK://PERCENTAGE OF MAX-RISK - Risk Option return "PERCENTAGE OF MAX-RISK"; break; default: return ""; break; } } //-- Retrieve user's Risk Floor Option string GetRiskFloor() { switch(RiskFloorOption) { case RiskFloorMin://MINIMUM LOTSIZE for Risk floor options return "MINIMUM LOTSIZE"; break; case RiskFloorMax://MAX-RISK for Risk floor options return "MAX-RISK"; break; case RiskFloorNone://NONE for Risk floor options return "NONE"; break; default: return ""; break; } } //-- Retrieve user's Risk Ceiling option string GetRiskCeil() { switch(RiskCeilOption) { case RiskCeilMax://MAX LOTSIZE for Risk ceiling options return "MAX LOTSIZE"; break; case RiskCeilMax2://MAX LOTSIZE(x2) for Risk ceiling options return "MAX LOTSIZE(x2)"; break; case RiskCeilMax3://MAX LOTSIZE(x3) for Risk ceiling options return "MAX LOTSIZE(x3)"; break; case RiskCeilMax4://MAX LOTSIZE(x4) for Risk ceiling options return "MAX LOTSIZE(x4)"; break; case RiskCeilMax5://MAX LOTSIZE(x5) for Risk ceiling options return "MAX LOTSIZE(x5)"; break; default: return ""; break; } } double Volume();//Get risk in Volume //Apply fixes to lot-size where applicable void NormalizeLotsize(double &Lotsize); }; //+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ //Initialize values CRiskManagement::CRiskManagement(void):Lots(0.0),max_percent(100), ORDERTYPE(ORDER_TYPE_BUY),OpenPrice(Ask()), ClosePrice(NormalizePrice(Ask()+Ask()*0.01)) { } //+------------------------------------------------------------------+ //|Get risk in Volume | //+------------------------------------------------------------------+ double CRiskManagement::Volume() { switch(RiskProfileOption) { case MINIMUM_LOT://MINIMUM LOTSIZE - Risk Option return LotsMin(); break; case MAXIMUM_LOT://MAXIMUM LOTSIZE - Risk Option Lots = LotsMax(); break; case PERCENTAGE_OF_BALANCE://PERCENTAGE OF BALANCE - Risk Option Lots = RiskProfile1(BALANCE); break; case PERCENTAGE_OF_FREEMARGIN://PERCENTAGE OF FREE-MARGIN - Risk Option Lots = RiskProfile1(MARGIN); break; case AMOUNT_PER_BALANCE://AMOUNT PER BALANCE - Risk Option Lots = RiskProfile2(BALANCE); break; case AMOUNT_PER_FREEMARGIN://AMOUNT PER FREE-MARGIN - Risk Option Lots = RiskProfile2(MARGIN); break; case LOTSIZE_PER_BALANCE://LOTSIZE PER BALANCE - Risk Option Lots = RiskProfile3(BALANCE); break; case LOTSIZE_PER_FREEMARGIN://LOTSIZE PER FREE-MARGIN - Risk Option Lots = RiskProfile3(MARGIN); break; case CUSTOM_LOT://CUSTOM LOTSIZE - Risk Option Lots = Risk_Profile_4; break; case PERCENTAGE_OF_MAXRISK://PERCENTAGE OF MAX-RISK - Risk Option Lots = MaxRisk(Risk_Profile_5); break; default: Lots = 0.0; break; } ValidateLotsize(Lots);//Check/Adjust Lotsize Limits NormalizeLotsize(Lots);//Normalize Lotsize return Lots; } //+------------------------------------------------------------------+ //|calculations for Risk options | //|(PERCENTAGE OF BALANCE and PERCENTAGE OF FREE-MARGIN) | //+------------------------------------------------------------------+ //-- calculations for Risk options (PERCENTAGE OF BALANCE and PERCENTAGE OF FREE-MARGIN) double CRiskManagement::RiskProfile1(const RiskMedium R_Medium) { SetMedium(R_Medium); RiskAmount = Medium*(Risk_Profile_1/100); return GetRisk(RiskAmount); } //+------------------------------------------------------------------+ //|calculations for Risk options | //|(AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN) | //+------------------------------------------------------------------+ //-- calculations for Risk options (AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN) double CRiskManagement::RiskProfile2(const RiskMedium R_Medium) { SetMedium(R_Medium); double risk = (Risk_Profile_2.RiskAmountBoF/Risk_Profile_2.RiskAmount); risk = (risk<1)?1:risk; if(Medium<=0) return 0.0; RiskAmount = Medium/risk; return GetRisk(RiskAmount); } //+------------------------------------------------------------------+ //|calculations for Risk options | //|(LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN) | //+------------------------------------------------------------------+ //-- calculations for Risk options (LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN) double CRiskManagement::RiskProfile3(const RiskMedium R_Medium) { SetMedium(R_Medium); return (Medium>0)?((Medium/Risk_Profile_3.RiskLotBoF)*Risk_Profile_3.RiskLot):0.0; } //+------------------------------------------------------------------+ //|calculations for Maximum allowable Risk | //+------------------------------------------------------------------+ //-- calculations for Maximum allowable Risk double CRiskManagement::MaxRisk(const double percent) { double margin=0.0,max_risk=0.0; //--- checks if(percent<0.01 || percent>100) { Print(__FUNCTION__," invalid parameters"); return(0.0); } //--- calculate margin requirements for 1 lot if(!OrderCalcMargin(ORDERTYPE,Symbol(),1.0,OpenPrice,margin) || margin<0.0) { Print(__FUNCTION__," margin calculation failed"); return(0.0); } //--- calculate maximum volume max_risk=Account.FreeMargin()*(percent/100.0)/margin; //--- return volume return(max_risk); } //+------------------------------------------------------------------+ //|Apply fixes to lot-size where applicable | //+------------------------------------------------------------------+ void CRiskManagement::NormalizeLotsize(double &Lotsize) { if(Lotsize<=0.0) return; //-- Check if the is a Volume limit for the current Symbol if(LotsLimit()>0.0) { if((Lots+PositionsVolume()+OrdersVolume())>LotsLimit()) { //-- calculation of available lotsize remaining double remaining_avail_lots = (LotsLimit()-(PositionsVolume()+OrdersVolume())); if(remaining_avail_lots>=LotsMin()) { if(RiskFloorOption==RiskFloorMin)//Check if Risk floor option is MINIMUM LOTSIZE { Print("Warning: Volume Limit Reached, minimum Lotsize selected."); Lotsize = LotsMin(); } else if(RiskFloorOption==RiskFloorMax)//Check if Risk floor option is MAX-RISK { Print("Warning: Volume Limit Reached, Lotsize Reduced."); Lotsize = ((remaining_avail_lots*(RiskFloorPercentage/100))>LotsMin())? (remaining_avail_lots*(RiskFloorPercentage/100)):LotsMin(); } } else { Print("Volume Limit Reached!"); Lotsize=0.0; return; } } } //Check if there is a valid Volume Step for the current Symbol if(LotsStep()>0.0) Lotsize=LotsStep()*MathFloor(Lotsize/LotsStep()); } //+------------------------------------------------------------------+ //|Application of Lot-size limits | //+------------------------------------------------------------------+ void CRiskManagement::ValidateLotsize(double &Lotsize) { switch(RiskFloorOption) { case RiskFloorMin://MINIMUM LOTSIZE for Risk floor options //-- Check if lot-size is not less than Minimum lot or more than maximum allowable risk if(Lotsize<LotsMin()||Lotsize>MaxRisk(max_percent)) { Lotsize=LotsMin(); } break; case RiskFloorMax://MAX-RISK for Risk floor options //-- Check if lot-size is more the maximum allowable risk if(Lotsize>MaxRisk(max_percent)) { Lotsize=(MaxRisk(RiskFloorPercentage)>LotsMin())?MaxRisk(RiskFloorPercentage):LotsMin(); } else if(Lotsize<LotsMin())//Check if lot-size is less than Minimum lot { Lotsize=LotsMin(); } break; case RiskFloorNone://NONE for Risk floor options //Check if lot-size is less than Minimum lot if(Lotsize<LotsMin()) { Lotsize=0.0; } break; default: Lotsize=0.0; break; } switch(RiskCeilOption) { case RiskCeilMax://MAX LOTSIZE for Risk ceiling options //Check if lot-size is more than Maximum lot if(Lotsize>LotsMax()) Lotsize=LotsMax(); break; case RiskCeilMax2://MAX LOTSIZE(x2) for Risk ceiling options //Check if lot-size is more than Maximum lot times two if(Lotsize>(LotsMax()*2)) Lotsize=(LotsMax()*2); break; case RiskCeilMax3://MAX LOTSIZE(x3) for Risk ceiling options //Check if lot-size is more than Maximum lot times three if(Lotsize>(LotsMax()*3)) Lotsize=(LotsMax()*3); break; case RiskCeilMax4://MAX LOTSIZE(x4) for Risk ceiling options //Check if lot-size is more than Maximum lot times four if(Lotsize>(LotsMax()*4)) Lotsize=(LotsMax()*4); break; case RiskCeilMax5://MAX LOTSIZE(x5) for Risk ceiling options //Check if lot-size is more than Maximum lot times five if(Lotsize>(LotsMax()*5)) Lotsize=(LotsMax()*5); break; default: break; } } //+------------------------------------------------------------------+
Die Variable RiskProfileOption vom Enumerations-Typ RiskOptions speichert die Risikoprofiloption des Nutzers/Händlers, die als Eingabe für den Experten dient.
//-- Enumeration declaration for Risk options enum RiskOptions { MINIMUM_LOT,//MINIMUM LOTSIZE MAXIMUM_LOT,//MAXIMUM LOTSIZE PERCENTAGE_OF_BALANCE,//PERCENTAGE OF BALANCE PERCENTAGE_OF_FREEMARGIN,//PERCENTAGE OF FREE-MARGIN AMOUNT_PER_BALANCE,//AMOUNT PER BALANCE AMOUNT_PER_FREEMARGIN,//AMOUNT PER FREE-MARGIN LOTSIZE_PER_BALANCE,//LOTSIZE PER BALANCE LOTSIZE_PER_FREEMARGIN,//LOTSIZE PER FREE-MARGIN CUSTOM_LOT,//CUSTOM LOTSIZE PERCENTAGE_OF_MAXRISK//PERCENTAGE OF MAX-RISK } RiskProfileOption;//variable for Risk options
Die Variable RiskFloorOption vom Enumerations-Typ RiskFloor speichert die minimale Risikopräferenz des Nutzers/Händlers, die als Eingabe für den Experten dient.
//-- Enumeration declaration for Risk floor enum RiskFloor { RiskFloorMin,//MINIMUM LOTSIZE RiskFloorMax,//MAX-RISK RiskFloorNone//NONE } RiskFloorOption;//variable for Risk floor
Die Variable RiskCeilOption vom Enumerations-Typ RiskCeil speichert die maximale Risikopräferenz des Nutzers/Händlers, die als Eingabe für den Experten dient.
//-- Enumeration declaration for Risk ceiling(Maximum allowable risk in terms of lot-size) enum RiskCeil { RiskCeilMax,//MAX LOTSIZE RiskCeilMax2,//MAX LOTSIZE(x2) RiskCeilMax3,//MAX LOTSIZE(x3) RiskCeilMax4,//MAX LOTSIZE(x4) RiskCeilMax5,//MAX LOTSIZE(x5) } RiskCeilOption;//variable for Risk ceiling
Der Nutzer/Händler (Kontosaldo oder freie Marge) wird in der „double“-Variablen RiskAmountBoF gespeichert und die „double“-Variablen RiskAmount speichert den Wert des Risikobetrags. Risk_Profile_2 wird verwendet, um die Eigenschaften AMOUNT PER BALANCE und AMOUNT PER FREE-MARGIN der Risikoprofile zu speichern.
//-- Structure declaration for Risk options (AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN) struct RISK_AMOUNT { double RiskAmountBoF;//store Balance or Free-Margin double RiskAmount;//store risk amount } Risk_Profile_2;//variable for Risk options (AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN)
Die Variable Risk_Profile_3 vom Typ Struktur RISK_LOT speichert die Eigenschaften LOTSIZE PER BALANCE und LOTSIZE PER FREE-MARGIN der Risikoprofile.
//-- Structure declaration for Risk options (LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN) struct RISK_LOT { double RiskLotBoF;//store Balance or Free-Margin double RiskLot;//store lot-size } Risk_Profile_3;//variable for Risk options (LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN)
Die Variable RiskFloorPercentage speichert den Prozentsatz des Max-Risikos für die Riskfloor-Option RiskFloorMax.
double RiskFloorPercentage;//variable for RiskFloorMax
In der Variablen Risk_Profile_1 wird der Risikoprozentsatz für die Risikooptionen PERCENTAGE OF BALANCE oder PERCENTAGE OF FREE-MARGIN gespeichert.
double Risk_Profile_1;//variable for Risk options (PERCENTAGE OF BALANCE and PERCENTAGE OF FREE-MARGIN)
In der Variablen Risk_Profile_4 wird die nutzerdefinierte Losgröße für die Risikooption CUSTOM LOTSIZE gespeichert.
double Risk_Profile_4;//variable for Risk option (CUSTOM LOTSIZE)
Die Variable Risk_Profile_5 speichert den Prozentsatz des maximalen Risikos für die Risikooption PERCENTAGE OF MAX-RISK.
double Risk_Profile_5;//variable for Risk option (PERCENTAGE OF MAX-RISK)
Mit der Funktion GetRiskOption wird die Risikooption des Nutzers/Händlers in einem String-Datentyp abgerufen.
//-- Retrieve user's Risk option string GetRiskOption() { switch(RiskProfileOption) { case MINIMUM_LOT://MINIMUM LOTSIZE - Risk Option return "MINIMUM LOTSIZE"; break; case MAXIMUM_LOT://MAXIMUM LOTSIZE - Risk Option return "MAXIMUM LOTSIZE"; break; case PERCENTAGE_OF_BALANCE://PERCENTAGE OF BALANCE - Risk Option return "PERCENTAGE OF BALANCE"; break; case PERCENTAGE_OF_FREEMARGIN://PERCENTAGE OF FREE-MARGIN - Risk Option return "PERCENTAGE OF FREE-MARGIN"; break; case AMOUNT_PER_BALANCE://AMOUNT PER BALANCE - Risk Option return "AMOUNT PER BALANCE"; break; case AMOUNT_PER_FREEMARGIN://AMOUNT PER FREE-MARGIN - Risk Option return "AMOUNT PER FREE-MARGIN"; break; case LOTSIZE_PER_BALANCE://LOTSIZE PER BALANCE - Risk Option return "LOTSIZE PER BALANCE"; break; case LOTSIZE_PER_FREEMARGIN://LOTSIZE PER FREE-MARGIN - Risk Option return "LOTSIZE PER FREE-MARGIN"; break; case CUSTOM_LOT://CUSTOM LOTSIZE - Risk Option return "CUSTOM LOTSIZE"; break; case PERCENTAGE_OF_MAXRISK://PERCENTAGE OF MAX-RISK - Risk Option return "PERCENTAGE OF MAX-RISK"; break; default: return ""; break; } }
In der Funktion GetRiskFloor werden wir die Option der Risikountergrenze Nutzers/Händlers in einem String-Datentyp abrufen.
//-- Retrieve user's Risk Floor Option string GetRiskFloor() { switch(RiskFloorOption) { case RiskFloorMin://MINIMUM LOTSIZE for Risk floor options return "MINIMUM LOTSIZE"; break; case RiskFloorMax://MAX-RISK for Risk floor options return "MAX-RISK"; break; case RiskFloorNone://NONE for Risk floor options return "NONE"; break; default: return ""; break; } }
In der Funktion GetRiskCeil werden wir die Risikohöchstgrenze des Nutzers/Händlers in einem String-Datentyp abrufen.
//-- Retrieve user's Risk Ceiling option string GetRiskCeil() { switch(RiskCeilOption) { case RiskCeilMax://MAX LOTSIZE for Risk ceiling options return "MAX LOTSIZE"; break; case RiskCeilMax2://MAX LOTSIZE(x2) for Risk ceiling options return "MAX LOTSIZE(x2)"; break; case RiskCeilMax3://MAX LOTSIZE(x3) for Risk ceiling options return "MAX LOTSIZE(x3)"; break; case RiskCeilMax4://MAX LOTSIZE(x4) for Risk ceiling options return "MAX LOTSIZE(x4)"; break; case RiskCeilMax5://MAX LOTSIZE(x5) for Risk ceiling options return "MAX LOTSIZE(x5)"; break; default: return ""; break; } }
Im Konstruktor der Klasse Risk Management werden wir die zuvor deklarierten Variablen mit einem Standardwert initialisieren. Der Standardwert für die Variable ORDERTYPE ist ORDER_TYPE_BUY, d.h. für die Risikooptionen, die einen Ordertyp zur Berechnung des Risikos erfordern, wird der Ordertyp durch diese Variable festgelegt und zur Simulation der Risikoberechnung für die Eröffnung von Geschäften verwendet. Der standardmäßige Eröffnungspreis in der Variablen OpenPrice gespeichert und es ist der Ask-Preis des Symbols für unseren ORDERTYPE. Der standardmäßige Schlusskurs ist eine 1%ige Abweichung vom Ask-Kurs, der in der Variablen ClosePrice gespeichert ist.
//Initialize values CRiskManagement::CRiskManagement(void):Lots(0.0),max_percent(100), ORDERTYPE(ORDER_TYPE_BUY),OpenPrice(Ask()), ClosePrice(NormalizePrice(Ask()+Ask()*0.01)) { }
Die Funktion „Volumen“ ruft die Losgröße für die Risikoprofiloption des Nutzers/Händlers ab und passt die Losgröße der ausgewählten Risikooption entsprechend der vom Nutzer/Händler ausgewählten Option „Risikohöchstgrenze“ und „Risikountergrenze“ an.
Danach wird die Losgröße normalisiert, sodass ein aktueller Handel mit der spezifischen Losgröße eröffnet werden kann.
double CRiskManagement::Volume() { switch(RiskProfileOption) { case MINIMUM_LOT://MINIMUM LOTSIZE - Risk Option return LotsMin(); break; case MAXIMUM_LOT://MAXIMUM LOTSIZE - Risk Option Lots = LotsMax(); break; case PERCENTAGE_OF_BALANCE://PERCENTAGE OF BALANCE - Risk Option Lots = RiskProfile1(BALANCE); break; case PERCENTAGE_OF_FREEMARGIN://PERCENTAGE OF FREE-MARGIN - Risk Option Lots = RiskProfile1(MARGIN); break; case AMOUNT_PER_BALANCE://AMOUNT PER BALANCE - Risk Option Lots = RiskProfile2(BALANCE); break; case AMOUNT_PER_FREEMARGIN://AMOUNT PER FREE-MARGIN - Risk Option Lots = RiskProfile2(MARGIN); break; case LOTSIZE_PER_BALANCE://LOTSIZE PER BALANCE - Risk Option Lots = RiskProfile3(BALANCE); break; case LOTSIZE_PER_FREEMARGIN://LOTSIZE PER FREE-MARGIN - Risk Option Lots = RiskProfile3(MARGIN); break; case CUSTOM_LOT://CUSTOM LOTSIZE - Risk Option Lots = Risk_Profile_4; break; case PERCENTAGE_OF_MAXRISK://PERCENTAGE OF MAX-RISK - Risk Option Lots = MaxRisk(Risk_Profile_5); break; default: Lots = 0.0; break; } ValidateLotsize(Lots);//Check/Adjust Lotsize Limits NormalizeLotsize(Lots);//Normalize Lotsize return Lots; }
Die Funktion SetMedium weist der „double“-Variablen Medium den Wert des Kontosaldos oder der freien Marge des Nutzers/Händlers auf der Grundlage der Enumerations-Variablen R_Medium zu.
//-- Set Medium variable value void SetMedium(const RiskMedium R_Medium) {Medium = (R_Medium==BALANCE)?Account.Balance():Account.FreeMargin();}
Die Funktion GetMinimumRisk weist der Variablen MinimumAmount das erforderliche Mindestrisiko für einen bestimmten Handel mit der minimalen Losgröße zu.
//-- Get Minimum Risk for a Trade using Minimum Lot-size bool GetMinimumRisk() { return OrderCalcProfit(ORDERTYPE,Symbol(),LotsMin(),OpenPrice,ClosePrice,MinimumAmount); }
Die Funktion GetRisk ermittelt die erforderliche Losgröße für einen bestimmten Risikobetrag in der Argumentvariablen Amount. Wenn der MinimumAmount (Mindestrisikobetrag für ein bestimmtes Handelsgeschäft) festgelegt wird. Amount wird durch MinimumAmount geteilt, um einen Quotienten zu erhalten, der mit der Mindestlosgröße multipliziert wird, um die erforderliche Losgröße für Amount zu erhalten.
//-- Retrieve Risk amount based on Risk inputs double GetRisk(double Amount) { if(!GetMinimumRisk()||Amount==0) return 0.0; return ((Amount/MinimumAmount)*LotsMin()); }
In der Funktion RiskProfile1 wird die Losgröße für die Risikooptionen PERCENTAGE OF BALANCE oder PERCENTAGE OF FREE-MARGIN berechnet und zurückgegeben.
//-- calculations for Risk options (PERCENTAGE OF BALANCE and PERCENTAGE OF FREE-MARGIN) double CRiskManagement::RiskProfile1(const RiskMedium R_Medium) { SetMedium(R_Medium); RiskAmount = Medium*(Risk_Profile_1/100); return GetRisk(RiskAmount); }
In der Funktion RiskProfile2 wird die Losgröße für die Risikooptionen AMOUNT PER BALANCE oder AMOUNT PER FREE-MARGIN berechnet und zurückgegeben.
//-- calculations for Risk options (AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN) double CRiskManagement::RiskProfile2(const RiskMedium R_Medium) { SetMedium(R_Medium); double risk = (Risk_Profile_2.RiskAmountBoF/Risk_Profile_2.RiskAmount); risk = (risk<1)?1:risk; if(Medium<=0) return 0.0; RiskAmount = Medium/risk; return GetRisk(RiskAmount); }
In der Funktion RiskProfile3 wird die Lot-Größe für die Risiko-Optionen LOTSIZE PER BALANCE oder LOTSIZE PER FREE-MARGIN berechnet und zurückgegeben.
//-- calculations for Risk options (LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN) double CRiskManagement::RiskProfile3(const RiskMedium R_Medium) { SetMedium(R_Medium); return (Medium>0)?((Medium/Risk_Profile_3.RiskLotBoF)*Risk_Profile_3.RiskLot):0.0; }
In der Funktion ValidateLotsize werden Anpassungen an der per Referenz übergebenen Variablen Lotsize vorgenommen.
Im ersten Switch-Ausdruck RiskFloorOption:
- Für den Fall, dass RiskFloorMin: Wir prüfen, ob die Variable Lotsize unter ihrer Untergrenze liegt und weisen ihr dann die minimale Losgröße des aktuellen Symbols zu. Wir prüfen die Untergrenze, d. h. ob der Variablenwert unter der Mindestlosgröße liegt. Die Obergrenze ist erreicht, wenn die Variable Lotsize über dem maximal möglichen Risiko liegt.
- Für den Fall, dass RiskFloorMax: Zunächst wird geprüft, ob die Variable Lotsize das maximal mögliche Risiko übersteigt. Ist dies der Fall, wird geprüft, ob das maximal gewünschte Mindestrisiko die minimale Losgröße übersteigt. War Lotsize ursprünglich kleiner als das maximal mögliche Risiko und kleiner als die minimale Lotsize, so wird die minimale Lotsize zugewiesen.
void CRiskManagement::ValidateLotsize(double &Lotsize) { switch(RiskFloorOption) { case RiskFloorMin://MINIMUM LOTSIZE for Risk floor options //-- Check if lot-size is not less than Minimum lot or more than maximum allowable risk if(Lotsize<LotsMin()||Lotsize>MaxRisk(max_percent)) { Lotsize=LotsMin(); } break; case RiskFloorMax://MAX-RISK for Risk floor options //-- Check if lot-size is more the maximum allowable risk if(Lotsize>MaxRisk(max_percent)) { Lotsize=(MaxRisk(RiskFloorPercentage)>LotsMin())?MaxRisk(RiskFloorPercentage):LotsMin(); } else if(Lotsize<LotsMin())//Check if lot-size is less than Minimum lot { Lotsize=LotsMin(); } break; case RiskFloorNone://NONE for Risk floor options //Check if lot-size is less than Minimum lot if(Lotsize<LotsMin()) { Lotsize=0.0; } break; default: Lotsize=0.0; break; } switch(RiskCeilOption) { case RiskCeilMax://MAX LOTSIZE for Risk ceiling options //Check if lot-size is more than Maximum lot if(Lotsize>LotsMax()) Lotsize=LotsMax(); break; case RiskCeilMax2://MAX LOTSIZE(x2) for Risk ceiling options //Check if lot-size is more than Maximum lot times two if(Lotsize>(LotsMax()*2)) Lotsize=(LotsMax()*2); break; case RiskCeilMax3://MAX LOTSIZE(x3) for Risk ceiling options //Check if lot-size is more than Maximum lot times three if(Lotsize>(LotsMax()*3)) Lotsize=(LotsMax()*3); break; case RiskCeilMax4://MAX LOTSIZE(x4) for Risk ceiling options //Check if lot-size is more than Maximum lot times four if(Lotsize>(LotsMax()*4)) Lotsize=(LotsMax()*4); break; case RiskCeilMax5://MAX LOTSIZE(x5) for Risk ceiling options //Check if lot-size is more than Maximum lot times five if(Lotsize>(LotsMax()*5)) Lotsize=(LotsMax()*5); break; default: break; } }
Die Funktion NormalizeLotsize hat die Aufgabe zu prüfen, ob die Losgröße innerhalb der Volumengrenze des Symbols liegt und ob die Losgröße mit dem Volumenschritt übereinstimmt.
Wenn die Losgröße das Volumenlimit des Symbols verletzt, berechnen wir die verbleibenden verfügbaren Losgrößen vor dem Volumenlimit. Danach wird geprüft, ob die verbleibende Losgröße größer oder gleich der Mindestlosgröße für das aktuelle Symbol ist.
- RiskFloorMin: Wir setzen die Variable Lotsize auf die minimale Losgröße.
- RisikoFloorMax: Wenn der RiskFloorPercentage der verbleibenden Losgröße größer ist als die Mindestlosgröße, wird die Variable Lotsize auf diesen Wert gesetzt. Wenn der RiskFloorPercentage der verbleibenden Losgröße kleiner oder gleich der Mindestlosgröße ist, setzen wir die Variable Lotsize auf die Mindestlosgröße.
void CRiskManagement::NormalizeLotsize(double &Lotsize) { if(Lotsize<=0.0) return; //-- Check if the is a Volume limit for the current Symbol if(LotsLimit()>0.0) { if((Lots+PositionsVolume()+OrdersVolume())>LotsLimit()) { //-- calculation of available lotsize remaining double remaining_avail_lots = (LotsLimit()-(PositionsVolume()+OrdersVolume())); if(remaining_avail_lots>=LotsMin()) { if(RiskFloorOption==RiskFloorMin)//Check if Risk floor option is MINIMUM LOTSIZE { Print("Warning: Volume Limit Reached, minimum Lotsize selected."); Lotsize = LotsMin(); } else if(RiskFloorOption==RiskFloorMax)//Check if Risk floor option is MAX-RISK { Print("Warning: Volume Limit Reached, Lotsize Reduced."); Lotsize = ((remaining_avail_lots*(RiskFloorPercentage/100))>LotsMin())? (remaining_avail_lots*(RiskFloorPercentage/100)):LotsMin(); } } else { Print("Volume Limit Reached!"); Lotsize=0.0; return; } } } //Check if there is a valid Volume Step for the current Symbol if(LotsStep()>0.0) Lotsize=LotsStep()*MathFloor(Lotsize/LotsStep()); }
Die Klasse der allgemeinen Grafik
Die allgemeine Grafikklasse zeigt allgemeine Eigenschaften des aktuellen Symbols und einige der vom Händler festgelegten Risikooptionen an.
CommonGraphics hat eine mehrstufige Vererbung von Klassen:
- CObjectProperties
- CChartProperties
- CSymbolProperties
CommonGraphics bindet die Klasse CRiskManagement ein.
CommonGraphics hat hierarchische Vererbung von Klassen:
- CSymbolProperties
- CSymbolInfo
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ #include "ObjectProperties.mqh" #include "RiskManagement.mqh" //+------------------------------------------------------------------+ //|CommonGraphics class | //+------------------------------------------------------------------+ class CCommonGraphics:CObjectProperties { private: CRiskManagement CRisk;//Risk management class object public: CCommonGraphics(void);//class constructor ~CCommonGraphics(void) {}//class destructor void GraphicsRefresh();//will create the chart objects }; //+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CCommonGraphics::CCommonGraphics(void) { GraphicsRefresh();//calling GraphicsRefresh function } //+------------------------------------------------------------------+ //|Specify Chart Objects | //+------------------------------------------------------------------+ void CCommonGraphics::GraphicsRefresh() { //-- Will create the rectangle object Square(0,"Symbol Properties",2,20,330,183,ANCHOR_LEFT_UPPER); //-- Will create the text object for the Symbol's name TextObj(0,"Symbol Name",Symbol(),5,23); //-- Will create the text object for the contract size TextObj(0,"Symbol Contract Size","Contract Size: "+string(ContractSize()),5,40,CORNER_LEFT_UPPER,9); //-- Will create the text object for the Symbol's Minimum lotsize TextObj(0,"Symbol MinLot","Minimum Lot: "+string(LotsMin()),5,60,CORNER_LEFT_UPPER,9); //-- Will create the text object for the Symbol's Maximum lotsize TextObj(0,"Symbol MaxLot","Max Lot: "+string(LotsMax()),5,80,CORNER_LEFT_UPPER,9); //-- Will create the text object for the Symbol's Volume Step TextObj(0,"Symbol Volume Step","Volume Step: "+string(LotsStep()),5,100,CORNER_LEFT_UPPER,9); //-- Will create the text object for the Symbol's Volume Limit TextObj(0,"Symbol Volume Limit","Volume Limit: "+string(LotsLimit()),5,120,CORNER_LEFT_UPPER,9); //-- Will create the text object for the trader's Risk Option TextObj(0,"Risk Option","Risk Option: "+CRisk.GetRiskOption(),5,140,CORNER_LEFT_UPPER,9); //-- Will create the text object for the trader's Risk Floor TextObj(0,"Risk Floor","Risk Floor: "+CRisk.GetRiskFloor(),5,160,CORNER_LEFT_UPPER,9); //-- Will create the text object for the trader's Risk Ceiling TextObj(0,"Risk Ceil","Risk Ceiling: "+CRisk.GetRiskCeil(),5,180,CORNER_LEFT_UPPER,9); } //+------------------------------------------------------------------+
In der Funktion GraphicsRefresh legen wir die Eigenschaften für unsere grafischen Chartobjekte fest.
void CCommonGraphics::GraphicsRefresh() { //-- Will create the rectangle object Square(0,"Symbol Properties",2,20,330,183,ANCHOR_LEFT_UPPER); //-- Will create the text object for the Symbol's name TextObj(0,"Symbol Name",Symbol(),5,23); //-- Will create the text object for the contract size TextObj(0,"Symbol Contract Size","Contract Size: "+string(ContractSize()),5,40,CORNER_LEFT_UPPER,9); //-- Will create the text object for the Symbol's Minimum lotsize TextObj(0,"Symbol MinLot","Minimum Lot: "+string(LotsMin()),5,60,CORNER_LEFT_UPPER,9); //-- Will create the text object for the Symbol's Maximum lotsize TextObj(0,"Symbol MaxLot","Max Lot: "+string(LotsMax()),5,80,CORNER_LEFT_UPPER,9); //-- Will create the text object for the Symbol's Volume Step TextObj(0,"Symbol Volume Step","Volume Step: "+string(LotsStep()),5,100,CORNER_LEFT_UPPER,9); //-- Will create the text object for the Symbol's Volume Limit TextObj(0,"Symbol Volume Limit","Volume Limit: "+string(LotsLimit()),5,120,CORNER_LEFT_UPPER,9); //-- Will create the text object for the trader's Risk Option TextObj(0,"Risk Option","Risk Option: "+CRisk.GetRiskOption(),5,140,CORNER_LEFT_UPPER,9); //-- Will create the text object for the trader's Risk Floor TextObj(0,"Risk Floor","Risk Floor: "+CRisk.GetRiskFloor(),5,160,CORNER_LEFT_UPPER,9); //-- Will create the text object for the trader's Risk Ceiling TextObj(0,"Risk Ceil","Risk Ceiling: "+CRisk.GetRiskCeil(),5,180,CORNER_LEFT_UPPER,9); }
Experte
Auch in diesem Artikel werden wir keine Handelsgeschäfte eröffnen.//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ //--- width and height of the canvas (used for drawing) #define IMG_WIDTH 200 #define IMG_HEIGHT 100 //--- enable to set color format ENUM_COLOR_FORMAT clr_format=COLOR_FORMAT_XRGB_NOALPHA; //--- drawing array (buffer) uint ExtImg[IMG_WIDTH*IMG_HEIGHT]; #include "News.mqh" CNews NewsObject;//Class CNews Object 'NewsObject' #include "TimeManagement.mqh" CTimeManagement CTM;//Class CTimeManagement Object 'CTM' #include "WorkingWithFolders.mqh" CFolders Folder();//Calling Class's Constructor #include "ChartProperties.mqh" CChartProperties CChart;//Class CChartProperties Object 'CChart' #include "RiskManagement.mqh" CRiskManagement CRisk;//Class CRiskManagement Object 'CRisk' #include "CommonGraphics.mqh" CCommonGraphics CGraphics();//Calling Class's Constructor enum iSeparator { Delimiter//__________________________ }; sinput group "+--------| RISK MANAGEMENT |--------+"; input RiskOptions RISK_Type=MINIMUM_LOT;//SELECT RISK OPTION input RiskFloor RISK_Mini=RiskFloorMin;//RISK FLOOR input double RISK_Mini_Percent=75;//MAX-RISK [100<-->0.01]% input RiskCeil RISK_Maxi=RiskCeilMax;//RISK CEILING sinput iSeparator iRisk_1=Delimiter;//__________________________ sinput iSeparator iRisk_1L=Delimiter;//PERCENTAGE OF [BALANCE | FREE-MARGIN] input double Risk_1_PERCENTAGE=3;//[100<-->0.01]% sinput iSeparator iRisk_2=Delimiter;//__________________________ sinput iSeparator iRisk_2L=Delimiter;//AMOUNT PER [BALANCE | FREE-MARGIN] input double Risk_2_VALUE=1000;//[BALANCE | FREE-MARGIN] input double Risk_2_AMOUNT=10;//EACH AMOUNT sinput iSeparator iRisk_3=Delimiter;//__________________________ sinput iSeparator iRisk_3L=Delimiter;//LOTSIZE PER [BALANCE | FREE-MARGIN] input double Risk_3_VALUE=1000;//[BALANCE | FREE-MARGIN] input double Risk_3_LOTSIZE=0.1;//EACH LOTS(VOLUME) sinput iSeparator iRisk_4=Delimiter;//__________________________ sinput iSeparator iRisk_4L=Delimiter;//CUSTOM LOTSIZE input double Risk_4_LOTSIZE=0.01;//LOTS(VOLUME) sinput iSeparator iRisk_5=Delimiter;//__________________________ sinput iSeparator iRisk_5L=Delimiter;//PERCENTAGE OF MAX-RISK input double Risk_5_PERCENTAGE=1;//[100<-->0.01]% //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //Initializing CRiskManagement variable for Risk options RiskProfileOption = RISK_Type; //Initializing CRiskManagement variable for Risk floor RiskFloorOption = RISK_Mini; //Initializing CRiskManagement variable for RiskFloorMax RiskFloorPercentage = (RISK_Mini_Percent>100)?100: (RISK_Mini_Percent<0.01)?0.01:RISK_Mini_Percent;//Percentage cannot be more than 100% or less than 0.01% //Initializing CRiskManagement variable for Risk ceiling RiskCeilOption = RISK_Maxi; //Initializing CRiskManagement variable for Risk options (PERCENTAGE OF BALANCE and PERCENTAGE OF FREE-MARGIN) Risk_Profile_1 = (Risk_1_PERCENTAGE>100)?100: (Risk_1_PERCENTAGE<0.01)?0.01:Risk_1_PERCENTAGE;//Percentage cannot be more than 100% or less than 0.01% //Initializing CRiskManagement variables for Risk options (AMOUNT PER BALANCE and AMOUNT PER FREE-MARGIN) Risk_Profile_2.RiskAmountBoF = Risk_2_VALUE; Risk_Profile_2.RiskAmount = Risk_2_AMOUNT; //Initializing CRiskManagement variables for Risk options (LOTSIZE PER BALANCE and LOTSIZE PER FREE-MARGIN) Risk_Profile_3.RiskLotBoF = Risk_3_VALUE; Risk_Profile_3.RiskLot = Risk_3_LOTSIZE; //Initializing CRiskManagement variable for Risk option (CUSTOM LOTSIZE) Risk_Profile_4 = Risk_4_LOTSIZE; //Initializing CRiskManagement variable for Risk option (PERCENTAGE OF MAX-RISK) Risk_Profile_5 = (Risk_5_PERCENTAGE>100)?100: (Risk_5_PERCENTAGE<0.01)?0.01:Risk_5_PERCENTAGE;//Percentage cannot be more than 100% or less than 0.01% CChart.ChartRefresh();//Load chart configurations CGraphics.GraphicsRefresh();//-- Create/Re-create chart objects if(!MQLInfoInteger(MQL_TESTER))//Checks whether the program is in the strategy tester { //--- create OBJ_BITMAP_LABEL object for drawing ObjectCreate(0,"STATUS",OBJ_BITMAP_LABEL,0,0,0); ObjectSetInteger(0,"STATUS",OBJPROP_XDISTANCE,5); ObjectSetInteger(0,"STATUS",OBJPROP_YDISTANCE,22); //--- specify the name of the graphical resource ObjectSetString(0,"STATUS",OBJPROP_BMPFILE,"::PROGRESS"); uint w,h; // variables for receiving text string sizes uint x,y; // variables for calculation of the current coordinates of text string anchor points /* In the Do while loop below, the code will check if the terminal is connected to the internet. If the the program is stopped the loop will break, if the program is not stopped and the terminal is connected to the internet the function CreateEconomicDatabase will be called from the News.mqh header file's object called NewsObject and the loop will break once called. */ bool done=false; do { //--- clear the drawing buffer array ArrayFill(ExtImg,0,IMG_WIDTH*IMG_HEIGHT,0); if(!TerminalInfoInteger(TERMINAL_CONNECTED)) { //-- integer dots used as a loading animation static int dots=0; //--- set the font TextSetFont("Arial",-150,FW_EXTRABOLD,0); TextGetSize("Waiting",w,h);//get text width and height values //--- calculate the coordinates of the 'Waiting' text x=10;//horizontal alignment y=IMG_HEIGHT/2-(h/2);//alignment for the text to be centered vertically //--- output the 'Waiting' text to ExtImg[] buffer TextOut("Waiting",x,y,TA_LEFT|TA_TOP,ExtImg,IMG_WIDTH,IMG_HEIGHT,ColorToARGB(CChart.SymbolBackground()),clr_format); //--- calculate the coordinates for the dots after the 'Waiting' text x=w+13;//horizontal alignment y=IMG_HEIGHT/2-(h/2);//alignment for the text to be centered vertically TextSetFont("Arial",-160,FW_EXTRABOLD,0); //--- output of dots to ExtImg[] buffer TextOut(StringSubstr("...",0,dots),x,y,TA_LEFT|TA_TOP,ExtImg,IMG_WIDTH,IMG_HEIGHT,ColorToARGB(CChart.SymbolBackground()),clr_format); //--- update the graphical resource ResourceCreate("::PROGRESS",ExtImg,IMG_WIDTH,IMG_HEIGHT,0,0,IMG_WIDTH,clr_format); //--- force chart update ChartRedraw(); dots=(dots==3)?0:dots+1; //-- Notify user that program is waiting for connection Print("Waiting for connection..."); Sleep(500); continue; } else { //--- set the font TextSetFont("Arial",-120,FW_EXTRABOLD,0); TextGetSize("Getting Ready",w,h);//get text width and height values x=20;//horizontal alignment y=IMG_HEIGHT/2-(h/2);//alignment for the text to be centered vertically //--- output the text 'Getting Ready...' to ExtImg[] buffer TextOut("Getting Ready...",x,y,TA_LEFT|TA_TOP,ExtImg,IMG_WIDTH,IMG_HEIGHT,ColorToARGB(CChart.SymbolBackground()),clr_format); //--- update the graphical resource ResourceCreate("::PROGRESS",ExtImg,IMG_WIDTH,IMG_HEIGHT,0,0,IMG_WIDTH,clr_format); //--- force chart update ChartRedraw(); //-- Notify user that connection is successful Print("Connection Successful!"); NewsObject.CreateEconomicDatabase();//calling the database create function done=true; } } while(!done&&!IsStopped()); //-- Delete chart object ObjectDelete(0,"STATUS"); //-- force chart to update ChartRedraw(); } else { //Checks whether the database file exists if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON)) { Print("Necessary Files Do not Exist!"); Print("Run Program outside of the Strategy Tester"); Print("Necessary Files Should be Created First"); return(INIT_FAILED); } else { //Checks whether the lastest database date includes the time and date being tested datetime latestdate = CTM.TimePlusOffset(NewsObject.GetLatestNewsDate(),CTM.DaysS());//Day after the lastest recorded time in the database if(latestdate<TimeCurrent()) { Print("Necessary Files outdated!"); Print("To Update Files: Run Program outside of the Strategy Tester"); } Print("Database Dates End at: ",latestdate); PrintFormat("Dates after %s will not be available for backtest",TimeToString(latestdate)); } } //-- the volume calculations and the risk type set by the trader Print("Lots: ",CRisk.Volume()," || Risk type: ",CRisk.GetRiskOption()); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+
Sobald alles kompiliert ist, werden wir einige Schritte durchgehen, die erfolgen, sobald der Experte auf dem Chart platziert ist.
Sobald Sie sich entschieden haben, welches Symbol-Chart-Fenster Sie öffnen möchten, könnte Ihr Chart ähnlich wie der obige Chart aussehen, bevor Sie den Experten auf ihm starten.
Jetzt werden wir den Experten starten.
Zunächst können wir die Eingabevariablen für das Risikomanagement konfigurieren, wobei ich die Standardwerte zunächst beibehalten werde.
Wenn Sie NewsTrading 2.00 zum ersten Mal ausführen und zuvor nicht NewsTrading 1.00 auf Ihrem Broker ausgeführt haben und die Kalenderdatenbank nicht im gemeinsamen Ordner vorhanden ist.
Ihr Chart wird auf diese Weise angezeigt, die Farben des Charts können sich von Broker zu Broker unterscheiden.
Wie in der nachstehenden Meldung zu sehen ist, werden die Lose entsprechend den in den Einstellungen ausgewählten Risikooptionen angezeigt.
Wenn das Terminal keine Verbindung findet.
Wenn Sie NewsTrading 2.00 Expert zum ersten Mal ausführen und die Kalenderdatenbank von NewsTrading 1.00 Expert erstellt wurde.
NewsTrading 2.00 wird alle Tabellen von NewsTrading 1.00 löschen.
Schlussfolgerung
In diesem Artikel haben wir untersucht, wie Vererbung funktioniert, mit einem Beispiel zur Veranschaulichung. Wir haben eine neue Klasse für die Sommerzeit erstellt, die als übergeordnete Klasse für die verschiedenen Klassen des Sommerzeitplans fungiert. Wir haben eine Klasse für Symboleigenschaften erstellt, um Symboleigenschaften von allen Klassen abzurufen, die von ihr erben. Wir haben auch eine Charteigenschaftsklasse erstellt, um das Chart anzupassen. Wir haben uns verschiedene SQLite-Methoden und eine einfache Möglichkeit zur Verbesserung der Gesamteffizienz der Datenbank angesehen. Wir haben eine Klasse für Objekteigenschaften erstellt, um Chartobjekte zu erstellen und zu löschen, und eine Klasse für Risikomanagement, um verschiedene Risikoprofile und Händler zu berücksichtigen. Schließlich haben wir die letzte Klasse namens Common Graphics erstellt, um die Symboleigenschaften zusammen mit den Risikooptionen des Händlers im Chart anzuzeigen. Im nächsten Artikel, „Nachrichtenhandel leicht gemacht (Teil 3): Durchführen von Handelsgeschäften“ werden wir endlich mit der Eröffnung von Geschäften beginnen, und ich kann es kaum erwarten, es in einem vernünftigen Zeitrahmen fertigzustellen!
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/14912
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.