From 0ddfa5869f45ad189070b95f7f6004daeff79abb Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 22 Nov 2023 19:06:32 +0100 Subject: [PATCH] Refs EA31337/EA31337-indicators-other#8. Added IndicatorLegacy.h file to allow using MQL5 versions of iNAME() indicators like iMA(), iRSI() in MQL4. Used to run MQL5 indicators in MQL4. --- IndicatorLegacy.h | 369 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 IndicatorLegacy.h diff --git a/IndicatorLegacy.h b/IndicatorLegacy.h new file mode 100644 index 000000000..0a5ef4dd6 --- /dev/null +++ b/IndicatorLegacy.h @@ -0,0 +1,369 @@ +/** + * @file + * Wrappers to be used by MQL4 code to allow calling MQL5's indicator functions like iMA() in MQL4. + */ + +#ifndef __MQL__ +#pragma once +#endif + +#ifdef __MQL4__ + +#include +#include +#include +#include + +/** + * Replacement for future OnCalculate(). Currently not used, but could be handy in the future. + */ +int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], + const double& high[], const double& low[], const double& close[], const long& tick_volume[], + const long& volume[], const int& spread[]) { + int _num_calculated = + OnCalculateMT5(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread); + + return _num_calculated; +} + +#define OnCalculate OnCalculateMT5 + +/** + * Wrapper class to be used by MQL4 code to allow calling MQL5's indicator functions like iMA() in MQL4. + */ +class IndicatorLegacy : public Dynamic { + // Handle to be used by BarsCalculated(), CopyBuffer() and so on. + int handle; + + // Name of the indicator. + string name; + + public: + /** + * Constructor. + */ + IndicatorLegacy(string _name) : name(_name) { handle = indis.Size(); } + + /** + * Returns indicator's handle. + */ + int GetHandle() { return handle; } + + /** + * Returns name of the indicator. + */ + string GetName() { return name; } + + /** + * Returns value for a given shift. + */ + virtual double GetValue(int _shift) = 0; + + /** + * Returns number of bars calculated for this indicator. + */ + int GetBarsCalculated() { + // @todo We probably need to replace it with some more specific check per indicator. + return Bars; + } + + // Dictionary of registered indicators (key -> indicator). + static DictStruct> indis; + + // Dictionary of registered indicators (handle -> indicator). + static DictStruct> indis_handles; + + /** + * Returns number of bars calculated for a given indicator's handle. + */ + static int GetBarsCalculated(int _handle) { + if (_handle < 0 || _handle >= (int)indis.Size()) { + Print("Error: Given handle index is out of bounds! Given handle index ", _handle, " and there is ", indis.Size(), + " handles available."); + DebugBreak(); + return 0; + } + + IndicatorLegacy* _indi = indis_handles[_handle].Ptr(); + return PTR_ATTRIB(_indi, GetBarsCalculated()); + } +}; + +DictStruct> IndicatorLegacy::indis; +DictStruct> IndicatorLegacy::indis_handles; + +/** + * MQL4 wrapper of MQL5's BarsCalculated(). + */ +int BarsCalculated(int _handle) { return IndicatorLegacy::GetBarsCalculated(_handle); } + +/** + * MQL4 wrapper of MQL5's CopyBuffer(). + */ +int CopyBuffer(int _handle, int _mode, int _start, int _count, double& _buffer[]) { + IndicatorLegacy* _indi = IndicatorLegacy::indis_handles[_handle].Ptr(); + + if (_mode != 0) { + Print("Only mode 0 is supported for ", PTR_ATTRIB(_indi, GetName()), + " legacy indicator as MQL4 supports only a single mode."); + DebugBreak(); + return 0; + } + + int _num_copied = 0; + int _buffer_size = ArraySize(_buffer); + + if (_buffer_size < _count) { + _buffer_size = ArrayResize(_buffer, _count); + } + + for (int i = 0; i < _count; ++i) { + double _value = PTR_ATTRIB(_indi, GetValue(_start + i)); + + if (_value == WRONG_VALUE) { + break; + } + + _buffer[_buffer_size - i - 1] = _value; + ++_num_copied; + } + + return _num_copied; +} + +/** + * Defines wrapper class and global iNAME() indicator function (e.g., iMA(), iATR()). + */ +// Print(#FN_NAME " key = ", _key); \ +#define DEFINE_LEGACY_INDICATOR(FN_NAME, BUILTIN_NAME, TYPED_PARAMS_COMMA, TYPED_PARAMS_NO_UDL_SEMICOLON, UNTYPED_PARAMS_COMMA_KEY, UNTYPED_PARAMS_COMMA_VALUES, ASSIGNMENTS_COMMA, UNTYPED_PARAMS_NO_UDL_COMMA_VALUES) \ +class BUILTIN_NAME##Legacy : public IndicatorLegacy { \ + TYPED_PARAMS_NO_UDL_SEMICOLON; \ +public: \ + BUILTIN_NAME##Legacy(string _name, TYPED_PARAMS_COMMA) : IndicatorLegacy(_name), ASSIGNMENTS_COMMA {} \ + virtual double GetValue(int _shift) { \ + double _value = ::BUILTIN_NAME(UNTYPED_PARAMS_NO_UDL_COMMA_VALUES, _shift); \ + if (false) Print(GetName(), "[-", _shift, "]: ", _value); \ + return _value; \ + } \ +}; \ +int FN_NAME(TYPED_PARAMS_COMMA) { \ + Ref _indi; \ + int _handle = INVALID_HANDLE; \ + string _key = Util::MakeKey(#FN_NAME, UNTYPED_PARAMS_COMMA_KEY); \ + if (IndicatorLegacy::indis.KeyExists(_key)) { \ + _indi = IndicatorLegacy::indis[_key]; \ + } \ + else { \ + _indi = new BUILTIN_NAME##Legacy(#BUILTIN_NAME, UNTYPED_PARAMS_COMMA_VALUES); \ + IndicatorLegacy::indis.Set(_key, _indi); \ + IndicatorLegacy::indis_handles.Set(PTR_ATTRIB(_indi.Ptr(), GetHandle()), _indi); \ + } \ + return PTR_ATTRIB(_indi.Ptr(), GetHandle()); \ +} + +/** + * 1-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_1(FN_NAME, INDI_NAME, T1, N1) \ + DEFINE_LEGACY_INDICATOR(INDI_NAME, T1 _##N1, T1 N1, _##N1, _##N1, N1(_##N1), N1); + +/** + * 2-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_2(FN_NAME, INDI_NAME, T1, N1, T2, N2) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2, T1 N1 SEMICOLON T2 N2, _##N1 COMMA _##N2, \ + _##N1 COMMA _##N2, N1(_##N1) COMMA N2(_##N2), N1 COMMA N2); + +/** + * 3-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_3(FN_NAME, INDI_NAME, T1, N1, T2, N2, T3, N3) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3, _##N1 COMMA _##N2 COMMA _##N3, \ + _##N1 COMMA _##N2 COMMA _##N3, N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3), \ + N1 COMMA N2 COMMA N3); + +/** + * 4-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_4(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4), N1 COMMA N2 COMMA N3 COMMA N4); + +/** + * 5-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_5(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5); + +/** + * 6-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_6(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6); + +/** + * 7-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_7(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR( \ + FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 _##N7, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 SEMICOLON T7 N7, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) COMMA N7(_##N7), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7); + +/** + * 8-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_8(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 \ + _##N7 COMMA T8 _##N8, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 \ + SEMICOLON T7 N7 SEMICOLON T8 N8, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) \ + COMMA N7(_##N7) COMMA N8(_##N8), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7 COMMA N8); + +/** + * Replacement for future StringConcatenate(). + */ +#define StringConcatenate StringConcatenateMT5 + +/** + * MQL4 wrapper of MQL5's StringConcatenate(). + */ +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j, K _k, L _l, + M _m) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k + (string)_l + (string)_m; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j, K _k, L _l) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k + (string)_l; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j, K _k) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d) { + _result = (string)_a + (string)_b + (string)_c + (string)_d; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c) { + _result = (string)_a + (string)_b + (string)_c; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b) { + _result = (string)_a + (string)_b; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a) { + _result = (string)_a; + return StringLen(_result); +} + +// ----- LEGACY INDICATOR DEFINITIONS + +// int iAC(string symbol, ENUM_TIMEFRAMES period); +DEFINE_LEGACY_INDICATOR_2(iAC, iAC, string, symbol, int, period); + +// int iAD(string symbol, ENUM_TIMEFRAMES period, ENUM_APPLIED_VOLUME applied_volume); +DEFINE_LEGACY_INDICATOR_2(iAD, iAD, string, symbol, int, period); + +// int iATR(string symbol, ENUM_TIMEFRAMES period, int ma_period); +DEFINE_LEGACY_INDICATOR_3(iATR, iATR, string, symbol, int, period, int, ma_period); + +// int iMA(string symbol, ENUM_TIMEFRAMES period, int ma_period, int ma_shift, ENUM_MA_METHOD ma_method, +// ENUM_APPLIED_PRICE applied_price); +#define T1 string +#define N1 symbol +#define T2 int +#define N2 period +#define T3 int +#define N3 ma_period +#define T4 int +#define N4 ma_shift +#define T5 int +#define N5 ma_method +#define T6 int +#define N6 applied_price +DEFINE_LEGACY_INDICATOR_6(iMA, iMA) +#undef T1 +#undef N1 +#undef T2 +#undef N2 +#undef T3 +#undef N3 +#undef T4 +#undef N4 +#undef T5 +#undef N5 +#undef T6 +#undef N6 + +#endif