From 9fb10086d771f47f19f7c8d87c265f5e1e32510b Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 1 Dec 2023 19:38:01 +0100 Subject: [PATCH 1/3] Refs EA31337-classes/EA31337-indicators-other#13, EA31337-classes/EA31337-indicators-other#15. WIP. TDI-RT-Clone and Heiken_Ashi_Smoothed indicators made to work in MT5. --- Indicator.define.h | 3 +- IndicatorLegacy.h | 119 +++++++++++++++++++++++++++++++++- Indicators/Indi_MA.mqh | 95 +++++++++++++++++++++++++-- Storage/ValueStorage.native.h | 16 ++++- 4 files changed, 222 insertions(+), 11 deletions(-) diff --git a/Indicator.define.h b/Indicator.define.h index 9987ff427..ede52fe7f 100644 --- a/Indicator.define.h +++ b/Indicator.define.h @@ -116,7 +116,7 @@ class DrawIndicator; _obj.SetHandle(_handle); \ } \ } \ - if (Terminal::IsVisualMode()) { \ + if (false && 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); \ @@ -128,6 +128,7 @@ class DrawIndicator; } \ } \ if (CopyBuffer(_handle, MODE, SHIFT, 1, _res) < 0) { \ + Print(#NATIVE_METHOD_CALL, " = ", _res[0], ", LE = ", _LastError); \ return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; \ } \ return _res[0]; diff --git a/IndicatorLegacy.h b/IndicatorLegacy.h index 0a5ef4dd6..471e84676 100644 --- a/IndicatorLegacy.h +++ b/IndicatorLegacy.h @@ -7,6 +7,19 @@ #pragma once #endif +#ifdef INDICATOR_LEGACY_VERSION_MT4 +#define INDICATOR_LEGACY_VERSION_DEFINED +#endif + +#ifdef INDICATOR_LEGACY_VERSION_MT5 +#define INDICATOR_LEGACY_VERSION_DEFINED +#endif + +#ifndef INDICATOR_LEGACY_VERSION_DEFINED +#define INDICATOR_LEGACY_VERSION_MT5 +#define INDICATOR_LEGACY_VERSION_DEFINED +#endif + #ifdef __MQL4__ #include @@ -14,6 +27,8 @@ #include #include +#ifdef INDICATOR_LEGACY_VERSION_MT5 + /** * Replacement for future OnCalculate(). Currently not used, but could be handy in the future. */ @@ -338,8 +353,30 @@ 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 iRSI(string symbol, ENUM_TIMEFRAMES period, int ma_period, int 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 applied_price +DEFINE_LEGACY_INDICATOR_4(iRSI, iRSI) +#undef T1 +#undef N1 +#undef T2 +#undef N2 +#undef T3 +#undef N3 +#undef T4 +#undef N4 +#undef T5 +#undef N5 +#undef T6 +#undef N6 + // 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 @@ -366,4 +403,82 @@ DEFINE_LEGACY_INDICATOR_6(iMA, iMA) #undef T6 #undef N6 -#endif +#endif // INDICATOR_LEGACY_VERSION_MT5 +#endif // __MQL4__ + +#ifdef __MQL5__ +#ifdef INDICATOR_LEGACY_VERSION_MT4 + +/** + * Replacement for future StringConcatenate(). + */ +#define StringConcatenate StringConcatenateMT4 + +/** + * MQL5 wrapper of MQL4's StringConcatenate(). + */ +template +string StringConcatenateMT4(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) { + return (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; +} +template +string StringConcatenateMT4(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) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k + (string)_l; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j, K _k) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d) { + return (string)_a + (string)_b + (string)_c + (string)_d; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c) { + return (string)_a + (string)_b + (string)_c; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b) { + return (string)_a + (string)_b; +} +template +string StringConcatenateMT4(string& _result, A _a) { + return (string)_a; +} + +#endif // INDICATOR_LEGACY_VERSION_MT4 +#endif // __MQL5__ diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index c2675a21a..a7b725ee9 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -141,11 +141,96 @@ class Indi_MA : public Indicator { #ifdef __MQL4__ return ::iMAOnArray(price, total, ma_period, ma_shift, ma_method, shift); #else - // We're reusing the same native array for each consecutive calculation. - NativeValueStorage *_array_storage = Singleton>::Get(); - _array_storage.SetData(price); - - return iMAOnArray((ValueStorage *)_array_storage, total, ma_period, ma_shift, ma_method, shift, cache); + if (cache != NULL) { + // We're reusing the same native array for each consecutive calculation. + NativeValueStorage *_array_storage = Singleton>::Get(); + _array_storage.SetData(price); + + return iMAOnArray((ValueStorage *)_array_storage, total, ma_period, ma_shift, ma_method, shift, cache); + } else { + double buf[], arr[], _result, pr, _array; + int pos, i, k, weight; + double sum, lsum; + if (total == 0) total = ArraySize(price); + if (total > 0 && total < ma_period) return (0); + if (shift > total - ma_period - ma_shift) return (0); + bool _was_series = ArrayGetAsSeries(price); + ArraySetAsSeries(price, true); + switch (ma_method) { + case MODE_SMA: + total = ArrayCopy(arr, price, 0, shift + ma_shift, ma_period); + if (ArrayResize(buf, total) < 0) return (0); + sum = 0; + pos = total - 1; + for (i = 1; i < ma_period; i++, pos--) sum += arr[pos]; + while (pos >= 0) { + sum += arr[pos]; + buf[pos] = sum / ma_period; + sum -= arr[pos + ma_period - 1]; + pos--; + } + _result = buf[0]; + break; + case MODE_EMA: + if (ArrayResize(buf, total) < 0) return (0); + pr = 2.0 / (ma_period + 1); + pos = total - 2; + while (pos >= 0) { + if (pos == total - 2) buf[pos + 1] = price[pos + 1]; + buf[pos] = price[pos] * pr + buf[pos + 1] * (1 - pr); + pos--; + } + _result = buf[0]; + break; + case MODE_SMMA: + if (ArrayResize(buf, total) < 0) return (0); + sum = 0; + pos = total - ma_period; + while (pos >= 0) { + if (pos == total - ma_period) { + for (i = 0, k = pos; i < ma_period; i++, k++) { + sum += price[k]; + buf[k] = 0; + } + } else + sum = buf[pos + 1] * (ma_period - 1) + price[pos]; + buf[pos] = sum / ma_period; + pos--; + } + _result = buf[0]; + break; + case MODE_LWMA: + if (ArrayResize(buf, total) < 0) return (0); + sum = 0.0; + lsum = 0.0; + weight = 0; + pos = total - 1; + for (i = 1; i <= ma_period; i++, pos--) { + _array = price[pos]; + sum += _array * i; + lsum += _array; + weight += i; + } + pos++; + i = pos + ma_period; + while (pos >= 0) { + buf[pos] = sum / weight; + if (pos == 0) break; + pos--; + i--; + _array = price[pos]; + sum = sum - lsum + _array * ma_period; + lsum -= price[i]; + lsum += _array; + } + _result = buf[0]; + break; + default: + _result = 0; + } + ArraySetAsSeries(price, _was_series); + return _result; + } #endif } diff --git a/Storage/ValueStorage.native.h b/Storage/ValueStorage.native.h index ea7ebb4ab..f13271087 100644 --- a/Storage/ValueStorage.native.h +++ b/Storage/ValueStorage.native.h @@ -34,6 +34,7 @@ template class NativeValueStorage : public ValueStorage { // Dynamic native array. C _values[]; + int _values_size; public: /** @@ -49,7 +50,16 @@ class NativeValueStorage : public ValueStorage { /** * Initializes array with given one. */ - void SetData(ARRAY_REF(C, _arr)) { ArrayCopy(_values, _arr); } + void SetData(ARRAY_REF(C, _arr)) { + bool _was_series = ArrayGetAsSeries(_arr); + ArraySetAsSeries(_arr, false); + ArraySetAsSeries(_values, false); + ArrayResize(_values, 0); + ArrayCopy(_values, _arr); + _values_size = ArraySize(_arr); + ArraySetAsSeries(_arr, _was_series); + ArraySetAsSeries(_values, _was_series); + } /** * Initializes storage with given value. @@ -60,7 +70,7 @@ class NativeValueStorage : public ValueStorage { * Fetches value from a given shift. Takes into consideration as-series flag. */ virtual C Fetch(int _shift) { - if (_shift < 0 || _shift >= ArraySize(_values)) { + if (_shift < 0 || _shift >= _values_size) { return (C)EMPTY_VALUE; // Print("Invalid buffer data index: ", _shift, ". Buffer size: ", ArraySize(_values)); // DebugBreak(); @@ -77,7 +87,7 @@ class NativeValueStorage : public ValueStorage { /** * Returns number of values available to fetch (size of the values buffer). */ - virtual int Size() const { return ArraySize(_values); } + virtual int Size() const { return _values_size; } /** * Resizes storage to given size. From 998d55ad461fe20c911bc1a50c052fc353b4eebd Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 24 Apr 2024 23:39:27 +0100 Subject: [PATCH 2/3] GHA: Compile: Fixes init-platform boolean condition --- .github/workflows/compile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index a71f92fee..9b36b4652 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -69,7 +69,7 @@ jobs: - name: Compile uses: fx31337/mql-compile-action@master with: - init-platform: ${{ ! env.SKIP_INIT }} + init-platform: ${{ env.SKIP_INIT == false }} mt-path: .mt${{ matrix.version }} path-ignore: .mt${{ matrix.version }} path: '${{ env.COMPILE_PATH }}/**/*.mq${{ matrix.version }}' From 7adfaf45deebe2cd45fe9afe5f2952042d96e6cf Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 25 Apr 2024 00:08:29 +0100 Subject: [PATCH 3/3] GHA: Compile: Fixes init-platform condition to compare with string, not boolean --- .github/workflows/compile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 9b36b4652..a5b9c6875 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -69,7 +69,7 @@ jobs: - name: Compile uses: fx31337/mql-compile-action@master with: - init-platform: ${{ env.SKIP_INIT == false }} + init-platform: ${{ env.SKIP_INIT == 'false' }} mt-path: .mt${{ matrix.version }} path-ignore: .mt${{ matrix.version }} path: '${{ env.COMPILE_PATH }}/**/*.mq${{ matrix.version }}'