From 5287625b0802d25cacf0e0db1207ed0a6d31dfc6 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 17 Nov 2022 19:29:42 +0100 Subject: [PATCH 01/42] WIP. Writing stubs/most important methods' implementations for Emscripten. --- Array.extern.h | 48 +++++-- Common.extern.h | 10 +- Convert.mqh | 2 + DateTime.entry.h | 171 +++++++++++++++++++++++++ DateTime.extern.h | 33 +++-- DateTime.mqh | 19 ++- DateTime.static.h | 207 +++++++++++++++++++++++++++++++ DateTime.struct.h | 309 ---------------------------------------------- Math.extern.h | 52 ++++++-- PlatformTime.h | 89 +++++++++++++ Std.h | 10 ++ String.extern.h | 35 ++++-- 12 files changed, 628 insertions(+), 357 deletions(-) create mode 100644 DateTime.entry.h create mode 100644 DateTime.static.h create mode 100644 PlatformTime.h diff --git a/Array.extern.h b/Array.extern.h index 4b6580d4d..f95f26d3c 100644 --- a/Array.extern.h +++ b/Array.extern.h @@ -24,36 +24,64 @@ #ifndef __MQL__ #pragma once +#include "Common.extern.h" #include "Std.h" +#include "String.extern.h" template -extern int ArraySize(const ARRAY_REF(T, _array)); +int ArraySize(const ARRAY_REF(T, _array)) { + return _array.size(); +} template -extern constexpr int ArraySize(const T REF(_array)[size]); +constexpr int ArraySize(const T REF(_array)[size]); template -extern int ArrayResize(ARRAY_REF(T, _array), int _new_size, int _reserve_size = 0); +int ArrayResize(ARRAY_REF(T, _array), int _new_size, int _reserve_size = 0) { + _array.resize(_new_size, _reserve_size); + return _new_size; +} template -extern bool ArraySetAsSeries(ARRAY_REF(T, _array), bool _flag); +bool ArraySetAsSeries(ARRAY_REF(T, _array), bool _flag) { + _array.setIsSeries(_flag); + return true; +} template -extern int ArrayMaximum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY); +int ArrayMaximum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} template -extern int ArrayMinimum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY); +int ArrayMinimum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} template -extern int ArrayFree(const ARRAY_REF(T, _array)); +int ArrayFree(ARRAY_REF(T, _array)) { + _array.resize(0, 0); + return 0; +} template -extern int ArrayReverse(const ARRAY_REF(T, _array)); +bool ArrayReverse(ARRAY_REF(T, _array)) { + _array.reverse(); + return true; +} template -extern int ArrayInitialize(ARRAY_REF(T, array), char value); +extern int ArrayInitialize(ARRAY_REF(T, array), char value) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} template -extern int ArraySort(ARRAY_REF(T, array)); +extern int ArraySort(ARRAY_REF(T, array)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} #endif diff --git a/Common.extern.h b/Common.extern.h index 03a90a139..3f6a5a840 100644 --- a/Common.extern.h +++ b/Common.extern.h @@ -23,12 +23,18 @@ // Define external global functions. #ifndef __MQL__ #pragma once +#include + #include "Chart.enum.h" #include "DateTime.enum.h" +#include "Terminal.define.h" + +void DebugBreak() { raise(SIGTRAP); } + +int _LastError = 0; -extern void DebugBreak(); // Errors. -extern void SetUserError(unsigned short user_error); +void SetUserError(unsigned short user_error) { _LastError = ERR_USER_ERROR_FIRST + user_error; } // Exceptions. extern int NotImplementedException(); // Print-related functions. diff --git a/Convert.mqh b/Convert.mqh index b371eeeca..dbc15b87c 100644 --- a/Convert.mqh +++ b/Convert.mqh @@ -30,6 +30,8 @@ #include "Account/Account.extern.h" #include "Array.mqh" #include "Convert.extern.h" +#include "DateTime.extern.h" +#include "DateTime.mqh" #include "Math.extern.h" #include "Order.enum.h" #include "SymbolInfo.enum.h" diff --git a/DateTime.entry.h b/DateTime.entry.h new file mode 100644 index 000000000..c99d8d27f --- /dev/null +++ b/DateTime.entry.h @@ -0,0 +1,171 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes DateTime's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "DateTime.static.h" +#include "PlatformTime.h" + +struct DateTimeEntry : MqlDateTime { + int week_of_year; + // Struct constructors. + DateTimeEntry() { Set(); } + DateTimeEntry(datetime _dt) { Set(_dt); } + DateTimeEntry(MqlDateTime& _dt) { + Set(_dt); +#ifndef __MQL__ + throw NotImplementedException(); +#endif + } + // Getters. + int GetDayOfMonth() { return day; } + int GetDayOfWeek() { + // Returns the zero-based day of week. + // (0-Sunday, 1-Monday, ... , 6-Saturday). + return day_of_week; + } + int GetDayOfYear() { return day_of_year + 1; } // Zero-based day of year (1st Jan = 0). + int GetHour() { return hour; } + int GetMinute() { return min; } + int GetMonth() { return mon; } + int GetSeconds() { return sec; } + // int GetWeekOfYear() { return week_of_year; } // @todo + int GetValue(ENUM_DATETIME_UNIT _unit) { + int _result = -1; + switch (_unit) { + case DATETIME_SECOND: + return GetSeconds(); + case DATETIME_MINUTE: + return GetMinute(); + case DATETIME_HOUR: + return GetHour(); + case DATETIME_DAY: + return GetDayOfMonth(); + case DATETIME_WEEK: + return -1; // return WeekOfYear(); // @todo + case DATETIME_MONTH: + return GetMonth(); + case DATETIME_YEAR: + return GetYear(); + default: + break; + } + return _result; + } + unsigned int GetValue(unsigned int _unit) { + if ((_unit & (DATETIME_DAY | DATETIME_WEEK)) != 0) { + return GetDayOfWeek(); + } else if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { + return GetDayOfMonth(); + } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { + return GetDayOfYear(); + } + return GetValue((ENUM_DATETIME_UNIT)_unit); + } + int GetYear() { return year; } + datetime GetTimestamp() { return StructToTime(THIS_REF); } + // Setters. + void Set() { + TimeToStruct(PlatformTime::CurrentTimestamp(), THIS_REF); + // @fixit Should also set day of week. + } + void SetGMT() { + TimeToStruct(::TimeGMT(), THIS_REF); + // @fixit Should also set day of week. + } + // Set date and time. + void Set(datetime _time) { + TimeToStruct(_time, THIS_REF); + // @fixit Should also set day of week. + } + // Set date and time. + void Set(MqlDateTime& _time) { + THIS_REF = _time; + // @fixit Should also set day of week. + } + void SetDayOfMonth(int _value) { + day = _value; + day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. + day_of_year = DateTimeStatic::DayOfYear(); // Zero-based day of year. + } + void SetDayOfYear(int _value) { + day_of_year = _value - 1; // Sets zero-based day of year. + day = DateTimeStatic::Month(); // Sets day of month (1..31). + day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. + } + void SetHour(int _value) { hour = _value; } + void SetMinute(int _value) { min = _value; } + void SetMonth(int _value) { mon = _value; } + void SetSeconds(int _value) { sec = _value; } + void SetWeekOfYear(int _value) { + week_of_year = _value; + // day = @todo; + // day_of_week = @todo; + // day_of_year = @todo; + } + void SetValue(ENUM_DATETIME_UNIT _unit, int _value) { + switch (_unit) { + case DATETIME_SECOND: + SetSeconds(_value); + break; + case DATETIME_MINUTE: + SetMinute(_value); + break; + case DATETIME_HOUR: + SetHour(_value); + break; + case DATETIME_DAY: + SetDayOfMonth(_value); + break; + case DATETIME_WEEK: + SetWeekOfYear(_value); + break; + case DATETIME_MONTH: + SetMonth(_value); + break; + case DATETIME_YEAR: + SetYear(_value); + break; + default: + break; + } + } + void SetValue(unsigned short _unit, int _value) { + if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { + SetDayOfMonth(_value); + } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { + SetDayOfYear(_value); + } else { + SetValue((ENUM_DATETIME_UNIT)_unit, _value); + } + } + void SetYear(int _value) { year = _value; } +}; diff --git a/DateTime.extern.h b/DateTime.extern.h index e3dee2b4f..0ece67d69 100644 --- a/DateTime.extern.h +++ b/DateTime.extern.h @@ -42,21 +42,18 @@ class datetime { time_t dt; public: - datetime(); - datetime(const long& _time); + datetime() { dt = 0; } + datetime(const long& _time) { dt = _time; } datetime(const int& _time); - bool operator==(const int _time) const; - bool operator==(const datetime& _time) const; - bool operator<(const int _time) const; - bool operator>(const int _time) const; - bool operator<(const datetime& _time); - bool operator>(const datetime& _time); - operator long() const; + bool operator==(const int _time) const = delete; + bool operator==(const datetime& _time) const { return dt == _time; } + bool operator<(const int _time) const = delete; + bool operator>(const int _time) const = delete; + bool operator<(const datetime& _time) const { return dt < _time; } + bool operator>(const datetime& _time) const { return dt > _time; } + operator long() const { return dt; } }; -extern datetime TimeCurrent(); -extern datetime TimeCurrent(MqlDateTime& dt_struct); - extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(datetime, time_array)); @@ -73,10 +70,20 @@ extern datetime TimeGMT(MqlDateTime& dt_struct); extern datetime TimeTradeServer(); extern datetime TimeTradeServer(MqlDateTime& dt_struct); extern datetime StringToTime(const string& value); -extern string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES); +string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES) { + /* + auto now = std::chrono::time_point(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); + */ + std::stringstream ss; + ss << __FUNCTION__ << " is not yet implemented!"; + // ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X"); + return ss.str(); +} template extern datetime operator"" _D(); #define DATETIME_LITERAL(STR) _D " ## STR ## " + #endif diff --git a/DateTime.mqh b/DateTime.mqh index df9fc38a3..2f9e1fa30 100644 --- a/DateTime.mqh +++ b/DateTime.mqh @@ -39,9 +39,12 @@ struct DataParamEntry; // Includes class enum and structs. #include "Array.mqh" #include "Data.struct.h" +#include "DateTime.entry.h" #include "DateTime.enum.h" #include "DateTime.extern.h" +#include "DateTime.static.h" #include "DateTime.struct.h" +#include "PlatformTime.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compatibility). @@ -61,7 +64,7 @@ class DateTime { /** * Class constructor. */ - DateTime() { TimeToStruct(TimeCurrent(), dt_curr); } + DateTime() { TimeToStruct(PlatformTime::CurrentTimestamp(), dt_curr); } DateTime(DateTime &r) : dt_curr(r.dt_curr), dt_last(r.dt_last) {} DateTime(DateTimeEntry &_dt) { dt_curr = _dt; } DateTime(MqlDateTime &_dt) { dt_curr = _dt; } @@ -198,7 +201,7 @@ class DateTime { /** * Updates datetime to the current one. */ - void Update() { dt_curr.Set(TimeCurrent()); } + void Update() { dt_curr.Set(PlatformTime::CurrentTimestamp()); } /* Conditions */ @@ -238,4 +241,16 @@ class DateTime { return DateTime::CheckCondition(_cond, _args); } }; + +#ifndef __MQL__ + +datetime TimeCurrent() { return PlatformTime::CurrentTimestamp(); } + +datetime TimeCurrent(MqlDateTime &dt_struct) { + dt_struct = PlatformTime::CurrentTime(); + return PlatformTime::CurrentTimestamp(); +} + +#endif + #endif // DATETIME_MQH diff --git a/DateTime.static.h b/DateTime.static.h new file mode 100644 index 000000000..1b5950128 --- /dev/null +++ b/DateTime.static.h @@ -0,0 +1,207 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes DateTime's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "DateTime.static.h" +#include "PlatformTime.h" + +/* + * Struct to provide static date and time methods. + */ +struct DateTimeStatic { + /** + * Returns the current day of the month (e.g. the day of month of the last known server time). + */ + static int Day(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::TimeDay(dt); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.day; +#endif + } + + /** + * Returns the current zero-based day of the week of the last known server time. + */ + static int DayOfWeek(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::DayOfWeek(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.day_of_week; +#endif + } + + /** + * Returns the current day of the year (e.g. the day of year of the last known server time). + */ + static int DayOfYear(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::DayOfYear(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.day_of_year + 1; +#endif + } + + /** + * Returns the hour of the last known server time by the moment of the program start. + */ + static int Hour(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Hour(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.hour; +#endif + } + + /** + * Check whether market is within peak hours. + */ + static bool IsPeakHour() { + MqlDateTime dt; + TimeToStruct(::TimeGMT(), dt); + return dt.hour >= 8 && dt.hour <= 16; + } + + /** + * Returns the current minute of the last known server time by the moment of the program start. + */ + static int Minute(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Minute(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.min; +#endif + } + + /** + * Returns the current month as number (e.g. the number of month of the last known server time). + */ + static int Month(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Month(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.mon; +#endif + } + + /** + * Returns the amount of seconds elapsed from the beginning of the current minute of the last known server time. + */ + static int Seconds(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Seconds(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.sec; +#endif + } + + /** + * Converts a time stamp into a string of "yyyy.mm.dd hh:mi" format. + */ + static string TimeToStr(datetime value, int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { +#ifdef __MQL4__ + return ::TimeToStr(value, mode); +#else // __MQL5__ + // #define TimeToStr(value, mode) DateTime::TimeToStr(value, mode) + return ::TimeToString(value, mode); +#endif + } + static string TimeToStr(int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { + return TimeToStr(PlatformTime::CurrentTimestamp(), mode); + } + + /** + * Returns the current time of the trade server. + */ + static datetime TimeTradeServer() { +#ifdef __MQL4__ + // Unlike MQL5 TimeTradeServer(), + // TimeCurrent() returns the last known server time. + return ::TimeCurrent(); +#else + // The calculation of the time value is performed in the client terminal + // and depends on the time settings of your computer. + return ::TimeTradeServer(); +#endif + } + + /** + * Returns the current year (e.g. the year of the last known server time). + */ + static int Year(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Year(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.year; +#endif + } +}; diff --git a/DateTime.struct.h b/DateTime.struct.h index c03391a23..f33543193 100644 --- a/DateTime.struct.h +++ b/DateTime.struct.h @@ -30,9 +30,6 @@ #pragma once #endif -// Forward declarations. -struct DateTimeStatic; - // Includes. #include "DateTime.enum.h" #include "Std.h" @@ -56,309 +53,3 @@ struct MqlDateTime { int day_of_year; // Zero-based day number of the year (1st Jan = 0). }; #endif - -/* - * Struct to provide static date and time methods. - */ -struct DateTimeStatic { - /** - * Returns the current day of the month (e.g. the day of month of the last known server time). - */ - static int Day(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::TimeDay(dt); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.day; -#endif - } - - /** - * Returns the current zero-based day of the week of the last known server time. - */ - static int DayOfWeek(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::DayOfWeek(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.day_of_week; -#endif - } - - /** - * Returns the current day of the year (e.g. the day of year of the last known server time). - */ - static int DayOfYear(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::DayOfYear(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.day_of_year + 1; -#endif - } - - /** - * Returns the hour of the last known server time by the moment of the program start. - */ - static int Hour(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Hour(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.hour; -#endif - } - - /** - * Check whether market is within peak hours. - */ - static bool IsPeakHour() { - MqlDateTime dt; - TimeToStruct(::TimeGMT(), dt); - return dt.hour >= 8 && dt.hour <= 16; - } - - /** - * Returns the current minute of the last known server time by the moment of the program start. - */ - static int Minute(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Minute(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.min; -#endif - } - - /** - * Returns the current month as number (e.g. the number of month of the last known server time). - */ - static int Month(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Month(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.mon; -#endif - } - - /** - * Returns the amount of seconds elapsed from the beginning of the current minute of the last known server time. - */ - static int Seconds(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Seconds(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.sec; -#endif - } - - /** - * Converts a time stamp into a string of "yyyy.mm.dd hh:mi" format. - */ - static string TimeToStr(datetime value, int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { -#ifdef __MQL4__ - return ::TimeToStr(value, mode); -#else // __MQL5__ - // #define TimeToStr(value, mode) DateTime::TimeToStr(value, mode) - return ::TimeToString(value, mode); -#endif - } - static string TimeToStr(int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { return TimeToStr(TimeCurrent(), mode); } - - /** - * Returns the current time of the trade server. - */ - static datetime TimeTradeServer() { -#ifdef __MQL4__ - // Unlike MQL5 TimeTradeServer(), - // TimeCurrent() returns the last known server time. - return ::TimeCurrent(); -#else - // The calculation of the time value is performed in the client terminal - // and depends on the time settings of your computer. - return ::TimeTradeServer(); -#endif - } - - /** - * Returns the current year (e.g. the year of the last known server time). - */ - static int Year(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Year(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.year; -#endif - } -}; - -struct DateTimeEntry : MqlDateTime { - int week_of_year; - // Struct constructors. - DateTimeEntry() { Set(); } - DateTimeEntry(datetime _dt) { Set(_dt); } - DateTimeEntry(MqlDateTime& _dt) { - Set(_dt); -#ifndef __MQL__ - throw NotImplementedException(); -#endif - } - // Getters. - int GetDayOfMonth() { return day; } - int GetDayOfWeek() { - // Returns the zero-based day of week. - // (0-Sunday, 1-Monday, ... , 6-Saturday). - return day_of_week; - } - int GetDayOfYear() { return day_of_year + 1; } // Zero-based day of year (1st Jan = 0). - int GetHour() { return hour; } - int GetMinute() { return min; } - int GetMonth() { return mon; } - int GetSeconds() { return sec; } - // int GetWeekOfYear() { return week_of_year; } // @todo - int GetValue(ENUM_DATETIME_UNIT _unit) { - int _result = -1; - switch (_unit) { - case DATETIME_SECOND: - return GetSeconds(); - case DATETIME_MINUTE: - return GetMinute(); - case DATETIME_HOUR: - return GetHour(); - case DATETIME_DAY: - return GetDayOfMonth(); - case DATETIME_WEEK: - return -1; // return WeekOfYear(); // @todo - case DATETIME_MONTH: - return GetMonth(); - case DATETIME_YEAR: - return GetYear(); - default: - break; - } - return _result; - } - unsigned int GetValue(unsigned int _unit) { - if ((_unit & (DATETIME_DAY | DATETIME_WEEK)) != 0) { - return GetDayOfWeek(); - } else if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { - return GetDayOfMonth(); - } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { - return GetDayOfYear(); - } - return GetValue((ENUM_DATETIME_UNIT)_unit); - } - int GetYear() { return year; } - datetime GetTimestamp() { return StructToTime(THIS_REF); } - // Setters. - void Set() { - TimeToStruct(::TimeCurrent(), THIS_REF); - // @fixit Should also set day of week. - } - void SetGMT() { - TimeToStruct(::TimeGMT(), THIS_REF); - // @fixit Should also set day of week. - } - // Set date and time. - void Set(datetime _time) { - TimeToStruct(_time, THIS_REF); - // @fixit Should also set day of week. - } - // Set date and time. - void Set(MqlDateTime& _time) { - THIS_REF = _time; - // @fixit Should also set day of week. - } - void SetDayOfMonth(int _value) { - day = _value; - day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. - day_of_year = DateTimeStatic::DayOfYear(); // Zero-based day of year. - } - void SetDayOfYear(int _value) { - day_of_year = _value - 1; // Sets zero-based day of year. - day = DateTimeStatic::Month(); // Sets day of month (1..31). - day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. - } - void SetHour(int _value) { hour = _value; } - void SetMinute(int _value) { min = _value; } - void SetMonth(int _value) { mon = _value; } - void SetSeconds(int _value) { sec = _value; } - void SetWeekOfYear(int _value) { - week_of_year = _value; - // day = @todo; - // day_of_week = @todo; - // day_of_year = @todo; - } - void SetValue(ENUM_DATETIME_UNIT _unit, int _value) { - switch (_unit) { - case DATETIME_SECOND: - SetSeconds(_value); - break; - case DATETIME_MINUTE: - SetMinute(_value); - break; - case DATETIME_HOUR: - SetHour(_value); - break; - case DATETIME_DAY: - SetDayOfMonth(_value); - break; - case DATETIME_WEEK: - SetWeekOfYear(_value); - break; - case DATETIME_MONTH: - SetMonth(_value); - break; - case DATETIME_YEAR: - SetYear(_value); - break; - default: - break; - } - } - void SetValue(unsigned short _unit, int _value) { - if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { - SetDayOfMonth(_value); - } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { - SetDayOfYear(_value); - } else { - SetValue((ENUM_DATETIME_UNIT)_unit, _value); - } - } - void SetYear(int _value) { year = _value; } -}; diff --git a/Math.extern.h b/Math.extern.h index 4dce9bfe7..07434b946 100644 --- a/Math.extern.h +++ b/Math.extern.h @@ -22,28 +22,56 @@ // Define external global functions. #ifndef __MQL__ +#pragma once + +#include + template -extern T MathAbs(T value); +T MathAbs(T value) { + return std::abs(value); +} template -extern T fabs(T value); +T fabs(T value) { + return std::abs(value); +} template -extern T pow(T base, T exponent); +T pow(T base, T exponent) { + return (T)std::pow(base, exponent); +} template -extern T MathPow(T base, T exponent); +T MathPow(T base, T exponent) { + return std::pow(base, exponent); +} template -extern T round(T value); +T round(T value) { + return std::round(value); +} template -extern T MathRound(T value); +T MathRound(T value) { + return std::round(value); +} template -extern T fmax(T value1, T value2); +T fmax(T value1, T value2) { + return std::max(value1, value2); +} template -extern T MathMax(T value1, T value2); +T MathMax(T value1, T value2) { + return std::max(value1, value2); +} template -extern T fmin(T value1, T value2); +T fmin(T value1, T value2) { + return std::min(value1, value2); +} template -extern T MathMin(T value1, T value2); +T MathMin(T value1, T value2) { + return std::min(value1, value2); +} template -extern T MathLog10(T value1); +T MathLog10(T value) { + return std::log10(value); +} template -extern T log10(T value); +T log10(T value) { + return std::log10(value); +} #endif diff --git a/PlatformTime.h b/PlatformTime.h new file mode 100644 index 000000000..8e62646f5 --- /dev/null +++ b/PlatformTime.h @@ -0,0 +1,89 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Includes. +#include "DateTime.enum.h" +#include "DateTime.mqh" +#include "DateTime.struct.h" + +/** + * @file + * Platform time retrieval. + */ +#ifndef __MQL__ +#pragma once + +// Includes. +#include +#include +#include "DateTime.struct.h" + +class PlatformTime { + static MqlDateTime current_time; + static long current_timestamp_s; + static long current_timestamp_ms; + + public: + static long CurrentTimestamp() { return current_timestamp_s; } + static long CurrentTimestampMs() { return current_timestamp_ms; } + static MqlDateTime CurrentTime() { return current_time; } + + void static Tick() { +#ifdef __MQL__ + static _last_time_ms = 0; + + current_time_s = ::TimeCurrent(¤t_time); + + current_time_ms = (long)GetTickCount(); + + if (_last_time_ms != 0 && current_time_ms < _last_time_ms) { + // Overflow occured (49.7 days passed). + // More info: https://docs.mql4.com/common/gettickcount + current_time_ms += _last_time_ms; + } + + _last_time_ms = current_time_ms; +#else + using namespace std::chrono; + current_timestamp_s = (long)duration_cast(system_clock::now().time_since_epoch()).count(); + current_timestamp_ms = (long)duration_cast(system_clock::now().time_since_epoch()).count(); + + using namespace std::chrono; + std::time_t t = std::time(0); + std::tm* now = std::localtime(&t); + current_time.day = now->tm_mday; + current_time.day_of_week = now->tm_wday; + current_time.day_of_year = now->tm_yday; + current_time.hour = now->tm_hour; + current_time.min = now->tm_min; + current_time.mon = now->tm_mon; + current_time.sec = now->tm_sec; + current_time.year = now->tm_year; +#endif + } +}; + +MqlDateTime PlatformTime::current_time{0, 0, 0, 0, 0, 0, 0, 0}; +long PlatformTime::current_timestamp_s = 0; +long PlatformTime::current_timestamp_ms = 0; + +#endif diff --git a/Std.h b/Std.h index 76ed66e47..2a982cb78 100644 --- a/Std.h +++ b/Std.h @@ -166,6 +166,8 @@ class _cpp_array { m_isSeries = r.m_isSeries; } + std::vector& str() { return m_data; } + void operator=(const _cpp_array& r) { m_data = r.m_data; m_isSeries = r.m_isSeries; @@ -196,6 +198,14 @@ class _cpp_array { */ int size() const { return (int)m_data.size(); } + void resize(int new_size, int reserve_size = 0) { + // E.g., size = 10, new_size = 90, reserve_size = 50 + // thus: new_reserve_size = new_size + reserve_size - (new_size % reserve_size) + // which is: 90 + reserve_size - (90 % reserve_size) = 90 + 50 - 40 = 100. + m_data.reserve(new_size + reserve_size - (new_size % reserve_size)); + m_data.resize(new_size); + } + /** * Checks whether */ diff --git a/String.extern.h b/String.extern.h index b59fb5a0d..943c7df61 100644 --- a/String.extern.h +++ b/String.extern.h @@ -29,15 +29,32 @@ // Define external global functions. #ifndef __MQL__ -extern double StringToDouble(string value); -extern int StringFind(string string_value, string match_substring, int start_pos = 0); -extern int StringLen(string string_value); -extern int StringSplit(const string& string_value, const unsigned short separator, ARRAY_REF(string, result)); -extern long StringToInteger(string value); -extern string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol = ' '); -extern string StringFormat(string format, ...); -extern string StringSubstr(string string_value, int start_pos, int length = -1); -extern unsigned short StringGetCharacter(string string_value, int pos); +double StringToDouble(string value) { return std::stod(value); } + +auto StringFind(const string string_value, string match_substring, int start_pos = 0) -> int { + return string_value.find(match_substring); +} +int StringLen(string string_value) { return string_value.size(); } +int StringSplit(const string& string_value, const unsigned short separator, ARRAY_REF(string, result)) { + auto start = 0U; + auto end = string_value.find((char)separator); + while (end != std::string::npos) { + result.str().push_back(string_value.substr(start, end - start)); + start = end + 1; // 1 - size of the separator. + end = string_value.find((char)separator, start); + } + return result.size(); +} +long StringToInteger(string value) { return std::stol(value); } +string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol = ' ') { + return std::to_string(number); +} + +string StringFormat(string format, ...); +string StringSubstr(string string_value, int start_pos, int length = -1) { + return string_value.substr(start_pos, length == -1 ? (string_value.size() - start_pos) : length); +} +unsigned short StringGetCharacter(string string_value, int pos); int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, unsigned int codepage = CP_ACP); #endif From d3936837ce0eae47e52bb34bc903ac8ab4e9cda7 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 30 Nov 2022 18:07:39 +0100 Subject: [PATCH 02/42] WIP. Added missing C++ methods regarding String printing/manipulations and conversion. --- Common.extern.h | 12 +-------- Convert.extern.h | 29 ++++++++++++++++----- String.extern.h | 66 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/Common.extern.h b/Common.extern.h index 3f6a5a840..61966cfb4 100644 --- a/Common.extern.h +++ b/Common.extern.h @@ -24,6 +24,7 @@ #ifndef __MQL__ #pragma once #include +#include #include "Chart.enum.h" #include "DateTime.enum.h" @@ -38,16 +39,5 @@ void SetUserError(unsigned short user_error) { _LastError = ERR_USER_ERROR_FIRST // Exceptions. extern int NotImplementedException(); // Print-related functions. -template -extern std::string StringFormat(const std::string& format, Args... args); - -template -extern std::string PrintFormat(const std::string& format, Args... args); - -template -extern void Print(Args... args); - -template -extern void Alert(Args... args); #endif diff --git a/Convert.extern.h b/Convert.extern.h index 4a5a02ed0..a2f4bd2db 100644 --- a/Convert.extern.h +++ b/Convert.extern.h @@ -23,12 +23,29 @@ // Prevents processing this includes file for the second time. #ifndef __MQL__ #pragma once -#endif + +// Includes. +#include +#include // Define external global functions. -#ifndef __MQL__ -extern double NormalizeDouble(double value, int digits); -extern string CharToString(unsigned char char_code); -extern string DoubleToString(double value, int digits = 8); -extern string ShortToString(unsigned short symbol_code); +double NormalizeDouble(double value, int digits) { return std::round(value / digits) * digits; } + +string CharToString(unsigned char char_code) { + std::stringstream ss; + ss << char_code; + return ss.str(); +} + +string DoubleToString(double value, int digits = 8) { + std::stringstream ss; + ss << std::setprecision(digits) << value; + return ss.str(); +} + +string ShortToString(unsigned short symbol_code) { + std::stringstream ss; + ss << symbol_code; + return ss.str(); +} #endif diff --git a/String.extern.h b/String.extern.h index 943c7df61..b1043fd2b 100644 --- a/String.extern.h +++ b/String.extern.h @@ -23,12 +23,18 @@ // Prevents processing this includes file for the second time. #ifndef __MQL__ #pragma once + +// Includes. +#include + +#include +#include +#include + #include "Std.h" #include "Terminal.define.h" -#endif // Define external global functions. -#ifndef __MQL__ double StringToDouble(string value) { return std::stod(value); } auto StringFind(const string string_value, string match_substring, int start_pos = 0) -> int { @@ -50,11 +56,63 @@ string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol return std::to_string(number); } -string StringFormat(string format, ...); +template +struct TuplePrinter { + static void print(const std::string& fmt, std::ostream& os, const Tuple& t) { + const size_t idx = fmt.find_last_of('%'); + TuplePrinter::print(std::string(fmt, 0, idx), os, t); + os << std::get(t) << std::string(fmt, idx + 1); + } +}; + +template +struct TuplePrinter { + static void print(const std::string& fmt, std::ostream& os, const Tuple& t) { + const size_t idx = fmt.find_first_of('%'); + os << std::string(fmt, 0, idx) << std::get<0>(t) << std::string(fmt, idx + 1); + } +}; + +template +void PrintTo(std::ostream& out, Arg&& arg, Args&&... args) { + out << std::forward(arg); + using expander = int[]; + (void)expander{0, (void(out << std::forward(args)), 0)...}; +} + +template +void Print(Arg&& arg, Args&&... args) { + PrintTo(std::cout, arg, args...); +} + +template +void Alert(Arg&& arg, Args&&... args) { + PrintTo(std::cerr, arg, args...); +} + +template +std::string StringFormat(const std::string& fmt, Args&&... args) { + std::stringstream ss; + const auto t = std::make_tuple(std::forward(args)...); + TuplePrinter::print(fmt, ss, t); + return ss.str(); +} + +template +void PrintFormat(const std::string& fmt, Args&&... args) { + std::cout << StringFormat(fmt, args...) << std::endl; +} + string StringSubstr(string string_value, int start_pos, int length = -1) { return string_value.substr(start_pos, length == -1 ? (string_value.size() - start_pos) : length); } -unsigned short StringGetCharacter(string string_value, int pos); +unsigned short StringGetCharacter(string string_value, int pos) { + if (pos < 0 || pos >= string_value.size()) { + Alert("Character index out of string boundary! Position passed: ", pos, ", string passed: \"", string_value, "\""); + } + return string_value[pos]; +} + int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, unsigned int codepage = CP_ACP); #endif From e36c9c960f800b63f109eaef05ce8c42c50c0c0a Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 1 Dec 2022 18:23:17 +0100 Subject: [PATCH 03/42] WIP. Trying to run emscripten-generated code in the browser. --- Common.extern.h | 9 ++++++++- DateTime.extern.h | 5 +++-- Math.extern.h | 1 + Std.h | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Common.extern.h b/Common.extern.h index 61966cfb4..43bc7f98f 100644 --- a/Common.extern.h +++ b/Common.extern.h @@ -30,7 +30,14 @@ #include "DateTime.enum.h" #include "Terminal.define.h" -void DebugBreak() { raise(SIGTRAP); } +void DebugBreak() { +#ifdef _MSC_VER + // @see https://learn.microsoft.com/en-us/cpp/intrinsics/debugbreak?view=msvc-170 + __debugbreak(); +#else + raise(SIGTRAP); +#endif +} int _LastError = 0; diff --git a/DateTime.extern.h b/DateTime.extern.h index 0ece67d69..1ffb17098 100644 --- a/DateTime.extern.h +++ b/DateTime.extern.h @@ -29,6 +29,7 @@ // Includes. #include + #include "DateTime.enum.h" #include "String.mqh" @@ -44,7 +45,7 @@ class datetime { public: datetime() { dt = 0; } datetime(const long& _time) { dt = _time; } - datetime(const int& _time); + // datetime(const int& _time); bool operator==(const int _time) const = delete; bool operator==(const datetime& _time) const { return dt == _time; } bool operator<(const int _time) const = delete; @@ -82,7 +83,7 @@ string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES) { } template -extern datetime operator"" _D(); +datetime operator"" _D(); #define DATETIME_LITERAL(STR) _D " ## STR ## " diff --git a/Math.extern.h b/Math.extern.h index 07434b946..a19b60b13 100644 --- a/Math.extern.h +++ b/Math.extern.h @@ -24,6 +24,7 @@ #ifndef __MQL__ #pragma once +#include #include template diff --git a/Std.h b/Std.h index 2a982cb78..d85cd83ac 100644 --- a/Std.h +++ b/Std.h @@ -202,7 +202,10 @@ class _cpp_array { // E.g., size = 10, new_size = 90, reserve_size = 50 // thus: new_reserve_size = new_size + reserve_size - (new_size % reserve_size) // which is: 90 + reserve_size - (90 % reserve_size) = 90 + 50 - 40 = 100. - m_data.reserve(new_size + reserve_size - (new_size % reserve_size)); + if (reserve_size > 0) { + new_size = reserve_size - (new_size % reserve_size); + } + m_data.reserve(new_size); m_data.resize(new_size); } From 42409e33161df00389e41b60f6ce18e85f184c1f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 15 Dec 2022 18:16:04 +0100 Subject: [PATCH 04/42] WIP. Trying to make smart pointers to work in JS. --- Convert.extern.h | 4 +-- DateTime.mqh | 4 +-- DictSlot.mqh | 2 ++ DictStruct.mqh | 17 +++------- Object.extern.h | 9 ++++- Refs.struct.h | 56 ++++++++++++++++++++++++-------- Serializer/SerializerConverter.h | 16 ++++++--- Serializer/SerializerJson.h | 26 ++++++++------- String.extern.h | 2 ++ Task/Task.h | 27 ++++++++++----- Task/Task.struct.h | 16 +++++++++ Task/TaskManager.h | 25 +++++++++++--- Trade/TradeSignal.h | 9 +++++ Trade/TradeSignalManager.h | 12 +++++++ 14 files changed, 164 insertions(+), 61 deletions(-) diff --git a/Convert.extern.h b/Convert.extern.h index a2f4bd2db..a21d6599e 100644 --- a/Convert.extern.h +++ b/Convert.extern.h @@ -25,8 +25,8 @@ #pragma once // Includes. -#include #include +#include // Define external global functions. double NormalizeDouble(double value, int digits) { return std::round(value / digits) * digits; } @@ -45,7 +45,7 @@ string DoubleToString(double value, int digits = 8) { string ShortToString(unsigned short symbol_code) { std::stringstream ss; - ss << symbol_code; + ss << (char)symbol_code; return ss.str(); } #endif diff --git a/DateTime.mqh b/DateTime.mqh index 2f9e1fa30..ab7abd69a 100644 --- a/DateTime.mqh +++ b/DateTime.mqh @@ -129,8 +129,8 @@ class DateTime { } #ifdef __debug_verbose__ - string _passed = - "time now " + (string)dt_curr.GetTimestamp() + ", time last " + (string)dt_last.GetTimestamp() + " "; + string _passed = "time now " + TimeToString(dt_curr.GetTimestamp()) + ", time last " + + TimeToString(dt_last.GetTimestamp()) + " "; if (_update) { _passed += "updating time "; diff --git a/DictSlot.mqh b/DictSlot.mqh index 41a85408d..eea48969d 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,6 +40,8 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} + DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} + bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } bool HasKey() { return bool(_flags & DICT_SLOT_HAS_KEY); } diff --git a/DictStruct.mqh b/DictStruct.mqh index 72e841a0e..5c47a1a06 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -89,17 +89,6 @@ class DictStruct : public DictBase { THIS_ATTR _mode = right._mode; } - void operator=(DictStruct& right) { - Clear(); - Resize(right.GetSlotCount()); - for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - THIS_ATTR _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; - } - THIS_ATTR _DictSlots_ref._num_used = right._DictSlots_ref._num_used; - THIS_ATTR _current_id = right._current_id; - THIS_ATTR _mode = right._mode; - } - void Clear() { for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); @@ -124,7 +113,7 @@ class DictStruct : public DictBase { /** * Inserts value using hashless key. */ - bool Push(V& value) { + bool Push(const V& value) { if (!InsertInto(THIS_ATTR _DictSlots_ref, value)) return false; return true; } @@ -136,6 +125,8 @@ class DictStruct : public DictBase { /** * Inserts value using hashless key. + * + * @todo Get rid of this method. */ #ifdef __MQL__ template <> @@ -385,7 +376,7 @@ class DictStruct : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { + bool InsertInto(DictSlotsRef& dictSlotsRef, const V& value) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeList; else if (THIS_ATTR _mode != DictModeList) { diff --git a/Object.extern.h b/Object.extern.h index f8b97dbd8..0b4bd3e35 100644 --- a/Object.extern.h +++ b/Object.extern.h @@ -25,5 +25,12 @@ * Includes external declarations related to objects. */ #ifndef __MQL__ -extern void *GetPointer(void *anyobject); +template +X* GetPointer(X& value) { + return &value; +} +template +X* GetPointer(X* ptr) { + return ptr; +} #endif diff --git a/Refs.struct.h b/Refs.struct.h index c97ad4b20..3225c782a 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -31,9 +31,15 @@ #endif // Includes. +#include + #include "Refs.rc.h" #include "Std.h" +#ifdef EMSCRIPTEN +#include +#endif + class Dynamic; // Forward class declaration. template @@ -87,6 +93,10 @@ struct SimpleRef { } }; +template +using base_type = + typename std::remove_cv::type>::type>::type; + /** * Class used to hold strong reference to reference-counted object. */ @@ -97,21 +107,34 @@ struct Ref { */ X* ptr_object; +#ifdef EMSCRIPTEN + typedef X element_type; +#endif + public: /** * Constructor. */ - Ref(X* _ptr) { THIS_REF = _ptr; } + Ref(X* _ptr) { + ptr_object = nullptr; + THIS_REF = _ptr; + } /** * Constructor. */ - Ref(Ref& ref) { THIS_REF = ref.Ptr(); } + Ref(const Ref& ref) { + ptr_object = nullptr; + Set(ref.Ptr()); + } /** * Constructor. */ - Ref(WeakRef& ref) { THIS_REF = ref.Ptr(); } + Ref(WeakRef& ref) { + ptr_object = nullptr; + Set(ref.Ptr()); + } /** * Constructor. @@ -126,7 +149,11 @@ struct Ref { /** * Returns pointer to target object. */ - X* Ptr() { return ptr_object; } + X* Ptr() const { return ptr_object; } + +#ifdef EMSCRIPTEN + X* get() const { return ptr_object; } +#endif /** * Checks whether any object is referenced. @@ -208,7 +235,11 @@ struct Ref { /** * Makes a strong reference to the given object. */ - X* operator=(X* _ptr) { + X* operator=(X* _ptr) { return Set(_ptr); } + /** + * Makes a strong reference to the given object. + */ + X* Set(X* _ptr) { if (ptr_object == _ptr) { // Assigning the same object. return Ptr(); @@ -240,18 +271,12 @@ struct Ref { /** * Makes a strong reference to the given weakly-referenced object. */ - X* operator=(WeakRef& right) { - THIS_REF = right.Ptr(); - return Ptr(); - } + X* operator=(const WeakRef& right) { return Set((X*)right.Ptr()); } /** * Makes a strong reference to the strongly-referenced object. */ - X* operator=(Ref& right) { - THIS_REF = right.Ptr(); - return Ptr(); - } + X* operator=(const Ref& right) { return Set((X*)right.Ptr()); } /** * Equality operator. @@ -259,6 +284,11 @@ struct Ref { bool operator==(const Ref& r) { return ptr_object != NULL && ptr_object == r.ptr_object; } }; +template +Ref make_ref() { + return Ref(); +} + /** * Class used to hold weak reference to reference-counted object. */ diff --git a/Serializer/SerializerConverter.h b/Serializer/SerializerConverter.h index 7e9490239..571bb1353 100644 --- a/Serializer/SerializerConverter.h +++ b/Serializer/SerializerConverter.h @@ -39,6 +39,10 @@ class SerializerNode; #include "SerializerDict.h" #include "SerializerNode.h" +#ifdef __debug__ +#include "SerializerJson.h" +#endif + class SerializerConverter { public: SerializerNode* root_node; @@ -70,8 +74,9 @@ class SerializerConverter { SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); #ifdef __debug__ Print("FromObject(): serializer flags: ", serializer_flags); - Print("FromObject(): result: ", - _serializer.GetRoot() != NULL ? _serializer.GetRoot().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); + Print("FromObject(): result: ", _serializer.GetRoot() != NULL + ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) + : "NULL"); #endif return _converter; } @@ -84,8 +89,9 @@ class SerializerConverter { SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); #ifdef __debug__ Print("FromObject(): serializer flags: ", serializer_flags); - Print("FromObject(): result: ", - _serializer.GetRoot() != NULL ? _serializer.GetRoot().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); + Print("FromObject(): result: ", _serializer.GetRoot() != NULL + ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) + : "NULL"); #endif return _converter; } @@ -115,7 +121,7 @@ class SerializerConverter { SerializerConverter _converter(((C*)NULL)PTR_DEREF Parse(arg), 0); #ifdef __debug__ Print("FromString(): result: ", - _converter.Node() != NULL ? _converter.Node().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); + _converter.Node() != NULL ? _converter.Node() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); #endif return _converter; } diff --git a/Serializer/SerializerJson.h b/Serializer/SerializerJson.h index fd3ed5fed..491954708 100644 --- a/Serializer/SerializerJson.h +++ b/Serializer/SerializerJson.h @@ -195,7 +195,7 @@ class SerializerJson { #ifdef __debug__ Print("SerializerJson: Value \"" + extracted + "\" for key " + - (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif expectingValue = false; @@ -217,7 +217,8 @@ class SerializerJson { } #ifdef __debug__ - Print("SerializerJson: Entering object for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Entering object for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif node = new SerializerNode(SerializerNodeObject, current, key); @@ -237,16 +238,18 @@ class SerializerJson { } #ifdef __debug__ - Print("SerializerJson: Leaving object for key " + (current != NULL && current.GetKeyParam() != NULL - ? ("\"" + current.GetKeyParam().ToString() + "\"") - : "")); + Print("SerializerJson: Leaving object for key " + + (current != NULL && current PTR_DEREF GetKeyParam() != NULL + ? ("\"" + current PTR_DEREF GetKeyParam() PTR_DEREF ToString() + "\"") + : "")); #endif current = PTR_ATTRIB(current, GetParent()); expectingValue = false; } else if (ch == '[') { #ifdef __debug__ - Print("SerializerJson: Entering list for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Entering list for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif if (expectingKey) { @@ -264,7 +267,8 @@ class SerializerJson { key = NULL; } else if (ch == ']') { #ifdef __debug__ - Print("SerializerJson: Leaving list for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Leaving list for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif if (expectingKey || expectingValue || PTR_ATTRIB(current, GetType()) != SerializerNodeArray) { @@ -285,8 +289,8 @@ class SerializerJson { value = StringFind(extracted, ".") != -1 ? SerializerNodeParam::FromValue(StringToDouble(extracted)) : SerializerNodeParam::FromValue(StringToInteger(extracted)); #ifdef __debug__ - Print("SerializerJson: Value " + value.AsString() + " for key " + - (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Value " + value PTR_DEREF AsString() + " for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif PTR_ATTRIB(current, AddChild(new SerializerNode(PTR_ATTRIB(current, GetType()) == SerializerNodeObject @@ -306,8 +310,8 @@ class SerializerJson { value = SerializerNodeParam::FromValue(ch == 't' ? true : false); #ifdef __debug__ - Print("SerializerJson: Value " + (value.ToBool() ? "true" : "false") + " for key " + - (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print(string("SerializerJson: Value ") + (value PTR_DEREF ToBool() ? "true" : "false") + " for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif // Skipping value. diff --git a/String.extern.h b/String.extern.h index b1043fd2b..55a0f4f78 100644 --- a/String.extern.h +++ b/String.extern.h @@ -78,6 +78,8 @@ void PrintTo(std::ostream& out, Arg&& arg, Args&&... args) { out << std::forward(arg); using expander = int[]; (void)expander{0, (void(out << std::forward(args)), 0)...}; + out << "\n"; + out.flush(); } template diff --git a/Task/Task.h b/Task/Task.h index 0854b9d18..c2ca184cc 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -30,10 +30,6 @@ #pragma once #endif -// Prevents processing this includes file for the second time. -#ifndef TASK_H -#define TASK_H - // Includes. #include "../DictStruct.mqh" #include "../Terminal.define.h" @@ -54,12 +50,12 @@ class Task : public Taskable { * Class constructor. */ Task() {} - Task(TaskEntry &_entry) { Add(_entry); } + Task(const TaskEntry &_entry) { Add(_entry); } /** * Class copy constructor. */ - Task(Task &_task) { tasks = PTR_TO_REF(_task.GetTasks()); } + Task(const Task &_task) { tasks = PTR_TO_REF(_task.GetTasks()); } /** * Class deconstructor. @@ -71,7 +67,7 @@ class Task : public Taskable { /** * Adds new task. */ - void Add(TaskEntry &_entry) { tasks.Push(_entry); } + void Add(const TaskEntry &_entry) { tasks.Push(_entry); } /* Virtual methods */ @@ -214,7 +210,7 @@ class Task : public Taskable { /** * Returns tasks. */ - DictStruct *GetTasks() { return &tasks; } + const DictStruct *GetTasks() const { return &tasks; } /** * Count entry flags. @@ -317,4 +313,17 @@ class Task : public Taskable { /* Other methods */ }; -#endif // TASK_H + +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(Task) { + emscripten::class_("Task").smart_ptr>("Ref").constructor(emscripten::optional_override([]() { + return Ref(new Task()); + })) + //.function("Add", optional_override([](Task &self, Ref task) { self.Add(task.Ptr()); })) + ; +} + +#endif diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 391eebc9c..db3a202cb 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -65,6 +65,15 @@ struct TaskEntry { public: // Constructors. TaskEntry() { Init(); } + TaskEntry(const TaskEntry &_entry) + : action(_entry.action), + cond(_entry.cond), + expires(_entry.expires), + last_process(_entry.last_process), + last_success(_entry.last_success), + flags(_entry.flags) { + Init(); + } TaskEntry(const TaskActionEntry &_action, const TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } template TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { @@ -143,3 +152,10 @@ struct TaskEntry { SERIALIZER_EMPTY_STUB; }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TaskEntry) { emscripten::class_("TaskEntry").constructor(); } + +#endif diff --git a/Task/TaskManager.h b/Task/TaskManager.h index 7cd985fde..d549cc95f 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -30,10 +30,6 @@ #pragma once #endif -// Prevents processing this includes file for the second time. -#ifndef TASK_MANAGER_H -#define TASK_MANAGER_H - // Includes. #include "../DictObject.mqh" #include "../Serializer/SerializerConverter.h" @@ -95,6 +91,11 @@ class TaskManager { return Add((Task *)_task_obj); } + /** + * Clears tasks list. + */ + void Clear() { tasks.Clear(); } + /* Processing methods */ /** @@ -110,4 +111,18 @@ class TaskManager { } }; -#endif // TASK_MANAGER_H +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TaskManager) { + emscripten::class_("TaskManager") + .constructor() + .function("Add", emscripten::optional_override([](TaskManager &self, Ref task) { + Print("Adding Task"); + self.Add(task.Ptr()); + })) + // .function("Add", emscripten::select_overload(&TaskManager::Add)) + .function("Clear", &TaskManager::Clear) + .function("Process", &TaskManager::Process); +} +#endif diff --git a/Trade/TradeSignal.h b/Trade/TradeSignal.h index 7a48524f5..4a11e43de 100644 --- a/Trade/TradeSignal.h +++ b/Trade/TradeSignal.h @@ -179,3 +179,12 @@ class TradeSignal { */ string ToString() { return signal.ToString(); } }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TradeSignal) { + emscripten::class_("TradeSignal").constructor().function("ToString", &TradeSignal::ToString); +} + +#endif diff --git a/Trade/TradeSignalManager.h b/Trade/TradeSignalManager.h index 87dd5c017..b9a03fb82 100644 --- a/Trade/TradeSignalManager.h +++ b/Trade/TradeSignalManager.h @@ -181,3 +181,15 @@ class TradeSignalManager : Dynamic { .ToString(SERIALIZER_JSON_NO_WHITESPACES); } }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TradeSignalManager) { + emscripten::class_("TradeSignalManager") + .constructor() + .function("SignalAdd", &TradeSignalManager::SignalAdd) + .function("ToString", &TradeSignalManager::ToString); +} + +#endif From da13c54bc5645cb5d3a7f7153bad10c5901b045f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 21 Dec 2022 20:42:07 +0100 Subject: [PATCH 05/42] WIP. Making Account and Exchange classes to work via Emscripten. Also introduced MemoryFileSystem for accessing temporary files written by MQL/C++ code. --- Account/Account.struct.h | 2 +- Account/AccountBase.struct.h | 3 +- Array.mqh | 6 +- Bar.struct.h | 4 +- BufferStruct.mqh | 8 +- Chart.struct.static.h | 6 ++ Data.struct.h | 54 +++++++++++-- DictStruct.mqh | 6 +- File.define.h | 35 +++++++- File.extern.h | 27 ++++++- File.mqh | 33 -------- Flags.h | 5 ++ Log.mqh | 1 + Object.mqh | 5 -- Platform.extern.h | 38 +++++++++ Platform.h | 15 +++- Refs.mqh | 10 +++ Refs.struct.h | 9 +++ Std.h | 21 +++++ Storage/MemoryFileSystem.h | 149 +++++++++++++++++++++++++++++++++++ String.extern.h | 32 ++------ SymbolInfo.mqh | 4 +- SymbolInfo.struct.h | 4 +- Task/TaskManager.h | 14 +++- Terminal.enum.h | 66 ++++++++++++---- Terminal.extern.h | 51 ++++++++++++ 26 files changed, 496 insertions(+), 112 deletions(-) create mode 100644 Platform.extern.h create mode 100644 Storage/MemoryFileSystem.h diff --git a/Account/Account.struct.h b/Account/Account.struct.h index 2ae613e55..efae51d51 100644 --- a/Account/Account.struct.h +++ b/Account/Account.struct.h @@ -28,7 +28,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#include "../Serializer.enum.h" +#include "../Serializer/Serializer.enum.h" #endif // Forward class declaration. diff --git a/Account/AccountBase.struct.h b/Account/AccountBase.struct.h index ab237c6b7..85a0cbde2 100644 --- a/Account/AccountBase.struct.h +++ b/Account/AccountBase.struct.h @@ -28,7 +28,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#include "../Serializer.enum.h" +#include "../Serializer/Serializer.enum.h" #endif // Forward class declaration. @@ -36,6 +36,7 @@ class Serializer; // Includes. #include "../Serializer/Serializer.h" +#include "../Std.h" #include "../Terminal.define.h" // Struct for account entries. diff --git a/Array.mqh b/Array.mqh index 040767b6f..8b2035edf 100644 --- a/Array.mqh +++ b/Array.mqh @@ -119,7 +119,7 @@ class Array { int i; string result = ""; for (i = 0; i < ArraySize(arr); i++) { - result += StringFormat("%d:%d%s", i, arr[i], sep); + result += StringFormat("%d:%d%s", i, arr[i], C_STR(sep)); } // Return text without last separator. return StringSubstr(result, 0, StringLen(result) - StringLen(sep)); @@ -136,7 +136,7 @@ class Array { int i; string result = ""; for (i = 0; i < ArraySize(arr); i++) { - result += StringFormat("%d:%g%s", i, arr[i], sep); + result += StringFormat("%d:%g%s", i, arr[i], C_STR(sep)); } // Return text without last separator. return StringSubstr(result, 0, StringLen(result) - StringLen(sep)); @@ -404,7 +404,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { int i; string res = ""; for (i = 0; i < ArraySize(arr); i++) { - res += StringFormat("%g%s", NormalizeDouble(arr[i], digits), dlm); + res += StringFormat("%g%s", NormalizeDouble(arr[i], digits), C_STR(dlm)); } res = StringSubstr(res, 0, StringLen(res) - StringLen(dlm)); return res; diff --git a/Bar.struct.h b/Bar.struct.h index 5d0f18255..a261a8673 100644 --- a/Bar.struct.h +++ b/Bar.struct.h @@ -54,12 +54,12 @@ struct BarOHLC BarOHLC() : open(0), high(0), low(0), close(0), time(0){}; BarOHLC(double _open, double _high, double _low, double _close, datetime _time = 0) : time(_time), open(_open), high(_high), low(_low), close(_close) { - if (_time == 0) { + if (_time == (datetime)0) { _time = TimeCurrent(); } } BarOHLC(ARRAY_REF(double, _prices), datetime _time = 0) : time(_time) { - _time = _time == 0 ? TimeCurrent() : _time; + _time = _time == (datetime)0 ? TimeCurrent() : _time; int _size = ArraySize(_prices); close = _prices[0]; open = _prices[_size - 1]; diff --git a/BufferStruct.mqh b/BufferStruct.mqh index 2bc6cd93c..bda4a34d9 100644 --- a/BufferStruct.mqh +++ b/BufferStruct.mqh @@ -63,17 +63,17 @@ class BufferStruct : public DictStruct { /** * Constructor. */ - BufferStruct() : max(INT_MIN), min(INT_MAX) { SetOverflowListener(BufferStructOverflowListener, 10); } + BufferStruct() : max(INT_MIN), min(INT_MAX) { THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } BufferStruct(BufferStruct& _right) : max(INT_MIN), min(INT_MAX) { this = _right; - SetOverflowListener(BufferStructOverflowListener, 10); + THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } /** * Adds new value. */ void Add(TStruct& _value, long _dt = 0) { - _dt = _dt > 0 ? _dt : TimeCurrent(); + _dt = _dt > 0 ? _dt : (long)TimeCurrent(); if (Set(_dt, _value)) { min = _dt < min ? _dt : min; max = _dt > max ? _dt : max; @@ -87,7 +87,7 @@ class BufferStruct : public DictStruct { min = INT_MAX; max = INT_MIN; if (_dt > 0) { - for (DictStructIterator iter(Begin()); iter.IsValid(); ++iter) { + for (DictStructIterator iter(THIS_ATTR Begin()); iter.IsValid(); ++iter) { long _time = iter.Key(); if (_older && _time < _dt) { Unset(iter.Key()); diff --git a/Chart.struct.static.h b/Chart.struct.static.h index a5c97d387..cf19e5805 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -25,9 +25,15 @@ * Includes Chart's static structs. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. #include "Chart.define.h" #include "Chart.symboltf.h" +#include "Platform.extern.h" #include "Terminal.define.h" /* Defines struct for chart static methods. */ diff --git a/Data.struct.h b/Data.struct.h index 9d6fe8959..a73a602c8 100644 --- a/Data.struct.h +++ b/Data.struct.h @@ -129,8 +129,42 @@ struct DataParamEntry : public MqlParam { string_value = _string_value; } DataParamEntry(const DataParamEntry &_r) { ASSIGN_TO_THIS(MqlParam, _r); } + + DataParamEntry(bool _value) { + type = TYPE_BOOL; + integer_value = _value; + } + DataParamEntry(const datetime _value) { + type = TYPE_DATETIME; + integer_value = _value; + } + DataParamEntry(double _value) { + type = TYPE_DOUBLE; + double_value = _value; + } + DataParamEntry(int _value) { + type = TYPE_INT; + integer_value = _value; + } + DataParamEntry(const string _value) { + type = TYPE_STRING; + string_value = _value; + } + DataParamEntry(unsigned int _value) { + type = TYPE_UINT; + integer_value = _value; + } + DataParamEntry(long _value) { + type = TYPE_LONG; + integer_value = _value; + } + DataParamEntry(unsigned long _value) { + type = TYPE_ULONG; + integer_value = (long)_value; + } + // Struct operators. - void operator=(const bool _value) { + void operator=(bool _value) { type = TYPE_BOOL; integer_value = _value; } @@ -138,11 +172,11 @@ struct DataParamEntry : public MqlParam { type = TYPE_DATETIME; integer_value = _value; } - void operator=(const double _value) { + void operator=(double _value) { type = TYPE_DOUBLE; double_value = _value; } - void operator=(const int _value) { + void operator=(int _value) { type = TYPE_INT; integer_value = _value; } @@ -150,15 +184,19 @@ struct DataParamEntry : public MqlParam { type = TYPE_STRING; string_value = _value; } - void operator=(const unsigned int _value) { + void operator=(unsigned int _value) { type = TYPE_UINT; integer_value = _value; } - template - void operator=(const T _value) { - type = TYPE_INT; - integer_value = (int)_value; + void operator=(long _value) { + type = TYPE_LONG; + integer_value = _value; + } + void operator=(unsigned long _value) { + type = TYPE_ULONG; + integer_value = (long)_value; } + bool operator==(const DataParamEntry &_s) { return type == _s.type && double_value == _s.double_value && integer_value == _s.integer_value && string_value == _s.string_value; diff --git a/DictStruct.mqh b/DictStruct.mqh index 5c47a1a06..8a52642fa 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -152,12 +152,12 @@ class DictStruct : public DictBase { V operator[](K key) { DictSlot* slot; - int position; + unsigned int position; if (THIS_ATTR _mode == DictModeList) slot = THIS_ATTR GetSlot((unsigned int)key); else - slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); + slot = THIS_ATTR GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); if (slot == NULL || !slot PTR_DEREF IsUsed()) { Alert("Invalid DictStruct key \"", key, "\" (called by [] operator). Returning empty structure."); @@ -174,7 +174,7 @@ class DictStruct : public DictBase { */ V GetByKey(const K _key) { unsigned int position; - DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); + DictSlot* slot = THIS_ATTR GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); if (!slot) { static V _empty; diff --git a/File.define.h b/File.define.h index e932ab836..39b5ce3d9 100644 --- a/File.define.h +++ b/File.define.h @@ -19,13 +19,46 @@ * along with this program. If not, see . * */ - // Defines. #ifndef __MQL__ +#pragma once + // File constants to read the whole value of char, short or int type. #define CHAR_VALUE 1 #define INT_VALUE 4 #define SHORT_VALUE 2 // Used for checking file handles (see FileOpen() and FileFindFirst()). #define INVALID_HANDLE -1 + +enum ENUM_FILE_PROPERTY_INTEGER { + FILE_EXISTS, + FILE_CREATE_DATE, + FILE_MODIFY_DATE, + FILE_ACCESS_DATE, + FILE_SIZE, + FILE_POSITION, + FILE_END, + FILE_LINE_END, + FILE_IS_COMMON, + FILE_IS_TEXT, + FILE_IS_BINARY, + FILE_IS_CSV, + FILE_IS_ANSI, + FILE_IS_READABLE, + FILE_IS_WRITABLE, +}; +enum ENUM_FILE_OPEN_FLAGS { + FILE_READ = 1, + FILE_WRITE = 2, + FILE_BIN = 4, + FILE_CSV = 8, + FILE_TXT = 16, + FILE_ANSI = 32, + FILE_UNICODE = 64, + FILE_SHARE_READ = 128, + FILE_SHARE_WRITE = 256, + FILE_REWRITE = 512, + FILE_COMMON = 4096, +}; + #endif diff --git a/File.extern.h b/File.extern.h index cc1c63cf6..de79731bf 100644 --- a/File.extern.h +++ b/File.extern.h @@ -22,15 +22,36 @@ // Includes. #include "File.define.h" +#include "Storage/MemoryFileSystem.h" +#include "String.extern.h" #include "Terminal.define.h" // Define external global functions. #ifndef __MQL__ + +MemoryFileSystem _memfs; + extern bool FileIsEnding(int file_handle); + extern bool FileIsExist(const string file_name, int common_flag = 0); -extern int FileClose(int file_handle); -extern int FileOpen(string file_name, int open_flags, short delimiter = '\t', unsigned int codepage = CP_ACP); + +void FileClose(int file_handle) { _memfs.FileClose(file_handle); } + +int FileOpen(string file_name, int open_flags, short delimiter = '\t', unsigned int codepage = CP_ACP) { + return _memfs.FileOpen(file_name, open_flags, delimiter, codepage); +} + extern int FileReadInteger(int file_handle, int size = INT_VALUE); + extern string FileReadString(int file_handle, int length = -1); -extern unsigned int FileWriteString(int file_handle, const string text_string, int length = -1); + +unsigned int FileWriteString(int file_handle, const string text_string, int length = -1) { + return _memfs.FileWrite(file_handle, text_string); +} + +template +unsigned int FileWrite(int file_handle, Arg&& arg, Args&&... args) { + return _memfs.FileWrite(file_handle, arg, args...); +} + #endif diff --git a/File.mqh b/File.mqh index c6e62fb54..7c98322de 100644 --- a/File.mqh +++ b/File.mqh @@ -37,39 +37,6 @@ #include "Terminal.enum.h" #include "Terminal.extern.h" -#ifndef __MQL__ -enum ENUM_FILE_PROPERTY_INTEGER { - FILE_EXISTS, - FILE_CREATE_DATE, - FILE_MODIFY_DATE, - FILE_ACCESS_DATE, - FILE_SIZE, - FILE_POSITION, - FILE_END, - FILE_LINE_END, - FILE_IS_COMMON, - FILE_IS_TEXT, - FILE_IS_BINARY, - FILE_IS_CSV, - FILE_IS_ANSI, - FILE_IS_READABLE, - FILE_IS_WRITABLE, -}; -enum ENUM_FILE_OPEN_FLAGS { - FILE_READ = 1, - FILE_WRITE = 2, - FILE_BIN = 4, - FILE_CSV = 8, - FILE_TXT = 16, - FILE_ANSI = 32, - FILE_UNICODE = 64, - FILE_SHARE_READ = 128, - FILE_SHARE_WRITE = 256, - FILE_REWRITE = 512, - FILE_COMMON = 4096, -}; -#endif - /** * Class to provide a group of functions for working with files. */ diff --git a/Flags.h b/Flags.h index 341eca289..8807629b4 100644 --- a/Flags.h +++ b/Flags.h @@ -20,6 +20,11 @@ * */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + /** * Flags manipulation helper. */ diff --git a/Log.mqh b/Log.mqh index f542b93e7..9930bebd3 100644 --- a/Log.mqh +++ b/Log.mqh @@ -33,6 +33,7 @@ class DictStruct; #include "Collection.mqh" #include "DateTime.mqh" #include "DictStruct.mqh" +#include "File.mqh" #include "Object.mqh" // Define assert macros. diff --git a/Object.mqh b/Object.mqh index b3d471a31..542c73a68 100644 --- a/Object.mqh +++ b/Object.mqh @@ -97,11 +97,6 @@ class Object : public Dynamic { } bool IsDynamic() { return IsDynamic(obj); } - /** - * Returns text representation of the object. - */ - virtual string ToString() { return StringFormat("[Object #%04x]", GetPointer(this)); } - /** * Returns text representation of the object. */ diff --git a/Platform.extern.h b/Platform.extern.h new file mode 100644 index 000000000..87adc94ca --- /dev/null +++ b/Platform.extern.h @@ -0,0 +1,38 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "Platform.h" + +#ifndef __MQL__ + +/** + * Returns number of candles for a given symbol and time-frame. + */ +static int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { return Platform::Bars(_symbol, _tf); } + +#endif diff --git a/Platform.h b/Platform.h index c7db1f1a7..ccbada32f 100644 --- a/Platform.h +++ b/Platform.h @@ -20,6 +20,11 @@ * */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. /** @@ -180,6 +185,14 @@ class Platform { */ static bool IsNewYear() { return (time_flags & DATETIME_YEAR) != 0; } + /** + * Returns number of candles for a given symbol and time-frame. + */ + static int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; + } + /** * Binds Candle and/or Tick indicator as a source of prices or data for given indicator. * @@ -322,8 +335,6 @@ int Platform::global_tick_index = 0; DictStruct> Platform::indis; DictStruct> Platform::indis_dflt; -// void OnTimer() { Print("Timer"); Platform::OnTimer(); } - /** * Will test given indicator class with platform-default data source bindings. */ diff --git a/Refs.mqh b/Refs.mqh index 6df09cd49..4a37f4cf6 100644 --- a/Refs.mqh +++ b/Refs.mqh @@ -130,6 +130,16 @@ class Dynamic { "side."); } } + + /** + * Returns text representation of the object. + */ + virtual string ToString() { + if (ptr_ref_counter == nullptr) return ""; + + return StringFormat("%d strong ref(s) and %d weak ref(s)", ptr_ref_counter PTR_DEREF num_strong_refs, + ptr_ref_counter PTR_DEREF num_weak_refs); + } }; #endif diff --git a/Refs.struct.h b/Refs.struct.h index 3225c782a..0eef226e6 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -282,6 +282,15 @@ struct Ref { * Equality operator. */ bool operator==(const Ref& r) { return ptr_object != NULL && ptr_object == r.ptr_object; } + + /** + * Returns information about object references counter. + */ + string ToString() { + if (ptr_object == nullptr) return "Empty pointer"; + + return ptr_object PTR_DEREF ToString(); + } }; template diff --git a/Std.h b/Std.h index d85cd83ac..59afc3671 100644 --- a/Std.h +++ b/Std.h @@ -296,6 +296,13 @@ class InvalidEnumValue { }; #ifndef __MQL__ +struct _WRONG_VALUE { + template + operator T() { + return (T)-1; + } +} WRONG_VALUE; + // Converter of NULL_VALUE into expected type. e.g., "int x = NULL_VALUE" will end up with "x = 0". struct _NULL_VALUE { template @@ -304,6 +311,20 @@ struct _NULL_VALUE { } } NULL_VALUE; +/** + * Converting an enumeration value of any type to a text form. + * + * @docs + * - https://www.mql5.com/en/docs/convert/enumtostring + */ +string EnumToString(int _value) { + std::stringstream ss; + // We really don't want to mess with type reflection here (if possible at all). So we are outputting the input + // integer. + ss << _value; + return ss.str(); +} + template <> inline _NULL_VALUE::operator const std::string() const { return ""; diff --git a/Storage/MemoryFileSystem.h b/Storage/MemoryFileSystem.h new file mode 100644 index 000000000..bd84d7a68 --- /dev/null +++ b/Storage/MemoryFileSystem.h @@ -0,0 +1,149 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * In-memory file-system used e.g., to create files in C++ and access them in JS via Emscripten. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once + +// Includes. +#include + +#include "../DictStruct.mqh" +#include "../File.define.h" +#include "../String.mqh" + +class MemoryFileSystemFile : public Dynamic { + public: + // FILE_* flags from MQL. + unsigned int flags; + + // Whether file is already opened. + bool opened; + + // MemoryFileSystemFile handle index. + int handle; + + // Auto-incremented handle index. + static unsigned int last_handle; + + // String-based buffer. + string buffer; + + // Current cursor offset. + int offset; + + /** + * Constructor. + */ + MemoryFileSystemFile(string data = "") { + handle = last_handle++; + buffer = data; + } +}; + +unsigned int MemoryFileSystemFile::last_handle = 0; + +class MemoryFileSystem { + // Files by path. + DictStruct> files_by_path; + + // Files by handle. + DictStruct> files_by_handle; + + public: + MemoryFileSystem() { + int _ea_version_handle = FileOpen("EA.txt", FILE_WRITE); + FileWrite(_ea_version_handle, "Hello world!"); + FileClose(_ea_version_handle); + } + + /** + * Opens file for reading/writing and returns its handle. + */ + int FileOpen(string _path, int _flags, short _delimiter = ';', unsigned int codepage = CP_ACP) { + Ref _file; + + if (files_by_path.KeyExists("_path")) { + _file = files_by_path.GetByKey(_path); + + if (_file REF_DEREF opened) { + // MemoryFileSystemFile is already opened. + Print("Error: MemoryFileSystemFile \"" + _path + "\" is already opened!"); + DebugBreak(); + return INVALID_HANDLE; + } + + if ((_flags & FILE_WRITE) != 0) { + // Truncating file. + _file REF_DEREF buffer = ""; + } + } else { + if ((_flags & FILE_READ) != 0) { + // MemoryFileSystemFile doesn't exit. + Print("Error: MemoryFileSystemFile \"" + _path + "\" doesn't exist!"); + DebugBreak(); + return INVALID_HANDLE; + } + + _file = new MemoryFileSystemFile(); + files_by_path.Set(_path, _file); + files_by_handle.Set(_file REF_DEREF handle, _file); + } + + return _file REF_DEREF handle; + } + + /** + * Closes file by the handle given. + */ + void FileClose(int handle) { + if (!files_by_handle.KeyExists(handle)) { + Print("Error: MemoryFileSystemFile handle ", handle, " is not opened!"); + DebugBreak(); + return; + } + + files_by_handle.Unset(handle); + } + + template + unsigned int FileWrite(int file_handle, Arg&& arg, Args&&... args) { + if (!files_by_handle.KeyExists(file_handle)) { + Print("Error: MemoryFileSystemFile handle ", file_handle, " is not opened!"); + DebugBreak(); + return 0; + } + + std::stringstream str; + PrintTo(str, arg, args...); + string data = str.str(); + Ref _file = files_by_handle.GetByKey(file_handle); + _file REF_DEREF buffer += data; + return data.size(); + } +}; + +#endif diff --git a/String.extern.h b/String.extern.h index 55a0f4f78..f4ea595a4 100644 --- a/String.extern.h +++ b/String.extern.h @@ -56,22 +56,14 @@ string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol return std::to_string(number); } -template -struct TuplePrinter { - static void print(const std::string& fmt, std::ostream& os, const Tuple& t) { - const size_t idx = fmt.find_last_of('%'); - TuplePrinter::print(std::string(fmt, 0, idx), os, t); - os << std::get(t) << std::string(fmt, idx + 1); - } -}; - -template -struct TuplePrinter { - static void print(const std::string& fmt, std::ostream& os, const Tuple& t) { - const size_t idx = fmt.find_first_of('%'); - os << std::string(fmt, 0, idx) << std::get<0>(t) << std::string(fmt, idx + 1); - } -}; +template +std::string StringFormat(std::string f, Args&&... args) { + int size = snprintf(nullptr, 0, f.c_str(), args...); + std::string res; + res.resize(size); + snprintf(&res[0], size + 1, f.c_str(), args...); + return res; +} template void PrintTo(std::ostream& out, Arg&& arg, Args&&... args) { @@ -92,14 +84,6 @@ void Alert(Arg&& arg, Args&&... args) { PrintTo(std::cerr, arg, args...); } -template -std::string StringFormat(const std::string& fmt, Args&&... args) { - std::stringstream ss; - const auto t = std::make_tuple(std::forward(args)...); - TuplePrinter::print(fmt, ss, t); - return ss.str(); -} - template void PrintFormat(const std::string& fmt, Args&&... args) { std::cout << StringFormat(fmt, args...) << std::endl; diff --git a/SymbolInfo.mqh b/SymbolInfo.mqh index 50d21311e..259d6caef 100644 --- a/SymbolInfo.mqh +++ b/SymbolInfo.mqh @@ -111,7 +111,7 @@ class SymbolInfo : public Object { */ MqlTick GetTick() { if (!SymbolInfoTick(symbol, last_tick)) { - GetLogger().Error("Cannot return current prices!", __FUNCTION__); + GetLogger() PTR_DEREF Error("Cannot return current prices!", __FUNCTION__); } return last_tick; } @@ -487,7 +487,7 @@ class SymbolInfo : public Object { static int _index = 0; if (_index++ >= ArraySize(tick_data) - 1) { if (ArrayResize(tick_data, _index + 100, 1000) < 0) { - GetLogger().Error(StringFormat("Cannot resize array (size: %d)!", _index), __FUNCTION__); + GetLogger() PTR_DEREF Error(StringFormat("Cannot resize array (size: %d)!", _index), __FUNCTION__); return false; } } diff --git a/SymbolInfo.struct.h b/SymbolInfo.struct.h index ea08ee9af..ba167a187 100644 --- a/SymbolInfo.struct.h +++ b/SymbolInfo.struct.h @@ -32,10 +32,10 @@ // Includes. #include "Serializer/Serializable.h" +#include "Serializer/Serializer.h" #include "Std.h" #include "SymbolInfo.struct.static.h" #include "Tick/Tick.struct.h" -#include "Serializer/Serializer.h" // Defines struct to store symbol data. struct SymbolInfoEntry @@ -58,7 +58,7 @@ struct SymbolInfoEntry spread = (unsigned int)round((ask - bid) * pow(10, SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS))); } // Copy constructor. - SymbolInfoEntry(const SymbolInfoEntry& _sie) { this = _sie; } + SymbolInfoEntry(const SymbolInfoEntry& _sie) { THIS_REF = _sie; } // Getters string ToCSV() { return StringFormat("%g,%g,%g,%g,%d", bid, ask, last, spread, volume); } // Serializers. diff --git a/Task/TaskManager.h b/Task/TaskManager.h index d549cc95f..7f017217a 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -94,7 +94,19 @@ class TaskManager { /** * Clears tasks list. */ - void Clear() { tasks.Clear(); } + void Clear() { + Task *task0 = tasks[0].Ptr(); + + for (int i = 0; i < tasks.Size(); ++i) { + std::cout << "Task #" << i << ": " << tasks[i].ToString() << std::endl; + } + + tasks.Clear(); + + std::cout << "Tasks cleared." << std::endl; + std::cout << task0 PTR_DEREF ToString() << std::endl; + // std::cout.flush(); + } /* Processing methods */ diff --git a/Terminal.enum.h b/Terminal.enum.h index 574615a23..386caf381 100644 --- a/Terminal.enum.h +++ b/Terminal.enum.h @@ -59,26 +59,46 @@ enum ENUM_INIT_RETCODE { #ifndef __MQL__ /** - * Enumeration for the MQL program properties (integer type). + * Enumeration for the MQL5 program properties (integer type). * * @docs * - https://www.mql5.com/en/docs/constants/environment_state/mql5_programm_info */ + enum ENUM_MQL_INFO_INTEGER { - MQL_DEBUG, // Indication that the program is running in the debugging mode (bool). - MQL_DLLS_ALLOWED, // The permission to use DLL for the given running program (bool). - MQL_FORWARD, // Indication that the program is running in the forward testing process (bool). - MQL_FRAME_MODE, // Indication that the program is running in gathering optimization result frames mode (bool). - MQL_LICENSE_TYPE, // Type of license of the EX module. - MQL_MEMORY_LIMIT, // Maximum possible amount of dynamic memory for MQL5 program in MB (int). - MQL_MEMORY_USED, // Memory used by MQL5 program in MB (int). - MQL_OPTIMIZATION, // Indication that the program is running in the optimization mode (bool). - MQL_PROFILER, // Indication that the program is running in the code profiling mode (bool). - MQL_PROGRAM_TYPE, // Type of the MQL5 program (ENUM_PROGRAM_TYPE). - MQL_SIGNALS_ALLOWED, // The permission to modify the Signals for the given running program (bool). - MQL_TESTER, // Indication that the program is running in the tester (bool). - MQL_TRADE_ALLOWED, // The permission to trade for the given running program (bool). - MQL_VISUAL_MODE, // Indication that the program is running in the visual testing mode (bool). + MQL_DEBUG = 5, // Indication that the program is running in the debugging mode (bool). + MQL_DLLS_ALLOWED = 3, // The permission to use DLL for the given running program (bool). + MQL_FORWARD = 16, // Indication that the program is running in the forward testing process (bool). + MQL_FRAME_MODE = 12, // Indication that the program is running in gathering optimization result frames mode (bool). + MQL_HANDLES_USED = 17, // The current number of active object handles. These include both dynamic (created via new) + // and non-dynamic objects, global/local variables or class members. The more handles a + // program uses, the more resources it consumes. + MQL_LICENSE_TYPE = 9, // Type of license of the EX module. + MQL_MEMORY_LIMIT = 13, // Maximum possible amount of dynamic memory for MQL5 program in MB (int). + MQL_MEMORY_USED = 11, // Memory used by MQL5 program in MB (int). + MQL_OPTIMIZATION = 7, // Indication that the program is running in the optimization mode (bool). + MQL_PROFILER = 10, // Indication that the program is running in the code profiling mode (bool). + MQL_PROGRAM_TYPE = 2, // Type of the MQL5 program (ENUM_PROGRAM_TYPE). + MQL_SIGNALS_ALLOWED = 14, // The permission to modify the Signals for the given running program (bool). + MQL_TESTER = 6, // Indication that the program is running in the tester (bool). + MQL_TRADE_ALLOWED = 4, // The permission to trade for the given running program (bool). + MQL_VISUAL_MODE = 8, // Indication that the program is running in the visual testing mode (bool). + + // Additional enumerations for MQL4 compatibility: + + // MQL4: + MQL_CODEPAGE = 128 +}; + +/** + * @docs + * - https://www.mql5.com/en/docs/constants/environment_state/mql5_programm_info#enum_program_type + */ +enum ENUM_PROGRAM_TYPE { + PROGRAM_SCRIPT, // Script. + PROGRAM_EXPERT, // Expert. + PROGRAM_INDICATOR, // Indicator + PROGRAM_SERVICE, // Service. }; /** @@ -88,8 +108,9 @@ enum ENUM_MQL_INFO_INTEGER { * - https://www.mql5.com/en/docs/constants/environment_state/mql5_programm_info */ enum ENUM_MQL_INFO_STRING { - MQL_PROGRAM_NAME, // Name of the running mql5-program (string). - MQL5_PROGRAM_PATH, // Path for the given running program (string). + MQL_PROGRAM_NAME, // Name of the running mql5-program (string). + MQL5_PROGRAM_PATH, // Path for the given running program (string). + MQL_PROGRAM_PATH = MQL5_PROGRAM_PATH // Same as above. }; /** @@ -164,6 +185,17 @@ enum ENUM_TERMINAL_INFO_INTEGER { TERMINAL_X64, // Indication of the "64-bit terminal" (bool). }; +/** + * Enumeration for MQLInfoInteger(MQL_LICENSE_TYPE). + */ +enum ENUM_LICENSE_TYPE { + LICENSE_FREE, // A free unlimited version. + LICENSE_DEMO, // A trial version of a paid product from the Market. It works only in the strategy tester. + LICENSE_FULL, // A purchased licensed version allows at least 5 activations. The number of activations is specified + // by seller. Seller may increase the allowed number of activations. + LICENSE_TIME // A version with limited term liсense. +}; + /** * Enumeration for the Terminal properties (string). * diff --git a/Terminal.extern.h b/Terminal.extern.h index 65582439f..ecb073b2c 100644 --- a/Terminal.extern.h +++ b/Terminal.extern.h @@ -22,7 +22,58 @@ // Define external global functions. #ifndef __MQL__ +#pragma once + +// Includes. +#include "String.mqh" +#include "Terminal.define.h" +#include "Terminal.enum.h" + extern int GetLastError(); extern string TerminalInfoString(int property_id); extern void ResetLastError(); +string MQLInfoString(int property_id) { + switch (property_id) { + case MQL_PROGRAM_NAME: + return "EA"; + case MQL_PROGRAM_PATH: + return ""; + } + return ""; +} + +int MQLInfoInteger(int property_id) { + switch (property_id) { + case MQL_CODEPAGE: + return CP_ACP; + case MQL_PROGRAM_TYPE: + return PROGRAM_EXPERT; + case MQL_DLLS_ALLOWED: + return false; + case MQL_TRADE_ALLOWED: + return true; + case MQL_SIGNALS_ALLOWED: + return true; + case MQL_DEBUG: + return true; + case MQL_PROFILER: + return false; + case MQL_TESTER: + return true; + case MQL_OPTIMIZATION: + return true; + case MQL_VISUAL_MODE: + return false; + case MQL_FRAME_MODE: + return false; + case MQL_LICENSE_TYPE: + return LICENSE_FREE; + } + return -1; +} + +bool _StopFlag = false; + +bool IsStopped() { return _StopFlag; } + #endif From ff982e32bf1a56f887cb2252beccf96ed1835d20 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 9 Jan 2023 19:39:57 +0100 Subject: [PATCH 06/42] WIP. End up with include loop. --- Dict.mqh | 101 +++---- Draw.mqh | 36 +-- File.extern.h | 1 + File.mqh | 5 + Indicator/Indicator.define.h | 4 +- Indicator/IndicatorBase.h | 5 +- Indicator/IndicatorData.h | 6 +- Indicators/Tick/Indi_TickRandom.mqh | 1 - Math.extern.h | 2 + Matrix.mqh | 18 +- MiniMatrix.h | 2 +- Object.extern.h | 60 +++++ Orders.mqh | 1 - Platform.h | 18 ++ Serializer/SerializerCsv.h | 125 ++++----- Std.h | 6 + Storage/ValueStorage.h | 28 +- Storage/ValueStorage.history.h | 1 - Storage/ValueStorage.spread.h | 1 - String.extern.h | 26 ++ Terminal.define.h | 398 +++++++++++++++++++--------- Trade.mqh | 1 - 22 files changed, 551 insertions(+), 295 deletions(-) diff --git a/Dict.mqh b/Dict.mqh index 56f894fdc..923e63575 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -26,6 +26,7 @@ #include "Convert.basic.h" #include "DictBase.mqh" +#include "DictIteratorBase.mqh" #include "Matrix.mqh" #include "Serializer/Serializer.h" #include "Serializer/SerializerNodeIterator.h" @@ -41,12 +42,12 @@ class DictIterator : public DictIteratorBase { /** * Constructor. */ - DictIterator(DictBase& dict, unsigned int slotIdx) : DictIteratorBase(dict, slotIdx) {} + DictIterator(DictBase& dict, unsigned int slotIdx) : DictIteratorBase(dict, slotIdx) {} /** * Copy constructor. */ - DictIterator(const DictIterator& right) : DictIteratorBase(right) {} + DictIterator(const DictIterator& right) : DictIteratorBase(right) {} }; /** @@ -70,37 +71,37 @@ class Dict : public DictBase { Clear(); Resize(right.GetSlotCount()); for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; + THIS_ATTR _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; } - _DictSlots_ref._num_used = right._DictSlots_ref._num_used; - _current_id = right._current_id; - _mode = right._mode; + THIS_ATTR _DictSlots_ref._num_used = right._DictSlots_ref._num_used; + THIS_ATTR _current_id = right._current_id; + THIS_ATTR _mode = right._mode; } void operator=(const Dict& right) { Clear(); Resize(right.GetSlotCount()); for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; + THIS_ATTR _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; } - _DictSlots_ref._num_used = right._DictSlots_ref._num_used; - _current_id = right._current_id; - _mode = right._mode; + THIS_ATTR _DictSlots_ref._num_used = right._DictSlots_ref._num_used; + THIS_ATTR _current_id = right._current_id; + THIS_ATTR _mode = right._mode; } void Clear() { - for (unsigned int i = 0; i < (unsigned int)ArraySize(_DictSlots_ref.DictSlots); ++i) { - if (_DictSlots_ref.DictSlots[i].IsUsed()) _DictSlots_ref.DictSlots[i].SetFlags(0); + for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { + if (THIS_ATTR _DictSlots_ref.DictSlots[i].IsUsed()) THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); } - _DictSlots_ref._num_used = 0; + THIS_ATTR _DictSlots_ref._num_used = 0; } /** * Inserts value using hashless key. */ bool Push(V value) { - if (!InsertInto(_DictSlots_ref, value)) return false; + if (!InsertInto(THIS_ATTR _DictSlots_ref, value)) return false; return true; } @@ -113,15 +114,15 @@ class Dict : public DictBase { * Inserts or replaces value for a given key. */ bool Set(K key, V value) { - if (!InsertInto(_DictSlots_ref, key, value, true)) return false; + if (!InsertInto(THIS_ATTR _DictSlots_ref, key, value, true)) return false; return true; } V operator[](K key) { - if (_mode == DictModeList) return GetSlot((unsigned int)key).value; + if (THIS_ATTR _mode == DictModeList) return THIS_ATTR GetSlot((unsigned int)key).value; int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, key, position); + DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); if (!slot) return (V)NULL; @@ -136,7 +137,7 @@ class Dict : public DictBase { */ V GetByKey(const K _key, V _default = NULL) { unsigned int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, _key, position); + DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); if (!slot) { return _default; @@ -149,7 +150,7 @@ class Dict : public DictBase { * Returns value for a given position. */ V GetByPos(unsigned int _position) { - DictSlot* slot = GetSlotByPos(_DictSlots_ref, _position); + DictSlot* slot = GetSlotByPos(THIS_ATTR _DictSlots_ref, _position); if (!slot) { Alert("Invalid DictStruct position \"", _position, "\" (called by GetByPos()). Returning empty structure."); @@ -164,10 +165,12 @@ class Dict : public DictBase { /** * Checks whether dictionary contains given key => value pair. */ +#ifdef __MQL__ template <> +#endif bool Contains(const K key, const V value) { unsigned int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, key, position); + DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); if (!slot) return false; @@ -177,9 +180,11 @@ class Dict : public DictBase { /** * Returns index of dictionary's value or -1 if value doesn't exist. */ +#ifdef __MQL__ template <> +#endif int IndexOf(V& value) { - for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + for (DictIteratorBase i(THIS_ATTR Begin()); i.IsValid(); ++i) { if (i.Value() == value) { return (int)i.Index(); } @@ -192,7 +197,7 @@ class Dict : public DictBase { * Checks whether dictionary contains given value. */ bool Contains(const V value) { - for (DictIterator i = Begin(); i.IsValid(); ++i) { + for (DictIterator i = THIS_ATTR Begin(); i.IsValid(); ++i) { if (i.Value() == value) { return true; } @@ -232,7 +237,7 @@ class Dict : public DictBase { if ((_is_full || !_is_performant) && allow_resize) { // We have to resize the dict as it is either full or have perfomance problems due to massive number of conflicts // when inserting new values. - if (overflow_listener == NULL) { + if (THIS_ATTR overflow_listener == NULL) { // There is no overflow listener so we can freely grow up the dict. if (!GrowUp()) { // Can't resize the dict. Error happened. @@ -240,8 +245,9 @@ class Dict : public DictBase { } } else { // Overflow listener will decide if we can grow up the dict. - if (overflow_listener(_is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, - dictSlotsRef._num_used, 0)) { + if (THIS_ATTR overflow_listener( + _is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, + dictSlotsRef._num_used, 0)) { // We can freely grow up the dict. if (!GrowUp()) { // Can't resize the dict. Error happened. @@ -268,11 +274,12 @@ class Dict : public DictBase { (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { ++_num_conflicts; - if (overflow_listener != NULL) { + if (THIS_ATTR overflow_listener != NULL) { // We had to skip slot as it is already occupied. Now we are checking if // there is too many conflicts/skips and thus we can overwrite slot in // the starting position. - if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + if (THIS_ATTR overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, + _num_conflicts)) { // Looks like dict is working as buffer and we can overwrite slot in the starting position. position = _starting_position; break; @@ -309,9 +316,9 @@ class Dict : public DictBase { * Inserts hashless value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, V value) { - if (_mode == DictModeUnknown) - _mode = DictModeList; - else if (_mode != DictModeList) { + if (THIS_ATTR _mode == DictModeUnknown) + THIS_ATTR _mode = DictModeList; + else if (THIS_ATTR _mode != DictModeList) { Alert("Warning: Dict already operates as a dictionary, not a list!"); DebugBreak(); return false; @@ -322,7 +329,7 @@ class Dict : public DictBase { if (!GrowUp()) return false; } - unsigned int position = Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); + unsigned int position = THIS_ATTR Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); // Searching for empty DictSlot. while (dictSlotsRef.DictSlots[position].IsUsed()) { @@ -342,14 +349,15 @@ class Dict : public DictBase { * Expands array of DictSlots by given percentage value. */ bool GrowUp(int percent = DICT_GROW_UP_PERCENT_DEFAULT) { - return Resize(MathMax(10, (int)((float)ArraySize(_DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); + return Resize( + MathMax(10, (int)((float)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } /** * Shrinks or expands array of DictSlots. */ bool Resize(int new_size) { - if (new_size <= MathMin(_DictSlots_ref._num_used, ArraySize(_DictSlots_ref.DictSlots))) { + if (new_size <= MathMin(THIS_ATTR _DictSlots_ref._num_used, ArraySize(THIS_ATTR _DictSlots_ref.DictSlots))) { // We already use minimum number of slots possible. return true; } @@ -367,36 +375,37 @@ class Dict : public DictBase { new_DictSlots._num_used = 0; // Copies entire array of DictSlots into new array of DictSlots. Hashes will be rehashed. - for (i = 0; i < ArraySize(_DictSlots_ref.DictSlots); ++i) { - if (!_DictSlots_ref.DictSlots[i].IsUsed()) continue; + for (i = 0; i < ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { + if (!THIS_ATTR _DictSlots_ref.DictSlots[i].IsUsed()) continue; - if (_DictSlots_ref.DictSlots[i].HasKey()) { - if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].key, _DictSlots_ref.DictSlots[i].value, false)) + if (THIS_ATTR _DictSlots_ref.DictSlots[i].HasKey()) { + if (!InsertInto(new_DictSlots, THIS_ATTR _DictSlots_ref.DictSlots[i].key, + THIS_ATTR _DictSlots_ref.DictSlots[i].value, false)) return false; } else { - if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].value)) return false; + if (!InsertInto(new_DictSlots, THIS_ATTR _DictSlots_ref.DictSlots[i].value)) return false; } } // Freeing old DictSlots array. - ArrayFree(_DictSlots_ref.DictSlots); + ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots); - _DictSlots_ref = new_DictSlots; + THIS_ATTR _DictSlots_ref = new_DictSlots; return true; } public: -#ifdef __cplusplus +#ifdef __MQL__ template <> #endif SerializerNodeType Serialize(Serializer& s) { if (s.IsWriting()) { - for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + for (DictIteratorBase i(THIS_ATTR Begin()); i.IsValid(); ++i) { V value = i.Value(); - s.Pass(THIS_REF, GetMode() == DictModeDict ? i.KeyAsString() : "", value); + s.Pass(THIS_REF, THIS_ATTR GetMode() == DictModeDict ? i.KeyAsString() : "", value); } - return (GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray; + return (THIS_ATTR GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray; } else { SerializerIterator i; @@ -432,9 +441,9 @@ class Dict : public DictBase { */ template Matrix* ToMatrix() { - Matrix* result = new Matrix(Size()); + Matrix* result = new Matrix(THIS_ATTR Size()); - for (DictIterator i = Begin(); i.IsValid(); ++i) result[i.Index()] = (X)i.Value(); + for (DictIterator i = THIS_ATTR Begin(); i.IsValid(); ++i) result[i.Index()] = (X)i.Value(); return result; } diff --git a/Draw.mqh b/Draw.mqh index 5c2fcca9e..3fb403904 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -30,8 +30,10 @@ class Chart; class Draw; // Includes. -#include "Chart.mqh" #include "Data.define.h" +#include "Object.extern.h" +#include "Platform.h" +#include "Terminal.define.h" #ifndef __MQL4__ // Defines macros (for MQL4 backward compatibility). @@ -41,21 +43,6 @@ class Draw; #define SetIndexShift(_index, _value) (PlotIndexSetInteger(_index, PLOT_SHIFT, _value)) #endif -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compatibility). -bool ObjectCreate(string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { - return Draw::ObjectCreate(0, _name, _otype, _swindow, _t1, _p1); -} -bool ObjectDelete(string _name) { return Draw::ObjectDelete(_name); } -bool ObjectSet(string _name, int _prop_id, double _value) { return Draw::ObjectSet(_name, _prop_id, _value); } -int ObjectsTotal(int _type = EMPTY) { return Draw::ObjectsTotal(); } -string ObjectName(int _index) { return Draw::ObjectName(_index); } -void SetIndexLabel(int _index, string _text) { Draw::SetIndexLabel(_index, _text); } -void SetIndexStyle(int _index, int _type, int _style = EMPTY, int _width = EMPTY, color _clr = CLR_NONE) { - Draw::SetIndexStyle(_index, _type, _style, _width, _clr); -} -#endif - #define WINDOW_MAIN 0 #ifdef __MQL5__ @@ -85,7 +72,7 @@ class Draw : public Object { /** * Class constructor. */ - Draw(long _chart_id = 0) : chart_id(_chart_id != 0 ? _chart_id : ChartID()) {} + Draw(long _chart_id = 0) : chart_id(_chart_id != 0 ? _chart_id : Platform::ChartID()) {} /* Graphic object related methods */ @@ -335,3 +322,18 @@ class Draw : public Object { return true; } }; + +#ifndef __MQL4__ +// Defines global functions (for MQL4 backward compatibility). +bool ObjectCreate(string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { + return Draw::ObjectCreate(0, _name, _otype, _swindow, _t1, _p1); +} +bool ObjectDelete(string _name) { return Draw::ObjectDelete(_name); } +bool ObjectSet(string _name, int _prop_id, double _value) { return Draw::ObjectSet(_name, _prop_id, _value); } +int ObjectsTotal(int _type = EMPTY) { return Draw::ObjectsTotal(); } +string ObjectName(int _index) { return Draw::ObjectName(_index); } +void SetIndexLabel(int _index, string _text) { Draw::SetIndexLabel(_index, _text); } +void SetIndexStyle(int _index, int _type, int _style = EMPTY, int _width = EMPTY, color _clr = CLR_NONE) { + Draw::SetIndexStyle(_index, _type, _style, _width, _clr); +} +#endif diff --git a/File.extern.h b/File.extern.h index de79731bf..ca4e965b5 100644 --- a/File.extern.h +++ b/File.extern.h @@ -28,6 +28,7 @@ // Define external global functions. #ifndef __MQL__ +#pragma once MemoryFileSystem _memfs; diff --git a/File.mqh b/File.mqh index 7c98322de..fc840d1a7 100644 --- a/File.mqh +++ b/File.mqh @@ -29,6 +29,11 @@ * - Files with which file operations are conducted means cannot be outside the file sandbox. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. #include "File.define.h" #include "File.extern.h" diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index 3d1a65c24..d0e2900df 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -35,8 +35,8 @@ #define DUMMY #define ICUSTOM_DEF(SET_HANDLE, PARAMS) \ - double _res[]; \ - if (_handle == NULL || _handle == INVALID_HANDLE) { \ + ARRAY(double, _res); \ + if (_handle == 0 || _handle == INVALID_HANDLE) { \ if ((_handle = ::iCustom(_symbol, _tf, _name PARAMS)) == INVALID_HANDLE) { \ SetUserError(ERR_USER_INVALID_HANDLE); \ return EMPTY_VALUE; \ diff --git a/Indicator/IndicatorBase.h b/Indicator/IndicatorBase.h index ff1327cb2..3dede1258 100644 --- a/Indicator/IndicatorBase.h +++ b/Indicator/IndicatorBase.h @@ -34,11 +34,10 @@ #include "../Array.mqh" #include "../BufferStruct.mqh" #include "../Chart.struct.tf.h" -//#include "../ChartBase.h" -#include "../ChartMt.h" #include "../DateTime.mqh" #include "../Log.mqh" #include "../Object.mqh" +#include "../Platform.extern.h" #include "../Refs.mqh" #include "../Serializer/Serializer.h" #include "../Serializer/SerializerCsv.h" @@ -192,7 +191,7 @@ class IndicatorBase : public Object { /** * Get name of the indicator. */ - virtual string GetName() = NULL; + virtual string GetName() = 0; /** * Get full name of the indicator (with "over ..." part). diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 58776bff9..78b5bb1f1 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -31,15 +31,13 @@ // Forward class declaration. class IndicatorBase; +class IndicatorDraw; // Includes. #include "../Bar.struct.h" -#include "../DrawIndicator.mqh" #include "../Flags.h" +#include "../Storage/IValueStorage.h" #include "../Storage/ItemsHistory.h" -#include "../Storage/ValueStorage.h" -#include "../Storage/ValueStorage.indicator.h" -#include "../Storage/ValueStorage.native.h" #include "../SymbolInfo.struct.h" #include "Indicator.enum.h" #include "IndicatorBase.h" diff --git a/Indicators/Tick/Indi_TickRandom.mqh b/Indicators/Tick/Indi_TickRandom.mqh index c3b3a6253..56e8148c5 100644 --- a/Indicators/Tick/Indi_TickRandom.mqh +++ b/Indicators/Tick/Indi_TickRandom.mqh @@ -31,7 +31,6 @@ #endif // Includes. -#include "../../Chart.struct.static.h" #include "../../Indicator/IndicatorTick.h" #include "../../Indicator/IndicatorTick.provider.h" diff --git a/Math.extern.h b/Math.extern.h index a19b60b13..7965fd1f3 100644 --- a/Math.extern.h +++ b/Math.extern.h @@ -75,4 +75,6 @@ template T log10(T value) { return std::log10(value); } +int MathRand() { return std::rand() % 32768; } +int rand() { return std::rand() % 32768; } #endif diff --git a/Matrix.mqh b/Matrix.mqh index 59f3eef39..de0f7177c 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -282,7 +282,7 @@ class MatrixDimension { /** * Sets physical position of the dimension in the matrix. */ - void SetPosition(int& _position[], int _level) { + void SetPosition(ARRAY_REF(int, _position), int _level) { for (int i = 0; i < ArraySize(_position); ++i) { position[i] = i < _level ? _position[i] : -1; } @@ -472,8 +472,8 @@ class MatrixDimension { * * @todo Allow of resizing containers instead of freeing them firstly. */ - static MatrixDimension* SetDimensions(MatrixDimension* _ptr_parent_dimension, int& _dimensions[], int index, - int& _current_position[]) { + static MatrixDimension* SetDimensions(MatrixDimension* _ptr_parent_dimension, ARRAY_REF(int, _dimensions), + int index, ARRAY_REF(int, _current_position)) { if (_ptr_parent_dimension == NULL) _ptr_parent_dimension = new MatrixDimension(); if (index == 0 && _dimensions[0] == 0) { @@ -634,7 +634,7 @@ class MatrixDimension { /** * Extracts dimensions's values to the given array. Used internally. */ - void FillArray(X& array[], int& offset) { + void FillArray(ARRAY_REF(X, array), int& offset) { int i; if (type == MATRIX_DIMENSION_TYPE_CONTAINERS) { for (i = 0; i < ArraySize(containers); ++i) { @@ -647,7 +647,7 @@ class MatrixDimension { } } - void FromArray(X& _array[], int& offset) { + void FromArray(ARRAY_REF(X, _array), int& offset) { int i; switch (type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: @@ -1378,7 +1378,7 @@ class Matrix { /** * Fills array with all values from the matrix. */ - void GetRawArray(X& array[]) { + void GetRawArray(ARRAY_REF(X, array)) { ArrayResize(array, GetSize()); int offset = 0; ptr_first_dimension.FillArray(array, offset); @@ -1425,7 +1425,7 @@ class Matrix { } #endif - void FillFromArray(X& _array[]) { + void FillFromArray(ARRAY_REF(X, _array)) { if (ArraySize(_array) != GetSize()) { Print("Matrix::FillFromArray(): input array (", ArraySize(_array), " elements) must be the same size as matrix (", GetSize(), " elements)!"); @@ -1908,10 +1908,10 @@ class Matrix { return GetDimensionsTotal(_dimensions); } - static int GetDimensionsTotal(int& dimensions[]) { + static int GetDimensionsTotal(FIXED_ARRAY_REF(int, dimensions, MATRIX_DIMENSIONS)) { int size = 0; - for (int i = 0; i < ArraySize(dimensions); ++i) { + for (int i = 0; i < MATRIX_DIMENSIONS; ++i) { if (dimensions[i] != 0) { if (size == 0) { size = 1; diff --git a/MiniMatrix.h b/MiniMatrix.h index 3ceaaa5ab..14560235f 100644 --- a/MiniMatrix.h +++ b/MiniMatrix.h @@ -27,7 +27,7 @@ template class MiniMatrix2d { public: - T data[]; + ARRAY(T, data); int size_x; int size_y; diff --git a/Object.extern.h b/Object.extern.h index 0b4bd3e35..8490e9499 100644 --- a/Object.extern.h +++ b/Object.extern.h @@ -25,6 +25,9 @@ * Includes external declarations related to objects. */ #ifndef __MQL__ + +#pragma once + template X* GetPointer(X& value) { return &value; @@ -33,4 +36,61 @@ template X* GetPointer(X* ptr) { return ptr; } + +template +ENUM_POINTER_TYPE CheckPointer(X& value) { + return (&value) != nullptr ? POINTER_DYNAMIC : POINTER_INVALID; +} +template +ENUM_POINTER_TYPE CheckPointer(X* ptr) { + return ptr != nullptr ? POINTER_DYNAMIC : POINTER_INVALID; +} + +enum ENUM_OBJECT { + OBJ_VLINE = 0, // Vertical Line + OBJ_HLINE = 1, // Horizontal Line + OBJ_TREND = 2, // Trend Line + OBJ_TRENDBYANGLE = 3, // Trend Line By Angle + OBJ_CYCLES = 4, // Cycle Lines + OBJ_ARROWED_LINE = 108, // Arrowed Line + OBJ_CHANNEL = 5, // Equidistant Channel + OBJ_STDDEVCHANNEL = 6, // Standard Deviation Channel + OBJ_REGRESSION = 7, // Linear Regression Channel + OBJ_PITCHFORK = 8, // Andrews’ Pitchfork + OBJ_GANNLINE = 9, // Gann Line + OBJ_GANNFAN = 10, // Gann Fan + OBJ_GANNGRID = 11, // Gann Grid + OBJ_FIBO = 12, // Fibonacci Retracement + OBJ_FIBOTIMES = 13, // Fibonacci Time Zones + OBJ_FIBOFAN = 14, // Fibonacci Fan + OBJ_FIBOARC = 15, // Fibonacci Arcs + OBJ_FIBOCHANNEL = 16, // Fibonacci Channel + OBJ_EXPANSION = 17, // Fibonacci Expansion + OBJ_ELLIOTWAVE5 = 18, // Elliott Motive Wave + OBJ_ELLIOTWAVE3 = 19, // Elliott Correction Wave + OBJ_RECTANGLE = 20, // Rectangle + OBJ_TRIANGLE = 21, // Triangle + OBJ_ELLIPSE = 22, // Ellipse + OBJ_ARROW_THUMB_UP = 23, // Thumbs Up + OBJ_ARROW_THUMB_DOWN = 24, // Thumbs Down + OBJ_ARROW_UP = 25, // Arrow Up + OBJ_ARROW_DOWN = 26, // Arrow Down + OBJ_ARROW_STOP = 27, // Stop Sign + OBJ_ARROW_CHECK = 28, // Check Sign + OBJ_ARROW_LEFT_PRICE = 29, // Left Price Label + OBJ_ARROW_RIGHT_PRICE = 30, // Right Price Label + OBJ_ARROW_BUY = 31, // Buy Sign + OBJ_ARROW_SELL = 32, // Sell Sign + OBJ_ARROW = 100, // Arrow + OBJ_TEXT = 101, // Text + OBJ_LABEL = 102, // Label + OBJ_BUTTON = 103, // Button + OBJ_CHART = 104, // Chart + OBJ_BITMAP = 105, // Bitmap + OBJ_BITMAP_LABEL = 106, // Bitmap Label + OBJ_EDIT = 107, // Edit + OBJ_EVENT = 109, // The "Event" object corresponding to an event in the economic calendar + OBJ_RECTANGLE_LABEL = 110 // The "Rectangle label" object for creating and designing the custom graphical interface. +}; + #endif diff --git a/Orders.mqh b/Orders.mqh index 2b5ca4057..906f018a6 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -25,7 +25,6 @@ class Orders; // Includes. #include "Account/Account.h" -#include "Chart.mqh" #include "Log.mqh" #include "Math.h" #include "Order.mqh" diff --git a/Platform.h b/Platform.h index ccbada32f..f0da9db31 100644 --- a/Platform.h +++ b/Platform.h @@ -25,6 +25,19 @@ #pragma once #endif +#ifndef __MQL__ + +/** + * Extern declarations for C++. + */ + +/** + * Returns number of candles for a given symbol and time-frame. + */ +extern int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf); + +#endif + // Includes. /** @@ -193,6 +206,11 @@ class Platform { return 0; } + /** + * Returns id of the current chart. + */ + static int ChartID() { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); } + /** * Binds Candle and/or Tick indicator as a source of prices or data for given indicator. * diff --git a/Serializer/SerializerCsv.h b/Serializer/SerializerCsv.h index 85992b779..aea45d535 100644 --- a/Serializer/SerializerCsv.h +++ b/Serializer/SerializerCsv.h @@ -55,12 +55,12 @@ class SerializerCsv { SerializerConverter* _stub = (SerializerConverter*)serializer_aux_arg; if (CheckPointer(_root) == POINTER_INVALID) { - Alert("SerializerCsv: Invalid root node poiner!"); + Alert("SerializerCsv: Invalid root node pointer!"); DebugBreak(); return NULL; } - if (_stub == NULL || _stub.Node() == NULL) { + if (_stub == NULL || _stub PTR_DEREF Node() == NULL) { Alert("SerializerCsv: Cannot convert to CSV without stub object!"); DebugBreak(); return NULL; @@ -72,12 +72,13 @@ class SerializerCsv { unsigned int _num_columns, _num_rows; int x, y; - if (_stub.Node().IsArray()) { - _num_columns = _stub.Node().MaximumNumChildrenInDeepEnd(); - _num_rows = _root.NumChildren(); + if (_stub PTR_DEREF Node() PTR_DEREF IsArray()) { + _num_columns = _stub PTR_DEREF Node() PTR_DEREF MaximumNumChildrenInDeepEnd(); + _num_rows = _root PTR_DEREF NumChildren(); } else { - _num_columns = MathMax(_stub.Node().MaximumNumChildrenInDeepEnd(), _root.MaximumNumChildrenInDeepEnd()); - _num_rows = _root.NumChildren() > 0 ? 1 : 0; + _num_columns = MathMax(_stub PTR_DEREF Node() PTR_DEREF MaximumNumChildrenInDeepEnd(), + _root PTR_DEREF MaximumNumChildrenInDeepEnd()); + _num_rows = _root PTR_DEREF NumChildren() > 0 ? 1 : 0; } if (_include_titles) { @@ -100,61 +101,61 @@ class SerializerCsv { _column_types_out = &_column_types; } - _matrix_out.Resize(_num_columns, _num_rows); - _column_types_out.Resize(_num_columns, 1); + _matrix_out PTR_DEREF Resize(_num_columns, _num_rows); + _column_types_out PTR_DEREF Resize(_num_columns, 1); if (_include_titles) { _column_titles.Resize(_num_columns, 1); int _titles_current_column = 0; - SerializerCsv::ExtractColumns(_stub.Node(), &_column_titles, _column_types_out, serializer_flags, + SerializerCsv::ExtractColumns(_stub PTR_DEREF Node(), &_column_titles, _column_types_out, serializer_flags, _titles_current_column); - for (x = 0; x < _matrix_out.SizeX(); ++x) { - _matrix_out.Set(x, 0, EscapeString(_column_titles.Get(x, 0))); + for (x = 0; x < _matrix_out PTR_DEREF SizeX(); ++x) { + _matrix_out PTR_DEREF Set(x, 0, EscapeString(_column_titles.Get(x, 0))); } } #ifdef __debug__ - Print("Stub: ", _stub.Node().ToString()); - Print("Data: ", _root.ToString()); + Print("Stub: ", _stub PTR_DEREF Node() PTR_DEREF ToString()); + Print("Data: ", _root PTR_DEREF ToString()); Print("Size: ", _num_columns, " x ", _num_rows); #endif - if (!SerializerCsv::FlattenNode(_root, _stub.Node(), _matrix_out, _column_types_out, _include_key ? 1 : 0, - _include_titles ? 1 : 0, serializer_flags)) { + if (!SerializerCsv::FlattenNode(_root, _stub PTR_DEREF Node(), PTR_TO_REF(_matrix_out), _column_types_out, + _include_key ? 1 : 0, _include_titles ? 1 : 0, serializer_flags)) { Alert("SerializerCsv: Error occured during flattening!"); } string _result; - for (y = 0; y < _matrix_out.SizeY(); ++y) { - for (x = 0; x < _matrix_out.SizeX(); ++x) { - _result += _matrix_out.Get(x, y); + for (y = 0; y < _matrix_out PTR_DEREF SizeY(); ++y) { + for (x = 0; x < _matrix_out PTR_DEREF SizeX(); ++x) { + _result += _matrix_out PTR_DEREF Get(x, y); - if (x != _matrix_out.SizeX() - 1) { + if (x != _matrix_out PTR_DEREF SizeX() - 1) { _result += ","; } } - if (y != _matrix_out.SizeY() - 1) _result += "\n"; + if (y != _matrix_out PTR_DEREF SizeY() - 1) _result += "\n"; } if ((serializer_flags & SERIALIZER_FLAG_REUSE_STUB) == 0) { - _stub.Clean(); + _stub PTR_DEREF Clean(); } return _result; } static string ParamToString(SerializerNodeParam* param) { - switch (param.GetType()) { + switch (param PTR_DEREF GetType()) { case SerializerNodeParamBool: case SerializerNodeParamLong: case SerializerNodeParamDouble: - return param.AsString(false, false, false, param.GetFloatingPointPrecision()); + return param PTR_DEREF AsString(false, false, false, param PTR_DEREF GetFloatingPointPrecision()); case SerializerNodeParamString: - return EscapeString(param.AsString(false, false, false, param.GetFloatingPointPrecision())); + return EscapeString(param PTR_DEREF AsString(false, false, false, param PTR_DEREF GetFloatingPointPrecision())); default: - Print("Error: Wrong param type ", EnumToString(param.GetType()), "!"); + Print("Error: Wrong param type ", EnumToString(param PTR_DEREF GetType()), "!"); DebugBreak(); } @@ -173,12 +174,12 @@ class SerializerCsv { */ static void ExtractColumns(SerializerNode* _stub, MiniMatrix2d* _titles, MiniMatrix2d* _column_types, int _flags, int& _column) { - for (unsigned int _stub_entry_idx = 0; _stub_entry_idx < _stub.NumChildren(); ++_stub_entry_idx) { - SerializerNode* _child = _stub.GetChild(_stub_entry_idx); - if (_child.IsContainer()) { + for (unsigned int _stub_entry_idx = 0; _stub_entry_idx < _stub PTR_DEREF NumChildren(); ++_stub_entry_idx) { + SerializerNode* _child = _stub PTR_DEREF GetChild(_stub_entry_idx); + if (_child PTR_DEREF IsContainer()) { ExtractColumns(_child, _titles, _column_types, _flags, _column); - } else if (_child.HasKey()) { - _titles.Set(_column++, 0, _child.Key()); + } else if (_child PTR_DEREF HasKey()) { + _titles PTR_DEREF Set(_column++, 0, _child PTR_DEREF Key()); } } } @@ -192,31 +193,31 @@ class SerializerCsv { bool _include_key = bool(_flags & SERIALIZER_CSV_INCLUDE_KEY); - if (_stub.IsArray()) { - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { + if (_stub PTR_DEREF IsArray()) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { if (_include_key) { // Adding object's key in the first row. - SerializerNode* _child = _data.GetChild(_data_entry_idx); - string key = _child.HasKey() ? _child.Key() : ""; + SerializerNode* _child = _data PTR_DEREF GetChild(_data_entry_idx); + string key = _child PTR_DEREF HasKey() ? _child PTR_DEREF Key() : ""; _cells.Set(0, _row + _data_entry_idx, key); } - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), _stub.GetChild(0), _cells, _column_types, _column, - _row + _data_entry_idx, 0, 0, _flags)) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), _stub PTR_DEREF GetChild(0), _cells, + _column_types, _column, _row + _data_entry_idx, 0, 0, _flags)) { return false; } } - } else if (_stub.IsObject()) { + } else if (_stub PTR_DEREF IsObject()) { // Object means that there is only one row. - if (_data.IsArray()) { + if (_data PTR_DEREF IsArray()) { // Stub is an object, but data is an array (should be?). - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), _stub, _cells, _column_types, _column, _row, 0, - 0, _flags)) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), _stub, _cells, _column_types, _column, + _row, 0, 0, _flags)) { return false; } - _column += (int)_stub.GetChild(_data_entry_idx).MaximumNumChildrenInDeepEnd(); + _column += (int)_stub PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF MaximumNumChildrenInDeepEnd(); } } else { // Stub and object are both arrays. @@ -237,34 +238,34 @@ class SerializerCsv { int _level, int _flags) { unsigned int _data_entry_idx, _entry_size; - if (_stub.IsObject()) { - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { - if (_stub.NumChildren() == 0) { - Print("Stub is empty for object representation of: ", _data.ToString(false, 2)); + if (_stub PTR_DEREF IsObject()) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { + if (_stub PTR_DEREF NumChildren() == 0) { + Print("Stub is empty for object representation of: ", _data PTR_DEREF ToString(false, 2)); Print( "Note that if you're serializing a dictionary, your stub must contain a single, dummy key and maximum " "possible object representation."); - Print("Missing key \"", _data.Key(), "\" in stub."); + Print("Missing key \"", _data PTR_DEREF Key(), "\" in stub."); DebugBreak(); } - _entry_size = MathMax(_stub.GetChild(_data_entry_idx).TotalNumChildren(), - _data.GetChild(_data_entry_idx).TotalNumChildren()); + _entry_size = MathMax(_stub PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren(), + _data PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren()); - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), - _stub != NULL ? _stub.GetChild(_data_entry_idx) : NULL, _cells, _column_types, - _column, _row, _data_entry_idx, _level + 1, _flags)) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), + _stub != NULL ? _stub PTR_DEREF GetChild(_data_entry_idx) : NULL, _cells, + _column_types, _column, _row, _data_entry_idx, _level + 1, _flags)) { return false; } _column += (int)_entry_size; } - } else if (_stub.IsArray()) { - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { - _entry_size = MathMax(_stub.GetChild(_data_entry_idx).TotalNumChildren(), - _data.GetChild(_data_entry_idx).TotalNumChildren()); + } else if (_stub PTR_DEREF IsArray()) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { + _entry_size = MathMax(_stub PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren(), + _data PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren()); - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), _stub.GetChild(0), _cells, _column_types, _column, - _row, _data_entry_idx, _level + 1, _flags)) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), _stub PTR_DEREF GetChild(0), _cells, + _column_types, _column, _row, _data_entry_idx, _level + 1, _flags)) { return false; } @@ -277,14 +278,14 @@ class SerializerCsv { bool _include_titles_tree = (_flags & SERIALIZER_CSV_INCLUDE_TITLES_TREE) == SERIALIZER_CSV_INCLUDE_TITLES_TREE; if (_column_types != NULL) { - if (_data.GetValueParam() == NULL) { + if (_data PTR_DEREF GetValueParam() == NULL) { Alert("Error: Expected value here! Stub is probably initialized without proper structure."); DebugBreak(); } - _column_types.Set(_column, 0, _data.GetValueParam().GetType()); + _column_types PTR_DEREF Set(_column, 0, _data PTR_DEREF GetValueParam() PTR_DEREF GetType()); } - _cells.Set(_column, _row, ParamToString(_data.GetValueParam())); + _cells.Set(_column, _row, ParamToString(_data PTR_DEREF GetValueParam())); } return true; diff --git a/Std.h b/Std.h index 59afc3671..8337ec71d 100644 --- a/Std.h +++ b/Std.h @@ -34,6 +34,10 @@ #include #endif +#ifndef __MQL__ +#define __FUNCSIG__ __FUNCTION__ +#endif + #ifdef __MQL__ #define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE)this) = ((TYPE)VALUE) #else @@ -93,6 +97,7 @@ * ARRAY_REF(, ) */ #define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS +#define FIXED_ARRAY_REF(T, N, S) ARRAY_REF(T, N) #define CONST_ARRAY_REF(T, N) const N ARRAY_DECLARATION_BRACKETS @@ -118,6 +123,7 @@ * ARRAY_REF(, ) */ #define ARRAY_REF(T, N) _cpp_array& N +#define FIXED_ARRAY_REF(T, N, S) T(&N)[S] #define CONST_ARRAY_REF(T, N) const _cpp_array& N diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index 6f704c47a..8e7fa6e66 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -256,20 +256,6 @@ int ArrayCopy(ARRAY_REF(D, _target), ValueStorage &_source, int _dst_start = return _num_copied; } -/** - * iHigest() version working on ValueStorage. - */ -int iHighest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { - return iPeak(_price, _count, _start, IPEAK_HIGHEST); -} - -/** - * iLowest() version working on ValueStorage. - */ -int iLowest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { - return iPeak(_price, _count, _start, IPEAK_LOWEST); -} - /** * iLowest() version working on ValueStorage. */ @@ -315,4 +301,18 @@ int iPeak(ValueStorage &_price, int _count, int _start, ENUM_IPEAK _type return _price_size - _peak_idx - 1; } +/** + * iHigest() version working on ValueStorage. + */ +int iHighest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { + return iPeak(_price, _count, _start, IPEAK_HIGHEST); +} + +/** + * iLowest() version working on ValueStorage. + */ +int iLowest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { + return iPeak(_price, _count, _start, IPEAK_LOWEST); +} + #endif // VALUE_STORAGE_H diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index ed11af3c9..73d64a74f 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -31,7 +31,6 @@ #endif // Includes. -#include "../Indicator/IndicatorData.h" #include "ValueStorage.h" // Forward declarations. diff --git a/Storage/ValueStorage.spread.h b/Storage/ValueStorage.spread.h index 98e3689fc..890b168a1 100644 --- a/Storage/ValueStorage.spread.h +++ b/Storage/ValueStorage.spread.h @@ -25,7 +25,6 @@ */ // Includes. -#include "../Chart.struct.h" #include "ObjectsCache.h" #include "ValueStorage.history.h" diff --git a/String.extern.h b/String.extern.h index f4ea595a4..8c1cde2f6 100644 --- a/String.extern.h +++ b/String.extern.h @@ -101,4 +101,30 @@ unsigned short StringGetCharacter(string string_value, int pos) { int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, unsigned int codepage = CP_ACP); + +bool StringInit(string& string_var, int new_len = 0, unsigned short character = 0) { + string_var = string(new_len, (char)character); + return true; +} + +/** + * It replaces all the found substrings of a string by a set sequence of symbols. + * + * @docs + * - https://www.mql5.com/en/docs/strings/stringreplace + */ +int StringReplace(string& str, const string& find, const string& replacement) { + int num_replacements; + for (size_t pos = 0;; pos += replacement.length()) { + // Locate the substring to replace + pos = str.find(find, pos); + if (pos == string::npos) break; + // Replace by erasing and inserting + str.erase(pos, find.length()); + str.insert(pos, replacement); + ++num_replacements; + } + return num_replacements; +} + #endif diff --git a/Terminal.define.h b/Terminal.define.h index 129089236..a316eea43 100644 --- a/Terminal.define.h +++ b/Terminal.define.h @@ -38,141 +38,275 @@ #define CP_UTF8 65001 // UTF-8 code page. // Colors. -#define AliceBlue 0xFFF8F0 -#define AntiqueWhite 0xD7EBFA -#define Aqua 0xFFFF00 -#define Aquamarine 0xD4FF7F -#define Beige 0xDCF5F5 -#define Bisque 0xC4E4FF -#define Black 0x000000 -#define BlanchedAlmond 0xCDEBFF -#define Blue 0xFF0000 -#define BlueViolet 0xE22B8A -#define Brown 0x2A2AA5 -#define BurlyWood 0x87B8DE -#define CadetBlue 0xA09E5F -#define Chartreuse 0x00FF7F -#define Chocolate 0x1E69D2 -#define Coral 0x507FFF -#define CornflowerBlue 0xED9564 -#define Cornsilk 0xDCF8FF -#define Crimson 0x3C14DC -#define DarkBlue 0x8B0000 -#define DarkGoldenrod 0x0B86B8 -#define DarkGray 0xA9A9A9 -#define DarkGreen 0x006400 -#define DarkKhaki 0x6BB7BD -#define DarkOliveGreen 0x2F6B55 -#define DarkOrange 0x008CFF -#define DarkOrchid 0xCC3299 -#define DarkSalmon 0x7A96E9 -#define DarkSlateBlue 0x8B3D48 -#define DarkSlateGray 0x4F4F2F -#define DarkTurquoise 0xD1CE00 -#define DarkViolet 0xD30094 -#define DeepPink 0x9314FF -#define DeepSkyBlue 0xFFBF00 -#define DimGray 0x696969 -#define DodgerBlue 0xFF901E -#define FireBrick 0x2222B2 -#define ForestGreen 0x228B22 -#define Gainsboro 0xDCDCDC -#define Gold 0x00D7FF -#define Goldenrod 0x20A5DA -#define Gray 0x808080 -#define Green 0x008000 -#define GreenYellow 0x2FFFAD -#define Honeydew 0xF0FFF0 -#define HotPink 0xB469FF -#define IndianRed 0x5C5CCD -#define Indigo 0x82004B -#define Ivory 0xF0FFFF -#define Khaki 0x8CE6F0 -#define Lavender 0xFAE6E6 -#define LavenderBlush 0xF5F0FF -#define LawnGreen 0x00FC7C -#define LemonChiffon 0xCDFAFF -#define LightBlue 0xE6D8AD -#define LightCoral 0x8080F0 -#define LightCyan 0xFFFFE0 -#define LightGoldenrod 0xD2FAFA -#define LightGray 0xD3D3D3 -#define LightGreen 0x90EE90 -#define LightPink 0xC1B6FF -#define LightSalmon 0x7AA0FF -#define LightSeaGreen 0xAAB220 -#define LightSkyBlue 0xFACE87 -#define LightSlateGray 0x998877 -#define LightSteelBlue 0xDEC4B0 -#define LightYellow 0xE0FFFF -#define Lime 0x00FF00 -#define LimeGreen 0x32CD32 -#define Linen 0xE6F0FA -#define Magenta 0xFF00FF -#define Maroon 0x000080 -#define MediumAquamarine 0xAACD66 -#define MediumBlue 0xCD0000 -#define MediumOrchid 0xD355BA -#define MediumPurple 0xDB7093 -#define MediumSeaGreen 0x71B33C -#define MediumSlateBlue 0xEE687B -#define MediumSpringGreen 0x9AFA00 -#define MediumTurquoise 0xCCD148 -#define MediumVioletRed 0x8515C7 -#define MidnightBlue 0x701919 -#define MintCream 0xFAFFF5 -#define MistyRose 0xE1E4FF -#define Moccasin 0xB5E4FF -#define NavajoWhite 0xADDEFF -#define Navy 0x800000 -#define OldLace 0xE6F5FD -#define Olive 0x008080 -#define OliveDrab 0x238E6B -#define Orange 0x00A5FF -#define OrangeRed 0x0045FF -#define Orchid 0xD670DA -#define PaleGoldenrod 0xAAE8EE -#define PaleGreen 0x98FB98 -#define PaleTurquoise 0xEEEEAF -#define PaleVioletRed 0x9370DB -#define PapayaWhip 0xD5EFFF -#define PeachPuff 0xB9DAFF -#define Peru 0x3F85CD -#define Pink 0xCBC0FF -#define Plum 0xDDA0DD -#define PowderBlue 0xE6E0B0 -#define Purple 0x800080 -#define Red 0x0000FF -#define RosyBrown 0x8F8FBC -#define RoyalBlue 0xE16941 -#define SaddleBrown 0x13458B -#define Salmon 0x7280FA -#define SandyBrown 0x60A4F4 -#define SeaGreen 0x578B2E -#define Seashell 0xEEF5FF -#define Sienna 0x2D52A0 -#define Silver 0xC0C0C0 -#define SkyBlue 0xEBCE87 -#define SlateBlue 0xCD5A6A -#define SlateGray 0x908070 -#define Snow 0xFAFAFF -#define SpringGreen 0x7FFF00 -#define SteelBlue 0xB48246 -#define Tan 0x8CB4D2 -#define Teal 0x808000 -#define Thistle 0xD8BFD8 -#define Tomato 0x4763FF -#define Turquoise 0xD0E040 -#define Violet 0xEE82EE -#define Wheat 0xB3DEF5 -#define White 0xFFFFFF -#define WhiteSmoke 0xF5F5F5 -#define Yellow 0x00FFFF -#define YellowGreen 0x32CD9A +#define clrAliceBlue 0x00F0F8FF +#define clrAntiqueWhite 0x00FAEBD7 +#define clrAqua 0x0000FFFF +#define clrAquamarine 0x007FFFD4 +#define clrBeige 0x00F5F5DC +#define clrBisque 0x00FFE4C4 +#define clrBlack 0x00000000 +#define clrBlanchedAlmond 0x00FFEBCD +#define clrBlue 0x000000FF +#define clrBlueViolet 0x008A2BE2 +#define clrBrown 0x00A52A2A +#define clrBurlyWood 0x00DEB887 +#define clrCadetBlue 0x005F9EA0 +#define clrChartreuse 0x007FFF00 +#define clrChocolate 0x00D2691E +#define clrCoral 0x00FF7F50 +#define clrCornflowerBlue 0x006495ED +#define clrCornsilk 0x00FFF8DC +#define clrCrimson 0x00DC143C +#define clrDarkBlue 0x0000008B +#define clrDarkGoldenrod 0x00B8860B +#define clrDarkGray 0x00A9A9A9 +#define clrDarkGreen 0x00006400 +#define clrDarkKhaki 0x00BDB76B +#define clrDarkOliveGreen 0x00556B2F +#define clrDarkOrange 0x00FF8C00 +#define clrDarkOrchid 0x009932CC +#define clrDarkSalmon 0x00E9967A +#define clrDarkSeaGreen 0x008FBC8F +#define clrDarkSlateBlue 0x00483D8B +#define clrDarkSlateGray 0x002F4F4F +#define clrDarkTurquoise 0x0000CED1 +#define clrDarkViolet 0x009400D3 +#define clrDeepPink 0x00FF1493 +#define clrDeepSkyBlue 0x0000BFFF +#define clrDimGray 0x00696969 +#define clrDodgerBlue 0x001E90FF +#define clrFireBrick 0x00B22222 +#define clrForestGreen 0x00228B22 +#define clrGainsboro 0x00DCDCDC +#define clrGold 0x00FFD700 +#define clrGoldenrod 0x00DAA520 +#define clrGray 0x00808080 +#define clrGreen 0x00008000 +#define clrGreenYellow 0x00ADFF2F +#define clrHoneydew 0x00F0FFF0 +#define clrHotPink 0x00FF69B4 +#define clrIndianRed 0x00CD5C5C +#define clrIndigo 0x004B0082 +#define clrIvory 0x00FFFFF0 +#define clrKhaki 0x00F0E68C +#define clrLavender 0x00E6E6FA +#define clrLavenderBlush 0x00FFF0F5 +#define clrLawnGreen 0x007CFC00 +#define clrLemonChiffon 0x00FFFACD +#define clrLightBlue 0x00ADD8E6 +#define clrLightCoral 0x00F08080 +#define clrLightCyan 0x00E0FFFF +#define clrLightGoldenrodYellow 0x00FAFAD2 +#define clrLightGreen 0x0090EE90 +#define clrLightGrey 0x00D3D3D3 +#define clrLightPink 0x00FFB6C1 +#define clrLightSalmon 0x00FFA07A +#define clrLightSeaGreen 0x0020B2AA +#define clrLightSkyBlue 0x0087CEFA +#define clrLightSlateGray 0x00778899 +#define clrLightSteelBlue 0x00B0C4DE +#define clrLightYellow 0x00FFFFE0 +#define clrLime 0x0000FF00 +#define clrLimeGreen 0x0032CD32 +#define clrLinen 0x00FAF0E6 +#define clrMagenta 0x00FF00FF +#define clrMaroon 0x00800000 +#define clrMediumAquamarine 0x0066CDAA +#define clrMediumBlue 0x000000CD +#define clrMediumOrchid 0x00BA55D3 +#define clrMediumPurple 0x009370DB +#define clrMediumSeaGreen 0x003CB371 +#define clrMediumSlateBlue 0x007B68EE +#define clrMediumSpringGreen 0x0000FA9A +#define clrMediumTurquoise 0x0048D1CC +#define clrMediumVioletRed 0x00C71585 +#define clrMidnightBlue 0x00191970 +#define clrMintCream 0x00F5FFFA +#define clrMistyRose 0x00FFE4E1 +#define clrMoccasin 0x00FFE4B5 +#define clrNavajoWhite 0x00FFDEAD +#define clrNavy 0x00000080 +#define clrOldLace 0x00FDF5E6 +#define clrOlive 0x00808000 +#define clrOliveDrab 0x006B8E23 +#define clrOrange 0x00FFA500 +#define clrOrangeRed 0x00FF4500 +#define clrOrchid 0x00DA70D6 +#define clrPaleGoldenrod 0x00EEE8AA +#define clrPaleGreen 0x0098FB98 +#define clrPaleTurquoise 0x00AFEEEE +#define clrPaleVioletRed 0x00DB7093 +#define clrPapayaWhip 0x00FFEFD5 +#define clrPeachPuff 0x00FFDAB9 +#define clrPeru 0x00CD853F +#define clrPink 0x00FFC0CB +#define clrPlum 0x00DDA0DD +#define clrPowderBlue 0x00B0E0E6 +#define clrPurple 0x00800080 +#define clrRed 0x00FF0000 +#define clrRosyBrown 0x00BC8F8F +#define clrRoyalBlue 0x004169E1 +#define clrSaddleBrown 0x008B4513 +#define clrSalmon 0x00FA8072 +#define clrSandyBrown 0x00F4A460 +#define clrSeaGreen 0x002E8B57 +#define clrSeashell 0x00FFF5EE +#define clrSienna 0x00A0522D +#define clrSilver 0x00C0C0C0 +#define clrSkyBlue 0x0087CEEB +#define clrSlateBlue 0x006A5ACD +#define clrSlateGray 0x00708090 +#define clrSnow 0x00FFFAFA +#define clrSpringGreen 0x0000FF7F +#define clrSteelBlue 0x004682B4 +#define clrTan 0x00D2B48C +#define clrTeal 0x00008080 +#define clrThistle 0x00D8BFD8 +#define clrTomato 0x00FF6347 +#define clrTurquoise 0x0040E0D0 +#define clrViolet 0x00EE82EE +#define clrWheat 0x00F5DEB3 +#define clrWhite 0x00FFFFFF +#define clrWhiteSmoke 0x00F5F5F5 +#define clrYellow 0x00FFFF00 +#define clrYellowGreen 0x009ACD32 + +#define AliceBlue clrAliceBlue +#define AntiqueWhite clrAntiqueWhite +#define Aqua clrAqua +#define Aquamarine clrAquamarine +#define Beige clrBeige +#define Bisque clrBisque +#define Black clrBlack +#define BlanchedAlmond clrBlanchedAlmond +#define Blue clrBlue +#define BlueViolet clrBlueViolet +#define Brown clrBrown +#define BurlyWood clrBurlyWood +#define CadetBlue clrCadetBlue +#define Chartreuse clrChartreuse +#define Chocolate clrChocolate +#define Coral clrCoral +#define CornflowerBlue clrCornflowerBlue +#define Cornsilk clrCornsilk +#define Crimson clrCrimson +#define DarkBlue clrDarkBlue +#define DarkGoldenrod clrDarkGoldenrod +#define DarkGray clrDarkGray +#define DarkGreen clrDarkGreen +#define DarkKhaki clrDarkKhaki +#define DarkOliveGreen clrDarkOliveGreen +#define DarkOrange clrDarkOrange +#define DarkOrchid clrDarkOrchid +#define DarkSalmon clrDarkSalmon +#define DarkSeaGreen clrDarkSeaGreen +#define DarkSlateBlue clrDarkSlateBlue +#define DarkSlateGray clrDarkSlateGray +#define DarkTurquoise clrDarkTurquoise +#define DarkViolet clrDarkViolet +#define DeepPink clrDeepPink +#define DeepSkyBlue clrDeepSkyBlue +#define DimGray clrDimGray +#define DodgerBlue clrDodgerBlue +#define FireBrick clrFireBrick +#define ForestGreen clrForestGreen +#define Gainsboro clrGainsboro +#define Gold clrGold +#define Goldenrod clrGoldenrod +#define Gray clrGray +#define Green clrGreen +#define GreenYellow clrGreenYellow +#define Honeydew clrHoneydew +#define HotPink clrHotPink +#define IndianRed clrIndianRed +#define Indigo clrIndigo +#define Ivory clrIvory +#define Khaki clrKhaki +#define Lavender clrLavender +#define LavenderBlush clrLavenderBlush +#define LawnGreen clrLawnGreen +#define LemonChiffon clrLemonChiffon +#define LightBlue clrLightBlue +#define LightCoral clrLightCoral +#define LightCyan clrLightCyan +#define LightGoldenrod clrLightGoldenrod +#define LightGray clrLightGray +#define LightGreen clrLightGreen +#define LightPink clrLightPink +#define LightSalmon clrLightSalmon +#define LightSeaGreen clrLightSeaGreen +#define LightSkyBlue clrLightSkyBlue +#define LightSlateGray clrLightSlateGray +#define LightSteelBlue clrLightSteelBlue +#define LightYellow clrLightYellow +#define Lime clrLime +#define LimeGreen clrLimeGreen +#define Linen clrLinen +#define Magenta clrMagenta +#define Maroon clrMaroon +#define MediumAquamarine clrMediumAquamarine +#define MediumBlue clrMediumBlue +#define MediumOrchid clrMediumOrchid +#define MediumPurple clrMediumPurple +#define MediumSeaGreen clrMediumSeaGreen +#define MediumSlateBlue clrMediumSlateBlue +#define MediumSpringGreen clrMediumSpringGreen +#define MediumTurquoise clrMediumTurquoise +#define MediumVioletRed clrMediumVioletRed +#define MidnightBlue clrMidnightBlue +#define MintCream clrMintCream +#define MistyRose clrMistyRose +#define Moccasin clrMoccasin +#define NavajoWhite clrNavajoWhite +#define Navy clrNavy +#define OldLace clrOldLace +#define Olive clrOlive +#define OliveDrab clrOliveDrab +#define Orange clrOrange +#define OrangeRed clrOrangeRed +#define Orchid clrOrchid +#define PaleGoldenrod clrPaleGoldenrod +#define PaleGreen clrPaleGreen +#define PaleTurquoise clrPaleTurquoise +#define PaleVioletRed clrPaleVioletRed +#define PapayaWhip clrPapayaWhip +#define PeachPuff clrPeachPuff +#define Peru clrPeru +#define Pink clrPink +#define Plum clrPlum +#define PowderBlue clrPowderBlue +#define Purple clrPurple +#define Red clrRed +#define RosyBrown clrRosyBrown +#define RoyalBlue clrRoyalBlue +#define SaddleBrown clrSaddleBrown +#define Salmon clrSalmon +#define SandyBrown clrSandyBrown +#define SeaGreen clrSeaGreen +#define Seashell clrSeashell +#define Sienna clrSienna +#define Silver clrSilver +#define SkyBlue clrSkyBlue +#define SlateBlue clrSlateBlue +#define SlateGray clrSlateGray +#define Snow clrSnow +#define SpringGreen clrSpringGreen +#define SteelBlue clrSteelBlue +#define Tan clrTan +#define Teal clrTeal +#define Thistle clrThistle +#define Tomato clrTomato +#define Turquoise clrTurquoise +#define Violet clrViolet +#define Wheat clrWheat +#define White clrWhite +#define WhiteSmoke clrWhiteSmoke +#define Yellow clrYellow +#define YellowGreen clrYellowGreen + #ifndef __MQL__ #define clrNONE -1 #define CLR_NONE -1 -#define DarkSeaGreen 0x8BBC8F #endif // Custom user errors. diff --git a/Trade.mqh b/Trade.mqh index f6eea3136..eb74a6564 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -31,7 +31,6 @@ class Trade; // Includes. #include "Account/AccountMt.h" -#include "Chart.mqh" #include "Convert.mqh" #include "DictStruct.mqh" #include "Indicator/IndicatorData.h" From 36993ce915e3b9a3bc458a2f233a22c5c0a93926 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 12 Jan 2023 20:08:20 +0100 Subject: [PATCH 07/42] WIP. Fixing Emscripten compilation errors. --- Chart.struct.tf.h | 4 +-- Draw.mqh | 2 +- DrawIndicator.mqh | 8 +++--- Indicator/Indicator.define.h | 3 ++ Indicator/Indicator.enum.h | 2 +- Indicator/Indicator.struct.h | 8 +++--- Indicator/IndicatorData.h | 31 +++++++++++---------- Indicator/IndicatorData.struct.cache.h | 4 +-- Indicator/IndicatorData.struct.h | 4 ++- Indicator/IndicatorData.struct.serialize.h | 8 +++--- Indicator/IndicatorData.struct.signal.h | 21 ++++++++++---- Order.struct.h | 7 +++-- Platform.extern.h | 22 +++++++++++---- Platform.h | 32 ++++++++++++++++++++++ Std.h | 2 +- 15 files changed, 110 insertions(+), 48 deletions(-) diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 1f1a2f89c..81f26a1c3 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -28,7 +28,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#include "Platform.h" +#include "Platform.extern.h" #endif // Forward declarations. @@ -280,7 +280,7 @@ struct ChartTf { * @param * _tf ENUM_TIMEFRAMES Specify timeframe enum. */ - static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { return ::PeriodSeconds(_tf); } + static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { return ChartTf::TfToSeconds(_tf); } /** * Returns text representation of the timeframe constant. diff --git a/Draw.mqh b/Draw.mqh index 3fb403904..5cea3f3ee 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -32,7 +32,7 @@ class Draw; // Includes. #include "Data.define.h" #include "Object.extern.h" -#include "Platform.h" +//#include "Platform.h" #include "Terminal.define.h" #ifndef __MQL4__ diff --git a/DrawIndicator.mqh b/DrawIndicator.mqh index 36269393e..d1ec770be 100644 --- a/DrawIndicator.mqh +++ b/DrawIndicator.mqh @@ -128,11 +128,11 @@ class DrawIndicator { } else { DrawPoint* last_point = last_points.GetByKey(_name); - draw.TLine(_name + "_" + IntegerToString(_time), last_point.value, _value, last_point.time, _time, color_line, - false, _window); + draw PTR_DEREF TLine(_name + "_" + IntegerToString(_time), last_point PTR_DEREF value, _value, + last_point PTR_DEREF time, _time, color_line, false, _window); - last_point.time = _time; - last_point.value = _value; + last_point PTR_DEREF time = _time; + last_point PTR_DEREF value = _value; } } }; diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index d0e2900df..b16a7b853 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -30,6 +30,9 @@ #pragma once #endif +// Includes. +#include "../Platform.extern.h" + // Defines macros. #define COMMA , #define DUMMY diff --git a/Indicator/Indicator.enum.h b/Indicator/Indicator.enum.h index 646788714..660658722 100644 --- a/Indicator/Indicator.enum.h +++ b/Indicator/Indicator.enum.h @@ -178,7 +178,7 @@ enum ENUM_SIGNAL_LINE { FINAL_SIGNAL_LINE_ENTRY, }; -#ifdef __MQL4__ +#ifndef __MQL5__ /** * The volume type is used in calculations. * diff --git a/Indicator/Indicator.struct.h b/Indicator/Indicator.struct.h index 90d45fea2..a05d0bb5f 100644 --- a/Indicator/Indicator.struct.h +++ b/Indicator/Indicator.struct.h @@ -85,19 +85,19 @@ struct IndicatorParams { DataParamEntry _param = input_params[_index]; switch (_param.type) { case TYPE_BOOL: - return (T)param.integer_value; + return (T)_param.integer_value; case TYPE_INT: case TYPE_LONG: case TYPE_UINT: case TYPE_ULONG: - return param.integer_value; + return _param.integer_value; case TYPE_DOUBLE: case TYPE_FLOAT: - return (T)param.double_value; + return (T)_param.double_value; case TYPE_CHAR: case TYPE_STRING: case TYPE_UCHAR: - return (T)param.string_value; + return (T)_param.string_value; default: SetUserError(ERR_INVALID_PARAMETER); break; diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 78b5bb1f1..981a52b82 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -31,10 +31,11 @@ // Forward class declaration. class IndicatorBase; -class IndicatorDraw; +class DrawIndicator; // Includes. #include "../Bar.struct.h" +#include "../Chart.struct.tf.h" #include "../Flags.h" #include "../Storage/IValueStorage.h" #include "../Storage/ItemsHistory.h" @@ -70,7 +71,7 @@ class IndicatorData : public IndicatorBase { IndicatorCalculateCache cache; IndicatorDataParams idparams; // Indicator data params. IndicatorState istate; - Ref indi_src; // Indicator used as data source. + Ref indi_src; // Indicator used as data source. protected: /* Protected methods */ @@ -87,7 +88,7 @@ class IndicatorData : public IndicatorBase { case IDATA_ICUSTOM: break; case IDATA_INDICATOR: - if (indi_src.IsSet() == NULL) { + if (indi_src.IsSet()) { // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); // SetDataSource(_indi_price, true, PRICE_OPEN); } @@ -120,9 +121,11 @@ class IndicatorData : public IndicatorBase { * Deinitialize drawing. */ void DeinitDraw() { + /* @todo: To refactor. if (draw) { delete draw; } + */ } public: @@ -225,7 +228,7 @@ class IndicatorData : public IndicatorBase { } return GetName() + "#" + IntegerToString(GetId()) + "-" + _mode + "[" + IntegerToString(_max_modes) + "]" + - (HasDataSource() ? (" (over " + GetDataSource(false).GetFullName() + ")") : ""); + (HasDataSource() ? (" (over " + GetDataSource(false) PTR_DEREF GetFullName() + ")") : ""); } /** @@ -391,13 +394,13 @@ class IndicatorData : public IndicatorBase { */ template double GetMax(int start_bar = 0, int count = WHOLE_ARRAY) { - double max = NULL; + double max = -DBL_MAX; int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); for (int shift = start_bar; shift <= last_bar; ++shift) { double value = GetEntry(shift).GetMax(_max_modes); - if (max == NULL || value > max) { + if (max == -DBL_MAX || value > max) { max = value; } } @@ -410,13 +413,13 @@ class IndicatorData : public IndicatorBase { */ template double GetMin(int start_bar, int count = WHOLE_ARRAY) { - double min = NULL; + double min = DBL_MAX; int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); for (int shift = start_bar; shift <= last_bar; ++shift) { double value = GetEntry(shift).GetMin(_max_modes); - if (min == NULL || value < min) { + if (min == DBL_MAX || value < min) { min = value; } } @@ -450,7 +453,7 @@ class IndicatorData : public IndicatorBase { */ template double GetMed(int start_bar, int count = WHOLE_ARRAY) { - double array[]; + ARRAY(double, array); int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); int num_bars = last_bar - start_bar + 1; @@ -513,7 +516,7 @@ class IndicatorData : public IndicatorBase { * Returns true of successful copy. * Returns false on invalid values. */ - bool CopyEntries(IndicatorDataEntry& _data[], int _count, int _start_shift = 0) { + bool CopyEntries(ARRAY_REF(IndicatorDataEntry, _data), int _count, int _start_shift = 0) { bool _is_valid = true; if (ArraySize(_data) < _count) { _is_valid &= ArrayResize(_data, _count) > 0; @@ -534,7 +537,7 @@ class IndicatorData : public IndicatorBase { * Returns false on invalid values. */ template - bool CopyValues(T& _data[], int _count, int _start_shift = 0, int _mode = 0) { + bool CopyValues(ARRAY_REF(T, _data), int _count, int _start_shift = 0, int _mode = 0) { bool _is_valid = true; if (ArraySize(_data) < _count) { _count = ArrayResize(_data, _count); @@ -1184,7 +1187,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's struct value via index. */ - virtual IndicatorDataEntry GetEntry(int _rel_shift = 0) = NULL; + virtual IndicatorDataEntry GetEntry(int _rel_shift = 0) = 0; /** * Returns the indicator's struct value via timestamp. @@ -1209,7 +1212,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's entry value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) = NULL; + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) = 0; /** * Returns the shift of the maximum value over a specific number of periods depending on type. @@ -1278,7 +1281,7 @@ class IndicatorData : public IndicatorBase { * * When indicator values are not valid, returns empty signals. */ - virtual IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) = NULL; + virtual IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) = 0; /** * Returns spread for the bar. diff --git a/Indicator/IndicatorData.struct.cache.h b/Indicator/IndicatorData.struct.cache.h index c6ee5e1dc..b3c7c4f0e 100644 --- a/Indicator/IndicatorData.struct.cache.h +++ b/Indicator/IndicatorData.struct.cache.h @@ -221,7 +221,7 @@ class IndicatorCalculateCache : public Dynamic { */ void Resize(int _buffers_size) { for (int i = 0; i < ArraySize(buffers); ++i) { - buffers[i].Resize(_buffers_size, 65535); + buffers[i] PTR_DEREF Resize(_buffers_size, 65535); } } @@ -230,7 +230,7 @@ class IndicatorCalculateCache : public Dynamic { */ template D GetValue(int _buffer_index, int _shift) { - return GetBuffer(_buffer_index).Fetch(_shift).Get(); + return GetBuffer(_buffer_index) PTR_DEREF Fetch(_shift).Get(); } /** diff --git a/Indicator/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h index 3e49d5902..7d399c0c1 100644 --- a/Indicator/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -188,7 +188,7 @@ struct IndicatorDataEntry { // Constructors. IndicatorDataEntry(int _size = 1) : flags(INDI_ENTRY_FLAG_NONE), timestamp(0) { Resize(_size); } - IndicatorDataEntry(IndicatorDataEntry &_entry) { THIS_REF = _entry; } + IndicatorDataEntry(const IndicatorDataEntry &_entry) { THIS_REF = _entry; } int GetSize() { return ArraySize(values); } // Operator overloading methods. template @@ -211,7 +211,9 @@ struct IndicatorDataEntry { T operator[](I _index) { return values[(int)_index].Get(); } +#ifdef __MQL__ template <> +#endif double operator[](int _index) { if (_index >= ArraySize(values)) { return 0; diff --git a/Indicator/IndicatorData.struct.serialize.h b/Indicator/IndicatorData.struct.serialize.h index c6b97399e..d2d8067dd 100644 --- a/Indicator/IndicatorData.struct.serialize.h +++ b/Indicator/IndicatorData.struct.serialize.h @@ -42,11 +42,11 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { switch (values[i].GetDataType()) { case TYPE_DOUBLE: - _s.Pass(THIS_REF, (string)i, values[i].value.vdbl, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vdbl, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); break; case TYPE_FLOAT: - _s.Pass(THIS_REF, (string)i, values[i].value.vflt, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vflt, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); break; case TYPE_INT: @@ -58,7 +58,7 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); } } else { - _s.Pass(THIS_REF, (string)i, values[i].value.vint, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vint, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } break; @@ -74,7 +74,7 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { */ SetUserError(ERR_INVALID_PARAMETER); } else { - _s.Pass(THIS_REF, (string)i, values[i].value.vlong, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vlong, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } break; diff --git a/Indicator/IndicatorData.struct.signal.h b/Indicator/IndicatorData.struct.signal.h index f27094803..0c141f95b 100644 --- a/Indicator/IndicatorData.struct.signal.h +++ b/Indicator/IndicatorData.struct.signal.h @@ -79,11 +79,22 @@ struct IndicatorSignal { } } SetSignal(INDICATOR_SIGNAL_CROSSOVER, _is_cross); + // INDICATOR_SIGNAL_DIVERGENCE - int _shift0 = ChartStatic::iBarShift(_symbol, _tf, _data[0].timestamp); - int _shift1 = ChartStatic::iBarShift(_symbol, _tf, _data[_size - 1].timestamp); - double _price_w0 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift0); - double _price_w1 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift1); + // + // @fixit Should use pointer to IndicatorBase as a source of prices. + // int _shift0 = ChartStatic::iBarShift(_symbol, _tf, _data[0].timestamp); + // int _shift1 = ChartStatic::iBarShift(_symbol, _tf, _data[_size - 1].timestamp); + // double _price_w0 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift0); + // double _price_w1 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift1); + Alert(__FUNCSIG__, " Should use pointer to IndicatorBase as a source of prices!"); + DebugBreak(); + + int _shift0 = 0; + int _shift1 = 1; + double _price_w0 = 0; + double _price_w1 = 0; + SetSignal(INDICATOR_SIGNAL_DIVERGENCE, ((_price_w0 - _price_w1 > 0) && (_data[0][_m1] - _data[_size - 1][_m1]) < 0) || ((_price_w0 - _price_w1) < 0 && (_data[0][_m1] - _data[_size - 1][_m1]) > 0)); @@ -142,7 +153,7 @@ struct IndicatorSignal { int _size = sizeof(int) * 8; for (int i = 0; i < _size; i++) { int _value = CheckSignals(1 << i) ? 1 : 0; - _s.Pass(this, (string)(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + _s.Pass(THIS_REF, IntegerToString(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } return SerializerNodeObject; } diff --git a/Order.struct.h b/Order.struct.h index fff61929c..93f02f4f3 100644 --- a/Order.struct.h +++ b/Order.struct.h @@ -139,7 +139,8 @@ struct OrderParams { // s.Pass(THIS_REF, "cond_args", cond_args); return SerializerNodeObject; } - } cond_close[]; + }; + ARRAY(OrderCloseCond, cond_close); bool dummy; // Whether order is dummy (fake) or not (real). color color_arrow; // Color of the opening arrow on the chart. unsigned short refresh_freq; // How often to refresh order values (in secs). @@ -201,7 +202,7 @@ struct OrderParams { SetUserError(ERR_INVALID_PARAMETER); } void SetConditionClose(ENUM_ORDER_CONDITION _cond, int _index = 0) { - DataParamEntry _args[]; + ARRAY(DataParamEntry, _args); SetConditionClose(_cond, _args, _index); } void SetConditionClose(ENUM_ORDER_CONDITION _cond, ARRAY_REF(DataParamEntry, _args), int _index = 0) { @@ -290,7 +291,7 @@ struct OrderData { volume_curr(0), volume_init(0) {} // Copy constructor. - OrderData(OrderData &_odata) { this = _odata; } + OrderData(OrderData &_odata) { THIS_REF = _odata; } // Getters. template T Get(ENUM_ORDER_PROPERTY_CUSTOM _prop_name) { diff --git a/Platform.extern.h b/Platform.extern.h index 87adc94ca..0c2ea98d6 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -23,16 +23,26 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#endif - -// Includes. -#include "Platform.h" -#ifndef __MQL__ +template +double iCustom(string symbol, int timeframe, string name, Args... args) { + Alert(__FUNCSIG__, " it not implemented!"); + return 0; +} /** * Returns number of candles for a given symbol and time-frame. */ -static int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { return Platform::Bars(_symbol, _tf); } +extern int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf); + +/** + * Returns the number of calculated data for the specified indicator. + */ +extern int BarsCalculated(int indicator_handle); + +/** + * Gets data of a specified buffer of a certain indicator in the necessary quantity. + */ +extern int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)); #endif diff --git a/Platform.h b/Platform.h index f0da9db31..f8d3a0a44 100644 --- a/Platform.h +++ b/Platform.h @@ -44,6 +44,7 @@ extern int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf); * Current platform's static methods. */ +#include "DrawIndicator.mqh" #include "Flags.h" #include "Indicator/IndicatorData.h" #include "Indicator/tests/classes/IndicatorTfDummy.h" @@ -206,6 +207,14 @@ class Platform { return 0; } + /** + * Returns the number of calculated data for the specified indicator. + */ + static int BarsCalculated(int indicator_handle) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; + } + /** * Returns id of the current chart. */ @@ -353,6 +362,29 @@ int Platform::global_tick_index = 0; DictStruct> Platform::indis; DictStruct> Platform::indis_dflt; +#ifndef __MQL__ +// Following methods must be there are they're externed in Platform.extern.h +// and there's no better place for them! + +/** + * Returns number of candles for a given symbol and time-frame. + */ +int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { return Platform::Bars(_symbol, _tf); } + +/** + * Returns the number of calculated data for the specified indicator. + */ +int BarsCalculated(int indicator_handle) { return Platform::BarsCalculated(indicator_handle); } + +/** + * Gets data of a specified buffer of a certain indicator in the necessary quantity. + */ +int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); +} + +#endif + /** * Will test given indicator class with platform-default data source bindings. */ diff --git a/Std.h b/Std.h index 8337ec71d..a7670198f 100644 --- a/Std.h +++ b/Std.h @@ -238,7 +238,7 @@ class color { unsigned int value; public: - color(unsigned int _color) { value = _color; } + color(unsigned int _color = 0) { value = _color; } color& operator=(unsigned int _color) { value = _color; return *this; From efa69daba8e2b380993b2d5f603f7f9c3920195f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Sat, 14 Jan 2023 13:47:56 +0100 Subject: [PATCH 08/42] WIP. Fixing Emscripten compilation errors. --- Deal.enum.h | 4 ++++ Order.mqh | 15 ++++++++------- Platform.extern.h | 21 +++++++++++++++++++++ Platform.h | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/Deal.enum.h b/Deal.enum.h index ceef21a7f..41c3ca747 100644 --- a/Deal.enum.h +++ b/Deal.enum.h @@ -26,6 +26,10 @@ */ #ifndef __MQL__ + +// Allows the preprocessor to include a header file when it is needed. +#pragma once + enum ENUM_DEAL_TYPE { DEAL_TYPE_BUY, DEAL_TYPE_SELL, diff --git a/Order.mqh b/Order.mqh index b0092bee5..b7508eace 100644 --- a/Order.mqh +++ b/Order.mqh @@ -305,9 +305,10 @@ class Order : public SymbolInfo { int _num = oparams.Get(ORDER_PARAM_COND_CLOSE_NUM); for (int _ci = 0; _ci < _num; _ci++) { ENUM_ORDER_CONDITION _cond = oparams.Get(ORDER_PARAM_COND_CLOSE, _ci); - DataParamEntry _cond_args[1]; - _cond_args[0] = oparams.Get(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _ci); - _result |= _result || Order::CheckCondition(_cond, _cond_args); + ARRAY(DataParamEntry, _cond_args); + DataParamEntry _item0 = oparams.Get(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _ci); + ArrayPush(_cond_args, _item0); + _result |= Order::CheckCondition(_cond, _cond_args); } } return _result; @@ -470,7 +471,7 @@ class Order : public SymbolInfo { #endif } datetime GetOpenTime() { - if (odata.Get(ORDER_PROP_TIME_OPENED) == 0) { + if (odata.Get(ORDER_PROP_TIME_OPENED) == (datetime)0) { OrderSelect(); odata.Set(ORDER_PROP_TIME_OPENED, Order::OrderOpenTime()); } @@ -503,7 +504,7 @@ class Order : public SymbolInfo { return (datetime)_result; #endif } - datetime GetCloseTime() { return IsClosed() ? odata.Get(ORDER_PROP_TIME_CLOSED) : 0; } + datetime GetCloseTime() { return IsClosed() ? odata.Get(ORDER_PROP_TIME_CLOSED) : (datetime)0; } /** * Returns comment of the currently selected order/position. @@ -695,7 +696,7 @@ class Order : public SymbolInfo { case ORDER_TP: return OrderTakeProfit(); } - return NULL; + return 0; } /** @@ -1003,7 +1004,7 @@ class Order : public SymbolInfo { * * @see: https://docs.mql4.com/trading/orderdelete */ - static bool OrderDelete(unsigned long _ticket, color _color = NULL) { + static bool OrderDelete(unsigned long _ticket, color _color = color()) { #ifdef __MQL4__ return ::OrderDelete((int)_ticket, _color); #else diff --git a/Platform.extern.h b/Platform.extern.h index 0c2ea98d6..81cd3a12a 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -24,6 +24,9 @@ // Allows the preprocessor to include a header file when it is needed. #pragma once +// Includes. +#include "Deal.enum.h" + template double iCustom(string symbol, int timeframe, string name, Args... args) { Alert(__FUNCSIG__, " it not implemented!"); @@ -45,4 +48,22 @@ extern int BarsCalculated(int indicator_handle); */ extern int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)); +extern unsigned long PositionGetTicket(int _index); + +extern long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id); + +extern double PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE property_id); + +extern string PositionGetString(ENUM_POSITION_PROPERTY_STRING property_id); + +extern int HistoryDealsTotal(); + +extern unsigned long HistoryDealGetTicket(int index); + +extern long HistoryDealGetInteger(unsigned long ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id); + +extern double HistoryDealGetDouble(unsigned long ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id); + +extern string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRING property_id); + #endif diff --git a/Platform.h b/Platform.h index f8d3a0a44..16e026f55 100644 --- a/Platform.h +++ b/Platform.h @@ -23,9 +23,9 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#endif -#ifndef __MQL__ +// Includes. +#include "Deal.enum.h" /** * Extern declarations for C++. @@ -383,6 +383,48 @@ int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, A Print("Not yet implemented: ", __FUNCTION__, " returns 0."); } +unsigned long PositionGetTicket(int _index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); } + +long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +string PositionGetString(ENUM_POSITION_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return ""; +} + +int HistoryDealsTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +unsigned long HistoryDealGetTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +long HistoryDealGetInteger(unsigned long ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double HistoryDealGetDouble(unsigned long ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return 0; +} + #endif /** From db0b8a0a3d74f4687764929dbb022277f2c04757 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 19 Jan 2023 20:06:25 +0100 Subject: [PATCH 09/42] WIP. Making code C++/Emscripten-compatible. --- Account/AccountMt.h | 3 +- Chart.struct.static.h | 4 +- Indicator/Indicator.define.h | 3 - Indicator/IndicatorData.h | 70 +++++------ Order.enum.h | 3 +- Order.mqh | 20 ++-- Order.struct.h | 1 + OrderQuery.h | 24 ++-- Orders.mqh | 33 ++--- Platform.extern.h | 69 +++++++++++ Platform.h | 148 +++++++++++++++++++++++ Refs.struct.h | 9 +- Serializer/SerializerConverter.h | 2 +- Std.h | 12 +- Storage/ValueStorage.indicator.h | 6 +- String.extern.h | 12 ++ Trade.mqh | 182 ++++++++++++++-------------- Trade.struct.h | 200 ++++++++++++++++--------------- 18 files changed, 525 insertions(+), 276 deletions(-) diff --git a/Account/AccountMt.h b/Account/AccountMt.h index 9e1713692..2ecb09dac 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -37,6 +37,7 @@ class AccountMt; #include "../Orders.mqh" #include "../Serializer/Serializer.h" #include "../SymbolInfo.mqh" +#include "../Task/TaskCondition.enum.h" #include "../Trade.struct.h" #include "Account.define.h" #include "Account.enum.h" @@ -283,7 +284,7 @@ class AccountMt { return ::AccountFreeMarginMode(); #else // @todo: Not implemented yet. - return NULL; + return NULL_VALUE; #endif } static double GetAccountFreeMarginMode() { return AccountMt::AccountFreeMarginMode(); } diff --git a/Chart.struct.static.h b/Chart.struct.static.h index cf19e5805..6d02bb9d4 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -75,7 +75,7 @@ struct ChartStatic { } return _bar_shift; #else // __MQL5__ - if (_time < 0) return (-1); + if (_time == (datetime)0) return (-1); ARRAY(datetime, arr); datetime _time0; // ENUM_TIMEFRAMES _tf = MQL4::TFMigrate(_tf); @@ -337,7 +337,7 @@ struct ChartStatic { // ENUM_TIMEFRAMES _tf = MQL4::TFMigrate(_tf); // @todo: Improves performance by caching values. - datetime _time = (_shift >= 0 && ::CopyTime(_symbol, _tf, _shift, 1, _arr) > 0) ? _arr[0] : 0; + datetime _time = (_shift >= 0 && ::CopyTime(_symbol, _tf, _shift, 1, _arr) > 0) ? _arr[0] : (datetime)0; if (_LastError != ERR_NO_ERROR) { Print("Error: ", _LastError, " while doing CopyTime() in ChartStatic::GetBarTime(", _symbol, ", ", diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index b16a7b853..d0e2900df 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -30,9 +30,6 @@ #pragma once #endif -// Includes. -#include "../Platform.extern.h" - // Defines macros. #define COMMA , #define DUMMY diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 981a52b82..d6ab968d3 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -30,7 +30,7 @@ #endif // Forward class declaration. -class IndicatorBase; +class IndicatorData; class DrawIndicator; // Includes. @@ -48,6 +48,8 @@ class DrawIndicator; #include "IndicatorData.struct.serialize.h" #include "IndicatorData.struct.signal.h" +extern IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData* _indi, int _mode); + /** * Implements class to store indicator data. */ @@ -71,7 +73,7 @@ class IndicatorData : public IndicatorBase { IndicatorCalculateCache cache; IndicatorDataParams idparams; // Indicator data params. IndicatorState istate; - Ref indi_src; // Indicator used as data source. + Ref indi_src; // Indicator used as data source. protected: /* Protected methods */ @@ -134,7 +136,7 @@ class IndicatorData : public IndicatorBase { /** * Class constructor. */ - IndicatorData(const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + IndicatorData(const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) : do_draw(false), idparams(_idparams), indi_src(_indi_src) { Init(); } @@ -576,7 +578,7 @@ class IndicatorData : public IndicatorBase { } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) { int _source_id = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)); - Print("Setting data source by id is now obsolete. Please use SetDataSource(IndicatorBase*) method for ", + Print("Setting data source by id is now obsolete. Please use SetDataSource(IndicatorData*) method for ", GetName(), " (data source id ", _source_id, ")."); DebugBreak(); @@ -608,7 +610,7 @@ class IndicatorData : public IndicatorBase { } if (_validate) { - ValidateDataSource(&this, _result); + ValidateDataSource(THIS_PTR, _result); } return _result; @@ -776,7 +778,7 @@ class IndicatorData : public IndicatorBase { // If _indi or any of the _indi's data source points to this indicator then this would create circular dependency. for (_curr = _indi; _curr != nullptr && _iterations_left != 0; - _curr = _curr.GetDataSource(false), --_iterations_left) { + _curr = _curr PTR_DEREF GetDataSource(false), --_iterations_left) { if (_curr == THIS_PTR) { // Circular dependency found. Print("Error: Circular dependency found when trying to attach " + _indi PTR_DEREF GetFullName() + " into " + @@ -788,15 +790,15 @@ class IndicatorData : public IndicatorBase { if (indi_src.IsSet()) { if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT) && - !bool(_indi.GetFlags() | INDI_FLAG_INDEXABLE_BY_SHIFT)) { - Print(GetFullName(), ": Cannot set data source to ", _indi.GetFullName(), + !bool(_indi PTR_DEREF GetFlags() | INDI_FLAG_INDEXABLE_BY_SHIFT)) { + Print(GetFullName(), ": Cannot set data source to ", _indi PTR_DEREF GetFullName(), ", because source indicator isn't indexable by shift!"); DebugBreak(); return; } if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP) && - !bool(_indi.GetFlags() | INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { - Print(GetFullName(), ": Cannot set data source to ", _indi.GetFullName(), + !bool(_indi PTR_DEREF GetFlags() | INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { + Print(GetFullName(), ": Cannot set data source to ", _indi PTR_DEREF GetFullName(), ", because source indicator isn't indexable by timestamp!"); DebugBreak(); return; @@ -804,14 +806,14 @@ class IndicatorData : public IndicatorBase { } if (indi_src.IsSet() && indi_src.Ptr() != _indi) { - indi_src.Ptr().RemoveListener(THIS_PTR); + indi_src REF_DEREF RemoveListener(THIS_PTR); } indi_src = _indi; if (_indi != NULL) { - indi_src.Ptr().AddListener(THIS_PTR); + indi_src REF_DEREF AddListener(THIS_PTR); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID), -1); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE), _input_mode); - indi_src.Ptr().OnBecomeDataSourceFor(THIS_PTR); + indi_src REF_DEREF OnBecomeDataSourceFor(THIS_PTR); } } @@ -870,14 +872,14 @@ class IndicatorData : public IndicatorBase { last_tick_index = _global_tick_index; // Checking and potentially initializing new data source. - if (HasDataSource(true) != NULL) { + if (HasDataSource(true)) { // Ticking data source if not yet ticked. - GetDataSource().Tick(_global_tick_index); + GetDataSource() PTR_DEREF Tick(_global_tick_index); } // Also ticking all used indicators if they've not yet ticked. for (DictStructIterator> iter = indicators.Begin(); iter.IsValid(); ++iter) { - iter.Value().Ptr().Tick(_global_tick_index); + iter.Value() REF_DEREF Tick(_global_tick_index); } // Overridable OnTick() method. @@ -925,27 +927,27 @@ class IndicatorData : public IndicatorBase { return; } - if (!_target.IsDataSourceModeSelectable()) { + if (!_target PTR_DEREF IsDataSourceModeSelectable()) { // We don't validate source mode as it will use all modes. return; } - if (_source.GetModeCount() > 1 && - _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { + if (_source PTR_DEREF GetModeCount() > 1 && + _target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { // Mode must be selected if source indicator has more that one mode. Alert("Warning! ", GetName(), " must select source indicator's mode via SetDataSourceMode(int). Defaulting to mode 0."); - _target.idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); + _target PTR_DEREF idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); DebugBreak(); - } else if (_source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == 1 && - _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { - _target.idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); - } else if (_target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) < 0 || - _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) > - _source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) { - Alert("Error! ", _target.GetName(), + } else if (_source PTR_DEREF Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == 1 && + _target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { + _target PTR_DEREF idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); + } else if (_target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) < 0 || + _target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) > + _source PTR_DEREF Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) { + Alert("Error! ", _target PTR_DEREF GetName(), " must select valid source indicator's mode via SetDataSourceMode(int) between 0 and ", - _source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)), "."); + _source PTR_DEREF Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)), "."); DebugBreak(); } } @@ -1329,7 +1331,7 @@ class IndicatorData : public IndicatorBase { default: Print("Error: Invalid applied price " + EnumToString(_ap) + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " - "IndicatorBase::HasSpecificAppliedPriceValueStorage()!"); + "IndicatorData::HasSpecificAppliedPriceValueStorage()!"); DebugBreak(); return false; } @@ -1372,7 +1374,7 @@ class IndicatorData : public IndicatorBase { default: Print("Error: Invalid applied price " + EnumToString(_ap) + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " - "IndicatorBase::GetSpecificAppliedPriceValueStorage()!"); + "IndicatorData::GetSpecificAppliedPriceValueStorage()!"); DebugBreak(); return NULL; } @@ -1736,7 +1738,7 @@ class IndicatorData : public IndicatorBase { } if (!value_storages[_mode].IsSet()) { - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + value_storages[_mode] = InstantiateIndicatorBufferValueStorageDouble(THIS_PTR, _mode); } return value_storages[_mode].Ptr(); } @@ -1754,7 +1756,7 @@ class IndicatorData : public IndicatorBase { void EmitEntry(IndicatorDataEntry& entry) { for (int i = 0; i < ArraySize(listeners); ++i) { if (listeners[i].ObjectExists()) { - listeners[i].Ptr().OnDataSourceEntry(entry); + listeners[i] REF_DEREF OnDataSourceEntry(entry); } } } @@ -1891,7 +1893,7 @@ class IndicatorData : public IndicatorBase { /** * BarsCalculated()-compatible method to be used on Indicator instance. */ -int BarsCalculated(IndicatorData* _indi) { return _indi.GetBarsCalculated(); } +int BarsCalculated(IndicatorData* _indi) { return _indi PTR_DEREF GetBarsCalculated(); } /** * CopyBuffer() method to be used on Indicator instance with ValueStorage buffer. @@ -1909,7 +1911,7 @@ int CopyBuffer(IndicatorData* _indi, int _mode, int _start, int _count, ValueSto } for (int i = _start; i < _count; ++i) { - IndicatorDataEntry _entry = _indi.GetEntry(i); + IndicatorDataEntry _entry = _indi PTR_DEREF GetEntry(i); if (!_entry.IsValid()) { break; diff --git a/Order.enum.h b/Order.enum.h index c6489a73d..c466d638a 100644 --- a/Order.enum.h +++ b/Order.enum.h @@ -243,7 +243,8 @@ enum ENUM_ORDER_TYPE { // price. ORDER_TYPE_SELL_STOP_LIMIT, // Upon reaching the order price, a pending Sell Limit order is placed at the StopLimit // price. - ORDER_TYPE_CLOSE_BY // Order to close a position by an opposite one. + ORDER_TYPE_CLOSE_BY, // Order to close a position by an opposite one. + ORDER_TYPE_UNSET // A NULL value. }; #endif diff --git a/Order.mqh b/Order.mqh index b7508eace..7808c34ca 100644 --- a/Order.mqh +++ b/Order.mqh @@ -1081,9 +1081,9 @@ class Order : public SymbolInfo { if (IsClosed()) { Refresh(); } else { - GetLogger().Warning(StringFormat("Failed to modify order (#%d/p:%g/sl:%g/tp:%g/code:%d).", - odata.Get(ORDER_PROP_TICKET), _price, _sl, _tp, _last_error), - __FUNCTION_LINE__, ToCSV()); + GetLogger() PTR_DEREF Warning(StringFormat("Failed to modify order (#%d/p:%g/sl:%g/tp:%g/code:%d).", + odata.Get(ORDER_PROP_TICKET), _price, _sl, _tp, _last_error), + __FUNCTION_LINE__, ToCSV()); Refresh(ORDER_SL); Refresh(ORDER_TP); // TODO: Refresh(ORDER_PRI) @@ -1693,7 +1693,7 @@ class Order : public SymbolInfo { if (!_result || _last_error > ERR_NO_ERROR) { if (_last_error > ERR_NO_ERROR && _last_error != 4014) { // @fixme: In MT4 (why 4014?). - GetLogger().Warning(StringFormat("Update failed! Error: %d", _last_error), __FUNCTION_LINE__); + GetLogger() PTR_DEREF Warning(StringFormat("Update failed! Error: %d", _last_error), __FUNCTION_LINE__); } odata.ProcessLastError(); ResetLastError(); @@ -1984,7 +1984,7 @@ class Order : public SymbolInfo { * Return text representation of the order. */ static string OrderTypeToString(ENUM_ORDER_TYPE _cmd, bool _lc = false) { - _cmd = _cmd != NULL ? _cmd : OrderType(); + _cmd = _cmd != ORDER_TYPE_UNSET ? _cmd : OrderType(); string _res = StringSubstr(EnumToString(_cmd), 11); StringReplace(_res, "_", " "); if (_lc) { @@ -2059,8 +2059,8 @@ class Order : public SymbolInfo { /** * Get color of the order based on its type. */ - static color GetOrderColor(ENUM_ORDER_TYPE _cmd = (ENUM_ORDER_TYPE)-1, color cbuy = Blue, color csell = Red) { - if (_cmd == NULL) _cmd = (ENUM_ORDER_TYPE)OrderType(); + static color GetOrderColor(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, color cbuy = Blue, color csell = Red) { + if (_cmd == ORDER_TYPE_UNSET) _cmd = (ENUM_ORDER_TYPE)OrderType(); return OrderData::GetTypeValue(_cmd) > 0 ? cbuy : csell; } @@ -2308,7 +2308,7 @@ class Order : public SymbolInfo { _out = OrderGetString(property_id); return true; #else - return OrderGetParam(property_id, selected_ticket_type, ORDER_SELECT_DATA_TYPE_STRING, _out) != (string)NULL_VALUE; + return OrderGetParam(property_id, selected_ticket_type, ORDER_SELECT_DATA_TYPE_STRING, _out) != NULL_STRING; #endif } @@ -2333,7 +2333,7 @@ class Order : public SymbolInfo { static long OrderGetValue(int property_id, ENUM_ORDER_SELECT_TYPE type, long &_out) { switch (type) { case ORDER_SELECT_TYPE_NONE: - return NULL; + return 0; case ORDER_SELECT_TYPE_ACTIVE: _out = ::OrderGetInteger((ENUM_ORDER_PROPERTY_INTEGER)property_id); break; @@ -2371,7 +2371,7 @@ class Order : public SymbolInfo { static double OrderGetValue(int property_id, ENUM_ORDER_SELECT_TYPE type, double &_out) { switch (type) { case ORDER_SELECT_TYPE_NONE: - return NULL; + return 0; case ORDER_SELECT_TYPE_ACTIVE: _out = ::OrderGetDouble((ENUM_ORDER_PROPERTY_DOUBLE)property_id); break; diff --git a/Order.struct.h b/Order.struct.h index 93f02f4f3..897f28394 100644 --- a/Order.struct.h +++ b/Order.struct.h @@ -33,6 +33,7 @@ // Includes. #include "Data.struct.h" #include "Order.enum.h" +#include "Platform.extern.h" #include "Serializer/Serializer.h" #include "SymbolInfo.struct.static.h" #include "Terminal.mqh" diff --git a/OrderQuery.h b/OrderQuery.h index aede72e81..a3a9c9e4b 100644 --- a/OrderQuery.h +++ b/OrderQuery.h @@ -62,8 +62,8 @@ class OrderQuery : public Dynamic { template T CalcSumByProp(E _prop) { T _sum = 0; - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { - _sum += iter.Value().Ptr().Get(_prop); + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { + _sum += iter.Value() REF_DEREF Get(_prop); } return _sum; } @@ -77,10 +77,10 @@ class OrderQuery : public Dynamic { template T CalcSumByPropWithCond(E _prop, ECT _prop_cond_type, ECV _prop_cond_value) { T _sum = 0; - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { Order *_order = iter.Value().Ptr(); - if (_order.Get(_prop_cond_type) == _prop_cond_value) { - _sum += _order.Get(_prop); + if (_order PTR_DEREF Get(_prop_cond_type) == _prop_cond_value) { + _sum += _order PTR_DEREF Get(_prop); } } return _sum; @@ -96,13 +96,13 @@ class OrderQuery : public Dynamic { template Ref FindByPropViaOp(E _prop, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP) _op) { Ref _order_ref_found; - if (orders.Size() == 0) { + if (orders PTR_DEREF Size() == 0) { return _order_ref_found; } - _order_ref_found = orders.Begin().Value(); - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { + _order_ref_found = orders PTR_DEREF Begin().Value(); + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { Ref _order_ref = iter.Value(); - if (Compare(_order_ref.Ptr().Get(_prop), _op, _order_ref_found.Ptr().Get(_prop))) { + if (Compare(_order_ref REF_DEREF Get(_prop), _op, _order_ref_found REF_DEREF Get(_prop))) { _order_ref_found = _order_ref; } } @@ -119,12 +119,12 @@ class OrderQuery : public Dynamic { template Ref FindByValueViaOp(E _prop, T _value, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP) _op) { Ref _order_ref_found; - if (orders.Size() == 0) { + if (orders PTR_DEREF Size() == 0) { return _order_ref_found; } - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { Ref _order_ref = iter.Value(); - if (Compare(_order_ref.Ptr().Get(_prop), _op, _value)) { + if (Compare(_order_ref REF_DEREF Get(_prop), _op, _value)) { _order_ref_found = _order_ref; break; } diff --git a/Orders.mqh b/Orders.mqh index 906f018a6..e5ca4df9f 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -25,6 +25,7 @@ class Orders; // Includes. #include "Account/Account.h" +#include "Chart.struct.static.h" #include "Log.mqh" #include "Math.h" #include "Order.mqh" @@ -78,7 +79,7 @@ class Orders { // Enum variables. ENUM_ORDERS_POOL pool; // Struct variables. - Order *orders[]; + ARRAY(Order *, orders); // Class variables. Ref logger; // Market *market; @@ -107,7 +108,7 @@ class Orders { orders[_size] = new Order(_req); return true; } else { - Logger().Error("Cannot allocate the memory.", __FUNCTION__); + Logger() PTR_DEREF Error("Cannot allocate the memory.", __FUNCTION__); return false; } } @@ -119,7 +120,7 @@ class Orders { */ Order *SelectOrder(unsigned long _ticket) { for (unsigned int _pos = ArraySize(orders); _pos >= 0; _pos--) { - if (orders[_pos].Get(ORDER_PROP_TICKET) == _ticket) { + if (orders[_pos] PTR_DEREF Get(ORDER_PROP_TICKET) == _ticket) { return orders[_pos]; } } @@ -139,7 +140,7 @@ class Orders { ArrayResize(orders, _size + 1, 100); return orders[_size] = new Order(_ticket); } - Logger().Error(StringFormat("Cannot select order (ticket=#%d)!", _ticket), __FUNCTION__); + Logger() PTR_DEREF Error(StringFormat("Cannot select order (ticket=#%d)!", _ticket), __FUNCTION__); return NULL; } @@ -148,10 +149,10 @@ class Orders { /** * Calculate number of lots for open positions. */ - static double GetOpenLots(string _symbol = NULL, long magic_number = 0, int magic_range = 0) { + static double GetOpenLots(string _symbol = NULL_STRING, long magic_number = 0, int magic_range = 0) { double total_lots = 0; // @todo: Convert to MQL5. - _symbol = _symbol != NULL ? _symbol : _Symbol; + _symbol = _symbol != NULL_STRING ? _symbol : _Symbol; for (int i = 0; i < OrdersTotal(); i++) { if (Order::TryOrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break; if (Order::OrderSymbol() == _symbol) { @@ -173,7 +174,7 @@ class Orders { * Returns sum of all stop loss or profit take points * from all opened orders for the given symbol. */ - static double TotalSLTP(ENUM_ORDER_TYPE _cmd = NULL, bool sl = true) { + static double TotalSLTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, bool sl = true) { double total_buy_sl = 0, total_buy_tp = 0; double total_sell_sl = 0, total_sell_tp = 0; // @todo: Convert to MQL5. @@ -219,7 +220,7 @@ class Orders { /** * Get sum of total stop loss values of opened orders. */ - double TotalSL(ENUM_ORDER_TYPE _cmd = NULL) { return TotalSLTP(_cmd, true); } + double TotalSL(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return TotalSLTP(_cmd, true); } /** * Get sum of total take profit values of opened orders. @@ -227,7 +228,7 @@ class Orders { * @return * Returns total take profit points. */ - double TotalTP(ENUM_ORDER_TYPE _cmd = NULL) { return TotalSLTP(_cmd, false); } + double TotalTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return TotalSLTP(_cmd, false); } /** * Get ratio of total stop loss points. @@ -235,7 +236,7 @@ class Orders { * @return * Returns ratio between 0 and 1. */ - double RatioSL(ENUM_ORDER_TYPE _cmd = NULL) { + double RatioSL(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return 1.0 / fmax(TotalSL(_cmd) + TotalTP(_cmd), 0.01) * TotalSL(_cmd); } @@ -245,7 +246,7 @@ class Orders { * @return * Returns ratio between 0 and 1. */ - double RatioTP(ENUM_ORDER_TYPE _cmd = NULL) { + double RatioTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return 1.0 / fmax(TotalSL(_cmd) + TotalTP(_cmd), 0.01) * TotalTP(_cmd); } @@ -255,13 +256,13 @@ class Orders { * @return * Returns sum of all lots from all opened orders. */ - double TotalLots(ENUM_ORDER_TYPE _cmd = NULL) { + double TotalLots(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { double buy_lots = 0, sell_lots = 0; // @todo: Convert to MQL5. for (int i = 0; i < OrdersTotal(); i++) { if (!Order::OrderSelect(i, SELECT_BY_POS)) { - Logger().Error(StringFormat("OrderSelect (%d) returned the error", i), __FUNCTION__, - Terminal::GetErrorText(GetLastError())); + Logger() PTR_DEREF Error(StringFormat("OrderSelect (%d) returned the error", i), __FUNCTION__, + Terminal::GetErrorText(GetLastError())); break; } if (Order::OrderSymbol() == _Symbol) { @@ -299,7 +300,7 @@ class Orders { } else if (_sell_lots > 0 && _sell_lots > _buy_lots) { return ORDER_TYPE_SELL; } else { - return NULL; + return ORDER_TYPE_UNSET; } } @@ -533,7 +534,7 @@ class Orders { */ static unsigned int GetOrdersByType(ENUM_ORDER_TYPE _cmd, string _symbol = NULL) { unsigned int _counter = 0; - _symbol = _symbol != NULL ? _symbol : _Symbol; + _symbol = _symbol != NULL_STRING ? _symbol : _Symbol; for (int i = 0; i < OrdersTotal(); i++) { if (Order::TryOrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break; if (Order::OrderSymbol() == _symbol) { diff --git a/Platform.extern.h b/Platform.extern.h index 81cd3a12a..41742d45e 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -26,6 +26,12 @@ // Includes. #include "Deal.enum.h" +#include "Order.define.h" + +// Forward declarations. +class MqlTradeRequest; +class MqlTradeResult; +class MqlTradeCheckResult; template double iCustom(string symbol, int timeframe, string name, Args... args) { @@ -48,6 +54,15 @@ extern int BarsCalculated(int indicator_handle); */ extern int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)); +extern int CopyOpen(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); +extern int CopyHigh(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); +extern int CopyLow(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); +extern int CopyClose(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); + extern unsigned long PositionGetTicket(int _index); extern long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id); @@ -66,4 +81,58 @@ extern double HistoryDealGetDouble(unsigned long ticket_number, ENUM_DEAL_PROPER extern string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRING property_id); +extern bool OrderSelect(int index); + +extern bool PositionSelectByTicket(int index); + +extern bool HistoryOrderSelect(int index); + +extern bool OrderSend(const MqlTradeRequest& request, MqlTradeResult& result); + +extern bool OrderCheck(const MqlTradeRequest& request, MqlTradeCheckResult& result); + +extern unsigned long OrderGetTicket(int index); + +extern unsigned long HistoryOrderGetTicket(int index); + +extern bool HistorySelectByPosition(long position_id); + +extern bool HistoryDealSelect(unsigned long ticket); + +extern long OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id); + +extern long HistoryOrderGetInteger(unsigned long ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id); + +extern double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property_id); + +extern double HistoryOrderGetDouble(unsigned long ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id); + +string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id); + +string HistoryOrderGetString(unsigned long ticket_number, ENUM_ORDER_PROPERTY_STRING property_id); + +extern int PositionsTotal(); + +extern bool HistorySelect(datetime from_date, datetime to_date); + +extern int HistoryOrdersTotal(); + +extern int OrdersTotal(); + +extern int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(long, arr)); + +extern int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(long, arr)); + +extern int ChartID(); + +extern bool OrderCalcMargin(ENUM_ORDER_TYPE _action, string _symbol, double _volume, double _price, double& _margin); + +double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id); + +long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); + +string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); + #endif diff --git a/Platform.h b/Platform.h index 16e026f55..8b2f666f9 100644 --- a/Platform.h +++ b/Platform.h @@ -26,6 +26,7 @@ // Includes. #include "Deal.enum.h" +#include "Order.struct.h" /** * Extern declarations for C++. @@ -425,6 +426,153 @@ string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRI return 0; } +bool OrderSelect(int index, int select, int pool = MODE_TRADES) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool PositionSelectByTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool HistoryOrderSelect(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool OrderSend(const MqlTradeRequest &request, MqlTradeResult &result) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool OrderCheck(const MqlTradeRequest &request, MqlTradeCheckResult &result) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +unsigned long OrderGetTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +unsigned long HistoryOrderGetTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +bool HistorySelectByPosition(long position_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool HistoryDealSelect(unsigned long ticket) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +long OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +long HistoryOrderGetInteger(unsigned long ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double HistoryOrderGetDouble(unsigned long ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return 0; +} + +string HistoryOrderGetString(unsigned long ticket_number, ENUM_ORDER_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return 0; +} + +int PositionsTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +bool HistorySelect(datetime from_date, datetime to_date) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return 0; +} + +int HistoryOrdersTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int OrdersTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyOpen(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyHigh(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyLow(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyClose(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(long, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(long, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int ChartID() { return Platform::ChartID(); } + +bool OrderCalcMargin(ENUM_ORDER_TYPE _action, string _symbol, double _volume, double _price, double &_margin) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return false; +} + +long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return false; +} + +string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return false; +} + #endif /** diff --git a/Refs.struct.h b/Refs.struct.h index 0eef226e6..da94bf8a1 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -317,12 +317,17 @@ struct WeakRef { /** * Constructor. */ - WeakRef(WeakRef& ref) { this = ref.Ptr(); } + WeakRef(const WeakRef& ref) { THIS_REF = ref.Ptr(); } /** * Constructor. */ - WeakRef(Ref& ref) { this = ref.Ptr(); } + WeakRef(WeakRef& ref) { THIS_REF = ref.Ptr(); } + + /** + * Constructor. + */ + WeakRef(Ref& ref) { THIS_REF = ref.Ptr(); } /** * Destructor. diff --git a/Serializer/SerializerConverter.h b/Serializer/SerializerConverter.h index 571bb1353..350cf0763 100644 --- a/Serializer/SerializerConverter.h +++ b/Serializer/SerializerConverter.h @@ -51,7 +51,7 @@ class SerializerConverter { SerializerConverter(SerializerNode* _root = NULL, int serializer_flags = 0) : root_node(_root), _serializer_flags(serializer_flags) {} - SerializerConverter(SerializerConverter& right) { + SerializerConverter(const SerializerConverter& right) { root_node = right.root_node; _serializer_flags = right._serializer_flags; } diff --git a/Std.h b/Std.h index a7670198f..aaa06888f 100644 --- a/Std.h +++ b/Std.h @@ -309,12 +309,16 @@ struct _WRONG_VALUE { } } WRONG_VALUE; +const char* _empty_string_c = ""; +const string _empty_string = ""; + // Converter of NULL_VALUE into expected type. e.g., "int x = NULL_VALUE" will end up with "x = 0". struct _NULL_VALUE { template - explicit operator T() const { + operator T() const { return (T)0; } + } NULL_VALUE; /** @@ -332,11 +336,13 @@ string EnumToString(int _value) { } template <> -inline _NULL_VALUE::operator const std::string() const { - return ""; +_NULL_VALUE::operator string() const { + return _empty_string; } +#define NULL_STRING "" #else #define NULL_VALUE NULL +#define NULL_STRING NULL #endif #ifndef __MQL__ diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 88887f356..4406fe397 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -48,7 +48,7 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { /** * Constructor. */ - IndicatorBufferValueStorage(IndicatorBase *_indi_candle, int _mode = 0, bool _is_series = false) + IndicatorBufferValueStorage(IndicatorData* _indi_candle, int _mode = 0, bool _is_series = false) : mode(_mode), HistoryValueStorage(_indi_candle) {} /** @@ -56,3 +56,7 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { */ C Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_rel_shift)); } }; + +IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData* _indi, int _mode) { + return new IndicatorBufferValueStorage(_indi, _mode); +} diff --git a/String.extern.h b/String.extern.h index 8c1cde2f6..26a4a9b74 100644 --- a/String.extern.h +++ b/String.extern.h @@ -27,6 +27,8 @@ // Includes. #include +#include +#include #include #include #include @@ -127,4 +129,14 @@ int StringReplace(string& str, const string& find, const string& replacement) { return num_replacements; } +string StringToLower(string str) { + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return ::tolower(c); }); + return str; +} + +string StringToUpper(string str) { + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return ::toupper(c); }); + return str; +} + #endif diff --git a/Trade.mqh b/Trade.mqh index eb74a6564..d6d98228d 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -46,7 +46,7 @@ class Trade; class Trade : public Taskable { public: AccountMt account; - Ref indi_candle; + Ref indi_candle; DictStruct> orders_active; DictStruct> orders_history; DictStruct> orders_pending; @@ -65,11 +65,11 @@ class Trade : public Taskable { /** * Class constructor. */ - Trade(IndicatorBase *_indi_candle) : indi_candle(_indi_candle), order_last(NULL) { + Trade(IndicatorData *_indi_candle) : indi_candle(_indi_candle), order_last(NULL) { SetName(); OrdersLoadByMagic(tparams.magic_no); }; - Trade(TradeParams &_tparams, IndicatorBase *_indi_candle) + Trade(TradeParams &_tparams, IndicatorData *_indi_candle) : indi_candle(_indi_candle), tparams(_tparams), order_last(NULL) { SetName(); OrdersLoadByMagic(tparams.magic_no); @@ -92,17 +92,19 @@ class Trade : public Taskable { /** * Class deconstructor. */ - void ~Trade() {} + ~Trade() {} /* Getters simple */ /** * Gets an account parameter value of double type. */ + /* template T Get(ENUM_ACCOUNT_INFO_DOUBLE _param) { return account.Get(_param); } + */ /** * Gets a trade state value. @@ -327,16 +329,16 @@ class Trade : public Taskable { bool _result = false; Ref _order = order_last; - if (_order.IsSet() && _order.Ptr().Get(ORDER_TYPE) == _cmd && - _order.Ptr().Get(ORDER_TIME_SETUP) > GetSource() PTR_DEREF GetBarTime()) { + if (_order.IsSet() && _order REF_DEREF Get(ORDER_TYPE) == _cmd && + _order REF_DEREF Get(ORDER_TIME_SETUP) > GetSource() PTR_DEREF GetBarTime()) { _result |= true; } if (!_result) { for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().Get(ORDER_TYPE) == _cmd) { - long _time_opened = _order.Ptr().Get(ORDER_TIME_SETUP); + if (_order REF_DEREF Get(ORDER_TYPE) == _cmd) { + long _time_opened = _order REF_DEREF Get(ORDER_TIME_SETUP); _result |= _shift > 0 && _time_opened < GetSource() PTR_DEREF GetBarTime(_shift - 1); _result |= _time_opened >= GetSource() PTR_DEREF GetBarTime(_shift); if (_result) { @@ -357,7 +359,7 @@ class Trade : public Taskable { OrderData _odata; double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); - if (_order.IsSet() && _order.Ptr().IsOpen()) { + if (_order.IsSet() && _order REF_DEREF IsOpen()) { if (_odata.Get(ORDER_TYPE) == _cmd) { switch (_cmd) { case ORDER_TYPE_BUY: @@ -373,7 +375,7 @@ class Trade : public Taskable { if (!_result) { for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid() && !_result; ++iter) { _order = iter.Value(); - if (_order.IsSet() && _order.Ptr().IsOpen()) { + if (_order.IsSet() && _order REF_DEREF IsOpen()) { if (_odata.Get(ORDER_TYPE) == _cmd) { switch (_cmd) { case ORDER_TYPE_BUY: @@ -531,8 +533,8 @@ class Trade : public Taskable { * * @see: https://www.mql5.com/en/code/8568 */ - double GetMaxLotSize(double _sl, ENUM_ORDER_TYPE _cmd = NULL) { - _cmd = _cmd == NULL ? Order::OrderType() : _cmd; + double GetMaxLotSize(double _sl, ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { + _cmd = _cmd == ORDER_TYPE_UNSET ? Order::OrderType() : _cmd; double risk_amount = account.GetTotalBalance() / 100 * tparams.risk_margin; double _ticks = fabs(_sl - GetSource() PTR_DEREF GetOpenOffer(_cmd)) / GetSource() PTR_DEREF GetSymbolProps().GetTickSize(); @@ -540,7 +542,7 @@ class Trade : public Taskable { lot_size1 *= GetSource() PTR_DEREF GetSymbolProps().GetVolumeMin(); return NormalizeLots(lot_size1); } - double GetMaxLotSize(unsigned int _pips, ENUM_ORDER_TYPE _cmd = NULL) { + double GetMaxLotSize(unsigned int _pips, ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return GetMaxLotSize(CalcOrderSLTP(_pips, _cmd, ORDER_TYPE_SL)); } @@ -653,8 +655,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. */ bool OrderAdd(Order *_order) { bool _result = false; - unsigned int _last_error = _order.Get(ORDER_PROP_LAST_ERROR); - logger.Link(_order.GetLogger()); + unsigned int _last_error = _order PTR_DEREF Get(ORDER_PROP_LAST_ERROR); + logger.Link(_order PTR_DEREF GetLogger()); Ref _ref_order = _order; switch (_last_error) { case 69539: @@ -663,7 +665,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. tstats.Add(TRADE_STAT_ORDERS_ERRORS); // Pass-through. case ERR_NO_ERROR: // 0 - orders_active.Set(_order.Get(ORDER_PROP_TICKET), _ref_order); + orders_active.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _ref_order); order_last = _order; tstates.AddState(TRADE_STATE_ORDERS_ACTIVE); tstats.Add(TRADE_STAT_ORDERS_OPENED); @@ -695,10 +697,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * Moves active order to history. */ bool OrderMoveToHistory(Order *_order) { - _order.Refresh(true); - orders_active.Unset(_order.Get(ORDER_PROP_TICKET)); + _order PTR_DEREF Refresh(true); + orders_active.Unset(_order PTR_DEREF Get(ORDER_PROP_TICKET)); Ref _ref_order = _order; - bool result = orders_history.Set(_order.Get(ORDER_PROP_TICKET), _ref_order); + bool result = orders_history.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _ref_order); /* @todo if (strategy != NULL) { strategy.OnOrderClose(_order); @@ -724,8 +726,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool _result = true; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { Ref _order = iter.Value(); - if (_order.IsSet() && _order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh(_force); + if (_order.IsSet() && _order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh(_force); } else if (_order.IsSet()) { _result &= OrderMoveToHistory(_order.Ptr()); if (_first_close) { @@ -744,9 +746,9 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool _result = true; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { Ref _order = iter.Value(); - if (_order.IsSet() && _order.Ptr().IsOpen(true)) { - if (_force || _order.Ptr().ShouldRefresh()) { - _order.Ptr().Refresh(_prop); + if (_order.IsSet() && _order REF_DEREF IsOpen(true)) { + if (_force || _order REF_DEREF ShouldRefresh()) { + _order REF_DEREF Refresh(_prop); } } else if (_order.IsSet()) { _result &= OrderMoveToHistory(_order.Ptr()); @@ -758,7 +760,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Sends a trade request. */ - bool RequestSend(MqlTradeRequest &_request, OrderParams &_oparams) { + bool RequestSend(const MqlTradeRequest &_request, OrderParams &_oparams) { bool _result = false; switch (_request.action) { case TRADE_ACTION_CLOSE_BY: @@ -783,11 +785,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. Order *_order = new Order(_request, _oparams); _result = OrderAdd(_order); if (_result) { - OnOrderOpen(_order); + OnOrderOpen(PTR_TO_REF(_order)); } return _result; } - bool RequestSend(MqlTradeRequest &_request) { + bool RequestSend(const MqlTradeRequest &_request) { OrderParams _oparams; return RequestSend(_request, _oparams); } @@ -798,11 +800,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool OrderLoad(Order *_order) { bool _result = false; Ref _order_ref = _order; - if (_order.IsOpen()) { + if (_order PTR_DEREF IsOpen()) { // @todo: _order.IsPending()? - _result &= orders_active.Set(_order.Get(ORDER_PROP_TICKET), _order_ref); + _result &= orders_active.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); } else { - _result &= orders_history.Set(_order.Get(ORDER_PROP_TICKET), _order_ref); + _result &= orders_history.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); } return _result && GetLastError() == ERR_NO_ERROR; } @@ -857,13 +859,13 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - if (_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + if (_order REF_DEREF OrderClose(_reason, _comment)) { _closed++; OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + logger.AddLastError(__FUNCTION_LINE__, _order REF_DEREF Get(ORDER_PROP_LAST_ERROR)); return -1; } } else { @@ -887,16 +889,16 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh(); - if (_order.Ptr().GetRequest().type == _cmd) { - if (_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh(); + if (_order REF_DEREF GetRequest().type == _cmd) { + if (_order REF_DEREF OrderClose(_reason, _comment)) { _closed++; OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { logger.Error("Error while closing order!", __FUNCTION_LINE__, - StringFormat("Code: %d", _order.Ptr().Get(ORDER_PROP_LAST_ERROR))); + StringFormat("Code: %d", _order REF_DEREF Get(ORDER_PROP_LAST_ERROR))); return -1; } order_last = _order; @@ -925,15 +927,15 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh((E)_prop); - if (Math::Compare(_order.Ptr().Get((E)_prop), _value, _op)) { - if (_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh((E)_prop); + if (Math::Compare(_order REF_DEREF Get((E)_prop), _value, _op)) { + if (_order REF_DEREF OrderClose(_reason, _comment)) { _closed++; OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + logger.AddLastError(__FUNCTION_LINE__, _order REF_DEREF Get(ORDER_PROP_LAST_ERROR)); return -1; } } @@ -961,17 +963,17 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh(); - if (Math::Compare(_order.Ptr().Get((E)_prop1), _value1, _op) && - Math::Compare(_order.Ptr().Get((E)_prop2), _value2, _op)) { - if (!_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh(); + if (Math::Compare(_order REF_DEREF Get((E)_prop1), _value1, _op) && + Math::Compare(_order REF_DEREF Get((E)_prop2), _value2, _op)) { + if (!_order REF_DEREF OrderClose(_reason, _comment)) { #ifndef __MQL4__ // @fixme: GH-571. - logger.Info(__FUNCTION_LINE__, _order.Ptr().ToString()); + logger.Info(__FUNCTION_LINE__, _order REF_DEREF ToString()); #endif // @fixme: GH-570. - // logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + // logger.AddLastError(__FUNCTION_LINE__, _order REF_DEREF Get(ORDER_PROP_LAST_ERROR)); logger.Warning("Issue with closing the order!", __FUNCTION_LINE__); ResetLastError(); return -1; @@ -1024,11 +1026,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Calculates the best SL/TP value for the order given the limits. */ - float CalcBestSLTP(float _value, // Suggested value. - float _max_pips, // Maximal amount of pips. - ENUM_ORDER_TYPE_VALUE _mode, // Type of value (stop loss or take profit). - ENUM_ORDER_TYPE _cmd = NULL, // Order type (e.g. buy or sell). - float _lot_size = 0 // Lot size of the order. + float CalcBestSLTP(float _value, // Suggested value. + float _max_pips, // Maximal amount of pips. + ENUM_ORDER_TYPE_VALUE _mode, // Type of value (stop loss or take profit). + ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, // Order type (e.g. buy or sell). + float _lot_size = 0 // Lot size of the order. ) { float _max_value1 = _max_pips > 0 ? CalcOrderSLTP(_max_pips, _cmd, _mode) : 0; float _max_value2 = tparams.risk_margin > 0 ? GetMaxSLTP(_cmd, _lot_size, _mode) : 0; @@ -1049,8 +1051,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. ENUM_ORDER_TYPE_VALUE _mode // Type of value (stop loss or take profit). ) { double _pip_size = SymbolInfoStatic::GetPipSize(GetSource() PTR_DEREF GetSymbol()); - double _price = _cmd == NULL ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); - _cmd = _cmd == NULL ? Order::OrderType() : _cmd; + double _price = _cmd == ORDER_TYPE_UNSET ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); + _cmd = _cmd == ORDER_TYPE_UNSET ? Order::OrderType() : _cmd; return _value > 0 ? float(_price + _value * _pip_size * Order::OrderDirection(_cmd, _mode)) : 0; } float CalcOrderSL(float _value, ENUM_ORDER_TYPE _cmd) { return CalcOrderSLTP(_value, _cmd, ORDER_TYPE_SL); } @@ -1068,14 +1070,14 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * @return * Returns maximum stop loss price value for the given symbol. */ - float GetMaxSLTP(ENUM_ORDER_TYPE _cmd = NULL, float _lot_size = 0, ENUM_ORDER_TYPE_VALUE _mode = ORDER_TYPE_SL, - float _risk_margin = 1.0) { - double _price = _cmd == NULL ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); + float GetMaxSLTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, float _lot_size = 0, + ENUM_ORDER_TYPE_VALUE _mode = ORDER_TYPE_SL, float _risk_margin = 1.0) { + double _price = _cmd == ORDER_TYPE_UNSET ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); // For the new orders, use the available margin for calculation, otherwise use the account balance. float _margin = Convert::MoneyToValue( - (_cmd == NULL ? account.GetMarginAvail() : account.GetTotalBalance()) / 100 * _risk_margin, _lot_size, - GetSource() PTR_DEREF GetSymbol()); - _cmd = _cmd == NULL ? Order::OrderType() : _cmd; + (_cmd == ORDER_TYPE_UNSET ? account.GetMarginAvail() : account.GetTotalBalance()) / 100 * _risk_margin, + _lot_size, GetSource() PTR_DEREF GetSymbol()); + _cmd = _cmd == ORDER_TYPE_UNSET ? Order::OrderType() : _cmd; // @fixme // _lot_size = _lot_size <= 0 ? fmax(Order::OrderLots(), GetSource() PTR_DEREF GetVolumeMin()) : _lot_size; return (float)_price + @@ -1084,10 +1086,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // + Convert::MoneyToValue(account.GetMarginAvail() / 100 * _risk_margin, _lot_size) + _margin * Order::OrderDirection(_cmd, _mode); } - float GetMaxSL(ENUM_ORDER_TYPE _cmd = NULL, float _lot_size = 0, float _risk_margin = 1.0) { + float GetMaxSL(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, float _lot_size = 0, float _risk_margin = 1.0) { return GetMaxSLTP(_cmd, _lot_size, ORDER_TYPE_SL, _risk_margin); } - float GetMaxTP(ENUM_ORDER_TYPE _cmd = NULL, float _lot_size = 0, float _risk_margin = 1.0) { + float GetMaxTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, float _lot_size = 0, float _risk_margin = 1.0) { return GetMaxSLTP(_cmd, _lot_size, ORDER_TYPE_TP, _risk_margin); } @@ -1207,7 +1209,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * * @todo: Improve number of increases for bull/bear variables. */ - double GetTrend(int method, ENUM_TIMEFRAMES _tf = NULL, bool simple = false) { + double GetTrend(int method, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, bool simple = false) { static datetime _last_trend_check = 0; static double _last_trend = 0; string symbol = GetSource() PTR_DEREF GetSymbol(); @@ -1354,7 +1356,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * @return * Returns Buy operation for bullish, Sell for bearish, otherwise NULL for neutral market trend. */ - ENUM_ORDER_TYPE GetTrendOp(int method, ENUM_TIMEFRAMES _tf = NULL, bool simple = false) { + ENUM_ORDER_TYPE GetTrendOp(int method, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, bool simple = false) { double _curr_trend = GetTrend(method, _tf, simple); return _curr_trend == 0 ? (ENUM_ORDER_TYPE)(ORDER_TYPE_BUY + ORDER_TYPE_SELL) : (_curr_trend > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL); @@ -1494,7 +1496,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. default: logger.Error(StringFormat("Invalid order type: %s!", EnumToString(_cmd), __FUNCTION__)); } - return NULL; + return 0; } double NormalizeSL(double _value, ENUM_ORDER_TYPE _cmd) { @@ -1851,7 +1853,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // case TRADE_ORDER_CONDS_IN_TREND: // case TRADE_ORDER_CONDS_IN_TREND_NOT: default: - GetLogger().Error(StringFormat("Invalid Trade condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error(StringFormat("Invalid Trade condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); SetUserError(ERR_INVALID_PARAMETER); break; } @@ -1903,21 +1905,17 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDER_CLOSE_MOST_LOSS: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - _result = _oquery_ref.Ptr() - .FindByPropViaOp(ORDER_PROP_PROFIT, - STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_LT)) - .Ptr() - .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); + _result = _oquery_ref REF_DEREF FindByPropViaOp( + ORDER_PROP_PROFIT, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_LT)) + REF_DEREF OrderClose(ORDER_REASON_CLOSED_BY_ACTION); RefreshActiveOrders(true, true); } break; case TRADE_ACTION_ORDER_CLOSE_MOST_PROFIT: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - _result = _oquery_ref.Ptr() - .FindByPropViaOp(ORDER_PROP_PROFIT, - STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_GT)) - .Ptr() - .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); + _result = _oquery_ref REF_DEREF FindByPropViaOp( + ORDER_PROP_PROFIT, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_GT)) + REF_DEREF OrderClose(ORDER_REASON_CLOSED_BY_ACTION); RefreshActiveOrders(true, true); } break; @@ -1957,22 +1955,24 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDERS_CLOSE_SIDE_IN_LOSS: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - ENUM_ORDER_TYPE _order_types1[] = {ORDER_TYPE_BUY, ORDER_TYPE_SELL}; - ENUM_ORDER_TYPE _order_type_profitable = - _oquery_ref.Ptr() - .FindPropBySum( - _order_types1, ORDER_PROP_PROFIT, ORDER_TYPE); + ARRAY(ENUM_ORDER_TYPE, _order_types1); + ArrayPush(_order_types1, ORDER_TYPE_BUY); + ArrayPush(_order_types1, ORDER_TYPE_SELL); + ENUM_ORDER_TYPE _order_type_profitable = _oquery_ref REF_DEREF + FindPropBySum( + _order_types1, ORDER_PROP_PROFIT, ORDER_TYPE); _result = OrdersCloseViaCmd(Order::NegateOrderType(_order_type_profitable), ORDER_REASON_CLOSED_BY_ACTION) >= 0; } break; case TRADE_ACTION_ORDERS_CLOSE_SIDE_IN_PROFIT: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - ENUM_ORDER_TYPE _order_types2[] = {ORDER_TYPE_BUY, ORDER_TYPE_SELL}; - ENUM_ORDER_TYPE _order_type_profitable2 = - _oquery_ref.Ptr() - .FindPropBySum( - _order_types2, ORDER_PROP_PROFIT, ORDER_TYPE); + ARRAY(ENUM_ORDER_TYPE, _order_types2); + ArrayPush(_order_types2, ORDER_TYPE_BUY); + ArrayPush(_order_types2, ORDER_TYPE_SELL); + ENUM_ORDER_TYPE _order_type_profitable2 = _oquery_ref REF_DEREF + FindPropBySum( + _order_types2, ORDER_PROP_PROFIT, ORDER_TYPE); _result = OrdersCloseViaCmd(_order_type_profitable2, ORDER_REASON_CLOSED_BY_ACTION) >= 0; } break; @@ -1986,7 +1986,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case TRADE_ACTION_STATE_ADD: tstates.AddState(_entry.GetArg(0).ToValue()); default: - GetLogger().Error(StringFormat("Invalid Trade action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error(StringFormat("Invalid Trade action: %d!", _entry.GetId(), __FUNCTION_LINE__)); SetUserError(ERR_INVALID_PARAMETER); break; } @@ -2036,7 +2036,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Binds IndicatorCandle-based class. */ - void SetSource(IndicatorBase *_indi_candle) { indi_candle = _indi_candle; } + void SetSource(IndicatorData *_indi_candle) { indi_candle = _indi_candle; } /** * Returns pointer to Log class. diff --git a/Trade.struct.h b/Trade.struct.h index 18b5aaa4c..beaf37140 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -37,6 +37,96 @@ struct TradeStats; #include "DateTime.mqh" #include "Trade.enum.h" +/* Structure for trade statistics. */ +struct TradeStats { + DateTime dt[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; + unsigned int order_stats[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; + // Struct constructors. + TradeStats() { ResetStats(); } + TradeStats(const TradeStats &r) { THIS_REF = r; } + // Check statistics for new periods + void Check() {} + /* Getters */ + // Get order stats for the given type and period. + unsigned int GetOrderStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, bool _reset = true) { +#ifdef __debug_verbose__ + Print("GetOrderStats: type ", EnumToString(_type), ", period ", EnumToString(_period), ", reset = ", _reset); +#endif + if (_reset && _period > TRADE_STAT_ALL) { + unsigned int _periods_started = dt[(int)_type][(int)_period].GetStartedPeriods(true, false); +#ifdef __debug_verbose__ + Print("GetOrderStats: _periods_started = ", _periods_started); +#endif + if (_periods_started >= DATETIME_HOUR) { + ResetStats(_type, _period, _periods_started); + } + } + return order_stats[(int)_type][(int)_period]; + } + /* Setters */ + // Add value for the given type and period. + void Add(ENUM_TRADE_STAT_TYPE _type, int _value = 1) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + order_stats[(int)_type][(int)p] += _value; + } + } + /* Reset stats for the given periods. */ + void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, unsigned int _periods) { + if ((_periods & DATETIME_HOUR) != 0) { + ResetStats(TRADE_STAT_PER_HOUR); + } + if ((_periods & DATETIME_DAY) != 0) { + ResetStats(TRADE_STAT_PER_DAY); + } + if ((_periods & DATETIME_WEEK) != 0) { + ResetStats(TRADE_STAT_PER_WEEK); + } + if ((_periods & DATETIME_MONTH) != 0) { + ResetStats(TRADE_STAT_PER_MONTH); + } + if ((_periods & DATETIME_YEAR) != 0) { + ResetStats(TRADE_STAT_PER_YEAR); + } + } + /* Reset stats for the given type and period. */ + void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period) { + order_stats[(int)_type][(int)_period] = 0; + } + /* Reset stats for the given period. */ + void ResetStats(ENUM_TRADE_STAT_PERIOD _period) { + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { + order_stats[t][(int)_period] = 0; +#ifdef __debug_verbose__ + Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(_period)); +#endif + dt[t][(int)_period].GetStartedPeriods(true, true); + } + } + /* Reset stats for the given type. */ + void ResetStats(ENUM_TRADE_STAT_TYPE _type) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + order_stats[(int)_type][p] = 0; +#ifdef __debug_vebose__ + Print("Resetting trade counter for type ", EnumToString(_type), " and period ", EnumToString(p)); +#endif + dt[(int)_type][p].GetStartedPeriods(true, true); + } + } + /* Reset all stats. */ + void ResetStats() { + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + order_stats[t][p] = 0; +#ifdef __debug_verbose__ + Print("Resetting trade counter for type ", EnumToString((ENUM_TRADE_STAT_TYPE)t), " and period ", + EnumToString((ENUM_TRADE_STAT_PERIOD)p)); +#endif + dt[t][p].GetStartedPeriods(true, true); + } + } + } +}; + /* Structure for trade parameters. */ struct TradeParams { float lot_size; // Default lot size. @@ -59,7 +149,7 @@ struct TradeParams { } TradeParams(unsigned long _magic_no, ENUM_LOG_LEVEL _ll = V_INFO) : bars_min(100), lot_size(0), order_comment(""), log_level(_ll), magic_no(_magic_no) {} - TradeParams(TradeParams &_tparams) { this = _tparams; } + TradeParams(const TradeParams &_tparams) { THIS_REF = _tparams; } // Deconstructor. ~TradeParams() {} // Getters. @@ -106,10 +196,10 @@ struct TradeParams { return limits_stats[(int)_type][(int)_period] > 0 && _value >= limits_stats[(int)_type][(int)_period]; } bool IsLimitGe(TradeStats &_stats) { - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - unsigned int _stat_value = _stats.GetOrderStats(t, p); - if (_stat_value > 0 && IsLimitGe(t, p, _stat_value)) { + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; ++t) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; ++p) { + unsigned int _stat_value = _stats.GetOrderStats((ENUM_TRADE_STAT_TYPE)t, (ENUM_TRADE_STAT_PERIOD)p); + if (_stat_value > 0 && IsLimitGe((ENUM_TRADE_STAT_TYPE)t, (ENUM_TRADE_STAT_PERIOD)p, _stat_value)) { return true; } } @@ -168,16 +258,16 @@ struct TradeParams { } void SetLimits(ENUM_TRADE_STAT_TYPE _type, unsigned int _value = 0) { // Set new trading limits for the given type. - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - limits_stats[(int)_type][(int)p] = _value; + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + limits_stats[(int)_type][p] = _value; } } void SetLimits(unsigned int _value = 0) { // Set new trading limits for all types and periods. // Zero value is for no limits. - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - limits_stats[(int)t][(int)p] = _value; + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + limits_stats[t][p] = _value; } } } @@ -195,94 +285,6 @@ struct TradeParams { } } trade_params_defaults; -/* Structure for trade statistics. */ -struct TradeStats { - DateTime dt[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; - unsigned int order_stats[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; - // Struct constructors. - TradeStats() { ResetStats(); } - // Check statistics for new periods - void Check() {} - /* Getters */ - // Get order stats for the given type and period. - unsigned int GetOrderStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, bool _reset = true) { -#ifdef __debug_verbose__ - Print("GetOrderStats: type ", EnumToString(_type), ", period ", EnumToString(_period), ", reset = ", _reset); -#endif - if (_reset && _period > TRADE_STAT_ALL) { - unsigned int _periods_started = dt[(int)_type][(int)_period].GetStartedPeriods(true, false); -#ifdef __debug_verbose__ - Print("GetOrderStats: _periods_started = ", _periods_started); -#endif - if (_periods_started >= DATETIME_HOUR) { - ResetStats(_type, _period, _periods_started); - } - } - return order_stats[(int)_type][(int)_period]; - } - /* Setters */ - // Add value for the given type and period. - void Add(ENUM_TRADE_STAT_TYPE _type, int _value = 1) { - for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - order_stats[(int)_type][(int)p] += _value; - } - } - /* Reset stats for the given periods. */ - void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, unsigned int _periods) { - if ((_periods & DATETIME_HOUR) != 0) { - ResetStats(TRADE_STAT_PER_HOUR); - } - if ((_periods & DATETIME_DAY) != 0) { - ResetStats(TRADE_STAT_PER_DAY); - } - if ((_periods & DATETIME_WEEK) != 0) { - ResetStats(TRADE_STAT_PER_WEEK); - } - if ((_periods & DATETIME_MONTH) != 0) { - ResetStats(TRADE_STAT_PER_MONTH); - } - if ((_periods & DATETIME_YEAR) != 0) { - ResetStats(TRADE_STAT_PER_YEAR); - } - } - /* Reset stats for the given type and period. */ - void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period) { - order_stats[(int)_type][(int)_period] = 0; - } - /* Reset stats for the given period. */ - void ResetStats(ENUM_TRADE_STAT_PERIOD _period) { - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - order_stats[(int)t][(int)_period] = 0; -#ifdef __debug_verbose__ - Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(_period)); -#endif - dt[(int)t][(int)_period].GetStartedPeriods(true, true); - } - } - /* Reset stats for the given type. */ - void ResetStats(ENUM_TRADE_STAT_TYPE _type) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - order_stats[(int)_type][(int)p] = 0; -#ifdef __debug_vebose__ - Print("Resetting trade counter for type ", EnumToString(_type), " and period ", EnumToString(p)); -#endif - dt[(int)_type][(int)p].GetStartedPeriods(true, true); - } - } - /* Reset all stats. */ - void ResetStats() { - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - order_stats[(int)t][(int)p] = 0; -#ifdef __debug_verbose__ - Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(p)); -#endif - dt[(int)t][(int)p].GetStartedPeriods(true, true); - } - } - } -}; - /* Structure for trade states. */ struct TradeStates { protected: @@ -352,7 +354,7 @@ struct TradeStates { int _size = sizeof(int) * 8; for (int i = 0; i < _size; i++) { int _value = CheckState(1 << i) ? 1 : 0; - _s.Pass(THIS_REF, (string)(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC); + _s.Pass(THIS_REF, IntegerToString(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC); } return SerializerNodeObject; } From f4c5d18c0a06f220c650be149d1db2a264b9542e Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 20 Jan 2023 15:00:34 +0100 Subject: [PATCH 10/42] WIP. Code is now compiling for a FX31337-wasm's tests/js/TestRunner.js --- Account/AccountMt.h | 9 +- Array.extern.h | 4 +- Array.mqh | 6 +- Bar.struct.h | 4 +- BufferStruct.mqh | 6 +- Chart.struct.static.h | 2 + Chart.struct.tf.h | 69 +++++- Collection.mqh | 11 +- Convert.basic.h | 28 +++ Dict.mqh | 8 +- DictBase.mqh | 20 +- DictStruct.mqh | 15 -- Indicator/Indicator.enum.h | 8 +- Indicator/Indicator.struct.h | 2 +- Indicator/IndicatorData.h | 48 ++-- Indicator/IndicatorData.struct.cache.h | 6 +- Indicator/IndicatorData.struct.h | 20 +- Indicator/IndicatorData.struct.signal.h | 4 +- Log.mqh | 9 +- Math.extern.h | 2 +- Matrix.mqh | 292 ++++++++++++------------ Order.mqh | 236 +++++++++++-------- Order.struct.h | 45 ++-- Orders.mqh | 6 + Platform.extern.h | 14 +- Platform.h | 5 + Refs.struct.h | 34 +-- Serializer/SerializerCsv.h | 5 +- Std.h | 6 + Storage/ItemsHistory.h | 2 +- Storage/ValueStorage.accessor.h | 4 +- Storage/ValueStorage.h | 2 - String.extern.h | 12 +- SymbolInfo.mqh | 11 +- Task/TaskManager.h | 2 + Task/TaskObject.h | 2 +- Terminal.mqh | 81 ++++--- Tick/Tick.struct.h | 4 +- Trade.mqh | 55 +++-- Trade.struct.h | 22 +- 40 files changed, 648 insertions(+), 473 deletions(-) diff --git a/Account/AccountMt.h b/Account/AccountMt.h index 2ecb09dac..fc9d2fee1 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -470,7 +470,7 @@ class AccountMt { */ bool IsFreeMargin(ENUM_ORDER_TYPE _cmd, double size_of_lot, string _symbol = NULL) { bool _res = true; - double margin = AccountFreeMarginCheck(_symbol, _cmd, size_of_lot); + // double margin = AccountFreeMarginCheck(_symbol, _cmd, size_of_lot); if (GetLastError() == 134 /* NOT_ENOUGH_MONEY */) _res = false; return (_res); } @@ -618,9 +618,10 @@ class AccountMt { return StringFormat( "Type: %s, Server/Company/Name: %s/%s/%s, Currency: %s, Balance: %g, Credit: %g, Equity: %g, Profit: %g, " "Margin Used/Free/Avail: %g(%.1f%%)/%g/%g, Orders limit: %g: Leverage: 1:%d, StopOut Level: %d (Mode: %d)", - GetType(), GetServerName(), GetCompanyName(), GetAccountName(), GetCurrency(), GetBalance(), GetCredit(), - GetEquity(), GetProfit(), GetMarginUsed(), GetMarginUsedInPct(), GetMarginFree(), GetMarginAvail(), - GetLimitOrders(), GetLeverage(), GetStopoutLevel(), GetStopoutMode()); + C_STR(GetType()), C_STR(GetServerName()), C_STR(GetCompanyName()), C_STR(GetAccountName()), + C_STR(GetCurrency()), GetBalance(), GetCredit(), GetEquity(), GetProfit(), GetMarginUsed(), + GetMarginUsedInPct(), GetMarginFree(), GetMarginAvail(), GetLimitOrders(), GetLeverage(), GetStopoutLevel(), + GetStopoutMode()); } /** diff --git a/Array.extern.h b/Array.extern.h index f95f26d3c..821a5c751 100644 --- a/Array.extern.h +++ b/Array.extern.h @@ -34,7 +34,9 @@ int ArraySize(const ARRAY_REF(T, _array)) { } template -constexpr int ArraySize(const T REF(_array)[size]); +constexpr int ArraySize(const T REF(_array)[size]) { + return size; +} template int ArrayResize(ARRAY_REF(T, _array), int _new_size, int _reserve_size = 0) { diff --git a/Array.mqh b/Array.mqh index 8b2035edf..c0417d65a 100644 --- a/Array.mqh +++ b/Array.mqh @@ -760,7 +760,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { template static void ArrayStore(ARRAY_REF(X, array), int index, X value, int reserve_size = 0) { if (index >= ArraySize(array)) { - ArrayResize(array, MathMax(index + 1, ArraySize(array)), reserve_size); + ::ArrayResize(array, MathMax(index + 1, ArraySize(array)), reserve_size); } else if (index < 0) { Print("Index cannot be negative! " + IntegerToString(index) + " passed."); DebugBreak(); @@ -772,11 +772,11 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { template void ArrayPush(ARRAY_REF(X, array), X value) { - ArrayResize(Array::ArraySize(array) + 1); + ::ArrayResize(array, Array::ArraySize(array) + 1); array[ArraySize(array) - 1] = value; } template void ArrayPushObject(ARRAY_REF(X, array), X& value) { - ArrayResize(array, Array::ArraySize(array) + 1); + ::ArrayResize(array, Array::ArraySize(array) + 1); array[Array::ArraySize(array) - 1] = value; } diff --git a/Bar.struct.h b/Bar.struct.h index a261a8673..bc0016259 100644 --- a/Bar.struct.h +++ b/Bar.struct.h @@ -51,7 +51,7 @@ struct BarOHLC datetime time; double open, high, low, close; // Struct constructor. - BarOHLC() : open(0), high(0), low(0), close(0), time(0){}; + BarOHLC() : time(0), open(0), high(0), low(0), close(0){}; BarOHLC(double _open, double _high, double _low, double _close, datetime _time = 0) : time(_time), open(_open), high(_high), low(_low), close(_close) { if (_time == (datetime)0) { @@ -259,5 +259,5 @@ struct BarEntry { s.PassStruct(THIS_REF, "ohlc", ohlc, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } - string ToCSV() { return StringFormat("%s", ohlc.ToCSV()); } + string ToCSV() { return StringFormat("%s", C_STR(ohlc.ToCSV())); } }; diff --git a/BufferStruct.mqh b/BufferStruct.mqh index bda4a34d9..216a9f15a 100644 --- a/BufferStruct.mqh +++ b/BufferStruct.mqh @@ -63,8 +63,8 @@ class BufferStruct : public DictStruct { /** * Constructor. */ - BufferStruct() : max(INT_MIN), min(INT_MAX) { THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } - BufferStruct(BufferStruct& _right) : max(INT_MIN), min(INT_MAX) { + BufferStruct() : min(INT_MAX), max(INT_MIN) { THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } + BufferStruct(BufferStruct& _right) : min(INT_MAX), max(INT_MIN) { this = _right; THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } @@ -74,7 +74,7 @@ class BufferStruct : public DictStruct { */ void Add(TStruct& _value, long _dt = 0) { _dt = _dt > 0 ? _dt : (long)TimeCurrent(); - if (Set(_dt, _value)) { + if (THIS_ATTR Set(_dt, _value)) { min = _dt < min ? _dt : min; max = _dt > max ? _dt : max; } diff --git a/Chart.struct.static.h b/Chart.struct.static.h index 6d02bb9d4..befc9946b 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -293,6 +293,8 @@ struct ChartStatic { ChartStatic::iClose(_symbol, _tf, _shift) + ChartStatic::iClose(_symbol, _tf, _shift)) / 4; break; + default: + break; // FINAL_APPLIED_PRICE_ENTRY. } return _result; } diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 81f26a1c3..c9644babf 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -49,7 +49,7 @@ struct ChartTf { public: // Constructors. ChartTf(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : tf(_tf), tfi(ChartTf::TfToIndex(_tf)){}; - ChartTf(ENUM_TIMEFRAMES_INDEX _tfi) : tfi(_tfi), tf(ChartTf::IndexToTf(_tfi)){}; + ChartTf(ENUM_TIMEFRAMES_INDEX _tfi) : tf(ChartTf::IndexToTf(_tfi)), tfi(_tfi){}; ChartTf(const ChartTf& _ctf) : tf(_ctf.tf), tfi(_ctf.tfi){}; // Struct operators. @@ -186,6 +186,65 @@ struct ChartTf { return PERIOD_CURRENT; } + /** + * Convert timeframe period to seconds. + * + * @param + * _tf ENUM_TIMEFRAMES Specify timeframe enum. + */ + static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { + switch (_tf) { + case PERIOD_CURRENT: + return TfToSeconds(Period()); + case PERIOD_M1: // 1 minute. + return 60; + case PERIOD_M2: // 2 minutes (non-standard). + return 60 * 2; + case PERIOD_M3: // 3 minutes (non-standard). + return 60 * 3; + case PERIOD_M4: // 4 minutes (non-standard). + return 60 * 4; + case PERIOD_M5: // 5 minutes. + return 60 * 5; + case PERIOD_M6: // 6 minutes (non-standard). + return 60 * 6; + case PERIOD_M10: // 10 minutes (non-standard). + return 60 * 10; + case PERIOD_M12: // 12 minutes (non-standard). + return 60 * 12; + case PERIOD_M15: // 15 minutes. + return 60 * 15; + case PERIOD_M20: // 20 minutes (non-standard). + return 60 * 20; + case PERIOD_M30: // 30 minutes. + return 60 * 30; + case PERIOD_H1: // 1 hour. + return 60 * 60; + case PERIOD_H2: // 2 hours (non-standard). + return 60 * 60 * 2; + case PERIOD_H3: // 3 hours (non-standard). + return 60 * 60 * 3; + case PERIOD_H4: // 4 hours. + return 60 * 60 * 4; + case PERIOD_H6: // 6 hours (non-standard). + return 60 * 60 * 6; + case PERIOD_H8: // 8 hours (non-standard). + return 60 * 60 * 8; + case PERIOD_H12: // 12 hours (non-standard). + return 60 * 60 * 12; + case PERIOD_D1: // Daily. + return 60 * 60 * 24; + case PERIOD_W1: // Weekly. + return 60 * 60 * 24 * 7; + case PERIOD_MN1: // Monthly. + return 60 * 60 * 24 * 30; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return 0; + } + /** * Convert period to proper chart timeframe value. * @@ -274,14 +333,6 @@ struct ChartTf { */ static double TfToMinutes(const ENUM_TIMEFRAMES _tf) { return ChartTf::TfToSeconds(_tf) / 60; } - /** - * Convert timeframe period to seconds. - * - * @param - * _tf ENUM_TIMEFRAMES Specify timeframe enum. - */ - static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { return ChartTf::TfToSeconds(_tf); } - /** * Returns text representation of the timeframe constant. * diff --git a/Collection.mqh b/Collection.mqh index d43fa1b70..875d550c3 100644 --- a/Collection.mqh +++ b/Collection.mqh @@ -30,7 +30,7 @@ /** * Class to deal with collection of objects. */ -template +template class Collection { protected: // Variables. @@ -45,8 +45,7 @@ class Collection { Collection() {} Collection(string _name) : name(_name) {} Collection(void *_obj) { Add(_obj); } - ~Collection() { - } + ~Collection() {} /* Setters */ @@ -99,7 +98,7 @@ class Collection { /** * Returns pointer to the current object. */ - X* GetCurrentItem() { return data[index].Ptr() != NULL ? data[index].Ptr() : NULL; } + X *GetCurrentItem() { return data[index].Ptr() != NULL ? data[index].Ptr() : NULL; } /** * Returns ID of the current object. @@ -160,7 +159,7 @@ class Collection { X *_object = GetSize() > 0 ? data[0].Ptr() : NULL; for (i = 0; i < ArraySize(data); i++) { double _weight = data[i].Ptr().GetWeight(); - if (_weight < _object.GetWeight()) { + if (_weight < _object PTR_DEREF GetWeight()) { _object = data[i].Ptr(); } } @@ -175,7 +174,7 @@ class Collection { X *_object = GetSize() > 0 ? data[0].Ptr() : NULL; for (i = 0; i < ArraySize(data); i++) { double _weight = data[i].Ptr().GetWeight(); - if (_weight > _object.GetWeight()) { + if (_weight > _object PTR_DEREF GetWeight()) { _object = data[i].Ptr(); } } diff --git a/Convert.basic.h b/Convert.basic.h index 3725a9e13..f4bd8f6df 100644 --- a/Convert.basic.h +++ b/Convert.basic.h @@ -104,6 +104,13 @@ class ConvertBasic { #endif } + template + static X StringTo(string _value) { + X _out; + StringToType(_value, _out); + return _out; + } + static void BoolToType(bool _value, bool& _out) { _out = _value; } static void BoolToType(bool _value, char& _out) { _out = (char)_value; } static void BoolToType(bool _value, unsigned char& _out) { _out = (unsigned char)_value; } @@ -119,6 +126,13 @@ class ConvertBasic { static void BoolToType(bool _value, color& _out) { _out = 0; } static void BoolToType(bool _value, datetime& _out) {} + template + static X BoolTo(bool _value) { + X _out; + BoolToType(_value, _out); + return _out; + } + static void LongToType(long _value, bool& _out) { _out = (bool)_value; } static void LongToType(long _value, char& _out) { _out = (char)_value; } static void LongToType(long _value, unsigned char& _out) { _out = (unsigned char)_value; } @@ -134,6 +148,13 @@ class ConvertBasic { static void LongToType(long _value, color& _out) { _out = 0; } static void LongToType(long _value, datetime& _out) {} + template + static X LongTo(long _value) { + X _out; + LongToType(_value, _out); + return _out; + } + static void DoubleToType(double _value, bool& _out) { _out = (bool)_value; } static void DoubleToType(double _value, char& _out) { _out = (char)_value; } static void DoubleToType(double _value, unsigned char& _out) { _out = (unsigned char)_value; } @@ -148,4 +169,11 @@ class ConvertBasic { static void DoubleToType(double _value, string& _out) { _out = _value ? "1" : "0"; } static void DoubleToType(double _value, color& _out) { _out = 0; } static void DoubleToType(double _value, datetime& _out) {} + + template + static X DoubleTo(double _value) { + X _out; + DoubleToType(_value, _out); + return _out; + } }; diff --git a/Dict.mqh b/Dict.mqh index 923e63575..e18268cd5 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -126,7 +126,7 @@ class Dict : public DictBase { if (!slot) return (V)NULL; - return slot.value; + return slot PTR_DEREF value; } /** @@ -143,7 +143,7 @@ class Dict : public DictBase { return _default; } - return slot.value; + return slot PTR_DEREF value; } /** @@ -159,7 +159,7 @@ class Dict : public DictBase { return _empty; } - return slot.value; + return slot PTR_DEREF value; } /** @@ -174,7 +174,7 @@ class Dict : public DictBase { if (!slot) return false; - return slot.value == value; + return slot PTR_DEREF value == value; } /** diff --git a/DictBase.mqh b/DictBase.mqh index 5490d8c4e..413894115 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -186,7 +186,15 @@ class DictBase { if (GetMode() == DictModeList) { // In list mode value index is the slot index. - position = (int)key; +#ifndef __MQL__ + if constexpr (std::is_same::value) { +#endif + position = (int)key; +#ifndef __MQL__ + } else { + RUNTIME_ERROR("List mode for a dict could only work if Dict's key type is an integer!"); + } +#endif } else { position = Hash(key) % ArraySize(_DictSlots_ref.DictSlots); } @@ -203,7 +211,15 @@ class DictBase { if (_DictSlots_ref.DictSlots[position].IsUsed()) { if (GetMode() == DictModeList) { - _should_be_removed = position == (unsigned int)key; +#ifndef __MQL__ + if constexpr (std::is_same::value) { +#endif + _should_be_removed = position == (unsigned int)key; +#ifndef __MQL__ + } else { + RUNTIME_ERROR("List mode for a dict could only work if Dict's key type is an integer!"); + } +#endif } else { _should_be_removed = _DictSlots_ref.DictSlots[position].HasKey() && _DictSlots_ref.DictSlots[position].key == key; diff --git a/DictStruct.mqh b/DictStruct.mqh index 8a52642fa..6ff0063fb 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -123,21 +123,6 @@ class DictStruct : public DictBase { */ bool operator+=(V& value) { return Push(value); } -/** - * Inserts value using hashless key. - * - * @todo Get rid of this method. - */ -#ifdef __MQL__ - template <> -#endif - bool Push(Dynamic* value) { - V ptr = value; - - if (!InsertInto(THIS_ATTR _DictSlots_ref, ptr)) return false; - return true; - } - /** * Inserts or replaces value for a given key. */ diff --git a/Indicator/Indicator.enum.h b/Indicator/Indicator.enum.h index 660658722..d5fd94008 100644 --- a/Indicator/Indicator.enum.h +++ b/Indicator/Indicator.enum.h @@ -193,10 +193,10 @@ enum ENUM_APPLIED_VOLUME { VOLUME_TICK = 0, VOLUME_REAL = 1 }; // Indicator flags. enum ENUM_INDI_FLAGS { - INDI_FLAG_INDEXABLE_BY_SHIFT, // Indicator supports indexation by shift. - INDI_FLAG_INDEXABLE_BY_TIMESTAMP, // Indicator supports indexation by shift. - INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT, // Source indicator must be indexable by shift. - INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP // Source indicator must be indexable by timestamp. + INDI_FLAG_INDEXABLE_BY_SHIFT = 1 << 0, // Indicator supports indexation by shift. + INDI_FLAG_INDEXABLE_BY_TIMESTAMP = 1 << 1, // Indicator supports indexation by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT = 1 << 2, // Source indicator must be indexable by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP = 1 << 3 // Source indicator must be indexable by timestamp. }; // Flags indicating which data sources are required to be provided in order indicator to work. diff --git a/Indicator/Indicator.struct.h b/Indicator/Indicator.struct.h index a05d0bb5f..d3fe759a3 100644 --- a/Indicator/Indicator.struct.h +++ b/Indicator/Indicator.struct.h @@ -48,13 +48,13 @@ struct ChartParams; /* Structure for indicator parameters. */ struct IndicatorParams { public: // @todo: Change it to protected. + string custom_indi_name; // Name of the indicator passed to iCustom() method. string name; // Name of the indicator. int shift; // Shift (relative to the current bar, 0 - default). unsigned int max_params; // Max supported input params. ENUM_INDICATOR_TYPE itype; // Indicator type (e.g. INDI_RSI). color indi_color; // Indicator color. ARRAY(DataParamEntry, input_params); // Indicator input params. - string custom_indi_name; // Name of the indicator passed to iCustom() method. string symbol; // Symbol used by indicator. public: /* Special methods */ diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index d6ab968d3..2d706bda3 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -95,6 +95,8 @@ class IndicatorData : public IndicatorBase { // SetDataSource(_indi_price, true, PRICE_OPEN); } break; + default: + break; } // By default, indicator is indexable only by shift and data source must be also indexable by shift. flags = INDI_FLAG_INDEXABLE_BY_SHIFT | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT; @@ -159,7 +161,7 @@ class IndicatorData : public IndicatorBase { * Access indicator entry data using [] operator via shift. */ IndicatorDataEntry operator[](int _rel_shift) { - if (!bool(flags | INDI_FLAG_INDEXABLE_BY_SHIFT)) { + if (!bool(flags & INDI_FLAG_INDEXABLE_BY_SHIFT)) { Print(GetFullName(), " is not indexable by shift!"); DebugBreak(); IndicatorDataEntry _default; @@ -227,6 +229,9 @@ class IndicatorData : public IndicatorBase { case IDATA_INDICATOR: _mode = "On-I"; break; + default: + _mode = "Unkw"; + break; } return GetName() + "#" + IntegerToString(GetId()) + "-" + _mode + "[" + IntegerToString(_max_modes) + "]" + @@ -256,7 +261,6 @@ class IndicatorData : public IndicatorBase { return _price; } datetime _bar_time = GetBarTime(_shift); - float _value = 0; BarOHLC _ohlc(_values, _bar_time); _price = _ohlc.GetAppliedPrice(_ap); } @@ -741,7 +745,7 @@ class IndicatorData : public IndicatorBase { */ void AddListener(IndicatorData* _indi) { WeakRef _ref = _indi; - ArrayPushObject(listeners, _ref); + ArrayPush(listeners, _ref); } /** @@ -789,15 +793,15 @@ class IndicatorData : public IndicatorBase { } if (indi_src.IsSet()) { - if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT) && - !bool(_indi PTR_DEREF GetFlags() | INDI_FLAG_INDEXABLE_BY_SHIFT)) { + if (bool(flags & INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT) && + !bool(_indi PTR_DEREF GetFlags() & INDI_FLAG_INDEXABLE_BY_SHIFT)) { Print(GetFullName(), ": Cannot set data source to ", _indi PTR_DEREF GetFullName(), ", because source indicator isn't indexable by shift!"); DebugBreak(); return; } - if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP) && - !bool(_indi PTR_DEREF GetFlags() | INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { + if (bool(flags & INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP) && + !bool(_indi PTR_DEREF GetFlags() & INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { Print(GetFullName(), ": Cannot set data source to ", _indi PTR_DEREF GetFullName(), ", because source indicator isn't indexable by timestamp!"); DebugBreak(); @@ -1004,7 +1008,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's value in plain format. */ - virtual string ToString(int _index = 0) { + string EntryToString(int _index = 0) { IndicatorDataEntry _entry = GetEntry(_index); int _serializer_flags = SERIALIZER_FLAG_SKIP_HIDDEN | SERIALIZER_FLAG_INCLUDE_DEFAULT | SERIALIZER_FLAG_INCLUDE_DYNAMIC | SERIALIZER_FLAG_INCLUDE_FEATURE; @@ -1044,10 +1048,6 @@ class IndicatorData : public IndicatorBase { } switch (GetAppliedPrice()) { - case PRICE_ASK: - return INDI_VS_TYPE_PRICE_ASK; - case PRICE_BID: - return INDI_VS_TYPE_PRICE_BID; case PRICE_OPEN: return INDI_VS_TYPE_PRICE_OPEN; case PRICE_HIGH: @@ -1062,6 +1062,12 @@ class IndicatorData : public IndicatorBase { return INDI_VS_TYPE_PRICE_TYPICAL; case PRICE_WEIGHTED: return INDI_VS_TYPE_PRICE_WEIGHTED; + default: + if ((int)GetAppliedPrice() == (int)PRICE_ASK) { + return INDI_VS_TYPE_PRICE_ASK; + } else if ((int)GetAppliedPrice() == (int)PRICE_BID) { + return INDI_VS_TYPE_PRICE_BID; + } } Print("Error: ", GetFullName(), " has not supported applied price set: ", EnumToString(GetAppliedPrice()), "!"); @@ -1310,10 +1316,6 @@ class IndicatorData : public IndicatorBase { } switch (_ap) { - case PRICE_ASK: - return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); - case PRICE_BID: - return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); case PRICE_OPEN: return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); case PRICE_HIGH: @@ -1329,6 +1331,11 @@ class IndicatorData : public IndicatorBase { case PRICE_WEIGHTED: return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_WEIGHTED); default: + if ((int)GetAppliedPrice() == (int)PRICE_ASK) { + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); + } else if ((int)GetAppliedPrice() == (int)PRICE_BID) { + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); + } Print("Error: Invalid applied price " + EnumToString(_ap) + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " "IndicatorData::HasSpecificAppliedPriceValueStorage()!"); @@ -1353,10 +1360,6 @@ class IndicatorData : public IndicatorBase { } switch (_ap) { - case PRICE_ASK: - return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); - case PRICE_BID: - return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); case PRICE_OPEN: return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); case PRICE_HIGH: @@ -1372,6 +1375,11 @@ class IndicatorData : public IndicatorBase { case PRICE_WEIGHTED: return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_WEIGHTED); default: + if ((int)GetAppliedPrice() == (int)PRICE_ASK) { + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); + } else if ((int)GetAppliedPrice() == (int)PRICE_BID) { + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); + } Print("Error: Invalid applied price " + EnumToString(_ap) + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " "IndicatorData::GetSpecificAppliedPriceValueStorage()!"); diff --git a/Indicator/IndicatorData.struct.cache.h b/Indicator/IndicatorData.struct.cache.h index b3c7c4f0e..492b305a9 100644 --- a/Indicator/IndicatorData.struct.cache.h +++ b/Indicator/IndicatorData.struct.cache.h @@ -176,8 +176,10 @@ class IndicatorCalculateCache : public Dynamic { return price_low_buffer; case PRICE_CLOSE: return price_close_buffer; + default: + RUNTIME_ERROR("Applied price not supported!"); } - return NULL; + return nullptr; } /** @@ -241,7 +243,7 @@ class IndicatorCalculateCache : public Dynamic { template D GetTailValue(int _buffer_index, int _shift) { ValueStorage *_buff = GetBuffer(_buffer_index); - int _index = _buff.IsSeries() ? _shift : (ArraySize(_buff) - _shift - 1); + int _index = _buff PTR_DEREF IsSeries() ? _shift : (ArraySize(_buff) - _shift - 1); return _buff[_index].Get(); } diff --git a/Indicator/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h index 7d399c0c1..dd4e29493 100644 --- a/Indicator/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -187,7 +187,7 @@ struct IndicatorDataEntry { ARRAY(IndicatorDataEntryValue, values); // Constructors. - IndicatorDataEntry(int _size = 1) : flags(INDI_ENTRY_FLAG_NONE), timestamp(0) { Resize(_size); } + IndicatorDataEntry(int _size = 1) : timestamp(0), flags(INDI_ENTRY_FLAG_NONE) { Resize(_size); } IndicatorDataEntry(const IndicatorDataEntry &_entry) { THIS_REF = _entry; } int GetSize() { return ArraySize(values); } // Operator overloading methods. @@ -327,7 +327,7 @@ struct IndicatorDataEntry { int GetYear() { return DateTimeStatic::Year(timestamp); } long GetTime() { return timestamp; }; ENUM_DATATYPE GetDataType(int _mode) { return values[_mode].GetDataType(); } - ushort GetDataTypeFlags(ENUM_DATATYPE _dt) { + unsigned short GetDataTypeFlags(ENUM_DATATYPE _dt) { switch (_dt) { case TYPE_BOOL: case TYPE_CHAR: @@ -402,21 +402,21 @@ struct IndicatorDataEntry { /* Structure for indicator data parameters. */ struct IndicatorDataParams { public: - // @todo: Move to protected. - bool is_draw; // Draw active. - color indi_color; // Indicator color. protected: /* Struct protected variables */ - bool is_fed; // Whether calc_start_bar is already calculated. int data_src_mode; // Mode used as input from data source. int draw_window; // Drawing window. - int src_id; // Id of the indicator to be used as data source. - int src_mode; // Mode of source indicator - unsigned int max_buffers; // Max buffers to store. - unsigned int max_modes; // Max supported indicator modes (values per entry). ENUM_DATATYPE dtype; // Type of basic data to store values (DTYPE_DOUBLE, DTYPE_INT). + unsigned int max_modes; // Max supported indicator modes (values per entry). + unsigned int max_buffers; // Max buffers to store. ENUM_IDATA_SOURCE_TYPE idstype; // Indicator's data source type (e.g. IDATA_BUILTIN, IDATA_ICUSTOM). ENUM_IDATA_VALUE_RANGE idvrange; // Indicator's range value data type. + color indi_color; // Indicator color. + // @todo: Move to protected. + bool is_draw; // Draw active. + bool is_fed; // Whether calc_start_bar is already calculated. + int src_id; // Id of the indicator to be used as data source. + int src_mode; // Mode of source indicator public: /* Struct enumerations */ enum ENUM_IDATA_PARAM { diff --git a/Indicator/IndicatorData.struct.signal.h b/Indicator/IndicatorData.struct.signal.h index 0c141f95b..0ea5024a6 100644 --- a/Indicator/IndicatorData.struct.signal.h +++ b/Indicator/IndicatorData.struct.signal.h @@ -90,8 +90,8 @@ struct IndicatorSignal { Alert(__FUNCSIG__, " Should use pointer to IndicatorBase as a source of prices!"); DebugBreak(); - int _shift0 = 0; - int _shift1 = 1; + // int _shift0 = 0; + // int _shift1 = 1; double _price_w0 = 0; double _price_w1 = 0; diff --git a/Log.mqh b/Log.mqh index 9930bebd3..0a4bff34a 100644 --- a/Log.mqh +++ b/Log.mqh @@ -60,12 +60,12 @@ class Log : public Object { ENUM_LOG_LEVEL log_level; string msg; }; - DictStruct> logs; - string filename; - ARRAY(log_entry, data); int last_entry; datetime last_flush; ENUM_LOG_LEVEL log_level; + string filename; + ARRAY(log_entry, data); + DictStruct> logs; public: /** @@ -145,7 +145,7 @@ class Log : public Object { * Adds a log entry. */ bool Add(string msg, string prefix, string suffix, ENUM_LOG_LEVEL entry_log_level = V_INFO) { - return Add(prefix, msg, suffix, entry_log_level); + return Add(entry_log_level, msg, prefix, suffix); } bool Add(ARRAY_REF(double, arr), string prefix, string suffix, ENUM_LOG_LEVEL entry_log_level = V_INFO) { return Add(prefix, Array::ArrToString(arr), suffix, entry_log_level); @@ -315,7 +315,6 @@ class Log : public Object { bool DeleteByTimestamp(datetime timestamp) { int size = ArraySize(data); if (size > 0) { - int offset = 0; for (int i = 0; i < size; i++) { if (data[i].timestamp == timestamp) { Erase(data, i); diff --git a/Math.extern.h b/Math.extern.h index 7965fd1f3..d63691eb4 100644 --- a/Math.extern.h +++ b/Math.extern.h @@ -76,5 +76,5 @@ T log10(T value) { return std::log10(value); } int MathRand() { return std::rand() % 32768; } -int rand() { return std::rand() % 32768; } +// int rand() { return std::rand() % 32768; } #endif diff --git a/Matrix.mqh b/Matrix.mqh index de0f7177c..5fdbc3e0f 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -137,30 +137,31 @@ struct MatrixDimensionAccessor { /** * Constructor. */ - MatrixDimensionAccessor(Matrix* _ptr_matrix = NULL, MatrixDimension* _ptr_dimension = NULL, int _index = 0) + MatrixDimensionAccessor(Matrix* _ptr_matrix = nullptr, MatrixDimension* _ptr_dimension = nullptr, + int _index = 0) : ptr_matrix(_ptr_matrix), ptr_dimension(_ptr_dimension), index(_index) {} /** * Index operator. Returns container or value accessor. */ MatrixDimensionAccessor operator[](int _index) { - return MatrixDimensionAccessor(ptr_matrix, ptr_dimension.containers[index], _index); + return MatrixDimensionAccessor(ptr_matrix, ptr_dimension PTR_DEREF containers[index], _index); } /** * Returns target dimension type. */ - ENUM_MATRIX_DIMENSION_TYPE Type() const { return ptr_dimension.type; } + ENUM_MATRIX_DIMENSION_TYPE Type() const { return ptr_dimension PTR_DEREF type; } #define MATRIX_ACCESSOR_OPERATOR(OP) \ void operator OP(X _value) { \ - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { \ - Print("Error: Trying to use matrix", ptr_matrix.Repr(), \ + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { \ + Print("Error: Trying to use matrix", ptr_matrix PTR_DEREF Repr(), \ "'s value operator " #OP " in a dimension which doesn't contain values!"); \ return; \ } \ \ - ptr_dimension.values[index] OP _value; \ + ptr_dimension PTR_DEREF values[index] OP _value; \ } MATRIX_ACCESSOR_OPERATOR(+=) @@ -172,24 +173,26 @@ struct MatrixDimensionAccessor { * Assignment operator. Sets value for this dimensions. */ void operator=(X _value) { - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { - Print("Error: Trying to set matrix", ptr_matrix.Repr(), "'s value in a dimension which doesn't contain values!"); + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { + Print("Error: Trying to set matrix", ptr_matrix PTR_DEREF Repr(), + "'s value in a dimension which doesn't contain values!"); return; } - ptr_dimension.values[index] = _value; + ptr_dimension PTR_DEREF values[index] = _value; } /** * Returns value pointed by this accessor. */ X Val() { - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { - Print("Error: Trying to get value from matrix", ptr_matrix.Repr(), "'s dimension which doesn't contain values!"); + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { + Print("Error: Trying to get value from matrix", ptr_matrix PTR_DEREF Repr(), + "'s dimension which doesn't contain values!"); return (X)EMPTY_VALUE; } - return ptr_dimension.values[index]; + return ptr_dimension PTR_DEREF values[index]; } /** @@ -197,16 +200,17 @@ struct MatrixDimensionAccessor { * dimension length. */ X ValOrZero() { - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { - Print("Error: Trying to get value from matrix", ptr_matrix.Repr(), "'s dimension which doesn't contain values!"); + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { + Print("Error: Trying to get value from matrix", ptr_matrix PTR_DEREF Repr(), + "'s dimension which doesn't contain values!"); return (X)EMPTY_VALUE; } - int _num_values = ArraySize(ptr_dimension.values); + int _num_values = ArraySize(ptr_dimension PTR_DEREF values); if (_num_values == 0 || index >= _num_values) return (X)0; - return ptr_dimension.values[index]; + return ptr_dimension PTR_DEREF values[index]; } }; @@ -219,13 +223,13 @@ class MatrixDimension { ENUM_MATRIX_DIMENSION_TYPE type; // Values array if type is "Values". - X values[]; + ARRAY(X, values); // Physical position of the dimension in the matrix. int position[MATRIX_DIMENSIONS - 1]; // Containers array if type is "Containers" - MatrixDimension* containers[]; + ARRAY(MatrixDimension, containers); /** * Constructor. @@ -249,13 +253,13 @@ class MatrixDimension { int i; if (type == MATRIX_DIMENSION_TYPE_CONTAINERS) { - ArrayResize(_clone.containers, ArraySize(containers)); + ArrayResize(_clone PTR_DEREF containers, ArraySize(containers)); for (i = 0; i < ArraySize(containers); ++i) { - _clone.containers[i] = containers[i].Clone(); + _clone PTR_DEREF containers[i] = containers[i].Clone(); } } else { - ArrayCopy(_clone.values, values); + ArrayCopy(_clone PTR_DEREF values, values); } return _clone; @@ -462,6 +466,9 @@ class MatrixDimension { ArrayFill(values, _last_size, _num_items - _last_size, (X)0); } break; + + default: + RUNTIME_ERROR("We shouldn't be here!"); } type = _type; @@ -478,21 +485,21 @@ class MatrixDimension { if (index == 0 && _dimensions[0] == 0) { // Matrix without any dimensions. - _ptr_parent_dimension.type = MATRIX_DIMENSION_TYPE_VALUES; + _ptr_parent_dimension PTR_DEREF type = MATRIX_DIMENSION_TYPE_VALUES; } - _ptr_parent_dimension.SetPosition(_current_position, index); + _ptr_parent_dimension PTR_DEREF SetPosition(_current_position, index); int i; if (_dimensions[index + 1] == 0) { - _ptr_parent_dimension.Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_VALUES); + _ptr_parent_dimension PTR_DEREF Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_VALUES); } else { - _ptr_parent_dimension.Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_CONTAINERS); + _ptr_parent_dimension PTR_DEREF Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_CONTAINERS); for (i = 0; i < _dimensions[index]; ++i) { - _ptr_parent_dimension.containers[i] = - SetDimensions(_ptr_parent_dimension.containers[i], _dimensions, index + 1, _current_position); + _ptr_parent_dimension PTR_DEREF containers[i] = + SetDimensions(_ptr_parent_dimension PTR_DEREF containers[i], _dimensions, index + 1, _current_position); ++_current_position[index]; } @@ -505,7 +512,6 @@ class MatrixDimension { * Executes operation on a single value. */ X OpSingle(ENUM_MATRIX_OPERATION _op, X _src = (X)0, X _arg1 = (X)0, X _arg2 = (X)0, X _arg3 = (X)0) { - int _pos = 0; switch (_op) { case MATRIX_OPERATION_ABS: return MathAbs(_src); @@ -668,20 +674,19 @@ class MatrixDimension { */ void Op(MatrixDimension* _r, ENUM_MATRIX_OPERATION _op, X _arg1 = (X)0, int _only_value_index = -1) { int i; - bool r_is_single = ArraySize(_r.values) == 1; - if (_r.type == MATRIX_DIMENSION_TYPE_VALUES && ArraySize(_r.values) == 1) { + if (_r PTR_DEREF type == MATRIX_DIMENSION_TYPE_VALUES && ArraySize(_r PTR_DEREF values) == 1) { // There is only one value in the right container, we will use that value for all operations. _only_value_index = 0; } switch (type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: - switch (_r.type) { + switch (_r PTR_DEREF type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: // Both dimensions have containers. for (i = 0; i < ArraySize(containers); ++i) { - containers[i].Op(_r.containers[ArraySize(_r.containers) == 1 ? 0 : i], _op, _arg1); + containers[i].Op(_r PTR_DEREF containers[ArraySize(_r PTR_DEREF containers) == 1 ? 0 : i], _op, _arg1); } break; case MATRIX_DIMENSION_TYPE_VALUES: @@ -695,21 +700,22 @@ class MatrixDimension { } break; case MATRIX_DIMENSION_TYPE_VALUES: - switch (_r.type) { + switch (_r PTR_DEREF type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: // Right dimension have containers. - if (ArraySize(_r.containers) != 1) { + if (ArraySize(_r PTR_DEREF containers) != 1) { Alert("Right container must have exactly one element!"); return; } - Op(_r.containers[0], _op, _arg1); + Op(_r PTR_DEREF containers[0], _op, _arg1); break; case MATRIX_DIMENSION_TYPE_VALUES: // Left and right dimensions have values or we use single right value. for (i = 0; i < ArraySize(values); ++i) { - values[i] = OpSingle(_op, values[i], _r.values[_only_value_index != -1 ? _only_value_index : i]); + values[i] = + OpSingle(_op, values[i], _r PTR_DEREF values[_only_value_index != -1 ? _only_value_index : i]); } break; @@ -763,7 +769,7 @@ class Matrix { return; } - Initialize(_right.ptr_first_dimension.Clone()); + Initialize(_right.ptr_first_dimension PTR_DEREF Clone()); } /** @@ -778,7 +784,7 @@ class Matrix { * Matrix initializer. */ void Initialize(MatrixDimension* _dimension) { - if (ptr_first_dimension != NULL) delete ptr_first_dimension; + if (ptr_first_dimension != nullptr) delete ptr_first_dimension; ptr_first_dimension = _dimension; // Calculating dimensions. @@ -791,11 +797,11 @@ class Matrix { for (i = 0; i < MATRIX_DIMENSIONS; ++i) { if (_dimension == NULL) break; - if (_dimension.type == MATRIX_DIMENSION_TYPE_CONTAINERS) { - dimensions[i] = ArraySize(_dimension.containers); - _dimension = _dimension.containers[0]; - } else if (_dimension.type == MATRIX_DIMENSION_TYPE_VALUES) { - dimensions[i++] = ArraySize(_dimension.values); + if (_dimension PTR_DEREF type == MATRIX_DIMENSION_TYPE_CONTAINERS) { + dimensions[i] = ArraySize(_dimension PTR_DEREF containers); + _dimension = _dimension PTR_DEREF containers[0]; + } else if (_dimension PTR_DEREF type == MATRIX_DIMENSION_TYPE_VALUES) { + dimensions[i++] = ArraySize(_dimension PTR_DEREF values); break; } else { Print("Internal error: unknown dimension type!"); @@ -824,14 +830,14 @@ class Matrix { /** * Assignment operator. */ - void operator=(const Matrix& _right) { Initialize(_right.ptr_first_dimension.Clone()); } + void operator=(const Matrix& _right) { Initialize(_right.ptr_first_dimension PTR_DEREF Clone()); } /** * Assignment operator. Initializes matrix using given dimension. */ Matrix(MatrixDimensionAccessor& accessor) { if (accessor.Type() == MATRIX_DIMENSION_TYPE_CONTAINERS) { - Initialize(accessor.ptr_dimension.containers[accessor.index].Clone()); + Initialize(accessor.ptr_dimension PTR_DEREF containers[accessor.index].Clone()); } else if (accessor.Type() == MATRIX_DIMENSION_TYPE_VALUES) { SetShape(1); this[0] = accessor.Val(); @@ -847,7 +853,7 @@ class Matrix { * Destructor. */ ~Matrix() { - if (ptr_first_dimension != NULL) { + if (ptr_first_dimension != nullptr) { delete ptr_first_dimension; } } @@ -925,7 +931,7 @@ class Matrix { return; } - int initial_container_size = ptr_first_dimension.DuplicateDimension(_level, _num); + int initial_container_size = ptr_first_dimension PTR_DEREF DuplicateDimension(_level, _num); dimensions[_level] += _num * initial_container_size; RecalculateSize(); } @@ -1068,7 +1074,7 @@ class Matrix { */ void Abs() { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_ABS); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_ABS); } } @@ -1077,7 +1083,7 @@ class Matrix { */ void Add(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_ADD, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_ADD, value); } } @@ -1091,7 +1097,7 @@ class Matrix { */ void Sub(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_SUBTRACT, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_SUBTRACT, value); } } @@ -1105,7 +1111,7 @@ class Matrix { */ void Mul(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_MULTIPLY, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_MULTIPLY, value); } } @@ -1119,7 +1125,7 @@ class Matrix { */ void Div(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_DIVIDE, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_DIVIDE, value); } } @@ -1128,7 +1134,7 @@ class Matrix { */ void Fill(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL, value); } } @@ -1137,7 +1143,7 @@ class Matrix { */ void FillRandom(int _seed = -1) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_RANDOM, _seed); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_RANDOM, _seed); } } @@ -1146,7 +1152,7 @@ class Matrix { */ void FillRandom(X _start, X _end, int _seed = -1) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_RANDOM_RANGE, _start, _end, _seed); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_RANDOM_RANGE, _start, _end, _seed); } } @@ -1155,7 +1161,7 @@ class Matrix { */ void FillPosAdd() { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_POS_ADD); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_POS_ADD); } } @@ -1164,7 +1170,7 @@ class Matrix { */ void FillPosMul() { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_POS_MUL); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_POS_MUL); } } @@ -1175,7 +1181,7 @@ class Matrix { X _out1 = 0, _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); } return _out1; } @@ -1187,7 +1193,7 @@ class Matrix { X _out1 = MaxOf((X)0), _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_MIN, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_MIN, 0, 0, 0, _out1, _out2, _out3); } return _out1; } @@ -1199,7 +1205,7 @@ class Matrix { X _out1 = MinOf((X)0), _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_MAX, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_MAX, 0, 0, 0, _out1, _out2, _out3); } return _out1; } @@ -1211,7 +1217,7 @@ class Matrix { X _out1 = 0, _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); return GetSize() > 0 ? _out1 / GetSize() : 0; } return MinOf((X)0); @@ -1219,7 +1225,7 @@ class Matrix { void Power(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_POWER, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_POWER, value); } } @@ -1228,7 +1234,7 @@ class Matrix { */ X Med() { if (ptr_first_dimension) { - X array[]; + ARRAY(X, array); GetRawArray(array); ArraySort(array); @@ -1293,8 +1299,8 @@ class Matrix { Matrix* operator+(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); } return result; @@ -1305,7 +1311,7 @@ class Matrix { */ void operator+=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); } } @@ -1315,8 +1321,8 @@ class Matrix { Matrix* operator-(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); } return result; @@ -1327,7 +1333,7 @@ class Matrix { */ void operator-=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); } } @@ -1337,8 +1343,8 @@ class Matrix { Matrix* operator*(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); } return result; @@ -1349,7 +1355,7 @@ class Matrix { */ void operator*=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); } } @@ -1359,8 +1365,8 @@ class Matrix { Matrix* operator/(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); } return result; @@ -1371,7 +1377,7 @@ class Matrix { */ void operator/=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); } } @@ -1381,21 +1387,21 @@ class Matrix { void GetRawArray(ARRAY_REF(X, array)) { ArrayResize(array, GetSize()); int offset = 0; - ptr_first_dimension.FillArray(array, offset); + ptr_first_dimension PTR_DEREF FillArray(array, offset); } /** * Flattens matrix. */ Matrix* Flatten() { - X values[]; + ARRAY(X, values); GetRawArray(values); Matrix* result = new Matrix(ArraySize(values)); for (int i = 0; i < ArraySize(values); ++i) { - result[i] = values[i]; + PTR_TO_REF(result)[i] = values[i]; } return result; @@ -1432,7 +1438,7 @@ class Matrix { } int offset = 0; - ptr_first_dimension.FromArray(_array, offset); + ptr_first_dimension PTR_DEREF FromArray(_array, offset); } /** @@ -1489,15 +1495,15 @@ class Matrix { Print("Mean(): Unsupported absolute difference operator: ", EnumToString(_abs_diff_op), "!"); } - if (!ShapeCompatible(&this, _prediction)) { - Print("MeanAbsolute(): Shape ", Repr(), " is not compatible with prediction shape ", _prediction.Repr(), "!"); - return NULL; + if (!ShapeCompatible(THIS_PTR, _prediction)) { + Print("MeanAbsolute(): Shape ", Repr(), " is not compatible with prediction shape ", _prediction PTR_DEREF Repr(), + "!"); + return nullptr; } - if (_weights != NULL && _weights.GetDimensions() > this PTR_DEREF GetDimensions()) { - Print("MeanAbsolute(): Shape ", Repr(), ": Weights must be a tensor level <= ", this PTR_DEREF GetDimensions(), - "!"); - return NULL; + if (_weights != nullptr && _weights PTR_DEREF GetDimensions() > this PTR_DEREF GetDimensions()) { + Print("MeanAbsolute(): Shape ", Repr(), ": Weights must be a tensor level <= ", THIS_ATTR GetDimensions(), "!"); + return nullptr; } Matrix*_matrix, *_pooled; @@ -1506,27 +1512,31 @@ class Matrix { _matrix = Clone(); // Calculating absolute difference between copied tensor and given prediction. - _matrix.ptr_first_dimension.Op(_prediction.ptr_first_dimension, _abs_diff_op); + _matrix PTR_DEREF ptr_first_dimension PTR_DEREF Op(_prediction PTR_DEREF ptr_first_dimension, _abs_diff_op); switch (_abs_diff_op) { case MATRIX_OPERATION_ABS_DIFF_SQUARE: case MATRIX_OPERATION_ABS_DIFF_SQUARE_LOG: // Reducing values of the last dimension of the matrix. - _pooled = _matrix.GetPooled(_reduction, MATRIX_PADDING_SAME, dimensions[1] == 0 ? dimensions[0] : 1, - dimensions[2] == 0 ? dimensions[1] : 1, dimensions[3] == 0 ? dimensions[2] : 1, - dimensions[4] == 0 ? dimensions[3] : 1, dimensions[5] == 0 ? dimensions[4] : 1); + _pooled = + _matrix PTR_DEREF GetPooled(_reduction, MATRIX_PADDING_SAME, dimensions[1] == 0 ? dimensions[0] : 1, + dimensions[2] == 0 ? dimensions[1] : 1, dimensions[3] == 0 ? dimensions[2] : 1, + dimensions[4] == 0 ? dimensions[3] : 1, dimensions[5] == 0 ? dimensions[4] : 1); // Physically reducing last dimension of the matrix. - _pooled.ReduceSimple(); + _pooled PTR_DEREF ReduceSimple(); delete _matrix; _matrix = _pooled; break; + default: + RUNTIME_ERROR("Difference operation not supported!") } - if (_weights != NULL) { + if (_weights != nullptr) { // Multiplying copied tensor by given weights. Note that weights tensor could be of lower level than original // tensor. - _matrix.ptr_first_dimension.Op(_weights.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + _matrix PTR_DEREF ptr_first_dimension PTR_DEREF Op(_weights PTR_DEREF ptr_first_dimension, + MATRIX_OPERATION_MULTIPLY); } return _matrix; @@ -1536,17 +1546,17 @@ class Matrix { * Reduces single or all dimensions containing only a single value. */ void ReduceSimple(bool _only_last_dimension = true, ENUM_MATRIX_OPERATION _reduce_op = MATRIX_OPERATION_SUM) { - if (ptr_first_dimension != NULL) { - ptr_first_dimension.ReduceSimple(_only_last_dimension ? GetDimensions() - 1 : 0, _reduce_op); + if (ptr_first_dimension != nullptr) { + ptr_first_dimension PTR_DEREF ReduceSimple(_only_last_dimension ? GetDimensions() - 1 : 0, _reduce_op); } } void Reduce(int _level = 0, ENUM_MATRIX_OPERATION _reduce_op = MATRIX_OPERATION_SUM) { - if (ptr_first_dimension == NULL) { + if (ptr_first_dimension == nullptr) { return; } - ptr_first_dimension.Reduce(_level, _reduce_op); + ptr_first_dimension PTR_DEREF Reduce(_level, _reduce_op); for (int i = _level + 1; i < MATRIX_DIMENSIONS; ++i) { dimensions[i] = 0; @@ -1559,11 +1569,12 @@ class Matrix { * Computes the Poisson loss */ Matrix* Poisson(Matrix* _prediction) { - if (ptr_first_dimension == NULL) { - return NULL; + if (ptr_first_dimension == nullptr) { + return nullptr; } Matrix* _clone = Clone(); - _clone.ptr_first_dimension.Op(_prediction.ptr_first_dimension, MATRIX_OPERATION_POISSON); + _clone PTR_DEREF ptr_first_dimension PTR_DEREF Op(_prediction PTR_DEREF ptr_first_dimension, + MATRIX_OPERATION_POISSON); return _clone; } @@ -1577,7 +1588,7 @@ class Matrix { Matrix* VectorReduce(Matrix* _product, ENUM_MATRIX_VECTOR_REDUCE _reduce, int _dimension = 0) { if (_dimension == -1) _dimension = GetDimensions() - 1; - if (!ShapeCompatibleLossely(&this, _product)) { + if (!ShapeCompatibleLossely(THIS_PTR, _product)) { // Alert("VectorReduce(): Incompatible shapes: ", Repr(), " and ", _product.Repr(), "!"); // return NULL; } @@ -1603,7 +1614,6 @@ class Matrix { Matrix* _ptr_result = new Matrix(_out_dims[0], _out_dims[1], _out_dims[2], _out_dims[3], _out_dims[4]); - int _curr_dimension = 0; bool _stop = false; while (!_stop) { @@ -1621,7 +1631,8 @@ class Matrix { // Taking one group at a time. for (int b = 0; b < dimensions[_dimension]; ++b) { X _value_a = GetValue(_index[0], _index[1], _index[2], _index[3], _index[4]); - X _value_b = _product.GetValueLossely(GetDimensions(), _index[0], _index[1], _index[2], _index[3], _index[4]); + X _value_b = + _product PTR_DEREF GetValueLossely(GetDimensions(), _index[0], _index[1], _index[2], _index[3], _index[4]); switch (_reduce) { case MATRIX_VECTOR_REDUCE_COSINE_SIMILARITY: @@ -1659,7 +1670,7 @@ class Matrix { break; } - _ptr_result.SetValue(_res, _out_index[0], _out_index[1], _out_index[2], _out_index[3], _out_index[4]); + _ptr_result PTR_DEREF SetValue(_res, _out_index[0], _out_index[1], _out_index[2], _out_index[3], _out_index[4]); if (_dimension == 0) ++_index[1]; @@ -1731,19 +1742,19 @@ class Matrix { switch (_reduction) { case MATRIX_OPERATION_SUM: - result = _diff.Sum(); + result = _diff PTR_DEREF Sum(); break; case MATRIX_OPERATION_MIN: - result = _diff.Min(); + result = _diff PTR_DEREF Min(); break; case MATRIX_OPERATION_MAX: - result = _diff.Max(); + result = _diff PTR_DEREF Max(); break; case MATRIX_OPERATION_AVG: - result = _diff.Avg(); + result = _diff PTR_DEREF Avg(); break; case MATRIX_OPERATION_MED: - result = _diff.Med(); + result = _diff PTR_DEREF Med(); break; default: Print("MeanAbsolute(): Unsupported reduction type: ", EnumToString(_reduction), "!"); @@ -1781,7 +1792,7 @@ class Matrix { */ Matrix* Relu() { Matrix* result = Clone(); - result.Relu_(); + result PTR_DEREF Relu_(); return result; } @@ -1792,7 +1803,7 @@ class Matrix { X _out1 = 0, _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_RELU, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_RELU, 0, 0, 0, _out1, _out2, _out3); } } @@ -1801,7 +1812,7 @@ class Matrix { */ Matrix* Clone() const { Matrix* _cloned = new Matrix(dimensions[0], dimensions[1], dimensions[2], dimensions[3], dimensions[4]); - _cloned.ptr_first_dimension.CopyFrom(ptr_first_dimension); + _cloned PTR_DEREF ptr_first_dimension PTR_DEREF CopyFrom(ptr_first_dimension); return _cloned; } @@ -1813,15 +1824,15 @@ class Matrix { void Set(X value, const int _1d, const int _2d = -1, const int _3d = -1, const int _4d = -1, const int _5d = -1) { if (_2d == -1) { - this[_1d] = value; + THIS_REF[_1d] = value; } else if (_3d == -1) { - this[_1d][_2d] = value; + THIS_REF[_1d][_2d] = value; } else if (_4d == -1) { - this[_1d][_2d][_3d] = value; + THIS_REF[_1d][_2d][_3d] = value; } else if (_5d == -1) { - this[_1d][_2d][_3d][_4d] = value; + THIS_REF[_1d][_2d][_3d][_4d] = value; } else { - this[_1d][_2d][_3d][_4d][_5d] = value; + THIS_REF[_1d][_2d][_3d][_4d][_5d] = value; } } @@ -1831,25 +1842,25 @@ class Matrix { if (dimensions[0] < _in_channels) { Alert("Insufficient number of channels in the input. First dimensions should have ", _in_channels, " arrays, got ", dimensions[0]); - return NULL; + return nullptr; } Matrix* clone = Clone(); - clone.DuplicateDimension(1, _out_channels - 1); + clone PTR_DEREF DuplicateDimension(1, _out_channels - 1); if (_weights != NULL) { - Matrix* weight_flattened = _weights.Flatten(); + Matrix* weight_flattened = _weights PTR_DEREF Flatten(); for (int _in_channel_idx = 0; _in_channel_idx < _in_channels; ++_in_channel_idx) { - clone.ptr_first_dimension.containers[_in_channel_idx].Op(weight_flattened.ptr_first_dimension, - MATRIX_OPERATION_MULTIPLY); + clone PTR_DEREF ptr_first_dimension PTR_DEREF containers[_in_channel_idx].Op( + weight_flattened PTR_DEREF ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); } delete weight_flattened; } - Matrix* pooled = - clone.GetPooled(MATRIX_OPERATION_SUM, MATRIX_PADDING_VALID, 1, 2, _krn_1d, _krn_2d, 0, // Kernel size. - 1, 2, _stride_1d, _stride_2d); + Matrix* pooled = clone PTR_DEREF GetPooled(MATRIX_OPERATION_SUM, MATRIX_PADDING_VALID, 1, 2, _krn_1d, _krn_2d, + 0, // Kernel size. + 1, 2, _stride_1d, _stride_2d); delete clone; return pooled; @@ -1966,7 +1977,7 @@ class Matrix { ChunkOp(_op, _padding, _pool_1d, _pool_2d, _pool_3d, _pool_4d, _pool_5d, _stride_1d, _stride_2d, _stride_3d, _stride_4d, _stride_5d, _chunk_1d, _chunk_2d, _chunk_3d, _chunk_4d, _chunk_5d); - _result.Set(result, _chunk_1d, _chunk_2d, _chunk_3d, _chunk_4d, _chunk_5d); + _result PTR_DEREF Set(result, _chunk_1d, _chunk_2d, _chunk_3d, _chunk_4d, _chunk_5d); } } } @@ -2016,7 +2027,7 @@ class Matrix { _accessor_d1 = this[d1]; if (_accessor_d1.Type() == MATRIX_DIMENSION_TYPE_VALUES) { - _MATRIX_AGGR(ptr_first_dimension.values[d1]); + _MATRIX_AGGR(ptr_first_dimension PTR_DEREF values[d1]); continue; } @@ -2113,16 +2124,16 @@ class Matrix { /** * Checks whether both matrices have the same dimensions' length. */ - static bool ShapeCompatible(Matrix* _a, Matrix* _b) { return _a.Repr() == _b.Repr(); } + static bool ShapeCompatible(Matrix* _a, Matrix* _b) { return _a PTR_DEREF Repr() == _b PTR_DEREF Repr(); } /** * Checks whether right matrix have less or equal dimensions' length.. */ static bool ShapeCompatibleLossely(Matrix* _a, Matrix* _b) { - if (_b.GetDimensions() > _a.GetDimensions()) return false; + if (_b PTR_DEREF GetDimensions() > _a PTR_DEREF GetDimensions()) return false; - for (int i = 0; i < _b.GetDimensions(); ++i) { - if (_b.dimensions[i] != 1 && _b.dimensions[i] > _a.dimensions[i]) return false; + for (int i = 0; i < _b PTR_DEREF GetDimensions(); ++i) { + if (_b PTR_DEREF dimensions[i] != 1 && _b PTR_DEREF dimensions[i] > _a PTR_DEREF dimensions[i]) return false; } return true; @@ -2131,20 +2142,17 @@ class Matrix { static Matrix* CreateFromString(string text) { Matrix* _ptr_matrix = new Matrix(); - _ptr_matrix.FromString(text); + _ptr_matrix PTR_DEREF FromString(text); return _ptr_matrix; } void FromString(string text) { - MatrixDimension*_dimensions[], *_root_dimension = NULL; - int _dimensions_length[MATRIX_DIMENSIONS] = {0, 0, 0, 0, 0}; + ARRAY(MatrixDimension*, _dimensions); + MatrixDimension* _root_dimension = nullptr; int i, _number_start_pos; - bool _had_values; X _number; bool _expecting_value_or_child = true; - bool _expecting_comma = false; - bool _expecting_end = false; for (i = 0; i < StringLen(text); ++i) { unsigned short _char = StringGetCharacter(text, i), c; @@ -2156,8 +2164,6 @@ class Matrix { return; } - _had_values = false; - if (ArraySize(_dimensions) != 0) { _dimensions[ArraySize(_dimensions) - 1].type = MATRIX_DIMENSION_TYPE_CONTAINERS; } @@ -2174,13 +2180,11 @@ class Matrix { } _expecting_value_or_child = true; - _expecting_end = true; break; case ']': ArrayResize(_dimensions, ArraySize(_dimensions) - 1, MATRIX_DIMENSIONS); _expecting_value_or_child = true; - _expecting_comma = false; break; case '0': @@ -2209,15 +2213,11 @@ class Matrix { i -= 2; _dimensions[ArraySize(_dimensions) - 1].type = MATRIX_DIMENSION_TYPE_VALUES; _dimensions[ArraySize(_dimensions) - 1].AddValue(_number); - _expecting_end = true; _expecting_value_or_child = true; - _expecting_comma = false; break; case ',': _expecting_value_or_child = true; - _expecting_comma = false; - _expecting_end = false; break; case ' ': case '\t': @@ -2241,7 +2241,7 @@ class Matrix { * */ string ToString(bool _whitespaces = false, int _precision = 3) { - return ptr_first_dimension.ToString(_whitespaces, _precision); + return ptr_first_dimension PTR_DEREF ToString(_whitespaces, _precision); } /** diff --git a/Order.mqh b/Order.mqh index 7808c34ca..7ecefc664 100644 --- a/Order.mqh +++ b/Order.mqh @@ -695,6 +695,8 @@ class Order : public SymbolInfo { return OrderStopLoss(); case ORDER_TP: return OrderTakeProfit(); + default: + break; } return 0; } @@ -1158,17 +1160,17 @@ class Order : public SymbolInfo { * Returns number of the ticket assigned to the order by the trade server * or -1 if it fails. */ - static long OrderSend(string _symbol, // Symbol. - int _cmd, // Operation. - double _volume, // Volume. - double _price, // Price. - unsigned long _deviation, // Deviation. - double _stoploss, // Stop loss. - double _takeprofit, // Take profit. - string _comment = NULL, // Comment. - unsigned long _magic = 0, // Magic number. - datetime _expiration = 0, // Pending order expiration. - color _arrow_color = clrNONE // Color. + static long OrderSend(string _symbol, // Symbol. + int _cmd, // Operation. + double _volume, // Volume. + double _price, // Price. + unsigned long _deviation, // Deviation. + double _stoploss, // Stop loss. + double _takeprofit, // Take profit. + string _comment = NULL_STRING, // Comment. + unsigned long _magic = 0, // Magic number. + datetime _expiration = 0, // Pending order expiration. + color _arrow_color = clrNONE // Color. ) { #ifdef __MQL4__ #ifdef __debug__ @@ -1300,7 +1302,7 @@ class Order : public SymbolInfo { // - https://www.mql5.com/en/docs/constants/errorswarnings/enum_trade_return_codes // - https://www.mql5.com/en/docs/constants/structures/mqltradecheckresult #ifdef __debug__ - PrintFormat("%s: Error %d: %s", __FUNCTION_LINE__, _result_check.retcode, _result_check.comment); + PrintFormat("%s: Error %d: %s", C_STR(__FUNCTION_LINE__), _result_check.retcode, C_STR(_result_check.comment)); #endif _result.retcode = _result_check.retcode; return false; @@ -1564,7 +1566,7 @@ class Order : public SymbolInfo { } else { #ifdef __debug__ PrintFormat("%s: Possible values for 'select' parameters are: SELECT_BY_POS or SELECT_BY_HISTORY.", - __FUNCTION_LINE__); + C_STR(__FUNCTION_LINE__)); #endif } _result = selected_ticket_type != ORDER_SELECT_TYPE_NONE; @@ -1742,8 +1744,6 @@ class Order : public SymbolInfo { * Update specific double value of the current order. */ bool RefreshDummy(ENUM_ORDER_PROPERTY_DOUBLE _prop_id) { - bool _result = false; - double _value = WRONG_VALUE; ResetLastError(); switch (_prop_id) { case ORDER_PRICE_CURRENT: @@ -1781,6 +1781,8 @@ class Order : public SymbolInfo { OrderCloseDummy(); } break; + default: + break; } break; case ORDER_PRICE_OPEN: @@ -1795,6 +1797,8 @@ class Order : public SymbolInfo { case ORDER_TP: odata.Set(_prop_id, orequest.tp); break; + default: + break; } return true; @@ -1805,12 +1809,13 @@ class Order : public SymbolInfo { */ bool RefreshDummy(ENUM_ORDER_PROPERTY_INTEGER _prop_id) { bool _result = false; - long _value = WRONG_VALUE; ResetLastError(); switch (_prop_id) { case ORDER_MAGIC: odata.Set(_prop_id, orequest.magic); break; + default: + break; } return _result && GetLastError() == ERR_NO_ERROR; @@ -1827,6 +1832,8 @@ class Order : public SymbolInfo { case ORDER_SYMBOL: odata.Set(_prop_id, orequest.symbol); break; + default: + break; } return true; @@ -1870,7 +1877,7 @@ class Order : public SymbolInfo { } else { int _last_error = GetLastError(); ologger.Error("Error refreshing order property!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); } return _result && GetLastError() == ERR_NO_ERROR; } @@ -1896,9 +1903,6 @@ class Order : public SymbolInfo { _result = Order::OrderGetInteger(ORDER_POSITION_BY_ID, _value); break; #endif - case (ENUM_ORDER_PROPERTY_INTEGER)ORDER_REASON: - _result = Order::OrderGetInteger((ENUM_ORDER_PROPERTY_INTEGER)ORDER_REASON, _value); - break; case ORDER_STATE: _result = Order::OrderGetInteger(ORDER_STATE, _value); break; @@ -1927,6 +1931,10 @@ class Order : public SymbolInfo { _result = Order::OrderGetInteger(ORDER_TYPE_TIME, _value); break; default: + if ((int)_prop_id == (int)ORDER_REASON) { + _result = Order::OrderGetInteger((ENUM_ORDER_PROPERTY_INTEGER)ORDER_REASON, _value); + break; + } return false; } if (_result) { @@ -1934,7 +1942,7 @@ class Order : public SymbolInfo { } else { int _last_error = GetLastError(); ologger.Error("Error updating order property!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); } return _result && GetLastError() == ERR_NO_ERROR; } @@ -1949,15 +1957,16 @@ class Order : public SymbolInfo { case ORDER_COMMENT: _value = Order::OrderGetString(ORDER_COMMENT); break; -#ifdef ORDER_EXTERNAL_ID - case (ENUM_ORDER_PROPERTY_STRING)ORDER_EXTERNAL_ID: - _value = Order::OrderGetString(ORDER_EXTERNAL_ID); - break; -#endif case ORDER_SYMBOL: _value = Order::OrderGetString(ORDER_SYMBOL); break; default: +#ifdef ORDER_EXTERNAL_ID + if ((int)_prop_id == (int)ORDER_EXTERNAL_ID) { + _value = Order::OrderGetString(ORDER_EXTERNAL_ID); + break; + } +#endif _result = false; break; } @@ -1966,7 +1975,7 @@ class Order : public SymbolInfo { } else { int _last_error = GetLastError(); ologger.Error("Error updating order property!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); } return true; } @@ -2019,6 +2028,8 @@ class Order : public SymbolInfo { return ORDER_TYPE_SELL; case ORDER_TYPE_SELL: return ORDER_TYPE_BUY; + default: + break; } return WRONG_VALUE; } @@ -2450,9 +2461,11 @@ class Order : public SymbolInfo { template static X OrderGetParam(int _prop_id, ENUM_ORDER_SELECT_TYPE _type, ENUM_ORDER_SELECT_DATA_TYPE _data_type, X &_out) { #ifndef __MQL4__ + long _long; + string _string; switch (selected_ticket_type) { case ORDER_SELECT_TYPE_NONE: - return NULL; + return NULL_VALUE; case ORDER_SELECT_TYPE_ACTIVE: case ORDER_SELECT_TYPE_HISTORY: @@ -2465,13 +2478,13 @@ class Order : public SymbolInfo { case ORDER_TIME_SETUP: return OrderGetValue(DEAL_TIME, _type, _out); case ORDER_TYPE: - switch ((int)OrderGetValue(DEAL_TYPE, _type, _out)) { + switch (OrderGetValue(DEAL_TYPE, _type, _long)) { case DEAL_TYPE_BUY: - return (X)ORDER_TYPE_BUY; + return ConvertBasic::LongTo(ORDER_TYPE_BUY); case DEAL_TYPE_SELL: - return (X)ORDER_TYPE_SELL; + return ConvertBasic::LongTo(ORDER_TYPE_SELL); default: - return NULL; + return NULL_VALUE; } break; case ORDER_STATE: @@ -2480,43 +2493,44 @@ class Order : public SymbolInfo { case ORDER_TIME_EXPIRATION: case ORDER_TIME_DONE: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TIME_SETUP_MSC: return OrderGetValue(DEAL_TIME_MSC, _type, _out); case ORDER_TIME_DONE_MSC: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TYPE_FILLING: case ORDER_TYPE_TIME: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_MAGIC: return OrderGetValue(DEAL_MAGIC, _type, _out); - case ORDER_REASON: - switch ((int)OrderGetValue(DEAL_REASON, _type, _out)) { - case DEAL_REASON_CLIENT: - return (X)ORDER_REASON_CLIENT; - case DEAL_REASON_MOBILE: - return (X)ORDER_REASON_MOBILE; - case DEAL_REASON_WEB: - return (X)ORDER_REASON_WEB; - case DEAL_REASON_EXPERT: - return (X)ORDER_REASON_EXPERT; - case DEAL_REASON_SL: - return (X)ORDER_REASON_SL; - case DEAL_REASON_TP: - return (X)ORDER_REASON_TP; - case DEAL_REASON_SO: - return (X)ORDER_REASON_SO; - default: - return NULL; - } - break; case ORDER_POSITION_ID: return OrderGetValue(DEAL_POSITION_ID, _type, _out); case ORDER_POSITION_BY_ID: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; + default: + if ((int)_prop_id == (int)ORDER_REASON) { + switch (OrderGetValue(DEAL_REASON, _type, _long)) { + case DEAL_REASON_CLIENT: + return ConvertBasic::LongTo(ORDER_REASON_CLIENT); + case DEAL_REASON_MOBILE: + return ConvertBasic::LongTo(ORDER_REASON_MOBILE); + case DEAL_REASON_WEB: + return ConvertBasic::LongTo(ORDER_REASON_WEB); + case DEAL_REASON_EXPERT: + return ConvertBasic::LongTo(ORDER_REASON_EXPERT); + case DEAL_REASON_SL: + return ConvertBasic::LongTo(ORDER_REASON_SL); + case DEAL_REASON_TP: + return ConvertBasic::LongTo(ORDER_REASON_TP); + case DEAL_REASON_SO: + return ConvertBasic::LongTo(ORDER_REASON_SO); + default: + return NULL_VALUE; + } + } } break; case ORDER_SELECT_DATA_TYPE_DOUBLE: @@ -2525,26 +2539,31 @@ class Order : public SymbolInfo { return OrderGetValue(DEAL_VOLUME, _type, _out); case ORDER_VOLUME_CURRENT: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_PRICE_OPEN: return OrderGetValue(DEAL_PRICE, _type, _out); case ORDER_SL: case ORDER_TP: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_PRICE_CURRENT: return OrderGetValue(DEAL_PRICE, _type, _out); case ORDER_PRICE_STOPLIMIT: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; } break; case ORDER_SELECT_DATA_TYPE_STRING: switch (_prop_id) { case ORDER_SYMBOL: case ORDER_COMMENT: - case ORDER_EXTERNAL_ID: - return NULL; + return NULL_VALUE; + default: +#ifdef ORDER_EXTERNAL_ID + if ((int)_prop_id == (int)ORDER_EXTERNAL_ID) { + return NULL_VALUE; + } +#endif } break; } @@ -2557,13 +2576,13 @@ class Order : public SymbolInfo { case ORDER_TIME_SETUP: return OrderGetValue(POSITION_TIME, _type, _out); case ORDER_TYPE: - switch ((int)OrderGetValue(POSITION_TYPE, _type, _out)) { + switch (OrderGetValue(POSITION_TYPE, _type, _long)) { case POSITION_TYPE_BUY: - return (X)ORDER_TYPE_BUY; + return ConvertBasic::LongTo(ORDER_TYPE_BUY); case POSITION_TYPE_SELL: - return (X)ORDER_TYPE_SELL; + return ConvertBasic::LongTo(ORDER_TYPE_SELL); default: - return NULL; + return NULL_VALUE; } break; case ORDER_STATE: @@ -2572,37 +2591,38 @@ class Order : public SymbolInfo { case ORDER_TIME_EXPIRATION: case ORDER_TIME_DONE: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TIME_SETUP_MSC: return OrderGetValue(POSITION_TIME_MSC, _type, _out); case ORDER_TIME_DONE_MSC: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TYPE_FILLING: case ORDER_TYPE_TIME: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_MAGIC: return OrderGetValue(POSITION_MAGIC, _type, _out); - case ORDER_REASON: - switch ((int)OrderGetValue(POSITION_REASON, _type, _out)) { - case POSITION_REASON_CLIENT: - return (X)ORDER_REASON_CLIENT; - case POSITION_REASON_MOBILE: - return (X)ORDER_REASON_MOBILE; - case POSITION_REASON_WEB: - return (X)ORDER_REASON_WEB; - case POSITION_REASON_EXPERT: - return (X)ORDER_REASON_EXPERT; - default: - return NULL; - } - break; case ORDER_POSITION_ID: return OrderGetValue(POSITION_IDENTIFIER, _type, _out); case ORDER_POSITION_BY_ID: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; + default: + if ((int)_prop_id == (int)ORDER_REASON) { + switch (OrderGetValue(POSITION_REASON, _type, _long)) { + case POSITION_REASON_CLIENT: + return ConvertBasic::LongTo(ORDER_REASON_CLIENT); + case POSITION_REASON_MOBILE: + return ConvertBasic::LongTo(ORDER_REASON_MOBILE); + case POSITION_REASON_WEB: + return ConvertBasic::LongTo(ORDER_REASON_WEB); + case POSITION_REASON_EXPERT: + return ConvertBasic::LongTo(ORDER_REASON_EXPERT); + default: + return NULL_VALUE; + } + } } break; case ORDER_SELECT_DATA_TYPE_DOUBLE: @@ -2612,7 +2632,7 @@ class Order : public SymbolInfo { case ORDER_VOLUME_CURRENT: // @fixme SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_PRICE_OPEN: return OrderGetValue(POSITION_PRICE_OPEN, _type, _out); case ORDER_SL: @@ -2624,7 +2644,7 @@ class Order : public SymbolInfo { case ORDER_PRICE_STOPLIMIT: // @fixme SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; } break; case ORDER_SELECT_DATA_TYPE_STRING: @@ -2633,15 +2653,19 @@ class Order : public SymbolInfo { return OrderGetValue(POSITION_SYMBOL, _type, _out); case ORDER_COMMENT: return OrderGetValue(POSITION_COMMENT, _type, _out); - case ORDER_EXTERNAL_ID: - return OrderGetValue(POSITION_EXTERNAL_ID, _type, _out); + default: +#ifdef ORDER_EXTERNAL_ID + if ((int)_prop_id == (int)ORDER_EXTERNAL_ID) { + return OrderGetValue(POSITION_EXTERNAL_ID, _type, _out); + } +#endif } break; } break; } - return NULL; + return NULL_VALUE; #else return OrderGetValue(_prop_id, _type, _out); #endif @@ -2680,7 +2704,7 @@ class Order : public SymbolInfo { * Returns true when the condition is met. */ bool CheckCondition(ENUM_ORDER_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { - float _profit = (float)Get(ORDER_PROP_PROFIT_PIPS); + // float _profit = (float)Get(ORDER_PROP_PROFIT_PIPS); switch (_cond) { case ORDER_COND_IN_LOSS: return Get(ORDER_PROP_PROFIT_PIPS) < (ArraySize(_args) > 0 ? -DataParamEntry::ToDouble(_args[0]) : 0); @@ -2699,6 +2723,8 @@ class Order : public SymbolInfo { return TimeCurrent() - odata.Get(ORDER_TIME_SETUP) > _arg_value; case ORDER_COND_LIFETIME_LT_ARG: return TimeCurrent() - odata.Get(ORDER_TIME_SETUP) < _arg_value; + default: + return false; } } case ORDER_COND_PROP_EQ_ARG: @@ -2719,6 +2745,8 @@ class Order : public SymbolInfo { return odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_prop_id) > _args[1].double_value; case ORDER_COND_PROP_LT_ARG: return odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_prop_id) < _args[1].double_value; + default: + return false; } case TYPE_INT: case TYPE_LONG: @@ -2732,6 +2760,8 @@ class Order : public SymbolInfo { return odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_prop_id) > _args[1].integer_value; case ORDER_COND_PROP_LT_ARG: return odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_prop_id) < _args[1].integer_value; + default: + return false; } case TYPE_STRING: Refresh((ENUM_ORDER_PROPERTY_STRING)_prop_id); @@ -2743,12 +2773,17 @@ class Order : public SymbolInfo { return odata.Get((ENUM_ORDER_PROPERTY_STRING)_prop_id) > _args[1].string_value; case ORDER_COND_PROP_LT_ARG: return odata.Get((ENUM_ORDER_PROPERTY_STRING)_prop_id) < _args[1].string_value; + default: + return false; } + default: + return false; } } } default: - ologger.Error(StringFormat("Invalid order condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + ologger.Error( + StringFormat("Invalid order condition: %s at %s!", C_STR(EnumToString(_cond)), C_STR(__FUNCTION_LINE__))); } SetUserError(ERR_INVALID_PARAMETER); return false; @@ -2771,12 +2806,12 @@ class Order : public SymbolInfo { bool ExecuteAction(ENUM_ORDER_ACTION _action, ARRAY_REF(DataParamEntry, _args)) { switch (_action) { case ORDER_ACTION_CLOSE: - switch (oparams.dummy) { - case false: - return OrderClose(ORDER_REASON_CLOSED_BY_ACTION); - case true: - return OrderCloseDummy(ORDER_REASON_CLOSED_BY_ACTION); + if (oparams.dummy) { + return OrderCloseDummy(ORDER_REASON_CLOSED_BY_ACTION); + } else { + return OrderClose(ORDER_REASON_CLOSED_BY_ACTION); } + break; case ORDER_ACTION_OPEN: return !oparams.dummy ? OrderSend() >= 0 : OrderSendDummy() >= 0; case ORDER_ACTION_COND_CLOSE_ADD: @@ -2792,7 +2827,8 @@ class Order : public SymbolInfo { oparams.AddConditionClose((ENUM_ORDER_CONDITION)_args[0].integer_value, _sargs); } default: - ologger.Error(StringFormat("Invalid order action: %s!", EnumToString(_action), __FUNCTION_LINE__)); + ologger.Error( + StringFormat("Invalid order action: %s at %s!", C_STR(EnumToString(_action)), C_STR(__FUNCTION_LINE__))); return false; } } @@ -2821,21 +2857,21 @@ class Order : public SymbolInfo { switch (_type) { case TYPE_DOUBLE: for (i = 0; i < Array::ArraySize(_props); i++) { - _output += StringFormat("%g%s", odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_props[i]), _dlm); + _output += StringFormat("%g%s", odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_props[i]), C_STR(_dlm)); } break; case TYPE_LONG: for (i = 0; i < Array::ArraySize(_props); i++) { - _output += StringFormat("%d%s", odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_props[i]), _dlm); + _output += StringFormat("%d%s", odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_props[i]), C_STR(_dlm)); } break; case TYPE_STRING: for (i = 0; i < Array::ArraySize(_props); i++) { - _output += StringFormat("%d%s", odata.Get((ENUM_ORDER_PROPERTY_STRING)_props[i]), _dlm); + _output += StringFormat("%s%s", C_STR(odata.Get((ENUM_ORDER_PROPERTY_STRING)_props[i])), C_STR(_dlm)); } break; default: - ologger.Error(StringFormat("%s: Unsupported type: %s!", __FUNCTION_LINE__, EnumToString(_type))); + ologger.Error(StringFormat("%s: Unsupported type: %s!", C_STR(__FUNCTION_LINE__), C_STR(EnumToString(_type)))); } return ""; } diff --git a/Order.struct.h b/Order.struct.h index 897f28394..cab1a5739 100644 --- a/Order.struct.h +++ b/Order.struct.h @@ -154,7 +154,7 @@ struct OrderParams { T Get(ENUM_ORDER_PARAM _param, int _index1 = 0, int _index2 = 0) { switch (_param) { case ORDER_PARAM_COLOR_ARROW: - return (T)color_arrow; + return (T)(unsigned int)color_arrow; case ORDER_PARAM_COND_CLOSE: return (T)cond_close[_index1].cond; case ORDER_PARAM_COND_CLOSE_ARG_VALUE: @@ -167,6 +167,9 @@ struct OrderParams { return (T)refresh_freq; case ORDER_PARAM_UPDATE_FREQ: return (T)update_freq; + default: + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; } SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; @@ -182,7 +185,7 @@ struct OrderParams { void Set(ENUM_ORDER_PARAM _param, T _value, int _index1 = 0, int _index2 = 0) { switch (_param) { case ORDER_PARAM_COLOR_ARROW: - color_arrow = (color)_value; + color_arrow = (color)(unsigned int)_value; return; case ORDER_PARAM_COND_CLOSE: SetConditionClose((ENUM_ORDER_CONDITION)_value, _index1); @@ -199,6 +202,8 @@ struct OrderParams { case ORDER_PARAM_UPDATE_FREQ: update_freq = (unsigned short)_value; return; + default: + SetUserError(ERR_INVALID_PARAMETER); } SetUserError(ERR_INVALID_PARAMETER); } @@ -232,12 +237,7 @@ struct OrderData { unsigned long position_by_id; // Position By ID. unsigned long ticket; // Ticket number. ENUM_ORDER_STATE state; // State. - datetime time_closed; // Closed time. - datetime time_done; // Execution/cancellation time. - datetime time_expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type). - datetime time_setup; // Setup time. - datetime time_last_refresh; // Last refresh of order values. - datetime time_last_update; // Last update of order stops. + string comment; // Comment. double commission; // Commission. double profit; // Profit. double total_profit; // Total profit (profit minus fees). @@ -246,22 +246,27 @@ struct OrderData { double price_current; // Current price. double price_stoplimit; // The limit order price for the StopLimit order. double swap; // Order cumulative swap. + datetime time_closed; // Closed time. + datetime time_done; // Execution/cancellation time. + long time_done_msc; // The time of execution/cancellation time (in msc). + datetime time_expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type). + datetime time_last_refresh; // Last refresh of order values. + datetime time_last_update; // Last update of order stops. + datetime time_setup; // Setup time. + long time_setup_msc; // The time of placing the order (in msc). double total_fees; // Total fees. double sl; // Current Stop loss level of the order. double tp; // Current Take Profit level of the order. - long time_setup_msc; // The time of placing the order (in msc). - long time_done_msc; // The time of execution/cancellation time (in msc). ENUM_ORDER_TYPE type; // Type. ENUM_ORDER_TYPE_FILLING type_filling; // Filling type. ENUM_ORDER_TYPE_TIME type_time; // Lifetime (the order validity period). ENUM_ORDER_REASON reason; // Reason or source for placing an order. ENUM_ORDER_REASON_CLOSE reason_close; // Reason or source for closing an order. unsigned int last_error; // Last error code. - double volume_curr; // Current volume. - double volume_init; // Initial volume. - string comment; // Comment. string ext_id; // External trading system identifier. string symbol; // Symbol of the order. + double volume_curr; // Current volume. + double volume_init; // Initial volume. public: OrderData() : magic(0), @@ -296,7 +301,6 @@ struct OrderData { // Getters. template T Get(ENUM_ORDER_PROPERTY_CUSTOM _prop_name) { - double _tick_value = SymbolInfoStatic::GetTickValue(symbol); switch (_prop_name) { case ORDER_PROP_COMMISSION: return (T)commission; @@ -330,6 +334,9 @@ struct OrderData { return (T)time_done; case ORDER_PROP_TOTAL_FEES: return (T)total_fees; + default: + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; } SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; @@ -366,13 +373,13 @@ struct OrderData { case ORDER_STATE: return (T)state; case ORDER_TIME_EXPIRATION: - return (T)time_expiration; + return (T)(long)time_expiration; case ORDER_TIME_DONE: - return (T)time_done; + return (T)(long)time_done; case ORDER_TIME_DONE_MSC: return (T)time_done_msc; case ORDER_TIME_SETUP: - return (T)time_setup; + return (T)(long)time_setup; case ORDER_TIME_SETUP_MSC: return (T)time_setup_msc; case ORDER_TYPE_FILLING: @@ -500,7 +507,7 @@ struct OrderData { profit = (double)_value; return; case ORDER_PROP_REASON_CLOSE: - reason_close = (ENUM_ORDER_REASON_CLOSE)_value; + reason_close = (ENUM_ORDER_REASON_CLOSE)(long)_value; return; case ORDER_PROP_TICKET: ticket = (unsigned long)_value; @@ -520,6 +527,8 @@ struct OrderData { case ORDER_PROP_TOTAL_FEES: total_fees = (double)_value; return; + default: + SetUserError(ERR_INVALID_PARAMETER); } SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Orders.mqh b/Orders.mqh index e5ca4df9f..aa0add09b 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -204,6 +204,9 @@ class Orders { // PrintFormat("%s:%d%d: OP_SELL: TP=%g, SL=%g, total: %g/%g", __FUNCTION__, i, OrdersTotal(), order_tp, // order_sl, total_sell_sl, total_sell_tp); break; + default: + RUNTIME_ERROR("Not supported order type!"); + return 0; } } } @@ -273,6 +276,9 @@ class Orders { case ORDER_TYPE_SELL: sell_lots += Order::OrderLots(); break; + default: + RUNTIME_ERROR("Not supported order type!"); + return 0; } } } diff --git a/Platform.extern.h b/Platform.extern.h index 41742d45e..943ec3bcd 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -29,9 +29,9 @@ #include "Order.define.h" // Forward declarations. -class MqlTradeRequest; -class MqlTradeResult; -class MqlTradeCheckResult; +struct MqlTradeRequest; +struct MqlTradeResult; +struct MqlTradeCheckResult; template double iCustom(string symbol, int timeframe, string name, Args... args) { @@ -129,10 +129,12 @@ extern int ChartID(); extern bool OrderCalcMargin(ENUM_ORDER_TYPE _action, string _symbol, double _volume, double _price, double& _margin); -double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id); +extern double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id); -long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); +extern long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); -string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); +extern string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); + +extern string Symbol(); #endif diff --git a/Platform.h b/Platform.h index 8b2f666f9..7a520a5b5 100644 --- a/Platform.h +++ b/Platform.h @@ -573,6 +573,11 @@ string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id) { return false; } +string Symbol() { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return false; +} + #endif /** diff --git a/Refs.struct.h b/Refs.struct.h index da94bf8a1..9827f7b1a 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -115,26 +115,17 @@ struct Ref { /** * Constructor. */ - Ref(X* _ptr) { - ptr_object = nullptr; - THIS_REF = _ptr; - } + Ref(X* _ptr) : ptr_object(nullptr) { THIS_REF = _ptr; } /** * Constructor. */ - Ref(const Ref& ref) { - ptr_object = nullptr; - Set(ref.Ptr()); - } + Ref(const Ref& ref) : ptr_object(nullptr) { Set(ref.Ptr()); } /** * Constructor. */ - Ref(WeakRef& ref) { - ptr_object = nullptr; - Set(ref.Ptr()); - } + Ref(WeakRef& ref) : ptr_object(nullptr) { Set(ref.Ptr()); } /** * Constructor. @@ -312,31 +303,26 @@ struct WeakRef { /** * Constructor. */ - WeakRef(X* _ptr = NULL) { this = _ptr; } - - /** - * Constructor. - */ - WeakRef(const WeakRef& ref) { THIS_REF = ref.Ptr(); } + WeakRef(X* _ptr = NULL) : ptr_ref_counter(nullptr) { THIS_REF = _ptr; } /** * Constructor. */ - WeakRef(WeakRef& ref) { THIS_REF = ref.Ptr(); } + WeakRef(const WeakRef& ref) : ptr_ref_counter(nullptr) { THIS_REF = ref.Ptr(); } /** * Constructor. */ - WeakRef(Ref& ref) { THIS_REF = ref.Ptr(); } + WeakRef(Ref& ref) : ptr_ref_counter(nullptr) { THIS_REF = ref.Ptr(); } /** * Destructor. */ ~WeakRef() { Unset(); } - bool ObjectExists() { return ptr_ref_counter != NULL && !PTR_ATTRIB(ptr_ref_counter, deleted); } + bool ObjectExists() const { return ptr_ref_counter != NULL && !PTR_ATTRIB(ptr_ref_counter, deleted); } - X* Ptr() { return ObjectExists() ? (X*)(PTR_ATTRIB(ptr_ref_counter, ptr_object)) : NULL; } + X* Ptr() const { return ObjectExists() ? (X*)(PTR_ATTRIB(ptr_ref_counter, ptr_object)) : NULL; } /** * Makes a weak reference to the given object. @@ -374,7 +360,7 @@ struct WeakRef { * Makes a weak reference to the given weakly-referenced object. */ X* operator=(WeakRef& right) { - this = right.Ptr(); + THIS_REF = right.Ptr(); return Ptr(); } @@ -382,7 +368,7 @@ struct WeakRef { * Makes a weak reference to the strongly-referenced object. */ X* operator=(Ref& right) { - this = right.Ptr(); + THIS_REF = right.Ptr(); return Ptr(); } diff --git a/Serializer/SerializerCsv.h b/Serializer/SerializerCsv.h index aea45d535..47d6f2c03 100644 --- a/Serializer/SerializerCsv.h +++ b/Serializer/SerializerCsv.h @@ -274,8 +274,9 @@ class SerializerCsv { } else { // A property. - bool _include_titles = bool(_flags & SERIALIZER_CSV_INCLUDE_TITLES); - bool _include_titles_tree = (_flags & SERIALIZER_CSV_INCLUDE_TITLES_TREE) == SERIALIZER_CSV_INCLUDE_TITLES_TREE; + // bool _include_titles = bool(_flags & SERIALIZER_CSV_INCLUDE_TITLES); + // bool _include_titles_tree = (_flags & SERIALIZER_CSV_INCLUDE_TITLES_TREE) == + // SERIALIZER_CSV_INCLUDE_TITLES_TREE; if (_column_types != NULL) { if (_data PTR_DEREF GetValueParam() == NULL) { diff --git a/Std.h b/Std.h index aaa06888f..d214d3bf2 100644 --- a/Std.h +++ b/Std.h @@ -174,6 +174,8 @@ class _cpp_array { std::vector& str() { return m_data; } + void push(const T& value) { m_data.push_back(value); } + void operator=(const _cpp_array& r) { m_data = r.m_data; m_isSeries = r.m_isSeries; @@ -354,3 +356,7 @@ _NULL_VALUE::operator string() const { extern ENUM_TIMEFRAMES Period(); #endif + +#define RUNTIME_ERROR(MSG) \ + Print(MSG); \ + DebugBreak(); diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index d1edaed1e..178dca0a8 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -196,7 +196,7 @@ class ItemsHistory { _from_time_ms = _item.GetTimeMs() + _item.GetLengthMs() + 1; } - long _current_time_ms = TimeCurrent() * 1000; + // long _current_time_ms = TimeCurrent() * 1000; if (_from_time_ms > (long)TimeCurrent() * 1000) { // There won't be items in the future. diff --git a/Storage/ValueStorage.accessor.h b/Storage/ValueStorage.accessor.h index 8d0a95112..d4fc60aee 100644 --- a/Storage/ValueStorage.accessor.h +++ b/Storage/ValueStorage.accessor.h @@ -70,12 +70,12 @@ class ValueStorageAccessor { /** * Fetches value from the storage. */ - const C Get() const { return storage.Fetch(index); } + const C Get() const { return storage PTR_DEREF Fetch(index); } /** * Stores value in the storage. */ - void Set(C value) { storage.Store(index, value); } + void Set(C value) { storage PTR_DEREF Store(index, value); } #define VALUE_STORAGE_ACCESSOR_OP(TYPE, OP) \ TYPE operator OP(const ValueStorageAccessor& _accessor) const { return Get() OP _accessor.Get(); } \ diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index 8e7fa6e66..b550627b0 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -228,8 +228,6 @@ int ArrayCopy(ARRAY_REF(D, _target), ValueStorage &_source, int _dst_start = } } - int _pre_fill = _dst_start; - count = MathMin(count, ArraySize(_source) - _src_start); int _dst_required_size = _dst_start + count; diff --git a/String.extern.h b/String.extern.h index 26a4a9b74..4064372b9 100644 --- a/String.extern.h +++ b/String.extern.h @@ -33,6 +33,7 @@ #include #include +#include "Math.extern.h" #include "Std.h" #include "Terminal.define.h" @@ -102,7 +103,14 @@ unsigned short StringGetCharacter(string string_value, int pos) { } int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, - unsigned int codepage = CP_ACP); + unsigned int codepage = CP_ACP) { + if (count == -1) count = text_string.size(); + + for (int i = start; i < MathMin(start + count, (int)text_string.size()); ++i) + array.push((unsigned char)text_string[i]); + + return array.size(); +} bool StringInit(string& string_var, int new_len = 0, unsigned short character = 0) { string_var = string(new_len, (char)character); @@ -116,7 +124,7 @@ bool StringInit(string& string_var, int new_len = 0, unsigned short character = * - https://www.mql5.com/en/docs/strings/stringreplace */ int StringReplace(string& str, const string& find, const string& replacement) { - int num_replacements; + int num_replacements = 0; for (size_t pos = 0;; pos += replacement.length()) { // Locate the substring to replace pos = str.find(find, pos); diff --git a/SymbolInfo.mqh b/SymbolInfo.mqh index 259d6caef..534646a66 100644 --- a/SymbolInfo.mqh +++ b/SymbolInfo.mqh @@ -518,10 +518,11 @@ class SymbolInfo : public Object { "Tick size: %g (%g pts), Tick value: %g (%g/%g), " + "Digits: %d, Spread: %d pts, Trade stops level: %d, " + "Trade contract size: %g, Min lot: %g, Max lot: %g, Lot step: %g, " + "Freeze level: %d, Swap (long/short/mode): %g/%g/%d, Margin initial (maintenance): %g (%g)", - GetSymbol(), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), GetPointSize(), GetPipSize(), - GetTickSize(), GetTradeTickSize(), GetTickValue(), GetTickValueProfit(), GetTickValueLoss(), GetDigits(), - GetSpread(), GetTradeStopsLevel(), GetTradeContractSize(), GetVolumeMin(), GetVolumeMax(), GetVolumeStep(), - GetFreezeLevel(), GetSwapLong(), GetSwapShort(), GetSwapMode(), GetMarginInit(), GetMarginMaintenance()); + C_STR(GetSymbol()), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), GetPointSize(), + GetPipSize(), GetTickSize(), GetTradeTickSize(), GetTickValue(), GetTickValueProfit(), GetTickValueLoss(), + GetDigits(), GetSpread(), GetTradeStopsLevel(), GetTradeContractSize(), GetVolumeMin(), GetVolumeMax(), + GetVolumeStep(), GetFreezeLevel(), GetSwapLong(), GetSwapShort(), GetSwapMode(), GetMarginInit(), + GetMarginMaintenance()); } /** @@ -531,7 +532,7 @@ class SymbolInfo : public Object { return !_header ? StringFormat(string("%s,%g,%g,%d,%g,%g,%g,") + "%g,%g,%g,%g,%g," + "%d,%d,%d," + "%g,%g,%g,%g," + "%d,%g,%g,%d,%g,%g", - GetSymbol(), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), + C_STR(GetSymbol()), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), GetPointSize(), GetPipSize(), GetTickSize(), GetTradeTickSize(), GetTickValue(), GetTickValueProfit(), GetTickValueLoss(), GetDigits(), GetSpread(), GetTradeStopsLevel(), GetTradeContractSize(), GetVolumeMin(), GetVolumeMax(), GetVolumeStep(), GetFreezeLevel(), diff --git a/Task/TaskManager.h b/Task/TaskManager.h index 7f017217a..d9a7fc0e7 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -131,6 +131,8 @@ EMSCRIPTEN_BINDINGS(TaskManager) { .constructor() .function("Add", emscripten::optional_override([](TaskManager &self, Ref task) { Print("Adding Task"); + Print(StringToUpper("Testing StringToUpper")); + Print(StringToLower("Testing StringToLower")); self.Add(task.Ptr()); })) // .function("Add", emscripten::select_overload(&TaskManager::Add)) diff --git a/Task/TaskObject.h b/Task/TaskObject.h index a26876edf..3258b38a5 100644 --- a/Task/TaskObject.h +++ b/Task/TaskObject.h @@ -54,7 +54,7 @@ class TaskObject : public Task { /** * Class constructor with task entry as argument. */ - TaskObject(TaskEntry &_tentry, TA *_obja = NULL, TC *_objc = NULL) : obja(_obja), objc(_objc), Task(_tentry) {} + TaskObject(TaskEntry &_tentry, TA *_obja = nullptr, TC *_objc = nullptr) : Task(_tentry), obja(_obja), objc(_objc) {} /** * Class deconstructor. diff --git a/Terminal.mqh b/Terminal.mqh index 77aa28d13..6c5116679 100644 --- a/Terminal.mqh +++ b/Terminal.mqh @@ -43,8 +43,8 @@ class Terminal; #include "Refs.mqh" #include "String.mqh" #include "Terminal.define.h" -#include "Terminal.extern.h" #include "Terminal.enum.h" +#include "Terminal.extern.h" #include "Terminal.struct.h" #ifdef __MQL5__ @@ -876,13 +876,13 @@ class Terminal : public Object { * Returns true when the condition is met. */ bool CheckCondition(ENUM_TERMINAL_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { - long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; - long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; + // long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; + // long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; switch (_cond) { case TERMINAL_COND_IS_CONNECTED: return !IsConnected(); default: - Print(StringFormat("Invalid terminal condition: %s!", EnumToString(_cond), __FUNCTION__)); + Print("Invalid terminal condition: ", EnumToString(_cond), " at ", __FUNCTION__, "!"); return false; } } @@ -910,14 +910,14 @@ class Terminal : public Object { * Returns true when the condition is met. */ bool ExecuteAction(ENUM_TERMINAL_ACTION _action, ARRAY_REF(MqlParam, _args)) { - long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; - long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; - long _arg3l = ArraySize(_args) > 2 ? DataParamEntry::ToInteger(_args[2]) : WRONG_VALUE; + // long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; + // long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; + // long _arg3l = ArraySize(_args) > 2 ? DataParamEntry::ToInteger(_args[2]) : WRONG_VALUE; switch (_action) { case TERMINAL_ACTION_CRASH: delete THIS_PTR; default: - Print(StringFormat("Invalid terminal action: %s!", EnumToString(_action), __FUNCTION__)); + Print("Invalid terminal action: ", EnumToString(_action), " at ", __FUNCTION__, "!"); return false; } } @@ -931,40 +931,39 @@ class Terminal : public Object { /** * Returns textual representation of the Terminal class. */ - string ToString(string _sep = "; ") { + string ToString() override { + string _sep = "; "; return StringFormat("Allow DLL: %s", IsDllsAllowed() ? "Yes" : "No") + _sep + - StringFormat("Allow Libraries: %s", IsLibrariesAllowed() ? "Yes" : "No") + _sep + - StringFormat("CPUs: %d", GetCpuCores()) + _sep + - // StringFormat("Community account: %s", (string)HasCommunityAccount()) + _sep + - // StringFormat("Community balance: %.2f", GetCommunityBalance()) + _sep + - // StringFormat("Community connection: %s", (string)IsCommunityConnected()) + _sep + - StringFormat("Disk space: %d", GetDiskSpace()) + _sep + - StringFormat("Enabled FTP: %s", IsFtpEnabled() ? "Yes" : "No") + _sep + - StringFormat("Enabled e-mail: %s", IsEmailEnabled() ? "Yes" : "No") + _sep + - // StringFormat("Enabled notifications: %s", (string)IsNotificationsEnabled()) + _sep + - StringFormat("IsOptimization: %s", IsOptimization() ? "Yes" : "No") + _sep + - StringFormat("IsRealtime: %s", IsRealtime() ? "Yes" : "No") + _sep + - StringFormat("IsTesting: %s", IsTesting() ? "Yes" : "No") + _sep + - StringFormat("IsVisual: %s", IsVisualMode() ? "Yes" : "No") + _sep + - // StringFormat("MQ ID: %s", (string)HasMetaQuotesId()) + _sep + - StringFormat("Memory (free): %d", GetFreeMemory()) + _sep + - StringFormat("Memory (physical): %d", GetPhysicalMemory()) + _sep + - StringFormat("Memory (total): %d", GetTotalMemory()) + _sep + - StringFormat("Memory (used): %d", GetUsedMemory()) + _sep + - StringFormat("Path (Common): %s", GetCommonPath()) + _sep + StringFormat("Path (Data): %s", GetDataPath()) + - _sep + StringFormat("Path (Expert): %s", GetExpertPath()) + _sep + - StringFormat("Path (Terminal): %s", GetTerminalPath()) + _sep + - StringFormat("Program name: %s", WindowExpertName()) + _sep + - StringFormat("Screen DPI: %d", GetScreenDpi()) + _sep + StringFormat("Terminal build: %d", GetBuild()) + - _sep + StringFormat("Terminal code page: %d", IntegerToString(GetCodePage())) + _sep + - StringFormat("Terminal company: %s", GetCompany()) + _sep + - StringFormat("Terminal connected: %s", IsConnected() ? "Yes" : "No") + _sep + - StringFormat("Terminal language: %s", GetLanguage()) + _sep + StringFormat("Terminal name: %s", GetName()) + - _sep + StringFormat("Termnal max bars: %d", GetMaxBars()) + _sep + - StringFormat("Trade allowed: %s", IsTradeAllowed() ? "Yes" : "No") + _sep + - StringFormat("Trade context busy: %s", IsTradeContextBusy() ? "Yes" : "No") + _sep + - StringFormat("Trade perm: %s", CheckPermissionToTrade() ? "Yes" : "No") + _sep + - StringFormat("Trade ping (last): %d", GetPingLast()); + StringFormat("Allow Libraries: %s", IsLibrariesAllowed() ? "Yes" : "No") + _sep + + StringFormat("CPUs: %d", GetCpuCores()) + _sep + + // StringFormat("Community account: %s", (string)HasCommunityAccount()) + _sep + + // StringFormat("Community balance: %.2f", GetCommunityBalance()) + _sep + + // StringFormat("Community connection: %s", (string)IsCommunityConnected()) + _sep + + StringFormat("Disk space: %d", GetDiskSpace()) + _sep + + StringFormat("Enabled FTP: %s", IsFtpEnabled() ? "Yes" : "No") + _sep + + StringFormat("Enabled e-mail: %s", IsEmailEnabled() ? "Yes" : "No") + _sep + + // StringFormat("Enabled notifications: %s", (string)IsNotificationsEnabled()) + _sep + + StringFormat("IsOptimization: %s", IsOptimization() ? "Yes" : "No") + _sep + + StringFormat("IsRealtime: %s", IsRealtime() ? "Yes" : "No") + _sep + + StringFormat("IsTesting: %s", IsTesting() ? "Yes" : "No") + _sep + + StringFormat("IsVisual: %s", IsVisualMode() ? "Yes" : "No") + _sep + + // StringFormat("MQ ID: %s", (string)HasMetaQuotesId()) + _sep + + StringFormat("Memory (free): %d", GetFreeMemory()) + _sep + + StringFormat("Memory (physical): %d", GetPhysicalMemory()) + _sep + + StringFormat("Memory (total): %d", GetTotalMemory()) + _sep + + StringFormat("Memory (used): %d", GetUsedMemory()) + _sep + "Path (Common): " + GetCommonPath() + _sep + + "Path (Data): " + GetDataPath() + _sep + "Path (Expert): " + GetExpertPath() + _sep + + "Path (Terminal): ", + GetTerminalPath() + _sep + "Program name: ", + WindowExpertName() + _sep + StringFormat("Screen DPI: %d", GetScreenDpi()) + _sep + + StringFormat("Terminal build: %d", GetBuild()) + _sep + + "Terminal code page: " + IntegerToString(GetCodePage()) + _sep + "Terminal company: " + GetCompany() + + _sep + "Terminal connected: " + (IsConnected() ? "Yes" : "No") + _sep + + "Terminal language: " + GetLanguage() + _sep + "Terminal name: " + GetName() + _sep + + StringFormat("Termnal max bars: %d", GetMaxBars()) + _sep + + "Trade allowed: " + (IsTradeAllowed() ? "Yes" : "No") + _sep + + "Trade context busy: " + (IsTradeContextBusy() ? "Yes" : "No") + _sep + "Trade perm: %s" + + (CheckPermissionToTrade() ? "Yes" : "No") + _sep + StringFormat("Trade ping (last): %d", GetPingLast()); } }; diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index b600e930d..9b0622bf2 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -69,8 +69,8 @@ template struct TickTAB : TickAB { long time_ms; // Time of the last prices update. // Struct constructors. - TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : time_ms(_time_ms), TickAB(_ask, _bid) {} - TickTAB(MqlTick &_tick) : time_ms(_tick.time_msc), TickAB(_tick) {} + TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : TickAB(_ask, _bid), time_ms(_time_ms) {} + TickTAB(MqlTick &_tick) : TickAB(_tick), time_ms(_tick.time_msc) {} /** * Method used by ItemsHistory. diff --git a/Trade.mqh b/Trade.mqh index d6d98228d..2f5b81303 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -241,7 +241,8 @@ class Trade : public Taskable { * Sets default name of trade instance. */ void SetName() { - name = StringFormat("%s@%s", GetSource() PTR_DEREF GetSymbol(), ChartTf::TfToString(GetSource() PTR_DEREF GetTf())); + name = StringFormat("%s@%s", C_STR(GetSource() PTR_DEREF GetSymbol()), + C_STR(ChartTf::TfToString(GetSource() PTR_DEREF GetTf()))); } /** @@ -269,6 +270,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result = _open < _low; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } return _result; @@ -291,6 +295,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result = GetSource() PTR_DEREF GetOpenOffer(_cmd) < _pp; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } return _result; @@ -368,6 +375,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result |= _odata.Get(ORDER_PRICE_OPEN) >= _price_curr; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } } @@ -384,6 +394,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result |= _odata.Get(ORDER_PRICE_OPEN) >= _price_curr; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } } else if (_order.IsSet()) { @@ -401,7 +414,7 @@ class Trade : public Taskable { bool _result = false; Ref _order = order_last; OrderData _odata; - double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); + // double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); if (_order.IsSet()) { _result = _odata.Get(ORDER_TYPE) != _cmd; @@ -661,7 +674,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. switch (_last_error) { case 69539: logger.Error("Error while opening an order!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); tstats.Add(TRADE_STAT_ORDERS_ERRORS); // Pass-through. case ERR_NO_ERROR: // 0 @@ -684,7 +697,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; default: logger.Error("Cannot add order!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); tstats.Add(TRADE_STAT_ORDERS_ERRORS); _result = false; break; @@ -854,7 +867,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * On error, returns -1. */ int OrdersCloseAll(ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_ALL, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { @@ -884,7 +897,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. */ int OrdersCloseViaCmd(ENUM_ORDER_TYPE _cmd, ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { @@ -922,7 +935,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. template int OrdersCloseViaProp(E _prop, T _value, ENUM_MATH_CONDITION _op, ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { @@ -958,7 +971,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. template int OrdersCloseViaProp2(E _prop1, T _value1, E _prop2, T _value2, ENUM_MATH_CONDITION _op, ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { @@ -1109,7 +1122,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return NormalizeSLTP(_value1 < _value2 ? _value1 : _value2, _cmd, _mode); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; case ORDER_TYPE_SELL_LIMIT: @@ -1120,11 +1133,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return NormalizeSLTP(_value1 > _value2 ? _value1 : _value2, _cmd, _mode); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; default: - logger.Error(StringFormat("Invalid order type: %s!", EnumToString(_cmd), __FUNCTION__)); + logger.Error(StringFormat("Invalid order type: %s at %s!", C_STR(EnumToString(_cmd)), C_STR(__FUNCTION__))); } return EMPTY_VALUE; } @@ -1475,7 +1488,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return fmax(_value, GetSource() PTR_DEREF GetBid() + GetTradeDistanceInValue()); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; // Selling is done at the Bid price. @@ -1490,11 +1503,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return fmin(_value, GetSource() PTR_DEREF GetAsk() - GetTradeDistanceInValue()); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; default: - logger.Error(StringFormat("Invalid order type: %s!", EnumToString(_cmd), __FUNCTION__)); + logger.Error(StringFormat("Invalid order type: %s at %s!", C_STR(EnumToString(_cmd)), C_STR(__FUNCTION__))); } return 0; } @@ -1578,7 +1591,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } #ifdef __debug__ if (!_is_valid) { - PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", __FUNCTION__, EnumToString(_cmd), _value, _price); + PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", __FUNCTION__, C_STR(EnumToString(_cmd)), _value, + _price); } #endif if (_is_valid && _value_prev > 0 && _locked) { @@ -1609,7 +1623,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. double ask = GetSource() PTR_DEREF GetAsk(); double bid = GetSource() PTR_DEREF GetBid(); double openprice = GetSource() PTR_DEREF GetOpenOffer(_cmd); - double closeprice = GetSource() PTR_DEREF GetCloseOffer(_cmd); + // double closeprice = GetSource() PTR_DEREF GetCloseOffer(_cmd); // The minimum distance of SYMBOL_TRADE_STOPS_LEVEL taken into account. double distance = GetTradeDistanceInValue(); // bool result; @@ -1698,7 +1712,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } #ifdef __debug__ if (!_is_valid) { - PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", __FUNCTION__, EnumToString(_cmd), _value, _price); + PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", C_STR(__FUNCTION__), C_STR(EnumToString(_cmd)), + _value, _price); } #endif if (_is_valid && _value_prev > 0 && _locked) { @@ -1853,7 +1868,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // case TRADE_ORDER_CONDS_IN_TREND: // case TRADE_ORDER_CONDS_IN_TREND_NOT: default: - GetLogger() PTR_DEREF Error(StringFormat("Invalid Trade condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error( + StringFormat("Invalid Trade condition: %d at %s!", _entry.GetId(), C_STR(__FUNCTION_LINE__))); SetUserError(ERR_INVALID_PARAMETER); break; } @@ -1986,7 +2002,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case TRADE_ACTION_STATE_ADD: tstates.AddState(_entry.GetArg(0).ToValue()); default: - GetLogger() PTR_DEREF Error(StringFormat("Invalid Trade action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + GetLogger() + PTR_DEREF Error(StringFormat("Invalid Trade action: %d at %s!", _entry.GetId(), C_STR(__FUNCTION_LINE__))); SetUserError(ERR_INVALID_PARAMETER); break; } diff --git a/Trade.struct.h b/Trade.struct.h index beaf37140..56919c02a 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -129,13 +129,13 @@ struct TradeStats { /* Structure for trade parameters. */ struct TradeParams { - float lot_size; // Default lot size. - float risk_margin; // Maximum account margin to risk (in %). - string order_comment; // Order comment. + unsigned short bars_min; // Minimum bars to trade. + string order_comment; // Order comment. + float lot_size; // Default lot size. + unsigned long magic_no; // Unique magic number used for the trading. + float risk_margin; // Maximum account margin to risk (in %). unsigned int limits_stats[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; unsigned int slippage; // Value of the maximum price slippage in points. - unsigned long magic_no; // Unique magic number used for the trading. - unsigned short bars_min; // Minimum bars to trade. ENUM_LOG_LEVEL log_level; // Log verbosity level. // Constructors. TradeParams(float _lot_size = 0, float _risk_margin = 1.0, unsigned int _slippage = 50) @@ -148,7 +148,7 @@ struct TradeParams { SetLimits(0); } TradeParams(unsigned long _magic_no, ENUM_LOG_LEVEL _ll = V_INFO) - : bars_min(100), lot_size(0), order_comment(""), log_level(_ll), magic_no(_magic_no) {} + : bars_min(100), order_comment(""), lot_size(0), magic_no(_magic_no), log_level(_ll) {} TradeParams(const TradeParams &_tparams) { THIS_REF = _tparams; } // Deconstructor. ~TradeParams() {} @@ -163,11 +163,13 @@ struct TradeParams { case TRADE_PARAM_MAGIC_NO: return (T)magic_no; case TRADE_PARAM_ORDER_COMMENT: - return (T)order_comment; + return ConvertBasic::StringTo(order_comment); case TRADE_PARAM_RISK_MARGIN: return (T)risk_margin; case TRADE_PARAM_SLIPPAGE: return (T)slippage; + default: + break; } SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; @@ -220,7 +222,7 @@ struct TradeParams { magic_no = (unsigned long)_value; return; case TRADE_PARAM_ORDER_COMMENT: - order_comment = (string)_value; + order_comment = SerializerConversions::ValueToString(_value); return; case TRADE_PARAM_RISK_MARGIN: risk_margin = (float)_value; @@ -228,6 +230,8 @@ struct TradeParams { case TRADE_PARAM_SLIPPAGE: slippage = (unsigned int)_value; return; + default: + break; } SetUserError(ERR_INVALID_PARAMETER); } @@ -328,6 +332,8 @@ struct TradeStates { return "Terminal offline"; case TRADE_STATE_TRADE_TERMINAL_SHUTDOWN: return "Terminal is shutting down"; + default: + break; } return "Unknown!"; } From c09b514e9afa31a5c11d5d0f81d2637da595ac71 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 26 Jan 2023 17:00:20 +0100 Subject: [PATCH 11/42] IndicatorsTest now compiles in MT5. Need to check other tests. --- Candle.struct.h | 5 +- DateTime.static.h | 17 ++-- DictSlot.mqh | 2 +- DictStruct.mqh | 4 +- Indicator/Indicator.h | 12 +-- Indicator/IndicatorData.h | 13 ++- Indicator/IndicatorData.struct.h | 2 + Indicators/Indi_Demo.mqh | 2 +- Indicators/Indi_Momentum.mqh | 4 +- Indicators/Indi_PriceFeeder.mqh | 2 +- Indicators/Indi_StdDev.mqh | 3 +- Log.mqh | 3 +- Platform.h | 5 +- PlatformTime.h | 19 ++-- Refs.struct.h | 13 +-- Storage/ValueStorage.indicator.h | 4 +- Task/Task.h | 4 +- Terminal.define.h | 4 + Terminal.mqh | 58 ++++++------- Tick/Tick.struct.h | 1 + tests/IndicatorsTest.mq5 | 144 +++++++++++++++---------------- 21 files changed, 166 insertions(+), 155 deletions(-) diff --git a/Candle.struct.h b/Candle.struct.h index 75acc6b09..6b2f502e3 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -236,7 +236,7 @@ struct CandleOCTOHLC : CandleOHLC { // Number of ticks which formed the candle. Also known as volume. int volume; - // Struct constructors. + // Struct constructor. CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, int _start_time = -1, int _length = 0, long _open_timestamp_ms = -1, long _close_timestamp_ms = -1, int _volume = 0) : CandleOHLC(_open, _high, _low, _close), @@ -251,6 +251,9 @@ struct CandleOCTOHLC : CandleOHLC { } } + // Struct constructor. + CandleOCTOHLC(const CandleOCTOHLC &r) { THIS_REF = r; } + /** * Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price. */ diff --git a/DateTime.static.h b/DateTime.static.h index 1b5950128..c2ca188d8 100644 --- a/DateTime.static.h +++ b/DateTime.static.h @@ -31,7 +31,6 @@ #endif // Includes. -#include "DateTime.static.h" #include "PlatformTime.h" /* @@ -43,7 +42,7 @@ struct DateTimeStatic { */ static int Day(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::TimeDay(dt); @@ -59,7 +58,7 @@ struct DateTimeStatic { */ static int DayOfWeek(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::DayOfWeek(); @@ -75,7 +74,7 @@ struct DateTimeStatic { */ static int DayOfYear(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::DayOfYear(); @@ -91,7 +90,7 @@ struct DateTimeStatic { */ static int Hour(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::Hour(); @@ -116,7 +115,7 @@ struct DateTimeStatic { */ static int Minute(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::Minute(); @@ -132,7 +131,7 @@ struct DateTimeStatic { */ static int Month(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::Month(); @@ -148,7 +147,7 @@ struct DateTimeStatic { */ static int Seconds(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::Seconds(); @@ -194,7 +193,7 @@ struct DateTimeStatic { */ static int Year(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::Year(); diff --git a/DictSlot.mqh b/DictSlot.mqh index eea48969d..07b42fbf2 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,7 +40,7 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} - DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} + DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key) { value = r.value; } bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } diff --git a/DictStruct.mqh b/DictStruct.mqh index 6ff0063fb..229a9567c 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -113,7 +113,7 @@ class DictStruct : public DictBase { /** * Inserts value using hashless key. */ - bool Push(const V& value) { + bool Push(V& value) { if (!InsertInto(THIS_ATTR _DictSlots_ref, value)) return false; return true; } @@ -361,7 +361,7 @@ class DictStruct : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const V& value) { + bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeList; else if (THIS_ATTR _mode != DictModeList) { diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 9bab3b18f..8d625a583 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -27,12 +27,6 @@ // Forward class declaration. struct IndicatorParams; -#include "Indicator.define.h" -#include "Indicator.enum.h" -#include "Indicator.struct.h" -#include "Indicator.struct.serialize.h" -#include "IndicatorData.h" - // Includes. #include "../Array.mqh" #include "../BufferStruct.mqh" @@ -48,6 +42,12 @@ struct IndicatorParams; #include "../Storage/ValueStorage.h" #include "../Storage/ValueStorage.indicator.h" #include "../Storage/ValueStorage.native.h" +#include "../Task/TaskCondition.enum.h" +#include "Indicator.define.h" +#include "Indicator.enum.h" +#include "Indicator.struct.h" +#include "Indicator.struct.serialize.h" +#include "IndicatorData.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compatibility). diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 2d706bda3..0707e4fe8 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -32,6 +32,11 @@ // Forward class declaration. class IndicatorData; class DrawIndicator; +class IValueStorage; + +struct ExternInstantiateIndicatorBufferValueStorageDouble { + static IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData*, int); +}; // Includes. #include "../Bar.struct.h" @@ -48,8 +53,6 @@ class DrawIndicator; #include "IndicatorData.struct.serialize.h" #include "IndicatorData.struct.signal.h" -extern IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData* _indi, int _mode); - /** * Implements class to store indicator data. */ @@ -745,7 +748,7 @@ class IndicatorData : public IndicatorBase { */ void AddListener(IndicatorData* _indi) { WeakRef _ref = _indi; - ArrayPush(listeners, _ref); + ArrayPushObject(listeners, _ref); } /** @@ -1746,7 +1749,9 @@ class IndicatorData : public IndicatorBase { } if (!value_storages[_mode].IsSet()) { - value_storages[_mode] = InstantiateIndicatorBufferValueStorageDouble(THIS_PTR, _mode); + value_storages[_mode] = + ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble(THIS_PTR, + _mode); } return value_storages[_mode].Ptr(); } diff --git a/Indicator/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h index dd4e29493..549c44219 100644 --- a/Indicator/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -530,6 +530,8 @@ struct IndicatorDataParams { indi_color = _clr; draw_window = _window; } + bool IsDrawing() { return is_draw; } + void SetIndicatorColor(color _clr) { indi_color = _clr; } }; diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index d4bf22c37..07afa9a28 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -81,7 +81,7 @@ class Indi_Demo : public Indicator { */ virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = Indi_Demo::iDemo(THIS_PTR, ToRelShift(_abs_shift)); - if (idparams.is_draw) { + if (idparams.IsDrawing()) { draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(ToRelShift(_abs_shift)), _value); } return _value; diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 122c15e37..679f96c45 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -150,7 +150,7 @@ class Indi_Momentum : public Indicator { // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), iparams.shift + ToRelShift(_abs_shift)); - if (idparams.is_draw) { + if (idparams.IsDrawing()) { draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); } break; @@ -164,7 +164,7 @@ class Indi_Momentum : public Indicator { // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), iparams.shift + ToRelShift(_abs_shift)); - if (idparams.is_draw) { + if (idparams.IsDrawing()) { draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); } break; diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index cbe8b7213..4b93f08ea 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -103,7 +103,7 @@ class Indi_PriceFeeder : public Indicator { void OnTick(int _global_tick_index) override { Indicator::OnTick(_global_tick_index); - if (idparams.is_draw) { + if (idparams.IsDrawing()) { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); IndicatorDataEntry _entry = GetEntry(0); for (int i = 0; i < _max_modes; ++i) { diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 3154b4e51..7de50a928 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -199,7 +199,8 @@ class Indi_StdDev : public Indicator { Indi_PriceFeeder *_indi_price_feeder; if (!ObjectsCache::TryGet(_key, _indi_price_feeder)) { IndiPriceFeederParams _params(); - _indi_price_feeder = ObjectsCache::Set(_key, new Indi_PriceFeeder(_params)); + IndicatorData *_indi_pf = new Indi_PriceFeeder(_params); + _indi_price_feeder = ObjectsCache::Set(_key, _indi_pf); } // Filling reused price feeder. diff --git a/Log.mqh b/Log.mqh index 0a4bff34a..b83ca09e0 100644 --- a/Log.mqh +++ b/Log.mqh @@ -188,7 +188,8 @@ class Log : public Object { void Link(Log *_log) { PTR_ATTRIB(_log, SetLevel(log_level)); // Sets the same level as this instance. // @todo: Make sure we're not linking the same instance twice. - logs.Push(_log); + Ref _ref_log = _log; + logs.Push(_ref_log); } /** diff --git a/Platform.h b/Platform.h index 7a520a5b5..90f8440cf 100644 --- a/Platform.h +++ b/Platform.h @@ -219,7 +219,10 @@ class Platform { /** * Returns id of the current chart. */ - static int ChartID() { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); } + static int ChartID() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; + } /** * Binds Candle and/or Tick indicator as a source of prices or data for given indicator. diff --git a/PlatformTime.h b/PlatformTime.h index 8e62646f5..89cb39527 100644 --- a/PlatformTime.h +++ b/PlatformTime.h @@ -23,7 +23,6 @@ // Includes. #include "DateTime.enum.h" #include "DateTime.mqh" -#include "DateTime.struct.h" /** * @file @@ -35,7 +34,9 @@ // Includes. #include #include + #include "DateTime.struct.h" +#endif class PlatformTime { static MqlDateTime current_time; @@ -49,19 +50,19 @@ class PlatformTime { void static Tick() { #ifdef __MQL__ - static _last_time_ms = 0; + static long _last_timestamp_ms = 0; - current_time_s = ::TimeCurrent(¤t_time); + current_timestamp_s = ::TimeCurrent(current_time); - current_time_ms = (long)GetTickCount(); + current_timestamp_ms = (long)GetTickCount(); - if (_last_time_ms != 0 && current_time_ms < _last_time_ms) { + if (_last_timestamp_ms != 0 && current_timestamp_ms < _last_timestamp_ms) { // Overflow occured (49.7 days passed). // More info: https://docs.mql4.com/common/gettickcount - current_time_ms += _last_time_ms; + current_timestamp_ms += _last_timestamp_ms; } - _last_time_ms = current_time_ms; + _last_timestamp_ms = current_timestamp_ms; #else using namespace std::chrono; current_timestamp_s = (long)duration_cast(system_clock::now().time_since_epoch()).count(); @@ -82,8 +83,6 @@ class PlatformTime { } }; -MqlDateTime PlatformTime::current_time{0, 0, 0, 0, 0, 0, 0, 0}; +MqlDateTime PlatformTime::current_time = {0, 0, 0, 0, 0, 0, 0, 0}; long PlatformTime::current_timestamp_s = 0; long PlatformTime::current_timestamp_ms = 0; - -#endif diff --git a/Refs.struct.h b/Refs.struct.h index 9827f7b1a..210f58f11 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -30,9 +30,6 @@ #pragma once #endif -// Includes. -#include - #include "Refs.rc.h" #include "Std.h" @@ -93,10 +90,6 @@ struct SimpleRef { } }; -template -using base_type = - typename std::remove_cv::type>::type>::type; - /** * Class used to hold strong reference to reference-counted object. */ @@ -284,9 +277,9 @@ struct Ref { } }; -template -Ref make_ref() { - return Ref(); +template +Ref MakeRef(X* _ptr) { + return Ref(_ptr); } /** diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 4406fe397..254767c7c 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -34,6 +34,7 @@ class IndicatorData; // Includes. +#include "../Indicator/IndicatorData.h" #include "ValueStorage.history.h" /** @@ -57,6 +58,7 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { C Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_rel_shift)); } }; -IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData* _indi, int _mode) { +IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble( + IndicatorData* _indi, int _mode) { return new IndicatorBufferValueStorage(_indi, _mode); } diff --git a/Task/Task.h b/Task/Task.h index c2ca184cc..266a60284 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -50,7 +50,7 @@ class Task : public Taskable { * Class constructor. */ Task() {} - Task(const TaskEntry &_entry) { Add(_entry); } + Task(TaskEntry &_entry) { Add(_entry); } /** * Class copy constructor. @@ -67,7 +67,7 @@ class Task : public Taskable { /** * Adds new task. */ - void Add(const TaskEntry &_entry) { tasks.Push(_entry); } + void Add(TaskEntry &_entry) { tasks.Push(_entry); } /* Virtual methods */ diff --git a/Terminal.define.h b/Terminal.define.h index a316eea43..fd66662aa 100644 --- a/Terminal.define.h +++ b/Terminal.define.h @@ -37,6 +37,8 @@ #define CP_UTF7 65000 // UTF-7 code page. #define CP_UTF8 65001 // UTF-8 code page. +#ifndef __MQL__ + // Colors. #define clrAliceBlue 0x00F0F8FF #define clrAntiqueWhite 0x00FAEBD7 @@ -304,6 +306,8 @@ #define Yellow clrYellow #define YellowGreen clrYellowGreen +#endif + #ifndef __MQL__ #define clrNONE -1 #define CLR_NONE -1 diff --git a/Terminal.mqh b/Terminal.mqh index 6c5116679..3fe1a77b0 100644 --- a/Terminal.mqh +++ b/Terminal.mqh @@ -934,36 +934,34 @@ class Terminal : public Object { string ToString() override { string _sep = "; "; return StringFormat("Allow DLL: %s", IsDllsAllowed() ? "Yes" : "No") + _sep + - StringFormat("Allow Libraries: %s", IsLibrariesAllowed() ? "Yes" : "No") + _sep + - StringFormat("CPUs: %d", GetCpuCores()) + _sep + - // StringFormat("Community account: %s", (string)HasCommunityAccount()) + _sep + - // StringFormat("Community balance: %.2f", GetCommunityBalance()) + _sep + - // StringFormat("Community connection: %s", (string)IsCommunityConnected()) + _sep + - StringFormat("Disk space: %d", GetDiskSpace()) + _sep + - StringFormat("Enabled FTP: %s", IsFtpEnabled() ? "Yes" : "No") + _sep + - StringFormat("Enabled e-mail: %s", IsEmailEnabled() ? "Yes" : "No") + _sep + - // StringFormat("Enabled notifications: %s", (string)IsNotificationsEnabled()) + _sep + - StringFormat("IsOptimization: %s", IsOptimization() ? "Yes" : "No") + _sep + - StringFormat("IsRealtime: %s", IsRealtime() ? "Yes" : "No") + _sep + - StringFormat("IsTesting: %s", IsTesting() ? "Yes" : "No") + _sep + - StringFormat("IsVisual: %s", IsVisualMode() ? "Yes" : "No") + _sep + - // StringFormat("MQ ID: %s", (string)HasMetaQuotesId()) + _sep + - StringFormat("Memory (free): %d", GetFreeMemory()) + _sep + - StringFormat("Memory (physical): %d", GetPhysicalMemory()) + _sep + - StringFormat("Memory (total): %d", GetTotalMemory()) + _sep + - StringFormat("Memory (used): %d", GetUsedMemory()) + _sep + "Path (Common): " + GetCommonPath() + _sep + - "Path (Data): " + GetDataPath() + _sep + "Path (Expert): " + GetExpertPath() + _sep + - "Path (Terminal): ", - GetTerminalPath() + _sep + "Program name: ", - WindowExpertName() + _sep + StringFormat("Screen DPI: %d", GetScreenDpi()) + _sep + - StringFormat("Terminal build: %d", GetBuild()) + _sep + - "Terminal code page: " + IntegerToString(GetCodePage()) + _sep + "Terminal company: " + GetCompany() + - _sep + "Terminal connected: " + (IsConnected() ? "Yes" : "No") + _sep + - "Terminal language: " + GetLanguage() + _sep + "Terminal name: " + GetName() + _sep + - StringFormat("Termnal max bars: %d", GetMaxBars()) + _sep + - "Trade allowed: " + (IsTradeAllowed() ? "Yes" : "No") + _sep + - "Trade context busy: " + (IsTradeContextBusy() ? "Yes" : "No") + _sep + "Trade perm: %s" + - (CheckPermissionToTrade() ? "Yes" : "No") + _sep + StringFormat("Trade ping (last): %d", GetPingLast()); + StringFormat("Allow Libraries: %s", IsLibrariesAllowed() ? "Yes" : "No") + _sep + + StringFormat("CPUs: %d", GetCpuCores()) + _sep + + // StringFormat("Community account: %s", (string)HasCommunityAccount()) + _sep + + // StringFormat("Community balance: %.2f", GetCommunityBalance()) + _sep + + // StringFormat("Community connection: %s", (string)IsCommunityConnected()) + _sep + + StringFormat("Disk space: %d", GetDiskSpace()) + _sep + + StringFormat("Enabled FTP: %s", IsFtpEnabled() ? "Yes" : "No") + _sep + + StringFormat("Enabled e-mail: %s", IsEmailEnabled() ? "Yes" : "No") + _sep + + // StringFormat("Enabled notifications: %s", (string)IsNotificationsEnabled()) + _sep + + StringFormat("IsOptimization: %s", IsOptimization() ? "Yes" : "No") + _sep + + StringFormat("IsRealtime: %s", IsRealtime() ? "Yes" : "No") + _sep + + StringFormat("IsTesting: %s", IsTesting() ? "Yes" : "No") + _sep + + StringFormat("IsVisual: %s", IsVisualMode() ? "Yes" : "No") + _sep + + // StringFormat("MQ ID: %s", (string)HasMetaQuotesId()) + _sep + + StringFormat("Memory (free): %d", GetFreeMemory()) + _sep + + StringFormat("Memory (physical): %d", GetPhysicalMemory()) + _sep + + StringFormat("Memory (total): %d", GetTotalMemory()) + _sep + + StringFormat("Memory (used): %d", GetUsedMemory()) + _sep + "Path (Common): " + GetCommonPath() + _sep + + "Path (Data): " + GetDataPath() + _sep + "Path (Expert): " + GetExpertPath() + _sep + + "Path (Terminal): " + GetTerminalPath() + _sep + "Program name: " + WindowExpertName() + _sep + + StringFormat("Screen DPI: %d", GetScreenDpi()) + _sep + StringFormat("Terminal build: %d", GetBuild()) + + _sep + "Terminal code page: " + IntegerToString(GetCodePage()) + _sep + "Terminal company: " + GetCompany() + + _sep + "Terminal connected: " + (IsConnected() ? "Yes" : "No") + _sep + + "Terminal language: " + GetLanguage() + _sep + "Terminal name: " + GetName() + _sep + + StringFormat("Termnal max bars: %d", GetMaxBars()) + _sep + + "Trade allowed: " + (IsTradeAllowed() ? "Yes" : "No") + _sep + + "Trade context busy: " + (IsTradeContextBusy() ? "Yes" : "No") + _sep + "Trade perm: %s" + + (CheckPermissionToTrade() ? "Yes" : "No") + _sep + StringFormat("Trade ping (last): %d", GetPingLast()); } }; diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 9b0622bf2..71f08dcf8 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -71,6 +71,7 @@ struct TickTAB : TickAB { // Struct constructors. TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : TickAB(_ask, _bid), time_ms(_time_ms) {} TickTAB(MqlTick &_tick) : TickAB(_tick), time_ms(_tick.time_msc) {} + TickTAB(const TickTAB &r) { THIS_REF = r; } /** * Method used by ItemsHistory. diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 1b96d9b5c..b1fc5c575 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -164,29 +164,29 @@ bool InitIndicators() { /* Standard indicators */ // AC. - indis.Push(new Indi_AC()); + indis.Push(Ref(new Indi_AC())); // AD. - indis.Push(new Indi_AD()); + indis.Push(Ref(new Indi_AD())); // ADX. IndiADXParams adx_params(14); - indis.Push(new Indi_ADX(adx_params)); + indis.Push(Ref(new Indi_ADX(adx_params))); // Alligator. IndiAlligatorParams alli_params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - indis.Push(new Indi_Alligator(alli_params)); + indis.Push(Ref(new Indi_Alligator(alli_params))); // Awesome Oscillator (AO). - indis.Push(new Indi_AO()); + indis.Push(Ref(new Indi_AO())); // Accumulation Swing Index (ASI). IndiASIParams _asi_params; - indis.Push(new Indi_ASI(_asi_params)); + indis.Push(Ref(new Indi_ASI(_asi_params))); // Average True Range (ATR). IndiATRParams atr_params(14); - indis.Push(new Indi_ATR(atr_params)); + indis.Push(Ref(new Indi_ATR(atr_params))); // Bollinger Bands - Built-in. IndiBandsParams bands_params(20, 2, 0, PRICE_OPEN); @@ -201,50 +201,50 @@ bool InitIndicators() { // Bears Power. IndiBearsPowerParams bears_params(13, PRICE_CLOSE); - indis.Push(new Indi_BearsPower(bears_params)); + indis.Push(Ref(new Indi_BearsPower(bears_params))); // Bulls Power. IndiBullsPowerParams bulls_params(13, PRICE_CLOSE); - indis.Push(new Indi_BullsPower(bulls_params)); + indis.Push(Ref(new Indi_BullsPower(bulls_params))); // Market Facilitation Index (BWMFI). IndiBWIndiMFIParams _bwmfi_params(1); - indis.Push(new Indi_BWMFI(_bwmfi_params)); + indis.Push(Ref(new Indi_BWMFI(_bwmfi_params))); // Commodity Channel Index (CCI). IndiCCIParams cci_params(14, PRICE_OPEN); - indis.Push(new Indi_CCI(cci_params)); + indis.Push(Ref(new Indi_CCI(cci_params))); // DeMarker. IndiDeMarkerParams dm_params(14); - indis.Push(new Indi_DeMarker(dm_params)); + indis.Push(Ref(new Indi_DeMarker(dm_params))); // Envelopes. IndiEnvelopesParams env_params(13, 0, MODE_SMA, PRICE_OPEN, 2); - indis.Push(new Indi_Envelopes(env_params)); + indis.Push(Ref(new Indi_Envelopes(env_params))); // Force Index. IndiForceParams force_params(13, MODE_SMA, PRICE_CLOSE); - indis.Push(new Indi_Force(force_params)); + indis.Push(Ref(new Indi_Force(force_params))); // Fractals. - indis.Push(new Indi_Fractals()); + indis.Push(Ref(new Indi_Fractals())); // Fractal Adaptive Moving Average (FRAMA). IndiFrAIndiMAParams frama_params(); - indis.Push(new Indi_FrAMA(frama_params)); + indis.Push(Ref(new Indi_FrAMA(frama_params))); // Gator Oscillator. IndiGatorParams gator_params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - indis.Push(new Indi_Gator(gator_params)); + indis.Push(Ref(new Indi_Gator(gator_params))); // Heiken Ashi. IndiHeikenAshiParams _ha_params(); - indis.Push(new Indi_HeikenAshi(_ha_params)); + indis.Push(Ref(new Indi_HeikenAshi(_ha_params))); // Ichimoku Kinko Hyo. IndiIchimokuParams ichi_params(9, 26, 52); - indis.Push(new Indi_Ichimoku(ichi_params)); + indis.Push(Ref(new Indi_Ichimoku(ichi_params))); // Moving Average. IndiMAParams ma_params(13, 0, MODE_SMA, PRICE_OPEN); @@ -263,23 +263,23 @@ bool InitIndicators() { // Money Flow Index (MFI). IndiMFIParams mfi_params(14); - indis.Push(new Indi_MFI(mfi_params)); + indis.Push(Ref(new Indi_MFI(mfi_params))); // Momentum (MOM). IndiMomentumParams mom_params(); - indis.Push(new Indi_Momentum(mom_params)); + indis.Push(Ref(new Indi_Momentum(mom_params))); // On Balance Volume (OBV). - indis.Push(new Indi_OBV()); + indis.Push(Ref(new Indi_OBV())); // OsMA. IndiOsMAParams osma_params(12, 26, 9, PRICE_CLOSE); - indis.Push(new Indi_OsMA(osma_params)); + indis.Push(Ref(new Indi_OsMA(osma_params))); // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); Ref indi_rsi = new Indi_RSI(rsi_params); - indis.Push(indi_rsi.Ptr()); + indis.Push(Ref(indi_rsi.Ptr())); // Bollinger Bands over RSI. IndiBandsParams indi_bands_over_rsi_params(20, 2, 0, PRICE_OPEN); @@ -302,11 +302,11 @@ bool InitIndicators() { // Relative Vigor Index (RVI). IndiRVIParams rvi_params(14); - indis.Push(new Indi_RVI(rvi_params)); + indis.Push(Ref(new Indi_RVI(rvi_params))); // Parabolic SAR. IndiSARParams sar_params(0.02, 0.2); - indis.Push(new Indi_SAR(sar_params)); + indis.Push(Ref(new Indi_SAR(sar_params))); // Standard Deviation (StdDev). Ref indi_price_for_stdev = new Indi_Price(PriceIndiParams()); @@ -314,24 +314,24 @@ bool InitIndicators() { // stddev_on_price_params.SetDraw(clrBlue, 1); // @fixme Ref indi_stddev_on_price = new Indi_StdDev(stddev_on_price_params, IDATA_BUILTIN, indi_price_for_stdev.Ptr()); - indis.Push(indi_stddev_on_price.Ptr()); + indis.Push(Ref(indi_stddev_on_price.Ptr())); // Stochastic Oscillator. IndiStochParams stoch_params(5, 3, 3, MODE_SMMA, STO_LOWHIGH); - indis.Push(new Indi_Stochastic(stoch_params)); + indis.Push(Ref(new Indi_Stochastic(stoch_params))); // Williams' Percent Range (WPR). IndiWPRParams wpr_params(14); - indis.Push(new Indi_WPR(wpr_params)); + indis.Push(Ref(new Indi_WPR(wpr_params))); // ZigZag. IndiZigZagParams zz_params(12, 5, 3); - indis.Push(new Indi_ZigZag(zz_params)); + indis.Push(Ref(new Indi_ZigZag(zz_params))); /* Special indicators */ // Demo/Dummy Indicator. - indis.Push(new Indi_Demo()); + indis.Push(Ref(new Indi_Demo())); // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); @@ -339,7 +339,7 @@ bool InitIndicators() { IndiBandsParams bands_on_price_params(); // bands_on_price_params.SetDraw(clrCadetBlue); // @fixme Ref indi_bands_on_price = new Indi_Bands(bands_on_price_params, IDATA_BUILTIN, indi_price_4_bands.Ptr()); - indis.Push(indi_bands_on_price.Ptr()); + indis.Push(Ref(indi_bands_on_price.Ptr())); // Standard Deviation (StdDev) over MA(SMA). // NOTE: If you set ma_shift parameter for MA, then StdDev will no longer @@ -352,7 +352,7 @@ bool InitIndicators() { Ref indi_stddev_on_ma_sma = new Indi_StdDev(stddev_params_on_ma_sma, IDATA_BUILTIN, indi_ma_sma_for_stddev.Ptr()); - indis.Push(indi_stddev_on_ma_sma.Ptr()); + indis.Push(Ref(indi_stddev_on_ma_sma.Ptr())); // Standard Deviation (StdDev) in SMA mode over Price. PriceIndiParams price_params_for_stddev_sma(); @@ -361,7 +361,7 @@ bool InitIndicators() { // stddev_sma_on_price_params.SetDraw(true, 1); // @fixme Ref indi_stddev_on_sma = new Indi_StdDev(stddev_sma_on_price_params, IDATA_BUILTIN, indi_price_for_stddev_sma.Ptr()); - indis.Push(indi_stddev_on_sma.Ptr()); + indis.Push(Ref(indi_stddev_on_sma.Ptr())); // Moving Average (MA) over Price indicator. PriceIndiParams price_params_4_ma(); @@ -370,7 +370,7 @@ bool InitIndicators() { // ma_on_price_params.SetDraw(clrYellowGreen); // @fixme ma_on_price_params.SetIndicatorType(INDI_MA_ON_PRICE); Ref indi_ma_on_price = new Indi_MA(ma_on_price_params, IDATA_BUILTIN, indi_price_4_ma.Ptr()); - indis.Push(indi_ma_on_price.Ptr()); + indis.Push(Ref(indi_ma_on_price.Ptr())); // Commodity Channel Index (CCI) over Price indicator. PriceIndiParams price_params_4_cci(); @@ -378,7 +378,7 @@ bool InitIndicators() { IndiCCIParams cci_on_price_params(); // cci_on_price_params.SetDraw(clrYellowGreen, 1); // @fixme Ref indi_cci_on_price = new Indi_CCI(cci_on_price_params, IDATA_BUILTIN, indi_price_4_cci.Ptr()); - indis.Push(indi_cci_on_price.Ptr()); + indis.Push(Ref(indi_cci_on_price.Ptr())); // Envelopes over Price indicator. PriceIndiParams price_params_4_envelopes(); @@ -387,7 +387,7 @@ bool InitIndicators() { // env_on_price_params.SetDraw(clrBrown); // @fixme Ref indi_envelopes_on_price = new Indi_Envelopes(env_on_price_params, IDATA_BUILTIN, indi_price_4_envelopes.Ptr()); - indis.Push(indi_envelopes_on_price.Ptr()); + indis.Push(Ref(indi_envelopes_on_price.Ptr())); // DEMA over Price indicator. PriceIndiParams price_params_4_dema(); @@ -404,7 +404,7 @@ bool InitIndicators() { // mom_on_price_params.SetDraw(clrDarkCyan); // @fixme Ref indi_momentum_on_price = new Indi_Momentum(mom_on_price_params, IDATA_BUILTIN, indi_price_4_momentum.Ptr()); - indis.Push(indi_momentum_on_price.Ptr()); + indis.Push(Ref(indi_momentum_on_price.Ptr())); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); @@ -412,13 +412,13 @@ bool InitIndicators() { IndiRSIParams rsi_on_price_params(); // rsi_on_price_params.SetDraw(clrBisque, 1); // @fixme Ref indi_rsi_on_price = new Indi_RSI(rsi_on_price_params, IDATA_BUILTIN, indi_price_4_rsi.Ptr()); - indis.Push(indi_rsi_on_price.Ptr()); + indis.Push(Ref(indi_rsi_on_price.Ptr())); // Drawer (socket-based) indicator over RSI over Price. IndiDrawerParams drawer_params(14, PRICE_OPEN); // drawer_params.SetDraw(clrBisque, 0); // @fixme Ref indi_drawer_on_rsi = new Indi_Drawer(drawer_params, IDATA_BUILTIN, indi_rsi_on_price.Ptr()); - indis.Push(indi_drawer_on_rsi.Ptr()); + indis.Push(Ref(indi_drawer_on_rsi.Ptr())); // Applied Price over OHCL indicator. IndiAppliedPriceParams applied_price_params(); @@ -426,11 +426,11 @@ bool InitIndicators() { IndiOHLCParams applied_price_ohlc_params(PRICE_TYPICAL); Ref indi_applied_price_on_price = new Indi_AppliedPrice(applied_price_params, IDATA_INDICATOR, new Indi_OHLC(applied_price_ohlc_params)); - indis.Push(indi_applied_price_on_price.Ptr()); + indis.Push(Ref(indi_applied_price_on_price.Ptr())); // ADXW. IndiADXWParams adxw_params(14); - indis.Push(new Indi_ADXW(adxw_params)); + indis.Push(Ref(new Indi_ADXW(adxw_params))); // AMA. IndiAMAParams ama_params(); @@ -438,126 +438,126 @@ bool InitIndicators() { // However, in that case we need to specifiy applied price (excluding ASK and BID). Indi_AMA* _indi_ama = new Indi_AMA(ama_params, IDATA_INDICATOR); _indi_ama.SetAppliedPrice(PRICE_OPEN); - indis.Push(_indi_ama); + indis.Push(Ref(_indi_ama)); // Original AMA. IndiAMAParams ama_params_orig(); ama_params_orig.SetName("Original AMA to compare"); - indis.Push(new Indi_AMA(ama_params_orig)); + indis.Push(Ref(new Indi_AMA(ama_params_orig))); // Chaikin Oscillator. IndiCHOParams cho_params(); - indis.Push(new Indi_CHO(cho_params)); + indis.Push(Ref(new Indi_CHO(cho_params))); // Chaikin Volatility. IndiCHVParams chv_params(); - indis.Push(new Indi_CHV(chv_params)); + indis.Push(Ref(new Indi_CHV(chv_params))); // Color Bars. IndiColorBarsParams color_bars_params(); - indis.Push(new Indi_ColorBars(color_bars_params)); + indis.Push(Ref(new Indi_ColorBars(color_bars_params))); // Color Candles Daily. IndiColorCandlesDailyParams color_candles_daily_params(); - indis.Push(new Indi_ColorCandlesDaily(color_candles_daily_params)); + indis.Push(Ref(new Indi_ColorCandlesDaily(color_candles_daily_params))); // Color Line. IndiColorLineParams color_line_params(); - indis.Push(new Indi_ColorLine(color_line_params)); + indis.Push(Ref(new Indi_ColorLine(color_line_params))); // Detrended Price Oscillator. IndiDetrendedPriceParams detrended_params(); - indis.Push(new Indi_DetrendedPrice(detrended_params)); + indis.Push(Ref(new Indi_DetrendedPrice(detrended_params))); // Mass Index. IndiMassIndexParams mass_index_params(); - indis.Push(new Indi_MassIndex(mass_index_params)); + indis.Push(Ref(new Indi_MassIndex(mass_index_params))); // OHLC. IndiOHLCParams ohlc_params(); - indis.Push(new Indi_OHLC(ohlc_params)); + indis.Push(Ref(new Indi_OHLC(ohlc_params))); // Price Channel. IndiPriceChannelParams price_channel_params(); - indis.Push(new Indi_PriceChannel(price_channel_params)); + indis.Push(Ref(new Indi_PriceChannel(price_channel_params))); // Price Volume Trend. IndiPriceVolumeTrendParams price_volume_trend_params(); - indis.Push(new Indi_PriceVolumeTrend(price_volume_trend_params)); + indis.Push(Ref(new Indi_PriceVolumeTrend(price_volume_trend_params))); // Bill Williams' Zone Trade. IndiBWZTParams bwzt_params(); - indis.Push(new Indi_BWZT(bwzt_params)); + indis.Push(Ref(new Indi_BWZT(bwzt_params))); // Rate of Change. IndiRateOfChangeParams rate_of_change_params(); - indis.Push(new Indi_RateOfChange(rate_of_change_params)); + indis.Push(Ref(new Indi_RateOfChange(rate_of_change_params))); // Triple Exponential Moving Average. IndiTEMAParams tema_params(); - indis.Push(new Indi_TEMA(tema_params)); + indis.Push(Ref(new Indi_TEMA(tema_params))); // Triple Exponential Average. IndiTRIXParams trix_params(); - indis.Push(new Indi_TRIX(trix_params)); + indis.Push(Ref(new Indi_TRIX(trix_params))); // Ultimate Oscillator. IndiUltimateOscillatorParams ultimate_oscillator_params(); - indis.Push(new Indi_UltimateOscillator(ultimate_oscillator_params)); + indis.Push(Ref(new Indi_UltimateOscillator(ultimate_oscillator_params))); // VIDYA. IndiVIDYAParams vidya_params(); - indis.Push(new Indi_VIDYA(vidya_params)); + indis.Push(Ref(new Indi_VIDYA(vidya_params))); // Volumes. IndiVolumesParams volumes_params(); - indis.Push(new Indi_Volumes(volumes_params)); + indis.Push(Ref(new Indi_Volumes(volumes_params))); // Volume Rate of Change. IndiVROCParams vol_rate_of_change_params(); - indis.Push(new Indi_VROC(vol_rate_of_change_params)); + indis.Push(Ref(new Indi_VROC(vol_rate_of_change_params))); // Larry Williams' Accumulation/Distribution. IndiWilliamsADParams williams_ad_params(); - indis.Push(new Indi_WilliamsAD(williams_ad_params)); + indis.Push(Ref(new Indi_WilliamsAD(williams_ad_params))); // ZigZag Color. IndiZigZagColorParams zigzag_color_params(); - indis.Push(new Indi_ZigZagColor(zigzag_color_params)); + indis.Push(Ref(new Indi_ZigZagColor(zigzag_color_params))); // Custom Moving Average. IndiCustomMovingAverageParams cma_params(); - indis.Push(new Indi_CustomMovingAverage(cma_params)); + indis.Push(Ref(new Indi_CustomMovingAverage(cma_params))); // Math (specialized indicator). IndiMathParams math_params(MATH_OP_SUB, BAND_UPPER, BAND_LOWER, 0, 0); // math_params.SetDraw(clrBlue); // @fixme math_params.SetName("Bands(UP - LO)"); Ref indi_math_1 = new Indi_Math(math_params, IDATA_INDICATOR, indi_bands.Ptr()); - indis.Push(indi_math_1.Ptr()); + indis.Push(Ref(indi_math_1.Ptr())); // Math (specialized indicator) via custom math method. IndiMathParams math_custom_params(MathCustomOp, BAND_UPPER, BAND_LOWER, 0, 0); // math_custom_params.SetDraw(clrBeige); // @fixme math_custom_params.SetName("Bands(Custom math fn)"); Ref indi_math_2 = new Indi_Math(math_custom_params, IDATA_INDICATOR, indi_bands.Ptr()); - indis.Push(indi_math_2.Ptr()); + indis.Push(Ref(indi_math_2.Ptr())); // RS (Math-based) indicator. IndiRSParams rs_params(); - indis.Push(new Indi_RS(rs_params)); + indis.Push(Ref(new Indi_RS(rs_params))); // Pattern Detector. IndiPatternParams pattern_params(); - indis.Push(new Indi_Pattern(pattern_params)); + indis.Push(Ref(new Indi_Pattern(pattern_params))); // Pivot. IndiPivotParams pivot_params(); - indis.Push(new Indi_Pivot(pivot_params)); + indis.Push(Ref(new Indi_Pivot(pivot_params))); // Candle Pattern Detector. CandleParams candle_params(); - indis.Push(new Indi_Candle(candle_params)); + indis.Push(Ref(new Indi_Candle(candle_params))); // Push white-listed indicators here. // whitelisted_indis.Push(_indi_test); @@ -592,7 +592,7 @@ bool PrintIndicators(string _prefix = "") { continue; } if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString(0)); + PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString()); } } return GetLastError() == ERR_NO_ERROR; From 88108ce6edc52215612c3e0995163cf64d799d3d Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Sat, 28 Jan 2023 00:04:09 +0100 Subject: [PATCH 12/42] WIP. Fixing MT5 tests. --- Database.mqh | 28 +++++++++++++++++++++------- DictSlot.mqh | 4 ++++ Draw.mqh | 3 ++- Market.struct.h | 1 + Matrix.mqh | 2 +- Order.enum.h | 2 ++ Order.mqh | 10 +++++----- PlatformTime.h | 1 - Task/TaskManager.h | 6 +++++- tests/EATest.mq5 | 1 + tests/OrderTest.mq5 | 2 +- tests/RefsTest.mq5 | 33 +++++++++++++++++---------------- tests/TerminalTest.mq5 | 4 ++-- 13 files changed, 62 insertions(+), 35 deletions(-) diff --git a/Database.mqh b/Database.mqh index 078949f49..2a4bcc82b 100644 --- a/Database.mqh +++ b/Database.mqh @@ -74,6 +74,21 @@ struct DatabaseTableColumnEntry { // State methods. bool IsKey() { return bool(flags & DATABASE_COLUMN_FLAG_IS_KEY); } bool IsNull() { return bool(flags & DATABASE_COLUMN_FLAG_IS_NULL); } + + DatabaseTableColumnEntry() {} + DatabaseTableColumnEntry(const string _name, const ENUM_DATATYPE _type, unsigned short _flags = 0, + unsigned short _char_size = 0) { + name = _name; + type = _type; + flags = _flags; + char_size = _char_size; + } + DatabaseTableColumnEntry(const DatabaseTableColumnEntry &r) { + name = r.name; + type = r.type; + flags = r.flags; + char_size = r.char_size; + } }; struct DatabaseTableSchema { DictStruct columns; @@ -84,6 +99,7 @@ struct DatabaseTableSchema { columns.Push(_columns[i]); } } + DatabaseTableSchema(const DatabaseTableSchema &r) { columns = r.columns; } // Methods. bool AddColumn(DatabaseTableColumnEntry &column) { return columns.Push(column); } }; @@ -98,13 +114,11 @@ struct DbSymbolInfoEntry : public SymbolInfoEntry { } // Methods. void DefineSchema() { - DatabaseTableColumnEntry _columns[] = { - {"bid", TYPE_DOUBLE}, {"ask", TYPE_DOUBLE}, {"last", TYPE_DOUBLE}, - {"spread", TYPE_DOUBLE}, {"volume", TYPE_INT}, - }; - for (int i = 0; i < ArraySize(_columns); i++) { - schema.columns.Push(_columns[i]); - } + schema.columns.Push(DatabaseTableColumnEntry("bid", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("ask", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("last", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("spread", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("volume", TYPE_INT)); } }; #endif diff --git a/DictSlot.mqh b/DictSlot.mqh index 07b42fbf2..3752244c9 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,7 +40,11 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} +#ifdef __MQL__ + DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} +#else DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key) { value = r.value; } +#endif bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } diff --git a/Draw.mqh b/Draw.mqh index 5cea3f3ee..0e637d088 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -33,6 +33,7 @@ class Draw; #include "Data.define.h" #include "Object.extern.h" //#include "Platform.h" +#include "Object.mqh" #include "Terminal.define.h" #ifndef __MQL4__ @@ -72,7 +73,7 @@ class Draw : public Object { /** * Class constructor. */ - Draw(long _chart_id = 0) : chart_id(_chart_id != 0 ? _chart_id : Platform::ChartID()) {} + Draw(long _chart_id = 0) : chart_id(_chart_id != 0 ? _chart_id : ::ChartID()) {} /* Graphic object related methods */ diff --git a/Market.struct.h b/Market.struct.h index 1283ce193..f7233b5ec 100644 --- a/Market.struct.h +++ b/Market.struct.h @@ -29,6 +29,7 @@ class Serializer; // Includes. +#include "DateTime.entry.h" #include "DateTime.struct.h" #include "Serializer/SerializerNode.enum.h" #include "Std.h" diff --git a/Matrix.mqh b/Matrix.mqh index 5fdbc3e0f..cb030c1fe 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -229,7 +229,7 @@ class MatrixDimension { int position[MATRIX_DIMENSIONS - 1]; // Containers array if type is "Containers" - ARRAY(MatrixDimension, containers); + ARRAY(MatrixDimension*, containers); /** * Constructor. diff --git a/Order.enum.h b/Order.enum.h index c466d638a..d9e9f3a20 100644 --- a/Order.enum.h +++ b/Order.enum.h @@ -246,6 +246,8 @@ enum ENUM_ORDER_TYPE { ORDER_TYPE_CLOSE_BY, // Order to close a position by an opposite one. ORDER_TYPE_UNSET // A NULL value. }; +#else +#define ORDER_TYPE_UNSET NULL #endif /* Positions */ diff --git a/Order.mqh b/Order.mqh index 7ecefc664..fed44822a 100644 --- a/Order.mqh +++ b/Order.mqh @@ -307,7 +307,7 @@ class Order : public SymbolInfo { ENUM_ORDER_CONDITION _cond = oparams.Get(ORDER_PARAM_COND_CLOSE, _ci); ARRAY(DataParamEntry, _cond_args); DataParamEntry _item0 = oparams.Get(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _ci); - ArrayPush(_cond_args, _item0); + ArrayPushObject(_cond_args, _item0); _result |= Order::CheckCondition(_cond, _cond_args); } } @@ -2478,7 +2478,7 @@ class Order : public SymbolInfo { case ORDER_TIME_SETUP: return OrderGetValue(DEAL_TIME, _type, _out); case ORDER_TYPE: - switch (OrderGetValue(DEAL_TYPE, _type, _long)) { + switch ((int)OrderGetValue(DEAL_TYPE, _type, _long)) { case DEAL_TYPE_BUY: return ConvertBasic::LongTo(ORDER_TYPE_BUY); case DEAL_TYPE_SELL: @@ -2512,7 +2512,7 @@ class Order : public SymbolInfo { return NULL_VALUE; default: if ((int)_prop_id == (int)ORDER_REASON) { - switch (OrderGetValue(DEAL_REASON, _type, _long)) { + switch ((int)OrderGetValue(DEAL_REASON, _type, _long)) { case DEAL_REASON_CLIENT: return ConvertBasic::LongTo(ORDER_REASON_CLIENT); case DEAL_REASON_MOBILE: @@ -2576,7 +2576,7 @@ class Order : public SymbolInfo { case ORDER_TIME_SETUP: return OrderGetValue(POSITION_TIME, _type, _out); case ORDER_TYPE: - switch (OrderGetValue(POSITION_TYPE, _type, _long)) { + switch ((int)OrderGetValue(POSITION_TYPE, _type, _long)) { case POSITION_TYPE_BUY: return ConvertBasic::LongTo(ORDER_TYPE_BUY); case POSITION_TYPE_SELL: @@ -2610,7 +2610,7 @@ class Order : public SymbolInfo { return NULL_VALUE; default: if ((int)_prop_id == (int)ORDER_REASON) { - switch (OrderGetValue(POSITION_REASON, _type, _long)) { + switch ((int)OrderGetValue(POSITION_REASON, _type, _long)) { case POSITION_REASON_CLIENT: return ConvertBasic::LongTo(ORDER_REASON_CLIENT); case POSITION_REASON_MOBILE: diff --git a/PlatformTime.h b/PlatformTime.h index 89cb39527..6b54aeffb 100644 --- a/PlatformTime.h +++ b/PlatformTime.h @@ -22,7 +22,6 @@ // Includes. #include "DateTime.enum.h" -#include "DateTime.mqh" /** * @file diff --git a/Task/TaskManager.h b/Task/TaskManager.h index d9a7fc0e7..8fa594a38 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -97,15 +97,19 @@ class TaskManager { void Clear() { Task *task0 = tasks[0].Ptr(); - for (int i = 0; i < tasks.Size(); ++i) { +#ifndef __MQL__ + for (unsigned int i = 0; i < tasks.Size(); ++i) { std::cout << "Task #" << i << ": " << tasks[i].ToString() << std::endl; } +#endif tasks.Clear(); +#ifndef __MQL__ std::cout << "Tasks cleared." << std::endl; std::cout << task0 PTR_DEREF ToString() << std::endl; // std::cout.flush(); +#endif } /* Processing methods */ diff --git a/tests/EATest.mq5 b/tests/EATest.mq5 index 96eb8238f..5f97929b5 100644 --- a/tests/EATest.mq5 +++ b/tests/EATest.mq5 @@ -28,6 +28,7 @@ struct DataParamEntry; // Includes. +#include "../Account/Account.struct.h" #include "../EA.mqh" #include "../Test.mqh" diff --git a/tests/OrderTest.mq5 b/tests/OrderTest.mq5 index 343adc249..7a0fc2dae 100644 --- a/tests/OrderTest.mq5 +++ b/tests/OrderTest.mq5 @@ -113,7 +113,7 @@ bool OpenOrder(int _index, int _order_no) { OrderParams _oparams; if (_request.type == ORDER_TYPE_SELL) { ARRAY(DataParamEntry, _cond_args); - DataParamEntry _param1 = ORDER_TYPE_TIME; + DataParamEntry _param1 = (int)ORDER_TYPE_TIME; DataParamEntry _param2 = PeriodSeconds() * (MAX_ORDERS + _index); ArrayPushObject(_cond_args, _param1); ArrayPushObject(_cond_args, _param2); diff --git a/tests/RefsTest.mq5 b/tests/RefsTest.mq5 index c3a38c88b..8f0b0cf9e 100644 --- a/tests/RefsTest.mq5 +++ b/tests/RefsTest.mq5 @@ -39,6 +39,7 @@ class DynamicClass : public Dynamic { int number; DynamicClass(int _number, DynamicClass* _parent = NULL) : number(_number), parent(_parent) {} + DynamicClass(const DynamicClass& r) { THIS_REF = r; } }; /** @@ -57,7 +58,6 @@ class BadDynamicClass : public Dynamic { */ int OnInit() { // Weak references only. - WeakRef dyn1 = new DynamicClass(1); assertTrueOrFail(dyn1.ObjectExists(), "Object should exist"); @@ -137,25 +137,26 @@ int OnInit() { // Dictionary of weak references. DictStruct> refs2; + /* - Ref dyn9_1 = new DynamicClass(1); - Ref dyn9_2 = new DynamicClass(2); - Ref dyn9_3 = new DynamicClass(3); - - WeakRef dyn9_1_weak_ref = dyn9_1; - WeakRef dyn9_2_weak_ref = dyn9_2; - WeakRef dyn9_3_weak_ref = dyn9_3; + Ref dyn9_1 = new DynamicClass(1); + Ref dyn9_2 = new DynamicClass(2); + Ref dyn9_3 = new DynamicClass(3); - refs2.Set("1", dyn9_1_weak_ref); - refs2.Set("2", dyn9_2_weak_ref); - refs2.Set("3", dyn9_3_weak_ref); + WeakRef dyn9_1_weak_ref = dyn9_1; + WeakRef dyn9_2_weak_ref = dyn9_2; + WeakRef dyn9_3_weak_ref = dyn9_3; - // Should make refs2["2"] to have no existing object. - dyn9_2 = NULL; + refs2.Set("1", dyn9_1_weak_ref); + refs2.Set("2", dyn9_2_weak_ref); + refs2.Set("3", dyn9_3_weak_ref); - assertTrueOrFail(refs2.GetByKey("1").ObjectExists(), "Object should exists"); - assertTrueOrFail(!refs2.GetByKey("2").ObjectExists(), "Object should not exists as it has no more strong references"); - assertTrueOrFail(refs2.GetByKey("3").ObjectExists(), "Object should exists"); + // Should make refs2["2"] to have no existing object. + dyn9_2 = NULL; + assertTrueOrFail(refs2.GetByKey("1").ObjectExists(), "Object should exists"); + assertTrueOrFail(!refs2.GetByKey("2").ObjectExists(), "Object should not exists as it has no more strong + references"); assertTrueOrFail(refs2.GetByKey("3").ObjectExists(), "Object should exists"); + */ return INIT_SUCCEEDED; } diff --git a/tests/TerminalTest.mq5 b/tests/TerminalTest.mq5 index 3c9fe2441..6373e7413 100644 --- a/tests/TerminalTest.mq5 +++ b/tests/TerminalTest.mq5 @@ -37,7 +37,7 @@ Terminal *terminal; */ int OnInit() { terminal = new Terminal(); - Print("TERMINAL (OnInit):\n\t\t\t", terminal.ToString("\n\t\t\t")); + Print("TERMINAL (OnInit):\n\t\t\t", terminal.ToString()); assertTrueOrFail(terminal.IsDllsAllowed(), "DLLs not allowed!"); assertTrueOrFail(terminal.IsExpertEnabled(), "Expert Advisors not allowed!"); assertTrueOrFail(terminal.IsLibrariesAllowed(), "Libraries not allowed!"); @@ -73,6 +73,6 @@ int OnInit() { * Implements OnDeinit(). */ void OnDeinit(const int reason) { - Print("TERMINAL (OnDeinit):\n\t\t\t", terminal.ToString("\n\t\t\t")); + Print("TERMINAL (OnDeinit):\n\t\t\t", terminal.ToString()); Object::Delete(terminal); } From 17cd38a13f3c5500cadff3ea86a6e1904eb2972f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 2 Feb 2023 16:16:16 +0100 Subject: [PATCH 13/42] Fixed C++ and MQL5 errors for tests in /tests folder. --- 3D/Chart3DCandles.h | 1 + 3D/Mesh.h | 5 +++++ 3D/Vertex.h | 17 ++++++++++++----- Account/Account.struct.h | 15 +++++++++++++++ BufferFXT.mqh | 14 ++++++++++++++ BufferStruct.mqh | 2 +- Chart.struct.h | 1 + Database.mqh | 1 + DateTime.entry.h | 1 + Indicators/Indi_RSI.mqh | 5 +++++ Strategy.mqh | 9 +++++---- Strategy.struct.h | 9 +++++++++ tests/DatabaseTest.mq5 | 14 +++++++------- 13 files changed, 77 insertions(+), 17 deletions(-) diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index 9f1cc40b9..ea421b0e5 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -25,6 +25,7 @@ * 3D chart candles renderer. */ +#include "../Chart.define.h" #include "Chart3DType.h" #include "Cube.h" #include "Device.h" diff --git a/3D/Mesh.h b/3D/Mesh.h index 0ee82c0dc..719b33aff 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -45,8 +45,13 @@ struct PointEntry { T point; long key; + // Default constructor. PointEntry() {} + // Copy constructor. + PointEntry(const PointEntry& r) : point(r.point), key(r.key) {} + + // Constructor. PointEntry(const T& _point) { point = _point; key = MakeKey(_point.Position.x, _point.Position.y, _point.Position.z); diff --git a/3D/Vertex.h b/3D/Vertex.h index 8466fa312..f9b84851e 100644 --- a/3D/Vertex.h +++ b/3D/Vertex.h @@ -8,11 +8,18 @@ struct Vertex { DXVector3 Normal; DXColor Color; - Vertex() { - Color.r = 1.0f; - Color.g = 1.0f; - Color.b = 1.0f; - Color.a = 1.0f; + // Default constructor. + Vertex(float r = 1, float g = 1, float b = 1, float a = 1) { + Color.r = r; + Color.g = g; + Color.b = b; + Color.a = a; + } + + Vertex(const Vertex &r) { + Position = r.Position; + Normal = r.Normal; + Color = r.Color; } static const ShaderVertexLayout Layout[3]; diff --git a/Account/Account.struct.h b/Account/Account.struct.h index efae51d51..4d90c2a94 100644 --- a/Account/Account.struct.h +++ b/Account/Account.struct.h @@ -48,6 +48,21 @@ struct AccountEntry { double margin_used; double margin_free; double margin_avail; + + // Default constructor. + AccountEntry() {} + + // Constructor. + AccountEntry(const AccountEntry& r) + : dtime(r.dtime), + balance(r.balance), + credit(r.credit), + equity(r.equity), + profit(r.profit), + margin_used(r.margin_used), + margin_free(r.margin_free), + margin_avail(r.margin_avail) {} + // Serializers. void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} SerializerNodeType Serialize(Serializer& _s) { diff --git a/BufferFXT.mqh b/BufferFXT.mqh index 61a372f85..a60dc0c02 100644 --- a/BufferFXT.mqh +++ b/BufferFXT.mqh @@ -73,6 +73,20 @@ struct BufferFXTEntry { int flag; // Flag to launch an expert (0 - bar will be modified, but the expert will not be launched). public: + // Default constructor + BufferFXTEntry() {} + + // Copy constructor + BufferFXTEntry(const BufferFXTEntry &r) + : otm(r.otm), + open(r.open), + high(r.high), + low(r.low), + close(r.close), + volume(r.volume), + ctm(r.ctm), + flag(r.flag) {} + bool operator==(const BufferFXTEntry &_s) { // @fixme return false; diff --git a/BufferStruct.mqh b/BufferStruct.mqh index 216a9f15a..a43c06074 100644 --- a/BufferStruct.mqh +++ b/BufferStruct.mqh @@ -64,7 +64,7 @@ class BufferStruct : public DictStruct { * Constructor. */ BufferStruct() : min(INT_MAX), max(INT_MIN) { THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } - BufferStruct(BufferStruct& _right) : min(INT_MAX), max(INT_MIN) { + BufferStruct(const BufferStruct& _right) : min(INT_MAX), max(INT_MIN) { this = _right; THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } diff --git a/Chart.struct.h b/Chart.struct.h index a4100f935..e0c04a219 100644 --- a/Chart.struct.h +++ b/Chart.struct.h @@ -51,6 +51,7 @@ struct ChartEntry { // Constructors. ChartEntry() {} ChartEntry(const BarEntry& _bar) { SetBar(_bar); } + ChartEntry(const ChartEntry& _r) { SetBar(_r.bar); } // Getters. BarEntry GetBar() { return bar; } string ToCSV() { return StringFormat("%s", bar.ToCSV()); } diff --git a/Database.mqh b/Database.mqh index 2a4bcc82b..80571651c 100644 --- a/Database.mqh +++ b/Database.mqh @@ -109,6 +109,7 @@ struct DbSymbolInfoEntry : public SymbolInfoEntry { DatabaseTableSchema schema; // Constructors. DbSymbolInfoEntry() { DefineSchema(); } + DbSymbolInfoEntry(const DbSymbolInfoEntry &r) { schema = r.schema; } DbSymbolInfoEntry(const MqlTick &_tick, const string _symbol = NULL) : SymbolInfoEntry(_tick, _symbol) { DefineSchema(); } diff --git a/DateTime.entry.h b/DateTime.entry.h index c99d8d27f..539ec5a45 100644 --- a/DateTime.entry.h +++ b/DateTime.entry.h @@ -33,6 +33,7 @@ // Includes. #include "DateTime.static.h" #include "PlatformTime.h" +#include "Std.h" struct DateTimeEntry : MqlDateTime { int week_of_year; diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 3b401778e..5aacd6181 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -79,6 +79,11 @@ struct IndiRSIParams : IndicatorParams { struct RSIGainLossData { double avg_gain; double avg_loss; + // Default constructor. + RSIGainLossData() {} + + // Copy constructor. + RSIGainLossData(const RSIGainLossData &r) : avg_gain(r.avg_gain), avg_loss(r.avg_loss) {} }; /** diff --git a/Strategy.mqh b/Strategy.mqh index d52f5168a..961808aa7 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -259,7 +259,7 @@ class Strategy : public Taskable { * Gets strategy entry. */ StgEntry GetEntry() { - StgEntry _entry = {}; + StgEntry _entry; for (ENUM_STRATEGY_STATS_PERIOD _p = EA_STATS_DAILY; _p < FINAL_ENUM_STRATEGY_STATS_PERIOD; _p++) { _entry.SetStats(stats_period[(int)_p], _p); } @@ -988,9 +988,10 @@ class Strategy : public Taskable { if (METHOD(_method, 1)) _result |= _result || !IsTrend(_cmd); // 2 if (METHOD(_method, 2)) _result |= _result || !trade REF_DEREF IsPivot(_cmd); // 4 if (METHOD(_method, 3)) - _result |= _result || Open[_shift] > High[_shift + 1] || Open[_shift] < Low[_shift + 1]; // 8 - if (METHOD(_method, 4)) _result |= _result || trade REF_DEREF IsPeak(_cmd); // 16 - if (METHOD(_method, 5)) _result |= _result || trade REF_DEREF HasOrderBetter(_cmd); // 32 + _result |= _result || iOpen(Symbol(), PERIOD_CURRENT, _shift) > iHigh(Symbol(), PERIOD_CURRENT, _shift + 1) || + iOpen(Symbol(), PERIOD_CURRENT, _shift) < iLow(Symbol(), PERIOD_CURRENT, _shift + 1); // 8 + if (METHOD(_method, 4)) _result |= _result || trade REF_DEREF IsPeak(_cmd); // 16 + if (METHOD(_method, 5)) _result |= _result || trade REF_DEREF HasOrderBetter(_cmd); // 32 /* if (METHOD(_method, 6)) _result |= diff --git a/Strategy.struct.h b/Strategy.struct.h index 5c4eef27f..19dce3bcd 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -436,6 +436,15 @@ struct StgStatsPeriod { struct StgEntry { unsigned short signals; StgStatsPeriod stats_period[FINAL_ENUM_STRATEGY_STATS_PERIOD]; + // Default constructor. + StgEntry() {} + + // Copy constructor. + StgEntry(const StgEntry &r) : signals(r.signals) { + for (int i = 0; i < FINAL_ENUM_STRATEGY_STATS_PERIOD; ++i) { + stats_period[i] = r.stats_period[i]; + } + } string ToCSV() { return StringFormat("%s,%s,%s,%s", stats_period[(int)EA_STATS_DAILY].ToCSV(), stats_period[(int)EA_STATS_WEEKLY].ToCSV(), stats_period[(int)EA_STATS_MONTHLY].ToCSV(), diff --git a/tests/DatabaseTest.mq5 b/tests/DatabaseTest.mq5 index c37b969c9..2cbc81ddf 100644 --- a/tests/DatabaseTest.mq5 +++ b/tests/DatabaseTest.mq5 @@ -45,13 +45,13 @@ int OnInit() { db = new Database(":memory:", DATABASE_OPEN_MEMORY); // Create Table1 table. - DatabaseTableColumnEntry columns[] = { - {"SYMBOL", TYPE_CHAR, DATABASE_COLUMN_FLAG_NONE, 6}, - {"BID", TYPE_DOUBLE}, - {"ASK", TYPE_DOUBLE}, - {"VOLUME", TYPE_INT, DATABASE_COLUMN_FLAG_IS_NULL}, - {"COMMENT", TYPE_STRING, DATABASE_COLUMN_FLAG_IS_NULL}, - }; + ARRAY(DatabaseTableColumnEntry, columns); + ArrayPushObject(columns, DatabaseTableColumnEntry("SYMBOL", TYPE_CHAR, DATABASE_COLUMN_FLAG_NONE, 6)); + ArrayPushObject(columns, DatabaseTableColumnEntry("BID", TYPE_DOUBLE)); + ArrayPushObject(columns, DatabaseTableColumnEntry("ASK", TYPE_DOUBLE)); + ArrayPushObject(columns, DatabaseTableColumnEntry("VOLUME", TYPE_INT, DATABASE_COLUMN_FLAG_IS_NULL)); + ArrayPushObject(columns, DatabaseTableColumnEntry("COMMENT", TYPE_STRING, DATABASE_COLUMN_FLAG_IS_NULL)); + DatabaseTableSchema schema = columns; assertTrueOrFail(db.CreateTable("Table1", schema), "Cannot create table! Error: " + (string)_LastError); DatabasePrint(db.GetHandle(), "PRAGMA TABLE_INFO(Table1);", 0); From a30a47652bc735652e9e74342c865ec84cdb1375 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 7 Feb 2023 17:51:32 +0100 Subject: [PATCH 14/42] WIP. Trying to make tests to run on MT4. --- Chart.struct.tf.h | 2 +- Indicator/Indicator.h | 6 +- Indicator/IndicatorData.h | 8 +- Indicator/tests/classes/Indicators.h | 19 +- Indicators/Indi_Demo.mqh | 2 +- Indicators/Indi_Momentum.mqh | 6 +- Indicators/Indi_PriceFeeder.mqh | 2 +- Refs.struct.h | 6 +- Storage/ValueStorage.indicator.h | 5 - SummaryReport.mqh | 507 ++++++++++++++------------- tests/IndicatorsTest.mq5 | 206 +++++------ 11 files changed, 390 insertions(+), 379 deletions(-) diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index c9644babf..f392ef0d5 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -195,7 +195,7 @@ struct ChartTf { static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { switch (_tf) { case PERIOD_CURRENT: - return TfToSeconds(Period()); + return PeriodSeconds(_tf); case PERIOD_M1: // 1 minute. return 60; case PERIOD_M2: // 2 minutes (non-standard). diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 8d625a583..8dc615bd7 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -207,9 +207,9 @@ class Indicator : public IndicatorData { * Sets whether indicator's buffers should be drawn on the chart. */ void SetDraw(bool _value, color _color = clrAquamarine, int _window = 0) { - draw.SetEnabled(_value); - draw.SetColorLine(_color); - draw.SetWindow(_window); + // draw.SetEnabled(_value); + // draw.SetColorLine(_color); + // draw.SetWindow(_window); } /* Converters */ diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 0707e4fe8..a08cdeae4 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -44,6 +44,7 @@ struct ExternInstantiateIndicatorBufferValueStorageDouble { #include "../Flags.h" #include "../Storage/IValueStorage.h" #include "../Storage/ItemsHistory.h" +#include "../Storage/ValueStorage.indicator.h" #include "../SymbolInfo.struct.h" #include "Indicator.enum.h" #include "IndicatorBase.h" @@ -72,7 +73,7 @@ class IndicatorData : public IndicatorBase { ARRAY(WeakRef, listeners); // List of indicators that listens for events from this one. BufferStruct idata; DictStruct> indicators; // Indicators list keyed by id. - DrawIndicator* draw; + // DrawIndicator* draw; IndicatorCalculateCache cache; IndicatorDataParams idparams; // Indicator data params. IndicatorState istate; @@ -1939,4 +1940,9 @@ int CopyBuffer(IndicatorData* _indi, int _mode, int _start, int _count, ValueSto return _num_copied; } +IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble( + IndicatorData* _indi, int _mode) { + return new IndicatorBufferValueStorage(_indi, _mode); +} + #endif // INDICATOR_DATA_H diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h index d71902dd5..aac05a9ee 100644 --- a/Indicator/tests/classes/Indicators.h +++ b/Indicator/tests/classes/Indicators.h @@ -37,24 +37,27 @@ * Helper class to store all indicators and call OnTick() on them. */ class Indicators { - Ref _indis[]; + DictStruct> _indis; public: void Add(IndicatorBase* _indi) { Ref _ref = _indi; - ArrayPushObject(_indis, _ref); + _indis.Push(_ref); } - void Remove(IndicatorData* _indi) { - Ref _ref = _indi; - Util::ArrayRemoveFirst(_indis, _ref); - } + void Add(Ref& _indi) { Add(_indi.Ptr()); } + + IndicatorData* Get(int index) { return _indis[index].Ptr(); } + + IndicatorData* operator[](int index) { return Get(index); } + + int Size() { return _indis.Size(); } /** * Executes OnTick() on every added indicator. */ void Tick(int _global_tick_index) { - for (int i = 0; i < ArraySize(_indis); ++i) { + for (unsigned int i = 0; i < _indis.Size(); ++i) { _indis[i].Ptr().OnTick(_global_tick_index); } } @@ -64,7 +67,7 @@ class Indicators { */ string ToString(int _shift = 0) { string _result; - for (int i = 0; i < ArraySize(_indis); ++i) { + for (unsigned int i = 0; i < _indis.Size(); ++i) { IndicatorDataEntry _entry = _indis[i].Ptr().GetEntry(_shift); _result += _indis[i].Ptr().GetFullName() + " = " + _entry.ToString() + "\n"; } diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index 07afa9a28..ca34c5186 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -82,7 +82,7 @@ class Indi_Demo : public Indicator { virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = Indi_Demo::iDemo(THIS_PTR, ToRelShift(_abs_shift)); if (idparams.IsDrawing()) { - draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(ToRelShift(_abs_shift)), _value); + // draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(ToRelShift(_abs_shift)), _value); } return _value; } diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 679f96c45..159f38f41 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -151,7 +151,8 @@ class Indi_Momentum : public Indicator { _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), iparams.shift + ToRelShift(_abs_shift)); if (idparams.IsDrawing()) { - draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); + // draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, + // 1); } break; case IDATA_ICUSTOM: @@ -165,7 +166,8 @@ class Indi_Momentum : public Indicator { _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), iparams.shift + ToRelShift(_abs_shift)); if (idparams.IsDrawing()) { - draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); + // draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, + // 1); } break; } diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index 4b93f08ea..be3fbd9d4 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -107,7 +107,7 @@ class Indi_PriceFeeder : public Indicator { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); IndicatorDataEntry _entry = GetEntry(0); for (int i = 0; i < _max_modes; ++i) { - draw.DrawLineTo(GetName() + "_" + IntegerToString(i), GetBarTime(0), _entry.values[i].GetDbl()); + // draw.DrawLineTo(GetName() + "_" + IntegerToString(i), GetBarTime(0), _entry.values[i].GetDbl()); } } } diff --git a/Refs.struct.h b/Refs.struct.h index 210f58f11..3de03deba 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -277,9 +277,9 @@ struct Ref { } }; -template -Ref MakeRef(X* _ptr) { - return Ref(_ptr); +template +Ref MakeRef(T* _ptr) { + return Ref(_ptr); } /** diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 254767c7c..58d4db243 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -57,8 +57,3 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { */ C Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_rel_shift)); } }; - -IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble( - IndicatorData* _indi, int _mode) { - return new IndicatorBufferValueStorage(_indi, _mode); -} diff --git a/SummaryReport.mqh b/SummaryReport.mqh index 964a52b98..11ef0fb46 100644 --- a/SummaryReport.mqh +++ b/SummaryReport.mqh @@ -22,6 +22,7 @@ #include "Account/AccountMt.h" #include "Convert.mqh" +#include "Indicator/IndicatorData.h" #include "Order.struct.h" #include "Terminal.mqh" #include "Trade.mqh" @@ -30,291 +31,291 @@ * Class to provide a summary report. */ class SummaryReport { - protected: - // Variables. - double init_deposit; - double summary_profit; - double gross_profit; - double gross_loss; - double max_profit; - double min_profit; - double con_profit1; - double con_profit2; - double con_loss1; - double con_loss2; - double max_loss; - double max_dd; - double max_dd_pct; - double rel_dd_pct; - double rel_dd; - double expected_payoff; - double profit_factor; - double abs_dd; - int summary_trades; - int profit_trades; - int loss_trades; - int short_trades; - int long_trades; - int win_short_trades; - int win_long_trades; - int con_profit_trades1; - int con_profit_trades2; - int con_loss_trades1; - int con_loss_trades2; - int avg_con_wins; - int avg_con_losses; + protected: + // Variables. + double init_deposit; + double summary_profit; + double gross_profit; + double gross_loss; + double max_profit; + double min_profit; + double con_profit1; + double con_profit2; + double con_loss1; + double con_loss2; + double max_loss; + double max_dd; + double max_dd_pct; + double rel_dd_pct; + double rel_dd; + double expected_payoff; + double profit_factor; + double abs_dd; + int summary_trades; + int profit_trades; + int loss_trades; + int short_trades; + int long_trades; + int win_short_trades; + int win_long_trades; + int con_profit_trades1; + int con_profit_trades2; + int con_loss_trades1; + int con_loss_trades2; + int avg_con_wins; + int avg_con_losses; - double init_balance; + double init_balance; - public: - /** - * Default constructor. - */ + public: + /** + * Default constructor. + */ SummaryReport() { InitVars(AccountMt::AccountBalance()); } - /** - * Constructor to initialize starting balance. - */ + /** + * Constructor to initialize starting balance. + */ SummaryReport(double deposit) { InitVars(deposit); } - /** - * Constructor to initialize starting balance. - */ - void InitVars(double deposit = 0) { - init_deposit = deposit; - max_loss = deposit; - summary_profit = 0.0; - gross_profit = 0.0; - gross_loss = 0.0; - max_profit = 0.0; - min_profit = 0.0; - con_profit1 = 0.0; - con_profit2 = 0.0; - con_loss1 = 0.0; - con_loss2 = 0.0; - max_dd = 0.0; - max_dd_pct = 0.0; - rel_dd_pct = 0.0; - rel_dd = 0.0; - expected_payoff = 0.0; - profit_factor = 0.0; - abs_dd = 0.0; - summary_trades = 0; - profit_trades = 0; - loss_trades = 0; - short_trades = 0; - long_trades = 0; - win_short_trades = 0; - win_long_trades = 0; - con_profit_trades1 = 0; - con_profit_trades2 = 0; - con_loss_trades1 = 0; - con_loss_trades2 = 0; - avg_con_wins = 0; - avg_con_losses = 0; - } + /** + * Constructor to initialize starting balance. + */ + void InitVars(double deposit = 0) { + init_deposit = deposit; + max_loss = deposit; + summary_profit = 0.0; + gross_profit = 0.0; + gross_loss = 0.0; + max_profit = 0.0; + min_profit = 0.0; + con_profit1 = 0.0; + con_profit2 = 0.0; + con_loss1 = 0.0; + con_loss2 = 0.0; + max_dd = 0.0; + max_dd_pct = 0.0; + rel_dd_pct = 0.0; + rel_dd = 0.0; + expected_payoff = 0.0; + profit_factor = 0.0; + abs_dd = 0.0; + summary_trades = 0; + profit_trades = 0; + loss_trades = 0; + short_trades = 0; + long_trades = 0; + win_short_trades = 0; + win_long_trades = 0; + con_profit_trades1 = 0; + con_profit_trades2 = 0; + con_loss_trades1 = 0; + con_loss_trades2 = 0; + avg_con_wins = 0; + avg_con_losses = 0; + } - /** - * Get initial deposit. - */ - double GetInitDeposit() { - static double deposit = 0; - if (deposit > 0) { - return deposit; + /** + * Get initial deposit. + */ + double GetInitDeposit() { + static double deposit = 0; + if (deposit > 0) { + return deposit; } else if (!Terminal::IsRealtime() && init_deposit > 0) { - deposit = init_deposit; - } else { - deposit = AccountMt::CalcInitDeposit(); - } - return (deposit); + deposit = init_deposit; + } else { + deposit = AccountMt::CalcInitDeposit(); } + return (deposit); + } - /** - * Calculates summary details. - */ - void CalculateSummary() { - int sequence = 0, profitseqs = 0, loss_seqs = 0; - double sequential = 0.0, prev_profit = EMPTY_VALUE, dd_pct, drawdown; - double max_peak = init_deposit, min_peak = init_deposit, balance = init_deposit; - int trades_total = TradeHistoryStatic::HistoryOrdersTotal(); - double profit; + /** + * Calculates summary details. + */ + void CalculateSummary() { + int sequence = 0, profitseqs = 0, loss_seqs = 0; + double sequential = 0.0, prev_profit = EMPTY_VALUE, dd_pct, drawdown; + double max_peak = init_deposit, min_peak = init_deposit, balance = init_deposit; + int trades_total = TradeHistoryStatic::HistoryOrdersTotal(); + double profit; - // Initialize summaries. - InitVars(init_deposit); + // Initialize summaries. + InitVars(init_deposit); - for (int i = 0; i < trades_total; i++) { - if (!Order::TryOrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) { - continue; - } - int type = Order::OrderType(); - // Initial balance not considered. - if (i == 0 && type == ACC_OP_BALANCE) continue; - // Calculate profit. - profit = OrderStatic::Profit() + OrderStatic::Commission() + Order::OrderSwap(); - balance += profit; - // Drawdown check. - if (max_peak < balance) { - drawdown = max_peak-min_peak; - if (max_peak != 0.0) { - dd_pct = drawdown / max_peak * 100.0; - if (rel_dd_pct < dd_pct) { - rel_dd_pct = dd_pct; - rel_dd = drawdown; - } - } - if (max_dd < drawdown) { - max_dd = drawdown; - max_dd_pct = max_peak != 0.0 ? max_dd / max_peak * 100.0 : 100.0; + for (int i = 0; i < trades_total; i++) { + if (!Order::TryOrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) { + continue; + } + int type = Order::OrderType(); + // Initial balance not considered. + if (i == 0 && type == ACC_OP_BALANCE) continue; + // Calculate profit. + profit = OrderStatic::Profit() + OrderStatic::Commission() + Order::OrderSwap(); + balance += profit; + // Drawdown check. + if (max_peak < balance) { + drawdown = max_peak - min_peak; + if (max_peak != 0.0) { + dd_pct = drawdown / max_peak * 100.0; + if (rel_dd_pct < dd_pct) { + rel_dd_pct = dd_pct; + rel_dd = drawdown; } - max_peak = balance; - min_peak = balance; } - if (min_peak > balance) min_peak = balance; - if (max_loss > balance) max_loss = balance; - // Market orders only. - if (type != ORDER_TYPE_BUY && type != ORDER_TYPE_SELL) continue; - // Calculate profit in points. - // profit = (OrderClosePrice() - OrderOpenPrice()) / MarketInfo(OrderSymbol(), MODE_POINT); - summary_profit += profit; - summary_trades++; - if (type == ORDER_TYPE_BUY) { - long_trades++; - } else if (type == ORDER_TYPE_SELL) { - short_trades++; + if (max_dd < drawdown) { + max_dd = drawdown; + max_dd_pct = max_peak != 0.0 ? max_dd / max_peak * 100.0 : 100.0; } - if (profit < 0) { - // Loss trades. - loss_trades++; - gross_loss += profit; - if (min_profit > profit) min_profit = profit; - // Fortune changed. - if (prev_profit != EMPTY_VALUE && prev_profit >= 0) { + max_peak = balance; + min_peak = balance; + } + if (min_peak > balance) min_peak = balance; + if (max_loss > balance) max_loss = balance; + // Market orders only. + if (type != ORDER_TYPE_BUY && type != ORDER_TYPE_SELL) continue; + // Calculate profit in points. + // profit = (OrderClosePrice() - OrderOpenPrice()) / MarketInfo(OrderSymbol(), MODE_POINT); + summary_profit += profit; + summary_trades++; + if (type == ORDER_TYPE_BUY) { + long_trades++; + } else if (type == ORDER_TYPE_SELL) { + short_trades++; + } + if (profit < 0) { + // Loss trades. + loss_trades++; + gross_loss += profit; + if (min_profit > profit) min_profit = profit; + // Fortune changed. + if (prev_profit != EMPTY_VALUE && prev_profit >= 0) { if (con_profit_trades1 < sequence || (con_profit_trades1 == sequence && con_profit2 < sequential)) { - con_profit_trades1 = sequence; - con_profit1 = sequential; - } - if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { - con_profit2 = sequential; - con_profit_trades2 = sequence; - } - profitseqs++; - avg_con_wins += sequence; - sequence = 0; - sequential = 0.0; + con_profit_trades1 = sequence; + con_profit1 = sequential; } - } else { - // Profit trades (profit >= 0). - profit_trades++; - if (type == ORDER_TYPE_BUY) win_long_trades++; - if (type == ORDER_TYPE_SELL) win_short_trades++; - gross_profit += profit; - if (max_profit < profit) max_profit = profit; - // Fortune changed. - if (prev_profit != EMPTY_VALUE && prev_profit < 0) { - if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { - con_loss_trades1 = sequence; - con_loss1 = sequential; - } - if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { - con_loss2 = sequential; - con_loss_trades2 = sequence; - } - loss_seqs++; - avg_con_losses += sequence; - sequence = 0; - sequential = 0.0; + if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { + con_profit2 = sequential; + con_profit_trades2 = sequence; } + profitseqs++; + avg_con_wins += sequence; + sequence = 0; + sequential = 0.0; } - sequence++; - sequential += profit; - prev_profit = profit; - } - // Final drawdown check. - drawdown = max_peak - min_peak; - if (max_peak != 0.0) { - dd_pct = drawdown / max_peak * 100.0; - if (rel_dd_pct < dd_pct) { - rel_dd_pct = dd_pct; - rel_dd = drawdown; - } - } - if (max_dd < drawdown) { - max_dd = drawdown; - max_dd_pct = max_peak != 0 ? max_dd / max_peak * 100.0 : 100.0; - } - // Consider last trade. - if (prev_profit != EMPTY_VALUE) { - profit = prev_profit; - if (profit < 0) { - if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { + } else { + // Profit trades (profit >= 0). + profit_trades++; + if (type == ORDER_TYPE_BUY) win_long_trades++; + if (type == ORDER_TYPE_SELL) win_short_trades++; + gross_profit += profit; + if (max_profit < profit) max_profit = profit; + // Fortune changed. + if (prev_profit != EMPTY_VALUE && prev_profit < 0) { + if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { con_loss_trades1 = sequence; con_loss1 = sequential; } - if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { + if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { con_loss2 = sequential; con_loss_trades2 = sequence; } loss_seqs++; avg_con_losses += sequence; + sequence = 0; + sequential = 0.0; + } + } + sequence++; + sequential += profit; + prev_profit = profit; + } + // Final drawdown check. + drawdown = max_peak - min_peak; + if (max_peak != 0.0) { + dd_pct = drawdown / max_peak * 100.0; + if (rel_dd_pct < dd_pct) { + rel_dd_pct = dd_pct; + rel_dd = drawdown; + } + } + if (max_dd < drawdown) { + max_dd = drawdown; + max_dd_pct = max_peak != 0 ? max_dd / max_peak * 100.0 : 100.0; + } + // Consider last trade. + if (prev_profit != EMPTY_VALUE) { + profit = prev_profit; + if (profit < 0) { + if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { + con_loss_trades1 = sequence; + con_loss1 = sequential; + } + if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { + con_loss2 = sequential; + con_loss_trades2 = sequence; + } + loss_seqs++; + avg_con_losses += sequence; } else { if (con_profit_trades1 < sequence || (con_profit_trades1 == sequence && con_profit2 < sequential)) { - con_profit_trades1 = sequence; - con_profit1 = sequential; - } + con_profit_trades1 = sequence; + con_profit1 = sequential; + } if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { - con_profit2 = sequential; - con_profit_trades2 = sequence; - } - profitseqs++; - avg_con_wins += sequence; + con_profit2 = sequential; + con_profit_trades2 = sequence; } + profitseqs++; + avg_con_wins += sequence; } - // Collecting done. - double dnum, profitkoef = 0.0, losskoef = 0.0, avg_profit = 0.0, avgloss = 0.0; - // Average consecutive wins and losses. - dnum = avg_con_wins; - avg_con_wins = profitseqs > 0 ? (int) (dnum / profitseqs + 0.5) : 0; - dnum = avg_con_losses; - avg_con_losses = loss_seqs > 0 ? (int) (dnum / loss_seqs + 0.5) : 0; - // Absolute values. - if (gross_loss < 0.0) gross_loss *=- 1.0; - if (min_profit < 0.0) min_profit *=- 1.0; - if (con_loss1 < 0.0) con_loss1 *=- 1.0; - if (con_loss2 < 0.0) con_loss2 *=- 1.0; - profit_factor = gross_loss > 0.0 ? gross_profit / gross_loss : 0.0; - // Expected payoff. - avg_profit = profit_trades > 0 ? gross_profit / profit_trades : 0; - avgloss = loss_trades > 0 ? gross_loss / loss_trades : 0; - if (summary_trades > 0) { - profitkoef = 1.0 * profit_trades / summary_trades; - losskoef = 1.0 * loss_trades / summary_trades; - expected_payoff = profitkoef * avg_profit - losskoef * avgloss; - } - // Absolute drawdown. - abs_dd = init_deposit - max_loss; } + // Collecting done. + double dnum, profitkoef = 0.0, losskoef = 0.0, avg_profit = 0.0, avgloss = 0.0; + // Average consecutive wins and losses. + dnum = avg_con_wins; + avg_con_wins = profitseqs > 0 ? (int)(dnum / profitseqs + 0.5) : 0; + dnum = avg_con_losses; + avg_con_losses = loss_seqs > 0 ? (int)(dnum / loss_seqs + 0.5) : 0; + // Absolute values. + if (gross_loss < 0.0) gross_loss *= -1.0; + if (min_profit < 0.0) min_profit *= -1.0; + if (con_loss1 < 0.0) con_loss1 *= -1.0; + if (con_loss2 < 0.0) con_loss2 *= -1.0; + profit_factor = gross_loss > 0.0 ? gross_profit / gross_loss : 0.0; + // Expected payoff. + avg_profit = profit_trades > 0 ? gross_profit / profit_trades : 0; + avgloss = loss_trades > 0 ? gross_loss / loss_trades : 0; + if (summary_trades > 0) { + profitkoef = 1.0 * profit_trades / summary_trades; + losskoef = 1.0 * loss_trades / summary_trades; + expected_payoff = profitkoef * avg_profit - losskoef * avgloss; + } + // Absolute drawdown. + abs_dd = init_deposit - max_loss; + } - /** - * Return summary report. - */ - string GetReport(string sep = "\n", string _currency = "") { - string output = ""; - _currency = _currency != "" ? _currency : AccountInfoString(ACCOUNT_CURRENCY); - output += StringFormat("Currency pair symbol: %s", _Symbol) + sep; - output += StringFormat("Initial deposit: %.2f %s", GetInitDeposit(), _currency) + sep; - output += StringFormat("Total net profit: %.2f %s", summary_profit, _currency) + sep; - output += StringFormat("Gross profit: %.2f %s", gross_profit, _currency) + sep; - output += StringFormat("Gross loss: %.2f %s", gross_loss, _currency) + sep; - output += StringFormat("Absolute drawdown: %.2f %s", abs_dd, _currency) + sep; + /** + * Return summary report. + */ + string GetReport(string sep = "\n", string _currency = "") { + string output = ""; + _currency = _currency != "" ? _currency : AccountInfoString(ACCOUNT_CURRENCY); + output += StringFormat("Currency pair symbol: %s", _Symbol) + sep; + output += StringFormat("Initial deposit: %.2f %s", GetInitDeposit(), _currency) + sep; + output += StringFormat("Total net profit: %.2f %s", summary_profit, _currency) + sep; + output += StringFormat("Gross profit: %.2f %s", gross_profit, _currency) + sep; + output += StringFormat("Gross loss: %.2f %s", gross_loss, _currency) + sep; + output += StringFormat("Absolute drawdown: %.2f %s", abs_dd, _currency) + sep; output += StringFormat("Maximal drawdown: %.1f %s (%.1f%%)", max_dd, _currency, max_dd_pct) + sep; output += StringFormat("Relative drawdown: (%.1f%%) %.1f %s", rel_dd_pct, rel_dd, _currency) + sep; - output += StringFormat("Profit factor: %.2f", profit_factor) + sep; - output += StringFormat("Expected payoff: %.2f", expected_payoff) + sep; - output += StringFormat("Trades total %d", summary_trades) + sep; + output += StringFormat("Profit factor: %.2f", profit_factor) + sep; + output += StringFormat("Expected payoff: %.2f", expected_payoff) + sep; + output += StringFormat("Trades total %d", summary_trades) + sep; output += StringFormat("Short positions (won %%): %d (%.1f%%)", short_trades, short_trades ? 100.0 * win_short_trades / short_trades : 0) + sep; @@ -327,22 +328,22 @@ class SummaryReport { output += StringFormat("Loss trades (%% of total): %d (%.1f%%)", loss_trades, loss_trades ? 100.0 * loss_trades / summary_trades : 0) + sep; - output += StringFormat("Largest profit trade: %.2f", max_profit) + sep; - output += StringFormat("Largest loss trade: %.2f", -min_profit) + sep; + output += StringFormat("Largest profit trade: %.2f", max_profit) + sep; + output += StringFormat("Largest loss trade: %.2f", -min_profit) + sep; output += StringFormat("Average profit trade: %.2f", profit_trades ? gross_profit / profit_trades : 0) + sep; output += StringFormat("Average loss trade: %.2f", loss_trades ? -gross_loss / loss_trades : 0) + sep; - output += StringFormat("Average consecutive wins: %.2f", avg_con_wins) + sep; - output += StringFormat("Average consecutive losses: %.2f", avg_con_losses) + sep; + output += StringFormat("Average consecutive wins: %.2f", avg_con_wins) + sep; + output += StringFormat("Average consecutive losses: %.2f", avg_con_losses) + sep; output += StringFormat("Maximum consecutive wins (profit in money): %d (%.2f)", con_profit_trades1, con_profit1) + sep; - output += StringFormat("Maximum consecutive losses (loss in money): %d (%.2f)", con_loss_trades1, -con_loss1) + sep; + output += StringFormat("Maximum consecutive losses (loss in money): %d (%.2f)", con_loss_trades1, -con_loss1) + sep; output += StringFormat("Maximal consecutive profit (count of wins): %.2f (%d)", con_profit2, con_profit_trades2) + sep; - output += StringFormat("Maximal consecutive loss (count of losses): %.2f (%d)", con_loss2, con_loss_trades2) + sep; - return output; - } + output += StringFormat("Maximal consecutive loss (count of losses): %.2f (%d)", con_loss2, con_loss_trades2) + sep; + return output; + } }; diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index b1fc5c575..b306ed976 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -38,6 +38,7 @@ struct DataParamEntry; #include "../DictObject.mqh" #include "../Indicator/Indicator.h" #include "../Indicator/tests/classes/IndicatorTfDummy.h" +#include "../Indicator/tests/classes/Indicators.h" #include "../Indicators/Bitwise/indicators.h" #include "../Indicators/Tick/Indi_TickMt.mqh" #include "../Indicators/indicators.h" @@ -51,9 +52,9 @@ struct DataParamEntry; enum ENUM_CUSTOM_INDICATORS { INDI_SPECIAL_MATH_CUSTOM = FINAL_INDICATOR_TYPE_ENTRY + 1 }; // Global variables. -DictStruct> indis; -DictStruct> whitelisted_indis; -DictStruct> tested; +Indicators indis; +DictStruct whitelisted_indis; +DictStruct tested; double test_values[] = {1.245, 1.248, 1.254, 1.264, 1.268, 1.261, 1.256, 1.250, 1.242, 1.240, 1.235, 1.240, 1.234, 1.245, 1.265, 1.274, 1.285, 1.295, 1.300, 1.312, 1.315, 1.320, 1.325, 1.335, 1.342, 1.348, 1.352, 1.357, 1.359, 1.422, 1.430, 1.435}; @@ -74,8 +75,8 @@ int OnInit() { Print("Connecting candle and tick indicators to all indicators..."); // Connecting all indicators to default candle indicator (which is connected to default tick indicator). - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - Platform::AddWithDefaultBindings(iter.Value().Ptr(), _Symbol, PERIOD_CURRENT); + for (int i = 0; i < indis.Size(); ++i) { + Platform::AddWithDefaultBindings(indis[i], _Symbol, PERIOD_CURRENT); } // Check for any errors. @@ -106,19 +107,20 @@ void OnTick() { return; } - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + for (int i = 0; i < indis.Size(); ++i) { + IndicatorData* _indi = indis[i]; + if (whitelisted_indis.Size() == 0) { - if (tested.Contains(iter.Value())) { + if (tested.Contains(_indi)) { // Indicator is already tested, skipping. continue; } } else { - if (!whitelisted_indis.Contains(iter.Value())) { + if (!whitelisted_indis.Contains(_indi)) { continue; } } - IndicatorData* _indi = iter.Value().Ptr(); IndicatorDataEntry _entry(_indi PTR_DEREF GetEntry()); // if (_indi.GetType() != INDI_AMA) @@ -128,7 +130,7 @@ void OnTick() { if (_entry.IsValid()) { PrintFormat("%s: bar %d: %s", _indi PTR_DEREF GetFullName(), _candles PTR_DEREF GetBars(), _indi PTR_DEREF ToString()); - tested.Push(iter.Value()); // Mark as tested. + tested.Push(_indi); // Mark as tested. } } } @@ -140,9 +142,11 @@ void OnTick() { */ void OnDeinit(const int reason) { int num_not_tested = 0; - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - if (!tested.Contains(iter.Value())) { - PrintFormat("%s: Indicator not tested: %s", __FUNCTION__, iter.Value().Ptr().GetFullName()); + for (int i = 0; i < indis.Size(); ++i) { + IndicatorData* _indi = indis[i]; + + if (!tested.Contains(_indi)) { + PrintFormat("%s: Indicator not tested: %s", __FUNCTION__, _indi.GetFullName()); ++num_not_tested; } } @@ -159,127 +163,127 @@ bool InitIndicators() { // Price indicator. Ref indi_price = new Indi_Price(PriceIndiParams()); - // indis.Push(indi_price); // @fixme: Make it work with the test? + // indis.Add(indi_price); // @fixme: Make it work with the test? /* Standard indicators */ // AC. - indis.Push(Ref(new Indi_AC())); + indis.Add(new Indi_AC()); // AD. - indis.Push(Ref(new Indi_AD())); + indis.Add(new Indi_AD()); // ADX. IndiADXParams adx_params(14); - indis.Push(Ref(new Indi_ADX(adx_params))); + indis.Add(new Indi_ADX(adx_params)); // Alligator. IndiAlligatorParams alli_params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - indis.Push(Ref(new Indi_Alligator(alli_params))); + indis.Add(new Indi_Alligator(alli_params)); // Awesome Oscillator (AO). - indis.Push(Ref(new Indi_AO())); + indis.Add(new Indi_AO()); // Accumulation Swing Index (ASI). IndiASIParams _asi_params; - indis.Push(Ref(new Indi_ASI(_asi_params))); + indis.Add(new Indi_ASI(_asi_params)); // Average True Range (ATR). IndiATRParams atr_params(14); - indis.Push(Ref(new Indi_ATR(atr_params))); + indis.Add(new Indi_ATR(atr_params)); // Bollinger Bands - Built-in. IndiBandsParams bands_params(20, 2, 0, PRICE_OPEN); Ref indi_bands = new Indi_Bands(bands_params); - indis.Push(indi_bands); - // whitelisted_indis.Push(indi_bands); + indis.Add(indi_bands); + // whitelisted_indis.Add(indi_bands); // Bollinger Bands - OnCalculate. Ref indi_bands_oncalculate = new Indi_Bands(bands_params, IDATA_ONCALCULATE); - indis.Push(indi_bands_oncalculate); - // whitelisted_indis.Push(indi_bands_oncalculate); + indis.Add(indi_bands_oncalculate); + // whitelisted_indis.Add(indi_bands_oncalculate); // Bears Power. IndiBearsPowerParams bears_params(13, PRICE_CLOSE); - indis.Push(Ref(new Indi_BearsPower(bears_params))); + indis.Add(new Indi_BearsPower(bears_params)); // Bulls Power. IndiBullsPowerParams bulls_params(13, PRICE_CLOSE); - indis.Push(Ref(new Indi_BullsPower(bulls_params))); + indis.Add(new Indi_BullsPower(bulls_params)); // Market Facilitation Index (BWMFI). IndiBWIndiMFIParams _bwmfi_params(1); - indis.Push(Ref(new Indi_BWMFI(_bwmfi_params))); + indis.Add(new Indi_BWMFI(_bwmfi_params)); // Commodity Channel Index (CCI). IndiCCIParams cci_params(14, PRICE_OPEN); - indis.Push(Ref(new Indi_CCI(cci_params))); + indis.Add(new Indi_CCI(cci_params)); // DeMarker. IndiDeMarkerParams dm_params(14); - indis.Push(Ref(new Indi_DeMarker(dm_params))); + indis.Add(new Indi_DeMarker(dm_params)); // Envelopes. IndiEnvelopesParams env_params(13, 0, MODE_SMA, PRICE_OPEN, 2); - indis.Push(Ref(new Indi_Envelopes(env_params))); + indis.Add(new Indi_Envelopes(env_params)); // Force Index. IndiForceParams force_params(13, MODE_SMA, PRICE_CLOSE); - indis.Push(Ref(new Indi_Force(force_params))); + indis.Add(new Indi_Force(force_params)); // Fractals. - indis.Push(Ref(new Indi_Fractals())); + indis.Add(new Indi_Fractals()); // Fractal Adaptive Moving Average (FRAMA). IndiFrAIndiMAParams frama_params(); - indis.Push(Ref(new Indi_FrAMA(frama_params))); + indis.Add(new Indi_FrAMA(frama_params)); // Gator Oscillator. IndiGatorParams gator_params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - indis.Push(Ref(new Indi_Gator(gator_params))); + indis.Add(new Indi_Gator(gator_params)); // Heiken Ashi. IndiHeikenAshiParams _ha_params(); - indis.Push(Ref(new Indi_HeikenAshi(_ha_params))); + indis.Add(new Indi_HeikenAshi(_ha_params)); // Ichimoku Kinko Hyo. IndiIchimokuParams ichi_params(9, 26, 52); - indis.Push(Ref(new Indi_Ichimoku(ichi_params))); + indis.Add(new Indi_Ichimoku(ichi_params)); // Moving Average. IndiMAParams ma_params(13, 0, MODE_SMA, PRICE_OPEN); Ref indi_ma = new Indi_MA(ma_params); - indis.Push(indi_ma); + indis.Add(indi_ma); // DEMA. IndiDEMAParams dema_params(13, 2, PRICE_OPEN); Ref indi_dema = new Indi_DEMA(dema_params, INDI_DEMA_DEFAULT_IDSTYPE, indi_price.Ptr()); - // indis.Push(indi_dema); // @fixme + // indis.Add(indi_dema); // @fixme // MACD. IndiMACDParams macd_params(12, 26, 9, PRICE_CLOSE); Ref macd = new Indi_MACD(macd_params); - indis.Push(macd); + indis.Add(macd); // Money Flow Index (MFI). IndiMFIParams mfi_params(14); - indis.Push(Ref(new Indi_MFI(mfi_params))); + indis.Add(new Indi_MFI(mfi_params)); // Momentum (MOM). IndiMomentumParams mom_params(); - indis.Push(Ref(new Indi_Momentum(mom_params))); + indis.Add(new Indi_Momentum(mom_params)); // On Balance Volume (OBV). - indis.Push(Ref(new Indi_OBV())); + indis.Add(new Indi_OBV()); // OsMA. IndiOsMAParams osma_params(12, 26, 9, PRICE_CLOSE); - indis.Push(Ref(new Indi_OsMA(osma_params))); + indis.Add(new Indi_OsMA(osma_params)); // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); Ref indi_rsi = new Indi_RSI(rsi_params); - indis.Push(Ref(indi_rsi.Ptr())); + indis.Add(indi_rsi.Ptr()); // Bollinger Bands over RSI. IndiBandsParams indi_bands_over_rsi_params(20, 2, 0, PRICE_OPEN); @@ -287,26 +291,26 @@ bool InitIndicators() { // Using RSI's mode 0 as applied price. indi_bands_over_rsi REF_DEREF SetDataSourceAppliedPrice(INDI_VS_TYPE_INDEX_0); indi_bands_over_rsi REF_DEREF SetDataSource(indi_rsi.Ptr()); - indis.Push(indi_bands_over_rsi); + indis.Add(indi_bands_over_rsi); // Standard Deviation (StdDev). IndiStdDevParams stddev_params(13, 10, MODE_SMA, PRICE_OPEN); Ref indi_stddev = new Indi_StdDev(stddev_params); - indis.Push(indi_stddev); + indis.Add(indi_stddev); // Relative Strength Index (RSI) over Standard Deviation (StdDev). IndiRSIParams indi_rsi_over_stddev_params(); Ref indi_rsi_over_stddev = new Indi_RSI(indi_rsi_over_stddev_params); indi_rsi_over_stddev.Ptr().SetDataSource(indi_stddev.Ptr()); - indis.Push(indi_rsi_over_stddev); + indis.Add(indi_rsi_over_stddev); // Relative Vigor Index (RVI). IndiRVIParams rvi_params(14); - indis.Push(Ref(new Indi_RVI(rvi_params))); + indis.Add(new Indi_RVI(rvi_params)); // Parabolic SAR. IndiSARParams sar_params(0.02, 0.2); - indis.Push(Ref(new Indi_SAR(sar_params))); + indis.Add(new Indi_SAR(sar_params)); // Standard Deviation (StdDev). Ref indi_price_for_stdev = new Indi_Price(PriceIndiParams()); @@ -314,24 +318,24 @@ bool InitIndicators() { // stddev_on_price_params.SetDraw(clrBlue, 1); // @fixme Ref indi_stddev_on_price = new Indi_StdDev(stddev_on_price_params, IDATA_BUILTIN, indi_price_for_stdev.Ptr()); - indis.Push(Ref(indi_stddev_on_price.Ptr())); + indis.Add(indi_stddev_on_price.Ptr()); // Stochastic Oscillator. IndiStochParams stoch_params(5, 3, 3, MODE_SMMA, STO_LOWHIGH); - indis.Push(Ref(new Indi_Stochastic(stoch_params))); + indis.Add(new Indi_Stochastic(stoch_params)); // Williams' Percent Range (WPR). IndiWPRParams wpr_params(14); - indis.Push(Ref(new Indi_WPR(wpr_params))); + indis.Add(new Indi_WPR(wpr_params)); // ZigZag. IndiZigZagParams zz_params(12, 5, 3); - indis.Push(Ref(new Indi_ZigZag(zz_params))); + indis.Add(new Indi_ZigZag(zz_params)); /* Special indicators */ // Demo/Dummy Indicator. - indis.Push(Ref(new Indi_Demo())); + indis.Add(new Indi_Demo()); // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); @@ -339,7 +343,7 @@ bool InitIndicators() { IndiBandsParams bands_on_price_params(); // bands_on_price_params.SetDraw(clrCadetBlue); // @fixme Ref indi_bands_on_price = new Indi_Bands(bands_on_price_params, IDATA_BUILTIN, indi_price_4_bands.Ptr()); - indis.Push(Ref(indi_bands_on_price.Ptr())); + indis.Add(indi_bands_on_price.Ptr()); // Standard Deviation (StdDev) over MA(SMA). // NOTE: If you set ma_shift parameter for MA, then StdDev will no longer @@ -352,7 +356,7 @@ bool InitIndicators() { Ref indi_stddev_on_ma_sma = new Indi_StdDev(stddev_params_on_ma_sma, IDATA_BUILTIN, indi_ma_sma_for_stddev.Ptr()); - indis.Push(Ref(indi_stddev_on_ma_sma.Ptr())); + indis.Add(indi_stddev_on_ma_sma.Ptr()); // Standard Deviation (StdDev) in SMA mode over Price. PriceIndiParams price_params_for_stddev_sma(); @@ -361,7 +365,7 @@ bool InitIndicators() { // stddev_sma_on_price_params.SetDraw(true, 1); // @fixme Ref indi_stddev_on_sma = new Indi_StdDev(stddev_sma_on_price_params, IDATA_BUILTIN, indi_price_for_stddev_sma.Ptr()); - indis.Push(Ref(indi_stddev_on_sma.Ptr())); + indis.Add(indi_stddev_on_sma.Ptr()); // Moving Average (MA) over Price indicator. PriceIndiParams price_params_4_ma(); @@ -370,7 +374,7 @@ bool InitIndicators() { // ma_on_price_params.SetDraw(clrYellowGreen); // @fixme ma_on_price_params.SetIndicatorType(INDI_MA_ON_PRICE); Ref indi_ma_on_price = new Indi_MA(ma_on_price_params, IDATA_BUILTIN, indi_price_4_ma.Ptr()); - indis.Push(Ref(indi_ma_on_price.Ptr())); + indis.Add(indi_ma_on_price.Ptr()); // Commodity Channel Index (CCI) over Price indicator. PriceIndiParams price_params_4_cci(); @@ -378,7 +382,7 @@ bool InitIndicators() { IndiCCIParams cci_on_price_params(); // cci_on_price_params.SetDraw(clrYellowGreen, 1); // @fixme Ref indi_cci_on_price = new Indi_CCI(cci_on_price_params, IDATA_BUILTIN, indi_price_4_cci.Ptr()); - indis.Push(Ref(indi_cci_on_price.Ptr())); + indis.Add(indi_cci_on_price.Ptr()); // Envelopes over Price indicator. PriceIndiParams price_params_4_envelopes(); @@ -387,7 +391,7 @@ bool InitIndicators() { // env_on_price_params.SetDraw(clrBrown); // @fixme Ref indi_envelopes_on_price = new Indi_Envelopes(env_on_price_params, IDATA_BUILTIN, indi_price_4_envelopes.Ptr()); - indis.Push(Ref(indi_envelopes_on_price.Ptr())); + indis.Add(indi_envelopes_on_price.Ptr()); // DEMA over Price indicator. PriceIndiParams price_params_4_dema(); @@ -396,7 +400,7 @@ bool InitIndicators() { // dema_on_price_params.SetDraw(clrRed); // @fixme Ref indi_dema_on_price = new Indi_DEMA(dema_on_price_params, INDI_DEMA_DEFAULT_IDSTYPE, indi_price_4_dema.Ptr()); - // indis.Push(indi_dema_on_price.Ptr()); // @fixme + // indis.Add(indi_dema_on_price.Ptr()); // @fixme // Momentum over Price indicator. Ref indi_price_4_momentum = new Indi_Price(); @@ -404,7 +408,7 @@ bool InitIndicators() { // mom_on_price_params.SetDraw(clrDarkCyan); // @fixme Ref indi_momentum_on_price = new Indi_Momentum(mom_on_price_params, IDATA_BUILTIN, indi_price_4_momentum.Ptr()); - indis.Push(Ref(indi_momentum_on_price.Ptr())); + indis.Add(indi_momentum_on_price.Ptr()); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); @@ -412,13 +416,13 @@ bool InitIndicators() { IndiRSIParams rsi_on_price_params(); // rsi_on_price_params.SetDraw(clrBisque, 1); // @fixme Ref indi_rsi_on_price = new Indi_RSI(rsi_on_price_params, IDATA_BUILTIN, indi_price_4_rsi.Ptr()); - indis.Push(Ref(indi_rsi_on_price.Ptr())); + indis.Add(indi_rsi_on_price.Ptr()); // Drawer (socket-based) indicator over RSI over Price. IndiDrawerParams drawer_params(14, PRICE_OPEN); // drawer_params.SetDraw(clrBisque, 0); // @fixme Ref indi_drawer_on_rsi = new Indi_Drawer(drawer_params, IDATA_BUILTIN, indi_rsi_on_price.Ptr()); - indis.Push(Ref(indi_drawer_on_rsi.Ptr())); + indis.Add(indi_drawer_on_rsi.Ptr()); // Applied Price over OHCL indicator. IndiAppliedPriceParams applied_price_params(); @@ -426,11 +430,11 @@ bool InitIndicators() { IndiOHLCParams applied_price_ohlc_params(PRICE_TYPICAL); Ref indi_applied_price_on_price = new Indi_AppliedPrice(applied_price_params, IDATA_INDICATOR, new Indi_OHLC(applied_price_ohlc_params)); - indis.Push(Ref(indi_applied_price_on_price.Ptr())); + indis.Add(indi_applied_price_on_price.Ptr()); // ADXW. IndiADXWParams adxw_params(14); - indis.Push(Ref(new Indi_ADXW(adxw_params))); + indis.Add(new Indi_ADXW(adxw_params)); // AMA. IndiAMAParams ama_params(); @@ -438,129 +442,129 @@ bool InitIndicators() { // However, in that case we need to specifiy applied price (excluding ASK and BID). Indi_AMA* _indi_ama = new Indi_AMA(ama_params, IDATA_INDICATOR); _indi_ama.SetAppliedPrice(PRICE_OPEN); - indis.Push(Ref(_indi_ama)); + indis.Add(_indi_ama); // Original AMA. IndiAMAParams ama_params_orig(); ama_params_orig.SetName("Original AMA to compare"); - indis.Push(Ref(new Indi_AMA(ama_params_orig))); + indis.Add(new Indi_AMA(ama_params_orig)); // Chaikin Oscillator. IndiCHOParams cho_params(); - indis.Push(Ref(new Indi_CHO(cho_params))); + indis.Add(new Indi_CHO(cho_params)); // Chaikin Volatility. IndiCHVParams chv_params(); - indis.Push(Ref(new Indi_CHV(chv_params))); + indis.Add(new Indi_CHV(chv_params)); // Color Bars. IndiColorBarsParams color_bars_params(); - indis.Push(Ref(new Indi_ColorBars(color_bars_params))); + indis.Add(new Indi_ColorBars(color_bars_params)); // Color Candles Daily. IndiColorCandlesDailyParams color_candles_daily_params(); - indis.Push(Ref(new Indi_ColorCandlesDaily(color_candles_daily_params))); + indis.Add(new Indi_ColorCandlesDaily(color_candles_daily_params)); // Color Line. IndiColorLineParams color_line_params(); - indis.Push(Ref(new Indi_ColorLine(color_line_params))); + indis.Add(new Indi_ColorLine(color_line_params)); // Detrended Price Oscillator. IndiDetrendedPriceParams detrended_params(); - indis.Push(Ref(new Indi_DetrendedPrice(detrended_params))); + indis.Add(new Indi_DetrendedPrice(detrended_params)); // Mass Index. IndiMassIndexParams mass_index_params(); - indis.Push(Ref(new Indi_MassIndex(mass_index_params))); + indis.Add(new Indi_MassIndex(mass_index_params)); // OHLC. IndiOHLCParams ohlc_params(); - indis.Push(Ref(new Indi_OHLC(ohlc_params))); + indis.Add(new Indi_OHLC(ohlc_params)); // Price Channel. IndiPriceChannelParams price_channel_params(); - indis.Push(Ref(new Indi_PriceChannel(price_channel_params))); + indis.Add(new Indi_PriceChannel(price_channel_params)); // Price Volume Trend. IndiPriceVolumeTrendParams price_volume_trend_params(); - indis.Push(Ref(new Indi_PriceVolumeTrend(price_volume_trend_params))); + indis.Add(new Indi_PriceVolumeTrend(price_volume_trend_params)); // Bill Williams' Zone Trade. IndiBWZTParams bwzt_params(); - indis.Push(Ref(new Indi_BWZT(bwzt_params))); + indis.Add(new Indi_BWZT(bwzt_params)); // Rate of Change. IndiRateOfChangeParams rate_of_change_params(); - indis.Push(Ref(new Indi_RateOfChange(rate_of_change_params))); + indis.Add(new Indi_RateOfChange(rate_of_change_params)); // Triple Exponential Moving Average. IndiTEMAParams tema_params(); - indis.Push(Ref(new Indi_TEMA(tema_params))); + indis.Add(new Indi_TEMA(tema_params)); // Triple Exponential Average. IndiTRIXParams trix_params(); - indis.Push(Ref(new Indi_TRIX(trix_params))); + indis.Add(new Indi_TRIX(trix_params)); // Ultimate Oscillator. IndiUltimateOscillatorParams ultimate_oscillator_params(); - indis.Push(Ref(new Indi_UltimateOscillator(ultimate_oscillator_params))); + indis.Add(new Indi_UltimateOscillator(ultimate_oscillator_params)); // VIDYA. IndiVIDYAParams vidya_params(); - indis.Push(Ref(new Indi_VIDYA(vidya_params))); + indis.Add(new Indi_VIDYA(vidya_params)); // Volumes. IndiVolumesParams volumes_params(); - indis.Push(Ref(new Indi_Volumes(volumes_params))); + indis.Add(new Indi_Volumes(volumes_params)); // Volume Rate of Change. IndiVROCParams vol_rate_of_change_params(); - indis.Push(Ref(new Indi_VROC(vol_rate_of_change_params))); + indis.Add(new Indi_VROC(vol_rate_of_change_params)); // Larry Williams' Accumulation/Distribution. IndiWilliamsADParams williams_ad_params(); - indis.Push(Ref(new Indi_WilliamsAD(williams_ad_params))); + indis.Add(new Indi_WilliamsAD(williams_ad_params)); // ZigZag Color. IndiZigZagColorParams zigzag_color_params(); - indis.Push(Ref(new Indi_ZigZagColor(zigzag_color_params))); + indis.Add(new Indi_ZigZagColor(zigzag_color_params)); // Custom Moving Average. IndiCustomMovingAverageParams cma_params(); - indis.Push(Ref(new Indi_CustomMovingAverage(cma_params))); + indis.Add(new Indi_CustomMovingAverage(cma_params)); // Math (specialized indicator). IndiMathParams math_params(MATH_OP_SUB, BAND_UPPER, BAND_LOWER, 0, 0); // math_params.SetDraw(clrBlue); // @fixme math_params.SetName("Bands(UP - LO)"); Ref indi_math_1 = new Indi_Math(math_params, IDATA_INDICATOR, indi_bands.Ptr()); - indis.Push(Ref(indi_math_1.Ptr())); + indis.Add(indi_math_1.Ptr()); // Math (specialized indicator) via custom math method. IndiMathParams math_custom_params(MathCustomOp, BAND_UPPER, BAND_LOWER, 0, 0); // math_custom_params.SetDraw(clrBeige); // @fixme math_custom_params.SetName("Bands(Custom math fn)"); Ref indi_math_2 = new Indi_Math(math_custom_params, IDATA_INDICATOR, indi_bands.Ptr()); - indis.Push(Ref(indi_math_2.Ptr())); + indis.Add(indi_math_2.Ptr()); // RS (Math-based) indicator. IndiRSParams rs_params(); - indis.Push(Ref(new Indi_RS(rs_params))); + indis.Add(new Indi_RS(rs_params)); // Pattern Detector. IndiPatternParams pattern_params(); - indis.Push(Ref(new Indi_Pattern(pattern_params))); + indis.Add(new Indi_Pattern(pattern_params)); // Pivot. IndiPivotParams pivot_params(); - indis.Push(Ref(new Indi_Pivot(pivot_params))); + indis.Add(new Indi_Pivot(pivot_params)); // Candle Pattern Detector. CandleParams candle_params(); - indis.Push(Ref(new Indi_Candle(candle_params))); + indis.Add(new Indi_Candle(candle_params)); // Push white-listed indicators here. - // whitelisted_indis.Push(_indi_test); + // whitelisted_indis.Add(_indi_test); return GetLastError() == ERR_NO_ERROR; } @@ -571,13 +575,13 @@ double MathCustomOp(double a, double b) { return 1.11 + (b - a) * 2.0; } * Print indicators. */ bool PrintIndicators(string _prefix = "") { - for (DictIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - if (whitelisted_indis.Size() != 0 && !whitelisted_indis.Contains(iter.Value())) { + for (int i = 0; i < indis.Size(); ++i) { + IndicatorData* _indi = indis[i]; + + if (whitelisted_indis.Size() != 0 && !whitelisted_indis.Contains(_indi)) { continue; } - IndicatorData* _indi = iter.Value().Ptr(); - if (_indi.GetModeCount() == 0) { // Indicator has no modes. PrintFormat("Skipping %s as it has no modes.", _indi.GetFullName()); From 720ec62b113ffce187fbad7d54c789190f85f6be Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 8 Feb 2023 16:42:03 +0100 Subject: [PATCH 15/42] WIP. Should fix tests in MT4 and MT5. --- DictSlot.mqh | 8 +++---- Indicator/tests/classes/Indicators.h | 4 ++-- Refs.struct.h | 16 ++++++++++++++ Tick/Tick.struct.h | 14 +++++++++++++ Tick/TickManager.h | 1 + tests/IndicatorsTest.mq5 | 4 ++-- tests/RefsTest.mq5 | 31 ++++++++++++++-------------- 7 files changed, 54 insertions(+), 24 deletions(-) diff --git a/DictSlot.mqh b/DictSlot.mqh index 3752244c9..1b28cea9e 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,11 +40,11 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} -#ifdef __MQL__ - DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} -#else + //#ifdef __MQL__ + // DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} + //#else DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key) { value = r.value; } -#endif + //#endif bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h index aac05a9ee..871d059a3 100644 --- a/Indicator/tests/classes/Indicators.h +++ b/Indicator/tests/classes/Indicators.h @@ -40,7 +40,7 @@ class Indicators { DictStruct> _indis; public: - void Add(IndicatorBase* _indi) { + void Add(IndicatorData* _indi) { Ref _ref = _indi; _indis.Push(_ref); } @@ -51,7 +51,7 @@ class Indicators { IndicatorData* operator[](int index) { return Get(index); } - int Size() { return _indis.Size(); } + int Size() { return (int)_indis.Size(); } /** * Executes OnTick() on every added indicator. diff --git a/Refs.struct.h b/Refs.struct.h index 3de03deba..ddda68a3b 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -357,6 +357,14 @@ struct WeakRef { return Ptr(); } + /** + * Makes a weak reference to the given weakly-referenced object. + */ + X* operator=(const WeakRef& right) { + THIS_REF = right.Ptr(); + return Ptr(); + } + /** * Makes a weak reference to the strongly-referenced object. */ @@ -365,6 +373,14 @@ struct WeakRef { return Ptr(); } + /** + * Makes a weak reference to the strongly-referenced object. + */ + X* operator=(const Ref& right) { + THIS_REF = right.Ptr(); + return Ptr(); + } + /** * Equality operator. */ diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 71f08dcf8..bda8880d5 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -47,6 +47,20 @@ struct MqlTick { long time_msc; // Time of a price last update in milliseconds. unsigned int flags; // Tick flags. unsigned long volume; // Volume for the current last price. + // Default constructor. + MqlTick() {} + + // Copy constructor. + MqlTick(){const MqlTick & r} { + time = r.time; + ask = r.ask; + bid = r.bid; + last = r.last; + volume_real = r.volume_real; + time_msc = r.time_msc; + flags = r.flags; + volume = r.volume; + } }; #endif diff --git a/Tick/TickManager.h b/Tick/TickManager.h index 76f2f0e1d..d34239ac3 100644 --- a/Tick/TickManager.h +++ b/Tick/TickManager.h @@ -27,6 +27,7 @@ // Includes. #include "../BufferStruct.mqh" +#include "Tick.struct.h" #include "TickManager.h" //#include "TickManager.struct.h" diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index b306ed976..c113d8892 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -53,8 +53,8 @@ enum ENUM_CUSTOM_INDICATORS { INDI_SPECIAL_MATH_CUSTOM = FINAL_INDICATOR_TYPE_EN // Global variables. Indicators indis; -DictStruct whitelisted_indis; -DictStruct tested; +Dict whitelisted_indis; +Dict tested; double test_values[] = {1.245, 1.248, 1.254, 1.264, 1.268, 1.261, 1.256, 1.250, 1.242, 1.240, 1.235, 1.240, 1.234, 1.245, 1.265, 1.274, 1.285, 1.295, 1.300, 1.312, 1.315, 1.320, 1.325, 1.335, 1.342, 1.348, 1.352, 1.357, 1.359, 1.422, 1.430, 1.435}; diff --git a/tests/RefsTest.mq5 b/tests/RefsTest.mq5 index 8f0b0cf9e..943a22378 100644 --- a/tests/RefsTest.mq5 +++ b/tests/RefsTest.mq5 @@ -137,26 +137,25 @@ int OnInit() { // Dictionary of weak references. DictStruct> refs2; - /* - Ref dyn9_1 = new DynamicClass(1); - Ref dyn9_2 = new DynamicClass(2); - Ref dyn9_3 = new DynamicClass(3); + Ref dyn9_1 = new DynamicClass(1); + Ref dyn9_2 = new DynamicClass(2); + Ref dyn9_3 = new DynamicClass(3); - WeakRef dyn9_1_weak_ref = dyn9_1; - WeakRef dyn9_2_weak_ref = dyn9_2; - WeakRef dyn9_3_weak_ref = dyn9_3; + WeakRef dyn9_1_weak_ref = dyn9_1; + WeakRef dyn9_2_weak_ref = dyn9_2; + WeakRef dyn9_3_weak_ref = dyn9_3; - refs2.Set("1", dyn9_1_weak_ref); - refs2.Set("2", dyn9_2_weak_ref); - refs2.Set("3", dyn9_3_weak_ref); + refs2.Set("1", dyn9_1_weak_ref); + refs2.Set("2", dyn9_2_weak_ref); + refs2.Set("3", dyn9_3_weak_ref); - // Should make refs2["2"] to have no existing object. - dyn9_2 = NULL; + // Should make refs2["2"] to have no existing object. + dyn9_2 = NULL; + + assertTrueOrFail(refs2.GetByKey("1").ObjectExists(), "Object should exists"); + assertTrueOrFail(!refs2.GetByKey("2").ObjectExists(), "Object should not exists as it has no more strong references"); + assertTrueOrFail(refs2.GetByKey("3").ObjectExists(), "Object should exists"); - assertTrueOrFail(refs2.GetByKey("1").ObjectExists(), "Object should exists"); - assertTrueOrFail(!refs2.GetByKey("2").ObjectExists(), "Object should not exists as it has no more strong - references"); assertTrueOrFail(refs2.GetByKey("3").ObjectExists(), "Object should exists"); - */ return INIT_SUCCEEDED; } From 032e8e7bcd2445093d72dcbcdc32ef2768b883ed Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 9 Feb 2023 18:23:28 +0100 Subject: [PATCH 16/42] WIP. Should fix errors in MT4, MT5 & C++ for TaskRunner. --- .github/workflows/compile-cpp.yml | 2 ++ Chart.struct.tf.h | 7 ++++++- Indicator/IndicatorData.h | 5 ++++- Storage/ValueStorage.history.h | 2 +- Storage/ValueStorage.indicator.h | 9 +++++++-- Tick/Tick.struct.h | 2 +- 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.github/workflows/compile-cpp.yml b/.github/workflows/compile-cpp.yml index 9a2d220e4..b68563cfe 100644 --- a/.github/workflows/compile-cpp.yml +++ b/.github/workflows/compile-cpp.yml @@ -43,6 +43,8 @@ jobs: with: compiler: gcc-latest - name: Compile ${{ matrix.file }} via emcc + if: always() run: emcc "${{ matrix.file }}" - name: Compile ${{ matrix.file }} via g++ + if: always() run: g++ -c "${{ matrix.file }}" diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index f392ef0d5..8eb01b41c 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -195,7 +195,12 @@ struct ChartTf { static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { switch (_tf) { case PERIOD_CURRENT: - return PeriodSeconds(_tf); +#ifdef __MQL__ + return ::PeriodSeconds(_tf); +#else + RUNTIME_ERROR("PeriodSeconds(PERIOD_CURRENT) is not implemented! Returning 0."); + return 0; +#endif case PERIOD_M1: // 1 minute. return 60; case PERIOD_M2: // 2 minutes (non-standard). diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index a08cdeae4..97fe40b4a 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -44,7 +44,6 @@ struct ExternInstantiateIndicatorBufferValueStorageDouble { #include "../Flags.h" #include "../Storage/IValueStorage.h" #include "../Storage/ItemsHistory.h" -#include "../Storage/ValueStorage.indicator.h" #include "../SymbolInfo.struct.h" #include "Indicator.enum.h" #include "IndicatorBase.h" @@ -1940,6 +1939,10 @@ int CopyBuffer(IndicatorData* _indi, int _mode, int _start, int _count, ValueSto return _num_copied; } +// clang-format off +#include "../Storage/ValueStorage.indicator.h" +// clang-format on + IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble( IndicatorData* _indi, int _mode) { return new IndicatorBufferValueStorage(_indi, _mode); diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index 73d64a74f..c78b69880 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -65,7 +65,7 @@ class HistoryValueStorage : public ValueStorage { /** * Initializes storage with given value. */ - virtual void Initialize(C _value) { + virtual void Initialize(C _value) override { Print("HistoryValueStorage does not implement Initialize()!"); DebugBreak(); } diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 58d4db243..06c125d80 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -32,6 +32,8 @@ // Forward declarations. class IndicatorData; +template +class HistoryValueStorage; // Includes. #include "../Indicator/IndicatorData.h" @@ -50,10 +52,13 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { * Constructor. */ IndicatorBufferValueStorage(IndicatorData* _indi_candle, int _mode = 0, bool _is_series = false) - : mode(_mode), HistoryValueStorage(_indi_candle) {} + : HistoryValueStorage(_indi_candle), mode(_mode) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - C Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_rel_shift)); } + C Fetch(int _rel_shift) override { + IndicatorData* _indi = THIS_ATTR indi_candle.Ptr(); + return _indi PTR_DEREF GetValue(mode, THIS_ATTR RealShift(_rel_shift)); + } }; diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index bda8880d5..fb27ecbfa 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -51,7 +51,7 @@ struct MqlTick { MqlTick() {} // Copy constructor. - MqlTick(){const MqlTick & r} { + MqlTick(const MqlTick &r) { time = r.time; ask = r.ask; bid = r.bid; From 11b6ce5a2184ff47f0c52ef10fc3f77f5b6ff157 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 16 Feb 2023 17:56:48 +0100 Subject: [PATCH 17/42] Added missing includes. --- Task/TaskAction.h | 1 + Task/TaskCondition.h | 1 + Task/TaskGetter.h | 1 + 3 files changed, 3 insertions(+) diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 56d053b99..5f48a66b7 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -35,6 +35,7 @@ #define TASK_ACTION_H // Includes. +#include "../DateTime.mqh" #include "../Std.h" #include "../Terminal.define.h" #include "TaskAction.enum.h" diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 4ccbdbf04..962c088bb 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -35,6 +35,7 @@ #define TASK_CONDITION_H // Includes. +#include "../DateTime.mqh" #include "../Std.h" #include "../Terminal.define.h" #include "TaskCondition.enum.h" diff --git a/Task/TaskGetter.h b/Task/TaskGetter.h index a7cddb16c..346add6f5 100644 --- a/Task/TaskGetter.h +++ b/Task/TaskGetter.h @@ -36,6 +36,7 @@ // Includes. //#include "TaskGetter.enum.h" +#include "../DateTime.mqh" #include "../Terminal.define.h" #include "TaskGetter.struct.h" #include "TaskGetterBase.h" From f78b9fd3dcf0ef559d9569e5c5c36925ded12ca4 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 16 Feb 2023 18:36:02 +0100 Subject: [PATCH 18/42] Addes required flags for emcc and gcc. --- .github/workflows/compile-cpp.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile-cpp.yml b/.github/workflows/compile-cpp.yml index b68563cfe..1aecc1521 100644 --- a/.github/workflows/compile-cpp.yml +++ b/.github/workflows/compile-cpp.yml @@ -44,7 +44,10 @@ jobs: compiler: gcc-latest - name: Compile ${{ matrix.file }} via emcc if: always() - run: emcc "${{ matrix.file }}" + run: > + emcc -s WASM=1 -s ENVIRONMENT=node -s EXIT_RUNTIME=0 -s NO_EXIT_RUNTIME=1 -s ASSERTIONS=1 -Wall -s + MODULARIZE=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 --bind -s EXPORTED_FUNCTIONS="[]" -g -std=c++17 + "${{ matrix.file }}" - name: Compile ${{ matrix.file }} via g++ if: always() - run: g++ -c "${{ matrix.file }}" + run: g++ -g -std=c++17 -c "${{ matrix.file }}" From a13a079532bbb0bf13797936be469660bd814bf9 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 17 Feb 2023 13:50:27 +0100 Subject: [PATCH 19/42] Made tests to continue even if one of them fails. --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 516d1a9b4..8f24b535e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -86,6 +86,7 @@ jobs: MtVersion: 4.0.0.1349 TestExpert: ${{ matrix.test }} RunOnError: show_logs 200 + if: always() timeout-minutes: 10 Scripts-MQL4: @@ -121,6 +122,7 @@ jobs: uses: fx31337/mql-tester-action@master with: Script: ${{ matrix.test }} + if: always() timeout-minutes: 10 Scripts-MQL4-Ignore: @@ -146,6 +148,7 @@ jobs: with: Script: ${{ matrix.test }} RunOnFail: "exit 0" + if: always() timeout-minutes: 10 Trade-Tests-MQL4: @@ -167,4 +170,5 @@ jobs: uses: fx31337/mql-tester-action@master with: Script: ${{ matrix.test }} + if: always() timeout-minutes: 10 From 2a5f72cb9bbf9f4aabc3983d72980c2d76ae82f7 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 17 Feb 2023 14:48:49 +0100 Subject: [PATCH 20/42] Added ToString() override to Indicator class, so IndicatorsTest will print the results. --- Indicator/Indicator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 8dc615bd7..20aa42c85 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -532,7 +532,7 @@ class Indicator : public IndicatorData { /** * Returns stored data in human-readable format. */ - // virtual bool ToString() = NULL; // @fixme? + string ToString() override { return EntryToString(); } /** * Whether we can and have to select mode when specifying data source. From a36e13553160d48e8fb9fedfa680c6fb085bc6f5 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 17 Feb 2023 19:37:14 +0100 Subject: [PATCH 21/42] WIP. Making FX's Indicator.cpp's to compile. --- Draw.mqh | 53 +++++++++------- DrawIndicator.mqh | 5 +- Platform.extern.h | 29 +++++++++ Platform.h | 70 +++++++++++++++++++++ Storage/ValueStorage.indicator.h | 1 - Terminal.enum.h | 105 +++++++++++++++++++++++++++++++ 6 files changed, 237 insertions(+), 26 deletions(-) diff --git a/Draw.mqh b/Draw.mqh index 0e637d088..c6c200af3 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -32,9 +32,11 @@ class Draw; // Includes. #include "Data.define.h" #include "Object.extern.h" -//#include "Platform.h" #include "Object.mqh" +#include "Platform.extern.h" #include "Terminal.define.h" +#include "Terminal.enum.h" +#include "Terminal.extern.h" #ifndef __MQL4__ // Defines macros (for MQL4 backward compatibility). @@ -46,7 +48,7 @@ class Draw; #define WINDOW_MAIN 0 -#ifdef __MQL5__ +#ifndef __MQL4__ #define OBJPROP_TIME1 ((ENUM_OBJECT_PROPERTY_INTEGER)0) #define OBJPROP_PRICE1 1 #define OBJPROP_TIME2 2 @@ -157,24 +159,6 @@ class Draw : public Object { return ::ObjectSet(name, prop_id, prop_value); #else // __MQL5__ switch (prop_id) { - // Datetime value to set/get first coordinate time part. - case OBJPROP_TIME1: - return ObjectSetInteger(chart_id, name, OBJPROP_TIME, (long)prop_value); - // Datetime value to set/get second coordinate time part. - case OBJPROP_TIME2: - return ObjectSetInteger(chart_id, name, OBJPROP_TIME, 1, (long)prop_value); - // Datetime value to set/get third coordinate time part. - case OBJPROP_TIME3: - return ObjectSetInteger(chart_id, name, OBJPROP_TIME, 2, (long)prop_value); - // Double value to set/get first coordinate price part. - case OBJPROP_PRICE1: - return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, (double)prop_value); - // Double value to set/get second coordinate price part. - case OBJPROP_PRICE2: - return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, 1, prop_value); - // Double value to set/get third coordinate price part. - case OBJPROP_PRICE3: - return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, 2, prop_value); case OBJPROP_ANGLE: // Double value to set/get angle object property in degrees. case OBJPROP_DEVIATION: // Double value to set/get deviation property for Standard deviation objects. case OBJPROP_SCALE: // Double value to set/get scale object property. @@ -203,6 +187,29 @@ class Draw : public Object { default: break; } + + // MQL4 enum values. + switch (prop_id) { + // Datetime value to set/get first coordinate time part. + case OBJPROP_TIME1: + return ObjectSetInteger(chart_id, name, OBJPROP_TIME, (long)prop_value); + // Datetime value to set/get second coordinate time part. + case OBJPROP_TIME2: + return ObjectSetInteger(chart_id, name, OBJPROP_TIME, 1, (long)prop_value); + // Datetime value to set/get third coordinate time part. + case OBJPROP_TIME3: + return ObjectSetInteger(chart_id, name, OBJPROP_TIME, 2, (long)prop_value); + // Double value to set/get first coordinate price part. + case OBJPROP_PRICE1: + return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, (double)prop_value); + // Double value to set/get second coordinate price part. + case OBJPROP_PRICE2: + return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, 1, prop_value); + // Double value to set/get third coordinate price part. + case OBJPROP_PRICE3: + return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, 2, prop_value); + } + return (false); #endif } @@ -261,7 +268,7 @@ class Draw : public Object { * Draw a vertical line. */ bool DrawVLine(string oname, datetime tm) { - bool result = Draw::ObjectCreate(NULL, oname, OBJ_VLINE, 0, tm, 0); + bool result = Draw::ObjectCreate(NULL_VALUE, oname, OBJ_VLINE, 0, tm, 0); if (!result) PrintFormat("%(): Can't create vertical line! code #", __FUNCTION__, GetLastError()); return (result); } @@ -270,7 +277,7 @@ class Draw : public Object { * Draw a horizontal line. */ bool DrawHLine(string oname, double value) { - bool result = Draw::ObjectCreate(NULL, oname, OBJ_HLINE, 0, 0, value); + bool result = Draw::ObjectCreate(NULL_VALUE, oname, OBJ_HLINE, 0, 0, value); if (!result) PrintFormat("%(): Can't create horizontal line! code #", __FUNCTION__, GetLastError()); return (result); } @@ -279,7 +286,7 @@ class Draw : public Object { * Delete a vertical line. */ bool DeleteVertLine(string oname) { - bool result = Draw::ObjectDelete(NULL, oname); + bool result = Draw::ObjectDelete(NULL_VALUE, oname); if (!result) PrintFormat("%(): Can't delete vertical line! code #", __FUNCTION__, GetLastError()); return (result); } diff --git a/DrawIndicator.mqh b/DrawIndicator.mqh index d1ec770be..02fbc3ec0 100644 --- a/DrawIndicator.mqh +++ b/DrawIndicator.mqh @@ -48,7 +48,7 @@ class DrawPoint { } // Special methods. DrawPoint(const DrawPoint& r) : time(r.time), value(r.value) {} - DrawPoint(datetime _time = NULL, double _value = 0) : time(_time), value(_value) {} + DrawPoint(datetime _time = 0, double _value = 0) : time(_time), value(_value) {} }; class DrawIndicator { @@ -124,7 +124,8 @@ class DrawIndicator { } if (!last_points.KeyExists(_name)) { - last_points.Set(_name, DrawPoint(_time, _value)); + DrawPoint _point(_time, _value); + last_points.Set(_name, _point); } else { DrawPoint* last_point = last_points.GetByKey(_name); diff --git a/Platform.extern.h b/Platform.extern.h index 943ec3bcd..8f6e8e7cf 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -27,6 +27,7 @@ // Includes. #include "Deal.enum.h" #include "Order.define.h" +#include "Terminal.enum.h" // Forward declarations. struct MqlTradeRequest; @@ -137,4 +138,32 @@ extern string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); extern string Symbol(); +extern string ObjectName(long _chart_id, int _pos, int _sub_window = -1, int _type = -1); + +extern int ObjectsTotal(long chart_id, int type = EMPTY, int window = -1); + +extern bool PlotIndexSetString(int plot_index, int prop_id, string prop_value); + +extern bool PlotIndexSetInteger(int plot_index, int prop_id, int prop_value); + +extern bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, long prop_value); + +extern bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, + long prop_value); + +extern bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value); + +extern bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, + double prop_value); + +extern bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1); +extern bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, + datetime _t2, double _p2); + +extern bool ObjectMove(long chart_id, string name, int point_index, datetime time, double price); + +extern bool ObjectDelete(long chart_id, string name); + +extern int ObjectFind(long chart_id, string name); + #endif diff --git a/Platform.h b/Platform.h index 90f8440cf..a2408db20 100644 --- a/Platform.h +++ b/Platform.h @@ -581,6 +581,76 @@ string Symbol() { return false; } +string ObjectName(long _chart_id, int _pos, int _sub_window = -1, int _type = -1) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return ""; +} + +int ObjectsTotal(long chart_id, int type = EMPTY, int window = -1) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +bool PlotIndexSetString(int plot_index, int prop_id, string prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool PlotIndexSetInteger(int plot_index, int prop_id, int prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, long prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, + long prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, + double prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, datetime _t2, + double _p2) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectMove(long chart_id, string name, int point_index, datetime time, double price) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectDelete(long chart_id, string name) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +int GetLastError() { return _LastError; } + +int ObjectFind(long chart_id, string name) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + #endif /** diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 06c125d80..54c249bf6 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -36,7 +36,6 @@ template class HistoryValueStorage; // Includes. -#include "../Indicator/IndicatorData.h" #include "ValueStorage.history.h" /** diff --git a/Terminal.enum.h b/Terminal.enum.h index 386caf381..5e56a0fe6 100644 --- a/Terminal.enum.h +++ b/Terminal.enum.h @@ -230,4 +230,109 @@ enum ENUM_UNINIT_REASON { REASON_INITFAILED = 8, REASON_CLOSE = 9, }; + +enum ENUM_DRAW_TYPE { + DRAW_NONE, + DRAW_LINE, + DRAW_SECTION, + DRAW_HISTOGRAM, + DRAW_HISTOGRAM2, + DRAW_ARROW, + DRAW_ZIGZAG, + DRAW_FILLING, + DRAW_BARS, + DRAW_CANDLES, + DRAW_COLOR_LINE, + DRAW_COLOR_SECTION, + DRAW_COLOR_HISTOGRAM, + DRAW_COLOR_HISTOGRAM2, + DRAW_COLOR_ARROW, + DRAW_COLOR_ZIGZAG, + DRAW_COLOR_BARS, + DRAW_COLOR_CANDLES +}; + +enum ENUM_PLOT_PROPERTY_INTEGER { + PLOT_ARROW, + PLOT_ARROW_SHIFT, + PLOT_DRAW_BEGIN, + PLOT_DRAW_TYPE, + PLOT_SHOW_DATA, + PLOT_SHIFT, + PLOT_LINE_STYLE, + PLOT_LINE_WIDTH, + PLOT_COLOR_INDEXES, + PLOT_LINE_COLOR +}; + +enum ENUM_PLOT_PROPERTY_DOUBLE { PLOT_EMPTY_VALUE }; + +enum ENUM_PLOT_PROPERTY_STRING { PLOT_LABEL }; + +enum ENUM_LINE_STYLE { STYLE_SOLID, STYLE_DASH, STYLE_DOT, STYLE_DASHDOT, STYLE_DASHDOTDOT }; + +enum ENUM_OBJECT_PROPERTY_INTEGER { + OBJPROP_COLOR, + OBJPROP_STYLE, + OBJPROP_WIDTH, + OBJPROP_BACK, + OBJPROP_ZORDER, + OBJPROP_FILL, + OBJPROP_HIDDEN, + OBJPROP_SELECTED, + OBJPROP_READONLY, + OBJPROP_TYPE, + OBJPROP_TIME, + OBJPROP_SELECTABLE, + OBJPROP_CREATETIME, + OBJPROP_LEVELS, + OBJPROP_LEVELCOLOR, + OBJPROP_LEVELSTYLE, + OBJPROP_LEVELWIDTH, + OBJPROP_ALIGN, + OBJPROP_FONTSIZE, + OBJPROP_RAY_LEFT, + OBJPROP_RAY_RIGHT, + OBJPROP_RAY, + OBJPROP_ELLIPSE, + OBJPROP_ARROWCODE, + OBJPROP_TIMEFRAMES, + OBJPROP_ANCHOR, + OBJPROP_XDISTANCE, + OBJPROP_YDISTANCE, + OBJPROP_DIRECTION, + OBJPROP_DEGREE, + OBJPROP_DRAWLINES, + OBJPROP_STATE, + OBJPROP_CHART_ID, + OBJPROP_XSIZE, + OBJPROP_YSIZE, + OBJPROP_XOFFSET, + OBJPROP_YOFFSET, + OBJPROP_PERIOD, + OBJPROP_DATE_SCALE, + OBJPROP_PRICE_SCALE, + OBJPROP_CHART_SCALE, + OBJPROP_BGCOLOR, + OBJPROP_CORNER, + OBJPROP_BORDER_TYPE, + OBJPROP_BORDER_COLOR +}; + +enum ENUM_OBJECT_PROPERTY_DOUBLE { OBJPROP_PRICE, OBJPROP_LEVELVALUE, OBJPROP_SCALE, OBJPROP_ANGLE, OBJPROP_DEVIATION }; + +enum ENUM_OBJECT_PROPERTY_STRING { + OBJPROP_NAME, + OBJPROP_TEXT, + OBJPROP_TOOLTIP, + OBJPROP_LEVELTEXT, + OBJPROP_FONT, + OBJPROP_BMPFILE, + OBJPROP_SYMBOL +}; + +enum ENUM_BORDER_TYPE { BORDER_FLAT, BORDER_RAISED, BORDER_SUNKEN }; + +enum ENUM_ALIGN_MODE { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT }; + #endif From ba94fa8e3c01604b1a751810126477b9e52d2b6b Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 21 Feb 2023 13:56:18 +0000 Subject: [PATCH 22/42] Sets job max-parallel to 4 as per API limits --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8f24b535e..e1c8d083f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -73,6 +73,7 @@ jobs: - SummaryReportTest - TickerTest - TradeTest + max-parallel: 4 steps: - uses: actions/download-artifact@v2 with: @@ -114,6 +115,7 @@ jobs: - TerminalTest - TimerTest - ValueStorageTest + max-parallel: 4 steps: - uses: actions/download-artifact@v2 with: From ccade1953784755550d182b1fd32b92556720a2d Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 23 Feb 2023 20:48:16 +0100 Subject: [PATCH 23/42] WIP. Using Indi_TickProvider to provide tick for Candle indicator and finally, for RSI or other one. --- Buffer/BufferTick.h | 8 +- Candle.struct.h | 53 ++++---- DictObject.mqh | 2 +- Indicator/Indicator.h | 65 +++++----- Indicator/IndicatorCandle.h | 40 +++--- Indicator/IndicatorCandle.provider.h | 4 +- Indicator/IndicatorData.h | 6 +- Indicator/IndicatorTf.h | 13 +- Indicator/IndicatorTf.provider.h | 4 +- Indicator/IndicatorTick.h | 28 ++-- Indicator/IndicatorTick.provider.h | 2 +- Indicator/tests/classes/IndicatorTfDummy.h | 2 +- Indicators/Indi_BWMFI.mqh | 12 +- Indicators/Indi_Envelopes.mqh | 6 +- Indicators/Indi_Fractals.mqh | 4 +- Indicators/Indi_Gator.mqh | 4 +- Indicators/Indi_Ichimoku.mqh | 13 +- Indicators/Tick/Indi_TickProvider.h | 142 +++++++++++++++++++++ Indicators/Tick/Indi_TickRandom.mqh | 4 +- Std.h | 13 ++ Storage/ObjectsCache.h | 2 +- Storage/ValueStorage.history.h | 8 ++ Storage/ValueStorage.indicator.h | 23 +++- Storage/ValueStorage.price_median.h | 4 +- Storage/ValueStorage.price_typical.h | 4 +- Storage/ValueStorage.price_weighted.h | 4 +- Storage/ValueStorage.spread.h | 4 +- Storage/ValueStorage.tick_volume.h | 4 +- Storage/ValueStorage.time.h | 4 +- Storage/ValueStorage.volume.h | 4 +- Tick/Tick.struct.h | 30 +++++ 31 files changed, 377 insertions(+), 139 deletions(-) create mode 100644 Indicators/Tick/Indi_TickProvider.h diff --git a/Buffer/BufferTick.h b/Buffer/BufferTick.h index 3aa8da911..f271905a1 100644 --- a/Buffer/BufferTick.h +++ b/Buffer/BufferTick.h @@ -30,6 +30,10 @@ #include "../Storage/IValueStorage.h" #include "../Tick/Tick.struct.h" +// Forward declarations. +template +class BufferTick; + // TV = Type of price stored by BufferTick. RV = Type of property to be retrieved from BufferTick. template class BufferTickValueStorage : ValueStorage { @@ -71,7 +75,7 @@ class BufferTickValueStorage : ValueStorage { /** * Returns number of values available to fetch (size of the values buffer). */ - int Size() override { return (int)buffer_tick.Size(); } + int Size() override { return (int)THIS_ATTR buffer_tick.Size(); } }; /** @@ -109,7 +113,7 @@ class BufferTick : public BufferStruct> { _vs_spread = NULL; _vs_volume = NULL; _vs_tick_volume = NULL; - SetOverflowListener(BufferStructOverflowListener, 10); + THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } public: diff --git a/Candle.struct.h b/Candle.struct.h index 6b2f502e3..1e0123a21 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -239,7 +239,7 @@ struct CandleOCTOHLC : CandleOHLC { // Struct constructor. CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, int _start_time = -1, int _length = 0, long _open_timestamp_ms = -1, long _close_timestamp_ms = -1, int _volume = 0) - : CandleOHLC(_open, _high, _low, _close), + : CandleOHLC(_open, _high, _low, _close), is_complete(true), start_time(_start_time), length(_length), @@ -254,6 +254,11 @@ struct CandleOCTOHLC : CandleOHLC { // Struct constructor. CandleOCTOHLC(const CandleOCTOHLC &r) { THIS_REF = r; } + // Virtual destructor. Required because of Emscripted warning, despite structure has no virtual methods: + // warning: destructor called on non-final 'CandleOCTOHLC' that has virtual functions but non-virtual + // destructor [-Wdelete-non-abstract-non-virtual-dtor] + virtual ~CandleOCTOHLC() {} + /** * Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price. */ @@ -264,7 +269,7 @@ struct CandleOCTOHLC : CandleOHLC { open_timestamp_ms = _timestamp_ms; close_timestamp_ms = _timestamp_ms; volume = _price != 0 ? 1 : 0; - open = high = low = close = _price; + THIS_ATTR open = THIS_ATTR high = THIS_ATTR low = THIS_ATTR close = _price; } /** @@ -280,19 +285,19 @@ struct CandleOCTOHLC : CandleOHLC { if (_is_init || _timestamp_ms < open_timestamp_ms) { open_timestamp_ms = _timestamp_ms; - open = _price; + THIS_ATTR open = _price; } if (_is_init || _timestamp_ms > close_timestamp_ms) { close_timestamp_ms = _timestamp_ms; - close = _price; + THIS_ATTR close = _price; } if (_is_init) { - high = _price; - low = _price; + THIS_ATTR high = _price; + THIS_ATTR low = _price; } else { - high = MathMax(high, _price); - low = MathMin(low, _price); + THIS_ATTR high = MathMax(THIS_ATTR high, _price); + THIS_ATTR low = MathMin(THIS_ATTR low, _price); } // Increasing candle's volume. ++volume; @@ -337,8 +342,8 @@ struct CandleOCTOHLC : CandleOHLC { * Returns text representation of candle. */ string ToString() { - return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", open, high, low, close, - is_complete ? "Complete" : "Incomplete", + return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", THIS_ATTR open, THIS_ATTR high, THIS_ATTR low, + THIS_ATTR close, is_complete ? "Complete" : "Incomplete", TimeToString(open_timestamp_ms, TIME_DATE | TIME_MINUTES | TIME_SECONDS), TimeToString(close_timestamp_ms, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); } @@ -352,18 +357,20 @@ struct CandleTOHLC : CandleOHLC { datetime time; // Struct constructors. CandleTOHLC(datetime _time = 0, T _open = 0, T _high = 0, T _low = 0, T _close = 0) - : time(_time), CandleOHLC(_open, _high, _low, _close) {} + : time(_time), CandleOHLC(_open, _high, _low, _close) {} // Getters. datetime GetTime() { return time; } // Serializers. SerializerNodeType Serialize(Serializer &s); // Converters. - string ToCSV() { return StringFormat("%d,%g,%g,%g,%g", time, open, high, low, close); } + string ToCSV() { + return StringFormat("%d,%g,%g,%g,%g", time, THIS_ATTR open, THIS_ATTR high, THIS_ATTR low, THIS_ATTR close); + } }; /* Method to serialize CandleEntry structure. */ template -SerializerNodeType CandleOHLC::Serialize(Serializer &s) { +SerializerNodeType CandleOHLC::Serialize(Serializer &s) { // s.Pass(THIS_REF, "time", TimeToString(time)); s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); @@ -374,25 +381,25 @@ SerializerNodeType CandleOHLC::Serialize(Serializer &s) { /* Method to serialize CandleEntry structure. */ template -SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { +SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { s.Pass(THIS_REF, "time", time); - s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "open", THIS_ATTR open, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "high", THIS_ATTR high, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "low", THIS_ATTR low, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close", THIS_ATTR close, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } /* Method to serialize CandleEntry structure. */ template -SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { +SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { s.Pass(THIS_REF, "is_complete", is_complete, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "open_timestamp_ms", open_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "close_timestamp_ms", close_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "open", THIS_ATTR open, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "high", THIS_ATTR high, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "low", THIS_ATTR low, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close", THIS_ATTR close, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "volume", volume, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } diff --git a/DictObject.mqh b/DictObject.mqh index c02437267..a19078a79 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -153,7 +153,7 @@ class DictObject : public DictBase { */ V* GetByKey(const K _key) { unsigned int position; - DictSlot* slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, _key, position); + DictSlot* slot = THIS_ATTR GetSlotByKey(this PTR_DEREF _DictSlots_ref, _key, position); if (!slot) return NULL; diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 20aa42c85..6f84b10e8 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -49,17 +49,6 @@ struct IndicatorParams; #include "Indicator.struct.serialize.h" #include "IndicatorData.h" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compatibility). -bool IndicatorBuffers(int _count) { return Indicator::SetIndicatorBuffers(_count); } -int IndicatorCounted(int _value = 0) { - static int prev_calculated = 0; - // https://docs.mql4.com/customind/indicatorcounted - prev_calculated = _value > 0 ? _value : prev_calculated; - return prev_calculated; -} -#endif - #ifdef __MQL5__ // Defines global functions (for MQL5 forward compatibility). template (GetModeCount()); + IndicatorDataEntry _entry = GetEntry(shift); + double value = _entry.GetMax(GetModeCount()); if (value > max) { max = value; max_idx = shift; @@ -183,7 +173,8 @@ class Indicator : public IndicatorData { int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); for (int shift = start_bar; shift <= last_bar; ++shift) { - double value = GetEntry(shift).GetMin(GetModeCount()); + IndicatorDataEntry _entry = GetEntry(shift); + double value = _entry.GetMin(GetModeCount()); if (value < min) { min = value; min_idx = shift; @@ -226,7 +217,7 @@ class Indicator : public IndicatorData { /* Buffer methods */ - virtual string CacheKey() { return GetFullName(); } + string CacheKey() override { return GetFullName(); } /** * Initializes a cached proxy between i*OnArray() methods and OnCalculate() @@ -358,9 +349,8 @@ class Indicator : public IndicatorData { * * When indicator values are not valid, returns empty signals. */ - IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) { - bool _is_valid = true; - IndicatorDataEntry _data[]; + IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) override { + ARRAY(IndicatorDataEntry, _data); if (!CopyEntries(_data, _count, _shift)) { // Some copied data is invalid, so returns empty signals. IndicatorSignal _signals(0); @@ -381,7 +371,7 @@ class Indicator : public IndicatorData { /** * Get more descriptive name of the indicator. */ - string GetDescriptiveName() { + string GetDescriptiveName() override { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); string name = iparams.name + " ("; @@ -393,8 +383,10 @@ class Indicator : public IndicatorData { name += "custom, "; break; case IDATA_INDICATOR: - name += "over " + GetDataSource().GetDescriptiveName() + ", "; + name += "over " + GetDataSource() PTR_DEREF GetDescriptiveName() + ", "; break; + default: + name += "unknown "; } name += IntegerToString(_max_modes) + (_max_modes == 1 ? " mode" : " modes"); @@ -407,14 +399,14 @@ class Indicator : public IndicatorData { /** * Sets name of the indicator. */ - void SetName(string _name) { iparams.SetName(_name); } + void SetName(string _name) override { iparams.SetName(_name); } /** * Sets indicator's handle. * * Note: Not supported in MT4. */ - void SetHandle(int _handle) { + void SetHandle(int _handle) override { istate.handle = _handle; istate.is_changed = true; } @@ -436,7 +428,7 @@ class Indicator : public IndicatorData { * @return * Returns true when the condition is met. */ - bool CheckCondition(ENUM_INDICATOR_CONDITION _cond, DataParamEntry& _args[]) { + bool CheckCondition(ENUM_INDICATOR_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { switch (_cond) { case INDI_COND_ENTRY_IS_MAX: // @todo: Add arguments, check if the entry value is max. @@ -461,7 +453,8 @@ class Indicator : public IndicatorData { // Indicator entry value is lesser than median. return false; default: - GetLogger().Error(StringFormat("Invalid indicator condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error( + StringFormat("Invalid indicator condition: %s at %s!", EnumToString(_cond), __FUNCTION_LINE__)); return false; } } @@ -480,18 +473,19 @@ class Indicator : public IndicatorData { * @return * Returns true when the action has been executed successfully. */ - virtual bool ExecuteAction(ENUM_INDICATOR_ACTION _action, DataParamEntry& _args[]) { + virtual bool ExecuteAction(ENUM_INDICATOR_ACTION _action, ARRAY_REF(DataParamEntry, _args)) { bool _result = true; long _arg1 = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; switch (_action) { case INDI_ACTION_CLEAR_CACHE: - _arg1 = _arg1 > 0 ? _arg1 : TimeCurrent(); + _arg1 = _arg1 != 0 ? _arg1 : (long)TimeCurrent(); Print("Action not yet implemented!"); DebugBreak(); // idata.Clear(_arg1); return true; default: - GetLogger().Error(StringFormat("Invalid Indicator action: %s!", EnumToString(_action), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error(StringFormat("Invalid Indicator action: %s at %s!", C_STR(EnumToString(_action)), + C_STR(__FUNCTION_LINE__))); return false; } return _result; @@ -537,7 +531,7 @@ class Indicator : public IndicatorData { /** * Whether we can and have to select mode when specifying data source. */ - virtual bool IsDataSourceModeSelectable() { return true; } + virtual bool IsDataSourceModeSelectable() override { return true; } /** * Checks if indicator entry is valid. @@ -652,7 +646,7 @@ class Indicator : public IndicatorData { DebugBreak(); } } - GetEntryAlter(_entry, _rel_shift); + THIS_ATTR GetEntryAlter(_entry, _rel_shift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { idata.Add(_entry, _bar_time); @@ -675,7 +669,7 @@ class Indicator : public IndicatorData { * This method allows user to modify the struct entry before it's added to cache. * This method is called on GetEntry() right after values are set. */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) { + void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) override { ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE)); _entry.AddFlags(_entry.GetDataTypeFlags(_dtype)); }; @@ -702,10 +696,21 @@ class Indicator : public IndicatorData { /** * Update indicator. */ - virtual bool Update() { + virtual bool Update() override { // @todo return false; }; }; +#ifndef __MQL4__ +// Defines global functions (for MQL4 backward compatibility). +bool IndicatorBuffers(int _count) { return Indicator::SetIndicatorBuffers(_count); } +int IndicatorCounted(int _value = 0) { + static int prev_calculated = 0; + // https://docs.mql4.com/customind/indicatorcounted + prev_calculated = _value > 0 ? _value : prev_calculated; + return prev_calculated; +} +#endif + #endif diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index d11686168..0f6c70ea6 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -84,8 +84,8 @@ class IndicatorCandle : public Indicator { */ void Init() { // Along with indexing by shift, we can also index via timestamp! - flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_INDI_CANDLE_MODE_ENTRY); + THIS_ATTR flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; + THIS_ATTR Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), (int)FINAL_INDI_CANDLE_MODE_ENTRY); } public: @@ -96,11 +96,11 @@ class IndicatorCandle : public Indicator { */ IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(INDI_CANDLE_HISTORY_SIZE) { + : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(INDI_CANDLE_HISTORY_SIZE) { Init(); } IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name), history(INDI_CANDLE_HISTORY_SIZE) { + : Indicator(_itype, _shift, _name), history(INDI_CANDLE_HISTORY_SIZE) { Init(); } @@ -154,13 +154,13 @@ class IndicatorCandle : public Indicator { int GetBars() override { // Will return number of bars prepended and appended to the history, // even if those bars were cleaned up because of history's candle limit. - return (int)history.GetPeakSize() - iparams.shift; + return (int)history.GetPeakSize() - THIS_ATTR iparams.shift; } /** * Returns current tick index (incremented every OnTick()). */ - int GetTickIndex() override { return GetTick() PTR_DEREF GetTickIndex(); } + int GetTickIndex() override { return THIS_ATTR GetTick() PTR_DEREF GetTickIndex(); } /** * Check if there is a new bar to parse. @@ -182,7 +182,7 @@ class IndicatorCandle : public Indicator { /** * Removes candle from the buffer. Used mainly for testing purposes. */ - void InvalidateCandle(int _abs_shift) { + void InvalidateCandle(int _abs_shift) override { if (_abs_shift != GetBarIndex()) { Print( "IndicatorCandle::InvalidateCandle() currently supports specyfing " @@ -198,7 +198,7 @@ class IndicatorCandle : public Indicator { /** * Returns time of the bar for a given shift. */ - virtual datetime GetBarTime(int _rel_shift = 0) { return history.GetItemTimeByShift(_rel_shift); } + datetime GetBarTime(int _rel_shift = 0) override { return history.GetItemTimeByShift(_rel_shift); } /** * Traverses source indicators' hierarchy and tries to find OHLC-featured @@ -216,7 +216,7 @@ class IndicatorCandle : public Indicator { BarOHLC _bar; CandleOCTOHLC _candle; - if (history.TryGetItemByShift(ToAbsShift(_rel_shift), _candle)) { + if (history.TryGetItemByShift(THIS_ATTR ToAbsShift(_rel_shift), _candle)) { _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.start_time); } @@ -262,7 +262,7 @@ class IndicatorCandle : public Indicator { */ IndicatorDataEntry GetEntry(int _shift = 0) override { ResetLastError(); - int _ishift = _shift + iparams.GetShift(); + int _ishift = _shift + THIS_ATTR iparams.GetShift(); CandleOCTOHLC _candle = history.GetItemByShift(_ishift); return CandleToEntry(_candle.GetTime(), _candle); } @@ -271,35 +271,35 @@ class IndicatorCandle : public Indicator { * Returns value storage for a given mode. */ IValueStorage* GetValueStorage(int _mode = 0) override { - if (_mode >= ArraySize(value_storages)) { - ArrayResize(value_storages, _mode + 1); + if (_mode >= ArraySize(THIS_ATTR value_storages)) { + ArrayResize(THIS_ATTR value_storages, _mode + 1); } - if (!value_storages[_mode].IsSet()) { + if (!THIS_ATTR value_storages[_mode].IsSet()) { // Buffer not yet created. switch (_mode) { case INDI_CANDLE_MODE_PRICE_OPEN: case INDI_CANDLE_MODE_PRICE_HIGH: case INDI_CANDLE_MODE_PRICE_LOW: case INDI_CANDLE_MODE_PRICE_CLOSE: - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + THIS_ATTR value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); break; case INDI_CANDLE_MODE_SPREAD: case INDI_CANDLE_MODE_TICK_VOLUME: case INDI_CANDLE_MODE_VOLUME: - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + THIS_ATTR value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); break; case INDI_CANDLE_MODE_TIME: - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + THIS_ATTR value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); break; case INDI_CANDLE_MODE_PRICE_MEDIAN: - value_storages[_mode] = new PriceMedianValueStorage(THIS_PTR); + THIS_ATTR value_storages[_mode] = new PriceMedianValueStorage(THIS_PTR); break; case INDI_CANDLE_MODE_PRICE_TYPICAL: - value_storages[_mode] = new PriceTypicalValueStorage(THIS_PTR); + THIS_ATTR value_storages[_mode] = new PriceTypicalValueStorage(THIS_PTR); break; case INDI_CANDLE_MODE_PRICE_WEIGHTED: - value_storages[_mode] = new PriceWeightedValueStorage(THIS_PTR); + THIS_ATTR value_storages[_mode] = new PriceWeightedValueStorage(THIS_PTR); break; default: Print("ERROR: Unsupported value storage mode ", _mode); @@ -307,7 +307,7 @@ class IndicatorCandle : public Indicator { } } - return value_storages[_mode].Ptr(); + return THIS_ATTR value_storages[_mode].Ptr(); } /** diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index b6737c945..ccecbd14e 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -47,8 +47,8 @@ class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider, ItemsHistoryItemProvider>>* _history, - long _time_ms, float _ask, float _bid) { + void OnTick(ItemsHistory, ItemsHistoryItemProvider>>* _history, long _time_ms, + float _ask, float _bid) { // Should be overrided. } diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 97fe40b4a..86bb1a443 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1216,7 +1216,7 @@ class IndicatorData : public IndicatorBase { * This method allows user to modify the struct entry before it's added to cache. * This method is called on GetEntry() right after values are set. */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry) {} + virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) {} // virtual ENUM_IDATA_VALUE_RANGE GetIDataValueRange() = NULL; @@ -1948,4 +1948,8 @@ IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIn return new IndicatorBufferValueStorage(_indi, _mode); } +#ifndef __MQL__ +int GetBarsFromStart(IndicatorData* _indi) { return _indi PTR_DEREF GetBars(); } +#endif + #endif // INDICATOR_DATA_H diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 577b21068..69f319706 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -50,7 +50,8 @@ class IndicatorTf : public IndicatorCandle(iparams.GetSecsPerCandle(), THIS_PTR)); + THIS_ATTR history.SetItemProvider( + new ItemsHistoryTfCandleProvider(THIS_ATTR iparams.GetSecsPerCandle(), THIS_PTR)); } public: @@ -60,7 +61,7 @@ class IndicatorTf : public IndicatorCandle { /** * Called when new tick was emitted from IndicatorTick-based source. */ - virtual void OnTick(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _time_ms, - float _ask, float _bid) { + void OnTick(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _time_ms, float _ask, + float _bid) { ++tick_index; // Print("IndicatorTf's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index a9a602440..29c298696 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -65,12 +65,12 @@ class IndicatorTick : public Indicator { */ void Init() { // We can't index by shift. - flags &= ~INDI_FLAG_INDEXABLE_BY_SHIFT; + THIS_ATTR flags &= ~INDI_FLAG_INDEXABLE_BY_SHIFT; // We can only index via timestamp. - flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; + THIS_ATTR flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; // Ask and Bid price. - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); + THIS_ATTR Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), (int)2); history.SetItemProvider(new ItemsHistoryTickProvider(THIS_PTR)); } @@ -82,17 +82,17 @@ class IndicatorTick : public Indicator { * Class constructor. */ IndicatorTick(string _symbol, const TS& _itparams, const IndicatorDataParams& _idparams, - IndicatorBase* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_itparams, _idparams, _indi_src, _indi_mode) { + IndicatorData* _indi_src = NULL, int _indi_mode = 0) + : Indicator(_itparams, _idparams, _indi_src, _indi_mode) { itparams = _itparams; if (_indi_src != NULL) { - SetDataSource(_indi_src, _indi_mode); + THIS_ATTR SetDataSource(_indi_src, _indi_mode); } symbol = _symbol; Init(); } IndicatorTick(string _symbol, ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name) { + : Indicator(_itype, _shift, _name) { symbol = _symbol; Init(); } @@ -115,12 +115,18 @@ class IndicatorTick : public Indicator { /** * Gets ask price for a given date and time. Return current ask price if _dt wasn't passed or is 0. */ - virtual double GetAsk(int _shift = 0) { return GetEntryValue(INDI_TICK_MODE_PRICE_ASK, _shift).Get(); } + double GetAsk(int _shift = 0) override { + IndicatorDataEntryValue _entry = GetEntryValue(INDI_TICK_MODE_PRICE_ASK, _shift); + return _entry.Get(); + } /** * Gets bid price for a given date and time. Return current bid price if _dt wasn't passed or is 0. */ - virtual double GetBid(int _shift = 0) { return GetEntryValue(INDI_TICK_MODE_PRICE_BID, _shift).Get(); } + double GetBid(int _shift = 0) override { + IndicatorDataEntryValue _entry = GetEntryValue(INDI_TICK_MODE_PRICE_BID, _shift); + return _entry.Get(); + } /** * Returns value storage of given kind. @@ -150,7 +156,7 @@ class IndicatorTick : public Indicator { /** * Checks whether indicator support given value storage type. */ - virtual bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { + bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { switch (_type) { case INDI_VS_TYPE_PRICE_ASK: case INDI_VS_TYPE_PRICE_BID: @@ -158,6 +164,8 @@ class IndicatorTick : public Indicator { case INDI_VS_TYPE_VOLUME: case INDI_VS_TYPE_TICK_VOLUME: return true; + default: + break; } return Indicator::HasSpecificValueStorage(_type); diff --git a/Indicator/IndicatorTick.provider.h b/Indicator/IndicatorTick.provider.h index 16659088a..660b6f0ab 100644 --- a/Indicator/IndicatorTick.provider.h +++ b/Indicator/IndicatorTick.provider.h @@ -33,7 +33,7 @@ #include "../Storage/ItemsHistory.h" /** - * Regenerates candles and updates exising candles from new ticks. Subclasses by IndicatorTf, IndicatorRenko. + * Regenerates candles and updates existing candles from new ticks. Derived by IndicatorTf, IndicatorRenko. */ template class ItemsHistoryTickProvider : public ItemsHistoryItemProvider> { diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 4e75818ed..458b4dfcc 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -45,7 +45,7 @@ class IndicatorTfDummy : public IndicatorTf { public: IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} IndicatorTfDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTf(_tf) {} - IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi = 0) : IndicatorTf(_tfi) {} + IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi = (ENUM_TIMEFRAMES_INDEX)0) : IndicatorTf(_tfi) {} string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index d9df71a79..aa18f3b17 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -138,14 +138,14 @@ class Indi_BWMFI : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ - Print(GetVolume(_shift), ", ", GetVolume(_shift + 1), " | ", GetValue(BWMFI_BUFFER, _shift), " > ", - GetValue(BWMFI_BUFFER, _shift + 1)); + Print(GetVolume(_rel_shift), ", ", GetVolume(_rel_shift + 1), " | ", GetValue(BWMFI_BUFFER, _rel_shift), + " > ", GetValue(BWMFI_BUFFER, _rel_shift + 1)); // @see: https://en.wikipedia.org/wiki/Market_facilitation_index - bool _vol_up = GetVolume(_shift) > GetVolume(_shift + 1); - bool _val_up = GetValue(BWMFI_BUFFER, _shift) > GetValue(BWMFI_BUFFER, _shift + 1); + bool _vol_up = GetVolume(_rel_shift) > GetVolume(_rel_shift + 1); + bool _val_up = GetValue(BWMFI_BUFFER, _rel_shift) > GetValue(BWMFI_BUFFER, _rel_shift + 1); double _histcolor = EMPTY_VALUE; switch (_vol_up) { case true: diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 7fc7ffd19..e5b813c06 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -237,11 +237,11 @@ class Indi_Envelopes : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ // The LINE_MAIN only exists in MQL4 for Envelopes. - _entry.values[LINE_MAIN] = GetValue((ENUM_LO_UP_LINE)LINE_MAIN, _shift); + _entry.values[LINE_MAIN] = GetValue((ENUM_LO_UP_LINE)LINE_MAIN, _rel_shift); #endif } diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index 6e920d173..6f93e25f1 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -124,8 +124,8 @@ class Indi_Fractals : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ // In MT4 line identifiers starts from 1, so populating also at 0. _entry.values[0] = _entry.values[LINE_UPPER]; diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index cbec2fac4..712fc8108 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -200,8 +200,8 @@ class Indi_Gator : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ // @todo: Can we calculate upper and lower histogram color in MT4? // @see: https://docs.mql4.com/indicators/igator diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index 42878ac52..32c546990 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -164,16 +164,17 @@ class Indi_Ichimoku : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); + int _abs_shift = ToAbsShift(_rel_shift); #ifdef __MQL4__ // In MQL4 value of LINE_TENKANSEN is 1 (not 0 as in MQL5), // so we are duplicating it. - _entry.values[0] = GetEntryValue(LINE_TENKANSEN, _shift); + _entry.values[0] = GetEntryValue(LINE_TENKANSEN, _abs_shift); #endif - _entry.values[LINE_SENKOUSPANA] = GetEntryValue(LINE_SENKOUSPANA, _shift + GetKijunSen()); - _entry.values[LINE_SENKOUSPANB] = GetEntryValue(LINE_SENKOUSPANB, _shift + GetKijunSen()); - _entry.values[LINE_CHIKOUSPAN] = GetEntryValue(LINE_CHIKOUSPAN, _shift + GetKijunSen()); + _entry.values[LINE_SENKOUSPANA] = GetEntryValue(LINE_SENKOUSPANA, _abs_shift + GetKijunSen()); + _entry.values[LINE_SENKOUSPANB] = GetEntryValue(LINE_SENKOUSPANB, _abs_shift + GetKijunSen()); + _entry.values[LINE_CHIKOUSPAN] = GetEntryValue(LINE_CHIKOUSPAN, _abs_shift + GetKijunSen()); } /** diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h new file mode 100644 index 000000000..2cfc24437 --- /dev/null +++ b/Indicators/Tick/Indi_TickProvider.h @@ -0,0 +1,142 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Tick-based indicator which you may feed with data. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../../Indicator/IndicatorTick.h" +#include "../../Indicator/IndicatorTick.provider.h" + +// Structs. +// Params for MT patform's tick-based indicator. +struct Indi_TickProviderParams : IndicatorParams { + Indi_TickProviderParams() : IndicatorParams(INDI_TICK_RANDOM) {} +}; + +// MT platform's tick-based indicator. +class Indi_TickProvider : public IndicatorTick> { + private: + int current_index; + ARRAY(TickTAB, buffer); + + public: + Indi_TickProvider(Indi_TickProviderParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTick(_p.symbol, _p, + IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_TickProvider(string _symbol = NULL_STRING, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0, string _name = "") + : IndicatorTick(_symbol, Indi_TickProviderParams(), + IndicatorDataParams(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), _indi_src) { + Init(); + } + + /** + * Initializes the class. + */ + void Init() { current_index = 0; } + + string GetName() override { return "Indi_TickProvider"; } + + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + unsigned int GetSuitableDataSourceTypes() override { return INDI_SUITABLE_DS_TYPE_EXPECT_NONE; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } + + /** + * Returns the indicator's struct entry for the given shift. + */ + IndicatorDataEntry GetEntry(int _index = 0) override { + IndicatorDataEntry _default; + return _default; + } + + /** + * Fetches historic ticks for a given time range. + */ + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) override { + // No history. + return false; + } + + /** + * Feeds ticks buffer with given array of new ticks. + */ + void Feed(ARRAY_REF(TickTAB, _ticks)) { + for (int i = 0; i < ArraySize(_ticks); ++i) { + ArrayPush(buffer, _ticks[i]); + } + } + + int BufferSize() { return ArraySize(buffer); } + + void OnTick(int _global_tick_index) override { + if (current_index >= ArraySize(buffer)) { + // No more ticks. + return; + } + + TickTAB _tick = buffer[current_index++]; + + IndicatorDataEntry _entry(TickToEntry(_tick.GetTimestamp(), _tick)); + EmitEntry(_entry); + // Appending tick into the history. + AppendEntry(_entry); + } +}; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(Indi_TickProviderBase) { + emscripten::class_>>( + "IndiTickProviderBase"); +} + +EMSCRIPTEN_BINDINGS(Indi_TickProvider) { + emscripten::class_< + Indi_TickProvider, + emscripten::base>>>( + "Indi_TickProvider") + //.smart_ptr>("Ref") + .constructor<>() + .function("BufferSize", &Indi_TickProvider::BufferSize) + .function("Feed", &Indi_TickProvider::Feed); +} + +#endif diff --git a/Indicators/Tick/Indi_TickRandom.mqh b/Indicators/Tick/Indi_TickRandom.mqh index 56e8148c5..5f131e6dd 100644 --- a/Indicators/Tick/Indi_TickRandom.mqh +++ b/Indicators/Tick/Indi_TickRandom.mqh @@ -93,8 +93,8 @@ class Indi_TickRandom : public IndicatorTick _tick(, _bid); - IndicatorDataEntry _entry(TickToEntry(_time, _tick)); + TickAB _tick(_ask, _bid); + IndicatorDataEntry _entry(TickToEntry(TimeCurrent(), _tick)); EmitEntry(_entry); // Appending tick into the history. AppendEntry(_entry); diff --git a/Std.h b/Std.h index d214d3bf2..190ad3af6 100644 --- a/Std.h +++ b/Std.h @@ -230,6 +230,19 @@ class _cpp_array { void setIsSeries(bool _isSeries) { m_isSeries = _isSeries; } }; +#ifdef EMSCRIPTEN +#include + +#define REGISTER_ARRAY_OF(N, T, D) \ + EMSCRIPTEN_BINDINGS(N) { \ + emscripten::class_<_cpp_array>(D) \ + .constructor() \ + .function("Push", &_cpp_array::push) \ + .function("Size", &_cpp_array::size); \ + } + +#endif + template class _cpp_array; #endif diff --git a/Storage/ObjectsCache.h b/Storage/ObjectsCache.h index 0ca816fba..bb6cf6fac 100644 --- a/Storage/ObjectsCache.h +++ b/Storage/ObjectsCache.h @@ -42,7 +42,7 @@ class DictStructDestructable : public DictStruct { * Destructor. */ ~DictStructDestructable() { - for (DictStructIterator iter = Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator iter = THIS_ATTR Begin(); iter.IsValid(); ++iter) { delete iter.Value(); } } diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index c78b69880..722bf422e 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -38,6 +38,10 @@ class IndicatorData; template class ValueStorage; +#ifndef __MQL__ +extern int GetBarsFromStart(IndicatorData* _indi); +#endif + /** * Storage for direct access to indicator's buffer for a given mode. */ @@ -90,7 +94,11 @@ class HistoryValueStorage : public ValueStorage { if (!indi_candle.ObjectExists()) { return 0; } +#ifdef __MQL__ return indi_candle REF_DEREF GetBars(); +#else + return GetBarsFromStart(indi_candle.Ptr()); +#endif } /** diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 54c249bf6..e01ecdc42 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -31,7 +31,6 @@ #endif // Forward declarations. -class IndicatorData; template class HistoryValueStorage; @@ -53,11 +52,27 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { IndicatorBufferValueStorage(IndicatorData* _indi_candle, int _mode = 0, bool _is_series = false) : HistoryValueStorage(_indi_candle), mode(_mode) {} - /** - * Fetches value from a given shift. Takes into consideration as-series flag. - */ +/** + * Fetches value from a given shift. Takes into consideration as-series flag. + */ +#ifdef __MQL__ C Fetch(int _rel_shift) override { IndicatorData* _indi = THIS_ATTR indi_candle.Ptr(); return _indi PTR_DEREF GetValue(mode, THIS_ATTR RealShift(_rel_shift)); } +#else + C Fetch(int _rel_shift) override; +#endif }; + +// clang-format off +#include "../Indicator/IndicatorData.h" +// clang-format on + +#ifndef __MQL__ +template +C IndicatorBufferValueStorage::Fetch(int _rel_shift) { + IndicatorData* _indi = THIS_ATTR indi_candle.Ptr(); + return _indi PTR_DEREF GetValue(mode, THIS_ATTR RealShift(_rel_shift)); +} +#endif \ No newline at end of file diff --git a/Storage/ValueStorage.price_median.h b/Storage/ValueStorage.price_median.h index 3752af417..890ffee3e 100644 --- a/Storage/ValueStorage.price_median.h +++ b/Storage/ValueStorage.price_median.h @@ -39,12 +39,12 @@ class PriceMedianValueStorage : public HistoryValueStorage { /** * Constructor. */ - PriceMedianValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + PriceMedianValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - PriceMedianValueStorage(PriceMedianValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + PriceMedianValueStorage(PriceMedianValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.price_typical.h b/Storage/ValueStorage.price_typical.h index 4bf51f786..fe99eb869 100644 --- a/Storage/ValueStorage.price_typical.h +++ b/Storage/ValueStorage.price_typical.h @@ -36,12 +36,12 @@ class PriceTypicalValueStorage : public HistoryValueStorage { /** * Constructor. */ - PriceTypicalValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + PriceTypicalValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - PriceTypicalValueStorage(PriceTypicalValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + PriceTypicalValueStorage(PriceTypicalValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.price_weighted.h b/Storage/ValueStorage.price_weighted.h index 17818583e..91029acc4 100644 --- a/Storage/ValueStorage.price_weighted.h +++ b/Storage/ValueStorage.price_weighted.h @@ -36,12 +36,12 @@ class PriceWeightedValueStorage : public HistoryValueStorage { /** * Constructor. */ - PriceWeightedValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + PriceWeightedValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - PriceWeightedValueStorage(PriceWeightedValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + PriceWeightedValueStorage(PriceWeightedValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.spread.h b/Storage/ValueStorage.spread.h index 890b168a1..17510321e 100644 --- a/Storage/ValueStorage.spread.h +++ b/Storage/ValueStorage.spread.h @@ -36,12 +36,12 @@ class SpreadValueStorage : public HistoryValueStorage { /** * Constructor. */ - SpreadValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + SpreadValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - SpreadValueStorage(SpreadValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + SpreadValueStorage(SpreadValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.tick_volume.h b/Storage/ValueStorage.tick_volume.h index cc6dd5ec6..f2f6d699b 100644 --- a/Storage/ValueStorage.tick_volume.h +++ b/Storage/ValueStorage.tick_volume.h @@ -36,12 +36,12 @@ class TickVolumeValueStorage : public HistoryValueStorage { /** * Constructor. */ - TickVolumeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + TickVolumeValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - TickVolumeValueStorage(TickVolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + TickVolumeValueStorage(TickVolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.time.h b/Storage/ValueStorage.time.h index 67461a958..c2bdf2bf1 100644 --- a/Storage/ValueStorage.time.h +++ b/Storage/ValueStorage.time.h @@ -37,12 +37,12 @@ class TimeValueStorage : public HistoryValueStorage { /** * Constructor. */ - TimeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + TimeValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - TimeValueStorage(TimeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + TimeValueStorage(TimeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.volume.h b/Storage/ValueStorage.volume.h index 68d5320ba..17072e40e 100644 --- a/Storage/ValueStorage.volume.h +++ b/Storage/ValueStorage.volume.h @@ -36,12 +36,12 @@ class VolumeValueStorage : public HistoryValueStorage { /** * Constructor. */ - VolumeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + VolumeValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - VolumeValueStorage(VolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + VolumeValueStorage(VolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index fb27ecbfa..2a4b5df7f 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -76,6 +76,8 @@ struct TickAB { TickAB(MqlTick &_tick) : ask((T)_tick.ask), bid((T)_tick.bid) {} }; +struct DoubleTickAB : TickAB {}; + /** * Structure for storing ask and bid prices of the symbol. */ @@ -92,6 +94,11 @@ struct TickTAB : TickAB { */ long GetTimeMs() { return time_ms; } + /** + * Returns time as timestamp (in seconds). + */ + long GetTimestamp() { return time_ms; } + /** * Method used by ItemsHistory. */ @@ -100,3 +107,26 @@ struct TickTAB : TickAB { return 0; } }; + +struct DoubleTickTAB : TickTAB {}; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TickAB) { + emscripten::value_object>("TickAB") + .field("ask", &TickAB::ask) + .field("bid", &TickAB::bid); +} + +EMSCRIPTEN_BINDINGS(TickTAB) { + // emscripten::value_object, emscripten::base>>("TickTABDouble") + emscripten::value_object>("TickTAB") + .field("ask", &TickAB::ask) + .field("bid", &TickAB::bid) + .field("time_ms", &TickTAB::time_ms); +} + +REGISTER_ARRAY_OF(ArrayTickTABDouble, TickTAB, "TickTABArray"); + +#endif From 16ebdc4ef4c3db51969b980fbe92fc76c60f3726 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 24 Feb 2023 15:10:08 +0100 Subject: [PATCH 24/42] Fixing MQL4 errors. --- Candle.struct.h | 14 ++++++++++++++ Storage/ValueStorage.indicator.h | 2 +- Tick/Tick.struct.h | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Candle.struct.h b/Candle.struct.h index 1e0123a21..360e5d1da 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -257,7 +257,9 @@ struct CandleOCTOHLC : CandleOHLC { // Virtual destructor. Required because of Emscripted warning, despite structure has no virtual methods: // warning: destructor called on non-final 'CandleOCTOHLC' that has virtual functions but non-virtual // destructor [-Wdelete-non-abstract-non-virtual-dtor] +#ifndef __MQL__ virtual ~CandleOCTOHLC() {} +#endif /** * Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price. @@ -370,7 +372,11 @@ struct CandleTOHLC : CandleOHLC { /* Method to serialize CandleEntry structure. */ template +#ifdef __MQL__ +SerializerNodeType CandleOHLC::Serialize(Serializer &s) { +#else SerializerNodeType CandleOHLC::Serialize(Serializer &s) { +#endif // s.Pass(THIS_REF, "time", TimeToString(time)); s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); @@ -381,7 +387,11 @@ SerializerNodeType CandleOHLC::Serialize(Serializer &s) { /* Method to serialize CandleEntry structure. */ template +#ifdef __MQL__ +SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { +#else SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { +#endif s.Pass(THIS_REF, "time", time); s.Pass(THIS_REF, "open", THIS_ATTR open, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "high", THIS_ATTR high, SERIALIZER_FIELD_FLAG_DYNAMIC); @@ -392,7 +402,11 @@ SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { /* Method to serialize CandleEntry structure. */ template +#ifdef __MQL__ +SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { +#else SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { +#endif s.Pass(THIS_REF, "is_complete", is_complete, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "open_timestamp_ms", open_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "close_timestamp_ms", close_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index e01ecdc42..eb52f8b21 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -75,4 +75,4 @@ C IndicatorBufferValueStorage::Fetch(int _rel_shift) { IndicatorData* _indi = THIS_ATTR indi_candle.Ptr(); return _indi PTR_DEREF GetValue(mode, THIS_ATTR RealShift(_rel_shift)); } -#endif \ No newline at end of file +#endif diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 2a4b5df7f..4493d31ce 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -31,6 +31,7 @@ // Includes. #include "../DateTime.extern.h" +#include "../Std.h" #ifndef __MQL__ /** From 65b8f294cf927570686bcd925d19ad7e537d12e4 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Sat, 25 Feb 2023 04:51:25 +0100 Subject: [PATCH 25/42] WIP. Fixing MT4 errors. --- Indicator/Indicator.define.h | 52 ++++++++++++++--------------- Indicator/IndicatorData.h | 11 +++--- Indicator/IndicatorData.struct.h | 4 ++- Indicators/Indi_AC.mqh | 21 +++++++----- Indicators/Indi_RSI.mqh | 36 -------------------- Indicators/Tick/Indi_TickProvider.h | 2 +- Indicators/Tick/Indi_TickRandom.mqh | 2 +- Object.enum.h | 3 ++ Object.extern.h | 3 ++ Platform.extern.h | 3 ++ Platform.h | 16 +++++---- Socket.mqh | 4 +-- Storage/Objects.h | 8 ++--- SymbolInfo.struct.static.h | 5 ++- 14 files changed, 77 insertions(+), 93 deletions(-) diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index d0e2900df..26d7142ea 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -100,32 +100,32 @@ #define EMPTY_VALUE DBL_MAX #endif -#define INDICATOR_BUILTIN_CALL_AND_RETURN(NATIVE_METHOD_CALL, MODE, SHIFT) \ - int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; \ - double _res[]; \ - ResetLastError(); \ - if (_handle == NULL || _handle == INVALID_HANDLE) { \ - if ((_handle = NATIVE_METHOD_CALL) == INVALID_HANDLE) { \ - SetUserError(ERR_USER_INVALID_HANDLE); \ - return EMPTY_VALUE; \ - } else if (Object::IsValid(_obj)) { \ - _obj.SetHandle(_handle); \ - } \ - } \ - if (Terminal::IsVisualMode()) { \ - /* To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), */ \ - /* we check the number of calculated data only in visual mode. */ \ - int _bars_calc = BarsCalculated(_handle); \ - if (GetLastError() > 0) { \ - return EMPTY_VALUE; \ - } else if (_bars_calc <= 2) { \ - SetUserError(ERR_USER_INVALID_BUFF_NUM); \ - return EMPTY_VALUE; \ - } \ - } \ - if (CopyBuffer(_handle, MODE, SHIFT, 1, _res) < 0) { \ - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; \ - } \ +#define INDICATOR_BUILTIN_CALL_AND_RETURN(NATIVE_METHOD_CALL, MODE, SHIFT) \ + int _handle = Object::IsValid(_obj) ? _obj PTR_DEREF Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : 0; \ + ARRAY(double, _res); \ + ResetLastError(); \ + if (_handle == 0 || _handle == INVALID_HANDLE) { \ + if ((_handle = NATIVE_METHOD_CALL) == INVALID_HANDLE) { \ + SetUserError(ERR_USER_INVALID_HANDLE); \ + return EMPTY_VALUE; \ + } else if (Object::IsValid(_obj)) { \ + _obj.SetHandle(_handle); \ + } \ + } \ + if (Terminal::IsVisualMode()) { \ + /* To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), */ \ + /* we check the number of calculated data only in visual mode. */ \ + int _bars_calc = BarsCalculated(_handle); \ + if (GetLastError() > 0) { \ + return EMPTY_VALUE; \ + } else if (_bars_calc <= 2) { \ + SetUserError(ERR_USER_INVALID_BUFF_NUM); \ + return EMPTY_VALUE; \ + } \ + } \ + if (CopyBuffer(_handle, MODE, SHIFT, 1, _res) < 0) { \ + return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; \ + } \ return _res[0]; #define INDI_REQUIRE_BARS_OR_RETURN(_indi, _period, _ret) \ diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 86bb1a443..ad1e5dc55 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1351,8 +1351,7 @@ class IndicatorData : public IndicatorBase { * Returns value storage to be used for given applied price or applied price overriden by target indicator via * SetDataSourceAppliedPrice(). */ - virtual ValueStorage* GetSpecificAppliedPriceValueStorage(ENUM_APPLIED_PRICE _ap, - IndicatorData* _target = nullptr) { + ValueStorage* GetSpecificAppliedPriceValueStorage(ENUM_APPLIED_PRICE _ap, IndicatorData* _target = nullptr) { if (_target != nullptr) { if (_target PTR_DEREF GetDataSourceAppliedType() != INDI_VS_TYPE_NONE) { // User wants to use custom value storage type as applied price, so we forcefully override AP given as the @@ -1448,15 +1447,13 @@ class IndicatorData : public IndicatorBase { /** * Fetches historic ticks for a given time range. */ - virtual bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { - return false; - } + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { return false; } /** * Fetches historic ticks for a given start time and minimum number of tick to retrieve. */ - virtual bool FetchHistoryByStartTimeAndCount(long _from_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _min_count, - ARRAY_REF(TickTAB, _out_ticks)) { + bool FetchHistoryByStartTimeAndCount(long _from_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _min_count, + ARRAY_REF(TickTAB, _out_ticks)) { // Print("FetchHistoryByStartTimeAndCount:"); // Print("- Requested _from_ms = ", _from_ms, ", _dir = ", EnumToString(_dir), ", _min_count = ", _min_count); diff --git a/Indicator/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h index 549c44219..66f137cf1 100644 --- a/Indicator/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -30,6 +30,7 @@ #define STRUCT_ENUM_INDICATOR_STATE_PROP STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) // Includes. +#include "../Serializer/SerializerConversions.h" #include "../Serializer/SerializerNode.enum.h" #include "IndicatorData.enum.h" @@ -389,7 +390,8 @@ struct IndicatorDataEntry { int _asize = ArraySize(values); string _result = ""; for (int i = 0; i < _asize; i++) { - _result += StringFormat("%s%s", (string)values[i].Get(), i < _asize ? "," : ""); + _result += + StringFormat("%s%s", C_STR(SerializerConversions::ValueToString(values[i].Get())), i < _asize ? "," : ""); } return _result; } diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index d51e1e7b2..ce3b3fb78 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -20,18 +20,15 @@ * */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. #include "../BufferStruct.mqh" #include "../Indicator/Indicator.h" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compability). -double iAC(string _symbol, int _tf, int _shift) { - ResetLastError(); - return Indi_AC::iAC(_symbol, (ENUM_TIMEFRAMES)_tf, _shift); -} -#endif - // Structs. struct IndiACParams : IndicatorParams { // Struct constructor. @@ -139,3 +136,11 @@ class Indi_AC : public Indicator { return _ptr; } }; + +#ifndef __MQL4__ +// Defines global functions (for MQL4 backward compability). +double iAC(string _symbol, int _tf, int _shift) { + ResetLastError(); + return Indi_AC::iAC(_symbol, (ENUM_TIMEFRAMES)_tf, _shift); +} +#endif diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 5aacd6181..2c4b409be 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -23,12 +23,6 @@ // Includes. #include "../DictStruct.mqh" #include "../Indicator/Indicator.h" -#include "Indi_Bands.mqh" -#include "Indi_CCI.mqh" -#include "Indi_Envelopes.mqh" -#include "Indi_MA.mqh" -#include "Indi_Momentum.mqh" -#include "Indi_StdDev.mqh" #include "Price/Indi_Price.mqh" #ifndef __MQL4__ @@ -336,34 +330,4 @@ class Indi_RSI : public Indicator { } return _value; } - - /** - * Provides built-in indicators whose can be used as data source. - */ - virtual IndicatorData *FetchDataSource(ENUM_INDICATOR_TYPE _id) { - if (_id == INDI_BANDS) { - IndiBandsParams bands_params; - return new Indi_Bands(bands_params); - } else if (_id == INDI_CCI) { - IndiCCIParams cci_params; - return new Indi_CCI(cci_params); - } else if (_id == INDI_ENVELOPES) { - IndiEnvelopesParams env_params; - return new Indi_Envelopes(env_params); - } else if (_id == INDI_MOMENTUM) { - IndiMomentumParams mom_params; - return new Indi_Momentum(mom_params); - } else if (_id == INDI_MA) { - IndiMAParams ma_params; - return new Indi_MA(ma_params); - } else if (_id == INDI_RSI) { - IndiRSIParams _rsi_params; - return new Indi_RSI(_rsi_params); - } else if (_id == INDI_STDDEV) { - IndiStdDevParams stddev_params; - return new Indi_StdDev(stddev_params); - } - - return IndicatorData::FetchDataSource(_id); - } }; diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h index 2cfc24437..389c6b2b1 100644 --- a/Indicators/Tick/Indi_TickProvider.h +++ b/Indicators/Tick/Indi_TickProvider.h @@ -89,7 +89,7 @@ class Indi_TickProvider : public IndicatorTick, _out_ticks)) override { + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { // No history. return false; } diff --git a/Indicators/Tick/Indi_TickRandom.mqh b/Indicators/Tick/Indi_TickRandom.mqh index 5f131e6dd..9d5763bf8 100644 --- a/Indicators/Tick/Indi_TickRandom.mqh +++ b/Indicators/Tick/Indi_TickRandom.mqh @@ -85,7 +85,7 @@ class Indi_TickRandom : public IndicatorTick, _out_ticks)) { + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { // No history. return false; } diff --git a/Object.enum.h b/Object.enum.h index 68d22f513..04d83c42b 100644 --- a/Object.enum.h +++ b/Object.enum.h @@ -26,6 +26,9 @@ */ #ifndef __MQLBUILD__ + +#pragma once + // Used for checking the type of the object pointer. // @docs // - https://docs.mql4.com/constants/namedconstants/enum_pointer_type diff --git a/Object.extern.h b/Object.extern.h index 8490e9499..68f44de50 100644 --- a/Object.extern.h +++ b/Object.extern.h @@ -28,6 +28,9 @@ #pragma once +// Includes. +#include "Object.enum.h" + template X* GetPointer(X& value) { return &value; diff --git a/Platform.extern.h b/Platform.extern.h index 8f6e8e7cf..fabde3d0b 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -25,7 +25,10 @@ #pragma once // Includes. +#include "Account/Account.enum.h" +#include "Data.define.h" #include "Deal.enum.h" +#include "Object.extern.h" #include "Order.define.h" #include "Terminal.enum.h" diff --git a/Platform.h b/Platform.h index a2408db20..349817853 100644 --- a/Platform.h +++ b/Platform.h @@ -359,7 +359,7 @@ class Platform { }; bool Platform::initialized = false; -DateTime Platform::time = 0; +DateTime Platform::time = (datetime)0; unsigned int Platform::time_flags = 0; bool Platform::time_clear_flags = true; int Platform::global_tick_index = 0; @@ -385,9 +385,13 @@ int BarsCalculated(int indicator_handle) { return Platform::BarsCalculated(indic */ int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; } -unsigned long PositionGetTicket(int _index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); } +unsigned long PositionGetTicket(int _index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); @@ -573,20 +577,20 @@ long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id) { string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); - return false; + return ""; } string Symbol() { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); - return false; + return ""; } -string ObjectName(long _chart_id, int _pos, int _sub_window = -1, int _type = -1) { +string ObjectName(long _chart_id, int _pos, int _sub_window, int _type) { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); return ""; } -int ObjectsTotal(long chart_id, int type = EMPTY, int window = -1) { +int ObjectsTotal(long chart_id, int type, int window) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } diff --git a/Socket.mqh b/Socket.mqh index be44e54f6..e1023634d 100644 --- a/Socket.mqh +++ b/Socket.mqh @@ -121,7 +121,7 @@ class Socket { return true; #else return false; -#endif; +#endif } /** @@ -184,7 +184,7 @@ class Socket { } #else return false; -#endif; +#endif } /** diff --git a/Storage/Objects.h b/Storage/Objects.h index 3be674f54..3af152e0f 100644 --- a/Storage/Objects.h +++ b/Storage/Objects.h @@ -49,12 +49,12 @@ class Objects { * Tries to retrieve pointer to object for a given key. Returns true if object did exist. */ static bool TryGet(CONST_REF_TO(string) key, C*& out_ptr) { - int position; - if (!GetObjects().KeyExists(key, position)) { + unsigned int position; + if (!GetObjects() PTR_DEREF KeyExists(key, position)) { out_ptr = NULL; return false; } else { - out_ptr = GetObjects().GetByPos(position).Ptr(); + out_ptr = GetObjects() PTR_DEREF GetByPos(position).Ptr(); return true; } } @@ -64,7 +64,7 @@ class Objects { */ static C* Set(CONST_REF_TO(string) key, C* ptr) { Ref _ref(ptr); - GetObjects().Set(key, _ref); + GetObjects() PTR_DEREF Set(key, _ref); return ptr; } }; diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index 72bb18844..5100e7f70 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -27,7 +27,10 @@ #include "MQL5.mqh" #include "Order.enum.h" +#include "Platform.extern.h" #include "Std.h" +#include "SymbolInfo.enum.h" +#include "SymbolInfo.extern.h" #include "Tick/Tick.struct.h" /** @@ -38,7 +41,7 @@ struct SymbolInfoStatic { /** * Get the current symbol pair from the current chart. */ - static string GetCurrentSymbol() { return _Symbol; } + static string GetCurrentSymbol() { return ::Symbol(); } /** * Updates and gets the latest tick prices. From 478b640130a922d1a0bca056a8eb14b2c7a4f75e Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 1 Mar 2023 19:10:02 +0100 Subject: [PATCH 26/42] WIP. Testing RSI over IndicatorTfDummy over Indi_TickProvider. Now we need to implement missing extern functions. --- Array.extern.h | 5 +++ Indicator/IndicatorData.h | 26 +++++++++++--- Indicator/tests/classes/Indicators.h | 8 +++-- Indicators/Indi_Drawer.mqh | 4 +-- Indicators/Indi_PriceFeeder.mqh | 6 ++-- Indicators/Indi_RSI.mqh | 54 ++++++++++++++++------------ Indicators/Price/Indi_Price.mqh | 24 ++++++------- Indicators/Tick/Indi_TickMt.mqh | 6 ++-- Indicators/Tick/Indi_TickProvider.h | 6 ++-- Indicators/Tick/Indi_TickRandom.mqh | 4 ++- Platform.h | 41 ++++++++++++++++++--- SymbolInfo.extern.h | 8 ++++- 12 files changed, 135 insertions(+), 57 deletions(-) diff --git a/Array.extern.h b/Array.extern.h index 821a5c751..675b26ca1 100644 --- a/Array.extern.h +++ b/Array.extern.h @@ -50,6 +50,11 @@ bool ArraySetAsSeries(ARRAY_REF(T, _array), bool _flag) { return true; } +template +bool ArrayGetAsSeries(ARRAY_REF(T, _array)) { + return _array.getIsSeries(); +} + template int ArrayMaximum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index ad1e5dc55..cb784124f 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -67,6 +67,7 @@ class IndicatorData : public IndicatorBase { int last_tick_index; // Index of the last tick. long first_tick_time_ms; // Time of the first ask/bid tick. void* mydata; + bool last_tick_result; // Result of the last Tick() invocation. ENUM_INDI_VS_TYPE retarget_ap_av; // Value storage type to be used as applied price/volume. ARRAY(Ref, value_storages); ARRAY(WeakRef, listeners); // List of indicators that listens for events from this one. @@ -865,10 +866,10 @@ class IndicatorData : public IndicatorBase { HasSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME); } - void Tick(int _global_tick_index) { + bool Tick(int _global_tick_index) { if (last_tick_index == _global_tick_index) { // We've already ticked. - return; + return last_tick_result; } if (_global_tick_index == 0) { @@ -884,13 +885,24 @@ class IndicatorData : public IndicatorBase { GetDataSource() PTR_DEREF Tick(_global_tick_index); } + last_tick_result = false; + // Also ticking all used indicators if they've not yet ticked. for (DictStructIterator> iter = indicators.Begin(); iter.IsValid(); ++iter) { - iter.Value() REF_DEREF Tick(_global_tick_index); + // If any of the attached indicators ticks then we signal that the tick happened, even if this indicator doesn't + // tick. It is because e.g., RSI could use Candle indicator and Candle could use Tick indicator. Ticking RSI + // doesn't signal tick in RSI, nor Candle, but only Tick indicator and only if new tick occured in the Tick + // indicator. In other words: Only Tick indicator returns true in its OnTick(). Also, in OnTick() it sends a tick + // into Candle indicator which aggregates ticks. RSI doesn't have OnTick() and we can't know if there is new RSI + // value. The only way to know that is to Tick all indicators in hierarchy and if one of them returns true in + // OnTick() then we know that we have new value for RSI. + last_tick_result |= iter.Value() REF_DEREF Tick(_global_tick_index); } // Overridable OnTick() method. - OnTick(_global_tick_index); + last_tick_result |= OnTick(_global_tick_index); + + return last_tick_result; } /** @@ -1835,7 +1847,11 @@ class IndicatorData : public IndicatorBase { /** * Called when new tick is retrieved from attached data source. */ - virtual void OnTick(int _global_tick_index) {} + virtual bool OnTick(int _global_tick_index) { + // We really don't know if new tick have happened. Let's just return false and let the Platform's Tick() method tick + // the Tick indicator in order to know if new tick was signalled. + return false; + } /** * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h index 871d059a3..f5676139d 100644 --- a/Indicator/tests/classes/Indicators.h +++ b/Indicator/tests/classes/Indicators.h @@ -53,12 +53,14 @@ class Indicators { int Size() { return (int)_indis.Size(); } + void Clear() { _indis.Clear(); } + /** * Executes OnTick() on every added indicator. */ void Tick(int _global_tick_index) { for (unsigned int i = 0; i < _indis.Size(); ++i) { - _indis[i].Ptr().OnTick(_global_tick_index); + _indis[i].Ptr() PTR_DEREF OnTick(_global_tick_index); } } @@ -68,8 +70,8 @@ class Indicators { string ToString(int _shift = 0) { string _result; for (unsigned int i = 0; i < _indis.Size(); ++i) { - IndicatorDataEntry _entry = _indis[i].Ptr().GetEntry(_shift); - _result += _indis[i].Ptr().GetFullName() + " = " + _entry.ToString() + "\n"; + IndicatorDataEntry _entry = _indis[i].Ptr() PTR_DEREF GetEntry(_shift); + _result += _indis[i].Ptr() PTR_DEREF GetFullName() + " = " + _entry.ToString() + "\n"; } return _result; } diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index d12dc6368..830284920 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -114,8 +114,8 @@ class Indi_Drawer : public Indicator { /** * Called when new tick is retrieved from attached data source. */ - void OnTick(int _global_tick_index) override { - Indicator::OnTick(_global_tick_index); + bool OnTick(int _global_tick_index) override { + return Indicator::OnTick(_global_tick_index); /* @fixme TaskActionEntry action(INDI_ACTION_SET_VALUE); diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index be3fbd9d4..78cc64f16 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -100,8 +100,8 @@ class Indi_PriceFeeder : public Indicator { /** * Called when new tick is retrieved from attached data source. */ - void OnTick(int _global_tick_index) override { - Indicator::OnTick(_global_tick_index); + bool OnTick(int _global_tick_index) override { + bool _result = Indicator::OnTick(_global_tick_index); if (idparams.IsDrawing()) { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); @@ -110,5 +110,7 @@ class Indi_PriceFeeder : public Indicator { // draw.DrawLineTo(GetName() + "_" + IntegerToString(i), GetBarTime(0), _entry.values[i].GetDbl()); } } + + return _result; } }; diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 2c4b409be..aa1a4a5f1 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -25,18 +25,6 @@ #include "../Indicator/Indicator.h" #include "Price/Indi_Price.mqh" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compability). -double iRSI(string _symbol, int _tf, int _period, int _ap, int _shift) { - ResetLastError(); - return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); -} -double iRSIOnArray(double &_arr[], int _total, int _period, int _abs_shift) { - ResetLastError(); - return Indi_RSI::iRSIOnArray(_arr, _total, _period, _abs_shift); -} -#endif - // Structs. struct IndiRSIParams : IndicatorParams { protected: @@ -45,14 +33,14 @@ struct IndiRSIParams : IndicatorParams { public: IndiRSIParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : applied_price(_ap), IndicatorParams(INDI_RSI) { + : IndicatorParams(INDI_RSI), applied_price(_ap) { shift = _shift; SetCustomIndicatorName("Examples\\RSI"); SetPeriod(_period); }; IndiRSIParams(IndiRSIParams &_params) { THIS_REF = _params; }; // Getters. - ENUM_APPLIED_PRICE GetAppliedPrice() override { return applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return applied_price; } int GetPeriod() { return period; } // Setters. void SetPeriod(int _period) { period = _period; } @@ -126,8 +114,13 @@ class Indi_RSI : public Indicator { ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iRSI(_symbol, _tf, _period, _applied_price, _shift); -#else // __MQL5__ +#elif __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iRSI(_symbol, _tf, _period, _applied_price), 0, _shift); +#else + RUNTIME_ERROR( + "In C++ Indi_RSI::iRSI() method couldn't be used directly. Please use an On-Indicator mode and attach " + "indicator via Platform::Add/AddWithDefaultBindings()."); + return DBL_MAX; #endif } @@ -140,13 +133,14 @@ class Indi_RSI : public Indicator { ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, Indi_RSI *_obj = NULL) { int i; - double indi_values[]; + ARRAY(double, indi_values); ArrayResize(indi_values, _period); double result; for (i = _shift; i < (int)_shift + (int)_period; i++) { - indi_values[_shift + _period - (i - _shift) - 1] = _indi[i][_obj.GetParams().indi_mode]; + indi_values[_shift + _period - (i - _shift) - 1] = + _indi PTR_DEREF GetSpecificAppliedPriceValueStorage(_applied_price) PTR_DEREF Fetch(i); } result = iRSIOnArray(indi_values, 0, _period - 1, 0); @@ -159,7 +153,7 @@ class Indi_RSI : public Indicator { * * @see https://school.stockcharts.com/doku.php?id=technical_indicators:relative_strength_index_rsi * - * Reson behind iRSI with SSMA and not just iRSIOnArray() (from above website): + * Reason behind iRSI with SMMA and not just iRSIOnArray() (from above website): * * "Taking the prior value plus the current value is a smoothing technique * similar to that used in calculating an exponential moving average. This @@ -182,7 +176,7 @@ class Indi_RSI : public Indicator { } int i; - double indi_values[]; + ARRAY(double, indi_values); ArrayResize(indi_values, _period); double result; @@ -238,7 +232,7 @@ class Indi_RSI : public Indicator { new_data.avg_gain = (last_data.avg_gain * (_period - 1) + curr_gain) / _period; new_data.avg_loss = (last_data.avg_loss * (_period - 1) + curr_loss) / _period; - _target.aux_data.Set(_bar_time_curr, new_data); + _target PTR_DEREF aux_data.Set(_bar_time_curr, new_data); if (new_data.avg_loss == 0.0) { // @fixme Why 0 loss? @@ -255,7 +249,7 @@ class Indi_RSI : public Indicator { /** * Calculates RSI on the array of values. */ - static double iRSIOnArray(double &array[], int total, int period, int shift) { + static double iRSIOnArray(ARRAY_REF(double, array), int total, int period, int shift) { #ifdef __MQL4__ return ::iRSIOnArray(array, total, period, shift); #else @@ -308,9 +302,9 @@ class Indi_RSI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override { double _value = EMPTY_VALUE; - double _res[]; + ARRAY(double, _res); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_RSI::iRSI(GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), @@ -327,7 +321,21 @@ class Indi_RSI : public Indicator { _value = Indi_RSI::iRSIOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), ToRelShift(_abs_shift)); break; + default: + RUNTIME_ERROR("Invalid indicator IDATA_* type!"); } return _value; } }; + +#ifndef __MQL4__ +// Defines global functions (for MQL4 backward compability). +double iRSI(string _symbol, int _tf, int _period, int _ap, int _shift) { + ResetLastError(); + return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); +} +double iRSIOnArray(ARRAY_REF(double, _arr), int _total, int _period, int _abs_shift) { + ResetLastError(); + return Indi_RSI::iRSIOnArray(_arr, _total, _period, _abs_shift); +} +#endif diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index 64d4791a9..91dd3811a 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -30,12 +30,12 @@ struct PriceIndiParams : IndicatorParams { ENUM_APPLIED_PRICE ap; // Struct constructor. - PriceIndiParams(ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) : ap(_ap), IndicatorParams(INDI_PRICE) { + PriceIndiParams(ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) : IndicatorParams(INDI_PRICE), ap(_ap) { SetShift(_shift); }; - PriceIndiParams(PriceIndiParams &_params) { THIS_REF = _params; }; + PriceIndiParams(PriceIndiParams &_params) : IndicatorParams() { THIS_REF = _params; }; // Getters. - ENUM_APPLIED_PRICE GetAppliedPrice() override { return ap; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return ap; } // Setters. void SetAppliedPrice(ENUM_APPLIED_PRICE _ap) { ap = _ap; } }; @@ -60,7 +60,7 @@ class Indi_Price : public Indicator { /** * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. */ - virtual unsigned int GetSuitableDataSourceTypes() { + unsigned int GetSuitableDataSourceTypes() override { // We can work only with Candle-based indicator attached. return INDI_SUITABLE_DS_TYPE_CANDLE; } @@ -111,21 +111,21 @@ class Indi_Price : public Indicator { case INDI_VS_TYPE_PRICE_ASK: // Tick. case INDI_VS_TYPE_PRICE_BID: // Tick. return GetPlatformPrices(GetSymbol(), iparams.GetAppliedPrice(), GetTf(), iparams.GetShift()) - .GetValueStorage(0); + PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_OPEN: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_OPEN, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_OPEN, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_HIGH: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_HIGH, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_HIGH, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_LOW: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_LOW, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_LOW, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_CLOSE: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_CLOSE, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_CLOSE, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_MEDIAN: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_MEDIAN, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_MEDIAN, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_TYPICAL: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_TYPICAL, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_TYPICAL, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_WEIGHTED: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_WEIGHTED, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_WEIGHTED, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); default: // Trying in parent class. return Indicator::GetSpecificValueStorage(_type); diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 39d588861..b87bdf585 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -154,7 +154,7 @@ class Indi_TickMt : public IndicatorTick= ArraySize(buffer)) { // No more ticks. - return; + return false; } TickTAB _tick = buffer[current_index++]; @@ -117,6 +117,8 @@ class Indi_TickProvider : public IndicatorTick _tick(_ask, _bid); @@ -98,5 +98,7 @@ class Indi_TickRandom : public IndicatorTick> indis_dflt; + // Result of the last tick. + static bool last_tick_result; + public: /** * Initializes platform. @@ -113,12 +116,14 @@ class Platform { DictStructIterator> _iter; + last_tick_result = false; + for (_iter = indis.Begin(); _iter.IsValid(); ++_iter) { - _iter.Value() REF_DEREF Tick(global_tick_index); + last_tick_result |= _iter.Value() REF_DEREF Tick(global_tick_index); } for (_iter = indis_dflt.Begin(); _iter.IsValid(); ++_iter) { - _iter.Value() REF_DEREF Tick(global_tick_index); + last_tick_result |= _iter.Value() REF_DEREF Tick(global_tick_index); } // Will check for new time periods in consecutive Platform::UpdateTime(). @@ -128,6 +133,11 @@ class Platform { ++global_tick_index; } + /** + * Checks whether we had a tick inside previous Tick() invocation. + */ + static bool HadTick() { return last_tick_result; } + /** * Returns dictionary of added indicators (keyed by unique id). */ @@ -359,6 +369,7 @@ class Platform { }; bool Platform::initialized = false; +bool Platform::last_tick_result = false; DateTime Platform::time = (datetime)0; unsigned int Platform::time_flags = 0; bool Platform::time_clear_flags = true; @@ -650,11 +661,33 @@ bool ObjectDelete(long chart_id, string name) { int GetLastError() { return _LastError; } +void ResetLastError() { _LastError = 0; } + int ObjectFind(long chart_id, string name) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } +bool TimeToStruct(datetime dt, MqlDateTime &dt_struct) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +SymbolGetter::operator string() { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return ""; +} + +ENUM_TIMEFRAMES Period() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return (ENUM_TIMEFRAMES)0; +} + +datetime StructToTime(MqlDateTime &dt_struct) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty datetime (0)."); + return (datetime)0; +} + #endif /** diff --git a/SymbolInfo.extern.h b/SymbolInfo.extern.h index 60b085d5b..f31450b70 100644 --- a/SymbolInfo.extern.h +++ b/SymbolInfo.extern.h @@ -27,11 +27,17 @@ // Define external global functions. #ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once + extern long SymbolInfoInteger(string name, ENUM_SYMBOL_INFO_INTEGER prop_id); extern bool SymbolInfoMarginRate(string name, ENUM_ORDER_TYPE order_type, double &initial_margin_rate, double &maintenance_margin_rate); extern bool SymbolInfoTick(string symbol, MqlTick &tick); // Define external global variables. -extern string _Symbol; +class SymbolGetter { + public: + operator string(); +} _Symbol; #endif From 30d6f7fbbd68eb4dab41cd9855adafd582fa8a8c Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 2 Mar 2023 19:04:26 +0100 Subject: [PATCH 27/42] WIP. Testing RSI over IndicatorTfDummy over Indi_TickProvider. RSI returns values. It's good! --- DateTime.extern.h | 15 +- DictBase.mqh | 1 + Indicator/Indicator.h | 1 + Indicator/IndicatorCandle.h | 2 +- Indicator/IndicatorTf.h | 24 +-- Indicator/IndicatorTf.struct.h | 22 ++- Indicator/tests/classes/IndicatorTfDummy.h | 17 +- Indicators/Tick/Indi_TickProvider.h | 5 +- Platform.define.h | 30 +++ Platform.extern.h | 58 +++--- Platform.h | 219 ++++++++++++++++----- PlatformTime.h | 22 +-- Serializer/SerializerConverter.h | 8 +- Serializer/SerializerCsv.h | 2 +- Std.h | 2 + Tick/Tick.struct.h | 26 +-- 16 files changed, 301 insertions(+), 153 deletions(-) create mode 100644 Platform.define.h diff --git a/DateTime.extern.h b/DateTime.extern.h index 1ffb17098..2f3bd3526 100644 --- a/DateTime.extern.h +++ b/DateTime.extern.h @@ -44,7 +44,7 @@ class datetime { public: datetime() { dt = 0; } - datetime(const long& _time) { dt = _time; } + datetime(const int64& _time) { dt = _time; } // datetime(const int& _time); bool operator==(const int _time) const = delete; bool operator==(const datetime& _time) const { return dt == _time; } @@ -52,7 +52,7 @@ class datetime { bool operator>(const int _time) const = delete; bool operator<(const datetime& _time) const { return dt < _time; } bool operator>(const datetime& _time) const { return dt > _time; } - operator long() const { return dt; } + operator int64() const { return dt; } }; extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, @@ -71,16 +71,7 @@ extern datetime TimeGMT(MqlDateTime& dt_struct); extern datetime TimeTradeServer(); extern datetime TimeTradeServer(MqlDateTime& dt_struct); extern datetime StringToTime(const string& value); -string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES) { - /* - auto now = std::chrono::time_point(); - auto in_time_t = std::chrono::system_clock::to_time_t(now); - */ - std::stringstream ss; - ss << __FUNCTION__ << " is not yet implemented!"; - // ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X"); - return ss.str(); -} +extern string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES); template datetime operator"" _D(); diff --git a/DictBase.mqh b/DictBase.mqh index 413894115..2d99174c2 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -61,6 +61,7 @@ class DictBase { _current_id = 0; _mode = DictModeUnknown; _flags = 0; + overflow_listener = nullptr; } /** diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 6f84b10e8..1083523a8 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -116,6 +116,7 @@ class Indicator : public IndicatorData { : IndicatorData(IndicatorDataParams::GetInstance()) { iparams.SetIndicatorType(_itype); iparams.SetShift(_shift); + SetName(_name); Init(); } diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 0f6c70ea6..d9fe084a2 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -94,7 +94,7 @@ class IndicatorCandle : public Indicator { /** * Class constructor. */ - IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, + IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(INDI_CANDLE_HISTORY_SIZE) { Init(); diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 69f319706..9f0aea621 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -59,34 +59,20 @@ class IndicatorTf : public IndicatorCandle { public: - IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} - IndicatorTfDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTf(_tf) {} - IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi = (ENUM_TIMEFRAMES_INDEX)0) : IndicatorTf(_tfi) {} + /* + @todo - string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } + IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} + */ + + IndicatorTfDummy(ENUM_TIMEFRAMES _tf) : IndicatorTf(IndicatorTfDummyParams(_tf), IndicatorDataParams()) {} + IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi) + : IndicatorTf(IndicatorTfDummyParams(ChartTf::IndexToTf(_tfi)), IndicatorDataParams()) {} + + string GetName() override { return "IndicatorTfDummy(" + iparams.tf.GetString() + ")"; } void OnDataSourceEntry(IndicatorDataEntry& entry) override { // When overriding OnDataSourceEntry() we have to remember to call parent diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h index 4f1f531b2..84fdf5439 100644 --- a/Indicators/Tick/Indi_TickProvider.h +++ b/Indicators/Tick/Indi_TickProvider.h @@ -64,7 +64,10 @@ class Indi_TickProvider : public IndicatorTick. + * + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Defines. +#define PLATFORM_WRONG_SYMBOL "" +#define PLATFORM_WRONG_TIMEFRAME ((ENUM_TIMEFRAMES)INT_MAX) diff --git a/Platform.extern.h b/Platform.extern.h index fabde3d0b..11edea715 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -67,9 +67,9 @@ extern int CopyLow(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, extern int CopyClose(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, close_array)); -extern unsigned long PositionGetTicket(int _index); +extern unsigned int64 PositionGetTicket(int _index); -extern long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id); +extern int64 PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id); extern double PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE property_id); @@ -77,13 +77,13 @@ extern string PositionGetString(ENUM_POSITION_PROPERTY_STRING property_id); extern int HistoryDealsTotal(); -extern unsigned long HistoryDealGetTicket(int index); +extern unsigned int64 HistoryDealGetTicket(int index); -extern long HistoryDealGetInteger(unsigned long ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id); +extern int64 HistoryDealGetInteger(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id); -extern double HistoryDealGetDouble(unsigned long ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id); +extern double HistoryDealGetDouble(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id); -extern string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRING property_id); +extern string HistoryDealGetString(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_STRING property_id); extern bool OrderSelect(int index); @@ -95,25 +95,25 @@ extern bool OrderSend(const MqlTradeRequest& request, MqlTradeResult& result); extern bool OrderCheck(const MqlTradeRequest& request, MqlTradeCheckResult& result); -extern unsigned long OrderGetTicket(int index); +extern unsigned int64 OrderGetTicket(int index); -extern unsigned long HistoryOrderGetTicket(int index); +extern unsigned int64 HistoryOrderGetTicket(int index); -extern bool HistorySelectByPosition(long position_id); +extern bool HistorySelectByPosition(int64 position_id); -extern bool HistoryDealSelect(unsigned long ticket); +extern bool HistoryDealSelect(unsigned int64 ticket); -extern long OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id); +extern int64 OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id); -extern long HistoryOrderGetInteger(unsigned long ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id); +extern int64 HistoryOrderGetInteger(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id); extern double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property_id); -extern double HistoryOrderGetDouble(unsigned long ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id); +extern double HistoryOrderGetDouble(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id); string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id); -string HistoryOrderGetString(unsigned long ticket_number, ENUM_ORDER_PROPERTY_STRING property_id); +string HistoryOrderGetString(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_STRING property_id); extern int PositionsTotal(); @@ -124,10 +124,10 @@ extern int HistoryOrdersTotal(); extern int OrdersTotal(); extern int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, - ARRAY_REF(long, arr)); + ARRAY_REF(int64, arr)); extern int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, - ARRAY_REF(long, arr)); + ARRAY_REF(int64, arr)); extern int ChartID(); @@ -135,38 +135,38 @@ extern bool OrderCalcMargin(ENUM_ORDER_TYPE _action, string _symbol, double _vol extern double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id); -extern long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); +extern int64 AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); extern string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); extern string Symbol(); -extern string ObjectName(long _chart_id, int _pos, int _sub_window = -1, int _type = -1); +extern string ObjectName(int64 _chart_id, int _pos, int _sub_window = -1, int _type = -1); -extern int ObjectsTotal(long chart_id, int type = EMPTY, int window = -1); +extern int ObjectsTotal(int64 chart_id, int type = EMPTY, int window = -1); extern bool PlotIndexSetString(int plot_index, int prop_id, string prop_value); extern bool PlotIndexSetInteger(int plot_index, int prop_id, int prop_value); -extern bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, long prop_value); +extern bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int64 prop_value); -extern bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, - long prop_value); +extern bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, + int64 prop_value); -extern bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value); +extern bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value); -extern bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, +extern bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, double prop_value); -extern bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1); -extern bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, +extern bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1); +extern bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, datetime _t2, double _p2); -extern bool ObjectMove(long chart_id, string name, int point_index, datetime time, double price); +extern bool ObjectMove(int64 chart_id, string name, int point_index, datetime time, double price); -extern bool ObjectDelete(long chart_id, string name); +extern bool ObjectDelete(int64 chart_id, string name); -extern int ObjectFind(long chart_id, string name); +extern int ObjectFind(int64 chart_id, string name); #endif diff --git a/Platform.h b/Platform.h index 703278ab1..9e4af58c7 100644 --- a/Platform.h +++ b/Platform.h @@ -27,6 +27,7 @@ // Includes. #include "Deal.enum.h" #include "Order.struct.h" +#include "Platform.define.h" /** * Extern declarations for C++. @@ -85,6 +86,12 @@ class Platform { // Result of the last tick. static bool last_tick_result; + // Symbol of the currently ticking indicator. + static string symbol; + + // Timeframe of the currently ticking indicator. + static ENUM_TIMEFRAMES period; + public: /** * Initializes platform. @@ -96,9 +103,6 @@ class Platform { } initialized = true; - - // Starting from current timestamp. - time.Update(); } /** @@ -110,6 +114,10 @@ class Platform { * Performs tick on every added indicator. */ static void Tick() { + // @todo Should update time for each ticking indicator and only when it signal a tick. + PlatformTime::Tick(); + time.Update(); + // Checking starting periods and updating time to current one. time_flags = time.GetStartedPeriods(); time.Update(); @@ -119,13 +127,37 @@ class Platform { last_tick_result = false; for (_iter = indis.Begin(); _iter.IsValid(); ++_iter) { + // Updating current symbol and timeframe to the ones used by ticking indicator and its parents. + symbol = _iter.Value() REF_DEREF GetSymbol(); + period = _iter.Value() REF_DEREF GetTf(); + +#ifdef __debug__ + PrintFormat("Tick #%d for %s for symbol %s and period %s", global_tick_index, + C_STR(_iter.Value() REF_DEREF GetFullName()), C_STR(symbol), C_STR(ChartTf::TfToString(period))); +#endif + last_tick_result |= _iter.Value() REF_DEREF Tick(global_tick_index); } for (_iter = indis_dflt.Begin(); _iter.IsValid(); ++_iter) { + // Updating current symbol and timeframe to the ones used by ticking indicator and its parents. + symbol = (_iter.Value() REF_DEREF GetTick(false) != nullptr) ? _iter.Value() REF_DEREF GetSymbol() + : PLATFORM_WRONG_SYMBOL; + period = (_iter.Value() REF_DEREF GetCandle(false) != nullptr) ? _iter.Value() REF_DEREF GetTf() + : PLATFORM_WRONG_TIMEFRAME; + +#ifdef __debug__ + PrintFormat("Tick #%d for %s for symbol %s and period %s", global_tick_index, + C_STR(_iter.Value() REF_DEREF GetFullName()), C_STR(symbol), C_STR(ChartTf::TfToString(period))); +#endif + last_tick_result |= _iter.Value() REF_DEREF Tick(global_tick_index); } + // Clearing symbol and period in order to signal retrieving symbol/period outside the ticking indicator. + symbol = PLATFORM_WRONG_SYMBOL; + period = PLATFORM_WRONG_TIMEFRAME; + // Will check for new time periods in consecutive Platform::UpdateTime(). time_clear_flags = true; @@ -280,13 +312,13 @@ class Platform { /** * Returns default Candle-compatible indicator for current platform for given symbol and TF. */ - static IndicatorData *FetchDefaultCandleIndicator(string _symbol = "", ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - if (_symbol == "") { - _symbol = _Symbol; + static IndicatorData *FetchDefaultCandleIndicator(string _symbol, ENUM_TIMEFRAMES _tf) { + if (_symbol == PLATFORM_WRONG_SYMBOL) { + RUNTIME_ERROR("Cannot fetch default candle indicator for unknown symbol!"); } - if (_tf == PERIOD_CURRENT) { - _tf = (ENUM_TIMEFRAMES)Period(); + if (_tf == PERIOD_CURRENT || _tf == PLATFORM_WRONG_TIMEFRAME) { + RUNTIME_ERROR("Cannot fetch default candle indicator for unknown period/timeframe!"); } // Candle is per symbol and TF. Single Candle indicator can't handle multiple TFs. @@ -311,9 +343,9 @@ class Platform { /** * Returns default Tick-compatible indicator for current platform for given symbol. */ - static IndicatorData *FetchDefaultTickIndicator(string _symbol = "") { - if (_symbol == "") { - _symbol = _Symbol; + static IndicatorData *FetchDefaultTickIndicator(string _symbol) { + if (_symbol == PLATFORM_WRONG_SYMBOL) { + RUNTIME_ERROR("Cannot fetch default tick indicator for unknown symbol!"); } string _key = Util::MakeKey("PlatformIndicatorTick", _symbol); @@ -366,6 +398,39 @@ class Platform { } return _result; } + + /** + * Returns symbol of the currently ticking indicator. + **/ + static string GetSymbol() { + if (symbol == PLATFORM_WRONG_SYMBOL) { + RUNTIME_ERROR("Retrieving symbol outside the OnTick() of the currently ticking indicator is prohibited!"); + } + return symbol; + } + + /** + * Returns timeframe of the currently ticking indicator. + **/ + static ENUM_TIMEFRAMES GetPeriod() { + if (period == PLATFORM_WRONG_TIMEFRAME) { + RUNTIME_ERROR( + "Retrieving period/timeframe outside the OnTick() of the currently ticking indicator is prohibited!"); + } + + return period; + } + + private: + /** + * Sets symbol of the currently ticking indicator. + **/ + static void SetSymbol(string _symbol) { symbol = _symbol; } + + /** + * Sets timeframe of the currently ticking indicator. + **/ + static void SetPeriod(ENUM_TIMEFRAMES _period) { period = _period; } }; bool Platform::initialized = false; @@ -374,6 +439,8 @@ DateTime Platform::time = (datetime)0; unsigned int Platform::time_flags = 0; bool Platform::time_clear_flags = true; int Platform::global_tick_index = 0; +string Platform::symbol = PLATFORM_WRONG_SYMBOL; +ENUM_TIMEFRAMES Platform::period = PLATFORM_WRONG_TIMEFRAME; DictStruct> Platform::indis; DictStruct> Platform::indis_dflt; @@ -399,12 +466,12 @@ int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, A return 0; } -unsigned long PositionGetTicket(int _index) { +unsigned int64 PositionGetTicket(int _index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id) { +int64 PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } @@ -424,22 +491,22 @@ int HistoryDealsTotal() { return 0; } -unsigned long HistoryDealGetTicket(int index) { +unsigned int64 HistoryDealGetTicket(int index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -long HistoryDealGetInteger(unsigned long ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id) { +int64 HistoryDealGetInteger(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -double HistoryDealGetDouble(unsigned long ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id) { +double HistoryDealGetDouble(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRING property_id) { +string HistoryDealGetString(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_STRING property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); return 0; } @@ -469,32 +536,32 @@ bool OrderCheck(const MqlTradeRequest &request, MqlTradeCheckResult &result) { return false; } -unsigned long OrderGetTicket(int index) { +unsigned int64 OrderGetTicket(int index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -unsigned long HistoryOrderGetTicket(int index) { +unsigned int64 HistoryOrderGetTicket(int index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -bool HistorySelectByPosition(long position_id) { +bool HistorySelectByPosition(int64 position_id) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool HistoryDealSelect(unsigned long ticket) { +bool HistoryDealSelect(unsigned int64 ticket) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -long OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id) { +int64 OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -long HistoryOrderGetInteger(unsigned long ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id) { +int64 HistoryOrderGetInteger(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } @@ -504,7 +571,7 @@ double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property_id) { return 0; } -double HistoryOrderGetDouble(unsigned long ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id) { +double HistoryOrderGetDouble(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } @@ -514,7 +581,7 @@ string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id) { return 0; } -string HistoryOrderGetString(unsigned long ticket_number, ENUM_ORDER_PROPERTY_STRING property_id) { +string HistoryOrderGetString(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_STRING property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); return 0; } @@ -559,12 +626,12 @@ int CopyClose(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int return 0; } -int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(long, arr)) { +int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(int64, arr)) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(long, arr)) { +int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(int64, arr)) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } @@ -581,7 +648,7 @@ double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id) { return false; } -long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id) { +int64 AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return false; } @@ -596,12 +663,12 @@ string Symbol() { return ""; } -string ObjectName(long _chart_id, int _pos, int _sub_window, int _type) { +string ObjectName(int64 _chart_id, int _pos, int _sub_window, int _type) { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); return ""; } -int ObjectsTotal(long chart_id, int type, int window) { +int ObjectsTotal(int64 chart_id, int type, int window) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } @@ -616,45 +683,45 @@ bool PlotIndexSetInteger(int plot_index, int prop_id, int prop_value) { return false; } -bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, long prop_value) { +bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int64 prop_value) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, - long prop_value) { +bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, + int64 prop_value) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value) { +bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, +bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, double prop_value) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { +bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, datetime _t2, +bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, datetime _t2, double _p2) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectMove(long chart_id, string name, int point_index, datetime time, double price) { +bool ObjectMove(int64 chart_id, string name, int point_index, datetime time, double price) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectDelete(long chart_id, string name) { +bool ObjectDelete(int64 chart_id, string name) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } @@ -663,29 +730,77 @@ int GetLastError() { return _LastError; } void ResetLastError() { _LastError = 0; } -int ObjectFind(long chart_id, string name) { +int ObjectFind(int64 chart_id, string name) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -bool TimeToStruct(datetime dt, MqlDateTime &dt_struct) { - Print("Not yet implemented: ", __FUNCTION__, " returns false."); - return false; -} +string TimeToString(datetime value, int mode) { + static std::stringstream ss; + ss.clear(); + ss.str(""); -SymbolGetter::operator string() { - Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); - return ""; + std::time_t time = value; + std::tm *ptm = std::localtime(&time); + char date[16], minutes[16], seconds[16]; + std::strftime(date, 32, "%Y.%m.%d", ptm); + std::strftime(minutes, 32, "%H:%M", ptm); + std::strftime(seconds, 32, "%S", ptm); + + if (mode | TIME_DATE) ss << date; + + if (mode | TIME_MINUTES) { + if (mode | TIME_DATE) { + ss << " "; + } + ss << minutes; + } + + if (mode | TIME_SECONDS) { + if (mode | TIME_DATE && !(mode | TIME_MINUTES)) { + ss << " "; + } else if (mode | TIME_MINUTES) { + ss << ":"; + } + ss << seconds; + } + + return ss.str(); } -ENUM_TIMEFRAMES Period() { - Print("Not yet implemented: ", __FUNCTION__, " returns 0."); - return (ENUM_TIMEFRAMES)0; +bool TimeToStruct(datetime dt, MqlDateTime &dt_struct) { + time_t now = (time_t)dt; + + tm *ltm = localtime(&now); + + dt_struct.day = ltm->tm_mday; + dt_struct.day_of_week = ltm->tm_wday; + dt_struct.day_of_year = ltm->tm_yday; + dt_struct.hour = ltm->tm_hour; + dt_struct.min = ltm->tm_min; + dt_struct.mon = ltm->tm_mon; + dt_struct.sec = ltm->tm_sec; + dt_struct.year = ltm->tm_year; + + return true; } +SymbolGetter::operator string() { return Platform::GetSymbol(); } + +ENUM_TIMEFRAMES Period() { return Platform::GetPeriod(); } + datetime StructToTime(MqlDateTime &dt_struct) { - Print("Not yet implemented: ", __FUNCTION__, " returns empty datetime (0)."); - return (datetime)0; + tm ltm; + ltm.tm_mday = dt_struct.day; + ltm.tm_wday = dt_struct.day_of_week; + ltm.tm_yday = dt_struct.day_of_year; + ltm.tm_hour = dt_struct.hour; + ltm.tm_min = dt_struct.min; + ltm.tm_mon = dt_struct.mon; + ltm.tm_sec = dt_struct.sec; + ltm.tm_year = dt_struct.year; + + return mktime(<m); } #endif diff --git a/PlatformTime.h b/PlatformTime.h index 6b54aeffb..b67cc43dc 100644 --- a/PlatformTime.h +++ b/PlatformTime.h @@ -39,21 +39,21 @@ class PlatformTime { static MqlDateTime current_time; - static long current_timestamp_s; - static long current_timestamp_ms; + static int64 current_timestamp_s; + static int64 current_timestamp_ms; public: - static long CurrentTimestamp() { return current_timestamp_s; } - static long CurrentTimestampMs() { return current_timestamp_ms; } + static int64 CurrentTimestamp() { return current_timestamp_s; } + static int64 CurrentTimestampMs() { return current_timestamp_ms; } static MqlDateTime CurrentTime() { return current_time; } void static Tick() { #ifdef __MQL__ - static long _last_timestamp_ms = 0; + static int64 _last_timestamp_ms = 0; current_timestamp_s = ::TimeCurrent(current_time); - current_timestamp_ms = (long)GetTickCount(); + current_timestamp_ms = (int64)GetTickCount(); if (_last_timestamp_ms != 0 && current_timestamp_ms < _last_timestamp_ms) { // Overflow occured (49.7 days passed). @@ -64,11 +64,11 @@ class PlatformTime { _last_timestamp_ms = current_timestamp_ms; #else using namespace std::chrono; - current_timestamp_s = (long)duration_cast(system_clock::now().time_since_epoch()).count(); - current_timestamp_ms = (long)duration_cast(system_clock::now().time_since_epoch()).count(); + current_timestamp_s = (int64)duration_cast(system_clock::now().time_since_epoch()).count(); + current_timestamp_ms = (int64)duration_cast(system_clock::now().time_since_epoch()).count(); using namespace std::chrono; - std::time_t t = std::time(0); + std::time_t t = current_timestamp_s; std::tm* now = std::localtime(&t); current_time.day = now->tm_mday; current_time.day_of_week = now->tm_wday; @@ -83,5 +83,5 @@ class PlatformTime { }; MqlDateTime PlatformTime::current_time = {0, 0, 0, 0, 0, 0, 0, 0}; -long PlatformTime::current_timestamp_s = 0; -long PlatformTime::current_timestamp_ms = 0; +int64 PlatformTime::current_timestamp_s = 0; +int64 PlatformTime::current_timestamp_ms = 0; diff --git a/Serializer/SerializerConverter.h b/Serializer/SerializerConverter.h index 350cf0763..8774f5f95 100644 --- a/Serializer/SerializerConverter.h +++ b/Serializer/SerializerConverter.h @@ -39,7 +39,7 @@ class SerializerNode; #include "SerializerDict.h" #include "SerializerNode.h" -#ifdef __debug__ +#ifdef __debug_verbose__ #include "SerializerJson.h" #endif @@ -72,7 +72,7 @@ class SerializerConverter { _serializer.FreeRootNodeOwnership(); _serializer.PassObject(_value, "", _value, SERIALIZER_FIELD_FLAG_VISIBLE); SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); -#ifdef __debug__ +#ifdef __debug_verbose__ Print("FromObject(): serializer flags: ", serializer_flags); Print("FromObject(): result: ", _serializer.GetRoot() != NULL ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) @@ -87,7 +87,7 @@ class SerializerConverter { _serializer.FreeRootNodeOwnership(); _serializer.PassObject(_value, "", _value, SERIALIZER_FIELD_FLAG_VISIBLE); SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); -#ifdef __debug__ +#ifdef __debug_verbose__ Print("FromObject(): serializer flags: ", serializer_flags); Print("FromObject(): result: ", _serializer.GetRoot() != NULL ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) @@ -119,7 +119,7 @@ class SerializerConverter { template static SerializerConverter FromString(string arg) { SerializerConverter _converter(((C*)NULL)PTR_DEREF Parse(arg), 0); -#ifdef __debug__ +#ifdef __debug_verbose__ Print("FromString(): result: ", _converter.Node() != NULL ? _converter.Node() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); #endif diff --git a/Serializer/SerializerCsv.h b/Serializer/SerializerCsv.h index 47d6f2c03..3390865ba 100644 --- a/Serializer/SerializerCsv.h +++ b/Serializer/SerializerCsv.h @@ -114,7 +114,7 @@ class SerializerCsv { } } -#ifdef __debug__ +#ifdef __debug_verbose__ Print("Stub: ", _stub PTR_DEREF Node() PTR_DEREF ToString()); Print("Data: ", _root PTR_DEREF ToString()); Print("Size: ", _num_columns, " x ", _num_rows); diff --git a/Std.h b/Std.h index 190ad3af6..13ffe0869 100644 --- a/Std.h +++ b/Std.h @@ -56,6 +56,7 @@ #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE* NAME = PTR #define nullptr NULL #define REF_DEREF .Ptr(). +#define int64 long #else #define THIS_ATTR this-> #define THIS_PTR (this) @@ -66,6 +67,7 @@ #define PTR_TO_REF(PTR) (*PTR) #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE& NAME = PTR #define REF_DEREF .Ptr()-> +#define int64 long long #endif // References. diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 4493d31ce..708f4fc3c 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -40,14 +40,14 @@ * https://www.mql5.com/en/docs/constants/structures/mqltick */ struct MqlTick { - datetime time; // Time of the last prices update. - double ask; // Current Ask price. - double bid; // Current Bid price. - double last; // Price of the last deal (last). - double volume_real; // Volume for the current last price with greater accuracy. - long time_msc; // Time of a price last update in milliseconds. - unsigned int flags; // Tick flags. - unsigned long volume; // Volume for the current last price. + datetime time; // Time of the last prices update. + double ask; // Current Ask price. + double bid; // Current Bid price. + double last; // Price of the last deal (last). + double volume_real; // Volume for the current last price with greater accuracy. + int64 time_msc; // Time of a price last update in milliseconds. + unsigned int flags; // Tick flags. + unsigned int64 volume; // Volume for the current last price. // Default constructor. MqlTick() {} @@ -84,26 +84,26 @@ struct DoubleTickAB : TickAB {}; */ template struct TickTAB : TickAB { - long time_ms; // Time of the last prices update. + int64 time_ms; // Time of the last prices update. // Struct constructors. - TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : TickAB(_ask, _bid), time_ms(_time_ms) {} + TickTAB(int64 _time_ms = 0, T _ask = 0, T _bid = 0) : TickAB(_ask, _bid), time_ms(_time_ms) {} TickTAB(MqlTick &_tick) : TickAB(_tick), time_ms(_tick.time_msc) {} TickTAB(const TickTAB &r) { THIS_REF = r; } /** * Method used by ItemsHistory. */ - long GetTimeMs() { return time_ms; } + int64 GetTimeMs() { return time_ms; } /** * Returns time as timestamp (in seconds). */ - long GetTimestamp() { return time_ms; } + int64 GetTimestamp() { return time_ms / 1000; } /** * Method used by ItemsHistory. */ - long GetLengthMs() { + int64 GetLengthMs() { // Ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. return 0; } From db3442db6185812fb7aab554227b92fce20aeb78 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 8 Mar 2023 17:20:36 +0100 Subject: [PATCH 28/42] Fixes recent syntax errors for C++. --- Chart.struct.static.h | 6 +++--- Indicator/IndicatorTf.h | 5 ++++- Orders.mqh | 4 ++-- Platform.h | 14 +++++++------- Std.h | 13 +++++++------ SymbolInfo.extern.h | 2 +- Tick/Tick.struct.h | 4 ++-- 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Chart.struct.static.h b/Chart.struct.static.h index befc9946b..2758c2d02 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -151,7 +151,7 @@ struct ChartStatic { if (_start < 0) return (-1); _count = (_count <= 0 ? ChartStatic::iBars(_symbol_tf.Symbol(), _symbol_tf.Tf()) : _count); ARRAY(double, arr_d); - ARRAY(long, arr_l); + ARRAY(int64, arr_l); ARRAY(datetime, arr_dt); ArraySetAsSeries(arr_d, true); switch (_type) { @@ -208,7 +208,7 @@ struct ChartStatic { if (_start < 0) return (-1); _count = (_count <= 0 ? iBars(_symbol, _tf) : _count); ARRAY(double, arr_d); - ARRAY(long, arr_l); + ARRAY(int64, arr_l); ARRAY(datetime, arr_dt); ArraySetAsSeries(arr_d, true); switch (_type) { @@ -314,7 +314,7 @@ struct ChartStatic { } return _volume; #else // __MQL5__ - ARRAY(long, _arr); + ARRAY(int64, _arr); ArraySetAsSeries(_arr, true); return (_shift >= 0 && CopyTickVolume(_symbol, _tf, _shift, 1, _arr) > 0) ? _arr[0] : 0; #endif diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 9f0aea621..c4195c68b 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -72,7 +72,10 @@ class IndicatorTf : public IndicatorCandle>(_icparams, _idparams) { + Init(); + } /** * Gets indicator's time-frame. diff --git a/Orders.mqh b/Orders.mqh index aa0add09b..89b821555 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -184,7 +184,7 @@ class Orders { // Terminal::GetErrorText(GetLastError())); break; } - if (Order::OrderSymbol() == _Symbol) { + if (Order::OrderSymbol() == (string)_Symbol) { double order_tp = Order::OrderTakeProfit(); double order_sl = Order::OrderStopLoss(); switch (Order::OrderType()) { @@ -268,7 +268,7 @@ class Orders { Terminal::GetErrorText(GetLastError())); break; } - if (Order::OrderSymbol() == _Symbol) { + if (Order::OrderSymbol() == (string)_Symbol) { switch (Order::OrderType()) { case ORDER_TYPE_BUY: buy_lots += Order::OrderLots(); diff --git a/Platform.h b/Platform.h index 9e4af58c7..f216c5d6b 100644 --- a/Platform.h +++ b/Platform.h @@ -747,19 +747,19 @@ string TimeToString(datetime value, int mode) { std::strftime(minutes, 32, "%H:%M", ptm); std::strftime(seconds, 32, "%S", ptm); - if (mode | TIME_DATE) ss << date; + if (mode & TIME_DATE) ss << date; - if (mode | TIME_MINUTES) { - if (mode | TIME_DATE) { + if (mode & TIME_MINUTES) { + if (mode & TIME_DATE) { ss << " "; } ss << minutes; } - if (mode | TIME_SECONDS) { - if (mode | TIME_DATE && !(mode | TIME_MINUTES)) { + if (mode & TIME_SECONDS) { + if (mode & TIME_DATE && !(mode & TIME_MINUTES)) { ss << " "; - } else if (mode | TIME_MINUTES) { + } else if (mode & TIME_MINUTES) { ss << ":"; } ss << seconds; @@ -785,7 +785,7 @@ bool TimeToStruct(datetime dt, MqlDateTime &dt_struct) { return true; } -SymbolGetter::operator string() { return Platform::GetSymbol(); } +SymbolGetter::operator string() const { return Platform::GetSymbol(); } ENUM_TIMEFRAMES Period() { return Platform::GetPeriod(); } diff --git a/Std.h b/Std.h index 13ffe0869..2d4848e6b 100644 --- a/Std.h +++ b/Std.h @@ -235,12 +235,13 @@ class _cpp_array { #ifdef EMSCRIPTEN #include -#define REGISTER_ARRAY_OF(N, T, D) \ - EMSCRIPTEN_BINDINGS(N) { \ - emscripten::class_<_cpp_array>(D) \ - .constructor() \ - .function("Push", &_cpp_array::push) \ - .function("Size", &_cpp_array::size); \ +#define REGISTER_ARRAY_OF(N, T, D) \ + EMSCRIPTEN_BINDINGS(N) { \ + emscripten::register_vector(D "CppVector"); \ + emscripten::class_<_cpp_array>(D) \ + .constructor() \ + .function("Push", &_cpp_array::push) \ + .function("Size", &_cpp_array::size); \ } #endif diff --git a/SymbolInfo.extern.h b/SymbolInfo.extern.h index f31450b70..0fe18dec6 100644 --- a/SymbolInfo.extern.h +++ b/SymbolInfo.extern.h @@ -38,6 +38,6 @@ extern bool SymbolInfoTick(string symbol, MqlTick &tick); // Define external global variables. class SymbolGetter { public: - operator string(); + operator string() const; } _Symbol; #endif diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 708f4fc3c..66f59a9c9 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -123,8 +123,8 @@ EMSCRIPTEN_BINDINGS(TickAB) { EMSCRIPTEN_BINDINGS(TickTAB) { // emscripten::value_object, emscripten::base>>("TickTABDouble") emscripten::value_object>("TickTAB") - .field("ask", &TickAB::ask) - .field("bid", &TickAB::bid) + .field("ask", &TickTAB::ask) + .field("bid", &TickTAB::bid) .field("time_ms", &TickTAB::time_ms); } From 93a46bbdcca161bc8d2c0a293c47c1f870ab1813 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 7 Apr 2023 19:50:12 +0200 Subject: [PATCH 29/42] Little changes for array #defines. --- Std.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Std.h b/Std.h index 2d4848e6b..8f5ca61de 100644 --- a/Std.h +++ b/Std.h @@ -98,6 +98,7 @@ * @usage * ARRAY_REF(, ) */ +#define ARRAY_TYPE(T) T[] #define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS #define FIXED_ARRAY_REF(T, N, S) ARRAY_REF(T, N) @@ -124,7 +125,8 @@ * @usage * ARRAY_REF(, ) */ -#define ARRAY_REF(T, N) _cpp_array& N +#define ARRAY_TYPE(T) _cpp_array +#define ARRAY_REF(T, N) ARRAY_TYPE(T)& N #define FIXED_ARRAY_REF(T, N, S) T(&N)[S] #define CONST_ARRAY_REF(T, N) const _cpp_array& N From 42de20c59740d02242c11a6690b06cdd62f0fe3c Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 20 Apr 2023 19:08:08 +0200 Subject: [PATCH 30/42] WIP. Making a Tester class and exporting IndicatorTfDummy and RSI indicator to be used in JS. --- Chart.enum.h | 30 ++++++++++++++++++++++ Indicator/IndicatorBase.h | 10 ++++++++ Indicator/IndicatorData.h | 15 +++++++++++ Indicator/tests/classes/IndicatorTfDummy.h | 30 ++++++++++++++++++++++ Indicators/Tick/Indi_TickProvider.h | 17 ++++++++---- Platform.h | 1 - Refs.struct.h | 7 +++++ 7 files changed, 104 insertions(+), 6 deletions(-) diff --git a/Chart.enum.h b/Chart.enum.h index 3a5463f87..e523c9dfa 100644 --- a/Chart.enum.h +++ b/Chart.enum.h @@ -126,6 +126,36 @@ enum ENUM_TIMEFRAMES { PERIOD_MN1 = 43200 // 1 month. }; +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(ENUM_TIMEFRAMES) { + emscripten::enum_("timeframes") + .value("CURRENT", PERIOD_CURRENT) + .value("M1", PERIOD_M1) + .value("M2", PERIOD_M2) + .value("M3", PERIOD_M3) + .value("M3", PERIOD_M3) + .value("M5", PERIOD_M5) + .value("M6", PERIOD_M6) + .value("M10", PERIOD_M10) + .value("M12", PERIOD_M12) + .value("M15", PERIOD_M15) + .value("M20", PERIOD_M20) + .value("M30", PERIOD_M30) + .value("H1", PERIOD_H1) + .value("H3", PERIOD_H3) + .value("H4", PERIOD_H4) + .value("H6", PERIOD_H6) + .value("H8", PERIOD_H8) + .value("H12", PERIOD_H12) + .value("D1", PERIOD_D1) + .value("W1", PERIOD_W1) + .value("MN1", PERIOD_MN1); +} +#endif + #endif // Define type of periods. diff --git a/Indicator/IndicatorBase.h b/Indicator/IndicatorBase.h index 3dede1258..fdbdb6b17 100644 --- a/Indicator/IndicatorBase.h +++ b/Indicator/IndicatorBase.h @@ -356,3 +356,13 @@ class IndicatorBase : public Object { #endif } }; + +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(IndicatorBase) { + emscripten::class_("IndicatorBase").smart_ptr>("Ref"); +} + +#endif diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index cb784124f..2d13e115a 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1965,4 +1965,19 @@ IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIn int GetBarsFromStart(IndicatorData* _indi) { return _indi PTR_DEREF GetBars(); } #endif +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(IndicatorData) { + emscripten::class_>("IndicatorData") + .smart_ptr>("Ref") + .function("SetSource", emscripten::optional_override([](IndicatorData& self, IndicatorData* base) { + self.SetDataSource(base); + }), + emscripten::allow_raw_pointer>()); +} + +#endif + #endif // INDICATOR_DATA_H diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 340a15b9b..171137d95 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -68,3 +68,33 @@ class IndicatorTfDummy : public IndicatorTf { #endif } }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyParams) { emscripten::value_object("indicators.TfParams"); } + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyBaseBaseBase) { + emscripten::class_, emscripten::base>( + "IndicatorTfDummyBaseBaseBase"); +} + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyBaseBase) { + emscripten::class_>, + emscripten::base>>("IndicatorTfDummyBaseBase"); +} + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyBase) { + emscripten::class_< + IndicatorTf, + emscripten::base>>>( + "IndicatorTfDummyBase"); +} + +EMSCRIPTEN_BINDINGS(IndicatorTfDummy) { + emscripten::class_>>("indicators.Tf") + .smart_ptr>("Ref") + .constructor(); +} + +#endif diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h index 84fdf5439..290433783 100644 --- a/Indicators/Tick/Indi_TickProvider.h +++ b/Indicators/Tick/Indi_TickProvider.h @@ -128,18 +128,25 @@ class Indi_TickProvider : public IndicatorTick +EMSCRIPTEN_BINDINGS(Indi_TickProviderBaseBase) { + emscripten::class_, emscripten::base>("IndiTickProviderBaseBase") + .smart_ptr>>("Ref>"); +} + EMSCRIPTEN_BINDINGS(Indi_TickProviderBase) { - emscripten::class_>>( - "IndiTickProviderBase"); + emscripten::class_>, + emscripten::base>>("IndiTickProviderBas e") + .smart_ptr>>>( + "Ref>"); } EMSCRIPTEN_BINDINGS(Indi_TickProvider) { emscripten::class_< Indi_TickProvider, emscripten::base>>>( - "Indi_TickProvider") - //.smart_ptr>("Ref") - .constructor<>() + "indicators.TickProvider") + .smart_ptr>("Ref") + .constructor(emscripten::optional_override([]() { return Ref(new Indi_TickProvider()); })) .function("BufferSize", &Indi_TickProvider::BufferSize) .function("Feed", &Indi_TickProvider::Feed); } diff --git a/Platform.h b/Platform.h index f216c5d6b..3800f0159 100644 --- a/Platform.h +++ b/Platform.h @@ -120,7 +120,6 @@ class Platform { // Checking starting periods and updating time to current one. time_flags = time.GetStartedPeriods(); - time.Update(); DictStructIterator> _iter; diff --git a/Refs.struct.h b/Refs.struct.h index ddda68a3b..b80fa30e7 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -130,6 +130,13 @@ struct Ref { */ ~Ref() { Unset(); } +#ifndef __MQL__ + template + operator Ref() { + return Ref(ptr_object); + } +#endif + /** * Returns pointer to target object. */ From 3bc9a57e22ef2c83e718d6e43b73169e545c5de0 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 28 Apr 2023 22:18:50 +0200 Subject: [PATCH 31/42] src/IndicatorTest.cpp --- Chart.enum.h | 11 +++++++ Indicator/IndicatorData.h | 24 ++++++++++++--- Indicator/tests/classes/IndicatorTfDummy.h | 11 +++++-- Indicators/Indi_RSI.mqh | 34 ++++++++++++++++++++-- Indicators/Tick/Indi_TickProvider.h | 27 +++++++++++++++++ Refs.struct.h | 8 +++-- Tick/Tick.struct.h | 8 +++++ 7 files changed, 112 insertions(+), 11 deletions(-) diff --git a/Chart.enum.h b/Chart.enum.h index e523c9dfa..1b61aeace 100644 --- a/Chart.enum.h +++ b/Chart.enum.h @@ -154,6 +154,17 @@ EMSCRIPTEN_BINDINGS(ENUM_TIMEFRAMES) { .value("W1", PERIOD_W1) .value("MN1", PERIOD_MN1); } + +EMSCRIPTEN_BINDINGS(ENUM_APPLIED_PRICE) { + emscripten::enum_("ap") + .value("open", PRICE_OPEN) + .value("high", PRICE_HIGH) + .value("low", PRICE_LOW) + .value("median", PRICE_MEDIAN) + .value("typical", PRICE_TYPICAL) + .value("weighted", PRICE_WEIGHTED); +} + #endif #endif diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 2d13e115a..7d1941353 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -83,6 +83,11 @@ class IndicatorData : public IndicatorBase { /* Protected methods */ bool Init() { +#ifdef __cplusplus + // In C++ we default to On-Indicator mode as there are no built-in ones. + idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR); +#endif + ArrayResize(value_storages, GetModeCount()); if (indi_src.IsSet()) { // SetDataSource(_indi_src, _indi_mode); @@ -868,6 +873,9 @@ class IndicatorData : public IndicatorBase { bool Tick(int _global_tick_index) { if (last_tick_index == _global_tick_index) { +#ifdef __debug_indicator__ + Print("We've already ticked tick index #", _global_tick_index, ". Skipping Tick() for ", GetFullName()); +#endif // We've already ticked. return last_tick_result; } @@ -879,13 +887,15 @@ class IndicatorData : public IndicatorBase { last_tick_index = _global_tick_index; + last_tick_result = false; + // Checking and potentially initializing new data source. if (HasDataSource(true)) { // Ticking data source if not yet ticked. - GetDataSource() PTR_DEREF Tick(_global_tick_index); - } - last_tick_result = false; + // If data source returns true, that means it ticked and there could be more ticks in the future. + last_tick_result |= GetDataSource() PTR_DEREF Tick(_global_tick_index); + } // Also ticking all used indicators if they've not yet ticked. for (DictStructIterator> iter = indicators.Begin(); iter.IsValid(); ++iter) { @@ -896,7 +906,13 @@ class IndicatorData : public IndicatorBase { // into Candle indicator which aggregates ticks. RSI doesn't have OnTick() and we can't know if there is new RSI // value. The only way to know that is to Tick all indicators in hierarchy and if one of them returns true in // OnTick() then we know that we have new value for RSI. - last_tick_result |= iter.Value() REF_DEREF Tick(_global_tick_index); + bool _tick_result = iter.Value() REF_DEREF Tick(_global_tick_index); + +#ifdef __debug_indicator__ + Print(iter.Value() REF_DEREF GetFullName(), "'s Tick() result: ", _tick_result ? "true" : "false"); +#endif + + last_tick_result |= _tick_result; } // Overridable OnTick() method. diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 171137d95..591c3f089 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -50,9 +50,16 @@ class IndicatorTfDummy : public IndicatorTf { IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} */ - IndicatorTfDummy(ENUM_TIMEFRAMES _tf) : IndicatorTf(IndicatorTfDummyParams(_tf), IndicatorDataParams()) {} + IndicatorTfDummy(ENUM_TIMEFRAMES _tf) : IndicatorTf(IndicatorTfDummyParams(_tf), IndicatorDataParams()) { Init(); } IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi) - : IndicatorTf(IndicatorTfDummyParams(ChartTf::IndexToTf(_tfi)), IndicatorDataParams()) {} + : IndicatorTf(IndicatorTfDummyParams(ChartTf::IndexToTf(_tfi)), IndicatorDataParams()) { + Init(); + } + + void Init() { + // Explicitly specifying built-in mode as in C++ default mode is On-Indicator. + idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_BUILTIN); + } string GetName() override { return "IndicatorTfDummy(" + iparams.tf.GetString() + ")"; } diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index aa1a4a5f1..78c121d8d 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -27,11 +27,9 @@ // Structs. struct IndiRSIParams : IndicatorParams { - protected: int period; ENUM_APPLIED_PRICE applied_price; - public: IndiRSIParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) : IndicatorParams(INDI_RSI), applied_price(_ap) { shift = _shift; @@ -303,6 +301,10 @@ class Indi_RSI : public Indicator { * (before mode and shift). */ IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override { +#ifdef __debug_indicator__ + Print("Indi_RSI::GetEntryValue(mode = ", _mode, ", abs_shift = ", _abs_shift, ")"); +#endif + double _value = EMPTY_VALUE; ARRAY(double, _res); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -339,3 +341,31 @@ double iRSIOnArray(ARRAY_REF(double, _arr), int _total, int _period, int _abs_sh return Indi_RSI::iRSIOnArray(_arr, _total, _period, _abs_shift); } #endif + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(Indi_RSI_Params) { + emscripten::value_object("indicators.RSIParams") + .field("period", &IndiRSIParams::period) + .field("appliedPrice", &IndiRSIParams::applied_price) + // Inherited fields: + .field("shift", &IndiRSIParams::shift); +} + +EMSCRIPTEN_BINDINGS(Indi_RSIBase) { + emscripten::class_, emscripten::base>("Indi_RSIBase"); +} + +EMSCRIPTEN_BINDINGS(Indi_RSI) { + emscripten::class_>>("indicators.RSI") + .smart_ptr>("Ref") + .constructor(&make_ref) + .constructor(&make_ref) + .constructor(&make_ref, + emscripten::allow_raw_pointer>()) + .constructor(&make_ref, + emscripten::allow_raw_pointer>()); +} + +#endif diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h index 290433783..28e9b9f93 100644 --- a/Indicators/Tick/Indi_TickProvider.h +++ b/Indicators/Tick/Indi_TickProvider.h @@ -67,6 +67,8 @@ class Indi_TickProvider : public IndicatorTick(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_BUILTIN); } string GetName() override { return "Indi_TickProvider"; } @@ -85,6 +87,10 @@ class Indi_TickProvider : public IndicatorTick, _out_ticks)) { +#ifdef __debug_indicator__ + Print("Indi_TickProvider::FetchHistoryByTimeRange(from_ms = ", _from_ms, ", to_ms = ", _to_ms, ")"); +#endif // No history. return false; } @@ -109,12 +118,23 @@ class Indi_TickProvider : public IndicatorTick= ArraySize(buffer)) { +#ifdef __debug_indicator__ + Print("Indi_TickProvider: Tick Index #", _global_tick_index, " is beyond buffer size ", ArraySize(buffer), + ", so acknowledging that there are no more ticks."); +#endif // No more ticks. return false; } TickTAB _tick = buffer[current_index++]; +#ifdef __debug_indicator__ + Print("Indi_TickProvider: OHLC: ", _tick.ToString()); +#endif IndicatorDataEntry _entry(TickToEntry(_tick.GetTimestamp(), _tick)); EmitEntry(_entry); @@ -128,6 +148,11 @@ class Indi_TickProvider : public IndicatorTick +EMSCRIPTEN_BINDINGS(Indi_TickProviderParams) { + emscripten::value_object("indicators.TickProviderParams") + .field("symbol", &Indi_TickProviderParams::symbol); +} + EMSCRIPTEN_BINDINGS(Indi_TickProviderBaseBase) { emscripten::class_, emscripten::base>("IndiTickProviderBaseBase") .smart_ptr>>("Ref>"); @@ -147,6 +172,8 @@ EMSCRIPTEN_BINDINGS(Indi_TickProvider) { "indicators.TickProvider") .smart_ptr>("Ref") .constructor(emscripten::optional_override([]() { return Ref(new Indi_TickProvider()); })) + .constructor(emscripten::optional_override( + [](Indi_TickProviderParams &_p) { return Ref(new Indi_TickProvider(_p)); })) .function("BufferSize", &Indi_TickProvider::BufferSize) .function("Feed", &Indi_TickProvider::Feed); } diff --git a/Refs.struct.h b/Refs.struct.h index b80fa30e7..92e667791 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -284,10 +284,12 @@ struct Ref { } }; -template -Ref MakeRef(T* _ptr) { - return Ref(_ptr); +#ifdef __cplusplus +template +Ref make_ref(Types&&... Args) { + return new T(std::forward(Args)...); } +#endif /** * Class used to hold weak reference to reference-counted object. diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 66f59a9c9..c2edbceca 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -107,6 +107,14 @@ struct TickTAB : TickAB { // Ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. return 0; } + + /** + * Return string representation of tick's OHLC. + */ + string ToString() { + return IntegerToString(time_ms) + ": Ask " + DoubleToString(THIS_ATTR ask) + + ", Bid: " + DoubleToString(THIS_ATTR bid); + } }; struct DoubleTickTAB : TickTAB {}; From 050cee419f4c1ea1a37b702d9bf10ae8eeb25296 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 24 May 2023 19:17:59 +0200 Subject: [PATCH 32/42] Empty commit to run tests. From 2d7e33940c9319f07f356251afa10bb70eabbdf6 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 24 May 2023 19:26:42 +0200 Subject: [PATCH 33/42] Fixes Indi_RSI #elif error. Also, added PERIOD_TF_IRREGULAR enum value for ENUM_TIMEFRAME, so IndicatorTfParams could be initialized as non-tf-based indicator type. --- Chart.enum.h | 3 +++ Indicator/IndicatorRenko.h | 4 ++-- Indicators/Indi_RSI.mqh | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Chart.enum.h b/Chart.enum.h index 1b61aeace..da71f9581 100644 --- a/Chart.enum.h +++ b/Chart.enum.h @@ -169,6 +169,9 @@ EMSCRIPTEN_BINDINGS(ENUM_APPLIED_PRICE) { #endif +// Non-TF based period. Used e.g., by Renko indicator. +#define PERIOD_TF_IRREGULAR ((ENUM_TIMEFRAMES)-1) + // Define type of periods. // @see: https://docs.mql4.com/constants/chartconstants/enum_timeframes #define TFS 21 diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index df4a403da..cea1ff7a0 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -55,11 +55,11 @@ enum ENUM_INDI_RENKO_CANDLE_TYPE { struct RenkoParams : IndicatorTfParams { int pips_limit; - RenkoParams(int _pips_limit = 10, int _shift = 0) : IndicatorTfParams("Renko") { + RenkoParams(int _pips_limit = 10, int _shift = 0) : IndicatorTfParams("Renko", PERIOD_TF_IRREGULAR) { pips_limit = _pips_limit; shift = _shift; }; - RenkoParams(RenkoParams &_params) : IndicatorTfParams("Renko") { THIS_REF = _params; }; + RenkoParams(RenkoParams &_params) : IndicatorTfParams("Renko", PERIOD_TF_IRREGULAR) { THIS_REF = _params; }; // Getters. unsigned int GetSecsPerCandle() { diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 78c121d8d..2b2825a90 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -112,13 +112,15 @@ class Indi_RSI : public Indicator { ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iRSI(_symbol, _tf, _period, _applied_price, _shift); -#elif __MQL5__ +#else +#ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iRSI(_symbol, _tf, _period, _applied_price), 0, _shift); #else RUNTIME_ERROR( "In C++ Indi_RSI::iRSI() method couldn't be used directly. Please use an On-Indicator mode and attach " "indicator via Platform::Add/AddWithDefaultBindings()."); return DBL_MAX; +#endif #endif } From 930cda41307f322211f032252be0f875eb504e7c Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 24 May 2023 19:31:44 +0200 Subject: [PATCH 34/42] Fixes tests using Platform::FetchDefaultCandleIndicator() as method now requires both, symbol and time-frame to be passed. --- Indicator/tests/IndicatorCandle.test.mq5 | 2 +- Indicator/tests/IndicatorRenko.test.mq5 | 2 +- Indicator/tests/IndicatorTf.test.mq5 | 6 +++--- PlatformTime.h | 2 ++ tests/3DTest.mq5 | 2 +- tests/BufferFXTTest.mq5 | 2 +- tests/DrawIndicatorTest.mq5 | 2 +- tests/OrderTest.mq5 | 2 +- 8 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Indicator/tests/IndicatorCandle.test.mq5 b/Indicator/tests/IndicatorCandle.test.mq5 index 79ba7453a..c2bbf072f 100644 --- a/Indicator/tests/IndicatorCandle.test.mq5 +++ b/Indicator/tests/IndicatorCandle.test.mq5 @@ -36,7 +36,7 @@ Ref indi_candle; */ int OnInit() { Platform::Init(); - Platform::Add(indi_candle = Platform::FetchDefaultCandleIndicator()); + Platform::Add(indi_candle = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1)); return _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; } diff --git a/Indicator/tests/IndicatorRenko.test.mq5 b/Indicator/tests/IndicatorRenko.test.mq5 index 483749ff6..80ff7d3b5 100644 --- a/Indicator/tests/IndicatorRenko.test.mq5 +++ b/Indicator/tests/IndicatorRenko.test.mq5 @@ -47,7 +47,7 @@ Ref indi_renko; int OnInit() { Platform::Init(); // Platform ticks. - indi_tick = Platform::FetchDefaultTickIndicator(); + indi_tick = Platform::FetchDefaultTickIndicator("EURUSD"); // Renko with 10 pips limit. Platform::Add(indi_renko = new IndicatorRenko(1)); diff --git a/Indicator/tests/IndicatorTf.test.mq5 b/Indicator/tests/IndicatorTf.test.mq5 index 139e1275f..f4db42ced 100644 --- a/Indicator/tests/IndicatorTf.test.mq5 +++ b/Indicator/tests/IndicatorTf.test.mq5 @@ -55,13 +55,13 @@ Ref indi_ama_custom; int OnInit() { Platform::Init(); // Platform ticks. - indi_tick = Platform::FetchDefaultTickIndicator(); + indi_tick = Platform::FetchDefaultTickIndicator("EURUSD"); // 1-second candles. // indicators.Add(indi_tf = new IndicatorTfDummy(1)); // 1:1 candles from platform using current timeframe. - indi_tf_real = Platform::FetchDefaultCandleIndicator(); + indi_tf_real = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); // 1-second candles. // indicators.Add(indi_ama = new Indi_AMA()); @@ -70,7 +70,7 @@ int OnInit() { _ama_params.applied_price = PRICE_OPEN; // AMA on platform candles. - Platform::Add(indi_ama_orig_sim = new Indi_AMA(_ama_params)); + Platform::AddWithDefaultBindings(indi_ama_orig_sim = new Indi_AMA(_ama_params), "EURUSD", PERIOD_M1); // Original built-in AMA indicator on platform OHLCs. Platform::Add(indi_ama_orig = new Indi_AMA(_ama_params, IDATA_BUILTIN)); diff --git a/PlatformTime.h b/PlatformTime.h index b67cc43dc..5cad5dd3c 100644 --- a/PlatformTime.h +++ b/PlatformTime.h @@ -37,6 +37,8 @@ #include "DateTime.struct.h" #endif +#include "Std.h" + class PlatformTime { static MqlDateTime current_time; static int64 current_timestamp_s; diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 35b329fd5..16e64e77f 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -66,7 +66,7 @@ int OnInit() { _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); _mesh.Ptr().SetShaderPS(_shader_p.Ptr()); - Ref _chart = new Chart3D(Platform::FetchDefaultCandleIndicator(), CHART3D_TYPE_CANDLES); + Ref _chart = new Chart3D(Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1), CHART3D_TYPE_CANDLES); unsigned int _rand_color = rand() * 1256; diff --git a/tests/BufferFXTTest.mq5 b/tests/BufferFXTTest.mq5 index ea1f59814..120f60725 100644 --- a/tests/BufferFXTTest.mq5 +++ b/tests/BufferFXTTest.mq5 @@ -36,7 +36,7 @@ BufferFXT *ticks; */ int OnInit() { Platform::Init(); - ticks = new BufferFXT(Platform::FetchDefaultCandleIndicator()); + ticks = new BufferFXT(Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1)); // Test 1. // @todo return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED); diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index 7863ca883..070545a33 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -47,7 +47,7 @@ int bar_processed; */ int OnInit() { Platform::Init(); - candles = Platform::FetchDefaultCandleIndicator(); + candles = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); bool _result = true; // Initialize indicators. _result &= InitIndicators(); diff --git a/tests/OrderTest.mq5 b/tests/OrderTest.mq5 index 7a0fc2dae..65b5beddf 100644 --- a/tests/OrderTest.mq5 +++ b/tests/OrderTest.mq5 @@ -48,7 +48,7 @@ Order *orders_dummy[MAX_ORDERS]; */ int OnInit() { Platform::Init(); - _candles = Platform::FetchDefaultCandleIndicator(); + _candles = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); bool _result = true; bar_processed = 0; assertTrueOrFail(GetLastError() == ERR_NO_ERROR, StringFormat("Error: %d!", GetLastError())); From df4bb442a5228af2b25d6fb4124e305731db13a3 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 1 Jun 2023 18:34:18 +0200 Subject: [PATCH 35/42] Tiny internal changes. Part of testing emcc API. --- Platform.h | 13 +++++++++---- Std.h | 5 ++++- String.extern.h | 39 +++++++++++++++++++++++++++++++++++++-- tests/IndicatorsTest.mq5 | 4 ++-- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/Platform.h b/Platform.h index 3800f0159..811bd6223 100644 --- a/Platform.h +++ b/Platform.h @@ -126,7 +126,8 @@ class Platform { last_tick_result = false; for (_iter = indis.Begin(); _iter.IsValid(); ++_iter) { - // Updating current symbol and timeframe to the ones used by ticking indicator and its parents. + // Print("Ticking ", _iter.Value() REF_DEREF GetFullName()); + // Updating current symbol and timeframe to the ones used by ticking indicator and its parents. symbol = _iter.Value() REF_DEREF GetSymbol(); period = _iter.Value() REF_DEREF GetTf(); @@ -313,11 +314,15 @@ class Platform { */ static IndicatorData *FetchDefaultCandleIndicator(string _symbol, ENUM_TIMEFRAMES _tf) { if (_symbol == PLATFORM_WRONG_SYMBOL) { - RUNTIME_ERROR("Cannot fetch default candle indicator for unknown symbol!"); + Print("Cannot fetch default candle indicator for unknown symbol \"", _symbol, "\" (passed TF value ", (int)_tf, + ")!"); + DebugBreak(); } if (_tf == PERIOD_CURRENT || _tf == PLATFORM_WRONG_TIMEFRAME) { - RUNTIME_ERROR("Cannot fetch default candle indicator for unknown period/timeframe!"); + Print("Cannot fetch default candle indicator for unknown period/timeframe (passed symbol \"", _symbol, + "\", TF value ", (int)_tf, ")!"); + DebugBreak(); } // Candle is per symbol and TF. Single Candle indicator can't handle multiple TFs. @@ -344,7 +349,7 @@ class Platform { */ static IndicatorData *FetchDefaultTickIndicator(string _symbol) { if (_symbol == PLATFORM_WRONG_SYMBOL) { - RUNTIME_ERROR("Cannot fetch default tick indicator for unknown symbol!"); + RUNTIME_ERROR("Cannot fetch default tick indicator for unknown symbol for indicator ", GetFullName(), "!"); } string _key = Util::MakeKey("PlatformIndicatorTick", _symbol); diff --git a/Std.h b/Std.h index 8f5ca61de..ecaa13dc3 100644 --- a/Std.h +++ b/Std.h @@ -26,6 +26,9 @@ #include "Math.define.h" #endif +// Includes. +#include "Data.enum.h" + // Data types. #ifdef __cplusplus #include @@ -126,7 +129,7 @@ * ARRAY_REF(, ) */ #define ARRAY_TYPE(T) _cpp_array -#define ARRAY_REF(T, N) ARRAY_TYPE(T)& N +#define ARRAY_REF(T, N) ARRAY_TYPE(T) & N #define FIXED_ARRAY_REF(T, N, S) T(&N)[S] #define CONST_ARRAY_REF(T, N) const _cpp_array& N diff --git a/String.extern.h b/String.extern.h index 4064372b9..487cde055 100644 --- a/String.extern.h +++ b/String.extern.h @@ -55,7 +55,7 @@ int StringSplit(const string& string_value, const unsigned short separator, ARRA return result.size(); } long StringToInteger(string value) { return std::stol(value); } -string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol = ' ') { +string IntegerToString(int64 number, int str_len = 0, unsigned short fill_symbol = ' ') { return std::to_string(number); } @@ -73,7 +73,7 @@ void PrintTo(std::ostream& out, Arg&& arg, Args&&... args) { out << std::forward(arg); using expander = int[]; (void)expander{0, (void(out << std::forward(args)), 0)...}; - out << "\n"; + out << std::endl; out.flush(); } @@ -147,4 +147,39 @@ string StringToUpper(string str) { return str; } +string EnumToString(ENUM_DATATYPE _value) { + switch (_value) { + case TYPE_BOOL: + return "TYPE_BOOL"; + case TYPE_CHAR: + return "TYPE_CHAR"; + case TYPE_COLOR: + return "TYPE_COLOR"; + case TYPE_DATETIME: + return "TYPE_DATETIME"; + case TYPE_DOUBLE: + return "TYPE_DOUBLE"; + case TYPE_FLOAT: + return "TYPE_FLOAT"; + case TYPE_INT: + return "TYPE_INT"; + case TYPE_LONG: + return "TYPE_LONG"; + case TYPE_SHORT: + return "TYPE_SHORT"; + case TYPE_STRING: + return "TYPE_STRING"; + case TYPE_UCHAR: + return "TYPE_UCHAR"; + case TYPE_UINT: + return "TYPE_UINT"; + case TYPE_ULONG: + return "TYPE_ULONG"; + case TYPE_USHORT: + return "TYPE_USHORT"; + } + + return ""; +} + #endif diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index c113d8892..d412f4b93 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -76,7 +76,7 @@ int OnInit() { Print("Connecting candle and tick indicators to all indicators..."); // Connecting all indicators to default candle indicator (which is connected to default tick indicator). for (int i = 0; i < indis.Size(); ++i) { - Platform::AddWithDefaultBindings(indis[i], _Symbol, PERIOD_CURRENT); + Platform::AddWithDefaultBindings(indis[i], _Symbol, PERIOD_M1); } // Check for any errors. @@ -96,7 +96,7 @@ int OnInit() { */ void OnTick() { Platform::Tick(); - IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); + IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_M1); if (_candles PTR_DEREF IsNewBar()) { if (_candles PTR_DEREF GetBarIndex() > 550) { From b3a7f4a9d807e9583bcb715192dd988d121668e5 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 5 Jun 2023 14:11:46 +0200 Subject: [PATCH 36/42] Fixes warning "too many arguments for function-like macro 'RUNTIME_ERROR'" --- Platform.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Platform.h b/Platform.h index 811bd6223..f1805daa5 100644 --- a/Platform.h +++ b/Platform.h @@ -349,7 +349,8 @@ class Platform { */ static IndicatorData *FetchDefaultTickIndicator(string _symbol) { if (_symbol == PLATFORM_WRONG_SYMBOL) { - RUNTIME_ERROR("Cannot fetch default tick indicator for unknown symbol for indicator ", GetFullName(), "!"); + Alert("Cannot fetch default tick indicator for unknown symbol!"); + DebugBreak(); } string _key = Util::MakeKey("PlatformIndicatorTick", _symbol); From 69220b5e56485850f04538fe0babb30bd29cbcc1 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 8 Jun 2023 16:42:57 +0200 Subject: [PATCH 37/42] Should fix problem with MA expecting additional bar, despite it has all required bars to generate averages. --- Indicators/Indi_Envelopes.mqh | 7 +++++-- Indicators/Indi_MA.mqh | 3 ++- Indicators/Indi_Momentum.mqh | 4 ---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index e5b813c06..2eac502d7 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -150,8 +150,6 @@ class Indi_Envelopes : public Indicator { int _mode, // (MT4 _mode): 0 - MODE_MAIN, 1 - MODE_UPPER, 2 - MODE_LOWER; (MT5 // _mode): 0 - UPPER_LINE, 1 - LOWER_LINE int _shift = 0) { - INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, _shift + _ma_shift + _ma_period); - return iEnvelopesOnArray(_source.GetSpecificAppliedPriceValueStorage(_ap, _target), 0, _ma_period, _ma_method, _ma_shift, _deviation, _mode, _shift, _target PTR_DEREF GetCache()); } @@ -173,6 +171,11 @@ class Indi_Envelopes : public Indicator { static double iEnvelopesOnArray(ValueStorage *_price, int _total, int _ma_period, ENUM_MA_METHOD _ma_method, int _ma_shift, double _deviation, int _mode, int _shift, IndicatorCalculateCache *_cache = NULL) { + // We need 1 bar more because MA methods assumes we have historic bars. + if (_price PTR_DEREF Size() < _shift + _ma_shift + _ma_period + 1) { + return DBL_MIN; + } + double _indi_value_buffer[]; double _result; diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 2f1a7ec69..2fe09b214 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -134,7 +134,8 @@ class Indi_MA : public Indicator { unsigned int ma_period, unsigned int ma_shift, ENUM_MA_METHOD ma_method, // (MT4/MT5): MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA ENUM_APPLIED_PRICE _ap, int shift = 0) { - INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, int(ma_period + ma_shift + shift)); + // We need 1 bar more because MA methods assumes we have historic bars. + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, int(ma_period + ma_shift + shift + 1)); ValueStorage *_data = (ValueStorage *)_source.GetSpecificAppliedPriceValueStorage(_ap, _target); return iMAOnArray(_data, 0, ma_period, ma_shift, ma_method, shift, _target PTR_DEREF GetCache()); } diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 159f38f41..4b7602ee7 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -109,13 +109,9 @@ class Indi_Momentum : public Indicator { double _indi_value_buffer[]; IndicatorDataEntry _entry(_indi.GetModeCount()); - _period += 1; - ArrayResize(_indi_value_buffer, _period); for (int i = 0; i < (int)_period; i++) { - // Print(": Getting data from ", _indi PTR_DEREF GetFullName(), " from shift ", i); - // Getting value from single, selected buffer. _indi_value_buffer[i] = _indi[i].GetValue(_mode); } From 03bcdf30388347850f1e552e2f99fc80bd7d14b9 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 8 Jun 2023 21:28:50 +0200 Subject: [PATCH 38/42] Little changes required by emcc support. --- Chart.struct.tf.h | 8 ++++++++ Indicator/Indicator.enum.h | 9 +++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 8eb01b41c..ddcfc17fc 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -186,6 +186,14 @@ struct ChartTf { return PERIOD_CURRENT; } + /** + * Convert timeframe period to miliseconds. + * + * @param + * _tf ENUM_TIMEFRAMES Specify timeframe enum. + */ + static int64 TfToMs(const ENUM_TIMEFRAMES _tf) { return (int64)TfToSeconds(_tf) * 1000; } + /** * Convert timeframe period to seconds. * diff --git a/Indicator/Indicator.enum.h b/Indicator/Indicator.enum.h index d5fd94008..f67244456 100644 --- a/Indicator/Indicator.enum.h +++ b/Indicator/Indicator.enum.h @@ -193,10 +193,11 @@ enum ENUM_APPLIED_VOLUME { VOLUME_TICK = 0, VOLUME_REAL = 1 }; // Indicator flags. enum ENUM_INDI_FLAGS { - INDI_FLAG_INDEXABLE_BY_SHIFT = 1 << 0, // Indicator supports indexation by shift. - INDI_FLAG_INDEXABLE_BY_TIMESTAMP = 1 << 1, // Indicator supports indexation by shift. - INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT = 1 << 2, // Source indicator must be indexable by shift. - INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP = 1 << 3 // Source indicator must be indexable by timestamp. + INDI_FLAG_INDEXABLE_BY_SHIFT = 1 << 0, // Indicator supports indexation by shift. + INDI_FLAG_INDEXABLE_BY_TIMESTAMP = 1 << 1, // Indicator supports indexation by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT = 1 << 2, // Source indicator must be indexable by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP = 1 << 3, // Source indicator must be indexable by timestamp. + INDI_FLAG_LOOSE_TF_CANDLE_INDICATOR = 1 << 4 // It is a non TF-based indicator, e.g., Renko. }; // Flags indicating which data sources are required to be provided in order indicator to work. From d53d07aa1745ab5efba7d7a7d7766600476b83f8 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 15 Jun 2023 15:28:06 +0200 Subject: [PATCH 39/42] Should fix problems with DrawIndicatorTest as Platform::AddWithDefaultBindings() must take symbol and time-frame (we use fixed pair of symbol and time-frame, so code will work in c++). --- Platform.h | 3 +-- tests/DrawIndicatorTest.mq5 | 16 +++++++++------- tests/IndicatorsTest.mq5 | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Platform.h b/Platform.h index f1805daa5..c02abac4b 100644 --- a/Platform.h +++ b/Platform.h @@ -186,8 +186,7 @@ class Platform { /** * Adds indicator to be processed by platform and tries to initialize its data source(s). */ - static void AddWithDefaultBindings(IndicatorData *_indi, CONST_REF_TO(string) _symbol = "", - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + static void AddWithDefaultBindings(IndicatorData *_indi, CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { Add(_indi); BindDefaultDataSource(_indi, _symbol, _tf); } diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index 070545a33..5081ff6f4 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -24,8 +24,8 @@ * Test functionality of DrawIndicator class. */ -#define __debug__ -#define __debug_verbose__ +//#define __debug__ +//#define __debug_verbose__ // Includes. #include "../DictStruct.mqh" @@ -73,7 +73,9 @@ void OnTick() { _indi.OnTick(Platform::GetGlobalTickIndex()); IndicatorDataEntry _entry = _indi.GetEntry(); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)) && _entry.IsValid()) { +#ifdef __debug__ PrintFormat("%s: bar %d: %s", _indi.GetName(), bar_processed, _indi.ToString()); +#endif } } } @@ -92,28 +94,28 @@ bool InitIndicators() { // Bollinger Bands. IndiBandsParams bands_params(20, 2, 0, PRICE_MEDIAN); - Platform::AddWithDefaultBindings(new Indi_Bands(bands_params)); + Platform::AddWithDefaultBindings(new Indi_Bands(bands_params), "EURUSD", PERIOD_M1); // Moving Average. IndiMAParams ma_params(13, 10, MODE_SMA, PRICE_OPEN); - Platform::AddWithDefaultBindings(new Indi_MA(ma_params)); + Platform::AddWithDefaultBindings(new Indi_MA(ma_params), "EURUSD", PERIOD_M1); // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); - Platform::AddWithDefaultBindings(new Indi_RSI(rsi_params)); + Platform::AddWithDefaultBindings(new Indi_RSI(rsi_params), "EURUSD", PERIOD_M1); /* Special indicators */ // Demo/Dummy Indicator. IndiDemoParams demo_params; - Platform::AddWithDefaultBindings(new Indi_Demo(demo_params)); + Platform::AddWithDefaultBindings(new Indi_Demo(demo_params), "EURUSD", PERIOD_M1); #ifndef __MQL4__ // @fixme: Make it work for MT4. // Current Price (used by custom indicators) . PriceIndiParams price_params(); // price_params.SetDraw(clrGreenYellow); - Platform::AddWithDefaultBindings(new Indi_Price(price_params)); + Platform::AddWithDefaultBindings(new Indi_Price(price_params), "EURUSD", PERIOD_M1); #endif /* @fixme: Array out of range. diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index d412f4b93..c06263758 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -76,7 +76,7 @@ int OnInit() { Print("Connecting candle and tick indicators to all indicators..."); // Connecting all indicators to default candle indicator (which is connected to default tick indicator). for (int i = 0; i < indis.Size(); ++i) { - Platform::AddWithDefaultBindings(indis[i], _Symbol, PERIOD_M1); + Platform::AddWithDefaultBindings(indis[i], "EURUSD", PERIOD_M1); } // Check for any errors. From b246c9db3e46416c796f188e05cb98340bf39b98 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 15 Jun 2023 18:13:54 +0200 Subject: [PATCH 40/42] Fixing CompileTest --- 3D/Cube.h | 4 ++-- 3D/Device.h | 29 +++++++++++++++++------------ 3D/Devices/MTDX/MTDXDevice.h | 14 +++++--------- 3D/Mesh.h | 4 ++-- Platform.h | 2 +- tests/3DTest.mq5 | 4 ++-- 6 files changed, 29 insertions(+), 28 deletions(-) diff --git a/3D/Cube.h b/3D/Cube.h index 0bc9038ff..5ed20a8b9 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -77,8 +77,8 @@ class Cube : public Mesh { * Initializes graphics device-related things. */ virtual void Initialize(Device* _device) { - SetShaderVS(_device.VertexShader(ShaderCubeSourceVS, T::Layout)); - SetShaderPS(_device.PixelShader(ShaderCubeSourcePS)); + SetShaderVS(_device.CreateVertexShader(ShaderCubeSourceVS, T::Layout)); + SetShaderPS(_device.CreatePixelShader(ShaderCubeSourcePS)); } #endif }; diff --git a/3D/Device.h b/3D/Device.h index d7b64f94f..5124a22ac 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -138,20 +138,25 @@ class Device : public Dynamic { /** * Creates vertex shader to be used by current graphics device. */ - virtual Shader* VertexShader(string _source_code, const ShaderVertexLayout& _layout[], - string _entry_point = "main") = NULL; + virtual Shader* CreateVertexShader(string _source_code, const ShaderVertexLayout& _layout[], + string _entry_point = "main") = NULL; /** * Creates pixel shader to be used by current graphics device. */ - virtual Shader* PixelShader(string _source_code, string _entry_point = "main") = NULL; + virtual Shader* CreatePixelShader(string _source_code, string _entry_point = "main") = 0; + + /** + * Creates vertex buffer to be used by current graphics device. + */ + virtual VertexBuffer* CreateVertexBuffer() = 0; /** * Creates vertex buffer to be used by current graphics device. */ template - VertexBuffer* VertexBuffer(T& data[]) { - VertexBuffer* _buff = VertexBuffer(); + VertexBuffer* CreateVertexBuffer(T& data[]) { + VertexBuffer* _buff = CreateVertexBuffer(); // Unfortunately we can't make this method virtual. if (dynamic_cast(_buff) != NULL) { // MT5's DirectX. @@ -165,15 +170,10 @@ class Device : public Dynamic { return _buff; } - /** - * Creates vertex buffer to be used by current graphics device. - */ - virtual VertexBuffer* VertexBuffer() = NULL; - /** * Creates index buffer to be used by current graphics device. */ - virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) = NULL; + virtual IndexBuffer* CreateIndexBuffer(unsigned int& _indices[]) = 0; /** * Renders vertex buffer with optional point indices. @@ -183,7 +183,7 @@ class Device : public Dynamic { /** * Renders vertex buffer with optional point indices. */ - virtual void RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; + virtual void RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = 0; /** * Renders given mesh. @@ -233,6 +233,11 @@ class Device : public Dynamic { int Height() { return frontend.Ptr().Height(); } void SetCameraOrtho3D(float _pos_x = 0.0f, float _pos_y = 0.0f, float _pos_z = 0.0f) { + if (Width() <= 0 || Height() <= 0) { + Print("Cannot set 2D camera as width or height of the viewport is zero!"); + DebugBreak(); + return; + } DXMatrixOrthoLH(mtx_projection, 1.0f * _pos_z, 1.0f / Width() * Height() * _pos_z, -10000, 10000); } diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 7bb1c93b8..166a924ed 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -93,15 +93,11 @@ class MTDXDevice : public Device { } } - /** - * Creates index buffer to be used by current graphics device. - */ - IndexBuffer* IndexBuffer() { return NULL; } - /** * Creates vertex shader to be used by current graphics device. */ - virtual Shader* VertexShader(string _source_code, const ShaderVertexLayout& _layout[], string _entry_point = "main") { + Shader* CreateVertexShader(string _source_code, const ShaderVertexLayout& _layout[], + string _entry_point = "main") override { MTDXShader* _shader = new MTDXShader(&this); _shader.Create(SHADER_TYPE_VS, _source_code, _entry_point); _shader.SetDataLayout(_layout); @@ -111,7 +107,7 @@ class MTDXDevice : public Device { /** * Creates pixel shader to be used by current graphics device. */ - virtual Shader* PixelShader(string _source_code, string _entry_point = "main") { + Shader* CreatePixelShader(string _source_code, string _entry_point = "main") override { MTDXShader* _shader = new MTDXShader(&this); _shader.Create(SHADER_TYPE_PS, _source_code, _entry_point); return _shader; @@ -120,12 +116,12 @@ class MTDXDevice : public Device { /** * Creates vertex buffer to be used by current graphics device. */ - VertexBuffer* VertexBuffer() { return new MTDXVertexBuffer(&this); } + VertexBuffer* CreateVertexBuffer() override { return new MTDXVertexBuffer(&this); } /** * Creates index buffer to be used by current graphics device. */ - virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) { + IndexBuffer* CreateIndexBuffer(unsigned int& _indices[]) override { IndexBuffer* _buffer = new MTDXIndexBuffer(&this); _buffer.Fill(_indices); return _buffer; diff --git a/3D/Mesh.h b/3D/Mesh.h index 719b33aff..d77c6ede8 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -254,8 +254,8 @@ class Mesh : public Dynamic { Print("Indices: ", _s_indices); #endif - vbuff = _vbuff = _device.VertexBuffer(_vertices); - ibuff = _ibuff = _device.IndexBuffer(_indices); + vbuff = _vbuff = _device.CreateVertexBuffer(_vertices); + ibuff = _ibuff = _device.CreateIndexBuffer(_indices); return true; } }; diff --git a/Platform.h b/Platform.h index c02abac4b..0431390d4 100644 --- a/Platform.h +++ b/Platform.h @@ -817,7 +817,7 @@ datetime StructToTime(MqlDateTime &dt_struct) { \ int OnInit() { \ Platform::Init(); \ - Platform::AddWithDefaultBindings(indi.Ptr()); \ + Platform::AddWithDefaultBindings(indi.Ptr(), "EURUSD", PERIOD_M1); \ bool _result = true; \ assertTrueOrFail(indi REF_DEREF IsValid(), "Error on IsValid!"); \ return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); \ diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 16e64e77f..9ac4d2872 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -59,8 +59,8 @@ int OnInit() { gfx.Start(new MT5Frontend()); - Ref _shader_v = gfx.VertexShader(ShaderSourceVS, Vertex::Layout); - Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + Ref _shader_v = gfx.CreateVertexShader(ShaderSourceVS, Vertex::Layout); + Ref _shader_p = gfx.CreatePixelShader(ShaderSourcePS); Ref> _mesh = new Cube(1.0f, 1.0f, 1.0f); _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); From 78d86348f7e5fcf757708aebd9a1e5f59934504b Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 15 Jun 2023 19:32:44 +0200 Subject: [PATCH 41/42] Fixes problem with not preserving TF passed to Candle indicators. --- Indicator/IndicatorTf.h | 5 +---- Platform.h | 23 +++++++++++++++++++---- tests/TradeTest.mq5 | 9 ++++----- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index c4195c68b..00f2ec094 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -39,9 +39,6 @@ template class IndicatorTf : public IndicatorCandle> { protected: - // Time-frame used to create candles. - ENUM_TIMEFRAMES tf; - /* Protected methods */ /** @@ -80,7 +77,7 @@ class IndicatorTf : public IndicatorCandle _ref = _indi; + + DictStructIterator> _iter; + for (_iter = indis_dflt.Begin(); _iter.IsValid(); ++_iter) { + if (_iter.Value() == _ref) { + Alert("Warning: ", _indi PTR_DEREF GetFullName(), + " was already added as default candle/tick indicator and shouldn't be added by Platform:Add() as default " + "indicators are also ticked when calling Platform::Tick()."); + DebugBreak(); + } + } + indis.Set(_indi PTR_DEREF GetId(), _ref); } @@ -333,11 +344,15 @@ class Platform { // Adding indicator to list of default indicators in order to tick it on every Tick() call. Ref _ref = _indi_candle; indis_dflt.Set(_indi_candle PTR_DEREF GetId(), _ref); - } - if (!_indi_candle PTR_DEREF HasDataSource()) { - // Missing tick indicator. - _indi_candle PTR_DEREF InjectDataSource(FetchDefaultTickIndicator(_symbol)); + if (!_indi_candle PTR_DEREF HasDataSource()) { + // Missing tick indicator. + _indi_candle PTR_DEREF InjectDataSource(FetchDefaultTickIndicator(_symbol)); + } +#ifdef __debug__ + Print("Added default candle indicator for symbol ", _symbol, " and time-frame ", _tf, ". Now it has symbol ", + _indi_candle PTR_DEREF GetSymbol(), " and time-frame ", EnumToString(_indi_candle PTR_DEREF GetTf())); +#endif } return _indi_candle; diff --git a/tests/TradeTest.mq5 b/tests/TradeTest.mq5 index 55ff0c3a4..cc828bdd7 100644 --- a/tests/TradeTest.mq5 +++ b/tests/TradeTest.mq5 @@ -46,10 +46,9 @@ bool _finish_test = false; */ int OnInit() { Platform::Init(); - _chart_m1 = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_M1); - _chart_m5 = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_M5); - Platform::Add(_chart_m1.Ptr()); - Platform::Add(_chart_m5.Ptr()); + _chart_m1 = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); + _chart_m5 = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M5); + return INIT_SUCCEEDED; } @@ -83,7 +82,7 @@ int Test() { // Test market. assertTrueOrFail(trade1 PTR_DEREF IsTradeAllowed(), "Trade not allowed!"); assertTrueOrFail(trade1 PTR_DEREF GetSource() PTR_DEREF GetTf() == PERIOD_M1, - StringFormat("Fail on GetTf() => [%s]!", trade1 PTR_DEREF GetSource() PTR_DEREF GetTf())); + StringFormat("Fail on GetTf() => [%d]!", trade1 PTR_DEREF GetSource() PTR_DEREF GetTf())); assertTrueOrFail(trade1 PTR_DEREF GetSource() PTR_DEREF GetOpen() > 0, "Fail on GetOpen()!"); assertTrueOrFail(trade1 PTR_DEREF GetSource() PTR_DEREF GetSymbol() == _Symbol, "Fail on GetSymbol()!"); // assertTrueOrFail(trade1.IsTradeAllowed(), "Fail on IsTradeAllowed()!"); // @fixme From 94d2da46e83dd7bad64be2b94c4f907c44e01808 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 16 Jun 2023 14:36:16 +0200 Subject: [PATCH 42/42] Fixes ZigZag and ZigZagColor value validation. --- Indicators/Indi_ZigZag.mqh | 4 +++- Indicators/Indi_ZigZagColor.mqh | 8 +++++--- Platform.h | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index fcb56a4d2..3242fd352 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -404,7 +404,9 @@ class Indi_ZigZag : public Indicator { /** * Checks if indicator entry values are valid. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return !_entry.HasValue(EMPTY_VALUE); } + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return _entry.values[0].Get() != DBL_MAX && _entry.values[0].Get() != EMPTY_VALUE; + } /* Getters */ diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index d0fcc7925..187bf02f3 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -61,13 +61,13 @@ class Indi_ZigZagColor : public Indicator { IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) : Indicator( _p, IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), - _indi_src){}; + _indi_src) {} Indi_ZigZagColor(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) : Indicator( IndiZigZagColorParams(), IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), - _indi_src){}; + _indi_src) {} /** * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. */ @@ -321,7 +321,9 @@ class Indi_ZigZagColor : public Indicator { /** * Checks if indicator entry values are valid. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return _entry.values[0].Get() != EMPTY_VALUE; } + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return _entry.values[0].Get() != DBL_MAX && _entry.values[0].Get() != EMPTY_VALUE; + } /* Getters */ diff --git a/Platform.h b/Platform.h index 041d239fd..b5f5a3828 100644 --- a/Platform.h +++ b/Platform.h @@ -844,7 +844,7 @@ datetime StructToTime(MqlDateTime &dt_struct) { IndicatorDataEntry _entry = indi REF_DEREF GetEntry(); \ bool _is_ready = indi REF_DEREF Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)); \ bool _is_valid = _entry.IsValid(); \ - Print(indi REF_DEREF ToString(), _is_ready ? "" : " (Not yet ready)"); \ + Print(indi REF_DEREF ToString(), _is_ready ? " (Ready)" : " (Not yet ready)"); \ if (_is_ready && !_is_valid) { \ Print(indi REF_DEREF ToString(), " (Invalid entry!)"); \ assertTrueOrExit(_entry.IsValid(), "Invalid entry!"); \