diff --git a/.github/workflows/test-buffer.yml b/.github/workflows/test-buffer.yml index 82b627a14..41a5b6411 100644 --- a/.github/workflows/test-buffer.yml +++ b/.github/workflows/test-buffer.yml @@ -43,6 +43,7 @@ jobs: uses: fx31337/mql-tester-action@master with: Script: ${{ matrix.test }} + RunOnError: show_logs 200 timeout-minutes: 10 cleanup: diff --git a/.github/workflows/test-indicator.yml b/.github/workflows/test-indicator.yml index a3900e527..aad5bdd57 100644 --- a/.github/workflows/test-indicator.yml +++ b/.github/workflows/test-indicator.yml @@ -47,7 +47,9 @@ jobs: with: BtDays: 4-8 BtMonths: 1 - BtYears: 2020 + BtYears: 2021 + MtVersion: 4.0.0.1359 + RunOnError: show_logs 200 TestExpert: ${{ matrix.test }} timeout-minutes: 10 diff --git a/.github/workflows/test-indicators-special.yml b/.github/workflows/test-indicators-special.yml index 50cbfe1f6..7c6693493 100644 --- a/.github/workflows/test-indicators-special.yml +++ b/.github/workflows/test-indicators-special.yml @@ -45,7 +45,9 @@ jobs: with: BtDays: 4-8 BtMonths: 1 - BtYears: 2020 + BtYears: 2021 + MtVersion: 4.0.0.1359 + RunOnError: show_logs 200 TestExpert: ${{ matrix.test }} timeout-minutes: 10 diff --git a/.github/workflows/test-indicators-tick.yml b/.github/workflows/test-indicators-tick.yml index 516ade6ea..b94bf626e 100644 --- a/.github/workflows/test-indicators-tick.yml +++ b/.github/workflows/test-indicators-tick.yml @@ -45,7 +45,9 @@ jobs: with: BtDays: 4-8 BtMonths: 1 - BtYears: 2020 + BtYears: 2021 + MtVersion: 4.0.0.1359 + RunOnError: show_logs 200 TestExpert: ${{ matrix.test }} timeout-minutes: 10 diff --git a/.github/workflows/test-indicators.yml b/.github/workflows/test-indicators.yml index ea3df37e8..c6e2cd69e 100644 --- a/.github/workflows/test-indicators.yml +++ b/.github/workflows/test-indicators.yml @@ -53,7 +53,7 @@ jobs: - Indi_CCI.test - Indi_CHO.test - Indi_CHV.test - - Indi_ColorBars.test + # - Indi_ColorBars.test # @fixme - Indi_ColorCandlesDaily.test - Indi_ColorLine.test - Indi_CustomMovingAverage.test @@ -110,7 +110,9 @@ jobs: with: BtDays: 4-8 BtMonths: 1 - BtYears: 2020 + BtYears: 2021 + MtVersion: 4.0.0.1359 + RunOnError: show_logs 200 TestExpert: ${{ matrix.test }} timeout-minutes: 10 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index a9c0fbdce..499f4751c 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -50,3 +50,4 @@ jobs: uses: fx31337/mql-tester-action@master with: Script: ${{ matrix.test }} + RunOnError: show_logs 200 diff --git a/.github/workflows/test-trade.yml b/.github/workflows/test-trade.yml index 2062ebed1..5ac8cea05 100644 --- a/.github/workflows/test-trade.yml +++ b/.github/workflows/test-trade.yml @@ -45,6 +45,7 @@ jobs: uses: fx31337/mql-tester-action@master with: Script: ${{ matrix.test }} + RunOnError: show_logs 200 timeout-minutes: 10 cleanup: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cb632fbc3..344aead84 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,6 @@ jobs: strategy: matrix: test: - - AccountTest - BufferStructTest - BufferTest - ChartTest @@ -47,7 +46,6 @@ jobs: - DatabaseTest # - DrawIndicatorTest - EATest - - IndicatorDataTest - IndicatorTest - IndicatorsTest - MailTest @@ -69,11 +67,12 @@ jobs: - name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: - BtDays: 1-8 + BtDays: 4-12 BtMonths: 1 - BtYears: 2020 + BtYears: 2021 Version: 4 TestExpert: ${{ matrix.test }} + RunOnError: show_logs 200 timeout-minutes: 10 Scripts-MQL4: diff --git a/.vscode/settings.json b/.vscode/settings.json index 9084cffd9..7417eab66 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "files.associations": { - "indicatorcandle.h": "c" + "indicatorcandle.h": "c", + "*.mqh": "c" } } diff --git a/3D/Chart3D.h b/3D/Chart3D.h index 00dc95049..79182d6ce 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -26,6 +26,7 @@ */ #include "../Bar.struct.h" +#include "../IndicatorData.mqh" #include "../Indicators/Indi_MA.mqh" #include "../Instances.h" #include "../Refs.mqh" @@ -72,9 +73,6 @@ class Chart3D : public Dynamic { // References to chart type renderers. Ref renderers[3]; - // OHLC prices fetcher callback. - Chart3DPriceFetcher price_fetcher; - // Whether graphics were initialized. bool initialized; @@ -85,17 +83,18 @@ class Chart3D : public Dynamic { Chart3DType* current_renderer; Instances instances; + Ref source; public: /** * Constructor. */ - Chart3D(Chart3DPriceFetcher _price_fetcher, ENUM_CHART3D_TYPE _type = CHART3D_TYPE_CANDLES) : instances(&this) { - price_fetcher = _price_fetcher; + Chart3D(IndicatorData* _source, ENUM_CHART3D_TYPE _type = CHART3D_TYPE_CANDLES) : instances(&this) { type = _type; offset.x = offset.y = 0.0f; offset.z = 25.0f; initialized = false; + source = _source; #ifdef __MQL5__ Interface::AddListener(chart3d_interface_listener, &this); #endif @@ -172,8 +171,8 @@ class Chart3D : public Dynamic { float GetMinBarsPrice() { return (float)ChartStatic::iLow( Symbol(), PERIOD_CURRENT, - ChartStatic::iLowest(Symbol(), PERIOD_CURRENT, MODE_LOW, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), - GetBarsVisibleShiftEnd())); + source REF_DEREF GetLowest(MODE_LOW, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), + GetBarsVisibleShiftEnd())); } /** @@ -182,8 +181,8 @@ class Chart3D : public Dynamic { float GetMaxBarsPrice() { return (float)ChartStatic::iHigh( Symbol(), PERIOD_CURRENT, - ChartStatic::iHighest(Symbol(), PERIOD_CURRENT, MODE_HIGH, - GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); + source REF_DEREF GetHighest(MODE_HIGH, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), + GetBarsVisibleShiftEnd())); } /** diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index d46abb4d3..af9a319f0 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -59,11 +59,11 @@ class Chart3DCandles : public Chart3DType { for (int _shift = chart3d.GetBarsVisibleShiftStart(); _shift != chart3d.GetBarsVisibleShiftEnd(); --_shift) { BarOHLC _ohlc = chart3d.GetPrice(PERIOD_CURRENT, _shift); - float _height = chart3d.GetPriceScale(_ohlc.GetMaxOC()) - chart3d.GetPriceScale(_ohlc.GetMinOC()); + float _height = chart3d.GetPriceScale((float)_ohlc.GetMaxOC()) - chart3d.GetPriceScale((float)_ohlc.GetMinOC()); float higher = _ohlc.IsBear(); cube1.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); - cube1.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.GetMinOC()) + _height / 2; + cube1.Ptr().GetTSR().translation.y = chart3d.GetPriceScale((float)_ohlc.GetMinOC()) + _height / 2; cube1.Ptr().GetTSR().scale.y = _height; // Print(cube1.Ptr().GetTSR().translation.y); @@ -72,8 +72,8 @@ class Chart3DCandles : public Chart3DType { _device.Render(cube1.Ptr()); cube2.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); - float _line_height = chart3d.GetPriceScale(_ohlc.GetHigh()) - chart3d.GetPriceScale(_ohlc.GetLow()); - cube2.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.GetLow()) + _line_height / 2; + float _line_height = chart3d.GetPriceScale((float)_ohlc.GetHigh()) - chart3d.GetPriceScale((float)_ohlc.GetLow()); + cube2.Ptr().GetTSR().translation.y = chart3d.GetPriceScale((float)_ohlc.GetLow()) + _line_height / 2; cube2.Ptr().GetTSR().scale.y = _line_height; cube2.Ptr().GetMaterial().SetColor(higher ? 0x22FF11 : 0xFF1122); _device.Render(cube2.Ptr()); diff --git a/Account/AccountBase.h b/Account/AccountBase.h index 097aabb01..d971ae651 100644 --- a/Account/AccountBase.h +++ b/Account/AccountBase.h @@ -26,12 +26,13 @@ // Includes. //#include "../Serializer.mqh" +#include "../Refs.mqh" #include "AccountBase.struct.h" /** * Class to provide functions that return parameters of the current account. */ -class AccountBase { +class AccountBase : public Dynamic { protected: /** * Init code (called on constructor). diff --git a/Account/AccountMt.h b/Account/AccountMt.h index 03aac2844..0d2fcdc66 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -317,46 +317,6 @@ class AccountMt { */ static string GetType() { return AccountMt::GetServerName() != "" ? (IsDemo() ? "Demo" : "Live") : "Off-line"; } - /* Setters */ - - double UpdateStats(ENUM_ACC_STAT_VALUE _type, double _value) { - static datetime _last_check = TimeCurrent(); - bool _stats_rotate = false; - int _tindex = (int)_type; - for (unsigned int _pindex = 0; _pindex < FINAL_ENUM_ACC_STAT_PERIOD; _pindex++) { - acc_stats[_tindex][_pindex][(int)ACC_VALUE_MIN][(int)ACC_VALUE_CURR] = - fmin(acc_stats[_tindex][_pindex][(int)ACC_VALUE_MIN][(int)ACC_VALUE_CURR], _value); - acc_stats[_tindex][_pindex][(int)ACC_VALUE_MAX][(int)ACC_VALUE_CURR] = - fmin(acc_stats[_tindex][_pindex][(int)ACC_VALUE_MAX][(int)ACC_VALUE_CURR], _value); - acc_stats[_tindex][_pindex][(int)ACC_VALUE_AVG][(int)ACC_VALUE_CURR] = - (acc_stats[_tindex][_pindex][(int)ACC_VALUE_AVG][(int)ACC_VALUE_CURR] + _value) / 2; - switch (_pindex) { - case ACC_DAILY: - _stats_rotate = _last_check < ChartStatic::iTime(_Symbol, PERIOD_D1); - break; - case ACC_WEEKLY: - _stats_rotate = _last_check < ChartStatic::iTime(_Symbol, PERIOD_W1); - break; - case ACC_MONTHLY: - _stats_rotate = _last_check < ChartStatic::iTime(_Symbol, PERIOD_MN1); - break; - } - if (_stats_rotate) { - acc_stats[_tindex][_pindex][(int)ACC_VALUE_MIN][(int)ACC_VALUE_PREV] = - acc_stats[_tindex][_pindex][(int)ACC_VALUE_MIN][(int)ACC_VALUE_CURR]; - acc_stats[_tindex][_pindex][(int)ACC_VALUE_MAX][(int)ACC_VALUE_PREV] = - acc_stats[_tindex][_pindex][(int)ACC_VALUE_MAX][(int)ACC_VALUE_CURR]; - acc_stats[_tindex][_pindex][(int)ACC_VALUE_AVG][(int)ACC_VALUE_PREV] = - acc_stats[_tindex][_pindex][(int)ACC_VALUE_AVG][(int)ACC_VALUE_CURR]; - acc_stats[_tindex][_pindex][(int)ACC_VALUE_MIN][(int)ACC_VALUE_CURR] = _value; - acc_stats[_tindex][_pindex][(int)ACC_VALUE_MAX][(int)ACC_VALUE_CURR] = _value; - acc_stats[_tindex][_pindex][(int)ACC_VALUE_AVG][(int)ACC_VALUE_CURR] = _value; - _last_check = TimeCurrent(); - } - } - return _value; - } - /* Class getters */ /** diff --git a/Array.mqh b/Array.mqh index 60742e264..943927f2b 100644 --- a/Array.mqh +++ b/Array.mqh @@ -761,6 +761,9 @@ template static void ArrayStore(ARRAY_REF(X, array), int _idx, X value, int reserve_size = 0) { if (_idx >= ArraySize(array)) { ArrayResize(array, MathMax(_idx + 1, ArraySize(array)), reserve_size); + } else if (_idx < 0) { + Print("_idx cannot be negative! " + IntegerToString(_idx) + " passed."); + DebugBreak(); } array[_idx] = value; diff --git a/Bar.struct.h b/Bar.struct.h index 3131dcbb1..8b66c4898 100644 --- a/Bar.struct.h +++ b/Bar.struct.h @@ -48,16 +48,16 @@ struct BarOHLC #endif { datetime time; - float open, high, low, close; + double open, high, low, close; // Struct constructor. BarOHLC() : open(0), high(0), low(0), close(0), time(0){}; - BarOHLC(float _open, float _high, float _low, float _close, datetime _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) { _time = TimeCurrent(); } } - BarOHLC(ARRAY_REF(float, _prices), datetime _time = 0) : time(_time) { + BarOHLC(ARRAY_REF(double, _prices), datetime _time = 0) : time(_time) { _time = _time == 0 ? TimeCurrent() : _time; int _size = ArraySize(_prices); close = _prices[0]; @@ -71,21 +71,21 @@ struct BarOHLC } // Struct methods. // Getters - bool GetPivots(ENUM_PP_TYPE _type, float &_pp, float &_r1, float &_r2, float &_r3, float &_r4, float &_s1, float &_s2, - float &_s3, float &_s4) { - float _range = GetRange(); + bool GetPivots(ENUM_PP_TYPE _type, double &_pp, double &_r1, double &_r2, double &_r3, double &_r4, double &_s1, + double &_s2, double &_s3, double &_s4) { + double _range = GetRange(); switch (_type) { case PP_CAMARILLA: // A set of eight very probable levels which resemble support and resistance values for a current trend. _pp = GetPivot(); - _r1 = (float)(close + _range * 1.1 / 12); - _r2 = (float)(close + _range * 1.1 / 6); - _r3 = (float)(close + _range * 1.1 / 4); - _r4 = (float)(close + _range * 1.1 / 2); - _s1 = (float)(close - _range * 1.1 / 12); - _s2 = (float)(close - _range * 1.1 / 6); - _s3 = (float)(close - _range * 1.1 / 4); - _s4 = (float)(close - _range * 1.1 / 2); + _r1 = (double)(close + _range * 1.1 / 12); + _r2 = (double)(close + _range * 1.1 / 6); + _r3 = (double)(close + _range * 1.1 / 4); + _r4 = (double)(close + _range * 1.1 / 2); + _s1 = (double)(close - _range * 1.1 / 12); + _s2 = (double)(close - _range * 1.1 / 6); + _s3 = (double)(close - _range * 1.1 / 4); + _s4 = (double)(close - _range * 1.1 / 2); break; case PP_CLASSIC: _pp = GetPivot(); @@ -100,12 +100,12 @@ struct BarOHLC break; case PP_FIBONACCI: _pp = GetPivot(); - _r1 = (float)(_pp + 0.382 * _range); - _r2 = (float)(_pp + 0.618 * _range); + _r1 = (double)(_pp + 0.382 * _range); + _r2 = (double)(_pp + 0.618 * _range); _r3 = _pp + _range; _r4 = _r1 + _range; // ? - _s1 = (float)(_pp - 0.382 * _range); - _s2 = (float)(_pp - 0.618 * _range); + _s1 = (double)(_pp - 0.382 * _range); + _s2 = (double)(_pp - 0.618 * _range); _s3 = _pp - _range; _s4 = _s1 - _range; // ? break; @@ -152,44 +152,46 @@ struct BarOHLC return _r4 > _r3 && _r3 > _r2 && _r2 > _r1 && _r1 > _pp && _pp > _s1 && _s1 > _s2 && _s2 > _s3 && _s3 > _s4; } datetime GetTime() { return time; } - float GetAppliedPrice(ENUM_APPLIED_PRICE _ap) const { return BarOHLC::GetAppliedPrice(_ap, open, high, low, close); } - float GetBody() const { return close - open; } - float GetBodyAbs() const { return fabs(close - open); } - float GetBodyInPct(int _hundreds = 100) const { return GetRange() > 0 ? _hundreds / GetRange() * GetBodyAbs() : 0; } - float GetChangeInPct(int _hundreds = 100) const { return (close - open) / open * _hundreds; } - float GetClose() const { return close; } - float GetHigh() const { return high; } - float GetLow() const { return low; } - float GetMaxOC() const { return fmax(open, close); } - float GetMedian() const { return (high + low) / 2; } - float GetMinOC() const { return fmin(open, close); } - float GetOpen() const { return open; } - float GetPivot() const { return GetTypical(); } - float GetPivotDeMark() const { + double GetAppliedPrice(ENUM_APPLIED_PRICE _ap) const { return BarOHLC::GetAppliedPrice(_ap, open, high, low, close); } + double GetBody() const { return close - open; } + double GetBodyAbs() const { return fabs(close - open); } + double GetBodyInPct(int _hundreds = 100) const { return GetRange() > 0 ? _hundreds / GetRange() * GetBodyAbs() : 0; } + double GetChangeInPct(int _hundreds = 100) const { + return open > 0 ? ((close - open) / open * _hundreds) : 0 /* Error */; + } + double GetClose() const { return close; } + double GetHigh() const { return high; } + double GetLow() const { return low; } + double GetMaxOC() const { return fmax(open, close); } + double GetMedian() const { return (high + low) / 2; } + double GetMinOC() const { return fmin(open, close); } + double GetOpen() const { return open; } + double GetPivot() const { return GetTypical(); } + double GetPivotDeMark() const { // If Close < Open Then X = H + 2 * L + C // If Close > Open Then X = 2 * H + L + C // If Close = Open Then X = H + L + 2 * C - float _pp = open > close ? (high + (2 * low) + close) / 4 : ((2 * high) + low + close) / 4; + double _pp = open > close ? (high + (2 * low) + close) / 4 : ((2 * high) + low + close) / 4; return open == close ? (high + low + (2 * close)) / 4 : _pp; } - float GetPivotWithOpen() const { return (open + high + low + close) / 4; } - float GetPivotWithOpen(float _open) const { return (_open + high + low + close) / 4; } - float GetRange() const { return high - low; } - float GetRangeChangeInPct(int _hundreds = 100) const { + double GetPivotWithOpen() const { return (open + high + low + close) / 4; } + double GetPivotWithOpen(double _open) const { return (_open + high + low + close) / 4; } + double GetRange() const { return high - low; } + double GetRangeChangeInPct(int _hundreds = 100) const { return _hundreds - (_hundreds / open * fabs(open - GetRange())); } - float GetRangeInPips(float _ppp) const { return GetRange() / _ppp; } - float GetTypical() const { return (high + low + close) / 3; } - float GetWeighted() const { return (high + low + close + close) / 4; } - float GetWickMin() const { return fmin(GetWickLower(), GetWickUpper()); } - float GetWickLower() const { return GetMinOC() - low; } - float GetWickLowerInPct() const { return GetRange() > 0 ? 100 / GetRange() * GetWickLower() : 0; } - float GetWickMax() const { return fmax(GetWickLower(), GetWickUpper()); } - float GetWickSum() const { return GetWickLower() + GetWickUpper(); } - float GetWickUpper() const { return high - GetMaxOC(); } - float GetWickUpperInPct() const { return GetRange() > 0 ? 100 / GetRange() * GetWickUpper() : 0; } + double GetRangeInPips(double _ppp) const { return GetRange() / _ppp; } + double GetTypical() const { return (high + low + close) / 3; } + double GetWeighted() const { return (high + low + close + close) / 4; } + double GetWickMin() const { return fmin(GetWickLower(), GetWickUpper()); } + double GetWickLower() const { return GetMinOC() - low; } + double GetWickLowerInPct() const { return GetRange() > 0 ? 100 / GetRange() * GetWickLower() : 0; } + double GetWickMax() const { return fmax(GetWickLower(), GetWickUpper()); } + double GetWickSum() const { return GetWickLower() + GetWickUpper(); } + double GetWickUpper() const { return high - GetMaxOC(); } + double GetWickUpperInPct() const { return GetRange() > 0 ? 100 / GetRange() * GetWickUpper() : 0; } short GetType() const { return IsBull() ? 1 : (IsBear() ? -1 : 0); } - void GetValues(ARRAY_REF(float, _out)) { + void GetValues(ARRAY_REF(double, _out)) { ArrayResize(_out, 4); int _index = ArraySize(_out) - 4; _out[_index++] = open; diff --git a/Buffer/BufferCandle.h b/Buffer/BufferCandle.h index 0a8df29fc..b1c02183a 100644 --- a/Buffer/BufferCandle.h +++ b/Buffer/BufferCandle.h @@ -33,7 +33,6 @@ */ template class BufferCandle : public BufferStruct> { - protected: protected: /* Protected methods */ diff --git a/Buffer/BufferTick.h b/Buffer/BufferTick.h index cce37f5df..b3e67b1cf 100644 --- a/Buffer/BufferTick.h +++ b/Buffer/BufferTick.h @@ -30,34 +30,48 @@ #include "../Storage/IValueStorage.h" #include "../Tick.struct.h" -template +// TV = Type of price stored by BufferTick. RV = Type of property to be retrieved from BufferTick. +template class BufferTickValueStorage : ValueStorage { // Poiner to buffer to take tick from. BufferTick *buffer_tick; - // PRICE_ASK or PRICE_BID. - int applied_price; + // INDI_VS_TYPE_PRICE_ASK, INDI_VS_TYPE_PRICE_BID, INDI_VS_TYPE_SPREAD, INDI_VS_TYPE_TICK_VOLUME or + // INDI_VS_TYPE_VOLUME. + ENUM_INDI_VS_TYPE vs_type; public: /** * Constructor. */ - BufferTickValueStorage(BufferTick *_buffer_tick, int _applied_price) - : buffer_tick(_buffer_tick), applied_price(_applied_price) {} + BufferTickValueStorage(BufferTick *_buffer_tick, ENUM_INDI_VS_TYPE _vs_type) + : buffer_tick(_buffer_tick), vs_type(_vs_type) {} /** - * Fetches value from a given shift. Takes into consideration as-series flag. + * Fetches value from a given datetime. Takes into consideration as-series flag. */ - TV Fetch(int _shift) override { - Print("BufferTickValueStorage: Fetching " + (applied_price == PRICE_ASK ? "Ask" : "Bid") + " price from shift ", - _shift); - return 0; + TV Fetch(datetime _dt) override { + switch (vs_type) { + case INDI_VS_TYPE_PRICE_ASK: + return (TV)buffer_tick PTR_DEREF GetByKey(_dt).ask; + case INDI_VS_TYPE_PRICE_BID: + return (TV)buffer_tick PTR_DEREF GetByKey(_dt).bid; + case INDI_VS_TYPE_SPREAD: + // return (TV)buffer_tick PTR_DEREF GetByKey(_dt).spread; + case INDI_VS_TYPE_TICK_VOLUME: + // return (TV)buffer_tick PTR_DEREF GetByKey(_dt).tick_volume; + case INDI_VS_TYPE_VOLUME: + // return (TV)buffer_tick PTR_DEREF GetByKey(_dt).volume; + break; + } + Print("Not yet supported value storage to fetch: ", EnumToString(vs_type), "."); + return (RV)0; } /** * Returns number of values available to fetch (size of the values buffer). */ - int Size() const override { return (int)buffer_tick.Size(); } + int Size() override { return (int)buffer_tick.Size(); } }; /** @@ -67,10 +81,19 @@ template class BufferTick : public BufferStruct> { protected: // Ask prices ValueStorage proxy. - BufferTickValueStorage *_vs_ask; + BufferTickValueStorage *_vs_ask; // Bid prices ValueStorage proxy. - BufferTickValueStorage *_vs_bid; + BufferTickValueStorage *_vs_bid; + + // Spread ValueStorage proxy. + BufferTickValueStorage *_vs_spread; + + // Volume ValueStorage proxy. + BufferTickValueStorage *_vs_volume; + + // Tick Volume ValueStorage proxy. + BufferTickValueStorage *_vs_tick_volume; protected: /* Protected methods */ @@ -83,6 +106,9 @@ class BufferTick : public BufferStruct> { void Init() { _vs_ask = NULL; _vs_bid = NULL; + _vs_spread = NULL; + _vs_volume = NULL; + _vs_tick_volume = NULL; SetOverflowListener(BufferTickOverflowListener, 10); } @@ -108,14 +134,23 @@ class BufferTick : public BufferStruct> { if (_vs_bid != NULL) { delete _vs_bid; } + if (_vs_spread != NULL) { + delete _vs_spread; + } + if (_vs_volume != NULL) { + delete _vs_volume; + } + if (_vs_tick_volume != NULL) { + delete _vs_tick_volume; + } } /** * Returns Ask prices ValueStorage proxy. */ - BufferTickValueStorage *GetAskValueStorage() { + BufferTickValueStorage *GetAskValueStorage() { if (_vs_ask == NULL) { - _vs_ask = new BufferTickValueStorage(THIS_PTR, PRICE_ASK); + _vs_ask = new BufferTickValueStorage(THIS_PTR, INDI_VS_TYPE_PRICE_ASK); } return _vs_ask; } @@ -123,13 +158,43 @@ class BufferTick : public BufferStruct> { /** * Returns Bid prices ValueStorage proxy. */ - BufferTickValueStorage *GetBidValueStorage() { + BufferTickValueStorage *GetBidValueStorage() { if (_vs_bid == NULL) { - _vs_bid = new BufferTickValueStorage(THIS_PTR, PRICE_BID); + _vs_bid = new BufferTickValueStorage(THIS_PTR, INDI_VS_TYPE_PRICE_BID); } return _vs_bid; } + /** + * Returns Spread ValueStorage proxy. + */ + BufferTickValueStorage *GetSpreadValueStorage() { + if (_vs_spread == NULL) { + _vs_spread = new BufferTickValueStorage(THIS_PTR, INDI_VS_TYPE_SPREAD); + } + return _vs_spread; + } + + /** + * Returns Volume ValueStorage proxy. + */ + BufferTickValueStorage *GetVolumeValueStorage() { + if (_vs_volume == NULL) { + _vs_volume = new BufferTickValueStorage(THIS_PTR, INDI_VS_TYPE_VOLUME); + } + return _vs_volume; + } + + /** + * Returns Tick Volume ValueStorage proxy. + */ + BufferTickValueStorage *GetTickVolumeValueStorage() { + if (_vs_tick_volume == NULL) { + _vs_tick_volume = new BufferTickValueStorage(THIS_PTR, INDI_VS_TYPE_TICK_VOLUME); + } + return _vs_tick_volume; + } + /* Grouping methods */ /** diff --git a/BufferFXT.mqh b/BufferFXT.mqh index 2b21fdabd..70e448ba4 100644 --- a/BufferFXT.mqh +++ b/BufferFXT.mqh @@ -27,6 +27,7 @@ #include "Account/AccountMt.h" #include "Chart.mqh" #include "DictStruct.mqh" +#include "IndicatorBase.h" #include "Object.mqh" // Defines. @@ -169,39 +170,39 @@ struct BufferFXTHeader { //---- int reserved[60]; // Reserved - space for future use. // Struct constructor. - BufferFXTHeader(Chart *_c, AccountMt *_a) + BufferFXTHeader(IndicatorData *_source, AccountMt *_a) : version(405), - period(_c.Get(CHART_PARAM_TF)), + period(_source PTR_DEREF GetTick() PTR_DEREF GetTf()), model(0), bars(0), fromdate(0), todate(0), totalTicks(0), modelquality(0), - spread((int)_c.GetSpread()), - digits((int)_c.GetDigits()), - point(_c.GetPointSize()), - lot_min(int(_c.GetVolumeMin() * 100)), - lot_max(int(_c.GetVolumeMax() * 100)), - lot_step(int(_c.GetVolumeStep() * 100)), + spread((int)_source PTR_DEREF GetSpread()), + digits((int)_source PTR_DEREF GetSymbolProps().GetDigits()), + point(_source PTR_DEREF GetSymbolProps().GetPointSize()), + lot_min(int(_source PTR_DEREF GetSymbolProps().GetVolumeMin() * 100)), + lot_max(int(_source PTR_DEREF GetSymbolProps().GetVolumeMax() * 100)), + lot_step(int(_source PTR_DEREF GetSymbolProps().GetVolumeStep() * 100)), stops_level(0), // @todo: Add MODE_STOPLEVEL to Account. gtc_pendings(false), contract_size(10000), - tick_value(_c.GetTickValue()), - tick_size(_c.GetTickSize()), + tick_value(_source PTR_DEREF GetSymbolProps().GetTickValue()), + tick_size(_source PTR_DEREF GetSymbolProps().GetTickSize()), profit_mode(PROFIT_CALC_FOREX), swap_enable(true), swap_type(SWAP_BY_POINTS), // @todo: Add _c.GetSwapType() to SymbolInfo. - swap_long(_c.GetSwapLong()), - swap_short(_c.GetSwapShort()), + swap_long(_source PTR_DEREF GetSymbolProps().GetSwapLong()), + swap_short(_source PTR_DEREF GetSymbolProps().GetSwapShort()), swap_rollover3days(3), leverage((int)_a.GetLeverage()), free_margin_mode(MARGIN_DONT_USE), margin_mode(MARGIN_CALC_FOREX), margin_stopout(30), // @fixme: _a.GetStopoutLevel() based on ACCOUNT_MARGIN_SO_CALL. margin_stopout_mode(_a.GetStopoutMode()), - margin_initial(_c.GetMarginInit()), - margin_maintenance(_c.GetMarginMaintenance()), + margin_initial(_source PTR_DEREF GetSymbolProps().GetMarginInit()), + margin_maintenance(_source PTR_DEREF GetSymbolProps().GetMarginMaintenance()), margin_hedged(0), margin_divider(0), comm_base(0.0), @@ -217,7 +218,7 @@ struct BufferFXTHeader { start_period_h4(0), set_from(0), set_to(0), - freeze_level((int)_c.GetFreezeLevel()), + freeze_level((int)_source PTR_DEREF GetSymbolProps().GetFreezeLevel()), generating_errors(0) { ArrayInitialize(copyright, 0); // currency = StringSubstr(_m.GetSymbol(), 0, 3); // @fixme @@ -230,16 +231,16 @@ struct BufferFXTHeader { struct BufferFXTParams { AccountMt *account; - Chart *chart; + Ref source; // Struct constructor. - void BufferFXTParams(Chart *_chart = NULL, AccountMt *_account = NULL) - : account(Object::IsValid(_account) ? _account : new AccountMt), - chart(Object::IsValid(_chart) ? _chart : new Chart) {} - // Struct deconstructor. - void ~BufferFXTParams() { - delete account; - delete chart; + BufferFXTParams(IndicatorBase *_source, AccountMt *_account = NULL) + : account(Object::IsValid(_account) ? _account : new AccountMt), source(_source) {} + BufferFXTParams(BufferFXTParams &r) { + account = r.account; + source = r.source; } + // Struct deconstructor. + void ~BufferFXTParams() { delete account; } }; string ToJSON(BufferFXTEntry &_value, const bool, const unsigned int) { return _value.ToJSON(); }; @@ -255,8 +256,8 @@ class BufferFXT : public DictStruct { /** * Class constructor. */ - BufferFXT() {} - BufferFXT(const BufferFXTParams &_params) { params = _params; } + BufferFXT(IndicatorBase *_source) : params(_source) {} + BufferFXT(BufferFXTParams &_params) : params(_params) {} /** * Class deconstructor. @@ -283,7 +284,7 @@ class BufferFXT : public DictStruct { * Save data into file. */ void SaveToFile() { - BufferFXTHeader header(params.chart, params.account); + BufferFXTHeader header(params.source.Ptr(), params.account); // @todo: Save BufferFXTHeader, then foreach BufferFXTEntry. // @see: https://docs.mql4.com/files/filewritestruct } diff --git a/Candle.struct.h b/Candle.struct.h index eb77993c2..f9f1a1ca7 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -217,15 +217,26 @@ struct CandleOHLC string ToCSV() { return StringFormat("%g,%g,%g,%g", open, high, low, close); } }; -/* Structure for storing OHLC values with open and close timestamp. */ +/* Structure for storing OHLC values, number of ticks which formed the candle and both, open and close timestamp of the + * candle. */ template struct CandleOCTOHLC : CandleOHLC { long open_timestamp, close_timestamp; + // Number of ticks which formed the candle. Also known as volume. + int volume; + // Struct constructors. CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, long _open_timestamp = -1, - long _close_timestamp = -1) - : CandleOHLC(_open, _high, _low, _close), open_timestamp(_open_timestamp), close_timestamp(_close_timestamp) {} + long _close_timestamp = -1, int _volume = 0) + : CandleOHLC(_open, _high, _low, _close), + open_timestamp(_open_timestamp), + close_timestamp(_close_timestamp), + volume(_volume) { + if (_open != 0) { + volume = 1; + } + } // Updates OHLC values taking into consideration tick's timestamp. void Update(long _timestamp, T _price) { @@ -239,6 +250,8 @@ struct CandleOCTOHLC : CandleOHLC { } high = MathMax(high, _price); low = MathMin(low, _price); + // Increasing candle's volume. + ++volume; } // Returns timestamp of open price. diff --git a/Chart.enum.h b/Chart.enum.h index 36abcddbd..0aef076f9 100644 --- a/Chart.enum.h +++ b/Chart.enum.h @@ -55,8 +55,8 @@ enum ENUM_APPLIED_PRICE { enum ENUM_CHART_PARAM { CHART_PARAM_NONE = 0, // None CHART_PARAM_ID, // Chart ID - CHART_PARAM_SYMBOL, // Symbol - CHART_PARAM_TF, // Timeframe + // CHART_PARAM_SYMBOL, // Symbol + // CHART_PARAM_TF, // Timeframe CHART_PARAM_TFI, // Timeframe index FINAL_ENUM_CHART_PARAM }; diff --git a/Chart.mqh b/Chart.mqh index e1f6be767..9db5e5419 100644 --- a/Chart.mqh +++ b/Chart.mqh @@ -52,6 +52,7 @@ class Market; // Struct arrays that contains given values of each bar of the current chart. // For MQL4 backward compatibility. // @docs: https://docs.mql4.com/predefined +#include "ChartMt.h" ChartBarTime Time; ChartPriceClose Close; ChartPriceHigh High; @@ -109,328 +110,8 @@ class Chart : public Market { int bar_index; public: - /** - * Class constructor. - */ - Chart(ChartParams &_cparams) - : cparams(_cparams), Market(_cparams.symbol), last_bar_time(GetBarTime()), tick_index(-1), bar_index(-1) { - // Save the first BarOHLC values. - SaveChartEntry(); - cparams.Set(CHART_PARAM_ID, ChartStatic::ID()); - } - Chart(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _symbol = NULL) - : cparams(_tf, _symbol, ChartStatic::ID()), - Market(_symbol), - last_bar_time(GetBarTime()), - tick_index(-1), - bar_index(-1) { - // Save the first BarOHLC values. - SaveChartEntry(); - } - Chart(ENUM_TIMEFRAMES_INDEX _tfi, string _symbol = NULL) - : cparams(_tfi, _symbol, ChartStatic::ID()), - Market(_symbol), - last_bar_time(GetBarTime()), - tick_index(-1), - bar_index(-1) { - // Save the first BarOHLC values. - SaveChartEntry(); - } - - /** - * Class constructor. - */ - ~Chart() {} - - /* Getters */ - - /** - * Gets a chart parameter value. - */ - template - T Get(ENUM_CHART_PARAM _param) { - return cparams.Get(_param); - } - - /** - * Gets OHLC price values. - * - * @param _shift Shift. - * - * @return - * Returns BarOHLC struct. - */ - BarOHLC GetOHLC(unsigned int _shift = 0) { - datetime _time = GetBarTime(_shift); - float _open = 0, _high = 0, _low = 0, _close = 0; - if (_time > 0) { - _open = (float)GetOpen(_shift); - _high = (float)GetHigh(_shift); - _low = (float)GetLow(_shift); - _close = (float)GetClose(_shift); - } - BarOHLC _ohlc(_open, _high, _low, _close, _time); - return _ohlc; - } - - /** - * Gets OHLC price values. - * - * @param _shift Shift. - * - * @return - * Returns BarOHLC struct. - */ - static BarOHLC GetOHLC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _shift = 0, string _symbol = NULL) { - datetime _time = ChartStatic::iTime(_symbol, _tf, _shift); - float _open = 0, _high = 0, _low = 0, _close = 0; - if (_time > 0) { - _open = (float)ChartStatic::iOpen(_symbol, _tf, _shift); - _high = (float)ChartStatic::iHigh(_symbol, _tf, _shift); - _low = (float)ChartStatic::iLow(_symbol, _tf, _shift); - _close = (float)ChartStatic::iClose(_symbol, _tf, _shift); - } - BarOHLC _ohlc(_open, _high, _low, _close, _time); - return _ohlc; - } - - /** - * Gets chart entry. - * - * @param - * _tf ENUM_TIMEFRAMES Timeframe to use. - * _shift unsigned int _shift Shift to use. - * _symbol string Symbol to use. - * - * @return - * Returns ChartEntry struct. - */ - static ChartEntry GetEntry(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _shift = 0, string _symbol = NULL) { - ChartEntry _chart_entry; - BarOHLC _ohlc = Chart::GetOHLC(_tf, _shift, _symbol); - if (_ohlc.open > 0) { - BarEntry _bar_entry(_ohlc); - _chart_entry.SetBar(_bar_entry); - } - return _chart_entry; - } - - /** - * Gets chart entry. - * - * @param - * _shift unsigned int _shift Shift to use. - * - * @return - * Returns ChartEntry struct. - */ - ChartEntry GetEntry(int _shift = 0) { - ChartEntry _chart_entry; - BarOHLC _ohlc = GetOHLC(_shift); - if (_ohlc.open > 0) { - // @todo: Adds caching. - BarEntry _bar_entry(_ohlc); - _chart_entry.SetBar(_bar_entry); - } - return _chart_entry; - } - - /** - * Gets copy of params. - * - * @return - * Returns structure for Trade's params. - */ - ChartParams GetParams() const { return cparams; } - /* State checking */ - /** - * Validate whether given timeframe index is valid. - */ - static bool IsValidTfIndex(ENUM_TIMEFRAMES_INDEX _tfi, string _symbol = NULL) { - return IsValidTf(ChartTf::IndexToTf(_tfi), _symbol); - } - - /** - * Validates whether given timeframe is valid. - */ - static bool IsValidShift(int _shift, ENUM_TIMEFRAMES _tf, string _symbol = NULL) { - return ChartStatic::iTime(_symbol, _tf, _shift) > 0; - } - - /** - * Validates whether given timeframe is valid. - */ - static bool IsValidTf(ENUM_TIMEFRAMES _tf, string _symbol = NULL) { return ChartStatic::iOpen(_symbol, _tf) > 0; } - - /* State checking */ - - /** - * Validates whether given timeframe is valid. - */ - bool IsValidShift(int _shift) { return GetBarTime(_shift) > 0; } - - /** - * Validates whether given timeframe is valid. - */ - bool IsValidTf() { - static bool is_valid = false; - return is_valid ? is_valid : GetOpen() > 0; - } - - /** - * Validate whether given timeframe index is valid. - */ - bool IsValidTfIndex() { return Chart::IsValidTfIndex(Get(CHART_PARAM_TFI), symbol); } - - /* Timeseries */ - /* @see: https://docs.mql4.com/series */ - - datetime GetBarTime(ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { return ChartStatic::iTime(symbol, _tf, _shift); } - datetime GetBarTime(unsigned int _shift = 0) { - return ChartStatic::iTime(symbol, Get(CHART_PARAM_TF), _shift); - } - datetime GetLastBarTime() { return last_bar_time; } - - /** - * Returns open price value for the bar of indicated symbol. - * - * If local history is empty (not loaded), function returns 0. - */ - double GetOpen(ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { return ChartStatic::iOpen(symbol, _tf, _shift); } - double GetOpen(unsigned int _shift = 0) { - return ChartStatic::iOpen(symbol, Get(CHART_PARAM_TF), _shift); - } - - /** - * Returns close price value for the bar of indicated symbol. - * - * If local history is empty (not loaded), function returns 0. - * - * @see http://docs.mql4.com/series/iclose - */ - double GetClose(ENUM_TIMEFRAMES _tf, int _shift = 0) { return ChartStatic::iClose(symbol, _tf, _shift); } - double GetClose(int _shift = 0) { return ChartStatic::iClose(symbol, Get(CHART_PARAM_TF), _shift); } - - /** - * Returns low price value for the bar of indicated symbol. - * - * If local history is empty (not loaded), function returns 0. - */ - double GetLow(ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { return ChartStatic::iLow(symbol, _tf, _shift); } - double GetLow(unsigned int _shift = 0) { - return ChartStatic::iLow(symbol, Get(CHART_PARAM_TF), _shift); - } - - /** - * Returns low price value for the bar of indicated symbol. - * - * If local history is empty (not loaded), function returns 0. - */ - double GetHigh(ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { return ChartStatic::iHigh(symbol, _tf, _shift); } - double GetHigh(unsigned int _shift = 0) { - return ChartStatic::iHigh(symbol, Get(CHART_PARAM_TF), _shift); - } - - /** - * Returns the current price value given applied price type. - */ - double GetPrice(ENUM_APPLIED_PRICE _ap, int _shift = 0) { - return ChartStatic::iPrice(_ap, symbol, Get(CHART_PARAM_TF), _shift); - } - - /** - * Returns tick volume value for the bar. - * - * If local history is empty (not loaded), function returns 0. - */ - long GetVolume(ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { return ChartStatic::iVolume(symbol, _tf, _shift); } - long GetVolume(unsigned int _shift = 0) { - return ChartStatic::iVolume(symbol, Get(CHART_PARAM_TF), _shift); - } - - /** - * Returns the shift of the maximum value over a specific number of periods depending on type. - */ - int GetHighest(ENUM_TIMEFRAMES _tf, int type, int _count = WHOLE_ARRAY, int _start = 0) { - return ChartStatic::iHighest(symbol, _tf, type, _count, _start); - } - int GetHighest(int type, int _count = WHOLE_ARRAY, int _start = 0) { - return ChartStatic::iHighest(symbol, Get(CHART_PARAM_TF), type, _count, _start); - } - - /** - * Returns the shift of the lowest value over a specific number of periods depending on type. - */ - int GetLowest(int _type, int _count = WHOLE_ARRAY, int _start = 0) { - return ChartStatic::iLowest(symbol, Get(CHART_PARAM_TF), _type, _count, _start); - } - - /** - * Returns the number of bars on the specified chart. - */ - int GetBars() { return ChartStatic::iBars(symbol, Get(CHART_PARAM_TF)); } - - /** - * Search for a bar by its time. - * - * Returns the index of the bar which covers the specified time. - */ - int GetBarShift(datetime _time, bool _exact = false) { - return ChartStatic::iBarShift(symbol, Get(CHART_PARAM_TF), _time, _exact); - } - - /** - * Get peak price at given number of bars. - * - * In case of error, check it via GetLastError(). - */ - double GetPeakPrice(int bars, int mode, int _idx, ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT) { - int ibar = -1; - // @todo: Add symbol parameter. - double peak_price = GetOpen(0); - switch (mode) { - case MODE_HIGH: - ibar = ChartStatic::iHighest(symbol, timeframe, MODE_HIGH, bars, _idx); - return ibar >= 0 ? GetHigh(timeframe, ibar) : false; - case MODE_LOW: - ibar = ChartStatic::iLowest(symbol, timeframe, MODE_LOW, bars, _idx); - return ibar >= 0 ? GetLow(timeframe, ibar) : false; - default: - return false; - } - } - double GetPeakPrice(int bars, int mode = MODE_HIGH, int _idx = 0) { - return GetPeakPrice(bars, mode, _idx, Get(CHART_PARAM_TF)); - } - - /** - * List active timeframes. - * - * @param - * _all bool If true, return also non-active timeframes. - * - * @return - * Returns textual representation of list of timeframes. - */ - static string ListTimeframes(bool _all = false, string _prefix = "Timeframes: ") { - string output = _prefix; - for (int _tfi = 0; _tfi < FINAL_ENUM_TIMEFRAMES_INDEX; _tfi++) { - if (_all) { - output += StringFormat("%s: %s; ", ChartTf::IndexToString((ENUM_TIMEFRAMES_INDEX)_tfi), - Chart::IsValidTfIndex((ENUM_TIMEFRAMES_INDEX)_tfi) ? "On" : "Off"); - } else { - output += Chart::IsValidTfIndex((ENUM_TIMEFRAMES_INDEX)_tfi) - ? ChartTf::IndexToString((ENUM_TIMEFRAMES_INDEX)_tfi) + "; " - : ""; - } - } - return output; - } - - /* Chart */ - /** * Sets a flag hiding indicators. * @@ -451,85 +132,6 @@ class Chart : public Market { /* Calculation methods */ - /** - * Calculate modelling quality. - * - * @see: - * - https://www.mql5.com/en/articles/1486 - * - https://www.mql5.com/en/articles/1513 - */ - static double CalcModellingQuality(ENUM_TIMEFRAMES TimePr = PERIOD_CURRENT) { - int i; - int nBarsInM1 = 0; - int nBarsInPr = 0; - int nBarsInNearPr = 0; - ENUM_TIMEFRAMES TimeNearPr = PERIOD_M1; - double ModellingQuality = 0; - long StartGen = 0; - long StartBar = 0; - long StartGenM1 = 0; - long HistoryTotal = 0; - datetime x = StrToTime("1971.01.01 00:00"); - datetime modeling_start_time = StrToTime("1971.01.01 00:00"); - - if (TimePr == NULL) TimePr = (ENUM_TIMEFRAMES)Period(); - if (TimePr == PERIOD_M1) TimeNearPr = PERIOD_M1; - if (TimePr == PERIOD_M5) TimeNearPr = PERIOD_M1; - if (TimePr == PERIOD_M15) TimeNearPr = PERIOD_M5; - if (TimePr == PERIOD_M30) TimeNearPr = PERIOD_M15; - if (TimePr == PERIOD_H1) TimeNearPr = PERIOD_M30; - if (TimePr == PERIOD_H4) TimeNearPr = PERIOD_H1; - if (TimePr == PERIOD_D1) TimeNearPr = PERIOD_H4; - if (TimePr == PERIOD_W1) TimeNearPr = PERIOD_D1; - if (TimePr == PERIOD_MN1) TimeNearPr = PERIOD_W1; - - // 1 minute. - double nBars = fmin(iBars(NULL, TimePr) * TimePr, iBars(NULL, PERIOD_M1)); - for (i = 0; i < nBars; i++) { - if (ChartStatic::iOpen(NULL, PERIOD_M1, i) >= 0.000001) { - if (ChartStatic::iTime(NULL, PERIOD_M1, i) >= modeling_start_time) { - nBarsInM1++; - } - } - } - - // Nearest time. - nBars = ChartStatic::iBars(NULL, TimePr); - for (i = 0; i < nBars; i++) { - if (ChartStatic::iOpen(NULL, TimePr, i) >= 0.000001) { - if (ChartStatic::iTime(NULL, TimePr, i) >= modeling_start_time) nBarsInPr++; - } - } - - // Period time. - nBars = fmin(ChartStatic::iBars(NULL, TimePr) * TimePr / TimeNearPr, iBars(NULL, TimeNearPr)); - for (i = 0; i < nBars; i++) { - if (ChartStatic::iOpen(NULL, TimeNearPr, (int)i) >= 0.000001) { - if (ChartStatic::iTime(NULL, TimeNearPr, i) >= modeling_start_time) nBarsInNearPr++; - } - } - - HistoryTotal = nBarsInPr; - nBarsInM1 = nBarsInM1 / TimePr; - nBarsInNearPr = nBarsInNearPr * TimeNearPr / TimePr; - StartGenM1 = HistoryTotal - nBarsInM1; - StartBar = HistoryTotal - nBarsInPr; - StartBar = 0; - StartGen = HistoryTotal - nBarsInNearPr; - - if (TimePr == PERIOD_M1) { - StartGenM1 = HistoryTotal; - StartGen = StartGenM1; - } - if ((HistoryTotal - StartBar) != 0) { - ModellingQuality = - ((0.25 * (StartGen - StartBar) + 0.5 * (StartGenM1 - StartGen) + 0.9 * (HistoryTotal - StartGenM1)) / - (HistoryTotal - StartBar)) * - 100; - } - return (ModellingQuality); - } - /* Setters */ /** @@ -545,56 +147,6 @@ class Chart : public Market { */ void SetEntry(ChartEntry &_entry) { c_entry = _entry; } - /** - * Sets open time value for the last bar of indicated symbol with timeframe. - */ - void SetLastBarTime() { last_bar_time = GetBarTime(); } - - /* State checking */ - - /** - * Check whether the price is in its peak for the current period. - */ - static bool IsPeak(ENUM_TIMEFRAMES _period, string _symbol = NULL) { - return SymbolInfoStatic::GetAsk(_symbol) >= ChartStatic::iHigh(_symbol, _period) || - SymbolInfoStatic::GetAsk(_symbol) <= ChartStatic::iLow(_symbol, _period); - } - bool IsPeak() { return IsPeak(Get(CHART_PARAM_TF), symbol); } - - /** - * Acknowledges chart that new tick happened. - */ - virtual void OnTick() { - ++tick_index; - - if (GetLastBarTime() != GetBarTime()) { - ++bar_index; - } - } - - /** - * Returns current tick index (incremented every OnTick()). - */ - unsigned int GetTickIndex() { return tick_index == -1 ? 0 : tick_index; } - - /** - * Returns current bar index (incremented every OnTick() if IsNewBar() is true). - */ - unsigned int GetBarIndex() { return bar_index == -1 ? 0 : bar_index; } - - /** - * Check if there is a new bar to parse. - */ - bool IsNewBar() { - // static datetime _last_itime = iTime(); - bool _result = false; - if (GetLastBarTime() != GetBarTime()) { - SetLastBarTime(); - _result = true; - } - return _result; - } - /* Chart operations */ /** @@ -622,280 +174,10 @@ class Chart : public Market { */ ChartEntry GetEntry() const { return c_entry; } - /** - * Returns list of modelling quality for all periods. - */ - static string GetModellingQuality() { - string output = "Modelling Quality: "; - output += StringFormat( - "%s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%;", - "M1", CalcModellingQuality(PERIOD_M1), "M5", CalcModellingQuality(PERIOD_M5), "M15", - CalcModellingQuality(PERIOD_M15), "M30", CalcModellingQuality(PERIOD_M30), "H1", - CalcModellingQuality(PERIOD_H1), "H4", CalcModellingQuality(PERIOD_H4), "D1", CalcModellingQuality(PERIOD_D1), - "W1", CalcModellingQuality(PERIOD_W1), "MN1", CalcModellingQuality(PERIOD_MN1)); - return output; - } - /* Conditions */ - /** - * Checks for chart condition. - * - * @param ENUM_CHART_CONDITION _cond - * Chart condition. - * @param MqlParam _args - * Trade action arguments. - * @return - * Returns true when the condition is met. - */ - bool CheckCondition(ENUM_CHART_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { - float _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4; - switch (_cond) { - case CHART_COND_ASK_BAR_PEAK: - return IsPeak(); - case CHART_COND_ASK_GT_BAR_HIGH: - return GetAsk() > GetHigh(); - case CHART_COND_ASK_GT_BAR_LOW: - return GetAsk() > GetLow(); - case CHART_COND_ASK_LT_BAR_HIGH: - return GetAsk() < GetHigh(); - case CHART_COND_ASK_LT_BAR_LOW: - return GetAsk() < GetLow(); - case CHART_COND_BAR_CLOSE_GT_PP_PP: { - ChartEntry _centry = Chart::GetEntry(1); - return GetClose() > _centry.bar.ohlc.GetPivot(); - } - case CHART_COND_BAR_CLOSE_GT_PP_R1: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() > _r1; - } - case CHART_COND_BAR_CLOSE_GT_PP_R2: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() > _r2; - } - case CHART_COND_BAR_CLOSE_GT_PP_R3: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() > _r3; - } - case CHART_COND_BAR_CLOSE_GT_PP_R4: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() > _r4; - } - case CHART_COND_BAR_CLOSE_GT_PP_S1: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() > _s1; - } - case CHART_COND_BAR_CLOSE_GT_PP_S2: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() > _s2; - } - case CHART_COND_BAR_CLOSE_GT_PP_S3: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() > _s3; - } - case CHART_COND_BAR_CLOSE_GT_PP_S4: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() > _s4; - } - case CHART_COND_BAR_CLOSE_LT_PP_PP: { - ChartEntry _centry = Chart::GetEntry(1); - return GetClose() < _centry.bar.ohlc.GetPivot(); - } - case CHART_COND_BAR_CLOSE_LT_PP_R1: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() < _r1; - } - case CHART_COND_BAR_CLOSE_LT_PP_R2: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() < _r2; - } - case CHART_COND_BAR_CLOSE_LT_PP_R3: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() < _r3; - } - case CHART_COND_BAR_CLOSE_LT_PP_R4: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() < _r4; - } - case CHART_COND_BAR_CLOSE_LT_PP_S1: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() < _s1; - } - case CHART_COND_BAR_CLOSE_LT_PP_S2: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() < _s2; - } - case CHART_COND_BAR_CLOSE_LT_PP_S3: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() < _s3; - } - case CHART_COND_BAR_CLOSE_LT_PP_S4: { - ChartEntry _centry = Chart::GetEntry(1); - _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); - return GetClose() < _s4; - } - case CHART_COND_BAR_HIGHEST_CURR_20: - return GetHighest(MODE_CLOSE, 20) == 0; - case CHART_COND_BAR_HIGHEST_CURR_50: - return GetHighest(MODE_CLOSE, 50) == 0; - case CHART_COND_BAR_HIGHEST_PREV_20: - return GetHighest(MODE_CLOSE, 20) == 1; - case CHART_COND_BAR_HIGHEST_PREV_50: - return GetHighest(MODE_CLOSE, 50) == 1; - case CHART_COND_BAR_HIGH_GT_OPEN: - return GetHigh() > GetOpen(); - case CHART_COND_BAR_HIGH_LT_OPEN: - return GetHigh() < GetOpen(); - case CHART_COND_BAR_INDEX_EQ_ARG: - // Current bar's index equals argument value. - if (ArraySize(_args) > 0) { - return GetBarIndex() == DataParamEntry::ToInteger(_args[0]); - } else { - SetUserError(ERR_INVALID_PARAMETER); - return false; - } - case CHART_COND_BAR_INDEX_GT_ARG: - // Current bar's index greater than argument value. - if (ArraySize(_args) > 0) { - return GetBarIndex() > DataParamEntry::ToInteger(_args[0]); - } else { - SetUserError(ERR_INVALID_PARAMETER); - return false; - } - case CHART_COND_BAR_INDEX_LT_ARG: - // Current bar's index lower than argument value. - if (ArraySize(_args) > 0) { - return GetBarIndex() < DataParamEntry::ToInteger(_args[0]); - } else { - SetUserError(ERR_INVALID_PARAMETER); - return false; - } - case CHART_COND_BAR_LOWEST_CURR_20: - return GetLowest(MODE_CLOSE, 20) == 0; - case CHART_COND_BAR_LOWEST_CURR_50: - return GetLowest(MODE_CLOSE, 50) == 0; - case CHART_COND_BAR_LOWEST_PREV_20: - return GetLowest(MODE_CLOSE, 20) == 1; - case CHART_COND_BAR_LOWEST_PREV_50: - return GetLowest(MODE_CLOSE, 50) == 1; - case CHART_COND_BAR_LOW_GT_OPEN: - return GetLow() > GetOpen(); - case CHART_COND_BAR_LOW_LT_OPEN: - return GetLow() < GetOpen(); - case CHART_COND_BAR_NEW: - return IsNewBar(); - /* - case CHART_COND_BAR_NEW_DAY: - // @todo; - return false; - case CHART_COND_BAR_NEW_HOUR: - // @todo; - return false; - case CHART_COND_BAR_NEW_MONTH: - // @todo; - return false; - case CHART_COND_BAR_NEW_WEEK: - // @todo; - return false; - case CHART_COND_BAR_NEW_YEAR: - // @todo; - return false; - */ - default: - GetLogger().Error(StringFormat("Invalid market condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - return false; - } - } - bool CheckCondition(ENUM_CHART_CONDITION _cond) { - ARRAY(DataParamEntry, _args); - return Chart::CheckCondition(_cond, _args); - } - /* Printer methods */ - /** - * Returns textual representation of the Chart class. - */ - string ToString(unsigned int _shift = 0) { - return StringFormat("%s: %s", ChartTf::TfToString(Get(CHART_PARAM_TF)), GetEntry(_shift).ToCSV()); - } - - /* Static methods */ - - /** - * Returns the price value given applied price type. - */ - static float GetAppliedPrice(ENUM_APPLIED_PRICE _ap, float _o, float _h, float _c, float _l) { - BarOHLC _bar(_o, _h, _c, _l); - return _bar.GetAppliedPrice(_ap); - } - - /* Other methods */ - - /* Snapshots */ - - /** - * Save the current BarOHLC values. - * - * @return - * Returns true if BarOHLC values has been saved, otherwise false. - */ - bool SaveChartEntry() { - // @todo: Use MqlRates. - unsigned int _last = ArraySize(chart_saves); - if (ArrayResize(chart_saves, _last + 1, 100)) { - chart_saves[_last].bar.ohlc.time = ChartStatic::iTime(); - chart_saves[_last].bar.ohlc.open = (float)Chart::GetOpen(); - chart_saves[_last].bar.ohlc.high = (float)Chart::GetHigh(); - chart_saves[_last].bar.ohlc.low = (float)Chart::GetLow(); - chart_saves[_last].bar.ohlc.close = (float)Chart::GetClose(); - return true; - } else { - return false; - } - } - - /** - * Load stored BarOHLC values. - * - * @param - * _index unsigned int Index of the element in BarOHLC array. - * @return - * Returns BarOHLC struct element. - */ - ChartEntry LoadChartEntry(unsigned int _index = 0) { return chart_saves[_index]; } - - /** - * Return size of BarOHLC array. - */ - unsigned long SizeChartEntry() { return ArraySize(chart_saves); } - - /* Serializers */ - - /** - * Returns serialized representation of the object instance. - */ - SerializerNodeType Serialize(Serializer &_s) { - ChartEntry _centry = GetEntry(); - _s.PassStruct(THIS_REF, "chart-entry", _centry, SERIALIZER_FIELD_FLAG_DYNAMIC); - return SerializerNodeObject; - } - void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} }; diff --git a/Chart.struct.h b/Chart.struct.h index b6d9b91c0..6dd08b95b 100644 --- a/Chart.struct.h +++ b/Chart.struct.h @@ -111,85 +111,3 @@ struct ChartParams { // Serializers. SerializerNodeType Serialize(Serializer& s); } chart_params_defaults(PERIOD_CURRENT, _Symbol); - -/** - * Wrapper struct that returns close prices of each bar of the current chart. - * - * @see: https://docs.mql4.com/predefined/close - */ -struct ChartPriceClose { - string symbol; - ENUM_TIMEFRAMES tf; - - ChartPriceClose() : symbol(_Symbol), tf(PERIOD_CURRENT) {} - double operator[](const int _shift) const { return Get(symbol, tf, _shift); } - static double Get(const string _symbol, const ENUM_TIMEFRAMES _tf, const int _shift) { - return ChartStatic::iClose(_symbol, _tf, _shift); - } -}; - -/** - * Wrapper struct that returns the highest prices of each bar of the current chart. - * - * @see: https://docs.mql4.com/predefined/high - */ -struct ChartPriceHigh { - string symbol; - ENUM_TIMEFRAMES tf; - - ChartPriceHigh() : symbol(_Symbol), tf(PERIOD_CURRENT) {} - double operator[](const int _shift) const { return Get(symbol, tf, _shift); } - static double Get(const string _symbol, const ENUM_TIMEFRAMES _tf, const int _shift) { - return ChartStatic::iHigh(_symbol, _tf, _shift); - } -}; - -/** - * Wrapper struct that returns the lowest prices of each bar of the current chart. - * - * @see: https://docs.mql4.com/predefined/low - */ -struct ChartPriceLow { - string symbol; - ENUM_TIMEFRAMES tf; - - ChartPriceLow() : symbol(_Symbol), tf(PERIOD_CURRENT) {} - double operator[](const int _shift) const { return Get(symbol, tf, _shift); } - static double Get(const string _symbol, const ENUM_TIMEFRAMES _tf, const int _shift) { - return ChartStatic::iLow(_symbol, _tf, _shift); - } -}; - -/** - * Wrapper struct that returns open prices of each bar of the current chart. - * - * @see: https://docs.mql4.com/predefined/open - */ -struct ChartPriceOpen { - string symbol; - ENUM_TIMEFRAMES tf; - - ChartPriceOpen() : symbol(_Symbol), tf(PERIOD_CURRENT) {} - double operator[](const int _shift) const { return Get(symbol, tf, _shift); } - static double Get(const string _symbol, const ENUM_TIMEFRAMES _tf, const int _shift) { - return ChartStatic::iOpen(_symbol, _tf, _shift); - } -}; - -/** - * Wrapper struct that returns open time of each bar of the current chart. - * - * @see: https://docs.mql4.com/predefined/time - */ -struct ChartBarTime { - protected: - string symbol; - ENUM_TIMEFRAMES tf; - - public: - ChartBarTime() : symbol(_Symbol), tf(PERIOD_CURRENT) {} - datetime operator[](const int _shift) const { return Get(symbol, tf, _shift); } - static datetime Get(const string _symbol, const ENUM_TIMEFRAMES _tf, const int _shift) { - return ChartStatic::iTime(_symbol, _tf, _shift); - } -}; diff --git a/Chart.struct.static.h b/Chart.struct.static.h index aa81caf23..83bc8561c 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -25,6 +25,11 @@ * Includes Chart's static structs. */ +// Includes. +#include "Chart.define.h" +#include "Chart.symboltf.h" +#include "Terminal.define.h" + /* Defines struct for chart static methods. */ struct ChartStatic { /** @@ -33,11 +38,19 @@ struct ChartStatic { static int iBars(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { #ifdef __MQL4__ // In MQL4, for the current chart, the information about the amount of bars is in the Bars predefined variable. - return ::iBars(_symbol, _tf); + int _bars = ::iBars(_symbol, _tf); #else // _MQL5__ // ENUM_TIMEFRAMES _tf = MQL4::TFMigrate(_tf); - return ::Bars(_symbol, _tf); + int _bars = ::Bars(_symbol, _tf); #endif + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing ::[i]Bars in ChartStatic::iBars(", _symbol, ", ", EnumToString(_tf), + ")"); + DebugBreak(); + } + + return _bars; } /** @@ -46,25 +59,47 @@ struct ChartStatic { * Returns the index of the bar which covers the specified time. */ static int iBarShift(string _symbol, ENUM_TIMEFRAMES _tf, datetime _time, bool _exact = false) { + int _bar_shift; #ifdef __MQL4__ - return ::iBarShift(_symbol, _tf, _time, _exact); + _bar_shift = ::iBarShift(_symbol, _tf, _time, _exact); + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing ::iBarShift() in ChartStatic::iBarShift(", _symbol, ", ", + EnumToString(_tf), ", ", TimeToString(_time), ", ", _exact, ")"); + DebugBreak(); + } + return _bar_shift; #else // __MQL5__ if (_time < 0) return (-1); ARRAY(datetime, arr); datetime _time0; // ENUM_TIMEFRAMES _tf = MQL4::TFMigrate(_tf); CopyTime(_symbol, _tf, 0, 1, arr); + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing 1st CopyTime() in ChartStatic::iBarShift(", _symbol, ", ", + EnumToString(_tf), ", ", TimeToString(_time), ", ", _exact, ")"); + DebugBreak(); + } + _time0 = arr[0]; if (CopyTime(_symbol, _tf, _time, _time0, arr) > 0) { if (ArraySize(arr) > 2) { - return ArraySize(arr) - 1; + _bar_shift = ArraySize(arr) - 1; } else { - return _time < _time0 ? 1 : 0; + _bar_shift = _time < _time0 ? 1 : 0; } } else { - return -1; + _bar_shift = -1; + } + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing 2nd CopyTime in ChartStatic::iBarShift(", _symbol, ", ", + EnumToString(_tf), ", ", TimeToString(_time), ", ", _exact, ")"); + DebugBreak(); } #endif + + return _bar_shift; } /** @@ -102,37 +137,37 @@ struct ChartStatic { /** * Returns the shift of the maximum value over a specific number of periods depending on type. */ - static int iHighest(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _type = MODE_HIGH, - unsigned int _count = WHOLE_ARRAY, int _start = 0) { + static int iHighest(const SymbolTf& _symbol_tf, int _type = MODE_HIGH, unsigned int _count = WHOLE_ARRAY, + int _start = 0) { #ifdef __MQL4__ - return ::iHighest(_symbol, _tf, _type, _count, _start); + return ::iHighest(_symbol_tf.Symbol(), _symbol_tf.Tf(), _type, _count, _start); #else // __MQL5__ if (_start < 0) return (-1); - _count = (_count <= 0 ? ChartStatic::iBars(_symbol, _tf) : _count); + _count = (_count <= 0 ? ChartStatic::iBars(_symbol_tf.Symbol(), _symbol_tf.Tf()) : _count); ARRAY(double, arr_d); ARRAY(long, arr_l); ARRAY(datetime, arr_dt); ArraySetAsSeries(arr_d, true); switch (_type) { case MODE_OPEN: - CopyOpen(_symbol, _tf, _start, _count, arr_d); + CopyOpen(_symbol_tf.Symbol(), _symbol_tf.Tf(), _start, _count, arr_d); break; case MODE_LOW: - CopyLow(_symbol, _tf, _start, _count, arr_d); + CopyLow(_symbol_tf.Symbol(), _symbol_tf.Tf(), _start, _count, arr_d); break; case MODE_HIGH: - CopyHigh(_symbol, _tf, _start, _count, arr_d); + CopyHigh(_symbol_tf.Symbol(), _symbol_tf.Tf(), _start, _count, arr_d); break; case MODE_CLOSE: - CopyClose(_symbol, _tf, _start, _count, arr_d); + CopyClose(_symbol_tf.Symbol(), _symbol_tf.Tf(), _start, _count, arr_d); break; case MODE_VOLUME: ArraySetAsSeries(arr_l, true); - CopyTickVolume(_symbol, _tf, _start, _count, arr_l); + CopyTickVolume(_symbol_tf.Symbol(), _symbol_tf.Tf(), _start, _count, arr_l); return (ArrayMaximum(arr_l, 0, _count) + _start); case MODE_TIME: ArraySetAsSeries(arr_dt, true); - CopyTime(_symbol, _tf, _start, _count, arr_dt); + CopyTime(_symbol_tf.Symbol(), _symbol_tf.Tf(), _start, _count, arr_dt); return (ArrayMaximum(arr_dt, 0, _count) + _start); default: break; @@ -293,6 +328,37 @@ struct ChartStatic { #endif } + /** + * Returns open time price value for the bar of indicated symbol. + * + * If local history is empty (not loaded), function returns 0. + */ + static datetime GetBarTime(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { +#ifdef __MQL4__ + datetime _time = ::iTime(_symbol, _tf, _shift); // Same as: Time[_shift] + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing ::iTime() in ChartStatic::GetBarTime(", _symbol, ", ", + EnumToString(_tf), ", ", _shift, ")"); + DebugBreak(); + } +#else // __MQL5__ + ARRAY(datetime, _arr); + // 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; + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing CopyTime() in ChartStatic::GetBarTime(", _symbol, ", ", + EnumToString(_tf), ", ", _shift, ")"); + DebugBreak(); + } +#endif + + return _time; + } + /** * Gets Chart ID. */ diff --git a/Chart.symboltf.h b/Chart.symboltf.h new file mode 100644 index 000000000..52411498d --- /dev/null +++ b/Chart.symboltf.h @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| 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 SymbolTf struct. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "Std.h" + +/** + * Represents symbol and timeframe. To be used by IndicatorBase and ChartBase classes. + */ +struct SymbolTf { + const string symbol; + const ENUM_TIMEFRAMES tf; + const string symbol_tf_key; + + CONST_REF_TO(string) Key() const { return symbol_tf_key; } + CONST_REF_TO(string) Symbol() const { return symbol; } + ENUM_TIMEFRAMES Tf() const { return tf; } + + SymbolTf(string _symbol, ENUM_TIMEFRAMES _tf) + : symbol(_symbol), tf(_tf), symbol_tf_key(_symbol + "_" + IntegerToString((int)_tf)) {} + + bool operator==(const SymbolTf& _r) const { return symbol_tf_key == _r.symbol_tf_key; } +}; diff --git a/ChartBase.h b/ChartBase.h new file mode 100644 index 000000000..7cf488116 --- /dev/null +++ b/ChartBase.h @@ -0,0 +1,718 @@ +//+------------------------------------------------------------------+ +//| 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 + * Class to provide generic chart operations. + */ + +// Prevents processing this includes file for the second time. +#ifndef __MQL__ +#pragma once +#endif + +#ifdef __DISABLE + +// Includes.` +#include "Bar.struct.h" +#include "Chart.enum.h" +#include "Chart.struct.h" +#include "Chart.symboltf.h" +#include "Data.define.h" +#include "Dict.mqh" +#include "Log.mqh" +#include "Refs.mqh" +#include "Task/TaskCondition.enum.h" + +/** + * Abstract class used as a base for market prices source. + */ +class ChartBase : public Dynamic { + // Unique, incremental id of the chart. + int id; + + // Generic chart params. + ChartParams cparams; + + // Time of the last bar. + datetime last_bar_time; + + // Index of the current bar. + int bar_index; + + // Whether new bar happened in the current tick. + bool is_new_bar; + + // Index of the current tick. + int tick_index; + + // Logger. + Ref logger; + + // Array of saved chart entries. + ARRAY(ChartEntry, chart_saves); + + public: + /** + * Constructor. + */ + ChartBase(string _symbol, ENUM_TIMEFRAMES _tf) : logger(new Log()) { + Set(CHART_PARAM_SYMBOL, _symbol); + Set(CHART_PARAM_TF, _tf); + + static int _id = 0; + id = _id++; + } + + /* Getters */ + + /** + * Gets a chart parameter value. + */ + template + T Get(ENUM_CHART_PARAM _param) { + return cparams.Get(_param); + } + + /** + * Returns time of the bar with a given shift. + */ + virtual datetime GetBarTime(int _shift = 0) = 0; + + datetime GetLastBarTime() { return last_bar_time; } + + /** + * Returns the number of bars on the chart. + */ + virtual int GetBars() = 0; + + /** + * Search for a bar by its time. + * + * Returns the index of the bar which covers the specified time. + */ + virtual int GetBarShift(datetime _time, bool _exact = false) = 0; + + /** + * Unique, incremental id of the chart. + */ + int GetId() { return id; } + + /** + * Returns pointer to logger. + */ + Log* GetLogger() { return logger.Ptr(); } + + /** + * Gets copy of params. + * + * @return + * Returns structure for Trade's params. + */ + ChartParams GetParams() const { return cparams; } + + /** + * Return symbol bound to chart. + */ + CONST_REF_TO(string) GetSymbol() { return cparams.Get(CHART_PARAM_SYMBOL); } + + /** + * Return time-frame bound to chart. + */ + ENUM_TIMEFRAMES GetTf() { return cparams.Get(CHART_PARAM_TF); } + + /** + * Returns open time price value for the bar of indicated symbol. + * + * If local history is empty (not loaded), function returns 0. + */ + virtual datetime GetTime(unsigned int _shift = 0) = 0; + + /** + * Return symbol pair for a given symbol index. + */ + virtual const string GetSymbolName(int _index) { return ::SymbolName(_index, true); } + + /** + * Return number of symbols available for the chart. + */ + virtual int GetSymbolsTotal() { return ::SymbolsTotal(true); } + + /* Price getters */ + + /** + * Returns the price value given applied price type. + */ + static float GetAppliedPrice(ENUM_APPLIED_PRICE _ap, float _o, float _h, float _c, float _l) { + BarOHLC _bar(_o, _h, _c, _l); + return _bar.GetAppliedPrice(_ap); + } + + /** + * Gets OHLC price values. + */ + virtual BarOHLC GetOHLC(int _shift = 0) { + datetime _time = GetBarTime(_shift); + float _open = 0, _high = 0, _low = 0, _close = 0; + if (_time > 0) { + _open = (float)GetOpen(_shift); + _high = (float)GetHigh(_shift); + _low = (float)GetLow(_shift); + _close = (float)GetClose(_shift); + } + BarOHLC _ohlc(_open, _high, _low, _close, _time); + return _ohlc; + } + + /** + * Returns the current price value given applied price type, symbol and timeframe. + */ + virtual double GetPrice(ENUM_APPLIED_PRICE _ap, int _shift = 0) = 0; + + /** + * Returns tick volume value for the bar. + * + * If local history is empty (not loaded), function returns 0. + */ + virtual long GetVolume(int _shift = 0) = 0; + + /** + * Returns the shift of the maximum value over a specific number of periods depending on type. + */ + virtual int GetHighest(int type, int _count = WHOLE_ARRAY, int _start = 0) = 0; + + /** + * Returns the shift of the minimum value over a specific number of periods depending on type. + */ + virtual int GetLowest(int type, int _count = WHOLE_ARRAY, int _start = 0) = 0; + + /** + * Gets chart entry. + * + * @param + * _tf ENUM_TIMEFRAMES Timeframe to use. + * _shift unsigned int _shift Shift to use. + * _symbol string Symbol to use. + * + * @return + * Returns ChartEntry struct. + */ + ChartEntry GetEntry(unsigned int _shift = 0) { + ChartEntry _chart_entry; + BarOHLC _ohlc = GetOHLC(_shift); + if (_ohlc.open > 0) { + BarEntry _bar_entry(_ohlc); + _chart_entry.SetBar(_bar_entry); + } + return _chart_entry; + } + + /** + * Returns ask price value for the bar of indicated symbol. + * + * If local history is empty (not loaded), function returns 0. + */ + double GetAsk(int _shift = 0) { return GetPrice(PRICE_ASK, _shift); } + + /** + * Returns bid price value for the bar of indicated symbol. + * + * If local history is empty (not loaded), function returns 0. + */ + double GetBid(int _shift = 0) { return GetPrice(PRICE_BID, _shift); } + + /** + * Returns close price value for the bar of indicated symbol. + * + * If local history is empty (not loaded), function returns 0. + */ + double GetClose(int _shift = 0) { return GetPrice(PRICE_CLOSE, _shift); } + + /** + * Returns high price value for the bar of indicated symbol. + * + * If local history is empty (not loaded), function returns 0. + */ + double GetHigh(int _shift = 0) { return GetPrice(PRICE_HIGH, _shift); } + + /** + * Returns open price value for the bar of indicated symbol. + * + * If local history is empty (not loaded), function returns 0. + */ + double GetOpen(int _shift = 0) { return GetPrice(PRICE_OPEN, _shift); } + + /** + * Returns low price value for the bar of indicated symbol. + * + * If local history is empty (not loaded), function returns 0. + */ + double GetLow(int _shift = 0) { return GetPrice(PRICE_LOW, _shift); } + + /** + * Get peak price at given number of bars. + * + * In case of error, check it via GetLastError(). + */ + virtual double GetPeakPrice(int _bars, int _mode, int _index) { + int _ibar = -1; + double peak_price = GetOpen(0); + switch (_mode) { + case MODE_HIGH: + _ibar = GetHighest(MODE_HIGH, _bars, _index); + return _ibar >= 0 ? GetHigh(_ibar) : false; + case MODE_LOW: + _ibar = GetLowest(MODE_LOW, _bars, _index); + return _ibar >= 0 ? GetLow(_ibar) : false; + default: + return false; + } + } + + /* Setters */ + + /** + * Sets chart parameter value. + */ + template + void Set(ENUM_CHART_PARAM _param, T _value) { + cparams.Set(_param, _value); + } + + /* State checking */ + + /** + * Checks whether chart has valid configuration. + */ + bool IsValid() { return GetOpen() > 0; } + + /** + * Validate whether given timeframe index is valid. + */ + bool IsValidTfIndex(ENUM_TIMEFRAMES_INDEX _tfi) { + if (!IsValid()) { + return false; + } + + for (int i = 0; i < GetTfIndicesTotal(); ++i) { + if (GetTfIndicesItem(i) == _tfi) { + return true; + } + } + + return false; + } + + /** + * Validates whether given timeframe is valid. + */ + bool IsValidShift(int _shift) { return GetTime(_shift) > 0; } + + /** + * Returns total number of timeframe indices the chart supports. Supports all TFs by default. + */ + virtual int GetTfIndicesTotal() { return FINAL_ENUM_TIMEFRAMES_INDEX; } + + /** + * Returns item from the list of timeframe indices the chart supports. Supports all TFs by default. + */ + virtual ENUM_TIMEFRAMES_INDEX GetTfIndicesItem(int _index) { return (ENUM_TIMEFRAMES_INDEX)_index; } + + /** + * List active timeframes. + * + * @param + * _all bool If true, return also non-active timeframes. + * + * @return + * Returns textual representation of list of timeframes. + */ + string ListTimeframes(bool _all = false, string _prefix = "Timeframes: ") { + string output = _prefix; + for (int i = 0; i < GetTfIndicesTotal(); i++) { + ENUM_TIMEFRAMES_INDEX _tfi = GetTfIndicesItem(i); + if (_all) { + output += StringFormat("%s: %s; ", ChartTf::IndexToString(_tfi), IsValidTfIndex(_tfi) ? "On" : "Off"); + } else { + output += IsValidTfIndex(_tfi) ? ChartTf::IndexToString(_tfi) + "; " : ""; + } + } + return output; + } + + /** + * Returns list of modelling quality for all periods. + */ + static string GetModellingQuality() { + string output = "Modelling Quality: "; + output += StringFormat( + "%s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%, %s: %.2f%%;", + "M1", CalcModellingQuality(PERIOD_M1), "M5", CalcModellingQuality(PERIOD_M5), "M15", + CalcModellingQuality(PERIOD_M15), "M30", CalcModellingQuality(PERIOD_M30), "H1", + CalcModellingQuality(PERIOD_H1), "H4", CalcModellingQuality(PERIOD_H4), "D1", CalcModellingQuality(PERIOD_D1), + "W1", CalcModellingQuality(PERIOD_W1), "MN1", CalcModellingQuality(PERIOD_MN1)); + return output; + } + + /** + * Calculate modelling quality. + * + * @see: + * - https://www.mql5.com/en/articles/1486 + * - https://www.mql5.com/en/articles/1513 + */ + static double CalcModellingQuality(ENUM_TIMEFRAMES TimePr = PERIOD_CURRENT) { + int nBarsInM1 = 0; + int nBarsInPr = 0; + int nBarsInNearPr = 0; + ENUM_TIMEFRAMES TimeNearPr = PERIOD_M1; + double ModellingQuality = 0; + long StartGen = 0; + long StartBar = 0; + long StartGenM1 = 0; + long HistoryTotal = 0; + datetime x = StrToTime("1971.01.01 00:00"); + datetime modeling_start_time = StrToTime("1971.01.01 00:00"); + + /** @TODO + + if (TimePr == NULL) TimePr = (ENUM_TIMEFRAMES)Period(); + if (TimePr == PERIOD_M1) TimeNearPr = PERIOD_M1; + if (TimePr == PERIOD_M5) TimeNearPr = PERIOD_M1; + if (TimePr == PERIOD_M15) TimeNearPr = PERIOD_M5; + if (TimePr == PERIOD_M30) TimeNearPr = PERIOD_M15; + if (TimePr == PERIOD_H1) TimeNearPr = PERIOD_M30; + if (TimePr == PERIOD_H4) TimeNearPr = PERIOD_H1; + if (TimePr == PERIOD_D1) TimeNearPr = PERIOD_H4; + if (TimePr == PERIOD_W1) TimeNearPr = PERIOD_D1; + if (TimePr == PERIOD_MN1) TimeNearPr = PERIOD_W1; + + // 1 minute. + double nBars = fmin(iBars(NULL, TimePr) * TimePr, iBars(NULL, PERIOD_M1)); + for (i = 0; i < nBars; i++) { + if (ChartStatic::iOpen(NULL, PERIOD_M1, i) >= 0.000001) { + if (GetTime(NULL, PERIOD_M1, i) >= modeling_start_time) { + nBarsInM1++; + } + } + } + + // Nearest time. + nBars = ChartStatic::iBars(NULL, TimePr); + for (i = 0; i < nBars; i++) { + if (ChartStatic::iOpen(NULL, TimePr, i) >= 0.000001) { + if (ChartStatic::iTime(NULL, TimePr, i) >= modeling_start_time) nBarsInPr++; + } + } + + // Period time. + nBars = fmin(ChartStatic::iBars(NULL, TimePr) * TimePr / TimeNearPr, iBars(NULL, TimeNearPr)); + for (i = 0; i < nBars; i++) { + if (ChartStatic::iOpen(NULL, TimeNearPr, (int)i) >= 0.000001) { + if (ChartStatic::iTime(NULL, TimeNearPr, i) >= modeling_start_time) nBarsInNearPr++; + } + } + + HistoryTotal = nBarsInPr; + nBarsInM1 = nBarsInM1 / TimePr; + nBarsInNearPr = nBarsInNearPr * TimeNearPr / TimePr; + StartGenM1 = HistoryTotal - nBarsInM1; + StartBar = HistoryTotal - nBarsInPr; + StartBar = 0; + StartGen = HistoryTotal - nBarsInNearPr; + + if (TimePr == PERIOD_M1) { + StartGenM1 = HistoryTotal; + StartGen = StartGenM1; + } + if ((HistoryTotal - StartBar) != 0) { + ModellingQuality = + ((0.25 * (StartGen - StartBar) + 0.5 * (StartGenM1 - StartGen) + 0.9 * (HistoryTotal - StartGenM1)) / + (HistoryTotal - StartBar)) * + 100; + } + */ + + return (ModellingQuality); + } + + /** + * Checks for chart condition. + * + * @param ENUM_CHART_CONDITION _cond + * Chart condition. + * @param MqlParam _args + * Trade action arguments. + * @return + * Returns true when the condition is met. + */ + bool CheckCondition(ENUM_CHART_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { + float _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4; + switch (_cond) { + case CHART_COND_ASK_BAR_PEAK: + return IsPeak(); + case CHART_COND_ASK_GT_BAR_HIGH: + return GetAsk() > GetHigh(); + case CHART_COND_ASK_GT_BAR_LOW: + return GetAsk() > GetLow(); + case CHART_COND_ASK_LT_BAR_HIGH: + return GetAsk() < GetHigh(); + case CHART_COND_ASK_LT_BAR_LOW: + return GetAsk() < GetLow(); + case CHART_COND_BAR_CLOSE_GT_PP_PP: { + ChartEntry _centry = GetEntry(1); + return GetClose() > _centry.bar.ohlc.GetPivot(); + } + case CHART_COND_BAR_CLOSE_GT_PP_R1: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() > _r1; + } + case CHART_COND_BAR_CLOSE_GT_PP_R2: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() > _r2; + } + case CHART_COND_BAR_CLOSE_GT_PP_R3: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() > _r3; + } + case CHART_COND_BAR_CLOSE_GT_PP_R4: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() > _r4; + } + case CHART_COND_BAR_CLOSE_GT_PP_S1: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() > _s1; + } + case CHART_COND_BAR_CLOSE_GT_PP_S2: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() > _s2; + } + case CHART_COND_BAR_CLOSE_GT_PP_S3: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() > _s3; + } + case CHART_COND_BAR_CLOSE_GT_PP_S4: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() > _s4; + } + case CHART_COND_BAR_CLOSE_LT_PP_PP: { + ChartEntry _centry = GetEntry(1); + return GetClose() < _centry.bar.ohlc.GetPivot(); + } + case CHART_COND_BAR_CLOSE_LT_PP_R1: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() < _r1; + } + case CHART_COND_BAR_CLOSE_LT_PP_R2: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() < _r2; + } + case CHART_COND_BAR_CLOSE_LT_PP_R3: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() < _r3; + } + case CHART_COND_BAR_CLOSE_LT_PP_R4: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() < _r4; + } + case CHART_COND_BAR_CLOSE_LT_PP_S1: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() < _s1; + } + case CHART_COND_BAR_CLOSE_LT_PP_S2: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() < _s2; + } + case CHART_COND_BAR_CLOSE_LT_PP_S3: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() < _s3; + } + case CHART_COND_BAR_CLOSE_LT_PP_S4: { + ChartEntry _centry = GetEntry(1); + _centry.bar.ohlc.GetPivots(PP_CLASSIC, _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4); + return GetClose() < _s4; + } + case CHART_COND_BAR_HIGHEST_CURR_20: + return GetHighest(MODE_CLOSE, 20) == 0; + case CHART_COND_BAR_HIGHEST_CURR_50: + return GetHighest(MODE_CLOSE, 50) == 0; + case CHART_COND_BAR_HIGHEST_PREV_20: + return GetHighest(MODE_CLOSE, 20) == 1; + case CHART_COND_BAR_HIGHEST_PREV_50: + return GetHighest(MODE_CLOSE, 50) == 1; + case CHART_COND_BAR_HIGH_GT_OPEN: + return GetHigh() > GetOpen(); + case CHART_COND_BAR_HIGH_LT_OPEN: + return GetHigh() < GetOpen(); + case CHART_COND_BAR_INDEX_EQ_ARG: + // Current bar's index equals argument value. + if (ArraySize(_args) > 0) { + return GetBarIndex() == DataParamEntry::ToInteger(_args[0]); + } else { + SetUserError(ERR_INVALID_PARAMETER); + return false; + } + case CHART_COND_BAR_INDEX_GT_ARG: + // Current bar's index greater than argument value. + if (ArraySize(_args) > 0) { + return GetBarIndex() > DataParamEntry::ToInteger(_args[0]); + } else { + SetUserError(ERR_INVALID_PARAMETER); + return false; + } + case CHART_COND_BAR_INDEX_LT_ARG: + // Current bar's index lower than argument value. + if (ArraySize(_args) > 0) { + return GetBarIndex() < DataParamEntry::ToInteger(_args[0]); + } else { + SetUserError(ERR_INVALID_PARAMETER); + return false; + } + case CHART_COND_BAR_LOWEST_CURR_20: + return GetLowest(MODE_CLOSE, 20) == 0; + case CHART_COND_BAR_LOWEST_CURR_50: + return GetLowest(MODE_CLOSE, 50) == 0; + case CHART_COND_BAR_LOWEST_PREV_20: + return GetLowest(MODE_CLOSE, 20) == 1; + case CHART_COND_BAR_LOWEST_PREV_50: + return GetLowest(MODE_CLOSE, 50) == 1; + case CHART_COND_BAR_LOW_GT_OPEN: + return GetLow() > GetOpen(); + case CHART_COND_BAR_LOW_LT_OPEN: + return GetLow() < GetOpen(); + case CHART_COND_BAR_NEW: + return IsNewBar(); + /* + case CHART_COND_BAR_NEW_DAY: + // @todo; + return false; + case CHART_COND_BAR_NEW_HOUR: + // @todo; + return false; + case CHART_COND_BAR_NEW_MONTH: + // @todo; + return false; + case CHART_COND_BAR_NEW_WEEK: + // @todo; + return false; + case CHART_COND_BAR_NEW_YEAR: + // @todo; + return false; + */ + default: + GetLogger().Error(StringFormat("Invalid market condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + return false; + } + } + bool CheckCondition(ENUM_CHART_CONDITION _cond) { + ARRAY(DataParamEntry, _args); + return CheckCondition(_cond, _args); + } + + /* Printer methods */ + + /** + * Returns textual representation of the Chart class. + */ + string ToString(unsigned int _shift = 0) { + return StringFormat("%s: %s", ChartTf::TfToString(Get(CHART_PARAM_TF)), GetEntry(_shift).ToCSV()); + } + + /* Snapshots */ + + /** + * Save the current BarOHLC values. + * + * @return + * Returns true if BarOHLC values has been saved, otherwise false. + */ + bool SaveChartEntry() { + // @todo: Use MqlRates. + unsigned int _last = ArraySize(chart_saves); + if (ArrayResize(chart_saves, _last + 1, 100)) { + chart_saves[_last].bar.ohlc.time = GetTime(); + chart_saves[_last].bar.ohlc.open = (float)GetOpen(); + chart_saves[_last].bar.ohlc.high = (float)GetHigh(); + chart_saves[_last].bar.ohlc.low = (float)GetLow(); + chart_saves[_last].bar.ohlc.close = (float)GetClose(); + return true; + } else { + return false; + } + } + + /* State checking */ + + /** + * Check whether the price is in its peak for the current period. + */ + bool IsPeak() { return GetAsk() >= GetHigh() || GetAsk() <= GetLow(); } + + /* Other methods */ + + /** + * Load stored BarOHLC values. + * + * @param + * _index unsigned int Index of the element in BarOHLC array. + * @return + * Returns BarOHLC struct element. + */ + ChartEntry LoadChartEntry(unsigned int _index = 0) { return chart_saves[_index]; } + + /** + * Return size of BarOHLC array. + */ + unsigned long SizeChartEntry() { return ArraySize(chart_saves); } + + /* Serializers */ + + /** + * Returns serialized representation of the object instance. + */ + SerializerNodeType Serialize(Serializer& _s) { + /** + TODO + + ChartEntry _centry = GetEntry(); + _s.PassStruct(THIS_REF, "chart-entry", _centry, SERIALIZER_FIELD_FLAG_DYNAMIC); + */ + return SerializerNodeObject; + } +}; + +#endif diff --git a/ChartMt.h b/ChartMt.h new file mode 100644 index 000000000..e87e8ddcc --- /dev/null +++ b/ChartMt.h @@ -0,0 +1,304 @@ +//+------------------------------------------------------------------+ +//| 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 + * Class to provide generic chart operations. + */ + +// Prevents processing this includes file for the second time. +#ifndef __MQL__ +#pragma once +#endif + +// Includes. +#include "Chart.symboltf.h" +#include "Terminal.define.h" + +#ifdef __DISABLED + +// Includes. +#include "Bar.struct.h" +#include "ChartBase.h" + +/** + * Meta-trader's native market prices source. + */ +class ChartMt : public ChartBase { + public: + /** + * Constructor. + */ + ChartMt(string _symbol, ENUM_TIMEFRAMES _tf) : ChartBase(_symbol, _tf) {} + + /** + * Returns new or existing instance of Chart for a given timeframe. + */ + static ChartMt* GetInstance(const SymbolTf& _symbol_tf) { + ChartMt* _ptr; + if (!Objects::TryGet(_symbol_tf.Key(), _ptr)) { + _ptr = Objects::Set(_symbol_tf.Key(), new ChartMt(_symbol_tf.Symbol(), _symbol_tf.Tf())); + } + return _ptr; + } + + // Virtual methods. + + /** + * Returns time of the bar with a given shift. + */ + virtual datetime GetBarTime(int _shift = 0) override { + datetime _time = ::iTime(GetSymbol(), GetTf(), _shift); + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing ::iTime() in ChartMt::GetBarTime(", _shift, ")"); + DebugBreak(); + } + + return _time; + } + + /** + * Returns the number of bars on the chart. + */ + virtual int GetBars() override { +#ifdef __MQL4__ + // In MQL4, for the current chart, the information about the amount of bars is in the Bars predefined variable. + return ::iBars(GetSymbol(), GetTf()); +#else // _MQL5__ + return ::Bars(GetSymbol(), GetTf()); +#endif + } + + /** + * Search for a bar by its time. + * + * Returns the index of the bar which covers the specified time. + */ + virtual int GetBarShift(datetime _time, bool _exact = false) override { + int _bar_shift; +#ifdef __MQL4__ + _bar_shift = ::iBarShift(GetTf(), _time, _exact); + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing ::iBarShift() in ChartMt::GetBarShift(", TimeToString(_time), ", ", + _exact, ")"); + DebugBreak(); + } +#else // __MQL5__ + if (_time < 0) return (-1); + ARRAY(datetime, arr); + datetime _time0; + // ENUM_TIMEFRAMES _tf = MQL4::TFMigrate(_tf); + CopyTime(GetSymbol(), GetTf(), 0, 1, arr); + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing 1st CopyTime() in ChartMt::GetBarShift(", TimeToString(_time), ", ", + _exact, ")"); + DebugBreak(); + } + + _time0 = arr[0]; + if (CopyTime(GetSymbol(), GetTf(), _time, _time0, arr) > 0) { + if (ArraySize(arr) > 2) { + _bar_shift = ArraySize(arr) - 1; + } else { + _bar_shift = _time < _time0 ? 1 : 0; + } + } else { + _bar_shift = -1; + } + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing 2nd CopyTime() in ChartMt::GetBarShift(", TimeToString(_time), ", ", + _exact, ")"); + DebugBreak(); + } +#endif + + return _bar_shift; + } + + /** + * Returns the shift of the maximum value over a specific number of periods depending on type. + */ + virtual int GetHighest(int type, int _count = WHOLE_ARRAY, int _start = 0) override { + int _highest = ::iHighest(GetSymbol(), GetTf(), (ENUM_SERIESMODE)type, _count, _start); + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing ::iHighest() in ChartMt::GetHighest(", type, ", ", _exact, ", ", + _start, ")"); + DebugBreak(); + } + + return _highest; + } + + /** + * Returns the shift of the minimum value over a specific number of periods depending on type. + */ + virtual int GetLowest(int type, int _count = WHOLE_ARRAY, int _start = 0) override { + int _lowest = ::iLowest(GetSymbol(), GetTf(), (ENUM_SERIESMODE)type, _count, _start); + + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError, " while doing ::iLowest() in ChartMt::GetHighest(", type, ", ", _exact, ", ", _start, + ")"); + DebugBreak(); + } + + return _lowest; + } + + /** + * Get peak price at given number of bars. + * + * In case of error, check it via GetLastError(). + */ + virtual double GetPeakPrice(int _bars, int _mode, int _index) override { + int _ibar = -1; + // @todo: Add symbol parameter. + double _peak_price = GetOpen(0); + switch (_mode) { + case MODE_HIGH: + _ibar = GetHighest(MODE_HIGH, _bars, _index); + return _ibar >= 0 ? GetHigh(_ibar) : false; + case MODE_LOW: + _ibar = GetLowest(MODE_LOW, _bars, _index); + return _ibar >= 0 ? GetLow(_ibar) : false; + default: + return false; + } + } + + /** + * Returns the current price value given applied price type, symbol and timeframe. + */ + virtual double GetPrice(ENUM_APPLIED_PRICE _ap, int _shift = 0) override { + switch (_ap) { + case PRICE_OPEN: + return ::iOpen(GetSymbol(), GetTf(), _shift); + case PRICE_HIGH: + return ::iHigh(GetSymbol(), GetTf(), _shift); + case PRICE_LOW: + return ::iLow(GetSymbol(), GetTf(), _shift); + case PRICE_CLOSE: + return ::iClose(GetSymbol(), GetTf(), _shift); + } + Print("Invalid applied price!"); + DebugBreak(); + return 0; + } + + /** + * Returns tick volume value for the bar. + * + * If local history is empty (not loaded), function returns 0. + */ + virtual long GetVolume(int _shift = 0) override { return ::iVolume(GetSymbol(), GetTf(), _shift); } +}; + +#endif + +/** + * Wrapper struct that returns close prices of each bar of the current chart. + * + * @see: https://docs.mql4.com/predefined/close + */ +struct ChartPriceClose { + protected: + const SymbolTf symbol_tf; + + public: + ChartPriceClose() : symbol_tf(Symbol(), PERIOD_CURRENT) {} + double operator[](const int _shift) const { return Get(symbol_tf, _shift); } + static double Get(const SymbolTf& _symbol_tf, const int _shift) { + return ChartStatic::iClose(_symbol_tf.Symbol(), _symbol_tf.Tf(), _shift); + } +}; + +/** + * Wrapper struct that returns the highest prices of each bar of the current chart. + * + * @see: https://docs.mql4.com/predefined/high + */ +struct ChartPriceHigh { + protected: + const SymbolTf symbol_tf; + + public: + ChartPriceHigh() : symbol_tf(Symbol(), PERIOD_CURRENT) {} + double operator[](const int _shift) const { return Get(symbol_tf, _shift); } + static double Get(const SymbolTf& _symbol_tf, const int _shift) { + return ChartStatic::iHigh(_symbol_tf.Symbol(), _symbol_tf.Tf(), _shift); + } +}; + +/** + * Wrapper struct that returns the lowest prices of each bar of the current chart. + * + * @see: https://docs.mql4.com/predefined/low + */ +struct ChartPriceLow { + protected: + const SymbolTf symbol_tf; + + public: + ChartPriceLow() : symbol_tf(Symbol(), PERIOD_CURRENT) {} + double operator[](const int _shift) const { return Get(symbol_tf, _shift); } + static double Get(const SymbolTf& _symbol_tf, const int _shift) { + return ChartStatic::iLow(_symbol_tf.Symbol(), _symbol_tf.Tf(), _shift); + } +}; + +/** + * Wrapper struct that returns open prices of each bar of the current chart. + * + * @see: https://docs.mql4.com/predefined/open + */ +struct ChartPriceOpen { + protected: + const SymbolTf symbol_tf; + + public: + ChartPriceOpen() : symbol_tf(Symbol(), PERIOD_CURRENT) {} + double operator[](const int _shift) const { return Get(symbol_tf, _shift); } + static double Get(const SymbolTf& _symbol_tf, const int _shift) { + return ChartStatic::iOpen(_symbol_tf.Symbol(), _symbol_tf.Tf(), _shift); + } +}; + +/** + * Wrapper struct that returns open time of each bar of the current chart. + * + * @see: https://docs.mql4.com/predefined/time + */ +struct ChartBarTime { + protected: + const SymbolTf symbol_tf; + + public: + ChartBarTime() : symbol_tf(Symbol(), PERIOD_CURRENT) {} + datetime operator[](const int _shift) const { return Get(symbol_tf, _shift); } + static datetime Get(const SymbolTf& _symbol_tf, const int _shift) { + return ChartStatic::GetBarTime(_symbol_tf.Symbol(), _symbol_tf.Tf(), _shift); + } +}; diff --git a/DateTime.mqh b/DateTime.mqh index 26bf37ded..4bbe8fe10 100644 --- a/DateTime.mqh +++ b/DateTime.mqh @@ -62,6 +62,7 @@ class DateTime { * Class constructor. */ DateTime() { TimeToStruct(TimeCurrent(), 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; } DateTime(datetime _dt) { dt_curr.Set(_dt); } @@ -114,8 +115,9 @@ class DateTime { _result |= DATETIME_SECOND; } - if (dt_curr.GetValue(DATETIME_DAY | DATETIME_WEEK) <= 1) { - // Check if it's a new week (Sunday/Monday). + if (dt_curr.GetValue(DATETIME_DAY | DATETIME_WEEK) == 0) { + // It's the first day of the week (Sunday). + // Note that GetValue() for the above flags just returns value of GetDayOfWeek(). // @see https://docs.mql4.com/dateandtime/dayofweek if (dt_curr.GetValue(DATETIME_DAY | DATETIME_WEEK) != dt_last.GetValue(DATETIME_DAY | DATETIME_WEEK)) { // New week started. @@ -123,7 +125,7 @@ class DateTime { } } -#ifdef __debug__ +#ifdef __debug_verbose__ string _passed = "time now " + (string)dt_curr.GetTimestamp() + ", time last " + (string)dt_last.GetTimestamp() + " "; @@ -176,28 +178,22 @@ class DateTime { /** * Sets the new DateTimeEntry struct. */ - void SetEntry(DateTimeEntry &_dt) { dt_curr = _dt; } + void SetEntry(DateTimeEntry &_dt) { + dt_last = dt_curr; + dt_curr = _dt; + } /* Dynamic methods */ /** * Checks if new minute started. - * - * @return bool - * Returns true when new minute started. */ - bool IsNewMinute(bool _update = true) { - bool _result = false; - if (_update) { - dt_last = dt_curr; - Update(); - } - if (dt_curr.GetSeconds() < dt_last.GetSeconds()) { - _result = true; - } - dt_last = dt_curr; - return _result; - } + bool IsNewMinute() { return (GetStartedPeriods(false, false) & DATETIME_MINUTE) != 0; } + + /** + * Checks if new hour started. + */ + bool IsNewHour() { return (GetStartedPeriods(false, false) & DATETIME_HOUR) != 0; } /** * Updates datetime to the current one. diff --git a/Dict.mqh b/Dict.mqh index 472c12105..843a1fc82 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -217,32 +217,34 @@ class Dict : public DictBase { DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); if (keySlot == NULL && !IsGrowUpAllowed()) { - // Resize is prohibited. - return false; + // Resize is prohibited, so we will just overwrite some slot. + allow_resize = false; } - // Will resize dict if there were performance problems before. - if (allow_resize && IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { - if (!GrowUp()) { - return false; + if (allow_resize) { + // Will resize dict if there were performance problems before or there is no slots. + if (IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + // We now have new positions of slots, so we have to take the corrent slot again. + keySlot = GetSlotByKey(dictSlotsRef, key, position); } - // We now have new positions of slots, so we have to take the corrent slot again. - keySlot = GetSlotByKey(dictSlotsRef, key, position); - } - if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { - // No DictSlotsRef.DictSlots available. - if (overflow_listener != NULL) { - if (!overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { - // Overwriting slot pointed exactly by key's position in the hash table (we don't check for possible - // conflicts). - keySlot = &dictSlotsRef.DictSlots[Hash(key) % ArraySize(dictSlotsRef.DictSlots)]; + if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { + // No DictSlotsRef.DictSlots available. + if (overflow_listener != NULL) { + if (!overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { + // Overwriting slot pointed exactly by key's position in the hash table (we don't check for possible + // conflicts). + keySlot = &dictSlotsRef.DictSlots[Hash(key) % ArraySize(dictSlotsRef.DictSlots)]; + } } - } - if (keySlot == NULL) { - // We need to expand array of DictSlotsRef.DictSlots (by 25% by default). - if (!GrowUp()) return false; + if (keySlot == NULL) { + // We need to expand array of DictSlotsRef.DictSlots (by 25% by default). + if (!GrowUp()) return false; + } } } @@ -278,8 +280,8 @@ class Dict : public DictBase { if (_overwrite_slot) { // Overwriting starting position for faster further lookup. position = _starting_position; - } else { - // Slot overwrite is not needed. Using empty slot. + } else if (!dictSlotsRef.DictSlots[position].IsUsed()) { + // If slot isn't already used then we increment number of used slots. ++dictSlotsRef._num_used; } diff --git a/DictObject.mqh b/DictObject.mqh index 260f62994..965025f6b 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -221,32 +221,34 @@ class DictObject : public DictBase { DictSlot* keySlot = this PTR_DEREF GetSlotByKey(dictSlotsRef, key, position); if (keySlot == NULL && !this PTR_DEREF IsGrowUpAllowed()) { - // Resize is prohibited. - return false; + // Resize is prohibited, so we will just overwrite some slot. + allow_resize = false; } - // Will resize dict if there were performance problems before. - if (allow_resize && this PTR_DEREF IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { - if (!GrowUp()) { - return false; + if (allow_resize) { + // Will resize dict if there were performance problems before or there is no slots. + if (this PTR_DEREF IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + // We now have new positions of slots, so we have to take the corrent slot again. + keySlot = this PTR_DEREF GetSlotByKey(dictSlotsRef, key, position); } - // We now have new positions of slots, so we have to take the corrent slot again. - keySlot = this PTR_DEREF GetSlotByKey(dictSlotsRef, key, position); - } - if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { - // No DictSlotsRef.DictSlots available. - if (this PTR_DEREF overflow_listener != NULL) { - if (!this PTR_DEREF overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { - // Overwriting slot pointed exactly by key's position in the hash table (we don't check for possible - // conflicts). - keySlot = &dictSlotsRef.DictSlots[this PTR_DEREF Hash(key) % ArraySize(dictSlotsRef.DictSlots)]; + if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { + // No DictSlotsRef.DictSlots available. + if (this PTR_DEREF overflow_listener != NULL) { + if (!this PTR_DEREF overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { + // Overwriting slot pointed exactly by key's position in the hash table (we don't check for possible + // conflicts). + keySlot = &dictSlotsRef.DictSlots[this PTR_DEREF Hash(key) % ArraySize(dictSlotsRef.DictSlots)]; + } } - } - if (keySlot == NULL) { - // We need to expand array of DictSlotsRef.DictSlots. - if (!GrowUp()) return false; + if (keySlot == NULL) { + // We need to expand array of DictSlotsRef.DictSlots. + if (!GrowUp()) return false; + } } } @@ -284,8 +286,8 @@ class DictObject : public DictBase { if (_overwrite_slot) { // Overwriting starting position for faster further lookup. position = _starting_position; - } else { - // Slot overwrite is not needed. Using empty slot PTR_DEREF + } else if (!dictSlotsRef.DictSlots[position].IsUsed()) { + // If slot isn't already used then we increment number of used slots. ++dictSlotsRef._num_used; } diff --git a/DictStruct.mqh b/DictStruct.mqh index 9f01a15a6..d30fb06bc 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -293,32 +293,34 @@ class DictStruct : public DictBase { DictSlot* keySlot = THIS_ATTR GetSlotByKey(dictSlotsRef, key, position); if (keySlot == NULL && !THIS_ATTR IsGrowUpAllowed()) { - // Resize is prohibited. - return false; + // Resize is prohibited, so we will just overwrite some slot. + allow_resize = false; } - // Will resize dict if there were performance problems before. - if (allow_resize && THIS_ATTR IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { - if (!GrowUp()) { - return false; + if (allow_resize) { + // Will resize dict if there were performance problems before or there is no slots. + if (THIS_ATTR IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + // We now have new positions of slots, so we have to take the corrent slot again. + keySlot = THIS_ATTR GetSlotByKey(dictSlotsRef, key, position); } - // We now have new positions of slots, so we have to take the corrent slot again. - keySlot = THIS_ATTR GetSlotByKey(dictSlotsRef, key, position); - } - if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { - // No DictSlotsRef.DictSlots available. - if (THIS_ATTR overflow_listener != NULL) { - if (!THIS_ATTR overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { - // Overwriting slot pointed exactly by key's position in the hash table (we don't check for possible - // conflicts). - keySlot = &dictSlotsRef.DictSlots[THIS_ATTR Hash(key) % ArraySize(dictSlotsRef.DictSlots)]; + if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { + // No DictSlotsRef.DictSlots available. + if (THIS_ATTR overflow_listener != NULL) { + if (!THIS_ATTR overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { + // Overwriting slot pointed exactly by key's position in the hash table (we don't check for possible + // conflicts). + keySlot = &dictSlotsRef.DictSlots[THIS_ATTR Hash(key) % ArraySize(dictSlotsRef.DictSlots)]; + } } - } - if (keySlot == NULL) { - // We need to expand array of DictSlotsRef.DictSlots. - if (!GrowUp()) return false; + if (keySlot == NULL) { + // We need to expand array of DictSlotsRef.DictSlots. + if (!GrowUp()) return false; + } } } @@ -356,8 +358,8 @@ class DictStruct : public DictBase { if (_overwrite_slot) { // Overwriting starting position for faster further lookup. position = _starting_position; - } else { - // Slot overwrite is not needed. Using empty slot. + } else if (!dictSlotsRef.DictSlots[position].IsUsed()) { + // If slot isn't already used then we increment number of used slots. ++dictSlotsRef._num_used; } diff --git a/Draw.mqh b/Draw.mqh index 2313ac735..fbb32f2f1 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -302,10 +302,12 @@ class Draw : public Chart { /** * Draw a line given the price. */ - void ShowLine(string oname, double price, int _colour = Yellow) { + void ShowLine(string oname, double price, int colour = Yellow) { + /** @TODO Draw::ObjectCreate(chart_id, oname, OBJ_HLINE, 0, GetBarTime(), price); Draw::ObjectSet(oname, OBJPROP_COLOR, _colour); Draw::ObjectMove(oname, 0, GetBarTime(), price); + */ } /** diff --git a/DrawIndicator.mqh b/DrawIndicator.mqh index 042dfa3c0..d3448a795 100644 --- a/DrawIndicator.mqh +++ b/DrawIndicator.mqh @@ -56,6 +56,8 @@ class DrawIndicator { color color_line; Draw* draw; IndicatorBase* indi; + bool enabled; + int window; public: // Object variables. @@ -66,7 +68,7 @@ class DrawIndicator { /** * Class constructor. */ - DrawIndicator(IndicatorBase* _indi) : indi(_indi) { + DrawIndicator(IndicatorBase* _indi) : indi(_indi), enabled(false), window(0) { // color_line = Object::IsValid(_indi) ? _indi.GetParams().indi_color : clrRed; // @fixme draw = new Draw(); } @@ -89,15 +91,38 @@ class DrawIndicator { /* Class methods */ + /** + * Sets whether drawing is enabled. + */ + void SetEnabled(bool _value) { enabled = _value; } + + /** + * Checks whether drawing is enabled. + */ + bool GetEnabled() { return enabled; } + /** * Sets color of line. */ void SetColorLine(color _clr) { color_line = _clr; } + /** + * Sets chart's window index. + */ + void SetWindow(int _window) { window = _window; } + /** * Draw line from the last point. */ - void DrawLineTo(string _name, datetime _time, double _value, int _window = WINDOW_MAIN) { + void DrawLineTo(string _name, datetime _time, double _value, int _window = -1) { + if (!enabled) { + return; + } + + if (_window == -1) { + _window = window; + } + if (!last_points.KeyExists(_name)) { last_points.Set(_name, DrawPoint(_time, _value)); } else { diff --git a/EA.mqh b/EA.mqh index b914b1bf7..fbc8f7f3d 100644 --- a/EA.mqh +++ b/EA.mqh @@ -31,12 +31,14 @@ // Includes. #include "Chart.mqh" +#include "./Chart.struct.static.h" #include "Data.struct.h" #include "Dict.mqh" #include "DictObject.mqh" #include "EA.enum.h" #include "EA.struct.h" #include "Market.mqh" +#include "Platform.h" #include "Refs.struct.h" #include "SerializerConverter.mqh" #include "SerializerCsv.mqh" @@ -82,7 +84,12 @@ class EA : public Taskable { /** * Init code (called on constructor). */ - void Init() { InitTask(); } + void Init() { + // Ensuring Platform singleton is already initialized. + Platform::Init(); + + InitTask(); + } /** * Process initial task (called on constructor). @@ -106,9 +113,9 @@ class EA : public Taskable { // Add and process tasks. Init(); // Initialize a trade instance for the current chart and symbol. - ChartParams _cparams((ENUM_TIMEFRAMES)_Period, _Symbol); + Ref _source = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); TradeParams _tparams(0, 1.0f, 0, eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); - Trade _trade(_tparams, _cparams); + Trade _trade(_tparams, _source.Ptr()); trade.Set(_Symbol, _trade); logger.Link(_trade.GetLogger()); logger.SetLevel(eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); @@ -201,7 +208,7 @@ class EA : public Taskable { _signals |= _strat.SignalClose(ORDER_TYPE_SELL, _scm, _scl, _ss) ? SIGNAL_CLOSE_SELL_MAIN : 0; _signals |= !_strat.SignalCloseFilter(ORDER_TYPE_SELL, _scfm) ? SIGNAL_CLOSE_SELL_FILTER : 0; _signals |= !_strat.SignalCloseFilterTime(_scft) ? SIGNAL_CLOSE_TIME_FILTER : 0; - TradeSignalEntry _sentry(_signals, _strat.Get(STRAT_PARAM_TF), _strat.Get(STRAT_PARAM_ID)); + TradeSignalEntry _sentry(_signals, _strat.GetSource() PTR_DEREF GetTf(), _strat.Get(STRAT_PARAM_ID)); _sentry.Set(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_STRENGTH), _strat.SignalOpen(_sofm, _sol, _ss)); _sentry.Set(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_TIME), ::TimeGMT()); return _sentry; @@ -278,7 +285,7 @@ class EA : public Taskable { string _comment_close = _strat != NULL && _sig_close != 0.0f ? _strat.GetOrderCloseComment() : __FUNCTION_LINE__; // Check if we should close the orders. - _trade_allowed &= _strat.GetTrade().IsTradeAllowed(_sig_close != 0.0f); + // _trade_allowed &= _strat.GetTrade().IsTradeAllowed(_sig_close != 0.0f); if (_sig_close != 0.0f && _trade_allowed) { if (_sig_close >= 0.5f) { // Close signal for buy order. @@ -304,7 +311,7 @@ class EA : public Taskable { unsigned int _sig_f = eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_SIGNAL_FILTER)); string _comment_open = _strat != NULL && _sig_open != 0.0f ? _strat.GetOrderOpenComment() : __FUNCTION_LINE__; // Open orders on signals. - _trade_allowed &= _strat.GetTrade().IsTradeAllowed(_sig_open != 0.0f); + // _trade_allowed &= _strat.GetTrade().IsTradeAllowed(_sig_open != 0.0f); if (_sig_open != 0.0f && _trade_allowed) { if (_sig_open >= 0.5f) { // Open signal for buy. @@ -373,29 +380,24 @@ class EA : public Taskable { */ virtual bool TradeRequest(ENUM_ORDER_TYPE _cmd, string _symbol = NULL, Strategy *_strat = NULL) { bool _result = false; - Trade *_etrade = trade.GetByKey(_symbol); - Trade *_strade = _strat.GetTrade(); + Trade *_trade = trade.GetByKey(_symbol); // Prepare a request. - MqlTradeRequest _request = _etrade.GetTradeOpenRequest(_cmd); + MqlTradeRequest _request = _trade.GetTradeOpenRequest(_cmd); _request.comment = _strat.GetOrderOpenComment(); _request.magic = _strat.Get(STRAT_PARAM_ID); _request.price = SymbolInfoStatic::GetOpenOffer(_symbol, _cmd); _request.volume = fmax(_strat.Get(STRAT_PARAM_LS), SymbolInfoStatic::GetVolumeMin(_symbol)); - _request.volume = _etrade.NormalizeLots(_request.volume); + + // @fixit Uncomment + // _request.volume = _trade.NormalizeLots(_request.volume); + // Check strategy's trade states. switch (_request.action) { case TRADE_ACTION_DEAL: - if (!_etrade.IsTradeRecommended()) { - if (logger.GetLevel() > V_INFO) { - logger.Debug( - StringFormat("Trade not opened due to EA trading states (%d).", _strade.GetStates().GetStates()), - __FUNCTION_LINE__); - } - return _result; - } else if (!_strade.IsTradeRecommended()) { + if (!_trade.IsTradeRecommended()) { if (logger.GetLevel() > V_INFO) { logger.Debug( - StringFormat("Trade not opened due to strategy trading states (%d).", _strade.GetStates().GetStates()), + StringFormat("Trade not opened due to EA trading states (%d).", _trade.GetStates().GetStates()), __FUNCTION_LINE__); } return _result; @@ -406,13 +408,13 @@ class EA : public Taskable { OrderParams _oparams; _strat.OnOrderOpen(_oparams); // Send the request. - _result = _etrade.RequestSend(_request, _oparams); + _result = _trade.RequestSend(_request, _oparams); if (!_result) { // && _strade.IsTradeRecommended( logger.Debug( StringFormat("Error while sending a trade request! Entry: %s", SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()), __FUNCTION_LINE__, StringFormat("Code: %d, Msg: %s", _LastError, Terminal::GetErrorText(_LastError))); - if (_etrade.IsTradeRecommended() && _strade.IsTradeRecommended()) { + if (_trade.IsTradeRecommended()) { logger.Debug( StringFormat("Error while sending a trade request! Entry: %s", SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()), @@ -441,8 +443,9 @@ class EA : public Taskable { ProcessPeriods(); // Process all enabled strategies and retrieve their signals. for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { + bool _can_trade = true; Strategy *_strat = iter.Value().Ptr(); - Trade *_trade = _strat.GetTrade(); + Trade *_trade = trade.GetByKey(_Symbol); if (_strat.IsEnabled()) { if (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) >= DATETIME_MINUTE) { // Process when new periods started. @@ -452,7 +455,7 @@ class EA : public Taskable { eresults.stg_processed_periods++; } if (_strat.TickFilter(_tick)) { - bool _can_trade = !_trade.HasState(TRADE_STATE_MODE_DISABLED); + _can_trade &= !_trade.HasState(TRADE_STATE_MODE_DISABLED); _can_trade &= !_strat.IsSuspended(); TradeSignalEntry _sentry = GetStrategySignalEntry(_strat, _can_trade, _strat.Get(STRAT_PARAM_SHIFT)); if (_sentry.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_SIGNALS)) > 0) { @@ -505,7 +508,7 @@ class EA : public Taskable { Strategy *_strati = iter.Value().Ptr(); IndicatorData *_indi = _strati.GetIndicator(); if (_indi != NULL) { - ENUM_TIMEFRAMES _itf = _indi.GetParams().tf.GetTf(); + ENUM_TIMEFRAMES _itf = _indi PTR_DEREF GetTf(); IndicatorDataEntry _ientry = _indi.GetEntry(); if (!data_indi.KeyExists(_itf)) { // Create new timeframe buffer if does not exist. diff --git a/Exchange/Exchange.h b/Exchange/Exchange.h index 8c32f9fe3..5551c69b9 100644 --- a/Exchange/Exchange.h +++ b/Exchange/Exchange.h @@ -33,11 +33,11 @@ #include "../Trade.mqh" #include "Exchange.struct.h" -class Exchange { +class Exchange : public Dynamic { protected: - DictObject accounts; - DictObject symbols; - DictObject trades; + DictStruct> accounts; + DictStruct> symbols; + DictStruct> trades; ExchangeParams eparams; public: @@ -61,17 +61,26 @@ class Exchange { /** * Adds account instance to the list. */ - void AccountAdd(AccountBase &_account, string _name) { accounts.Set(_name, _account); } + void AccountAdd(AccountBase *_account, string _name) { + Ref _ref = _account; + accounts.Set(_name, _ref); + } /** * Adds symbol instance to the list. */ - void SymbolAdd(SymbolInfo &_sinfo, string _name) { symbols.Set(_name, _sinfo); } + void SymbolAdd(SymbolInfo *_sinfo, string _name) { + Ref _ref = _sinfo; + symbols.Set(_name, _ref); + } /** * Adds trade instance to the list. */ - void TradeAdd(Trade &_trade, string _name) { trades.Set(_name, _trade); } + void TradeAdd(Trade *_trade, string _name) { + Ref _ref = _trade; + trades.Set(_name, _ref); + } /* Removers */ diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 index 8a259676e..d3d289c61 100644 --- a/Exchange/tests/Exchange.test.mq5 +++ b/Exchange/tests/Exchange.test.mq5 @@ -25,6 +25,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Exchange.h" @@ -32,7 +33,10 @@ class AccountDummy : public AccountBase {}; // class ExchangeDummy : public Exchange {}; class SymbolDummy : public SymbolInfo {}; -class TradeDummy : public Trade {}; +class TradeDummy : public Trade { + public: + TradeDummy(IndicatorBase *_indi_candle) : Trade(_indi_candle) {} +}; // Global variables. ExchangeDummy ex_dummy; @@ -41,22 +45,26 @@ ExchangeDummy ex_dummy; bool TestExchange01() { bool _result = true; // Initialize a dummy Exchange instance. - ExchangeDummy exchange; + Ref exchange = new ExchangeDummy(); + // Attach instances of dummy accounts. - AccountDummy account01; - AccountDummy account02; - exchange.AccountAdd(account01, "Account01"); - exchange.AccountAdd(account02, "Account02"); + Ref account01 = new AccountDummy(); + Ref account02 = new AccountDummy(); + exchange REF_DEREF AccountAdd(account01.Ptr(), "Account01"); + exchange REF_DEREF AccountAdd(account02.Ptr(), "Account02"); + // Attach instances of dummy symbols. - SymbolDummy symbol01; - SymbolDummy symbol02; - exchange.SymbolAdd(symbol01, "Symbol01"); - exchange.SymbolAdd(symbol02, "Symbol02"); + Ref symbol01 = new SymbolDummy(); + Ref symbol02 = new SymbolDummy(); + exchange REF_DEREF SymbolAdd(symbol01.Ptr(), "Symbol01"); + exchange REF_DEREF SymbolAdd(symbol02.Ptr(), "Symbol02"); + // Attach instances of dummy trades. - TradeDummy trade01; - TradeDummy trade02; - exchange.TradeAdd(trade01, "Trade01"); - exchange.TradeAdd(trade02, "Trade02"); + Ref trade01 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT)); + Ref trade02 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT)); + + exchange REF_DEREF TradeAdd(trade01.Ptr(), "Trade01"); + exchange REF_DEREF TradeAdd(trade02.Ptr(), "Trade02"); return _result; } @@ -64,6 +72,7 @@ bool TestExchange01() { * Implements OnInit(). */ int OnInit() { + Platform::Init(); bool _result = true; assertTrueOrFail(TestExchange01(), "Fail!"); return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; diff --git a/Flags.h b/Flags.h new file mode 100644 index 000000000..cbc9b04f7 --- /dev/null +++ b/Flags.h @@ -0,0 +1,105 @@ +//+------------------------------------------------------------------+ +//| 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 . + * + */ + +/** + * Flags manipulation helper. + */ +template +struct Flags { + // Bit-based value. + unsigned T value; + + /** + * Constructor. + */ + Flags(T _value = 0) : value(_value) {} + + /** + * Adds given flag to the current value. + */ + void AddFlag(T _flag) { + if ((_flag & (_flag - 1)) != 0) { + Print("WARNING: Please use Flags::AddFlags() when adding multiple flags!"); + DebugBreak(); + } + + value |= _flag; + } + + /** + * Adds multiple flags to the current value. + */ + void AddFlags(T _flags) { + if ((_flags & (_flags - 1)) == 0) { + Print("WARNING: Please use Flags::AddFlag() when adding a single flag!"); + DebugBreak(); + } + + value |= _flags; + } + + /** + * Clears given flag or multiple flags from the current value. + */ + void ClearFlags(T _flags) { value &= ~_flags; } + + /** + * Checks whether current value has given flag. (Same as HasAllFlags()). + */ + bool HasFlag(T _flag) { + if ((_flag & (_flag - 1)) != 0) { + Print("WARNING: Please use Flags::HasFlags() when checking for multiple flags!"); + DebugBreak(); + } + + return (value & _flag) == _flag; + } + + /** + * Checks whether current value has all given flags. + */ + bool HasAllFlags(T _flags) { + if ((_flags & (_flags - 1)) == 0) { + Print("WARNING: Please use Flags::HasFlag() when checking for a single flag!"); + DebugBreak(); + } + + return (value & _flags) == _flags; + } + + /** + * Checks whether current value has any of the given flags. + */ + bool HasAnyFlag(T _flags) { + if ((_flags & (_flags - 1)) == 0) { + Print("WARNING: Please use Flags::HasFlag() when checking for a single flag!"); + DebugBreak(); + } + + return (value & _flags) != 0; + } + + /** + * Clears current value. + */ + void Clear() { value = 0; } +}; diff --git a/Indicator.enum.h b/Indicator.enum.h index 6a5f88794..a25601c79 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -212,6 +212,7 @@ enum INDICATOR_ENTRY_FLAGS { // Storage type for IndicatorBase::GetSpecificValueStorage(). enum ENUM_INDI_VS_TYPE { + INDI_VS_TYPE_NONE, // Not set. INDI_VS_TYPE_TIME, // Candle. INDI_VS_TYPE_TICK_VOLUME, // Candle. INDI_VS_TYPE_VOLUME, // Candle. @@ -225,6 +226,18 @@ enum ENUM_INDI_VS_TYPE { INDI_VS_TYPE_PRICE_WEIGHTED, // Candle. INDI_VS_TYPE_PRICE_BID, // Tick. INDI_VS_TYPE_PRICE_ASK, // Tick. + // Indexed value storages, available if indicator have buffer at this index: + INDI_VS_TYPE_INDEX_0, + INDI_VS_TYPE_INDEX_1, + INDI_VS_TYPE_INDEX_2, + INDI_VS_TYPE_INDEX_4, + INDI_VS_TYPE_INDEX_5, + INDI_VS_TYPE_INDEX_6, + INDI_VS_TYPE_INDEX_7, + INDI_VS_TYPE_INDEX_8, + INDI_VS_TYPE_INDEX_9, + INDI_VS_TYPE_INDEX_FIRST = INDI_VS_TYPE_INDEX_0, + INDI_VS_TYPE_INDEX_LAST = INDI_VS_TYPE_INDEX_9 }; // Indicator flags. @@ -234,3 +247,26 @@ enum ENUM_INDI_FLAGS { 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. }; + +// Flags indicating which data sources are required to be provided in order indicator to work. +enum ENUM_INDI_SUITABLE_DS_TYPE { + INDI_SUITABLE_DS_TYPE_EXPECT_NONE = 1 << 0, + INDI_SUITABLE_DS_TYPE_TICK = 1 << 1, // Indicator requires Tick-based data source in the hierarchy. + INDI_SUITABLE_DS_TYPE_CANDLE = 1 << 2, // Indicator requires Candle-based data source in the hierarchy. + INDI_SUITABLE_DS_TYPE_CUSTOM = 1 << 3, // Indicator requires parent data source to have custom set of buffers/modes. + INDI_SUITABLE_DS_TYPE_AP = + 1 << 4, // Indicator requires single, targetted (by applied price) buffer from data source in the hierarchy. + INDI_SUITABLE_DS_TYPE_AV = + 1 << 5, // Indicator requires single, targetted (by applied volume) buffer from data source in the hierarchy. + INDI_SUITABLE_DS_TYPE_BASE_ONLY = 1 << 6, // Required data source must be directly connected to this data source. + INDI_SUITABLE_DS_TYPE_EXPECT_ANY = 1 << 7, // Requires data source of any kind. +}; + +// Type of data source mode. Required to determine what "mode" means for the user. +enum ENUM_INDI_DS_MODE_KIND { + INDI_DS_MODE_KIND_INDEX, // Mode is a buffer index. + INDI_DS_MODE_KIND_VS_TYPE, // Mode is a value from ENUM_INDI_VS_TYPE enumeration, e.g., ENUM_INDI_VS_PRICE_OPEN. + INDI_DS_MODE_KIND_AP, // Mode is a value from ENUM_APPLIED_PRICE enumeration. It is used to retrieve value storage + // based on ENUM_INDI_VS_TYPE enumeration, e.g., PRICE_OPEN becomes ENUM_INDI_VS_PRICE_OPEN. +}; +//+------------------------------------------------------------------+ diff --git a/Indicator.mqh b/Indicator.mqh index 9b42320b9..f1b1df4c5 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -24,15 +24,12 @@ #ifndef INDICATOR_MQH #define INDICATOR_MQH -// Forward declaration. -class Chart; - // Includes. #include "Array.mqh" #include "BufferStruct.mqh" -#include "Chart.mqh" #include "DateTime.mqh" #include "DrawIndicator.mqh" +#include "Flags.h" #include "Indicator.define.h" #include "Indicator.enum.h" #include "Indicator.struct.cache.h" @@ -92,34 +89,8 @@ double iCustom5(string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C template class Indicator : public IndicatorData { protected: - DrawIndicator* draw; TS iparams; - protected: - /* Protected methods */ - - bool Init() { return InitDraw(); } - - /** - * Initialize indicator data drawing on custom data. - */ - bool InitDraw() { - if (iparams.is_draw && !Object::IsValid(draw)) { - draw = new DrawIndicator(THIS_PTR); - draw.SetColorLine(iparams.indi_color); - } - return iparams.is_draw; - } - - /** - * Deinitialize drawing. - */ - void DeinitDraw() { - if (draw) { - delete draw; - } - } - public: /* Indicator enumerations */ @@ -149,18 +120,17 @@ class Indicator : public IndicatorData { iparams = _iparams; Init(); } - Indicator(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "") + Indicator(ENUM_INDICATOR_TYPE _itype, int _shift = 0, string _name = "") : IndicatorData(IndicatorDataParams::GetInstance()) { iparams.SetIndicatorType(_itype); iparams.SetShift(_shift); - iparams.SetTf(_tf); Init(); } /** * Class deconstructor. */ - ~Indicator() { DeinitDraw(); } + ~Indicator() {} /* Getters */ @@ -180,6 +150,46 @@ class Indicator : public IndicatorData { return istate.Get(_param); } + /** + * Returns the highest bar's index (shift). + */ + template + int GetHighest(int count = WHOLE_ARRAY, int start_bar = 0) { + int max_idx = -1; + double max = -DBL_MAX; + 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).GetMax(GetModeCount()); + if (value > max) { + max = value; + max_idx = shift; + } + } + + return max_idx; + } + + /** + * Returns the lowest bar's index (shift). + */ + template + int GetLowest(int count = WHOLE_ARRAY, int start_bar = 0) { + int min_idx = -1; + double min = DBL_MAX; + 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()); + if (value < min) { + min = value; + min_idx = shift; + } + } + + return min_idx; + } + /* Setters */ /** @@ -190,6 +200,15 @@ class Indicator : public IndicatorData { idparams.Set(_param, _value); } + /** + * 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); + } + /* Buffer methods */ virtual string CacheKey() { return GetFullName(); } @@ -309,116 +328,16 @@ class Indicator : public IndicatorData { } */ - /** - * Checks whether indicator have given mode index. - * - * If given mode is -1 (default one) and indicator has exactly one mode, then mode index will be replaced by 0. - */ - void ValidateDataSourceMode(int& _out_mode) { - if (_out_mode == -1) { - // First mode will be used by default, or, if selected indicator has more than one mode, error will happen. - if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)) != 1) { - Alert("Error: ", GetName(), " must have exactly one possible mode in order to skip using SetDataSourceMode()!"); - DebugBreak(); - } - _out_mode = 0; - } else if (_out_mode + 1 > Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) { - Alert("Error: ", GetName(), " have ", Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)), - " mode(s) buy you tried to reference mode with index ", _out_mode, - "! Ensure that you properly set mode via SetDataSourceMode()."); - DebugBreak(); - } - } - - /** - * Provides built-in indicators whose can be used as data source. - */ - virtual IndicatorBase* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } - - /** - * Returns currently selected data source doing validation. - */ - IndicatorData* GetDataSource() { - IndicatorData* _result = NULL; - - if (GetDataSourceRaw() != NULL) { - _result = GetDataSourceRaw(); - } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) { - int _source_id = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)); - - if (indicators.KeyExists(_source_id)) { - _result = indicators[_source_id].Ptr(); - } else { - Ref _source = FetchDataSource((ENUM_INDICATOR_TYPE)_source_id); - - if (!_source.IsSet()) { - Alert(GetName(), " has no built-in source indicator ", _source_id); - DebugBreak(); - } else { - indicators.Set(_source_id, _source); - - _result = _source.Ptr(); - } - } - } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_INDICATOR) { - // User sets data source's mode to On-Indicator, but not set data source via SetDataSource()! - - // Requesting potential data source. - IndicatorData* _ds = OnDataSourceRequest(); - - if (_ds != NULL) { - // Initializing with new data source. - SetDataSource(_ds); - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR); - } - } - - ValidateDataSource(&this, _result); - - return _result; - } - /** * Gets number of modes available to retrieve by GetValue(). */ - virtual int GetModeCount() { return 0; } - - /** - * Whether data source is selected. - */ - virtual bool HasDataSource(bool _try_initialize = false) { - if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) { - return true; - } - - if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_INDICATOR && - GetDataSourceRaw() == NULL && _try_initialize) { - SetDataSource(OnDataSourceRequest()); - } - - return GetDataSourceRaw() != NULL; - } + // int GetModeCount() override { return (int)iparams.max_modes; } /** * Gets indicator's params. */ IndicatorParams GetParams() { return iparams; } - /** - * Gets indicator's symbol. - */ - // string GetSymbol() { return Get(CHART_PARAM_SYMBOL); } - - /** - * Gets indicator's time-frame. - */ - // ENUM_TIMEFRAMES GetTf() { return Get(CHART_PARAM_TF); } - - /** - * Gets indicator's time-frame. - */ - ENUM_TIMEFRAMES GetTf() { return iparams.tf.GetTf(); } - /** * Gets indicator's signals. * @@ -433,7 +352,7 @@ class Indicator : public IndicatorData { return _signals; } // Returns signals. - IndicatorSignal _signals(_data, idparams, cparams, _mode1, _mode2); + IndicatorSignal _signals(_data, idparams, GetSymbol(), GetTf(), _mode1, _mode2); return _signals; } @@ -470,14 +389,6 @@ class Indicator : public IndicatorData { /* Setters */ - /** - * Sets an indicator's chart parameter value. - */ - template - void Set(ENUM_CHART_PARAM _param, T _value) { - Chart::Set(_param, _value); - } - /** * Sets name of the indicator. */ @@ -498,11 +409,6 @@ class Indicator : public IndicatorData { */ void SetParams(IndicatorParams& _iparams) { iparams = _iparams; } - /** - * Sets indicator's symbol. - */ - void SetSymbol(string _symbol) { Set(CHART_PARAM_SYMBOL, _symbol); } - /* Conditions */ /** @@ -615,52 +521,6 @@ class Indicator : public IndicatorData { return true; } - void OnTick() override { - Chart::OnTick(); - - if (iparams.is_draw) { - int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); - // Print("Drawing ", GetName(), iparams.indi_data != NULL ? (" (over " + iparams.indi_data.GetName() + ")") : ""); - for (int i = 0; i < _max_modes; ++i) - draw.DrawLineTo(GetName() + "_" + IntegerToString(i) + "_" + - Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)), - GetBarTime(0), GetEntry(0)[i], iparams.draw_window); - } - } - - /** - * Sets indicator data source. - */ - void SetDataSource(IndicatorData* _indi, int _input_mode = -1) override { - 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(), - ", 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(), - ", because source indicator isn't indexable by timestamp!"); - DebugBreak(); - return; - } - } - - if (indi_src.IsSet() && indi_src.Ptr() != _indi) { - indi_src.Ptr().RemoveListener(THIS_PTR); - } - indi_src = _indi; - if (_indi != NULL) { - indi_src.Ptr().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); - } - } - /* Data representation methods */ /* Virtual methods */ @@ -687,55 +547,34 @@ class Indicator : public IndicatorData { _result &= _entry.GetSize() > 0; if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_REAL)) { if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { + _result &= !_entry.HasValue(INT_MAX); // Empty value from indicator. _result &= !_entry.HasValue(DBL_MAX); - _result &= !_entry.HasValue(NULL); } else { _result &= !_entry.HasValue(FLT_MAX); - _result &= !_entry.HasValue(NULL); } } else { if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED)) { if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { _result &= !_entry.HasValue(ULONG_MAX); - _result &= !_entry.HasValue(NULL); } else { _result &= !_entry.HasValue(UINT_MAX); - _result &= !_entry.HasValue(NULL); } } else { if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { _result &= !_entry.HasValue(LONG_MAX); - _result &= !_entry.HasValue(NULL); } else { _result &= !_entry.HasValue(INT_MAX); - _result &= !_entry.HasValue(NULL); } } } return _result; } - /** - * Get full name of the indicator (with "over ..." part). - */ - string GetFullName() override { - return GetName() + "[" + Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)) + "]" + - (HasDataSource() ? (" (over " + GetDataSource().GetFullName() + ")") : ""); - } - /** * Get indicator type. */ ENUM_INDICATOR_TYPE GetType() override { return iparams.itype; } - /** - * Update indicator. - */ - virtual bool Update() { - // @todo - return false; - }; - /** * Returns the indicator's struct entry for the given shift. * @@ -744,15 +583,30 @@ class Indicator : public IndicatorData { * @return * Returns IndicatorDataEntry struct filled with indicator values. */ - IndicatorDataEntry GetEntry(int _index = -1) override { + IndicatorDataEntry GetEntry(long _index = -1) override { ResetLastError(); - int _ishift = _index >= 0 ? _index : iparams.GetShift(); - long _bar_time = GetBarTime(_ishift); + int _ishift = _index >= 0 ? (int)_index : iparams.GetShift(); + long _bar_time; + _bar_time = GetBarTime(_ishift); + + if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_BUILTIN && + (GetPossibleDataModes() & IDATA_BUILTIN) == 0) { + // Indicator is set to use built-in mode, but it doesn't support it. + if ((GetPossibleDataModes() & IDATA_ONCALCULATE) != 0) { + // Indicator supports OnCalculate() mode. + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_ONCALCULATE); + } else { + Print("Error: Indicator ", GetFullName(), + " does not support built-in mode and there is no other mode that it can use."); + DebugBreak(); + } + } + IndicatorDataEntry _entry = idata.GetByKey(_bar_time); if (_bar_time > 0 && !_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); _entry.Resize(_max_modes); - _entry.timestamp = _bar_time; + _entry.timestamp = GetBarTime(_ishift); #ifndef __MQL4__ if (IndicatorBase::Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED))) { // Resets the handle on any parameter changes. @@ -788,6 +642,13 @@ class Indicator : public IndicatorData { SetUserError(ERR_INVALID_PARAMETER); break; } + + if (_LastError != ERR_SUCCESS) { + datetime _bar_dt = (datetime)_bar_time; + Print("Error: Code ", _LastError, " while trying to retrieve entry at shift ", _ishift, ", mode ", _mode, + ", time ", _bar_dt); + DebugBreak(); + } } GetEntryAlter(_entry, _ishift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); @@ -812,7 +673,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 _timestamp = -1) { + virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _shift) { ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE)); _entry.AddFlags(_entry.GetDataTypeFlags(_dtype)); }; @@ -829,6 +690,21 @@ class Indicator : public IndicatorData { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); return GetEntry(_ishift)[_mode]; } + + /* Virtual methods */ + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + virtual unsigned int GetPossibleDataModes() { return 0; } + + /** + * Update indicator. + */ + virtual bool Update() { + // @todo + return false; + }; }; #endif diff --git a/Indicator.struct.h b/Indicator.struct.h index 83da13b7e..0961b0b38 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -44,7 +44,9 @@ struct ChartParams; #include "Data.struct.h" #include "DateTime.struct.h" #include "Indicator.enum.h" +#include "Indicator.struct.cache.h" #include "SerializerNode.enum.h" +#include "Storage/ValueStorage.indicator.h" /* Structure for indicator parameters. */ struct IndicatorParams { @@ -52,13 +54,11 @@ struct IndicatorParams { string name; // Name of the indicator. int shift; // Shift (relative to the current bar, 0 - default). unsigned int max_params; // Max supported input params. - ChartTf tf; // Chart's timeframe. ENUM_INDICATOR_TYPE itype; // Indicator type (e.g. INDI_RSI). color indi_color; // Indicator color. ARRAY(DataParamEntry, input_params); // Indicator input params. - bool is_draw; // Draw active. - int draw_window; // Drawing window. string custom_indi_name; // Name of the indicator passed to iCustom() method. + string symbol; // Symbol used by indicator. public: /* Special methods */ // Constructor. @@ -72,43 +72,17 @@ struct IndicatorParams { // idvrange(IDATA_RANGE_UNKNOWN), // indi_data_source_id(-1), // indi_data_source_mode(-1), - itype(_itype), - is_draw(false), - indi_color(clrNONE), - draw_window(0), - tf(_tf) { + itype(_itype) { Init(); }; - IndicatorParams(string _name) - : custom_indi_name(""), - name(_name), - shift(0), - // max_modes(1), - // max_buffers(10), - // idstype(_idstype), - // idvrange(IDATA_RANGE_UNKNOWN), - // indi_data_source_id(-1), - // indi_data_source_mode(-1), - is_draw(false), - indi_color(clrNONE), - draw_window(0) { - Init(); - }; - // Copy constructor. - IndicatorParams(IndicatorParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - THIS_REF = _params; - if (_tf != PERIOD_CURRENT) { - tf.SetTf(_tf); - } - } + IndicatorParams(string _name) : custom_indi_name(""), name(_name), shift(0) { Init(); }; void Init() {} /* Getters */ string GetCustomIndicatorName() const { return custom_indi_name; } - color GetIndicatorColor() const { return indi_color; } int GetMaxParams() const { return (int)max_params; } int GetShift() const { return shift; } + string GetSymbol() const { return symbol; } ENUM_INDICATOR_TYPE GetIndicatorType() { return itype; } - ENUM_TIMEFRAMES GetTf() const { return tf.GetTf(); } template T GetInputParam(int _index, T _default) const { DataParamEntry _param = input_params[_index]; @@ -136,16 +110,6 @@ struct IndicatorParams { } /* Setters */ void SetCustomIndicatorName(string _name) { custom_indi_name = _name; } - void SetDraw(bool _draw = true, int _window = 0) { - is_draw = _draw; - draw_window = _window; - } - void SetDraw(color _clr, int _window = 0) { - is_draw = true; - indi_color = _clr; - draw_window = _window; - } - void SetIndicatorColor(color _clr) { indi_color = _clr; } void SetIndicatorType(ENUM_INDICATOR_TYPE _itype) { itype = _itype; } void SetInputParams(ARRAY_REF(DataParamEntry, _params)) { int _asize = ArraySize(_params); @@ -160,7 +124,7 @@ struct IndicatorParams { } void SetName(string _name) { name = _name; }; void SetShift(int _shift) { shift = _shift; } - void SetTf(ENUM_TIMEFRAMES _tf) { tf.SetTf(_tf); } + void SetSymbol(string _symbol) { symbol = _symbol; } // Serializers. // SERIALIZER_EMPTY_STUB; // template <> diff --git a/Indicator.struct.serialize.h b/Indicator.struct.serialize.h index c97c69d9d..a3132c6a4 100644 --- a/Indicator.struct.serialize.h +++ b/Indicator.struct.serialize.h @@ -42,9 +42,9 @@ SerializerNodeType IndicatorParams::Serialize(Serializer &s) { // s.PassObject(this, "indicator", indi_data); // @todo // s.Pass(THIS_REF, "indi_data_ownership", indi_data_ownership); - s.Pass(THIS_REF, "indi_color", indi_color, SERIALIZER_FIELD_FLAG_HIDDEN); - s.Pass(THIS_REF, "is_draw", is_draw); - s.Pass(THIS_REF, "draw_window", draw_window, SERIALIZER_FIELD_FLAG_HIDDEN); + // s.Pass(THIS_REF, "indi_color", indi_color, SERIALIZER_FIELD_FLAG_HIDDEN); + // s.Pass(THIS_REF, "is_draw", is_draw); + // s.Pass(THIS_REF, "draw_window", draw_window, SERIALIZER_FIELD_FLAG_HIDDEN); s.Pass(THIS_REF, "custom_indi_name", custom_indi_name); return SerializerNodeObject; } diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index ee4e045c2..593da9406 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -33,6 +33,14 @@ #include "../Buffer/BufferCandle.h" #include "../Candle.struct.h" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.price_median.h" +#include "../Storage/ValueStorage.price_typical.h" +#include "../Storage/ValueStorage.price_weighted.h" +#include "../Storage/ValueStorage.spread.h" +#include "../Storage/ValueStorage.tick_volume.h" +#include "../Storage/ValueStorage.time.h" +#include "../Storage/ValueStorage.volume.h" +#include "TickBarCounter.h" // Indicator modes. enum ENUM_INDI_CANDLE_MODE { @@ -42,8 +50,13 @@ enum ENUM_INDI_CANDLE_MODE { INDI_CANDLE_MODE_PRICE_CLOSE, INDI_CANDLE_MODE_SPREAD, INDI_CANDLE_MODE_TICK_VOLUME, + INDI_CANDLE_MODE_TIME, INDI_CANDLE_MODE_VOLUME, FINAL_INDI_CANDLE_MODE_ENTRY, + // Following modes are dynamically calculated. + INDI_CANDLE_MODE_PRICE_MEDIAN, + INDI_CANDLE_MODE_PRICE_TYPICAL, + INDI_CANDLE_MODE_PRICE_WEIGHTED, }; /** @@ -53,6 +66,7 @@ template class IndicatorCandle : public Indicator { protected: BufferCandle icdata; + TickBarCounter counter; protected: /* Protected methods */ @@ -67,6 +81,7 @@ class IndicatorCandle : public Indicator { flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; icdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); icdata.SetOverflowListener(IndicatorCandleOverflowListener, 10); + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_INDI_CANDLE_MODE_ENTRY); } public: @@ -80,14 +95,130 @@ class IndicatorCandle : public Indicator { : Indicator(_icparams, _idparams, _indi_src, _indi_mode) { Init(); } - IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - string _name = "") - : Indicator(_itype, _tf, _shift, _name) { + IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") + : Indicator(_itype, _shift, _name) { Init(); } + /** + * 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_TICK | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /* Getters */ + + /** + * Gets open price for a given, optional shift. + */ + double GetOpen(int _shift = 0) override { return GetOHLC(_shift).open; } + + /** + * Gets high price for a given, optional shift. + */ + double GetHigh(int _shift = 0) override { return GetOHLC(_shift).high; } + + /** + * Gets low price for a given, optional shift. + */ + double GetLow(int _shift = 0) override { return GetOHLC(_shift).low; } + + /** + * Gets close price for a given, optional shift. + */ + double GetClose(int _shift = 0) override { return GetOHLC(_shift).close; } + + /** + * Returns the current price value given applied price type, symbol and timeframe. + */ + double GetPrice(ENUM_APPLIED_PRICE _ap, int _shift = 0) override { return GetOHLC(_shift).GetAppliedPrice(_ap); } + + /** + * Returns current bar index (incremented every OnTick() if IsNewBar() is true). + */ + int GetBarIndex() override { return counter.GetBarIndex(); } + + /** + * Returns the number of bars on the chart. + */ + int GetBars() override { return (int)icdata.Size(); } + + /** + * Returns current tick index (incremented every OnTick()). + */ + int GetTickIndex() override { return counter.GetTickIndex(); } + + /** + * Check if there is a new bar to parse. + */ + bool IsNewBar() override { return counter.is_new_bar; } + /* Virtual method implementations */ + /** + * Traverses source indicators' hierarchy and tries to find OHLC-featured + * indicator. IndicatorCandle satisfies such requirements. + */ + IndicatorData* GetCandle(bool _warn_if_not_found = true, IndicatorData* _originator = nullptr) override { + // We are the candle indicator! + return THIS_PTR; + } + + /** + * Gets OHLC price values. + */ + BarOHLC GetOHLC(int _shift = 0) override { + datetime _bar_time = GetBarTime(_shift); + BarOHLC _ohlc; + + if ((long)_bar_time != 0) { + CandleOCTOHLC candle = icdata.GetByKey((long)_bar_time); + _ohlc.open = (float)candle.open; + _ohlc.high = (float)candle.high; + _ohlc.low = (float)candle.low; + _ohlc.close = (float)candle.close; + _ohlc.time = _bar_time; + } + +#ifdef __debug_verbose__ + Print("Fetching OHLC #", _shift, " from ", TimeToString(_ohlc.time, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); + Print("^- ", _ohlc.open, ", ", _ohlc.high, ", ", _ohlc.low, ", ", _ohlc.close); +#endif + + return _ohlc; + } + + /** + * Returns volume value for the bar. + * + * If local history is empty (not loaded), function returns 0. + */ + long GetVolume(int _shift = 0) override { + datetime _bar_time = GetBarTime(_shift); + + if ((long)_bar_time == 0) { + return 0; + } + + CandleOCTOHLC candle = icdata.GetByKey((long)_bar_time); + return candle.volume; + } + + /** + * Returns spread for the bar. + * + * If local history is empty (not loaded), function returns 0. + */ + long GetSpread(int _shift = 0) override { return 0; } + + /** + * Returns tick volume value for the bar. + * + * If local history is empty (not loaded), function returns 0. + */ + long GetTickVolume(int _shift = 0) override { return GetVolume(); } + /** * Returns the indicator's data entry. * @@ -96,40 +227,65 @@ class IndicatorCandle : public Indicator { * @return * Returns IndicatorDataEntry struct filled with indicator values. */ - IndicatorDataEntry GetEntry(int _index = -1) override { + IndicatorDataEntry GetEntry(long _index = -1) override { ResetLastError(); - unsigned int _ishift = _index >= 0 ? _index : iparams.GetShift(); - long _candle_time = CalcCandleTimestamp(GetBarTime(_ishift)); - long _curr_candle_time; + int _ishift = _index >= 0 ? (int)_index : iparams.GetShift(); + long _candle_time = GetBarTime(_ishift); CandleOCTOHLC _candle; + _candle = icdata.GetByKey(_candle_time); - // Trying current and older shifts. - if (icdata.Size() > 0) { - int i = 0; - while (true) { - _curr_candle_time = CalcCandleTimestamp(GetBarTime(i++)); + if (!_candle.IsValid()) { + // No candle found. + DebugBreak(); + Print(GetFullName(), ": Missing candle at shift ", _index, " (", + TimeToString(_candle_time, TIME_DATE | TIME_MINUTES | TIME_SECONDS), "). Lowest timestamp in history is ", + icdata.GetMin()); + } - if (_curr_candle_time < icdata.GetMin()) { - // There is no older entries. - break; - } + return CandleToEntry(_candle_time, _candle); + } - _candle = icdata.GetByKey(_curr_candle_time); + /** + * Returns value storage for a given mode. + */ + IValueStorage* GetValueStorage(int _mode = 0) override { + if (_mode >= ArraySize(value_storages)) { + ArrayResize(value_storages, _mode + 1); + } - if (_candle.IsValid()) { + if (!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); + 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); + break; + case INDI_CANDLE_MODE_TIME: + value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + break; + case INDI_CANDLE_MODE_PRICE_MEDIAN: + value_storages[_mode] = new PriceMedianValueStorage(THIS_PTR); break; - } + case INDI_CANDLE_MODE_PRICE_TYPICAL: + value_storages[_mode] = new PriceTypicalValueStorage(THIS_PTR); + break; + case INDI_CANDLE_MODE_PRICE_WEIGHTED: + value_storages[_mode] = new PriceWeightedValueStorage(THIS_PTR); + break; + default: + Print("ERROR: Unsupported value storage mode ", _mode); + DebugBreak(); } } - if (!_candle.IsValid()) { - // Giving up. - DebugBreak(); - Print(GetFullName(), ": Missing candle after thorough search at shift ", _index, " (", TimeToString(_candle_time), - "). Lowest timestamp in history is ", icdata.GetMin()); - } - - return CandleToEntry(_candle_time, _candle); + return value_storages[_mode].Ptr(); } /** @@ -162,12 +318,23 @@ class IndicatorCandle : public Indicator { * Converts candle into indicator's data entry. */ IndicatorDataEntry CandleToEntry(long _timestamp, CandleOCTOHLC& _candle) { - IndicatorDataEntry _entry(4); + IndicatorDataEntry _entry(FINAL_INDI_CANDLE_MODE_ENTRY); _entry.timestamp = _timestamp; - _entry.values[0] = _candle.open; - _entry.values[1] = _candle.high; - _entry.values[2] = _candle.low; - _entry.values[3] = _candle.close; + _entry.values[INDI_CANDLE_MODE_PRICE_OPEN] = _candle.open; + _entry.values[INDI_CANDLE_MODE_PRICE_HIGH] = _candle.high; + _entry.values[INDI_CANDLE_MODE_PRICE_LOW] = _candle.low; + _entry.values[INDI_CANDLE_MODE_PRICE_CLOSE] = _candle.close; + _entry.values[INDI_CANDLE_MODE_SPREAD] = 0.1; // @todo + _entry.values[INDI_CANDLE_MODE_TICK_VOLUME] = _candle.volume; + _entry.values[INDI_CANDLE_MODE_TIME] = _timestamp; + _entry.values[INDI_CANDLE_MODE_VOLUME] = _candle.volume; + + // @todo We may consider adding these three buffers directly. + // BarOHLC _ohlc(_candle.open, _candle.high, _candle.low, _candle.close); + // _entry.values[INDI_CANDLE_MODE_PRICE_MEDIAN] = _ohlc.GetMedian(); + // _entry.values[INDI_CANDLE_MODE_PRICE_TYPICAL] = _ohlc.GetTypical(); + // _entry.values[INDI_CANDLE_MODE_PRICE_WEIGHTED] = _ohlc.GetWeighted(); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, _candle.IsValid()); return _entry; } @@ -179,15 +346,25 @@ class IndicatorCandle : public Indicator { long _candle_timestamp = CalcCandleTimestamp(_tick_timestamp); #ifdef __debug_verbose__ - Print("Updating candle for ", GetFullName(), " at candle ", TimeToString(_candle_timestamp), " from tick at ", - TimeToString(_tick_timestamp)); + Print("Updating candle for ", GetFullName(), " at candle ", + TimeToString(_candle_timestamp, TIME_DATE | TIME_MINUTES | TIME_SECONDS), " from tick at ", + TimeToString(_tick_timestamp, TIME_DATE | TIME_MINUTES | TIME_SECONDS), ": ", _price); #endif CandleOCTOHLC _candle(_price, _price, _price, _price, _tick_timestamp, _tick_timestamp); if (icdata.KeyExists(_candle_timestamp)) { // Candle already exists. _candle = icdata.GetByKey(_candle_timestamp); + +#ifdef __debug_verbose__ + Print("Candle was ", _candle.ToCSV()); +#endif + _candle.Update(_tick_timestamp, _price); + +#ifdef __debug_verbose__ + Print("Candle is ", _candle.ToCSV()); +#endif } icdata.Add(_candle, _candle_timestamp); @@ -206,6 +383,9 @@ class IndicatorCandle : public Indicator { void OnDataSourceEntry(IndicatorDataEntry& entry) override { // Updating candle from bid price. UpdateCandle(entry.timestamp, entry[1]); + + // Updating tick & bar indices. + counter.OnTick(CalcCandleTimestamp(entry.timestamp)); }; /** @@ -221,10 +401,18 @@ class IndicatorCandle : public Indicator { return GetValueStorage(INDI_CANDLE_MODE_PRICE_LOW); case INDI_VS_TYPE_PRICE_CLOSE: return GetValueStorage(INDI_CANDLE_MODE_PRICE_CLOSE); + case INDI_VS_TYPE_PRICE_MEDIAN: + return GetValueStorage(INDI_CANDLE_MODE_PRICE_MEDIAN); + case INDI_VS_TYPE_PRICE_TYPICAL: + return GetValueStorage(INDI_CANDLE_MODE_PRICE_TYPICAL); + case INDI_VS_TYPE_PRICE_WEIGHTED: + return GetValueStorage(INDI_CANDLE_MODE_PRICE_WEIGHTED); case INDI_VS_TYPE_SPREAD: return GetValueStorage(INDI_CANDLE_MODE_SPREAD); case INDI_VS_TYPE_TICK_VOLUME: return GetValueStorage(INDI_CANDLE_MODE_TICK_VOLUME); + case INDI_VS_TYPE_TIME: + return GetValueStorage(INDI_CANDLE_MODE_TIME); case INDI_VS_TYPE_VOLUME: return GetValueStorage(INDI_CANDLE_MODE_VOLUME); default: @@ -236,14 +424,18 @@ class IndicatorCandle : public Indicator { /** * Checks whether indicator support given value storage type. */ - bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { + bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { switch (_type) { case INDI_VS_TYPE_PRICE_OPEN: case INDI_VS_TYPE_PRICE_HIGH: case INDI_VS_TYPE_PRICE_LOW: case INDI_VS_TYPE_PRICE_CLOSE: + case INDI_VS_TYPE_PRICE_MEDIAN: + case INDI_VS_TYPE_PRICE_TYPICAL: + case INDI_VS_TYPE_PRICE_WEIGHTED: case INDI_VS_TYPE_SPREAD: case INDI_VS_TYPE_TICK_VOLUME: + case INDI_VS_TYPE_TIME: case INDI_VS_TYPE_VOLUME: return true; default: diff --git a/Indicator/IndicatorCandleSource.h b/Indicator/IndicatorCandleSource.h deleted file mode 100644 index 084c0d1d4..000000000 --- a/Indicator/IndicatorCandleSource.h +++ /dev/null @@ -1,108 +0,0 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, 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 "../Indicator.mqh" -#include "tests/classes/IndicatorTfDummy.h" -#include "tests/classes/IndicatorTickReal.h" - -/** - * Indicator to be used with IndicatorCandle as a data source. - */ -template -class IndicatorCandleSource : public Indicator { - public: - /** - * Class constructor. - */ - IndicatorCandleSource(const TS& _iparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_iparams, _indi_src, _indi_mode) {} - IndicatorCandleSource(const TS& _iparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(_iparams, _tf) {} - IndicatorCandleSource(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - string _name = "") - : Indicator(_itype, _tf, _shift, _name) {} - - /** - * Class deconstructor. - */ - ~IndicatorCandleSource() {} - - /** - * Sets indicator data source. - */ - void SetDataSource(IndicatorBase* _indi, int _input_mode = -1) override { - if (_indi == NULL) { - // Just deselecting data source. - Indicator::SetDataSource(_indi, _input_mode); - return; - } - - // We can only use data sources which supports all possible modes from IndicatorCandle. - bool _result = true; - - _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); - _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); - _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); - _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); - _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_SPREAD); - _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME); - _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_VOLUME); - - if (!_result) { - Alert("Passed indicator ", _indi.GetFullName(), " does not define all required specific data storages!"); - DebugBreak(); - } - - Indicator::SetDataSource(_indi, _input_mode); - } - - /** - * Called when user tries to set given data source. Could be used to check if indicator implements all required value - * storages. - */ - bool OnValidateDataSource(IndicatorBase* _ds, string& _reason) override { - // @todo Make use of this method. - return true; - } - - /** - * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on - * some data source. - */ - IndicatorBase* OnDataSourceRequest() override { - // Defaulting to real platform ticks. - IndicatorBase* _indi_tick = - new IndicatorTickReal(GetSymbol(), GetTf(), "Ticker for Tf on IndicatorCandleSource-based indicator"); - - // Tf will work on real platform ticks. - IndicatorBase* _indi_tf = new IndicatorTfDummy(GetTf()); - _indi_tf.SetDataSource(_indi_tick); - - // Indicator will work on Tf, which will receive real platform ticks. - return _indi_tf; - } -}; diff --git a/Indicator/IndicatorTf.struct.h b/Indicator/IndicatorTf.struct.h index 727766bbf..d6e3e55b5 100644 --- a/Indicator/IndicatorTf.struct.h +++ b/Indicator/IndicatorTf.struct.h @@ -35,6 +35,7 @@ /* Structure for IndicatorTf class parameters. */ struct IndicatorTfParams : IndicatorParams { + ChartTf tf; unsigned int spc; // Seconds per candle. // Struct constructor. IndicatorTfParams(unsigned int _spc = 60) : spc(_spc) {} diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 3026e289b..80f3b1080 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -32,6 +32,7 @@ // Includes. #include "../Buffer/BufferTick.h" #include "../Indicator.mqh" +#include "../Indicator.struct.h" // Indicator modes. enum ENUM_INDI_TICK_MODE { @@ -48,6 +49,8 @@ class IndicatorTick : public Indicator { protected: BufferTick itdata; TS itparams; + string symbol; + SymbolInfoProp symbol_props; protected: /* Protected methods */ @@ -75,21 +78,49 @@ class IndicatorTick : public Indicator { /** * Class constructor. */ - IndicatorTick(const TS& _itparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, - int _indi_mode = 0) + IndicatorTick(string _symbol, const TS& _itparams, const IndicatorDataParams& _idparams, + IndicatorBase* _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); } + symbol = _symbol; Init(); } - IndicatorTick(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - string _name = "") - : Indicator(_itype, _tf, _shift, _name) { + IndicatorTick(string _symbol, ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") + : Indicator(_itype, _shift, _name) { + symbol = _symbol; Init(); } + /** + * 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 time of the bar for a given shift. + */ + datetime GetBarTime(int _shift = 0) override { + if (_shift != 0) { + Print("Error: IndicatorTick::GetBarTime() does not yet support getting entries by shift other than 0!"); + DebugBreak(); + } + + return (datetime)itdata.GetMax(); + } + + /** + * Gets ask price for a given date and time. Return current ask price if _dt wasn't passed or is 0. + */ + virtual double GetAsk(datetime _dt = 0) { return GetEntry(_dt).GetValue(INDI_TICK_MODE_PRICE_ASK); } + + /** + * Gets bid price for a given date and time. Return current bid price if _dt wasn't passed or is 0. + */ + virtual double GetBid(datetime _dt = 0) { return GetEntry(_dt).GetValue(INDI_TICK_MODE_PRICE_BID); } + /** * Returns value storage of given kind. */ @@ -99,6 +130,12 @@ class IndicatorTick : public Indicator { return (IValueStorage*)itdata.GetAskValueStorage(); case INDI_VS_TYPE_PRICE_BID: return (IValueStorage*)itdata.GetBidValueStorage(); + case INDI_VS_TYPE_SPREAD: + return (IValueStorage*)itdata.GetSpreadValueStorage(); + case INDI_VS_TYPE_VOLUME: + return (IValueStorage*)itdata.GetVolumeValueStorage(); + case INDI_VS_TYPE_TICK_VOLUME: + return (IValueStorage*)itdata.GetTickVolumeValueStorage(); default: // Trying in parent class. return Indicator::GetSpecificValueStorage(_type); @@ -112,6 +149,9 @@ class IndicatorTick : public Indicator { switch (_type) { case INDI_VS_TYPE_PRICE_ASK: case INDI_VS_TYPE_PRICE_BID: + case INDI_VS_TYPE_SPREAD: + case INDI_VS_TYPE_VOLUME: + case INDI_VS_TYPE_TICK_VOLUME: return true; } @@ -128,18 +168,33 @@ class IndicatorTick : public Indicator { } } + /** + * Stores entry in the buffer for later rerieval. + */ + void StoreEntry(IndicatorDataEntry& _entry) override { itdata.Add(EntryToTick(_entry), _entry.timestamp); } + /** * @todo */ IndicatorDataEntry TickToEntry(long _timestamp, TickAB& _tick) { IndicatorDataEntry _entry(2); _entry.timestamp = _timestamp; - _entry.values[0] = _tick.ask; - _entry.values[1] = _tick.bid; - _entry.SetFlags(INDI_ENTRY_FLAG_IS_VALID); + _entry.values[INDI_TICK_MODE_PRICE_ASK] = _tick.ask; + _entry.values[INDI_TICK_MODE_PRICE_BID] = _tick.bid; + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, _tick.ask != 0 && _tick.bid != 0); return _entry; } + /** + * @todo + */ + TickAB EntryToTick(IndicatorDataEntry& _entry) { + TickAB _tick; + _tick.ask = _entry.GetValue(INDI_TICK_MODE_PRICE_ASK); + _tick.bid = _entry.GetValue(INDI_TICK_MODE_PRICE_BID); + return _tick; + } + /** * Returns the indicator's data entry. * @@ -148,8 +203,16 @@ class IndicatorTick : public Indicator { * @return * Returns IndicatorDataEntry struct filled with indicator values. */ - IndicatorDataEntry GetEntry(int _timestamp = 0) override { + IndicatorDataEntry GetEntry(long _dt = 0) override { ResetLastError(); + long _timestamp; + + if ((long)_dt != 0) { + _timestamp = (long)_dt; + } else { + _timestamp = itdata.GetMax(); + } + if (itdata.KeyExists(_timestamp)) { TickAB _tick = itdata.GetByKey(_timestamp); return TickToEntry(_timestamp, _tick); @@ -158,7 +221,7 @@ class IndicatorTick : public Indicator { // No tick at given timestamp. Returning invalid entry. IndicatorDataEntry _entry(_max_modes); - GetEntryAlter(_entry, _timestamp); + GetEntryAlter(_entry, (datetime)_entry.timestamp); for (int i = 0; i < _max_modes; ++i) { _entry.values[i] = (double)0; @@ -174,7 +237,7 @@ class IndicatorTick : public Indicator { * 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 _timestamp = -1) { + virtual void GetEntryAlter(IndicatorDataEntry& _entry, datetime _time) { ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE)); _entry.AddFlags(_entry.GetDataTypeFlags(_dtype)); }; @@ -187,11 +250,50 @@ class IndicatorTick : public Indicator { * @return * Returns DataParamEntry struct filled with a single value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) override { + if (_shift != 0) { + Print("Error: IndicatorTick does not yet support getting entries by shift other than 0!"); + DebugBreak(); + IndicatorDataEntryValue _default; + return _default; + } + int _ishift = _shift >= 0 ? _shift : itparams.GetShift(); - return GetEntry(_ishift)[_mode]; + // @todo Support for shift. + return GetEntry((datetime)0)[_mode]; + } + + /** + * Gets symbol of the tick. + */ + string GetSymbol() override { return symbol; } + + /** + * Gets symbol info for active symbol. + */ + SymbolInfoProp GetSymbolProps() override { + if (!symbol_props.initialized) { + Print( + "Error: Tried to fetch symbol properties, but they're not yet initialized! Please call " + "SetSymbolProps(SymbolInfoProp) before trying to use symbol-related information."); + DebugBreak(); + } + return symbol_props; } + /** + * Sets symbol info for symbol attached to the indicator. + */ + void SetSymbolProps(const SymbolInfoProp& _props) override { + symbol_props = _props; + symbol_props.initialized = true; + } + + /** + * Traverses source indicators' hierarchy and tries to find IndicatorTick object at the end. + */ + virtual IndicatorTick* GetTickIndicator() { return THIS_PTR; } + /* Setters */ /** @@ -204,15 +306,6 @@ class IndicatorTick : public Indicator { itdata.Add(_tick, _timestamp); } - /** - * Sets indicator data source. - */ - void SetDataSource(IndicatorBase* _indi, int _input_mode = -1) { - indi_src = _indi; - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID), -1); - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE), _input_mode); - } - /* Virtual methods */ /** @@ -224,7 +317,7 @@ class IndicatorTick : public Indicator { * Returns MqlTick struct with prices of the symbol. */ virtual MqlTick GetTick(int _timestamp = 0) { - IndicatorDataEntry _entry = GetEntry(_timestamp); + IndicatorDataEntry _entry = GetEntry((datetime)_timestamp); MqlTick _tick; _tick.time = (datetime)_entry.GetTime(); _tick.bid = _entry[0]; @@ -232,46 +325,6 @@ class IndicatorTick : public Indicator { return _tick; } - /** - * Checks if indicator entry is valid. - * - * @return - * Returns true if entry is valid (has valid values), otherwise false. - */ - virtual bool IsValidEntry(IndicatorDataEntry& _entry) { - bool _result = true; - _result &= _entry.timestamp > 0; - _result &= _entry.GetSize() > 0; - if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_REAL)) { - if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { - _result &= !_entry.HasValue(DBL_MAX); - _result &= !_entry.HasValue(NULL); - } else { - _result &= !_entry.HasValue(FLT_MAX); - _result &= !_entry.HasValue(NULL); - } - } else { - if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED)) { - if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { - _result &= !_entry.HasValue(ULONG_MAX); - _result &= !_entry.HasValue(NULL); - } else { - _result &= !_entry.HasValue(UINT_MAX); - _result &= !_entry.HasValue(NULL); - } - } else { - if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { - _result &= !_entry.HasValue(LONG_MAX); - _result &= !_entry.HasValue(NULL); - } else { - _result &= !_entry.HasValue(INT_MAX); - _result &= !_entry.HasValue(NULL); - } - } - } - return _result; - } - /* Callback methods */ /** diff --git a/Indicator/IndicatorTickOrCandleSource.h b/Indicator/IndicatorTickOrCandleSource.h deleted file mode 100644 index defe2c019..000000000 --- a/Indicator/IndicatorTickOrCandleSource.h +++ /dev/null @@ -1,102 +0,0 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, 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 "../Indicator.mqh" -#include "tests/classes/IndicatorTfDummy.h" -#include "tests/classes/IndicatorTickReal.h" - -/** - * Indicator to be used with IndicatorTick or IndicatorCandle as a data source. - * - * In order it to work with - */ -template -class IndicatorTickOrCandleSource : public Indicator { - public: - /** - * Class constructor. - */ - IndicatorTickOrCandleSource(const TS& _iparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, - int _indi_mode = 0) - : Indicator(_iparams, _idparams, _indi_src, _indi_mode) {} - IndicatorTickOrCandleSource(const TS& _iparams, const IndicatorDataParams& _idparams, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) - : Indicator(_iparams, _idparams, _tf) {} - IndicatorTickOrCandleSource(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - string _name = "") - : Indicator(_itype, _tf, _shift, _name) {} - - /** - * Class deconstructor. - */ - ~IndicatorTickOrCandleSource() {} - - /** - * Called when user tries to set given data source. Could be used to check if indicator implements all required value - * storages. - */ - bool OnValidateDataSource(IndicatorData* _ds, string& _reason) override { - // @todo Make use of this method. - return true; - } - - /** - * Called when data source emits new entry (historic or future one). - */ - void OnDataSourceEntry(IndicatorDataEntry& entry) override{ - // We do nothing. - }; - - /** - * Creates default, tick based indicator for given applied price. - */ - IndicatorData* DataSourceRequestReturnDefault(int _applied_price) override { - // Returning real candle indicator. Thus way we can use SetAppliedPrice() and select Ask or Bid price. - IndicatorData* _indi; - - switch (_applied_price) { - case PRICE_ASK: - case PRICE_BID: - case PRICE_OPEN: - case PRICE_HIGH: - case PRICE_LOW: - case PRICE_CLOSE: - case PRICE_MEDIAN: - case PRICE_TYPICAL: - case PRICE_WEIGHTED: - // @todo ASK/BID should return Tick indicator. Other APs should return Candle-over-Tick indicator. - _indi = new IndicatorTfDummy(GetTf()); - _indi.SetDataSource(new IndicatorTickReal(GetTf())); - return _indi; - } - - Print("Passed wrong value for applied price for ", GetFullName(), " indicator!"); - DebugBreak(); - return NULL; - } -}; diff --git a/Indicator/TickBarCounter.h b/Indicator/TickBarCounter.h new file mode 100644 index 000000000..47d227631 --- /dev/null +++ b/Indicator/TickBarCounter.h @@ -0,0 +1,114 @@ +//+------------------------------------------------------------------+ +//| 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 . + * + */ + +// Ignore processing of this file if already included. +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +/** + * Tick & bar counter for IndicatorCandle/IndicatorTf. + */ +struct TickBarCounter { + // Time of the last bar. + datetime last_bar_time; + + // Index of the current bar. + int bar_index; + + // Whether new bar happened in the current tick. + bool is_new_bar; + + // Index of the current tick. + int tick_index; + + /** + * Increases current bar index (used in OnTick()). If there was no bar, the current bar will become 0. + */ + void IncreaseBarIndex() { SetBarIndex(bar_index == -1 ? 0 : bar_index + 1); } + + /** + * Increases current tick index (used in OnTick()). If there was no tick, the current tick will become 0. + */ + void IncreaseTickIndex() { SetTickIndex(tick_index == -1 ? 0 : tick_index + 1); } + + /* Getters */ + + /** + * Returns current bar index (incremented every OnTick() if IsNewBar() is true). + */ + int GetBarIndex() { return bar_index; } + + /** + * Returns current tick index (incremented every OnTick()). + */ + int GetTickIndex() { return tick_index; } + + /** + * Check if there is a new bar to parse. + */ + bool IsNewBarInternal(datetime _bar_time) { + bool _result = false; + if (last_bar_time != _bar_time) { + SetLastBarTime(_bar_time); + _result = true; + } + return _result; + } + + /* Setters */ + + /** + * Sets current bar index. + */ + void SetBarIndex(int _bar_index) { bar_index = _bar_index; } + + /** + * Sets last bar time. + */ + void SetLastBarTime(datetime _dt) { last_bar_time = _dt; } + + /** + * Sets current tick index. + */ + void SetTickIndex(int _tick_index) { tick_index = _tick_index; } + + /** + * Updates tick & bar indices. + */ + void OnTick(datetime _bar_time) { + IncreaseTickIndex(); + + if (is_new_bar) { + // IsNewBar() will no longer signal new bar. + is_new_bar = false; + } + + if (IsNewBarInternal(_bar_time)) { + IncreaseBarIndex(); + is_new_bar = true; + } else { + is_new_bar = false; + } + } +}; diff --git a/Indicator/tests/IndicatorTf.test.mq5 b/Indicator/tests/IndicatorTf.test.mq5 index 3bc42ca32..f3db2878e 100644 --- a/Indicator/tests/IndicatorTf.test.mq5 +++ b/Indicator/tests/IndicatorTf.test.mq5 @@ -28,33 +28,37 @@ // Includes. #include "../../Indicators/Indi_AMA.mqh" +#include "../../Indicators/Tick/Indi_TickMt.mqh" +#include "../../Platform.h" #include "../../Test.mqh" #include "../../Util.h" #include "../IndicatorTf.h" #include "../IndicatorTick.h" #include "classes/IndicatorTfDummy.h" -#include "classes/IndicatorTickReal.h" #include "classes/Indicators.h" -Indicators indicators; -Ref indi_tick; +Ref indi_tick; Ref indi_tf; -Ref indi_tf_orig_sim; +Ref indi_tf_real; Ref indi_ama; Ref indi_ama_orig; Ref indi_ama_orig_sim; +Ref indi_ama_oncalculate; +Ref indi_ama_custom; /** * Implements OnInit(). */ int OnInit() { - indicators.Add(indi_tick = new IndicatorTickReal(PERIOD_CURRENT)); + Platform::Init(); + // Platform ticks. + indi_tick = Platform::FetchDefaultTickIndicator(); // 1-second candles. // indicators.Add(indi_tf = new IndicatorTfDummy(1)); // 1:1 candles from platform using current timeframe. - indicators.Add(indi_tf_orig_sim = new IndicatorTfDummy(ChartTf::TfToSeconds(PERIOD_CURRENT))); + indi_tf_real = Platform::FetchDefaultCandleIndicator(); // 1-second candles. // indicators.Add(indi_ama = new Indi_AMA()); @@ -63,24 +67,35 @@ int OnInit() { _ama_params.applied_price = PRICE_OPEN; // AMA on platform candles. - indicators.Add(indi_ama_orig_sim = new Indi_AMA(_ama_params)); + Platform::Add(indi_ama_orig_sim = new Indi_AMA(_ama_params)); - // Original built-in or OnCalculate()-based AMA indicator on platform OHLCs. - indicators.Add(indi_ama_orig = new Indi_AMA(_ama_params)); + // Original built-in AMA indicator on platform OHLCs. + Platform::Add(indi_ama_orig = new Indi_AMA(_ama_params, IDATA_BUILTIN)); + indi_ama_orig.Ptr().SetDataSource(indi_tf_real.Ptr()); + + // OnCalculate()-based version of AMA indicator on platform OHLCs. + Platform::Add(indi_ama_oncalculate = new Indi_AMA(_ama_params, IDATA_ONCALCULATE)); + indi_ama_oncalculate.Ptr().SetDataSource(indi_tf_real.Ptr()); + + // iCustom()-based version of AMA indicator on platform OHLCs. + Platform::Add(indi_ama_custom = new Indi_AMA(_ama_params, IDATA_ICUSTOM)); + indi_ama_custom.Ptr().SetDataSource(indi_tf_real.Ptr()); // Candles will be initialized from tick's history. - // indi_tf.Ptr().SetDataSource(indi_tick.Ptr()); - indi_tf_orig_sim.Ptr().SetDataSource(indi_tick.Ptr()); + // indi_tf.Ptr().SetDataSource(indi_tick.Ptr()); // @fixme: Invalid pointer access. + // indi_tf_real.Ptr().SetDataSource(indi_tick.Ptr()); // @fixme: Invalid pointer access. // AMA will work on the candle indicator. - // indi_ama.Ptr().SetDataSource(indi_tf.Ptr()); + // indi_ama.Ptr().SetDataSource(indi_tf.Ptr()); // @fixme: Invalid pointer access. // AMA will work on the simulation of real candles. - indi_ama_orig_sim.Ptr().SetDataSource(indi_tf_orig_sim.Ptr()); + // indi_ama_orig_sim.Ptr().SetDataSource(indi_tf_real.Ptr()); // @fixme: Invalid pointer access. // Checking if there are candles for last 100 ticks. - // Print(indi_tf.Ptr().GetName(), "'s historic candles (from 100 ticks):"); - // Print(indi_tf.Ptr().CandlesToString()); +#ifdef __debug__ + Print(indi_tf.Ptr().GetName(), "'s historic candles (from 100 ticks):"); + Print(indi_tf.Ptr().CandlesToString()); +#endif return (INIT_SUCCEEDED); } @@ -88,18 +103,32 @@ int OnInit() { * Implements OnTick(). */ void OnTick() { + Platform::Tick(); + +#ifdef __debug__ + if (indi_tf_real.Ptr().IsNewBar()) { + Print("New bar: ", indi_tf_real.Ptr().GetBarIndex()); + } + string o = DoubleToStr(iOpen(_Symbol, PERIOD_CURRENT, 0), 5); string h = DoubleToStr(iHigh(_Symbol, PERIOD_CURRENT, 0), 5); string l = DoubleToStr(iLow(_Symbol, PERIOD_CURRENT, 0), 5); string c = DoubleToStr(iClose(_Symbol, PERIOD_CURRENT, 0), 5); - string time = TimeToString(iTime(_Symbol, PERIOD_CURRENT, 0)); + string time = TimeToString(iTime(_Symbol, PERIOD_CURRENT, 0), TIME_DATE | TIME_MINUTES | TIME_SECONDS); + + Util::Print("Tick: " + IntegerToString((long)iTime(indi_tf_real.Ptr().GetSymbol(), indi_tf_real.Ptr().GetTf(), 0)) + + " (" + time + "), real = " + o + ", " + h + ", " + l + ", " + c); - Util::Print("Tick: " + IntegerToString((long)iTime(_Symbol, PERIOD_CURRENT, 0)) + " (" + time + "), real = " + o + - ", " + h + ", " + l + ", " + c); + string c_o = DoubleToStr(indi_tf_real.Ptr().GetOpen(0), 5); + string c_h = DoubleToStr(indi_tf_real.Ptr().GetHigh(0), 5); + string c_l = DoubleToStr(indi_tf_real.Ptr().GetLow(0), 5); + string c_c = DoubleToStr(indi_tf_real.Ptr().GetClose(0), 5); - indicators.Tick(); + Util::Print("Tick: " + IntegerToString(indi_tf_real.Ptr().GetBarTime(0)) + " (" + time + "), candle = " + c_o + ", " + + c_h + ", " + c_l + ", " + c_c); - Util::Print(indicators.ToString(0)); + Util::Print(Platform::IndicatorsToString(0)); +#endif } /** @@ -107,6 +136,6 @@ void OnTick() { */ void OnDeinit(const int reason) { // Printing all grouped candles. - Print(indi_tf_orig_sim.Ptr().GetName(), "'s all candles:"); - Print(indi_tf_orig_sim.Ptr().CandlesToString()); + Print(indi_tf_real.Ptr().GetName(), "'s all candles:"); + Print(indi_tf_real.Ptr().CandlesToString()); } diff --git a/Indicator/tests/IndicatorTick.test.mq5 b/Indicator/tests/IndicatorTick.test.mq5 index 00845ae9f..9cca139b8 100644 --- a/Indicator/tests/IndicatorTick.test.mq5 +++ b/Indicator/tests/IndicatorTick.test.mq5 @@ -32,7 +32,7 @@ * Implements OnInit(). */ int OnInit() { - IndicatorTickDummy _indi_tick(PERIOD_CURRENT); + IndicatorTickDummy _indi_tick(_Symbol); long _time = 1; for (double _price = 0.1; _price <= 2.0; _price += 0.1) { MqlTick _tick; diff --git a/Indicator/tests/classes/IndicatorTickDummy.h b/Indicator/tests/classes/IndicatorTickDummy.h index b6c75949b..eeeebb8f3 100644 --- a/Indicator/tests/classes/IndicatorTickDummy.h +++ b/Indicator/tests/classes/IndicatorTickDummy.h @@ -41,10 +41,8 @@ struct IndicatorTickDummyParams : IndicatorParams { // Dummy tick-based indicator. class IndicatorTickDummy : public IndicatorTick { public: - IndicatorTickDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "") - : IndicatorTick(INDI_TICK, _tf, _shift, _name) { - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); - } + IndicatorTickDummy(string _symbol, int _shift = 0, string _name = "") + : IndicatorTick(_symbol, INDI_TICK, _shift, _name) {} string GetName() override { return "IndicatorTickDummy"; } diff --git a/Indicator/tests/classes/IndicatorTickReal.h b/Indicator/tests/classes/IndicatorTickReal.h deleted file mode 100644 index 143abb45d..000000000 --- a/Indicator/tests/classes/IndicatorTickReal.h +++ /dev/null @@ -1,115 +0,0 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, 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 - * Real tick-based indicator. - */ - -#ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once -#endif - -// Includes. -#include "../../../Chart.struct.static.h" -#include "../../IndicatorTick.h" - -// Params for real tick-based indicator. -struct IndicatorTickRealParams : IndicatorParams { - IndicatorTickRealParams() : IndicatorParams(INDI_TICK) {} -}; - -// Real tick-based indicator. -class IndicatorTickReal : public IndicatorTick { - public: - IndicatorTickReal(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "") - : IndicatorTick(INDI_TICK, _tf, _shift, _name) { - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 3); - } - - string GetName() override { return "IndicatorTickReal"; } - - void OnBecomeDataSourceFor(IndicatorData* _indi) override { - // Feeding base indicator with historic entries of this indicator. -#ifdef __debug__ - Print(GetFullName(), " became a data source for ", _indi.GetFullName()); -#endif - -#ifndef __MQL4__ - int _ticks_to_emit = 1000; - -#ifdef __debug_verbose__ - Print(_indi.GetFullName(), " will be now filled with ", _ticks_to_emit, - " historical entries generated by " + GetFullName()); -#endif - - static MqlTick _ticks[]; - ArrayResize(_ticks, 0); - - int _tries = 10; - int _num_copied = -1; - - while (_tries-- > 0) { - _num_copied = CopyTicks(GetSymbol(), _ticks, COPY_TICKS_ALL); - - if (_num_copied == -1) { - Sleep(1000); - } else { - break; - } - } - - // Clearing possible error 4004. - ResetLastError(); - - for (int i = 0; i < _num_copied; ++i) { - TickAB _tick(_ticks[i].ask, _ticks[i].bid); - // We can't call EmitEntry() here, as tick would go to multiple sources at the same time! - _indi.OnDataSourceEntry(TickToEntry(_ticks[i].time, _tick)); - } -#endif - } - - void OnTick() override { -#ifdef __MQL4__ - // Refreshes Ask/Bid constants. - RefreshRates(); - double _ask = Ask; - double _bid = Bid; - long _time = TimeCurrent(); -#else - static MqlTick _ticks[]; - // Copying only the last tick. - int _num_copied = CopyTicks(GetSymbol(), _ticks, COPY_TICKS_INFO, 0, 1); - -#ifdef __debug_verbose__ - Print("TickReal: ", TimeToString(_ticks[0].time), " = ", _ticks[0].bid); -#endif - - double _ask = _ticks[0].ask; - double _bid = _ticks[0].bid; - long _time = _ticks[0].time; -#endif - TickAB _tick(_ask, _bid); - EmitEntry(TickToEntry(_time, _tick)); - } -}; diff --git a/IndicatorBase.h b/IndicatorBase.h index c12383fbe..db20447a6 100644 --- a/IndicatorBase.h +++ b/IndicatorBase.h @@ -37,13 +37,18 @@ class Chart; #include "Array.mqh" #include "BufferStruct.mqh" #include "Chart.mqh" +#include "Chart.struct.tf.h" +#include "ChartBase.h" +#include "ChartMt.h" #include "DateTime.mqh" #include "DrawIndicator.mqh" +#include "Flags.h" #include "Indicator.define.h" #include "Indicator.enum.h" #include "Indicator.struct.cache.h" #include "Indicator.struct.h" #include "Indicator.struct.serialize.h" +#include "Log.mqh" #include "Object.mqh" #include "Refs.mqh" #include "Serializer.mqh" @@ -54,14 +59,10 @@ class Chart; /** * Class to deal with indicators. */ -class IndicatorBase : public Chart { +class IndicatorBase : public Object { protected: IndicatorState istate; - void* mydata; - int calc_start_bar; // Index of the first valid bar (from 0). - bool indicator_builtin; - long last_tick_time; // Time of the last Tick() call. - int flags; // Flags such as INDI_FLAG_INDEXABLE_BY_SHIFT. + Ref logger; public: /* Indicator enumerations */ @@ -81,28 +82,15 @@ class IndicatorBase : public Chart { /** * Class constructor. */ - IndicatorBase(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _symbol = NULL) : Chart(_tf, _symbol) { - // 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; - calc_start_bar = 0; - last_tick_time = 0; - } - - /** - * Class constructor. - */ - IndicatorBase(ENUM_TIMEFRAMES_INDEX _tfi, string _symbol = NULL) : Chart(_tfi, _symbol) { - // 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; - calc_start_bar = 0; - last_tick_time = 0; - } + IndicatorBase() {} /** * Class deconstructor. */ virtual ~IndicatorBase() { ReleaseHandle(); } + /* Operator overloading methods */ + /* Buffer methods */ virtual string CacheKey() { return GetName(); } @@ -180,79 +168,28 @@ class IndicatorBase : public Chart { /* Getters */ - /** - * Returns indicator's flags. - */ - int GetFlags() { return flags; } - - /** - * Gets an indicator's chart parameter value. - */ - template - T Get(ENUM_CHART_PARAM _param) { - return Chart::Get(_param); - } - /** * Gets an indicator's state property value. */ template - T Get(STRUCT_ENUM_INDICATOR_STATE_PROP _prop) { + T Get(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop) { return istate.Get(_prop); } /** - * Gets number of modes available to retrieve by GetValue(). + * Returns logger. */ - virtual int GetModeCount() { return 0; } + Log* GetLogger() { + if (!logger.IsSet()) { + logger = new Log(); + } + return logger.Ptr(); + } /* Getters */ - /** - * Whether data source is selected. - */ - virtual bool HasDataSource(bool _try_initialize = false) { return false; } - - /** - * Returns currently selected data source doing validation. - */ - virtual IndicatorBase* GetDataSource() { return NULL; } - - /** - * Get indicator type. - */ - virtual ENUM_INDICATOR_TYPE GetType() { return INDI_NONE; } - - /** - * Get data type of indicator. - */ - virtual ENUM_DATATYPE GetDataType() { return (ENUM_DATATYPE)-1; } - - /** - * Get name of the indicator. - */ - virtual string GetName() { return EnumToString(GetType()); } - - /** - * Get full name of the indicator (with "over ..." part). - */ - virtual string GetFullName() { return GetName(); } - - /** - * Get more descriptive name of the indicator. - */ - virtual string GetDescriptiveName() { return GetName(); } - /* Setters */ - /** - * Sets an indicator's chart parameter value. - */ - template - void Set(ENUM_CHART_PARAM _param, T _value) { - Chart::Set(_param, _value); - } - /** * Sets an indicator's state property value. */ @@ -276,7 +213,7 @@ class IndicatorBase : public Chart { /** * Sets indicator's symbol. */ - void SetSymbol(string _symbol) { Set(CHART_PARAM_SYMBOL, _symbol); } + // void SetSymbol(string _symbol) { Set(CHART_PARAM_SYMBOL, _symbol); } /* Other methods */ @@ -299,6 +236,21 @@ class IndicatorBase : public Chart { /* Virtual methods */ + /** + * Get name of the indicator. + */ + virtual string GetName() = NULL; + + /** + * Get full name of the indicator (with "over ..." part). + */ + virtual string GetFullName() { return GetName(); } + + /** + * Get more descriptive name of the indicator. + */ + virtual string GetDescriptiveName() { return GetName(); } + /** * Returns indicator value for a given shift and mode. */ @@ -320,11 +272,6 @@ class IndicatorBase : public Chart { */ // virtual bool ToString() = NULL; // @fixme? - /** - * Gets indicator's symbol. - */ - string GetSymbol() { return Get(CHART_PARAM_SYMBOL); } - /* Defines MQL backward compatible methods */ double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, int _mode, int _shift) { diff --git a/IndicatorData.enum.h b/IndicatorData.enum.h index cadbeaba1..10d745040 100644 --- a/IndicatorData.enum.h +++ b/IndicatorData.enum.h @@ -30,15 +30,15 @@ #pragma once #endif -/* Defines type of source data for */ +/* Defines type of source data for. Also used for Indicator::GetPossibleDataModes(). */ enum ENUM_IDATA_SOURCE_TYPE { - IDATA_BUILTIN = 0, // Platform built-in - IDATA_CHART, // Chart calculation - IDATA_ICUSTOM, // iCustom: Custom indicator file - IDATA_ICUSTOM_LEGACY, // iCustom: Custom, legacy, provided by MT indicator file - IDATA_INDICATOR, // OnIndicator: Another indicator as a source of data - IDATA_ONCALCULATE, // OnCalculate: Custom calculation function - IDATA_MATH // Math-based indicator + IDATA_BUILTIN = 1 << 0, // Platform built-in + IDATA_CHART = 1 << 1, // Chart calculation + IDATA_ICUSTOM = 1 << 2, // iCustom: Custom indicator file + IDATA_ICUSTOM_LEGACY = 1 << 3, // iCustom: Custom, legacy, provided by MT indicator file + IDATA_INDICATOR = 1 << 4, // OnIndicator: Another indicator as a source of data + IDATA_ONCALCULATE = 1 << 5, // OnCalculate: Custom calculation function + IDATA_MATH = 1 << 6 // Math-based indicator }; /* Defines range value data type for indicator storage. */ diff --git a/IndicatorData.mqh b/IndicatorData.mqh index 2405b8051..5cb7564c5 100644 --- a/IndicatorData.mqh +++ b/IndicatorData.mqh @@ -36,10 +36,19 @@ class IndicatorData : public IndicatorBase { protected: // Class variables. - ARRAY(ValueStorage*, value_storages); + bool do_draw; + bool indicator_builtin; + bool is_fed; // Whether calc_start_bar is already calculated. + int calc_start_bar; // Index of the first valid bar (from 0). + int flags; // Flags such as INDI_FLAG_INDEXABLE_BY_SHIFT. + long last_tick_time; // Time of the last Tick() call. + void* mydata; + 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. BufferStruct idata; DictStruct> indicators; // Indicators list keyed by id. + DrawIndicator* draw; IndicatorCalculateCache cache; IndicatorDataParams idparams; // Indicator data params. Ref indi_src; // Indicator used as data source. @@ -65,30 +74,54 @@ class IndicatorData : public IndicatorBase { } 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; + calc_start_bar = 0; + last_tick_time = 0; + retarget_ap_av = INDI_VS_TYPE_NONE; + InitDraw(); return true; } + /** + * Initialize indicator data drawing on custom data. + */ + bool InitDraw() { + if (idparams.is_draw && !Object::IsValid(draw)) { + draw = new DrawIndicator(THIS_PTR); + draw.SetColorLine(idparams.indi_color); + } + return idparams.is_draw; + } + + /** + * Deinitialize drawing. + */ + void DeinitDraw() { + if (draw) { + delete draw; + } + } + public: /* Special methods */ /** * Class constructor. */ - IndicatorData(const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) - : idparams(_idparams), indi_src(_indi_src) {} + IndicatorData(const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + : do_draw(false), idparams(_idparams), indi_src(_indi_src) { + Init(); + } IndicatorData(const IndicatorDataParams& _idparams, ENUM_TIMEFRAMES _tf, string _symbol = NULL) - : idparams(_idparams), IndicatorBase(_tf, _symbol) {} + : do_draw(false), idparams(_idparams) { + Init(); + } /** * Class deconstructor. */ - virtual ~IndicatorData() { - for (int i = 0; i < ArraySize(value_storages); ++i) { - if (value_storages[i] != NULL) { - delete value_storages[i]; - } - } - } + virtual ~IndicatorData() { DeinitDraw(); } /* Operator overloading methods */ @@ -146,6 +179,37 @@ class IndicatorData : public IndicatorBase { return _entry.CheckFlag(_prop); } + /** + * Returns indicator's flags. + */ + int GetFlags() { return flags; } + + /** + * Get full name of the indicator (with "over ..." part). + */ + string GetFullName() { + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); + string _mode; + + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { + case IDATA_BUILTIN: + _mode = "B-in"; + break; + case IDATA_ONCALCULATE: + _mode = "On-C"; + break; + case IDATA_ICUSTOM: + _mode = "iCus"; + break; + case IDATA_INDICATOR: + _mode = "On-I"; + break; + } + + return GetName() + "#" + IntegerToString(GetId()) + "-" + _mode + "[" + IntegerToString(_max_modes) + "]" + + (HasDataSource() ? (" (over " + GetDataSource(false).GetFullName() + ")") : ""); + } + /** * Returns price corresponding to indicator value for a given shift and mode. * @@ -155,8 +219,8 @@ class IndicatorData : public IndicatorBase { * Returns price value of the corresponding indicator values. */ template - float GetValuePrice(int _shift = 0, int _mode = 0, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL) { - float _price = 0; + double GetValuePrice(int _shift = 0, int _mode = 0, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL) { + double _price = 0; ENUM_IDATA_VALUE_RANGE _idvrange = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDVRANGE)); if (_idvrange != IDATA_RANGE_PRICE) { @@ -176,16 +240,6 @@ class IndicatorData : public IndicatorBase { return _price; } - /* Setters */ - - /** - * Sets a value in IndicatorDataParams struct. - */ - template - void Set(STRUCT_ENUM_IDATA_PARAM _param, T _value) { - idparams.Set(_param, _value); - } - /* State methods */ /** @@ -310,44 +364,9 @@ class IndicatorData : public IndicatorBase { /* Getters */ /** - * Returns the highest bar's index (shift). - */ - template - int GetHighest(int count = WHOLE_ARRAY, int start_bar = 0) { - int max_idx = -1; - double max = -DBL_MAX; - 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).GetMax(GetModeCount()); - if (value > max) { - max = value; - max_idx = shift; - } - } - - return max_idx; - } - - /** - * Returns the lowest bar's index (shift). + * Get current close price depending on the operation type. */ - template - int GetLowest(int count = WHOLE_ARRAY, int start_bar = 0) { - int min_idx = -1; - double min = DBL_MAX; - 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()); - if (value < min) { - min = value; - min_idx = shift; - } - } - - return min_idx; - } + double GetCloseOffer(ENUM_ORDER_TYPE _cmd) { return _cmd == ORDER_TYPE_BUY ? GetBid() : GetAsk(); } /** * Returns the highest value. @@ -438,6 +457,35 @@ class IndicatorData : public IndicatorBase { return median; } + /** + * Get current (or by given date and time) open price depending on the operation type. + */ + double GetOpenOffer(ENUM_ORDER_TYPE _cmd, datetime _dt = 0) { + // Use the right open price at opening of a market order. For example: + // - When selling, only the latest Bid prices can be used. + // - When buying, only the latest Ask prices can be used. + return _cmd == ORDER_TYPE_BUY ? GetAsk(_dt) : GetBid(_dt); + } + + /** + * Returns symbol and optionally TF to be used e.g., to identify + */ + string GetSymbolTf(string _separator = "@") { + if (!HasCandleInHierarchy()) { + return ""; + } + + // Symbol is available throught Tick indicator at the end of the hierarchy. + string _res = GetSymbol(); + + if (HasCandleInHierarchy()) { + // TF is available throught Candle indicator at the end of the hierarchy. + _res += _separator + ChartTf::TfToString(GetTf()); + } + + return _res; + } + /* Data methods */ /** @@ -518,7 +566,56 @@ class IndicatorData : public IndicatorBase { /** * Get pointer to data of indicator. */ - BufferStruct* GetData() { return GET_PTR(idata); } + BufferStruct* GetData() { return GetPointer(idata); } + + /** + * Returns currently selected data source doing validation. + */ + IndicatorData* GetDataSource(bool _validate = true) { + IndicatorData* _result = NULL; + + if (GetDataSourceRaw() != NULL) { + _result = GetDataSourceRaw(); + } 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 ", + GetName(), " (data source id ", _source_id, ")."); + DebugBreak(); + + if (indicators.KeyExists(_source_id)) { + _result = indicators[_source_id].Ptr(); + } else { + Ref _source = FetchDataSource((ENUM_INDICATOR_TYPE)_source_id); + + if (!_source.IsSet()) { + Alert(GetName(), " has no built-in source indicator ", _source_id); + DebugBreak(); + } else { + indicators.Set(_source_id, _source); + + _result = _source.Ptr(); + } + } + } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_INDICATOR) { + // User sets data source's mode to On-Indicator, but not set data source via SetDataSource()! + + // Requesting potential data source. + _result = OnDataSourceRequest(); + + if (_result != NULL) { + // Initializing with new data source. + SetDataSource(_result); + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR); + } + } + + if (_validate) { + ValidateDataSource(&this, _result); + } + + return _result; + } /** * Returns given data source type. Used by i*OnIndicator methods if indicator's Calculate() uses other indicators. @@ -541,12 +638,17 @@ class IndicatorData : public IndicatorBase { return _result; } + /** + * Gets value storage type previously set by SetDataSourceAppliedPrice() or SetDataSourceAppliedVolume(). + */ + ENUM_INDI_VS_TYPE GetDataSourceAppliedType() { return retarget_ap_av; } + // int GetDataSourceMode() { return indi_src_mode; } /** * Returns currently selected data source without any validation. */ - IndicatorBase* GetDataSourceRaw() { return indi_src.Ptr(); } + IndicatorData* GetDataSourceRaw() { return indi_src.Ptr(); } /** * Returns values for a given shift. @@ -587,11 +689,46 @@ class IndicatorData : public IndicatorBase { } /** - * Provides built-in indicators whose can be used as data source. + * Whether data source is selected. + */ + bool HasDataSource(bool _try_initialize = false) { + if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) { + return true; + } + + if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_INDICATOR && + GetDataSourceRaw() == NULL && _try_initialize) { + SetDataSource(OnDataSourceRequest()); + } + + return GetDataSourceRaw() != NULL; + } + + /** + * Whether given data source is in the hierarchy. + */ + bool HasDataSource(IndicatorData* _indi) { + if (THIS_PTR == _indi) return true; + + if (HasDataSource(true)) { + return GetDataSourceRaw() PTR_DEREF HasDataSource(_indi); + } + + return false; + } + + /** + * Checks whether there is attached suitable data source (if required). */ - virtual IndicatorBase* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } + bool HasSuitableDataSource() { + Flags _flags = GetSuitableDataSourceTypes(); + return !_flags.HasFlag(INDI_SUITABLE_DS_TYPE_EXPECT_NONE) && GetSuitableDataSource(false) != nullptr; + } - /* Checkers */ + /** + * Checks whether indicator have given mode (max_modes is greater that given mode). + */ + bool HasValueStorage(int _mode = 0) { return _mode < GetModeCount(); } /** * Whether we can and have to select mode when specifying data source. @@ -617,91 +754,103 @@ class IndicatorData : public IndicatorBase { } /** - * Sets data source's input mode. + * Sets the value for IndicatorDataParams struct. */ - // void SetDataSourceMode(int _mode) { indi_src_mode = _mode; } + template + void Set(STRUCT_ENUM_IDATA_PARAM _param, T _value) { + idparams.Set(_param, _value); + } - /* Storage methods */ + /** + * Sets indicator data source. + */ + void SetDataSource(IndicatorData* _indi, int _input_mode = -1) { + // Detecting circular dependency. + IndicatorData* _curr; + int _iterations_left = 50; + + // 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) { + if (_curr == THIS_PTR) { + // Circular dependency found. + Print("Error: Circular dependency found when trying to attach " + _indi PTR_DEREF GetFullName() + " into " + + GetFullName() + "!"); + DebugBreak(); + return; + } + } - ValueStorage* GetValueStorage(int _mode = 0) { - if (_mode >= ArraySize(value_storages)) { - ArrayResize(value_storages, _mode + 1); + 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(), + ", 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(), + ", because source indicator isn't indexable by timestamp!"); + DebugBreak(); + return; + } } - if (value_storages[_mode] == NULL) { - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + if (indi_src.IsSet() && indi_src.Ptr() != _indi) { + indi_src.Ptr().RemoveListener(THIS_PTR); + } + indi_src = _indi; + if (_indi != NULL) { + indi_src.Ptr().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); } - return value_storages[_mode]; } /** - * Returns value storage of given kind. + * Uses custom value storage type as applied price. */ - virtual IValueStorage* GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { - Print("Error: ", GetFullName(), " indicator has no storage type ", EnumToString(_type), "!"); - DebugBreak(); - return NULL; + void SetDataSourceAppliedPrice(ENUM_INDI_VS_TYPE _vs_type) { + // @todo Check if given value storage is of compatible type (double)! + retarget_ap_av = _vs_type; } - virtual IValueStorage* GetSpecificAppliedPriceValueStorage(ENUM_APPLIED_PRICE _ap) { - switch (_ap) { - case PRICE_ASK: - return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); - case PRICE_BID: - return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); - case PRICE_OPEN: - return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); - case PRICE_HIGH: - return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); - case PRICE_LOW: - return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); - case PRICE_CLOSE: - return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); - case PRICE_MEDIAN: - case PRICE_TYPICAL: - case PRICE_WEIGHTED: - default: - Print("Error: Invalid applied price " + EnumToString(_ap) + - ", only PRICE_(OPEN|HIGH|LOW|CLOSE) are currently supported by " - "IndicatorBase::GetSpecificAppliedPriceValueStorage()!"); - DebugBreak(); - return NULL; - } - } + /** + * Sets data source's input mode. + */ + // void SetDataSourceMode(int _mode) { indi_src_mode = _mode; } - virtual bool HasSpecificAppliedPriceValueStorage(ENUM_APPLIED_PRICE _ap) { - 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: - return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); - case PRICE_LOW: - return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); - case PRICE_CLOSE: - return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); - case PRICE_MEDIAN: - case PRICE_TYPICAL: - case PRICE_WEIGHTED: - default: - Print("Error: Invalid applied price " + EnumToString(_ap) + - ", only PRICE_(OPEN|HIGH|LOW|CLOSE) are currently supported by " - "IndicatorBase::HasSpecificAppliedPriceValueStorage()!"); - DebugBreak(); - return false; - } - } + /* Candle methods */ /** - * Checks whether indicator support given value storage type. + * Checks whether there is Candle-featured in the hierarchy. + */ + bool HasCandleInHierarchy() { return GetCandle(false) != nullptr; } + + /** + * Checks whether current indicator has all buffers required to be a Candle-compatible indicator. */ - virtual bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { return false; } + bool IsCandleIndicator() { + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN) && HasSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH) && + HasSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW) && HasSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE) && + HasSpecificValueStorage(INDI_VS_TYPE_SPREAD) && HasSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME) && + HasSpecificValueStorage(INDI_VS_TYPE_TIME) && HasSpecificValueStorage(INDI_VS_TYPE_VOLUME); + } /* Tick methods */ + /** + * Checks whether current indicator has all buffers required to be a Tick-compatible indicator. + */ + bool IsTickIndicator() { + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK) && HasSpecificValueStorage(INDI_VS_TYPE_PRICE_BID) && + HasSpecificValueStorage(INDI_VS_TYPE_SPREAD) && HasSpecificValueStorage(INDI_VS_TYPE_VOLUME) && + HasSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME); + } + void Tick() { long _current_time = TimeCurrent(); @@ -727,7 +876,30 @@ class IndicatorData : public IndicatorBase { OnTick(); } - /* Validate methods */ + /** + * Checks whether there is Tick-featured in the hierarchy. + */ + bool HasTickInHierarchy() { return GetTick(false) != nullptr; } + + /* Data source methods */ + + /** + * Injects data source between this indicator and its data source. + */ + void InjectDataSource(IndicatorData* _indi) { + if (_indi == THIS_PTR) { + // Indicator already injected. + return; + } + + IndicatorData* _previous_ds = GetDataSource(false); + + SetDataSource(_indi); + + if (_previous_ds != nullptr) { + _indi PTR_DEREF SetDataSource(_previous_ds); + } + } /** * Loads and validates built-in indicators whose can be used as data source. @@ -770,6 +942,27 @@ class IndicatorData : public IndicatorBase { } } + /** + * Checks whether indicator have given mode index. + * + * If given mode is -1 (default one) and indicator has exactly one mode, then mode index will be replaced by 0. + */ + void ValidateDataSourceMode(int& _out_mode) { + if (_out_mode == -1) { + // First mode will be used by default, or, if selected indicator has more than one mode, error will happen. + if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)) != 1) { + Alert("Error: ", GetName(), " must have exactly one possible mode in order to skip using SetDataSourceMode()!"); + DebugBreak(); + } + _out_mode = 0; + } else if (_out_mode + 1 > Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) { + Alert("Error: ", GetName(), " have ", Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)), + " mode(s) buy you tried to reference mode with index ", _out_mode, + "! Ensure that you properly set mode via SetDataSourceMode()."); + DebugBreak(); + } + } + /** * Validates currently selected indicator used as data source. */ @@ -805,49 +998,621 @@ class IndicatorData : public IndicatorBase { /* Virtual methods */ /** - * Returns currently selected data source doing validation. + * Returns applied price as set by the indicator's params. */ - virtual IndicatorData* GetDataSource() { return NULL; } + virtual ENUM_APPLIED_PRICE GetAppliedPrice() { + Print("Error: GetAppliedPrice() was requested by ", GetFullName(), ", but it does not implement it!"); + DebugBreak(); + return (ENUM_APPLIED_PRICE)-1; + } /** - * Returns the indicator's struct value. + * Returns value storage's buffer type from this indicator's applied price (indicator must override GetAppliedPrice() + * method!). */ - virtual IndicatorDataEntry GetEntry(datetime _dt) { - Print(GetFullName(), - " must implement IndicatorDataEntry IndicatorBase::GetEntry(datetime _dt) in order to use GetEntry(datetime " - "_dt) or _indi[datetime] subscript operator!"); + virtual ENUM_INDI_VS_TYPE GetAppliedPriceValueStorageType() { + if (retarget_ap_av != INDI_VS_TYPE_NONE) { + // User wants to use custom value storage type as applied price. + return retarget_ap_av; + } + + 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: + return INDI_VS_TYPE_PRICE_HIGH; + case PRICE_LOW: + return INDI_VS_TYPE_PRICE_LOW; + case PRICE_CLOSE: + return INDI_VS_TYPE_PRICE_CLOSE; + case PRICE_MEDIAN: + return INDI_VS_TYPE_PRICE_MEDIAN; + case PRICE_TYPICAL: + return INDI_VS_TYPE_PRICE_TYPICAL; + case PRICE_WEIGHTED: + return INDI_VS_TYPE_PRICE_WEIGHTED; + } + + Print("Error: ", GetFullName(), " has not supported applied price set: ", EnumToString(GetAppliedPrice()), "!"); DebugBreak(); - IndicatorDataEntry _default; - return _default; + return (ENUM_INDI_VS_TYPE)-1; } /** - * Returns the indicator's struct value. + * Returns applied volume as set by the indicator's params. */ - virtual IndicatorDataEntry GetEntry(int _index = 0) = NULL; + virtual ENUM_APPLIED_VOLUME GetAppliedVolume() { + Print("Error: GetAppliedVolume() was requested by ", GetFullName(), ", but it does not implement it!"); + DebugBreak(); + return (ENUM_APPLIED_VOLUME)-1; + } /** - * Alters indicator's struct value. - * - * 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. + * Returns value storage's buffer type from this indicator's applied volume (indicator must override + * GetAppliedVolume() method!). */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _index = -1) = NULL; + virtual ENUM_INDI_VS_TYPE GetAppliedVolumeValueStorageType() { + if (retarget_ap_av != INDI_VS_TYPE_NONE) { + // User wants to use custom value storage type as applied volume. + return retarget_ap_av; + } - // virtual ENUM_IDATA_VALUE_RANGE GetIDataValueRange() = NULL; + switch (GetAppliedVolume()) { + case VOLUME_TICK: + return INDI_VS_TYPE_TICK_VOLUME; + case VOLUME_REAL: + return INDI_VS_TYPE_VOLUME; + } + + Print("Error: ", GetFullName(), " has not supported applied volume set: ", EnumToString(GetAppliedVolume()), "!"); + DebugBreak(); + return (ENUM_INDI_VS_TYPE)-1; + } /** - * Returns the indicator's entry value. + * Gets ask price for a given date and time. Return current ask price if _dt wasn't passed or is 0. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) = NULL; + virtual double GetAsk(datetime _dt = 0) { return GetTick() PTR_DEREF GetAsk(_dt); } /** - * Gets indicator's signals. + * Returns the number of bars on the chart. + */ + virtual int GetBars() { return GetCandle() PTR_DEREF GetBars(); } + + /** + * Returns index of the current bar. + */ + virtual int GetBarIndex() { return GetCandle() PTR_DEREF GetBarIndex(); } + + /** + * Returns time of the bar for a given shift. + */ + virtual datetime GetBarTime(int _shift = 0) { return GetCandle() PTR_DEREF GetBarTime(_shift); } + + /** + * Search for a bar by its time. + * + * Returns the index of the bar which covers the specified time. + */ + virtual int GetBarShift(datetime _time, bool _exact = false) { + return GetTick() PTR_DEREF GetBarShift(_time, _exact); + } + + /** + * Gets bid price for a given date and time. Return current bid price if _dt wasn't passed or is 0. + */ + virtual double GetBid(datetime _dt = 0) { return GetTick() PTR_DEREF GetBid(_dt); } + + /** + * Traverses source indicators' hierarchy and tries to find OHLC-featured + * indicator. IndicatorCandle satisfies such requirements. + */ + virtual IndicatorData* GetCandle(bool _warn_if_not_found = true, IndicatorData* _originator = nullptr) { + if (_originator == nullptr) { + _originator = THIS_PTR; + } + if (IsCandleIndicator()) { + return THIS_PTR; + } else if (HasDataSource()) { + return GetDataSource() PTR_DEREF GetCandle(_warn_if_not_found, _originator); + } else { + // _indi_src == NULL. + if (_warn_if_not_found) { + Print( + "Can't find Candle-compatible indicator (which have storage buffers for: Open, High, Low, Close, Spread, " + "Tick Volume, Time, Volume) in the " + "hierarchy of ", + _originator PTR_DEREF GetFullName(), "!"); + DebugBreak(); + } + return NULL; + } + } + + /** + * Get data type of indicator. + */ + virtual ENUM_DATATYPE GetDataType() { return (ENUM_DATATYPE)-1; } + + /** + * Gets close price for a given, optional shift. + */ + virtual double GetClose(int _shift = 0) { return GetCandle() PTR_DEREF GetClose(_shift); } + + /** + * Returns the indicator's struct value via index. + */ + virtual IndicatorDataEntry GetEntry(long _index = 0) = NULL; + + /** + * Returns the indicator's struct value via timestamp. + */ + // virtual IndicatorDataEntry GetEntry(datetime _dt) = NULL; + + /** + * Gets high price for a given, optional shift. + */ + virtual double GetHigh(int _shift = 0) { return GetCandle() PTR_DEREF GetHigh(_shift); } + + /** + * Alters indicator's struct value. + * + * 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 ENUM_IDATA_VALUE_RANGE GetIDataValueRange() = NULL; + + /** + * Returns the indicator's entry value. + */ + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) = NULL; + + /** + * Returns the shift of the maximum value over a specific number of periods depending on type. + */ + virtual int GetHighest(int type, int _count = WHOLE_ARRAY, int _start = 0) { + return GetCandle() PTR_DEREF GetHighest(type, _count, _start); + } + + /** + * Returns time of the last bar. + */ + virtual datetime GetLastBarTime() { return GetCandle() PTR_DEREF GetLastBarTime(); } + + /** + * Gets low price for a given, optional shift. + */ + virtual double GetLow(int _shift = 0) { return GetCandle() PTR_DEREF GetLow(_shift); } + + /** + * Returns the shift of the minimum value over a specific number of periods depending on type. + */ + virtual int GetLowest(int type, int _count = WHOLE_ARRAY, int _start = 0) { + return GetCandle() PTR_DEREF GetLowest(type, _count, _start); + } + + /** + * Gets number of modes available to retrieve by GetValue(). + */ + virtual int GetModeCount() { return 0; } + + /** + * Get name of the indicator. + */ + virtual string GetName() { return EnumToString(GetType()); } + + /** + * Gets open price for a given, optional shift. + */ + virtual double GetOpen(int _shift = 0) { return GetCandle() PTR_DEREF GetOpen(_shift); } + + /** + * Gets OHLC price values. + */ + virtual BarOHLC GetOHLC(int _shift = 0) { return GetCandle() PTR_DEREF GetOHLC(_shift); } + + /** + * Get peak price at given number of bars. + * + * In case of error, check it via GetLastError(). + */ + virtual double GetPeakPrice(int _bars, int _mode, int _index) { + return GetTick() PTR_DEREF GetPeakPrice(_bars, _mode, _index); + } + + /** + * Returns the current price value given applied price type, symbol and timeframe. + */ + virtual double GetPrice(ENUM_APPLIED_PRICE _ap, int _shift = 0) { + return GetCandle() PTR_DEREF GetPrice(_ap, _shift); + } + + /** + * Gets indicator's signals. * * 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; + /** + * Returns spread for the bar. + * + * If local history is empty (not loaded), function returns 0. + */ + virtual long GetSpread(int _shift = 0) { return GetCandle() PTR_DEREF GetSpread(_shift); } + + /** + * Returns spread in pips. + */ + virtual double GetSpreadInPips(int _shift = 0) { + return (GetAsk() - GetBid()) * pow(10, GetSymbolProps().GetPipDigits()); + } + + virtual bool HasSpecificAppliedPriceValueStorage(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 + // parameter. + // @todo Check for value storage compatibility (double). + return HasSpecificValueStorage(_target PTR_DEREF GetDataSourceAppliedType()); + } + } + + 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: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); + case PRICE_LOW: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); + case PRICE_CLOSE: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); + case PRICE_MEDIAN: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_MEDIAN); + case PRICE_TYPICAL: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_TYPICAL); + case PRICE_WEIGHTED: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_WEIGHTED); + default: + Print("Error: Invalid applied price " + EnumToString(_ap) + + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " + "IndicatorBase::HasSpecificAppliedPriceValueStorage()!"); + DebugBreak(); + return false; + } + } + + /** + * 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) { + 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 + // parameter. + // @todo Check for value storage compatibility (double). + return (ValueStorage*)GetSpecificValueStorage(_target PTR_DEREF GetDataSourceAppliedType()); + } + } + + 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: + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); + case PRICE_LOW: + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); + case PRICE_CLOSE: + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); + case PRICE_MEDIAN: + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_MEDIAN); + case PRICE_TYPICAL: + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_TYPICAL); + case PRICE_WEIGHTED: + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_WEIGHTED); + default: + Print("Error: Invalid applied price " + EnumToString(_ap) + + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " + "IndicatorBase::GetSpecificAppliedPriceValueStorage()!"); + DebugBreak(); + return NULL; + } + } + + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + virtual unsigned int GetSuitableDataSourceTypes() { return 0; } + + /** + * Gets indicator's symbol. + */ + virtual string GetSymbol() { return GetTick() PTR_DEREF GetSymbol(); } + + /** + * Gets symbol info for active symbol. + */ + virtual SymbolInfoProp GetSymbolProps() { return GetTick() PTR_DEREF GetSymbolProps(); } + + /** + * Gets indicator's time-frame. + */ + virtual ENUM_TIMEFRAMES GetTf() { return GetCandle() PTR_DEREF GetTf(); } + + /** + * Traverses source indicators' hierarchy and tries to find Ask, Bid, Spread, + * Volume and Tick Volume-featured indicator. IndicatorTick satisfies such + * requirements. + */ + virtual IndicatorData* GetTick(bool _warn_if_not_found = true) { + if (IsTickIndicator()) { + return THIS_PTR; + } else if (HasDataSource()) { + return GetDataSource() PTR_DEREF GetTick(); + } + + // No IndicatorTick compatible indicator found in hierarchy. + if (_warn_if_not_found) { + Print( + "Can't find Tick-compatible indicator (which have storage buffers for: Ask, Bid, Spread, Volume, Tick " + "Volume) in the hierarchy!"); + DebugBreak(); + } + return NULL; + } + + /** + * Returns tick volume value for the bar. + * + * If local history is empty (not loaded), function returns 0. + */ + virtual long GetTickVolume(int _shift = 0) { return GetCandle() PTR_DEREF GetTickVolume(_shift); } + + /** + * Returns value storage of given kind. + */ + virtual IValueStorage* GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { + Print("Error: ", GetFullName(), " indicator has no storage type ", EnumToString(_type), "!"); + DebugBreak(); + return NULL; + } + + /** + * Returns best suited data source for this indicator. + */ + virtual IndicatorData* GetSuitableDataSource(bool _warn_if_not_found = true) { + Flags _suitable_types = GetSuitableDataSourceTypes(); + IndicatorData* _curr_indi; + + // There shouldn't be any attached data source. + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_EXPECT_NONE) && GetDataSource() != nullptr) { + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), " doesn't support attaching data source, but has one attached!"); + DebugBreak(); + } + return nullptr; + } + + // Custom set of required buffers. Will invoke virtual OnCheckIfSuitableDataSource(). + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_CUSTOM)) { + // Searching suitable data source in hierarchy. + for (_curr_indi = GetDataSource(false); _curr_indi != nullptr; + _curr_indi = _curr_indi PTR_DEREF GetDataSource(false)) { + if (OnCheckIfSuitableDataSource(_curr_indi)) return _curr_indi; + + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_BASE_ONLY)) { + // Directly connected data source must be suitable, so we stops for loop. + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), + " requested custom type of data source to be directly connected to this indicator, but none " + "satisfies the requirements!"); + DebugBreak(); + } + return nullptr; + } + } + + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), + " requested custom type of indicator as data source, but there is none in the hierarchy which satisfies " + "the requirements!"); + DebugBreak(); + } + return nullptr; + } + + // Requires Candle-compatible indicator in the hierarchy. + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_CANDLE)) { + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_BASE_ONLY)) { + // Candle indicator must be directly connected to this indicator as its data source. + _curr_indi = GetDataSource(false); + + if (_curr_indi == nullptr || !_curr_indi PTR_DEREF IsCandleIndicator()) { + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), + " must have Candle-compatible indicator directly conected as a data source! We don't search for it " + "further in the hierarchy."); + DebugBreak(); + } + return nullptr; + } + + return _curr_indi; + } else { + // Candle indicator must be in the data source hierarchy. + _curr_indi = GetCandle(false); + + if (_curr_indi != nullptr) return _curr_indi; + + if (!_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_TICK)) { + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), + " requested Candle-compatible type of indicator as data source, but there is none in the hierarchy!"); + DebugBreak(); + } + return nullptr; + } + } + } + + // Requires Tick-compatible indicator in the hierarchy. + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_TICK)) { + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_BASE_ONLY)) { + // Tick indicator must be directly connected to this indicator as its data source. + _curr_indi = GetDataSource(false); + + if (_curr_indi == nullptr || !_curr_indi PTR_DEREF IsTickIndicator()) { + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), + " must have Tick-compatible indicator directly connected as a data source! We don't search for it " + "further in the hierarchy."); + DebugBreak(); + } + } + + return _curr_indi; + } else { + _curr_indi = GetTick(false); + if (_curr_indi != nullptr) return _curr_indi; + + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), " must have Tick-compatible indicator in the data source hierarchy!"); + DebugBreak(); + } + return nullptr; + } + } + + ENUM_INDI_VS_TYPE _requested_vs_type; + + // Requires a single buffered or OHLC-compatible indicator (targetted via applied price) in the hierarchy. + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_AP)) { + // Applied price is defined by this indicator, so it must override GetAppliedPrice(). + _requested_vs_type = GetAppliedPriceValueStorageType(); + + // Searching for given buffer type in the hierarchy. + for (_curr_indi = GetDataSource(false); _curr_indi != nullptr; + _curr_indi = _curr_indi PTR_DEREF GetDataSource(false)) { + if (_curr_indi PTR_DEREF HasSpecificValueStorage(_requested_vs_type)) { + return _curr_indi; + } + + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_BASE_ONLY)) { + // Directly connected data source must have given data storage buffer, so we stops for loop. + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), + " requested directly connected data source to contain value storage of type ", + EnumToString(_requested_vs_type), ", but there is no such data storage!"); + DebugBreak(); + } + return nullptr; + } + } + + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), " requested that there is data source that contain value storage of type ", + EnumToString(_requested_vs_type), " in the hierarchy, but there is no such data source!"); + DebugBreak(); + } + return nullptr; + } + + // Requires a single buffered or OHLC-compatible indicator (targetted via applied price or volume) in the hierarchy. + if (_suitable_types.HasAnyFlag(INDI_SUITABLE_DS_TYPE_AP | INDI_SUITABLE_DS_TYPE_AV)) { + _requested_vs_type = (ENUM_INDI_VS_TYPE)-1; + + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_AP)) { + // Applied price is defined by this indicator, so it must override GetAppliedPrice(). + _requested_vs_type = GetAppliedPriceValueStorageType(); + } else if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_AV)) { + // Applied volume is defined by this indicator, so it must override GetAppliedVolume(). + _requested_vs_type = GetAppliedVolumeValueStorageType(); + } + + // Searching for given buffer type in the hierarchy. + for (_curr_indi = GetDataSource(false); _curr_indi != nullptr; + _curr_indi = _curr_indi PTR_DEREF GetDataSource(false)) { + if (_curr_indi PTR_DEREF HasSpecificValueStorage(_requested_vs_type)) { + return _curr_indi; + } + + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_BASE_ONLY)) { + // Directly connected data source must have given data storage buffer, so we stops for loop. + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), + " requested directly connected data source to contain value storage of type ", + EnumToString(_requested_vs_type), ", but there is no such data storage!"); + DebugBreak(); + } + return nullptr; + } + } + + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), " requested that there is data source that contain value storage of type ", + EnumToString(_requested_vs_type), " in the hierarchy, but there is no such data source!"); + DebugBreak(); + } + return nullptr; + } + + if (_warn_if_not_found) { + Print("Error: ", GetFullName(), + " must have data source, but its configuration leave us without suitable one. Please override " + "GetSuitableDataSourceTypes() method so it will return suitable data source types!"); + DebugBreak(); + } + + return nullptr; + } + + /** + * Returns current tick index (incremented every OnTick()). + */ + virtual int GetTickIndex() { return GetTick() PTR_DEREF GetTickIndex(); } + + /** + * Get indicator type. + */ + virtual ENUM_INDICATOR_TYPE GetType() { return INDI_NONE; } + + /** + * Returns value storage for a given mode. + */ + virtual IValueStorage* GetValueStorage(int _mode = 0) { + if (_mode >= ArraySize(value_storages)) { + ArrayResize(value_storages, _mode + 1); + } + + if (!value_storages[_mode].IsSet()) { + value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + } + return value_storages[_mode].Ptr(); + } + + /** + * Returns volume value for the bar. + * + * If local history is empty (not loaded), function returns 0. + */ + virtual long GetVolume(int _shift = 0) { return GetCandle() PTR_DEREF GetVolume(_shift); } + /** * Sends entry to listening indicators. */ @@ -864,11 +1629,57 @@ class IndicatorData : public IndicatorBase { */ virtual void EmitHistory() {} + /** + * Provides built-in indicators whose can be used as data source. + */ + virtual IndicatorData* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } + + /** + * Checks whether indicator support given value storage type. + */ + virtual bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { + // Maybe indexed value storage? E.g., INDI_VS_TYPE_INDEX_0. + if ((int)_type >= INDI_VS_TYPE_INDEX_FIRST && (int)_type <= INDI_VS_TYPE_INDEX_LAST) { + return HasValueStorage((int)_type - INDI_VS_TYPE_INDEX_FIRST); + } + return false; + } + + /** + * Check if there is a new bar to parse. + */ + virtual bool IsNewBar() { return GetCandle() PTR_DEREF IsNewBar(); } + /** * Called when indicator became a data source for other indicator. */ virtual void OnBecomeDataSourceFor(IndicatorData* _base_indi){}; + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + virtual bool OnCheckIfSuitableDataSource(IndicatorData* _ds) { + Flags _suitable_types = GetSuitableDataSourceTypes(); + + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_EXPECT_NONE)) { + return false; + } + + ENUM_INDI_VS_TYPE _requested_vs_type; + + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_AP)) { + _requested_vs_type = GetAppliedPriceValueStorageType(); + return _ds PTR_DEREF HasSpecificValueStorage(_requested_vs_type); + } + + if (_suitable_types.HasFlag(INDI_SUITABLE_DS_TYPE_AV)) { + _requested_vs_type = GetAppliedVolumeValueStorageType(); + return _ds PTR_DEREF HasSpecificValueStorage(_requested_vs_type); + } + + return false; + } + /** * Called when data source emits new entry (historic or future one). */ @@ -906,9 +1717,14 @@ class IndicatorData : public IndicatorBase { } /** - * Sets indicator data source. + * Sets symbol info for symbol attached to the indicator. */ - virtual void SetDataSource(IndicatorData* _indi, int _input_mode = -1) = NULL; + virtual void SetSymbolProps(const SymbolInfoProp& _props) {} + + /** + * Stores entry in the buffer for later rerieval. + */ + virtual void StoreEntry(IndicatorDataEntry& entry) {} /** * Update indicator. @@ -922,13 +1738,6 @@ class IndicatorData : public IndicatorBase { * Loads and validates built-in indicators whose can be used as data source. */ // virtual void ValidateDataSource(IndicatorData* _target, IndicatorData* _source) {} - - /** - * Checks whether indicator have given mode index. - * - * If given mode is -1 (default one) and indicator has exactly one mode, then mode index will be replaced by 0. - */ - virtual void ValidateDataSourceMode(int& _out_mode) {} }; /** diff --git a/IndicatorData.struct.h b/IndicatorData.struct.h index 04616e9b9..451cbd770 100644 --- a/IndicatorData.struct.h +++ b/IndicatorData.struct.h @@ -29,9 +29,7 @@ #define STRUCT_ENUM_IDATA_PARAM STRUCT_ENUM(IndicatorDataParams, ENUM_IDATA_PARAM) // Includes. -#include "Indicator.struct.cache.h" #include "SerializerNode.enum.h" -#include "Storage/ValueStorage.indicator.h" // Type-less value for IndicatorDataEntryValue structure. union IndicatorDataEntryTypelessValue { @@ -46,6 +44,13 @@ struct IndicatorDataEntryValue { unsigned char flags; IndicatorDataEntryTypelessValue value; + // Constructors. + template + IndicatorDataEntryValue(T _value, unsigned char _flags = 0) : flags(_flags) { + Set(_value); + } + IndicatorDataEntryValue(unsigned char _flags = 0) : flags(_flags) {} + // Returns type of the value. ENUM_DATATYPE GetDataType() { return (ENUM_DATATYPE)((flags & 0xF0) >> 4); } @@ -392,10 +397,15 @@ 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. @@ -424,11 +434,14 @@ struct IndicatorDataParams { ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, ENUM_IDATA_VALUE_RANGE _idvrange = IDATA_RANGE_UNKNOWN, int _data_src_mode = 0) : data_src_mode(_data_src_mode), + draw_window(0), dtype(_dtype), max_modes(_max_modes), max_buffers(10), idstype(_idstype), idvrange(_idvrange), + indi_color(clrNONE), + is_draw(false), is_fed(false), src_id(-1), src_mode(-1){}; @@ -462,6 +475,7 @@ struct IndicatorDataParams { SetUserError(ERR_INVALID_PARAMETER); return (T)WRONG_VALUE; } + color GetIndicatorColor() const { return indi_color; } static IndicatorDataParams GetInstance(unsigned int _max_modes = 1, ENUM_DATATYPE _dtype = TYPE_DOUBLE, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, ENUM_IDATA_VALUE_RANGE _idvrange = IDATA_RANGE_UNKNOWN, @@ -503,4 +517,14 @@ struct IndicatorDataParams { } SetUserError(ERR_INVALID_PARAMETER); } + void SetDraw(bool _draw = true, int _window = 0) { + is_draw = _draw; + draw_window = _window; + } + void SetDraw(color _clr, int _window = 0) { + is_draw = true; + indi_color = _clr; + draw_window = _window; + } + void SetIndicatorColor(color _clr) { indi_color = _clr; } }; diff --git a/IndicatorData.struct.signal.h b/IndicatorData.struct.signal.h index b75e22b13..b90060014 100644 --- a/IndicatorData.struct.signal.h +++ b/IndicatorData.struct.signal.h @@ -37,8 +37,7 @@ struct IndicatorDataParams; struct IndicatorParams; // Includes. -//#include "IndicatorData.enum.h" -//#include "Indicator.struct.h" +#include "Indicator.struct.h" /* Structure for indicator signals. */ struct IndicatorSignal { @@ -58,16 +57,15 @@ struct IndicatorSignal { // Constructors. IndicatorSignal(int _signals = 0) : signals(_signals) {} - IndicatorSignal(ARRAY_REF(IndicatorDataEntry, _data), IndicatorDataParams &_idp, ChartParams &_cp, int _m1 = 0, - int _m2 = 0) + IndicatorSignal(ARRAY_REF(IndicatorDataEntry, _data), IndicatorDataParams &_idp, string _symbol, ENUM_TIMEFRAMES _tf, + int _m1 = 0, int _m2 = 0) : signals(0) { - CalcSignals(_data, _idp, _cp, _m1, _m2); + CalcSignals(_data, _idp, _symbol, _tf, _m1, _m2); } - // Main methods. // Calculate signal values. - void CalcSignals(ARRAY_REF(IndicatorDataEntry, _data), IndicatorDataParams &_idp, ChartParams &_cp, int _m1 = 0, - int _m2 = 0) { + void CalcSignals(ARRAY_REF(IndicatorDataEntry, _data), IndicatorDataParams &_idp, string _symbol, ENUM_TIMEFRAMES _tf, + int _m1 = 0, int _m2 = 0) { int _size = ArraySize(_data); // INDICATOR_SIGNAL_CROSSOVER bool _is_cross = false; @@ -82,10 +80,10 @@ struct IndicatorSignal { } SetSignal(INDICATOR_SIGNAL_CROSSOVER, _is_cross); // INDICATOR_SIGNAL_DIVERGENCE - int _shift0 = ChartStatic::iBarShift(_cp.symbol, _cp.tf.GetTf(), _data[0].timestamp); - int _shift1 = ChartStatic::iBarShift(_cp.symbol, _cp.tf.GetTf(), _data[_size - 1].timestamp); - double _price_w0 = ChartStatic::iPrice(PRICE_WEIGHTED, _cp.symbol, _cp.tf.GetTf(), _shift0); - double _price_w1 = ChartStatic::iPrice(PRICE_WEIGHTED, _cp.symbol, _cp.tf.GetTf(), _shift1); + 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); 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)); @@ -120,7 +118,6 @@ struct IndicatorSignal { } SetSignal(INDICATOR_SIGNAL_VOLATILE, _is_vola); } - // Signal methods for bitwise operations. /* Getters */ bool CheckSignals(unsigned int _flags) { return (signals & _flags) != 0; } diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index 8f24465b0..b1d62529b 100644 --- a/Indicators/Bitwise/Indi_Candle.mqh +++ b/Indicators/Bitwise/Indi_Candle.mqh @@ -23,7 +23,7 @@ // Includes. #include "../../Bar.struct.h" #include "../../BufferStruct.mqh" -#include "../../Indicator/IndicatorTickOrCandleSource.h" +#include "../../Indicator.mqh" #include "../../Pattern.struct.h" #include "../../Serializer.mqh" #include "../Price/Indi_Price.mqh" @@ -32,36 +32,58 @@ // Structs. struct CandleParams : IndicatorParams { // Struct constructor. - CandleParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorParams(INDI_CANDLE) { - shift = _shift; - tf = _tf; - }; - CandleParams(CandleParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + CandleParams(int _shift = 0) : IndicatorParams(INDI_CANDLE) { shift = _shift; }; + CandleParams(CandleParams &_params) { THIS_REF = _params; }; }; /** * Implements Candle Pattern Detector. */ -class Indi_Candle : public IndicatorTickOrCandleSource { +class Indi_Candle : public Indicator { public: /** * Class constructor. */ Indi_Candle(CandleParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_INT, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), - _indi_src){}; - Indi_Candle(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_CANDLE, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_INT, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src){}; + + Indi_Candle(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(CandleParams(), + IndicatorDataParams::GetInstance(1, TYPE_INT, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src){}; + + /** + * 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_CUSTOM; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_ICUSTOM; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // Patter uses OHLC. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { + void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { _entry.SetFlag(INDI_ENTRY_FLAG_IS_BITWISE, true); Indicator::GetEntryAlter(_entry, _shift); } @@ -69,15 +91,15 @@ class Indi_Candle : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); BarOHLC _ohlcs[1]; switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - // In this mode, price is fetched from chart. - _ohlcs[0] = Chart::GetOHLC(_ishift); + // In this mode, price is fetched from IndicatorCandle. + _ohlcs[0] = GetCandle() PTR_DEREF GetOHLC(_ishift); break; case IDATA_INDICATOR: // In this mode, price is fetched from given indicator. Such indicator diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index f86b811af..8d5105831 100644 --- a/Indicators/Bitwise/Indi_Pattern.mqh +++ b/Indicators/Bitwise/Indi_Pattern.mqh @@ -23,7 +23,7 @@ // Includes. #include "../../Bar.struct.h" #include "../../BufferStruct.mqh" -#include "../../Indicator/IndicatorTickOrCandleSource.h" +#include "../../Indicator.mqh" #include "../../Pattern.struct.h" #include "../../Serializer.mqh" #include "../Price/Indi_Price.mqh" @@ -33,32 +33,57 @@ struct IndiPatternParams : IndicatorParams { // Struct constructor. IndiPatternParams(int _shift = 0) : IndicatorParams(INDI_PATTERN) { shift = _shift; }; - IndiPatternParams(IndiPatternParams& _params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiPatternParams(IndiPatternParams& _params) { THIS_REF = _params; }; }; /** * Implements Pattern Detector. */ -class Indi_Pattern : public IndicatorTickOrCandleSource { +class Indi_Pattern : public Indicator { public: /** * Class constructor. */ Indi_Pattern(IndiPatternParams& _p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData* _indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(5, TYPE_UINT, _idstype, IDATA_RANGE_BITWISE, _indi_src_mode), - _indi_src){}; - Indi_Pattern(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_PATTERN, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(5, TYPE_UINT, _idstype, IDATA_RANGE_BITWISE, _indi_src_mode), + _indi_src) {} + + Indi_Pattern(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData* _indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiPatternParams(), + IndicatorDataParams::GetInstance(5, TYPE_UINT, _idstype, IDATA_RANGE_BITWISE, _indi_src_mode), + _indi_src) {} + + /** + * 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_CUSTOM; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData* _ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // Patter uses OHLC. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { int i; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); @@ -66,9 +91,9 @@ class Indi_Pattern : public IndicatorTickOrCandleSource { switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - // In this mode, price is fetched from chart. + // In this mode, price is fetched from candle. for (i = 0; i < _max_modes; ++i) { - _ohlcs[i] = Chart::GetOHLC(_ishift + i); + _ohlcs[i] = GetCandle() PTR_DEREF GetOHLC(_ishift + i); if (!_ohlcs[i].IsValid()) { // Return empty entry on invalid candles. return WRONG_VALUE; @@ -114,9 +139,9 @@ class Indi_Pattern : public IndicatorTickOrCandleSource { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _shift = 0) { + void GetEntryAlter(IndicatorDataEntry& _entry, int _shift) override { _entry.SetFlag(INDI_ENTRY_FLAG_IS_BITWISE, true); - Indicator::GetEntryAlter(_entry); + Indicator::GetEntryAlter(_entry, _shift); } /** diff --git a/Indicators/Bitwise/indicators.h b/Indicators/Bitwise/indicators.h index 26bfb4e5a..2cb3bb23c 100644 --- a/Indicators/Bitwise/indicators.h +++ b/Indicators/Bitwise/indicators.h @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2021, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index 4fe2c24d7..f8e2be624 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -39,16 +39,13 @@ struct IndiACParams : IndicatorParams { SetCustomIndicatorName("Examples\\Accelerator"); shift = _shift; }; - IndiACParams(IndiACParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiACParams(IndiACParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_AC : public IndicatorTickOrCandleSource { +class Indi_AC : public Indicator { protected: /* Protected methods */ @@ -69,14 +66,28 @@ class Indi_AC : public IndicatorTickOrCandleSource { */ Indi_AC(IndiACParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) { + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { Init(); - }; - Indi_AC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AC, _tf, _shift) { + } + + Indi_AC(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiACParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { Init(); - }; + } + /** + * 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; } + + public: + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -90,39 +101,14 @@ class Indi_AC : public IndicatorTickOrCandleSource { #ifdef __MQL4__ return ::iAC(_symbol, _tf, _shift); #else // __MQL5__ - int _handle = - Object::IsValid(_obj) ? _obj.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_HANDLE)) : NULL; - double _res[]; - if (_handle == NULL || _handle == INVALID_HANDLE) { - if ((_handle = ::iAC(_symbol, _tf)) == 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, 0, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iAC(_symbol, _tf), 0, _shift); #endif } /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) override { IndicatorDataEntryValue _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -139,13 +125,16 @@ class Indi_AC : public IndicatorTickOrCandleSource { } /** - * Returns reusable indicator for a given symbol and time-frame. + * Returns reusable indicator with the same candle indicator as given indicator's one. */ - static Indi_AC *GetCached(string _symbol, ENUM_TIMEFRAMES _tf) { + static Indi_AC *GetCached(IndicatorData *_indi) { Indi_AC *_ptr; - string _key = Util::MakeKey(_symbol, (int)_tf); + // There will be only one Indi_AC per IndicatorCandle instance. + string _key = Util::MakeKey(_indi PTR_DEREF GetCandle() PTR_DEREF GetId()); if (!Objects::TryGet(_key, _ptr)) { - _ptr = Objects::Set(_key, new Indi_AC(_tf)); + _ptr = Objects::Set(_key, new Indi_AC()); + // Assigning the same candle indicator for AC as in _indi. + _ptr.SetDataSource(_indi PTR_DEREF GetCandle()); } return _ptr; } diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index 1240760c9..aaa4193d5 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -38,29 +38,44 @@ struct IndiADParams : IndicatorParams { SetCustomIndicatorName("Examples\\AD"); shift = _shift; }; - IndiADParams(IndiADParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiADParams(IndiADParams &_params) { THIS_REF = _params; }; }; /** * Implements the Accumulation/Distribution indicator. */ -class Indi_AD : public IndicatorTickOrCandleSource { +class Indi_AD : public Indicator { public: /** * Class constructor. */ Indi_AD(IndiADParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_AD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AD, _tf, _shift) { - iparams.SetTf(_tf); - }; + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, + _indi_src_mode), + _indi_src){}; + + Indi_AD(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiADParams(), + IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, + _indi_src_mode), + _indi_src){}; + /** + * 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 | IDATA_ICUSTOM; } + + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return true; } /** * Returns the indicator value. @@ -72,40 +87,19 @@ class Indi_AD : public IndicatorTickOrCandleSource { static double iAD(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ - return ::iAD(_symbol, _tf, _shift); + Print("We'll now retrieve value from ::iAD(", _symbol, ", ", EnumToString(_tf), ", ", _shift, ")..."); + double _value = ::iAD(_symbol, _tf, _shift); + Print("value = \"", _value, "\", LastError: ", _LastError); + return _value; #else // __MQL5__ - int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; - double _res[]; - if (_handle == NULL || _handle == INVALID_HANDLE) { - if ((_handle = ::iAD(_symbol, _tf, VOLUME_TICK)) == 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, 0, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iAD(_symbol, _tf, VOLUME_TICK), 0, _shift); #endif } /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index e1516d4df..d61f173ad 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "Price/Indi_Price.mqh" #ifndef __MQL4__ @@ -38,24 +38,19 @@ struct IndiADXParams : IndicatorParams { unsigned int period; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - IndiADXParams(unsigned int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + IndiADXParams(unsigned int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) : period(_period), applied_price(_ap), IndicatorParams(INDI_ADX) { SetShift(_shift); if (custom_indi_name == "") { SetCustomIndicatorName("Examples\\ADX"); } }; - IndiADXParams(IndiADXParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; }; /** * Implements the Average Directional Movement Index indicator. */ -class Indi_ADX : public IndicatorTickOrCandleSource { +class Indi_ADX : public Indicator { protected: /* Protected methods */ @@ -67,15 +62,37 @@ class Indi_ADX : public IndicatorTickOrCandleSource { */ Indi_ADX(IndiADXParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_RANGE, _indi_src_mode), - _indi_src) { + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, + _indi_src_mode), + _indi_src) { Init(); } - Indi_ADX(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_ADX, _tf, _shift) { + + Indi_ADX(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiADXParams(), + IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, + _indi_src_mode), + _indi_src) { Init(); } + /** + * 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 | IDATA_ICUSTOM; } + + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return Indicator::IsValidEntry(_entry) && _entry.IsWithinRange(0.0, 100.0); + } /** * Returns the indicator value. @@ -90,7 +107,10 @@ class Indi_ADX : public IndicatorTickOrCandleSource { // MODE_PLUSDI/PLUSDI_LINE, 2 - MODE_MINUSDI/MINUSDI_LINE int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ - return ::iADX(_symbol, _tf, _period, _applied_price, _mode, _shift); + Print("We'll now retrieve value from ::iADX(", _symbol, ", ", EnumToString(_tf), ", ", _shift, ")..."); + double _value = ::iADX(_symbol, _tf, _period, _applied_price, _mode, _shift); + Print("value = \"", _value, "\", LastError: ", _LastError); + return _value; #else // __MQL5__ int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; double _res[]; @@ -123,7 +143,7 @@ class Indi_ADX : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -141,13 +161,6 @@ class Indi_ADX : public IndicatorTickOrCandleSource { return _value; } - /** - * Checks if indicator entry values are valid. - */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { - return Indicator::IsValidEntry(_entry) && _entry.IsWithinRange(0.0, 100.0); - } - /* Getters */ /** @@ -160,7 +173,7 @@ class Indi_ADX : public IndicatorTickOrCandleSource { * * Note: Not used in MT5. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 4d61bd5d4..6b5856d57 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -22,9 +22,9 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" +#include "../Storage/ValueStorage.applied_price.h" #include "../Storage/ValueStorage.h" -#include "../Storage/ValueStorage.price.h" #include "../Storage/ValueStorage.spread.h" #include "../Storage/ValueStorage.tick_volume.h" #include "../Storage/ValueStorage.time.h" @@ -36,47 +36,86 @@ // Structs. struct IndiADXWParams : IndiADXParams { // Struct constructor. - IndiADXWParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) - : IndiADXParams(_period, _ap, _shift, _tf) { + IndiADXWParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) + : IndiADXParams(_period, _ap, _shift) { itype = itype == INDI_NONE || itype == INDI_ADX ? INDI_ADXW : itype; - if (custom_indi_name == "" || custom_indi_name == "Examples\\ADX") { + if (custom_indi_name == "") { SetCustomIndicatorName("Examples\\ADXW"); } }; - IndiADXWParams(IndiADXWParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; }; /** * Implements the Average Directional Movement Index indicator by Welles Wilder. */ -class Indi_ADXW : public IndicatorTickOrCandleSource { +class Indi_ADXW : public Indicator { public: /** * Class constructor. */ Indi_ADXW(IndiADXWParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_RANGE, _indi_src_mode), - _indi_src){}; - Indi_ADXW(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_ADXW, _tf, _shift){}; + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, + _indi_src_mode), + _indi_src){}; + + Indi_ADXW(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiADXWParams(), + IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, + _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } /** - * Built-in version of ADX Wilder. + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // RS uses OHLC. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } + + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return _entry.IsWithinRange(0.0, 100.0); } + + /** + * Built-in or OnCalculate-based version of ADX Wilder. */ static double iADXWilder(string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, int _mode = LINE_MAIN_ADX, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iADXWilder(_symbol, _tf, _ma_period), _mode, _shift); #else - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_ADXW", _ma_period)); - return iADXWilderOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _ma_period, _mode, _shift, _cache); + if (_obj == nullptr) { + Print( + "Indi_ADXW::iADXWilder() can work without supplying pointer to IndicatorData only in MQL5. In this platform " + "the pointer is required."); + DebugBreak(); + return 0; + } + return iADXWilder(_obj, _ma_period, _mode, _shift); #endif } @@ -109,10 +148,8 @@ class Indi_ADXW : public IndicatorTickOrCandleSource { /** * On-indicator version of ADX Wilder. */ - static double iADXWilderOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, - int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, Util::MakeKey("Indi_ADXW_ON_" + _indi.GetFullName(), _period)); + static double iADXWilder(IndicatorData *_indi, int _period, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_period)); return iADXWilderOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, _shift, _cache); } @@ -228,20 +265,22 @@ class Indi_ADXW : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_ADXW::iADXWilder(GetSymbol(), GetTf(), GetPeriod(), _mode, _ishift, THIS_PTR); break; + case IDATA_ONCALCULATE: + _value = Indi_ADXW::iADXWilder(THIS_PTR, GetPeriod(), _mode, _ishift); + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, _mode, _ishift); break; case IDATA_INDICATOR: - _value = Indi_ADXW::iADXWilderOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod() /*]*/, _mode, - _ishift, THIS_PTR); + _value = Indi_ADXW::iADXWilder(THIS_PTR, GetPeriod(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index d8f686c9d..6fe75201c 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -22,10 +22,8 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" -#include "../Indicator/tests/classes/IndicatorTfDummy.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.h" -#include "../Storage/ValueStorage.price.h" #include "Price/Indi_Price.mqh" // Structs. @@ -42,35 +40,52 @@ struct IndiAMAParams : IndicatorParams { fast_period(_fast_period), slow_period(_slow_period), ama_shift(_ama_shift), - applied_price(_ap) { + applied_price(_ap), + IndicatorParams(INDI_AMA) { // Defaulting to on-indicator mode (will use real ticks from platform via IndicatorTickReal). SetShift(_shift); if (custom_indi_name == "") { SetCustomIndicatorName("Examples\\AMA"); } }; - IndiAMAParams(IndiAMAParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - } + IndiAMAParams(IndiAMAParams &_params) { THIS_REF = _params; } }; /** * Implements the AMA indicator. */ -class Indi_AMA : public IndicatorTickOrCandleSource { +class Indi_AMA : public Indicator { public: /** * Class constructor. */ Indi_AMA(IndiAMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src) { - iparams.SetIndicatorType(INDI_AMA); - }; - Indi_AMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AMA, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + + Indi_AMA(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiAMAParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + /** + * 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_AP | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { +#ifdef __MQL5__ + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; +#else + return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; +#endif + } /** * Built-in version of AMA. @@ -82,11 +97,14 @@ class Indi_AMA : public IndicatorTickOrCandleSource { INDICATOR_BUILTIN_CALL_AND_RETURN( ::iAMA(_symbol, _tf, _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, _ap), _mode, _shift); #else - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT( - _symbol, _tf, _ap, - Util::MakeKey("Indi_AMA", _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, (int)_ap)); - return iAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ama_period, _fast_ema_period, _slow_ema_period, - _ama_shift, _mode, _shift, _cache); + if (_obj == nullptr) { + Print( + "Indi_AMA::iAMA() can work without supplying pointer to IndicatorData only in MQL5. In this platform the " + "pointer is required."); + DebugBreak(); + return 0; + } + return iAMAOnIndicator(_obj, _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, _ap, _mode, _shift); #endif } @@ -115,13 +133,10 @@ class Indi_AMA : public IndicatorTickOrCandleSource { /** * On-indicator version of AMA. */ - static double iAMAOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ama_period, - int _fast_ema_period, int _slow_ema_period, int _ama_shift, ENUM_APPLIED_PRICE _ap, - int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS_SPECIFIC( - _indi, _symbol, _tf, _ap, - Util::MakeKey("Indi_AMA_ON_" + _indi.GetFullName(), _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, - (int)_ap)); + static double iAMAOnIndicator(IndicatorData *_indi, int _ama_period, int _fast_ema_period, int _slow_ema_period, + int _ama_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT( + _indi, _ap, Util::MakeKey(_ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, (int)_ap)); return iAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, _mode, _shift, _cache); } @@ -173,14 +188,6 @@ class Indi_AMA : public IndicatorTickOrCandleSource { CalculateInit(InpPeriodAMA, InpFastPeriodEMA, InpSlowPeriodEMA, InpShiftAMA, ExtFastSC, ExtSlowSC, ExtPeriodAMA, ExtSlowPeriodEMA, ExtFastPeriodEMA); - -#ifdef __debug__ - for (int x = prev_calculated; x < rates_total; ++x) { - Print("price[", x, "] = ", price[x].Get(), - ", O = ", iOpen(Symbol(), PERIOD_CURRENT, Bars(Symbol(), PERIOD_CURRENT) - x - 1)); - } -#endif - int i; // Check for rates count. if (rates_total < ExtPeriodAMA + begin) return (0); @@ -222,7 +229,7 @@ class Indi_AMA : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -235,10 +242,13 @@ class Indi_AMA : public IndicatorTickOrCandleSource { GetFastPeriod(), GetSlowPeriod(), GetAMAShift() /*]*/, _mode, _ishift); break; + case IDATA_ONCALCULATE: + _value = Indi_AMA::iAMAOnIndicator(THIS_PTR, /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), GetAMAShift(), + GetAppliedPrice() /*]*/, _mode, _ishift); + break; case IDATA_INDICATOR: - _value = Indi_AMA::iAMAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), - GetSlowPeriod(), GetAMAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, - THIS_PTR); + _value = Indi_AMA::iAMAOnIndicator(THIS_PTR, /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), GetAMAShift(), + GetAppliedPrice() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -285,7 +295,7 @@ class Indi_AMA : public IndicatorTickOrCandleSource { /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index c7d9671eb..24e05a3a3 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -38,16 +38,13 @@ struct IndiAOParams : IndicatorParams { SetCustomIndicatorName("Examples\\Awesome_Oscillator"); shift = _shift; }; - IndiAOParams(IndiAOParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiAOParams(IndiAOParams &_params) { THIS_REF = _params; }; }; /** * Implements the Awesome oscillator. */ -class Indi_AO : public IndicatorTickOrCandleSource { +class Indi_AO : public Indicator { protected: /* Protected methods */ @@ -68,14 +65,27 @@ class Indi_AO : public IndicatorTickOrCandleSource { */ Indi_AO(IndiAOParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) { + : Indicator(_p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { Init(); }; - Indi_AO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AO, _tf, _shift) { + Indi_AO(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiAOParams(), + IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { Init(); }; + /** + * 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; } + + public: + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -121,7 +131,7 @@ class Indi_AO : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -138,21 +148,21 @@ class Indi_AO : public IndicatorTickOrCandleSource { } /** - * Returns reusable indicator for a given symbol and time-frame. + * Returns reusable indicator with the same candle indicator as given indicator's one. */ - static Indi_AO *GetCached(string _symbol, ENUM_TIMEFRAMES _tf) { + static Indi_AO *GetCached(IndicatorData *_indi) { Indi_AO *_ptr; - string _key = Util::MakeKey(_symbol, (int)_tf); + // There will be only one Indi_AO per IndicatorCandle instance. + string _key = Util::MakeKey(_indi PTR_DEREF GetCandle() PTR_DEREF GetId()); if (!Objects::TryGet(_key, _ptr)) { - _ptr = Objects::Set(_key, new Indi_AO(_tf)); + _ptr = Objects::Set(_key, new Indi_AO()); + // Assigning the same candle indicator for AO as in _indi. + _ptr.SetDataSource(_indi PTR_DEREF GetCandle()); } return _ptr; } - /** * Checks if indicator entry values are valid. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { - return _entry.values[0].Get() != EMPTY_VALUE; - } + bool IsValidEntry(IndicatorDataEntry &_entry) override { return _entry.values[0].Get() != EMPTY_VALUE; } }; diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index 4c138f997..3137ae317 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" // Structs. @@ -30,21 +30,17 @@ struct IndiASIParams : IndicatorParams { unsigned int period; double mpc; // Struct constructor. - IndiASIParams(double _mpc = 300.0, int _shift = 0) : IndicatorParams(INDI_ASI, PERIOD_CURRENT) { + IndiASIParams(double _mpc = 300.0, int _shift = 0) : IndicatorParams(INDI_ASI) { SetCustomIndicatorName("Examples\\ASI"); mpc = _mpc; shift = _shift; }; - IndiASIParams(IndiASIParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; }; /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_ASI : public IndicatorTickOrCandleSource { +class Indi_ASI : public Indicator { protected: /* Protected methods */ @@ -63,21 +59,49 @@ class Indi_ASI : public IndicatorTickOrCandleSource { */ Indi_ASI(IndiASIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_ONCALCULATE, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) { + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { Init(); }; - Indi_ASI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_ASI, _tf, _shift) { + Indi_ASI(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_ONCALCULATE, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiASIParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { Init(); }; /** - * Built-in version of ASI. + * 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_CUSTOM | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + // RS uses OHLC. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } + + /** + * OnCalculate-based version of ASI as there is no built-in one. */ - static double iASI(string _symbol, ENUM_TIMEFRAMES _tf, double _mpc, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_ASI", _mpc)); + static double iASI(IndicatorData *_indi, double _mpc, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_mpc)); return iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mpc, _mode, _shift, _cache); } @@ -102,16 +126,6 @@ class Indi_ASI : public IndicatorTickOrCandleSource { return _cache.GetTailValue(_mode, _shift); } - /** - * On-indicator version of ASI. - */ - static double iASIOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, double _mpc, int _mode = 0, - int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, - Util::MakeKey("Indi_ASI_ON_" + _indi.GetFullName(), _mpc)); - return iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mpc, _mode, _shift, _cache); - } - /** * OnInit() method for ASI indicator. */ @@ -149,9 +163,18 @@ class Indi_ASI : public IndicatorTickOrCandleSource { ExtSIBuffer[0] = 0.0; ExtTRBuffer[0] = high[0] - low[0]; } + + // Print("- ASI cycle " + IntegerToString(pos) + " - " + IntegerToString(rates_total)); + // Main cycle. for (int i = pos; i < rates_total && !IsStopped(); i++) { // Get some data. + + // Print("Prev: "+ StringifyOHLC(open, high, low, close, i-3)); + // Print("Prev: "+ StringifyOHLC(open, high, low, close, i-2)); + // Print("Prev: "+ StringifyOHLC(open, high, low, close, i-1)); + // Print("Curr: "+ StringifyOHLC(open, high, low, close, i)); + double dPrevClose = close[i - 1].Get(); double dPrevOpen = open[i - 1].Get(); double dClose = close[i].Get(); @@ -183,23 +206,20 @@ class Indi_ASI : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { + case IDATA_BUILTIN: case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetMaximumPriceChanging() /*]*/, 0, _ishift); break; - case IDATA_ONCALCULATE: { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(GetSymbol(), GetTf(), - Util::MakeKey("Indi_ASI", GetMaximumPriceChanging())); - _value = - iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, GetMaximumPriceChanging(), _mode, _ishift, _cache); - } break; + case IDATA_ONCALCULATE: + _value = Indi_ASI::iASI(THIS_PTR, GetMaximumPriceChanging(), _mode, _ishift); + break; case IDATA_INDICATOR: - _value = Indi_ASI::iASIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetMaximumPriceChanging() /*]*/, - _mode, _ishift, THIS_PTR); + _value = Indi_ASI::iASI(THIS_PTR, GetMaximumPriceChanging(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index 56f509842..fc3b68387 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -39,10 +39,7 @@ struct IndiATRParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\ATR"); }; - IndiATRParams(IndiATRParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiATRParams(IndiATRParams &_params) { THIS_REF = _params; }; }; /** @@ -50,17 +47,29 @@ struct IndiATRParams : IndicatorParams { * * Note: It doesn't give independent signals. It is used to define volatility (trend strength). */ -class Indi_ATR : public IndicatorTickOrCandleSource { +class Indi_ATR : public Indicator { public: /** * Class constructor. */ Indi_ATR(IndiATRParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) {} - Indi_ATR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_ATR, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_ATR(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiATRParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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 | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -105,7 +114,7 @@ class Indi_ATR : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -122,15 +131,17 @@ class Indi_ATR : public IndicatorTickOrCandleSource { } /** - * Returns reusable indicator for a given parameters. + * Returns reusable indicator with the same candle indicator as given indicator's one. */ - static Indi_ATR *GetCached(string _symbol, ENUM_TIMEFRAMES _tf, int _period) { + static Indi_ATR *GetCached(IndicatorData *_indi, int _period) { Indi_ATR *_ptr; - string _key = Util::MakeKey(_symbol, (int)_tf, _period); + // There will be only one Indi_ATR per IndicatorCandle instance. + string _key = Util::MakeKey(_indi PTR_DEREF GetCandle() PTR_DEREF GetId()); if (!Objects::TryGet(_key, _ptr)) { - IndiATRParams _p(_period, _tf); - _ptr = Objects::Set(_key, new Indi_ATR(_p)); - _ptr.SetSymbol(_symbol); + IndiATRParams _params(_period); + _ptr = Objects::Set(_key, new Indi_ATR(_params)); + // Assigning the same candle indicator for ATR as in _indi. + _ptr.SetDataSource(_indi PTR_DEREF GetCandle()); } return _ptr; } diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index 5631250c0..d24872c06 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -85,27 +85,37 @@ struct IndiAlligatorParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\Alligator"); }; - IndiAlligatorParams(IndiAlligatorParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiAlligatorParams(IndiAlligatorParams &_params) { THIS_REF = _params; }; }; /** * Implements the Alligator indicator. */ -class Indi_Alligator : public IndicatorTickOrCandleSource { +class Indi_Alligator : public Indicator { public: /** * Class constructor. */ Indi_Alligator(IndiAlligatorParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( + : Indicator( _p, IndicatorDataParams::GetInstance(FINAL_ALLIGATOR_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE), _indi_src, _indi_src_mode) {} - Indi_Alligator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_ADX, _tf, _shift){}; + Indi_Alligator(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator( + IndiAlligatorParams(), + IndicatorDataParams::GetInstance(FINAL_ALLIGATOR_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE), + _indi_src, _indi_src_mode){}; + /** + * 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 | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -165,7 +175,7 @@ class Indi_Alligator : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); #ifdef __MQL4__ @@ -241,7 +251,7 @@ class Indi_Alligator : public IndicatorTickOrCandleSource { /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Class setters */ diff --git a/Indicators/Indi_AppliedPrice.mqh b/Indicators/Indi_AppliedPrice.mqh index 30c0169a8..ed319b117 100644 --- a/Indicators/Indi_AppliedPrice.mqh +++ b/Indicators/Indi_AppliedPrice.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "OHLC/Indi_OHLC.mqh" // Structs. @@ -33,16 +33,13 @@ struct IndiAppliedPriceParams : IndicatorParams { : applied_price(_applied_price), IndicatorParams(INDI_APPLIED_PRICE) { shift = _shift; }; - IndiAppliedPriceParams(IndiAppliedPriceParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiAppliedPriceParams(IndiAppliedPriceParams &_params) { THIS_REF = _params; }; }; /** * Implements the "Applied Price over OHCL Indicator" indicator, e.g. over Indi_Price. */ -class Indi_AppliedPrice : public IndicatorTickOrCandleSource { +class Indi_AppliedPrice : public Indicator { protected: void OnInit() { if (!indi_src.IsSet()) { @@ -57,16 +54,30 @@ class Indi_AppliedPrice : public IndicatorTickOrCandleSource= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_INDICATOR: if (HasDataSource()) { - // Future validation of indi_src will check if we set mode for source indicator - // (e.g. for applied price of Indi_Price). - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE), GetAppliedPrice()); _value = Indi_AppliedPrice::iAppliedPriceOnIndicator(GetDataSource(), GetAppliedPrice(), _ishift); } break; @@ -119,7 +127,7 @@ class Indi_AppliedPrice : public IndicatorTickOrCandleSource { +class Indi_BWMFI : public Indicator { protected: /* Protected methods */ @@ -76,17 +73,32 @@ class Indi_BWMFI : public IndicatorTickOrCandleSource { */ Indi_BWMFI(IndiBWIndiMFIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_BWMFI_BUFFER_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) { + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_BWMFI_BUFFER_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, + _indi_src_mode), + _indi_src) { Init(); } - Indi_BWMFI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_BWMFI, _tf, _shift) { + Indi_BWMFI(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiBWIndiMFIParams(), + IndicatorDataParams::GetInstance(FINAL_BWMFI_BUFFER_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, + _indi_src_mode), + _indi_src) { Init(); } + /** + * 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; } + + public: + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_ICUSTOM; } + /** * Returns the indicator value. * @@ -130,10 +142,9 @@ class Indi_BWMFI : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = BWMFI_BUFFER, int _shift = 0) { - int _ishift = iparams.GetShift() + _shift; - + virtual IndicatorDataEntryValue GetEntryValue(int _mode = BWMFI_BUFFER, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: @@ -153,8 +164,8 @@ class Indi_BWMFI : public IndicatorTickOrCandleSource { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { - Indicator::GetEntryAlter(_entry); + void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { + Indicator::GetEntryAlter(_entry, _shift); #ifdef __MQL4__ // @see: https://en.wikipedia.org/wiki/Market_facilitation_index bool _vol_up = GetVolume(_shift) > GetVolume(_shift); diff --git a/Indicators/Indi_BWZT.mqh b/Indicators/Indi_BWZT.mqh index 8164b5f5b..e6d9c6c80 100644 --- a/Indicators/Indi_BWZT.mqh +++ b/Indicators/Indi_BWZT.mqh @@ -52,23 +52,20 @@ struct IndiBWZTParams : IndicatorParams { SetCustomIndicatorName("Examples\\BW-ZoneTrade"); shift = _shift; }; - IndiBWZTParams(IndiBWZTParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiBWZTParams(IndiBWZTParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bill Williams' Zone Trade. */ -class Indi_BWZT : public IndicatorTickOrCandleSource { +class Indi_BWZT : public Indicator { protected: /* Protected methods */ /** * Initialize. */ - void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_INDI_BWZT_MODE_ENTRY); } + void Init() {} public: /** @@ -76,25 +73,59 @@ class Indi_BWZT : public IndicatorTickOrCandleSource { */ Indi_BWZT(IndiBWZTParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_INDI_BWZT_MODE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) { + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_BWZT_MODE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, + _indi_src_mode), + _indi_src) { Init(); }; - Indi_BWZT(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_BWZT, _tf, _shift) { + Indi_BWZT(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiBWZTParams(), + IndicatorDataParams::GetInstance(FINAL_INDI_BWZT_MODE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, + _indi_src_mode), + _indi_src) { Init(); }; /** - * Built-in version of BWZT. + * 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_CUSTOM | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // RS uses OHLC. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } + + /** + * OnCalculate-based version of BWZT as there is no built-in one. */ - static double iBWZT(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_BWZT"); + static double iBWZT(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); + + // Will return Indi_AC with the same candles source as _indi's. + Indi_AC *_indi_ac = Indi_AC::GetCached(_indi); - Indi_AC *_indi_ac = Indi_AC::GetCached(_symbol, _tf); - Indi_AO *_indi_ao = Indi_AO::GetCached(_symbol, _tf); + // Will return Indi_AO with the same candles source as _indi's. + Indi_AO *_indi_ao = Indi_AO::GetCached(_indi); return iBWZTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache, _indi_ac, _indi_ao); } @@ -128,8 +159,7 @@ class Indi_BWZT : public IndicatorTickOrCandleSource { */ static double iBWZTOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode, int _shift, IndicatorData *_obj) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, - Util::MakeKey("Indi_BWZT_ON_" + _indi.GetFullName())); + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey("Indi_BWZT_ON_" + _indi.GetFullName())); Indi_AC *_indi_ac = _obj.GetDataSource(INDI_AC); Indi_AO *_indi_ao = _obj.GetDataSource(INDI_AO); @@ -221,18 +251,19 @@ class Indi_BWZT : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_BWZT::iBWZT(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = Indi_BWZT::iBWZT(THIS_PTR, _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; case IDATA_INDICATOR: - _value = Indi_BWZT::iBWZTOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + _value = Indi_BWZT::iBWZT(THIS_PTR, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index b9ba9f938..f9a414031 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "Indi_CCI.mqh" #include "Indi_Envelopes.mqh" #include "Indi_MA.mqh" @@ -72,16 +72,13 @@ struct IndiBandsParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\BB"); }; - IndiBandsParams(IndiBandsParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiBandsParams(IndiBandsParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bollinger Bands® indicator. */ -class Indi_Bands : public IndicatorTickSource { +class Indi_Bands : public Indicator { protected: /* Protected methods */ @@ -96,16 +93,36 @@ class Indi_Bands : public IndicatorTickSource { */ Indi_Bands(IndiBandsParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickSource(_p, - IndicatorDataParams::GetInstance(FINAL_BANDS_LINE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src) { + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_BANDS_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, + _indi_src_mode), + _indi_src) { Init(); } - Indi_Bands(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_BANDS, _tf, _shift) { + Indi_Bands(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiBandsParams(), + IndicatorDataParams::GetInstance(FINAL_BANDS_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, + _indi_src_mode), + _indi_src) { Init(); } + /** + * 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_AP | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + public: + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } + /** * Returns the indicator value. * @@ -143,52 +160,52 @@ class Indi_Bands : public IndicatorTickSource { if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; } + return _res[0]; #endif } /** * Calculates Bands on another indicator. - * - * When _applied_price is set to -1, method will */ - static double iBandsOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, - double _deviation, int _bands_shift, + static double iBandsOnIndicator(IndicatorData *_target, IndicatorData *_source, string _symbol, ENUM_TIMEFRAMES _tf, + unsigned int _period, double _deviation, int _bands_shift, ENUM_APPLIED_PRICE _ap, ENUM_BANDS_LINE _mode, // (MT4/MT5): 0 - MODE_MAIN/BASE_LINE, 1 - // MODE_UPPER/UPPER_BAND, 2 - MODE_LOWER/LOWER_BAND - int _shift, Indi_Bands *_target = NULL) { + int _shift, IndicatorData *_indi_source = NULL) { double _indi_value_buffer[]; double _std_dev; double _line_value; - ArrayResize(_indi_value_buffer, _period); + ValueStorage *_indi_applied_price = _source PTR_DEREF GetSpecificAppliedPriceValueStorage(_ap, _target); - for (int i = _bands_shift; i < (int)_period; i++) { - int current_shift = _shift + (i - _bands_shift); - // Getting current indicator value. - _indi_value_buffer[i - _bands_shift] = - _indi[i - _bands_shift] - .values[_target != NULL ? _target.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)) : 0] - .Get(); - } + // Period can't be higher than number of available bars. + _period = MathMin(_period, ArraySize(_indi_applied_price)); - // Base band. - _line_value = Indi_MA::SimpleMA(_shift, _period, _indi_value_buffer); + ArrayCopy(_indi_value_buffer, _indi_applied_price, 0, _bands_shift + _shift, _period); + + // Base band. Calculating MA from "_period" number of values or less. + _line_value = Indi_MA::SimpleMA(0, _period, _indi_value_buffer); // Standard deviation. _std_dev = Indi_StdDev::iStdDevOnArray(_indi_value_buffer, _line_value, _period); + double _result = EMPTY_VALUE; + switch (_mode) { case BAND_BASE: // Already calculated. - return _line_value; + _result = _line_value; + break; case BAND_UPPER: - return _line_value + /* band deviations */ _deviation * _std_dev; + _result = _line_value + /* band deviations */ _deviation * _std_dev; + break; case BAND_LOWER: - return _line_value - /* band deviations */ _deviation * _std_dev; + _result = _line_value - /* band deviations */ _deviation * _std_dev; + break; } - return EMPTY_VALUE; + return _result; } static double iBandsOnArray(double &array[], int total, int period, double deviation, int bands_shift, int mode, @@ -196,8 +213,13 @@ class Indi_Bands : public IndicatorTickSource { #ifdef __MQL4__ return ::iBandsOnArray(array, total, period, deviation, bands_shift, mode, shift); #else // __MQL5__ - Indi_PriceFeeder price_feeder(array); - return iBandsOnIndicator(&price_feeder, NULL, NULL, period, deviation, bands_shift, (ENUM_BANDS_LINE)mode, shift); + static Ref price_feeder = new Indi_PriceFeeder(); + price_feeder REF_DEREF SetPrices(array); + price_feeder REF_DEREF SetDataSourceAppliedPrice(INDI_VS_TYPE_INDEX_0); + // First parameter is a pointer to target indicator. It is used to override applied price, so we configure it on the + // price feeder itself and pass it as both, target and source indicator. + return iBandsOnIndicator(price_feeder.Ptr(), price_feeder.Ptr(), NULL, NULL, period, deviation, bands_shift, + (ENUM_APPLIED_PRICE)0 /* unused */, (ENUM_BANDS_LINE)mode, shift); #endif } @@ -252,7 +274,7 @@ class Indi_Bands : public IndicatorTickSource { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = BAND_BASE, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = BAND_BASE, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -260,14 +282,20 @@ class Indi_Bands : public IndicatorTickSource { _value = Indi_Bands::iBands(GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, _ishift, THIS_PTR); break; + case IDATA_ONCALCULATE: + _value = + Indi_Bands::iBandsOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), + GetBandsShift(), GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, _ishift); + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), GetBandsShift(), GetDeviation(), GetAppliedPrice() /* ] */, _mode, _ishift); break; case IDATA_INDICATOR: // Calculating bands value from specified indicator. - _value = Indi_Bands::iBandsOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), - GetBandsShift(), (ENUM_BANDS_LINE)_mode, _ishift, THIS_PTR); + _value = Indi_Bands::iBandsOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), + GetDeviation(), GetBandsShift(), GetAppliedPrice(), + (ENUM_BANDS_LINE)_mode, _ishift, THIS_PTR); break; } return _value; @@ -285,27 +313,33 @@ class Indi_Bands : public IndicatorTickSource { * Provides built-in indicators whose can be used as data source. */ virtual IndicatorData *FetchDataSource(ENUM_INDICATOR_TYPE _id) { + IndicatorData *_result = NULL; if (_id == INDI_BANDS) { IndiBandsParams bands_params(); - return new Indi_Bands(bands_params); + _result = Indi_Bands(bands_params); } else if (_id == INDI_CCI) { IndiCCIParams cci_params(); - return new Indi_CCI(cci_params); + _result = new Indi_CCI(cci_params); } else if (_id == INDI_ENVELOPES) { IndiEnvelopesParams env_params(); - return new Indi_Envelopes(env_params); + _result = new Indi_Envelopes(env_params); } else if (_id == INDI_MOMENTUM) { IndiMomentumParams mom_params(); - return new Indi_Momentum(mom_params); + _result = new Indi_Momentum(mom_params); } else if (_id == INDI_MA) { IndiMAParams ma_params(); - return new Indi_MA(ma_params); + _result = new Indi_MA(ma_params); } else if (_id == INDI_RSI) { IndiRSIParams _rsi_params(); - return new Indi_RSI(_rsi_params); + _result = new Indi_RSI(_rsi_params); } else if (_id == INDI_STDDEV) { IndiStdDevParams stddev_params(); - return new Indi_StdDev(stddev_params); + _result = new Indi_StdDev(stddev_params); + } + + if (_result != nullptr) { + _result.SetDataSource(GetCandle()); + return _result; } return IndicatorData::FetchDataSource(_id); @@ -331,7 +365,7 @@ class Indi_Bands : public IndicatorTickSource { /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index ce01fd901..4cb9cd79d 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -41,27 +41,35 @@ struct IndiBearsPowerParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\Bears"); }; - IndiBearsPowerParams(IndiBearsPowerParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiBearsPowerParams(IndiBearsPowerParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bears Power indicator. */ -class Indi_BearsPower : public IndicatorTickOrCandleSource { +class Indi_BearsPower : public Indicator { public: /** * Class constructor. */ Indi_BearsPower(IndiBearsPowerParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) {} - Indi_BearsPower(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_BEARS, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_BearsPower(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiBearsPowerParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -107,7 +115,7 @@ class Indi_BearsPower : public IndicatorTickOrCandleSource /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -136,7 +144,7 @@ class Indi_BearsPower : public IndicatorTickOrCandleSource * * Note: Not used in MT5. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index d9a624724..3b599acd2 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -41,27 +41,35 @@ struct IndiBullsPowerParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\Bulls"); }; - IndiBullsPowerParams(IndiBullsPowerParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiBullsPowerParams(IndiBullsPowerParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bulls Power indicator. */ -class Indi_BullsPower : public IndicatorTickOrCandleSource { +class Indi_BullsPower : public Indicator { public: /** * Class constructor. */ Indi_BullsPower(IndiBullsPowerParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) {} - Indi_BullsPower(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_BULLS, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_BullsPower(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiBullsPowerParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -107,7 +115,7 @@ class Indi_BullsPower : public IndicatorTickOrCandleSource /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -136,7 +144,7 @@ class Indi_BullsPower : public IndicatorTickOrCandleSource * * Note: Not used in MT5. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index eeba6f603..ed6aee388 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickSource.h" +#include "../Indicator.mqh" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" #include "Price/Indi_Price.mqh" @@ -48,26 +48,39 @@ struct IndiCCIParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\CCI"); }; - IndiCCIParams(IndiCCIParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiCCIParams(IndiCCIParams &_params) { THIS_REF = _params; }; }; /** * Implements the Commodity Channel Index indicator. */ -class Indi_CCI : public IndicatorTickSource { +class Indi_CCI : public Indicator { public: /** * Class constructor. */ Indi_CCI(IndiCCIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) {} - Indi_CCI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_CCI, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_CCI(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiCCIParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + /** + * 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_AP | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } /** * Returns the indicator value. @@ -148,7 +161,7 @@ class Indi_CCI : public IndicatorTickSource { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); double _value = EMPTY_VALUE; switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -157,6 +170,11 @@ class Indi_CCI : public IndicatorTickSource { _value = Indi_CCI::iCCI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift /* + iparams.shift*/, THIS_PTR); break; + case IDATA_ONCALCULATE: + // @fixit Somehow shift isn't used neither in MT4 nor MT5. + _value = + Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), _ishift /* + iparams.shift*/); + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), GetAppliedPrice() /* ] */, 0, _ishift); @@ -165,9 +183,8 @@ class Indi_CCI : public IndicatorTickSource { ValidateSelectedDataSource(); // @fixit Somehow shift isn't used neither in MT4 nor MT5. - _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), - Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)), - _ishift /* + iparams.shift*/); + _value = + Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), _ishift /* + iparams.shift*/); break; } return _value; @@ -183,7 +200,7 @@ class Indi_CCI : public IndicatorTickSource { /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index b6e6127f3..267fe5288 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" #include "../Util.h" #include "Indi_MA.mqh" @@ -44,27 +44,37 @@ struct IndiCHOParams : IndicatorParams { slow_ma = _slow_ma; smooth_method = _smooth_method; }; - IndiCHOParams(IndiCHOParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiCHOParams(IndiCHOParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_CHO : public IndicatorTickOrCandleSource { +class Indi_CHO : public Indicator { public: /** * Class constructor. */ Indi_CHO(IndiCHOParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_CHO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_CHAIKIN, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_CHO(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiCHOParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CANDLE | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } /** * Built-in version of Chaikin Oscillator. @@ -76,8 +86,15 @@ class Indi_CHO : public IndicatorTickOrCandleSource { INDICATOR_BUILTIN_CALL_AND_RETURN(::iChaikin(_symbol, _tf, _fast_ma_period, _slow_ma_period, _ma_method, _av), _mode, _shift); #else + if (_obj == nullptr) { + Print( + "Indi_CHO::iChaikin() can work without supplying pointer to IndicatorData only in MQL5. In this platform the " + "pointer is required."); + DebugBreak(); + return 0; + } INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( - _symbol, _tf, Util::MakeKey("Indi_CHO", _fast_ma_period, _slow_ma_period, (int)_ma_method, (int)_av)); + _obj, Util::MakeKey(_fast_ma_period, _slow_ma_period, (int)_ma_method, (int)_av)); return iChaikinOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _fast_ma_period, _slow_ma_period, _ma_method, _av, _mode, _shift, _cache); #endif @@ -109,13 +126,10 @@ class Indi_CHO : public IndicatorTickOrCandleSource { /** * On-indicator version of Chaikin Oscillator. */ - static double iChaikinOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _fast_ma_period, - int _slow_ma_period, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_VOLUME _av, - int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, - Util::MakeKey("Indi_CHO_ON_" + _indi.GetFullName(), _fast_ma_period, _slow_ma_period, (int)_ma_method, - (int)_av)); + static double iChaikinOnIndicator(IndicatorData *_indi, int _fast_ma_period, int _slow_ma_period, + ENUM_MA_METHOD _ma_method, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( + _indi, Util::MakeKey(_fast_ma_period, _slow_ma_period, (int)_ma_method, (int)_av)); return iChaikinOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _fast_ma_period, _slow_ma_period, _ma_method, _av, _mode, _shift, _cache); } @@ -184,11 +198,12 @@ class Indi_CHO : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: + case IDATA_ONCALCULATE: _value = Indi_CHO::iChaikin(GetSymbol(), GetTf(), /*[*/ GetSlowMA(), GetFastMA(), GetSmoothMethod(), GetInputVolume() /*]*/, _mode, _ishift, THIS_PTR); break; @@ -197,8 +212,8 @@ class Indi_CHO : public IndicatorTickOrCandleSource { GetSlowMA(), GetSmoothMethod(), GetInputVolume() /*]*/, 0, _ishift); break; case IDATA_INDICATOR: - _value = Indi_CHO::iChaikinOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetFastMA(), GetSlowMA(), - GetSmoothMethod(), GetInputVolume() /*]*/, _mode, _ishift, THIS_PTR); + _value = Indi_CHO::iChaikinOnIndicator(GetDataSource(), /*[*/ GetFastMA(), GetSlowMA(), GetSmoothMethod(), + GetInputVolume() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index 678df5af0..2e6c56531 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" #include "../Util.h" #include "Indi_MA.mqh" @@ -45,35 +45,58 @@ struct IndiCHVParams : IndicatorParams { smooth_method = _smooth_method; smooth_period = _smooth_period; }; - IndiCHVParams(IndiCHVParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiCHVParams(IndiCHVParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_CHV : public IndicatorTickOrCandleSource { +class Indi_CHV : public Indicator { public: /** * Class constructor. */ Indi_CHV(IndiCHVParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_CHV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_CHAIKIN_V, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_CHV(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiCHVParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // CHV uses high and low prices only. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW); + } /** - * Built-in version of Chaikin Volatility. + * OnCalculate-based version of Chaikin Volatility as there is no built-in one. */ - static double iCHV(string _symbol, ENUM_TIMEFRAMES _tf, int _smooth_period, int _chv_period, - ENUM_CHV_SMOOTH_METHOD _smooth_method, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( - _symbol, _tf, Util::MakeKey("Indi_CHV", _smooth_period, _chv_period, _smooth_method)); + double iCHV(IndicatorData *_indi, int _smooth_period, int _chv_period, ENUM_CHV_SMOOTH_METHOD _smooth_method, + int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, + Util::MakeKey(_smooth_period, _chv_period, _smooth_method)); return iCHVOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _smooth_period, _chv_period, _smooth_method, _mode, _shift, _cache); } @@ -103,19 +126,6 @@ class Indi_CHV : public IndicatorTickOrCandleSource { return _cache.GetTailValue(_mode, _shift); } - /** - * On-indicator version of Chaikin Volatility. - */ - static double iCHVOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _smooth_period, - int _chv_period, ENUM_CHV_SMOOTH_METHOD _smooth_method, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, - Util::MakeKey("Indi_CHV_ON_" + _indi.GetFullName(), _smooth_period, _chv_period, _smooth_method)); - return iCHVOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _smooth_period, _chv_period, _smooth_method, _mode, - _shift, _cache); - } - /** * OnInit() method for Chaikin Volatility indicator. */ @@ -179,21 +189,20 @@ class Indi_CHV : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_CHV::iCHV(GetSymbol(), GetTf(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/, - _mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = iCHV(THIS_PTR, GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod(), _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _ishift); break; case IDATA_INDICATOR: - _value = Indi_CHV::iCHVOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetSmoothPeriod(), - GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _ishift, THIS_PTR); + _value = iCHV(THIS_PTR, GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index 1fcdc3584..d7a1755e7 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" // Structs. @@ -32,34 +32,43 @@ struct IndiColorBarsParams : IndicatorParams { SetCustomIndicatorName("Examples\\ColorBars"); shift = _shift; }; - IndiColorBarsParams(IndiColorBarsParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiColorBarsParams(IndiColorBarsParams &_params) { THIS_REF = _params; }; }; /** * Implements Color Bars */ -class Indi_ColorBars : public IndicatorTickOrCandleSource { +class Indi_ColorBars : public Indicator { public: /** * Class constructor. */ Indi_ColorBars(IndiColorBarsParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(5, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_ColorBars(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_COLOR_BARS, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(5, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_ColorBars(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiColorBarsParams(), + IndicatorDataParams::GetInstance(5, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CANDLE | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } /** - * "Built-in" version of Color Bars. + * OnCalculate-based version of Color Bars as there is no built-in one. */ - static double iColorBars(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_ColorBars"); + static double iColorBars(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); return iColorBarsOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -85,16 +94,6 @@ class Indi_ColorBars : public IndicatorTickOrCandleSource { return _cache.GetTailValue(_mode, _shift); } - /** - * On-indicator version of Color Bars. - */ - static double iColorBarsOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, - int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, - Util::MakeKey("Indi_ColorBars_ON_" + _indi.GetFullName())); - return iColorBarsOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); - } - /** * OnCalculate() method for Color Bars indicator. */ @@ -126,18 +125,19 @@ class Indi_ColorBars : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_ColorBars::iColorBars(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = Indi_ColorBars::iColorBars(THIS_PTR, _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; case IDATA_INDICATOR: - _value = Indi_ColorBars::iColorBarsOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + _value = Indi_ColorBars::iColorBars(THIS_PTR, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index ac97914ef..c156e0a98 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" // Structs. @@ -32,33 +32,56 @@ struct IndiColorCandlesDailyParams : IndicatorParams { SetCustomIndicatorName("Examples\\ColorCandlesDaily"); shift = _shift; }; - IndiColorCandlesDailyParams(IndiColorCandlesDailyParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiColorCandlesDailyParams(IndiColorCandlesDailyParams &_params) { THIS_REF = _params; }; }; /** * Implements Color Bars */ -class Indi_ColorCandlesDaily : public IndicatorTickOrCandleSource { +class Indi_ColorCandlesDaily : public Indicator { public: /** * Class constructor. */ Indi_ColorCandlesDaily(IndiColorCandlesDailyParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(5, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_ColorCandlesDaily(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_COLOR_CANDLES_DAILY, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(5, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_ColorCandlesDaily(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : Indicator(IndiColorCandlesDailyParams(), + IndicatorDataParams::GetInstance(5, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // Volume uses volume only. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } /** - * "Built-in" version of Color Candles Daily. + * OnCalculate-based version of Color Candles Daily as there is no built-in one. */ - static double iCCD(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_ColorCandlesDaily"); + static double iCCD(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); return iCCDOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -84,16 +107,6 @@ class Indi_ColorCandlesDaily : public IndicatorTickOrCandleSource(_mode, _shift); } - /** - * On-indicator version of Color Candles Daily. - */ - static double iCCDOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, - int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, Util::MakeKey("Indi_ColorCandlesDaily_ON_" + _indi.GetFullName())); - return iCCDOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); - } - /** * OnCalculate() method for Color Candles Daily indicator. */ @@ -122,19 +135,19 @@ class Indi_ColorCandlesDaily : public IndicatorTickOrCandleSource= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_ColorCandlesDaily::iCCD(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = Indi_ColorCandlesDaily::iCCD(THIS_PTR, _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; case IDATA_INDICATOR: - _value = - Indi_ColorCandlesDaily::iCCDOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + _value = Indi_ColorCandlesDaily::iCCD(THIS_PTR, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index 8645ceefb..cf3fa6b4a 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" #include "Indi_MA.mqh" @@ -35,37 +35,58 @@ struct IndiColorLineParams : IndicatorParams { SetCustomIndicatorName("Examples\\ColorLine"); shift = _shift; }; - IndiColorLineParams(IndiColorLineParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiColorLineParams(IndiColorLineParams &_params) { THIS_REF = _params; }; }; /** * Implements Color Bars */ -class Indi_ColorLine : public IndicatorTickOrCandleSource { +class Indi_ColorLine : public Indicator { public: /** * Class constructor. */ Indi_ColorLine(IndiColorLineParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_ColorLine(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_COLOR_LINE, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_ColorLine(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiColorLineParams(), + IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + * + * @fixit Should require Candle data source? + */ + unsigned int GetSuitableDataSourceTypes() override { return INDI_SUITABLE_DS_TYPE_CANDLE; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } /** - * "Built-in" version of Color Line. + * Checks whether given data source satisfies our requirements. */ - static double iColorLine(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_ColorLine"); + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } - Indi_MA *_indi_ma = Indi_MA::GetCached(_symbol, _tf, 10, 0, MODE_EMA, PRICE_CLOSE); + // Volume uses volume only. + return _ds PTR_DEREF HasSpecificValueStorage(INDI_VS_TYPE_VOLUME); + } + /** + * OnCalculate-based version of Color Line as there is no built-in one. + */ + static double iColorLine(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); + // Will return Indi_MA with the same candles source as _indi's. + // @fixit There should be Candle attached to MA! + Indi_MA *_indi_ma = Indi_MA::GetCached(_indi, 10, 0, MODE_EMA, PRICE_CLOSE); return iColorLineOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache, _indi_ma); } @@ -94,13 +115,9 @@ class Indi_ColorLine : public IndicatorTickOrCandleSource { /** * On-indicator version of Color Line. */ - static double iColorLineOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, - int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, - Util::MakeKey("Indi_ColorLine_ON_" + _indi.GetFullName())); - + static double iColorLineOnIndicator(IndicatorData *_indi, int _mode, int _shift, IndicatorData *_obj) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); Indi_MA *_indi_ma = _obj.GetDataSource(INDI_MA); - return iColorLineOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache, _indi_ma); } @@ -201,18 +218,19 @@ class Indi_ColorLine : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_ColorLine::iColorLine(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = iColorLine(THIS_PTR, _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; case IDATA_INDICATOR: - _value = Indi_ColorLine::iColorLineOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + _value = iColorLine(THIS_PTR, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_CustomMovingAverage.mqh b/Indicators/Indi_CustomMovingAverage.mqh index 06b061ac6..1e997dc45 100644 --- a/Indicators/Indi_CustomMovingAverage.mqh +++ b/Indicators/Indi_CustomMovingAverage.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" // Structs. struct IndiCustomMovingAverageParams : IndicatorParams { @@ -45,32 +45,41 @@ struct IndiCustomMovingAverageParams : IndicatorParams { smooth_period = _smooth_period; smooth_shift = _smooth_shift; }; - IndiCustomMovingAverageParams(IndiCustomMovingAverageParams& _params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiCustomMovingAverageParams(IndiCustomMovingAverageParams& _params) { THIS_REF = _params; }; }; /** * Implements the Custom Moving Average indicator. */ -class Indi_CustomMovingAverage : public IndicatorTickOrCandleSource { +class Indi_CustomMovingAverage : public Indicator { public: /** * Class constructor. */ Indi_CustomMovingAverage(IndiCustomMovingAverageParams& _p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_ICUSTOM, IndicatorData* _indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src){}; - Indi_CustomMovingAverage(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_CUSTOM_MOVING_AVG, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + Indi_CustomMovingAverage(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_ICUSTOM, + IndicatorData* _indi_src = NULL, int _indi_src_mode = 0) + : Indicator(IndiCustomMovingAverageParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + + /** + * 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_ICUSTOM; } /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index 8aa8ec7bd..1229b059c 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -24,10 +24,17 @@ #ifndef INDI_DEMA_MQH #define INDI_DEMA_MQH +// Defines. +#ifdef __MQL5__ +#define INDI_DEMA_DEFAULT_IDSTYPE IDATA_BUILTIN +#else +#define INDI_DEMA_DEFAULT_IDSTYPE IDATA_ONCALCULATE +#endif + // Includes. #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Refs.mqh" #include "../Storage/Objects.h" #include "../Storage/ValueStorage.h" @@ -36,12 +43,12 @@ #include "Price/Indi_Price.mqh" // Structs. -struct IndiDEIndiMAParams : IndicatorParams { +struct IndiDEMAParams : IndicatorParams { int ma_shift; unsigned int period; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - IndiDEIndiMAParams(unsigned int _period = 14, int _ma_shift = 0, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + IndiDEMAParams(unsigned int _period = 14, int _ma_shift = 0, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) : period(_period), ma_shift(_ma_shift), applied_price(_ap), IndicatorParams(INDI_DEMA) { SetCustomIndicatorName("Examples\\DEMA"); SetShift(_shift); @@ -49,27 +56,40 @@ struct IndiDEIndiMAParams : IndicatorParams { SetCustomIndicatorName("Examples\\DEMA"); } }; - IndiDEIndiMAParams(IndiDEIndiMAParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiDEMAParams(IndiDEMAParams &_params) { THIS_REF = _params; }; }; /** * Implements the Moving Average indicator. */ -class Indi_DEMA : public IndicatorTickOrCandleSource { +class Indi_DEMA : public Indicator { public: /** * Class constructor. */ - Indi_DEMA(IndiDEIndiMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, - int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src) {} - Indi_DEMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_DEMA, _tf, _shift) {} + Indi_DEMA(IndiDEMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = INDI_DEMA_DEFAULT_IDSTYPE, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + Indi_DEMA(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = INDI_DEMA_DEFAULT_IDSTYPE, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : Indicator(IndiDEMAParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + + /** + * 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_AP | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } /** * Updates the indicator value. @@ -106,21 +126,22 @@ class Indi_DEMA : public IndicatorTickOrCandleSource { } return _res[0]; #else - Indi_Price *_indi_price = Indi_Price::GetCached(_symbol, _applied_price, _tf, _shift); - // Note that _applied_price and Indi_Price mode indices are compatible. - return Indi_DEMA::iDEMAOnIndicatorSlow(_indi_price.GetCache(), _indi_price, 0, _period, _ma_shift, _shift); -#endif - } + if (_obj == nullptr) { + Print( + "Indi_DEMA::iDEMA() can work without supplying pointer to IndicatorData only in MQL5. In this platform the " + "pointer is required."); + DebugBreak(); + return 0; + } - static double iDEMAOnIndicatorSlow(IndicatorCalculateCache *cache, IndicatorData *_indi, int indi_mode, - unsigned int ma_period, unsigned int ma_shift, int shift) { - return iDEMAOnArray(_indi.GetValueStorage(indi_mode), 0, ma_period, ma_shift, shift, cache); + return iDEMAOnIndicator(_obj, _period, _ma_shift, _applied_price, _mode, _shift); +#endif } static double iDEMAOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, unsigned int _ma_period, unsigned int _ma_shift, int _mode, int _shift, IndicatorCalculateCache *_cache = NULL, bool _recalculate = false) { - if (_cache == NULL) { + if (_cache == nullptr) { Print("iDEMAOnArray() cannot yet work without cache object!"); DebugBreak(); return 0.0f; @@ -147,16 +168,17 @@ class Indi_DEMA : public IndicatorTickOrCandleSource { /** * On-indicator version of DEMA. */ - static double iDEMAOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, int _ma_shift, - ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( - _indi, _symbol, _tf, (int)_ap, Util::MakeKey("Indi_CHV_ON_" + _indi.GetFullName(), _period, _ma_shift)); + static double iDEMAOnIndicator(IndicatorData *_indi, int _period, int _ma_shift, ENUM_APPLIED_PRICE _ap, + int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_indi, _ap, Util::MakeKey(_period, _ma_shift)); return iDEMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _ma_shift, _mode, _shift, _cache); } static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &DemaBuffer, ValueStorage &Ema, ValueStorage &EmaOfEma, int InpPeriodEMA) { - if (rates_total < 2 * InpPeriodEMA - 2) return (0); + if (rates_total < 2 * InpPeriodEMA - 1) { + return 0; + } int start; if (prev_calculated == 0) @@ -168,7 +190,9 @@ class Indi_DEMA : public IndicatorTickOrCandleSource { Indi_MA::ExponentialMAOnBuffer(rates_total, prev_calculated, InpPeriodEMA - 1, InpPeriodEMA, Ema, EmaOfEma); - for (int i = start; i < rates_total && !IsStopped(); i++) DemaBuffer[i] = 2.0 * Ema[i].Get() - EmaOfEma[i].Get(); + for (int i = start; i < rates_total && !IsStopped(); i++) { + DemaBuffer[i] = 2.0 * Ema[i].Get() - EmaOfEma[i].Get(); + } return (rates_total); } @@ -176,24 +200,29 @@ class Indi_DEMA : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // We're getting DEMA from Price indicator. + _value = Indi_DEMA::iDEMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetMAShift(), GetAppliedPrice() /*]*/, _ishift, _mode, THIS_PTR); break; + case IDATA_ONCALCULATE: + _value = Indi_DEMA::iDEMAOnIndicator(GetDataSource(), /*[*/ GetPeriod(), GetMAShift(), GetAppliedPrice() /*]*/, + _mode, _ishift); + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /*[*/ GetPeriod(), GetMAShift(), GetAppliedPrice() /*]*/, _mode, _ishift); break; case IDATA_INDICATOR: // Calculating DEMA value from specified indicator. - _value = Indi_DEMA::iDEMAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetMAShift(), - GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + _value = Indi_DEMA::iDEMAOnIndicator(GetDataSource(), /*[*/ GetPeriod(), GetMAShift(), GetAppliedPrice() /*]*/, + _mode, _ishift); break; } return _value; @@ -203,8 +232,7 @@ class Indi_DEMA : public IndicatorTickOrCandleSource { * Checks if indicator entry values are valid. */ virtual bool IsValidEntry(IndicatorDataEntry &_entry) { - return Indicator::IsValidEntry(_entry) && _entry.IsGt(0) && - _entry.IsLt(DBL_MAX); + return Indicator::IsValidEntry(_entry) && _entry.IsGt(0) && _entry.IsLt(DBL_MAX); } /* Getters */ @@ -228,7 +256,7 @@ class Indi_DEMA : public IndicatorTickOrCandleSource { * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index 0b0aad7c0..d78e6bc65 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -39,27 +39,35 @@ struct IndiDeMarkerParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\DeMarker"); }; - IndiDeMarkerParams(IndiDeMarkerParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiDeMarkerParams(IndiDeMarkerParams &_params) { THIS_REF = _params; }; }; /** * Implements the DeMarker indicator. */ -class Indi_DeMarker : public IndicatorTickOrCandleSource { +class Indi_DeMarker : public Indicator { public: /** * Class constructor. */ Indi_DeMarker(IndiDeMarkerParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), - _indi_src) {} - Indi_DeMarker(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_DEMARKER, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + Indi_DeMarker(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiDeMarkerParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -104,7 +112,7 @@ class Indi_DeMarker : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index a58f0a682..46d351fa9 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "Price/Indi_Price.mqh" /** @@ -39,44 +39,51 @@ struct IndiDemoParams : IndicatorParams { SetCustomIndicatorName("Examples\\Demo"); } }; - IndiDemoParams(IndiDemoParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiDemoParams(IndiDemoParams &_params) { THIS_REF = _params; }; }; /** * Demo/Dummy Indicator. */ -class Indi_Demo : public IndicatorTickOrCandleSource { +class Indi_Demo : public Indicator { public: /** * Class constructor. */ Indi_Demo(IndiDemoParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_Demo(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_DEMO, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_Demo(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiDemoParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CANDLE; } + + /** + * 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 value. */ - static double iDemo(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - IndicatorData *_obj = NULL) { - return 0.1 + (0.1 * _obj.GetBarIndex()); + static double iDemo(IndicatorData *_obj, int _shift = 0) { + return 0.1 + (0.1 * _obj PTR_DEREF GetCandle() PTR_DEREF GetBarIndex()); } /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - double _value = Indi_Demo::iDemo(GetSymbol(), GetTf(), _ishift, THIS_PTR); - if (iparams.is_draw) { - draw.DrawLineTo(GetName(), GetBarTime(_ishift), _value); + double _value = Indi_Demo::iDemo(THIS_PTR, _ishift); + if (idparams.is_draw) { + draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(_ishift), _value); } return _value; } diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index 738aa54f4..70030acbc 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -22,8 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" -#include "../Storage/ValueStorage.price.h" +#include "../Indicator.mqh" #include "Indi_MA.mqh" // Structs. @@ -38,35 +37,53 @@ struct IndiDetrendedPriceParams : IndicatorParams { period = _period; shift = _shift; }; - IndiDetrendedPriceParams(IndiDetrendedPriceParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiDetrendedPriceParams(IndiDetrendedPriceParams &_params) { THIS_REF = _params; }; }; /** * Implements Detrended Price Oscillator. */ -class Indi_DetrendedPrice : public IndicatorTickOrCandleSource { +class Indi_DetrendedPrice : public Indicator { public: /** * Class constructor. */ Indi_DetrendedPrice(IndiDetrendedPriceParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_DetrendedPrice(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_DETRENDED_PRICE, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_DetrendedPrice(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiDetrendedPriceParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_AP; } /** - * Built-in version of AMA. + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. */ - static double iDPO(string _symbol, ENUM_TIMEFRAMES _tf, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, - int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_symbol, _tf, _ap, - Util::MakeKey("Indi_DPO", _period, (int)_ap)); + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // Volume uses volume only. + return _ds PTR_DEREF HasSpecificValueStorage(INDI_VS_TYPE_VOLUME); + } + + /** + * Built-in version of DPO. + */ + static double iDPO(IndicatorData *_indi, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_indi, _ap, Util::MakeKey(_indi.GetId())); return iDPOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _ap, _mode, _shift, _cache); } @@ -91,16 +108,6 @@ class Indi_DetrendedPrice : public IndicatorTickOrCandleSource(_mode, _shift); } - /** - * On-indicator version of DPO. - */ - static double iDPOOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, - ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( - _indi, _symbol, _tf, _ap, Util::MakeKey("Indi_DPO_ON_" + _indi.GetFullName(), _period, (int)_ap)); - return iDPOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _ap, _mode, _shift, _cache); - } - /** * OnCalculate() method for DPO indicator. */ @@ -128,21 +135,20 @@ class Indi_DetrendedPrice : public IndicatorTickOrCandleSource= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_DetrendedPrice::iDPO(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, - _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = iDPO(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _ishift); break; case IDATA_INDICATOR: - _value = Indi_DetrendedPrice::iDPOOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), - GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + _value = iDPO(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -160,7 +166,7 @@ class Indi_DetrendedPrice : public IndicatorTickOrCandleSource { +class Indi_Drawer : public Indicator { Redis redis; public: @@ -43,17 +40,30 @@ class Indi_Drawer : public IndicatorTickOrCandleSource { */ Indi_Drawer(const IndiDrawerParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(0, TYPE_DOUBLE, _idstype, IDATA_RANGE_UNKNOWN, _indi_src_mode), - _indi_src), + : Indicator(_p, IndicatorDataParams::GetInstance(0, TYPE_DOUBLE, _idstype, IDATA_RANGE_UNKNOWN, _indi_src_mode), + _indi_src), redis(true) { Init(); } - Indi_Drawer(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_DRAWER, _tf, _shift), redis(true) { + Indi_Drawer(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiDrawerParams(), + IndicatorDataParams::GetInstance(0, TYPE_DOUBLE, _idstype, IDATA_RANGE_UNKNOWN, _indi_src_mode), + _indi_src), + redis(true) { Init(); } + /** + * 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_ANY; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_INDICATOR; } + void Init() { // Drawer is always ready. @@ -104,7 +114,6 @@ class Indi_Drawer : public IndicatorTickOrCandleSource { virtual void OnTick() { Indicator::OnTick(); - TaskActionEntry action(INDI_ACTION_SET_VALUE); /* @fixme TaskActionEntry action(INDI_ACTION_SET_VALUE); ArrayResize(action.args, 3); @@ -118,7 +127,8 @@ class Indi_Drawer : public IndicatorTickOrCandleSource { action.args[2].double_value = 1.25; */ - //string json = SerializerConverter::FromObject(action).ToString(/*SERIALIZER_JSON_NO_WHITESPACES*/); + // string json = + // SerializerConverter::FromObject(action).ToString(/*SERIALIZER_JSON_NO_WHITESPACES*/); /* @fixme RedisMessage msg; @@ -206,7 +216,7 @@ class Indi_Drawer : public IndicatorTickOrCandleSource { /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_Drawer.struct.h b/Indicators/Indi_Drawer.struct.h index 9a245acd8..473209d9f 100644 --- a/Indicators/Indi_Drawer.struct.h +++ b/Indicators/Indi_Drawer.struct.h @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2020, 31337 Investments Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -27,6 +27,7 @@ // Includes. #include "../Indicator.struct.h" +#include "../SerializerNode.enum.h" // Structs. @@ -39,12 +40,8 @@ struct IndiDrawerParams : IndicatorParams { : period(_period), applied_price(_ap), IndicatorParams(INDI_DRAWER) { // Fetching history data is not yet implemented. SetCustomIndicatorName("Examples\\Drawer"); - // Simulating a single, valid buffer. - }; - IndiDrawerParams(IndiDrawerParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; }; + IndiDrawerParams(IndiDrawerParams &_params) { THIS_REF = _params; }; // Serializers. SERIALIZER_EMPTY_STUB; SerializerNodeType Serialize(Serializer &s); diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index fa5aa8954..f21fc1af0 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/Singleton.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" @@ -62,16 +62,13 @@ struct IndiEnvelopesParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\Envelopes"); }; - IndiEnvelopesParams(IndiEnvelopesParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiEnvelopesParams(IndiEnvelopesParams &_params) { THIS_REF = _params; }; }; /** * Implements the Envelopes indicator. */ -class Indi_Envelopes : public IndicatorTickOrCandleSource { +class Indi_Envelopes : public Indicator { protected: /* Protected methods */ @@ -93,15 +90,29 @@ class Indi_Envelopes : public IndicatorTickOrCandleSource { */ Indi_Envelopes(IndiEnvelopesParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src) { + : Indicator(_p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { Init(); } - Indi_Envelopes(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_ENVELOPES, _tf, _shift) { + Indi_Envelopes(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiEnvelopesParams(), + IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { Init(); - }; + } + /** + * 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_AP; } + + public: + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } /** * Returns the indicator value. @@ -155,16 +166,15 @@ class Indi_Envelopes : public IndicatorTickOrCandleSource { #endif } - static double iEnvelopesOnIndicator(IndicatorCalculateCache *_cache, IndicatorData *_indi, string _symbol, + static double iEnvelopesOnIndicator(IndicatorData *_target, IndicatorData *_source, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, ENUM_MA_METHOD _ma_method, // (MT4/MT5): MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA - int _indi_mode, // Source indicator's mode index. May be -1 to use first buffer - int _ma_shift, double _deviation, + ENUM_APPLIED_PRICE _ap, int _ma_shift, double _deviation, int _mode, // (MT4 _mode): 0 - MODE_MAIN, 1 - MODE_UPPER, 2 - MODE_LOWER; (MT5 // _mode): 0 - UPPER_LINE, 1 - LOWER_LINE int _shift = 0) { - return iEnvelopesOnArray(_indi.GetValueStorage(_indi_mode), 0, _ma_period, _ma_method, _ma_shift, _deviation, _mode, - _shift, _cache); + return iEnvelopesOnArray(_source.GetSpecificAppliedPriceValueStorage(_ap, _target), 0, _ma_period, _ma_method, + _ma_shift, _deviation, _mode, _shift, _target PTR_DEREF GetCache()); } static double iEnvelopesOnArray(double &price[], int total, int ma_period, ENUM_MA_METHOD ma_method, int ma_shift, @@ -215,7 +225,7 @@ class Indi_Envelopes : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -223,15 +233,20 @@ class Indi_Envelopes : public IndicatorTickOrCandleSource { _value = Indi_Envelopes::iEnvelopes(GetSymbol(), GetTf(), GetMAPeriod(), GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation(), _mode, _ishift, THIS_PTR); break; + case IDATA_ONCALCULATE: + // @todo Is cache needed here? + _value = Indi_Envelopes::iEnvelopesOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), + GetMAMethod(), GetAppliedPrice(), GetMAShift(), GetDeviation(), + _mode, _ishift); + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetMAPeriod(), GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation() /**/, _mode, _ishift); break; case IDATA_INDICATOR: - _value = Indi_Envelopes::iEnvelopesOnIndicator(GetCache(), GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), - GetMAMethod(), - Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)), - GetMAShift(), GetDeviation(), _mode, _ishift); + _value = Indi_Envelopes::iEnvelopesOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), + GetMAMethod(), GetAppliedPrice(), GetMAShift(), GetDeviation(), + _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -243,8 +258,8 @@ class Indi_Envelopes : public IndicatorTickOrCandleSource { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { - Indicator::GetEntryAlter(_entry); + void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { + Indicator::GetEntryAlter(_entry, _shift); #ifdef __MQL4__ // The LINE_MAIN only exists in MQL4 for Envelopes. _entry.values[LINE_MAIN] = GetValue((ENUM_LO_UP_LINE)LINE_MAIN, _shift); @@ -278,7 +293,7 @@ class Indi_Envelopes : public IndicatorTickOrCandleSource { /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /** * Get deviation value. diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index 36e8c50a0..ad0caebda 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -32,7 +32,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -55,16 +55,13 @@ struct IndiForceParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\Force_Index"); }; - IndiForceParams(IndiForceParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiForceParams(IndiForceParams &_params) { THIS_REF = _params; }; }; /** * Implements the Force Index indicator. */ -class Indi_Force : public IndicatorTickOrCandleSource { +class Indi_Force : public Indicator { protected: public: /** @@ -72,11 +69,22 @@ class Indi_Force : public IndicatorTickOrCandleSource { */ Indi_Force(IndiForceParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) {} - Indi_Force(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_FORCE, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_Force(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiForceParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -121,7 +129,7 @@ class Indi_Force : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -154,7 +162,7 @@ class Indi_Force : public IndicatorTickOrCandleSource { /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index 5948a8142..51c2320f2 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" // Structs. @@ -40,27 +40,52 @@ struct IndiFrAIndiMAParams : IndicatorParams { period = _period; shift = _shift; }; - IndiFrAIndiMAParams(IndiFrAIndiMAParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiFrAIndiMAParams(IndiFrAIndiMAParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_FrAMA : public IndicatorTickOrCandleSource { +class Indi_FrAMA : public Indicator { public: /** * Class constructor. */ Indi_FrAMA(IndiFrAIndiMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_FrAMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_FRAMA, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_FrAMA(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiFrAIndiMAParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_AP; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // FrAMA uses OHLC only. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } /** * Built-in version of FrAMA. @@ -70,8 +95,14 @@ class Indi_FrAMA : public IndicatorTickOrCandleSource { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iFrAMA(_symbol, _tf, _ma_period, _ma_shift, _ap), _mode, _shift); #else - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, - Util::MakeKey("Indi_FrAMA", _ma_period, _ma_shift, (int)_ap)); + if (_obj == nullptr) { + Print( + "Indi_FrAMA::iFrAMA() can work without supplying pointer to IndicatorData only in MQL5. In this platform the " + "pointer is required."); + DebugBreak(); + return 0; + } + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_obj, Util::MakeKey(_ma_period, _ma_shift, (int)_ap)); return iFrAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _ma_period, _ma_shift, _ap, _mode, _shift, _cache); #endif } @@ -101,11 +132,9 @@ class Indi_FrAMA : public IndicatorTickOrCandleSource { /** * On-indicator version of FrAMA. */ - static double iFrAMAOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, - int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, Util::MakeKey("Indi_AMA_ON_" + _indi.GetFullName(), _ma_period, _ma_shift, (int)_ap)); + static double iFrAMAOnIndicator(IndicatorData *_indi, int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, + int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_ma_period, _ma_shift, (int)_ap)); return iFrAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _ma_period, _ma_shift, _ap, _mode, _shift, _cache); } @@ -118,7 +147,7 @@ class Indi_FrAMA : public IndicatorTickOrCandleSource { if (prev_calculated == 0) { start = 2 * InpPeriodFrAMA - 1; for (i = 0; i <= start; i++) - FrAmaBuffer[i] = PriceValueStorage::GetApplied(open, high, low, close, i, InpAppliedPrice); + FrAmaBuffer[i] = AppliedPriceValueStorage::GetApplied(open, high, low, close, i, InpAppliedPrice); } else start = prev_calculated - 1; @@ -136,7 +165,7 @@ class Indi_FrAMA : public IndicatorTickOrCandleSource { double n3 = (hi3 - lo3) / (2 * InpPeriodFrAMA); double d = (MathLog(n1 + n2) - MathLog(n3)) / math_log_2; double alfa = MathExp(-4.6 * (d - 1.0)); - double _iprice = PriceValueStorage::GetApplied(open, high, low, close, i, InpAppliedPrice); + double _iprice = AppliedPriceValueStorage::GetApplied(open, high, low, close, i, InpAppliedPrice); FrAmaBuffer[i] = alfa * _iprice + (1 - alfa) * FrAmaBuffer[i - 1].Get(); } @@ -148,21 +177,23 @@ class Indi_FrAMA : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_FrAMA::iFrAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFRAMAShift(), GetAppliedPrice() /*]*/, - _mode, _ishift, THIS_PTR); + _value = + iFrAMA(GetSymbol(), GetTf(), GetPeriod(), GetFRAMAShift(), GetAppliedPrice(), _mode, _ishift, THIS_PTR); + break; + case IDATA_ONCALCULATE: + _value = iFrAMAOnIndicator(GetDataSource(), GetPeriod(), GetFRAMAShift(), GetAppliedPrice(), _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetFRAMAShift() /*]*/, 0, _ishift); break; case IDATA_INDICATOR: - _value = Indi_FrAMA::iFrAMAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), - GetFRAMAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + _value = iFrAMAOnIndicator(GetDataSource(), GetPeriod(), GetFRAMAShift(), GetAppliedPrice(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -185,7 +216,7 @@ class Indi_FrAMA : public IndicatorTickOrCandleSource { /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index 7b6555bbc..fa08a645a 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -38,16 +38,13 @@ struct IndiFractalsParams : IndicatorParams { SetCustomIndicatorName("Examples\\Fractals"); shift = _shift; }; - IndiFractalsParams(IndiFractalsParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiFractalsParams(IndiFractalsParams &_params) { THIS_REF = _params; }; }; /** * Implements the Fractals indicator. */ -class Indi_Fractals : public IndicatorTickOrCandleSource { +class Indi_Fractals : public Indicator { protected: /* Protected methods */ @@ -62,16 +59,29 @@ class Indi_Fractals : public IndicatorTickOrCandleSource { */ Indi_Fractals(IndiFractalsParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_LO_UP_LINE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), - _indi_src) { - Init(); - } - Indi_Fractals(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_FRACTALS, _tf, _shift) { + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_LO_UP_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), + _indi_src) { Init(); } + Indi_Fractals(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiFractalsParams(), + IndicatorDataParams::GetInstance(FINAL_LO_UP_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), + _indi_src) {} + + /** + * 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; } + + public: + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -118,12 +128,12 @@ class Indi_Fractals : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_Fractals::iFractals(GetSymbol(), GetTf(), (ENUM_LO_UP_LINE)_mode, _ishift, THIS_PTR); + _value = _value = Indi_Fractals::iFractals(GetSymbol(), GetTf(), (ENUM_LO_UP_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); @@ -137,8 +147,8 @@ class Indi_Fractals : public IndicatorTickOrCandleSource { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { - Indicator::GetEntryAlter(_entry); + void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { + Indicator::GetEntryAlter(_entry, _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 7822fa257..d573da0c9 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -93,16 +93,13 @@ struct IndiGatorParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\Gator"); }; - IndiGatorParams(IndiGatorParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiGatorParams(IndiGatorParams &_params) { THIS_REF = _params; }; }; /** * Implements the Gator oscillator. */ -class Indi_Gator : public IndicatorTickOrCandleSource { +class Indi_Gator : public Indicator { protected: /* Protected methods */ @@ -117,17 +114,32 @@ class Indi_Gator : public IndicatorTickOrCandleSource { */ Indi_Gator(IndiGatorParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_GATOR_LINE_HISTOGRAM_ENTRY, TYPE_DOUBLE, - _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) { + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_GATOR_LINE_HISTOGRAM_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { Init(); } - Indi_Gator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_GATOR, _tf, _shift) { + Indi_Gator(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiGatorParams(), + IndicatorDataParams::GetInstance(FINAL_GATOR_LINE_HISTOGRAM_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { Init(); } + /** + * 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; } + + public: + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_ICUSTOM; } + /** * Returns the indicator value. * @@ -186,7 +198,7 @@ class Indi_Gator : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -212,8 +224,8 @@ class Indi_Gator : public IndicatorTickOrCandleSource { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { - Indicator::GetEntryAlter(_entry); + void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { + Indicator::GetEntryAlter(_entry, _shift); #ifdef __MQL4__ // @todo: Can we calculate upper and lower histogram color in MT4? // @see: https://docs.mql4.com/indicators/igator @@ -271,7 +283,7 @@ class Indi_Gator : public IndicatorTickOrCandleSource { /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index 3d6e13726..84e6a8969 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" // Enums. @@ -60,16 +60,13 @@ struct IndiHeikenAshiParams : IndicatorParams { } shift = _shift; }; - IndiHeikenAshiParams(IndiHeikenAshiParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiHeikenAshiParams(IndiHeikenAshiParams &_params) { THIS_REF = _params; }; }; /** * Implements the Heiken-Ashi indicator. */ -class Indi_HeikenAshi : public IndicatorTickOrCandleSource { +class Indi_HeikenAshi : public Indicator { protected: /* Protected methods */ @@ -84,15 +81,45 @@ class Indi_HeikenAshi : public IndicatorTickOrCandleSource */ Indi_HeikenAshi(IndiHeikenAshiParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_HA_MODE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src) { + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_HA_MODE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, + _indi_src_mode), + _indi_src) { Init(); } - Indi_HeikenAshi(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_HEIKENASHI, _tf, _shift) { - Init(); + Indi_HeikenAshi(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiHeikenAshiParams(), + IndicatorDataParams::GetInstance(FINAL_HA_MODE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, + _indi_src_mode), + _indi_src) {} + + /** + * 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_CUSTOM; } + + public: + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // HA uses OHLC only. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); } /** @@ -145,11 +172,10 @@ class Indi_HeikenAshi : public IndicatorTickOrCandleSource } /** - * "Built-in" version of Heiken Ashi. + * OnCalculate-based version of Color Heiken Ashi as there is no built-in one. */ - static double iHeikenAshi(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, - Indi_HeikenAshi *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_HeikenAshi"); + static double iHeikenAshi(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); return iHeikenAshiOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -175,16 +201,6 @@ class Indi_HeikenAshi : public IndicatorTickOrCandleSource return _cache.GetTailValue(_mode, _shift); } - /** - * On-indicator version of Heiken Ashi. - */ - static double iHeikenAshiOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, - int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, - Util::MakeKey("Indi_HeikenAshi_ON_" + _indi.GetFullName())); - return iHeikenAshiOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); - } - /** * OnCalculate() method for Mass Index indicator. */ @@ -223,11 +239,12 @@ class Indi_HeikenAshi : public IndicatorTickOrCandleSource /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = HA_OPEN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = HA_OPEN, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: + case IDATA_ONCALCULATE: #ifdef __MQL4__ // Converting MQL4's enum into MQL5 one, as OnCalculate uses further one. switch (_mode) { @@ -245,7 +262,7 @@ class Indi_HeikenAshi : public IndicatorTickOrCandleSource break; } #endif - _value = Indi_HeikenAshi::iHeikenAshi(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + _value = Indi_HeikenAshi::iHeikenAshi(THIS_PTR, _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); @@ -255,8 +272,7 @@ class Indi_HeikenAshi : public IndicatorTickOrCandleSource _ishift, THIS_PTR); break; case IDATA_INDICATOR: - _value = - Indi_HeikenAshi::iHeikenAshiOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + _value = Indi_HeikenAshi::iHeikenAshi(THIS_PTR, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index 64c0588c0..8924096f8 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -73,23 +73,20 @@ struct IndiIchimokuParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\Ichimoku"); }; - IndiIchimokuParams(IndiIchimokuParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiIchimokuParams(IndiIchimokuParams &_params) { THIS_REF = _params; }; }; /** * Implements the Ichimoku Kinko Hyo indicator. */ -class Indi_Ichimoku : public IndicatorTickOrCandleSource { +class Indi_Ichimoku : public Indicator { protected: /* Protected methods */ /** * Initialize. */ - void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_ICHIMOKU_LINE_ENTRY); } + void Init() {} public: /** @@ -97,17 +94,32 @@ class Indi_Ichimoku : public IndicatorTickOrCandleSource { */ Indi_Ichimoku(IndiIchimokuParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_ICHIMOKU_LINE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src) { + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_ICHIMOKU_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, + _indi_src_mode), + _indi_src) { Init(); } - Indi_Ichimoku(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_ICHIMOKU, _tf, _shift) { + Indi_Ichimoku(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiIchimokuParams(), + IndicatorDataParams::GetInstance(FINAL_ICHIMOKU_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, + _indi_src_mode), + _indi_src) { Init(); } + /** + * 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; } + + public: + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_ICUSTOM; } + /** * Returns the indicator value. * @@ -155,7 +167,7 @@ class Indi_Ichimoku : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -176,8 +188,8 @@ class Indi_Ichimoku : public IndicatorTickOrCandleSource { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { - Indicator::GetEntryAlter(_entry); + void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { + Indicator::GetEntryAlter(_entry, _shift); #ifdef __MQL4__ // In MQL4 value of LINE_TENKANSEN is 1 (not 0 as in MQL5), // so we are duplicating it. diff --git a/Indicators/Indi_Killzones.mqh b/Indicators/Indi_Killzones.mqh index dfc03c4dc..d8c43a299 100644 --- a/Indicators/Indi_Killzones.mqh +++ b/Indicators/Indi_Killzones.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Market.struct.h" // Defines enumerations. @@ -51,12 +51,8 @@ struct IndiKillzonesParams : IndicatorParams { // Struct constructor. IndiKillzonesParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorParams(INDI_PIVOT) { SetShift(_shift); - tf = _tf; - }; - IndiKillzonesParams(IndiKillzonesParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; }; + IndiKillzonesParams(IndiKillzonesParams &_params) { THIS_REF = _params; }; }; struct Indi_Killzones_Time : MarketTimeForex { @@ -88,7 +84,7 @@ struct Indi_Killzones_Time : MarketTimeForex { /** * Implements Pivot Detector. */ -class Indi_Killzones : public IndicatorTickOrCandleSource { +class Indi_Killzones : public Indicator { protected: Indi_Killzones_Time ikt; @@ -98,17 +94,44 @@ class Indi_Killzones : public IndicatorTickOrCandleSource { */ Indi_Killzones(IndiKillzonesParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_CHART, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_INDI_KILLZONES_MODE_ENTRY, TYPE_FLOAT, - _idstype, IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src) {} - Indi_Killzones(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_KILLZONES, _tf, _shift) {} + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_KILLZONES_MODE_ENTRY, TYPE_FLOAT, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + Indi_Killzones(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_CHART, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiKillzonesParams(), + IndicatorDataParams::GetInstance(FINAL_INDI_KILLZONES_MODE_ENTRY, TYPE_FLOAT, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + + /** + * 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_CUSTOM; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_CHART; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // Killzones uses high and low prices only. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW); + } /** * Returns the indicator's value. */ - IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { float _value = FLT_MAX; int _index = (int)_mode / 2; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); @@ -121,7 +144,9 @@ class Indi_Killzones : public IndicatorTickOrCandleSource { ikt.Set(::TimeGMT()); if (ikt.CheckHours(_index)) { // Pass values to check for new highs or lows. - ikt.Update(_mode % 2 == 0 ? (float)GetHigh(_ishift) : (float)GetLow(_ishift), _index); + ikt.Update(_mode % 2 == 0 ? (float)GetCandle() PTR_DEREF GetHigh(_ishift) + : (float)GetCandle() PTR_DEREF GetLow(_ishift), + _index); } // Set a final value. _value = _mode % 2 == 0 ? ikt.GetHigh(_index) : ikt.GetLow(_index); diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 625a4d61b..66b0542a9 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -27,7 +27,7 @@ // Includes. #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../Indicator/IndicatorTickSource.h" +#include "../Indicator.mqh" #include "../Refs.mqh" #include "../Storage/Singleton.h" #include "../Storage/ValueStorage.h" @@ -60,26 +60,49 @@ struct IndiMAParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\Moving Average"); }; - IndiMAParams(IndiMAParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiMAParams(IndiMAParams &_params) { THIS_REF = _params; }; }; /** * Implements the Moving Average indicator. */ -class Indi_MA : public IndicatorTickSource { +class Indi_MA : public Indicator { public: /** * Class constructor. */ Indi_MA(IndiMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src) {} - Indi_MA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_MA, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + Indi_MA(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiMAParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + /** + * 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_AP; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // Volume uses volume only. + return _ds PTR_DEREF HasSpecificValueStorage(INDI_VS_TYPE_VOLUME); + } /** * Returns the indicator value. @@ -89,15 +112,15 @@ class Indi_MA : public IndicatorTickSource { * - https://www.mql5.com/en/docs/indicators/ima */ static double iMA(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _ma_period, unsigned int _ma_shift, - ENUM_MA_METHOD _ma_method, ENUM_APPLIED_PRICE _applied_array, int _shift = 0, + ENUM_MA_METHOD _ma_method, ENUM_APPLIED_PRICE _applied_price, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ - return ::iMA(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_array, _shift); + return ::iMA(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_price, _shift); #else // __MQL5__ int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; double _res[]; if (_handle == NULL || _handle == INVALID_HANDLE) { - if ((_handle = ::iMA(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_array)) == INVALID_HANDLE) { + if ((_handle = ::iMA(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_price)) == INVALID_HANDLE) { SetUserError(ERR_USER_INVALID_HANDLE); return EMPTY_VALUE; } else if (Object::IsValid(_obj)) { @@ -125,11 +148,12 @@ class Indi_MA : public IndicatorTickSource { /** * Calculates MA on another indicator. */ - static double iMAOnIndicator(IndicatorCalculateCache *cache, IndicatorData *_indi, int indi_mode, - string symbol, ENUM_TIMEFRAMES tf, unsigned int ma_period, unsigned int ma_shift, + static double iMAOnIndicator(IndicatorData *_target, IndicatorData *_source, string symbol, ENUM_TIMEFRAMES tf, + unsigned int ma_period, unsigned int ma_shift, ENUM_MA_METHOD ma_method, // (MT4/MT5): MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA - int shift = 0) { - return iMAOnArray(_indi.GetValueStorage(indi_mode), 0, ma_period, ma_shift, ma_method, shift, cache); + ENUM_APPLIED_PRICE _ap, int shift = 0) { + ValueStorage *_data = (ValueStorage *)_source.GetSpecificAppliedPriceValueStorage(_ap, _target); + return iMAOnArray(_data, 0, ma_period, ma_shift, ma_method, shift, _target PTR_DEREF GetCache()); } /** @@ -140,96 +164,11 @@ class Indi_MA : public IndicatorTickSource { #ifdef __MQL4__ return ::iMAOnArray(price, total, ma_period, ma_shift, ma_method, shift); #else - 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; - } + // 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); #endif } @@ -711,7 +650,7 @@ class Indi_MA : public IndicatorTickSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -719,15 +658,18 @@ class Indi_MA : public IndicatorTickSource { _value = Indi_MA::iMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), _ishift, THIS_PTR); break; + case IDATA_ONCALCULATE: + _value = Indi_MA::iMAOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), + GetMAMethod(), GetAppliedPrice(), _ishift); + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice() /* ] */, 0, _ishift); break; case IDATA_INDICATOR: // Calculating MA value from specified indicator. - _value = Indi_MA::iMAOnIndicator(GetCache(), GetDataSource(), - Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)), GetSymbol(), - GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), _ishift); + _value = Indi_MA::iMAOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), + GetMAMethod(), GetAppliedPrice(), _ishift); break; } @@ -735,16 +677,18 @@ class Indi_MA : public IndicatorTickSource { } /** - * Returns reusable indicator. + * Returns reusable indicator with the same candle indicator as given indicator's one. */ - static Indi_MA *GetCached(string _symbol, ENUM_TIMEFRAMES _tf, int _period, int _ma_shift, ENUM_MA_METHOD _ma_method, + static Indi_MA *GetCached(IndicatorData *_indi, int _period, int _ma_shift, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_PRICE _ap) { Indi_MA *_ptr; - string _key = Util::MakeKey(_symbol, (int)_tf, _period, _ma_shift, (int)_ma_method, (int)_ap); + string _key = + Util::MakeKey(_indi PTR_DEREF GetCandle() PTR_DEREF GetId(), _period, _ma_shift, (int)_ma_method, (int)_ap); if (!Objects::TryGet(_key, _ptr)) { IndiMAParams _p(_period, _ma_shift, _ma_method, _ap); _ptr = Objects::Set(_key, new Indi_MA(_p)); - _ptr.SetSymbol(_symbol); + // Assigning the same candle indicator for MA as in _indi. + _ptr.SetDataSource(_indi PTR_DEREF GetCandle()); } return _ptr; } @@ -804,7 +748,7 @@ class Indi_MA : public IndicatorTickSource { * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_array; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_array; } /* Setters */ @@ -844,9 +788,9 @@ class Indi_MA : public IndicatorTickSource { * - https://docs.mql4.com/constants/indicatorconstants/prices#enum_applied_price_enum * - https://www.mql5.com/en/docs/constants/indicatorconstants/prices#enum_applied_price_enum */ - void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_array) { + void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - iparams.applied_array = _applied_array; + iparams.applied_array = _applied_price; } }; #endif // INDI_MA_MQH diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index e590f3f7f..338517687 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -49,28 +49,38 @@ struct IndiMACDParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\MACD"); }; - IndiMACDParams(IndiMACDParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiMACDParams(IndiMACDParams &_params) { THIS_REF = _params; }; }; /** * Implements the Moving Averages Convergence/Divergence indicator. */ -class Indi_MACD : public IndicatorTickOrCandleSource { +class Indi_MACD : public Indicator { public: /** * Class constructor. */ Indi_MACD(IndiMACDParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_RANGE, _indi_src_mode), - _indi_src) {} - Indi_MACD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_MACD, _tf, _shift) {} + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, + _indi_src_mode), + _indi_src) {} + Indi_MACD(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiMACDParams(), + IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, + _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -119,7 +129,7 @@ class Indi_MACD : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -141,9 +151,7 @@ class Indi_MACD : public IndicatorTickOrCandleSource { /** * Checks if indicator entry values are valid. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { - return !_entry.HasValue(DBL_MAX); - } + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return !_entry.HasValue(DBL_MAX); } /* Getters */ @@ -173,7 +181,7 @@ class Indi_MACD : public IndicatorTickOrCandleSource { * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index 475683850..73f20e646 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -41,26 +41,35 @@ struct IndiMFIParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\MFI"); }; - IndiMFIParams(IndiMFIParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiMFIParams(IndiMFIParams &_params) { THIS_REF = _params; }; }; /** * Implements the Money Flow Index indicator. */ -class Indi_MFI : public IndicatorTickOrCandleSource { +class Indi_MFI : public Indicator { public: /** * Class constructor. */ Indi_MFI(IndiMFIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), - _indi_src) {} - Indi_MFI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_MFI, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + Indi_MFI(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiMFIParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } /** * Calculates the Money Flow Index indicator and returns its value. @@ -114,7 +123,7 @@ class Indi_MFI : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index 9a20d087c..c1c85d1f8 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" #include "Indi_MA.mqh" @@ -40,35 +40,55 @@ struct IndiMassIndexParams : IndicatorParams { shift = _shift; sum_period = _sum_period; }; - IndiMassIndexParams(IndiMassIndexParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiMassIndexParams(IndiMassIndexParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_MassIndex : public IndicatorTickOrCandleSource { +class Indi_MassIndex : public Indicator { public: /** * Class constructor. */ Indi_MassIndex(IndiMassIndexParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_MassIndex(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_MASS_INDEX, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_MassIndex(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiMassIndexParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM; } + + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // MI uses high and low prices only. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW); + } /** - * Built-in version of Mass Index. + * OnCalculate-based version of Mass Index as there is no built-in one. */ - static double iMI(string _symbol, ENUM_TIMEFRAMES _tf, int _period, int _second_period, int _sum_period, - int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( - _symbol, _tf, Util::MakeKey("Indi_MassIndex", _period, _second_period, _sum_period)); + static double iMI(IndicatorData *_indi, int _period, int _second_period, int _sum_period, int _mode = 0, + int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_period, _second_period, _sum_period)); return iMIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _second_period, _sum_period, _mode, _shift, _cache); } @@ -95,19 +115,6 @@ class Indi_MassIndex : public IndicatorTickOrCandleSource { return _cache.GetTailValue(_mode, _shift); } - /** - * On-indicator version of Mass Index. - */ - static double iMIOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, - int _second_period, int _sum_period, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, - Util::MakeKey("Indi_MassIndex_ON_" + _indi.GetFullName(), _period, _second_period, _sum_period)); - return iMIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _second_period, _sum_period, _mode, _shift, - _cache); - } - /** * OnCalculate() method for Mass Index indicator. */ @@ -169,21 +176,20 @@ class Indi_MassIndex : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_MassIndex::iMI(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetSecondPeriod(), GetSumPeriod() /*]*/, - _mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = Indi_MassIndex::iMI(THIS_PTR, GetPeriod(), GetSecondPeriod(), GetSumPeriod(), _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _ishift); break; case IDATA_INDICATOR: - _value = Indi_MassIndex::iMIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), - GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _ishift, THIS_PTR); + _value = Indi_MassIndex::iMI(THIS_PTR, GetPeriod(), GetSecondPeriod(), GetSumPeriod(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 06c137242..fc62b5e7c 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -30,7 +30,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "Indi_PriceFeeder.mqh" #ifndef __MQL4__ @@ -51,27 +51,40 @@ struct IndiMomentumParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\Momentum"); }; - IndiMomentumParams(IndiMomentumParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiMomentumParams(IndiMomentumParams &_params) { THIS_REF = _params; }; }; /** * Implements the Momentum indicator. */ -class Indi_Momentum : public IndicatorTickOrCandleSource { +class Indi_Momentum : public Indicator { public: /** * Class constructor. */ Indi_Momentum(IndiMomentumParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) {} - Indi_Momentum(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_MOMENTUM, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_Momentum(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiMomentumParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + + /** + * 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_AP | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } /** * Returns the indicator value. @@ -127,7 +140,8 @@ class Indi_Momentum : public IndicatorTickOrCandleSource { _indi_value_buffer[i] = _indi[i].GetValue(_mode); } - double momentum = (_indi_value_buffer[0] / _indi_value_buffer[_period - 1]) * 100; + double _last_value = _indi_value_buffer[_period - 1]; + double momentum = _last_value != 0.0 ? (_indi_value_buffer[0] / _last_value) * 100 : 0.0; return momentum; } @@ -144,7 +158,7 @@ class Indi_Momentum : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -153,6 +167,14 @@ class Indi_Momentum : public IndicatorTickOrCandleSource { _value = Indi_Momentum::iMomentum(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), iparams.shift + _ishift, THIS_PTR); break; + case IDATA_ONCALCULATE: + // @fixit Somehow shift isn't used neither in MT4 nor MT5. + _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), + iparams.shift + _shift); + if (idparams.is_draw) { + draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + _shift), _value, 1); + } + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _ishift); @@ -162,9 +184,8 @@ class Indi_Momentum : public IndicatorTickOrCandleSource { // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), - Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)), iparams.shift + _shift); - if (iparams.is_draw) { + if (idparams.is_draw) { draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + _shift), _value, 1); } break; @@ -186,7 +207,7 @@ class Indi_Momentum : public IndicatorTickOrCandleSource { * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index 933d47ca7..48f259884 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -48,26 +48,47 @@ struct IndiOBVParams : IndicatorParams { IndiOBVParams(ENUM_APPLIED_PRICE _ap, int _shift = 0) : applied_price(_ap), IndicatorParams(INDI_OBV) { shift = _shift; }; - IndiOBVParams(IndiOBVParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiOBVParams(IndiOBVParams &_params) { THIS_REF = _params; }; }; /** * Implements the On Balance Volume indicator. */ -class Indi_OBV : public IndicatorTickOrCandleSource { +class Indi_OBV : public Indicator { public: /** * Class constructor. */ Indi_OBV(IndiOBVParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) {} - Indi_OBV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_OBV, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_OBV(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiOBVParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // Volume uses volume only. + return _ds PTR_DEREF HasSpecificValueStorage(INDI_VS_TYPE_VOLUME); + } /** * Returns the indicator value. @@ -117,7 +138,7 @@ class Indi_OBV : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -145,12 +166,12 @@ class Indi_OBV : public IndicatorTickOrCandleSource { * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /** * Get applied volume type (MT5 only). */ - ENUM_APPLIED_VOLUME GetAppliedVolume() { return iparams.applied_volume; } + ENUM_APPLIED_VOLUME GetAppliedVolume() override { return iparams.applied_volume; } /* Setters */ diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index 8c53a3bf6..b88ec377b 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -48,27 +48,35 @@ struct IndiOsMAParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\OsMA"); }; - IndiOsMAParams(IndiOsMAParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiOsMAParams(IndiOsMAParams &_params) { THIS_REF = _params; }; }; /** * Implements the Moving Average of Oscillator indicator. */ -class Indi_OsMA : public IndicatorTickOrCandleSource { +class Indi_OsMA : public Indicator { public: /** * Class constructor. */ Indi_OsMA(IndiOsMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) {} - Indi_OsMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_OSMA, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_OsMA(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiOsMAParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -115,7 +123,7 @@ class Indi_OsMA : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); double _value = EMPTY_VALUE; switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -162,7 +170,7 @@ class Indi_OsMA : public IndicatorTickOrCandleSource { * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index 76e1a7d7f..b3d954d93 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -34,40 +34,62 @@ struct IndiPivotParams : IndicatorParams { method = _method; shift = _shift; }; - IndiPivotParams(IndiPivotParams& _params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiPivotParams(IndiPivotParams& _params) { THIS_REF = _params; }; }; /** * Implements Pivot Detector. */ -class Indi_Pivot : public IndicatorTickOrCandleSource { +class Indi_Pivot : public Indicator { protected: /* Protected methods */ /** * Initialize. */ - void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 9); } + void Init() {} + + protected: + /* Protected methods */ public: /** * Class constructor. */ - Indi_Pivot(IndiPivotParams& _p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData* _indi_src = NULL, + Indi_Pivot(IndiPivotParams& _p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_INDICATOR, IndicatorData* _indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(9, TYPE_FLOAT, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) { + : Indicator(_p, IndicatorDataParams::GetInstance(9, TYPE_FLOAT, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { Init(); }; - Indi_Pivot(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_PIVOT, _tf, _shift) { - iparams.tf = _tf; + Indi_Pivot(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_INDICATOR, IndicatorData* _indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiPivotParams(), + IndicatorDataParams::GetInstance(9, TYPE_FLOAT, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { Init(); - }; + } + /** + * 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_CUSTOM; } + + public: + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData* _ds) override { + // Pivot uses OHLC only. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } /** * Returns the indicator's struct entry for the given shift. @@ -79,23 +101,23 @@ class Indi_Pivot : public IndicatorTickOrCandleSource { */ virtual IndicatorDataEntry GetEntry(int _shift = 0) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - long _bar_time = GetBarTime(_ishift); + long _bar_time = GetCandle() PTR_DEREF GetBarTime(_ishift); IndicatorDataEntry _entry = idata.GetByKey(_bar_time); if (_bar_time > 0 && !_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) { ResetLastError(); BarOHLC _ohlc = GetOHLC(_ishift); - _entry.timestamp = GetBarTime(_ishift); + _entry.timestamp = GetCandle() PTR_DEREF GetBarTime(_ishift); if (_ohlc.IsValid()) { _entry.Resize(Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))); - _ohlc.GetPivots(GetMethod(), _entry.values[0].value.vflt, _entry.values[1].value.vflt, - _entry.values[2].value.vflt, _entry.values[3].value.vflt, _entry.values[4].value.vflt, - _entry.values[5].value.vflt, _entry.values[6].value.vflt, _entry.values[7].value.vflt, - _entry.values[8].value.vflt); + _ohlc.GetPivots(GetMethod(), _entry.values[0].value.vdbl, _entry.values[1].value.vdbl, + _entry.values[2].value.vdbl, _entry.values[3].value.vdbl, _entry.values[4].value.vdbl, + _entry.values[5].value.vdbl, _entry.values[6].value.vdbl, _entry.values[7].value.vdbl, + _entry.values[8].value.vdbl); for (int i = 0; i <= 8; ++i) { - _entry.values[i].SetDataType(TYPE_FLOAT); + _entry.values[i].SetDataType(TYPE_DOUBLE); } } - GetEntryAlter(_entry, _ishift); + GetEntryAlter(_entry, _shift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { idata.Add(_entry, _bar_time); @@ -115,7 +137,7 @@ class Indi_Pivot : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); return GetEntry(_ishift)[_mode]; } @@ -156,7 +178,7 @@ class Indi_Pivot : public IndicatorTickOrCandleSource { switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // In this mode, price is fetched from chart. - _ohlc = Chart::GetOHLC(_shift); + _ohlc = GetCandle() PTR_DEREF GetOHLC(_shift); break; case IDATA_INDICATOR: // In this mode, price is fetched from given indicator. Such indicator diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index b02bb2c98..c6d066a11 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "Indi_ZigZag.mqh" // Structs. @@ -34,34 +34,53 @@ struct IndiPriceChannelParams : IndicatorParams { SetCustomIndicatorName("Examples\\Price_Channel"); shift = _shift; }; - IndiPriceChannelParams(IndiPriceChannelParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiPriceChannelParams(IndiPriceChannelParams &_params) { THIS_REF = _params; }; }; /** * Implements Price Channel indicator. */ -class Indi_PriceChannel : public IndicatorTickOrCandleSource { +class Indi_PriceChannel : public Indicator { public: /** * Class constructor. */ Indi_PriceChannel(IndiPriceChannelParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_PriceChannel(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_PRICE_CHANNEL, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_PriceChannel(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiPriceChannelParams(), + IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM; } /** - * Returns value for Price Channel indicator. + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. */ - static double iPriceChannel(string _symbol, ENUM_TIMEFRAMES _tf, int _period, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_PriceChannel", _period)); + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // PC uses high and low prices only. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH | PRICE_LOW); + } + + /** + * OnCalculate-based version of Price Channel indicator as there is no built-in one. + */ + static double iPriceChannel(IndicatorData *_indi, int _period, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_period)); return iPriceChannelOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, _shift, _cache); } @@ -87,16 +106,6 @@ class Indi_PriceChannel : public IndicatorTickOrCandleSource(_mode, _shift); } - /** - * On-indicator version of Price Channel. - */ - static double iPriceChannelOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, - int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, Util::MakeKey("Indi_PriceChannel_ON_" + _indi.GetFullName(), _period)); - return iPriceChannelOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, _shift, _cache); - } - /** * OnCalculate() method for Price Channel indicator. */ @@ -117,20 +126,20 @@ class Indi_PriceChannel : public IndicatorTickOrCandleSource= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_PriceChannel::iPriceChannel(GetSymbol(), GetTf(), GetPeriod(), _mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = iPriceChannel(THIS_PTR, GetPeriod(), _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _ishift); break; case IDATA_INDICATOR: - _value = Indi_PriceChannel::iPriceChannelOnIndicator(GetDataSource(), GetSymbol(), GetTf(), - /*[*/ GetPeriod() /*]*/, _mode, _ishift, THIS_PTR); + _value = iPriceChannel(THIS_PTR, GetPeriod(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index 1e1cf8bab..122dd8ff3 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" // Structs. struct IndiPriceFeederParams : IndicatorParams { @@ -40,33 +40,43 @@ struct IndiPriceFeederParams : IndicatorParams { * @todo Use more modes (full OHCL). */ IndiPriceFeederParams(const double& _price_data[], int _total = 0) : IndicatorParams(INDI_PRICE_FEEDER) { - tf = PERIOD_CURRENT; ArrayCopy(price_data, _price_data, 0, 0, _total == 0 ? WHOLE_ARRAY : _total); }; - IndiPriceFeederParams(IndiPriceFeederParams& _params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiPriceFeederParams(IndiPriceFeederParams& _params) { THIS_REF = _params; }; }; /** * Price Indicator. */ -class Indi_PriceFeeder : public IndicatorTickOrCandleSource { +class Indi_PriceFeeder : public Indicator { public: /** * Class constructor. */ Indi_PriceFeeder(IndiPriceFeederParams& _p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData* _indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src){}; - Indi_PriceFeeder(const double& _price_data[], int _total = 0) : IndicatorTickOrCandleSource(INDI_PRICE_FEEDER) { - ArrayCopy(iparams.price_data, _price_data); - }; - Indi_PriceFeeder(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_PRICE_FEEDER, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + Indi_PriceFeeder(const double& _price_data[], int _total = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData* _indi_src = NULL, int _indi_src_mode = 0) + : Indicator(IndiPriceFeederParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + Indi_PriceFeeder(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData* _indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiPriceFeederParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + + /** + * 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; } void SetPrices(const double& _price_data[], int _total = 0) { iparams = IndiPriceFeederParams(_price_data, _total); } @@ -78,7 +88,7 @@ class Indi_PriceFeeder : public IndicatorTickOrCandleSource= 0 ? _shift : iparams.GetShift(); @@ -91,7 +101,7 @@ class Indi_PriceFeeder : public IndicatorTickOrCandleSource::OnTick(); - if (iparams.is_draw) { + if (idparams.is_draw) { 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_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index fcd22323d..ec56c2e53 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" // Structs. @@ -35,34 +35,43 @@ struct IndiPriceVolumeTrendParams : IndicatorParams { SetCustomIndicatorName("Examples\\PVT"); shift = _shift; }; - IndiPriceVolumeTrendParams(IndiPriceVolumeTrendParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiPriceVolumeTrendParams(IndiPriceVolumeTrendParams &_params) { THIS_REF = _params; }; }; /** * Implements the Price Volume Trend indicator. */ -class Indi_PriceVolumeTrend : public IndicatorTickOrCandleSource { +class Indi_PriceVolumeTrend : public Indicator { public: /** * Class constructor. */ Indi_PriceVolumeTrend(IndiPriceVolumeTrendParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_PriceVolumeTrend(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_PRICE_VOLUME_TREND, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_PriceVolumeTrend(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : Indicator(IndiPriceVolumeTrendParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CANDLE | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } /** - * Built-in version of Price Volume Trend. + * OnCalculate-based version of Price Volume Trend as there is no built-in one. */ - static double iPVT(string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_PriceVolumeTrend", (int)_av)); + static double iPVT(IndicatorData *_indi, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey((int)_av)); return iPVTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _shift, _cache); } @@ -90,10 +99,8 @@ class Indi_PriceVolumeTrend : public IndicatorTickOrCandleSource= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = - Indi_PriceVolumeTrend::iPVT(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = iPVT(THIS_PTR, GetAppliedVolume(), _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetAppliedVolume() /*]*/, 0, _ishift); break; case IDATA_INDICATOR: - _value = Indi_PriceVolumeTrend::iPVTOnIndicator(GetDataSource(), GetSymbol(), GetTf(), - /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); + _value = iPVT(THIS_PTR, GetAppliedVolume(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index c8a657138..b19c0daea 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "OHLC/Indi_OHLC.mqh" #include "Special/Indi_Math.mqh" @@ -34,16 +34,13 @@ struct IndiRSParams : IndicatorParams { applied_volume = _applied_volume; shift = _shift; }; - IndiRSParams(IndiRSParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiRSParams(IndiRSParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_RS : public IndicatorTickOrCandleSource { +class Indi_RS : public Indicator { DictStruct> imath; public: @@ -52,29 +49,53 @@ class Indi_RS : public IndicatorTickOrCandleSource { */ Indi_RS(IndiRSParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_MATH, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_DIFF, _indi_src_mode), - _indi_src) { + : Indicator(_p, + IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_DIFF, _indi_src_mode), + _indi_src) { Init(); }; - Indi_RS(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_RS, _tf, _shift) { + Indi_RS(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_MATH, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiRSParams(), + IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_DIFF, _indi_src_mode), + _indi_src) { Init(); }; + /** + * 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_CUSTOM | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_MATH; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // RS uses OHLC. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } + void Init() { if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_MATH) { IndiOHLCParams _iohlc_params(); - // @todo Symbol should be already defined for a chart. - // @todo If it's not, move initialization to GetValue()/GetEntry() method. - Indi_OHLC *_iohlc = Indi_OHLC::GetCached(GetSymbol(), GetTf(), 0); IndiMathParams _imath0_p(MATH_OP_SUB, INDI_OHLC_CLOSE, 0, INDI_OHLC_CLOSE, 1); IndiMathParams _imath1_p(MATH_OP_SUB, INDI_OHLC_CLOSE, 1, INDI_OHLC_CLOSE, 0); - _imath0_p.SetTf(GetTf()); - _imath1_p.SetTf(GetTf()); Ref _imath0 = new Indi_Math(_imath0_p); Ref _imath1 = new Indi_Math(_imath1_p); - _imath0.Ptr().SetDataSource(_iohlc, 0); - _imath1.Ptr().SetDataSource(_iohlc, 0); imath.Set(0, _imath0); imath.Set(1, _imath1); } @@ -83,10 +104,13 @@ class Indi_RS : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_MATH: + // Updating Maths' data sources to be the same as RS data source. + imath.GetByKey(0) REF_DEREF SetDataSource(GetDataSource()); + imath.GetByKey(1) REF_DEREF SetDataSource(GetDataSource()); return imath[_mode].Ptr().GetEntryValue(); break; default: @@ -100,21 +124,4 @@ class Indi_RS : public IndicatorTickOrCandleSource { * Checks if indicator entry values are valid. */ virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return true; } - - /* Getters */ - - /** - * Get applied volume. - */ - ENUM_APPLIED_VOLUME GetAppliedVolume() { return iparams.applied_volume; } - - /* Setters */ - - /** - * Set applied volume. - */ - void SetAppliedVolume(ENUM_APPLIED_VOLUME _applied_volume) { - istate.is_changed = true; - iparams.applied_volume = _applied_volume; - } }; diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index e0707a65b..0826d327a 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -22,7 +22,7 @@ // Includes. #include "../DictStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "Indi_Bands.mqh" #include "Indi_CCI.mqh" #include "Indi_Envelopes.mqh" @@ -33,9 +33,9 @@ #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). -double iRSI(string _symbol, int _tf, int _period, ENUM_APPLIED_PRICE _ap, int _shift) { +double iRSI(string _symbol, int _tf, int _period, int _ap, int _shift) { ResetLastError(); - return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, _ap, _shift); + return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); } double iRSIOnArray(double &_arr[], int _total, int _period, int _shift) { ResetLastError(); @@ -56,12 +56,9 @@ struct IndiRSIParams : IndicatorParams { SetCustomIndicatorName("Examples\\RSI"); SetPeriod(_period); }; - IndiRSIParams(IndiRSIParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiRSIParams(IndiRSIParams &_params) { THIS_REF = _params; }; // Getters. - ENUM_APPLIED_PRICE GetAppliedPrice() { return applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return applied_price; } int GetPeriod() { return period; } // Setters. void SetPeriod(int _period) { period = _period; } @@ -87,7 +84,7 @@ struct RSIGainLossData { /** * Implements the Relative Strength Index indicator. */ -class Indi_RSI : public IndicatorTickOrCandleSource { +class Indi_RSI : public Indicator { DictStruct aux_data; public: @@ -96,10 +93,28 @@ class Indi_RSI : public IndicatorTickOrCandleSource { */ Indi_RSI(IndiRSIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), - _indi_src) {} - Indi_RSI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_RSI, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + Indi_RSI(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiRSIParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + + /** + * 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_AP; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * Returns applied price as set by the indicator's params. + */ + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.GetAppliedPrice(); } /** * Returns the indicator value. @@ -155,11 +170,11 @@ class Indi_RSI : public IndicatorTickOrCandleSource { * RSI values. To exactly replicate our RSI numbers, a formula will need at * least 250 data points." */ - static double iRSIOnIndicator(IndicatorData *_indi, Indi_RSI *_obj, string _symbol = NULL, + static double iRSIOnIndicator(Indi_RSI *_target, IndicatorData *_source, string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _period = 14, - ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0) { - long _bar_time_curr = _obj.GetBarTime(_shift); - long _bar_time_prev = _obj.GetBarTime(_shift + 1); + ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) { + long _bar_time_curr = _source PTR_DEREF GetBarTime(_shift); + long _bar_time_prev = _source PTR_DEREF GetBarTime(_shift + 1); if (fmin(_bar_time_curr, _bar_time_prev) < 0) { // Return empty value on invalid bar time. return EMPTY_VALUE; @@ -175,16 +190,17 @@ class Indi_RSI : public IndicatorTickOrCandleSource { RSIGainLossData last_data, new_data; unsigned int data_position; double diff; - int _mode = _obj.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)); - if (!_obj.aux_data.KeyExists(_bar_time_prev, data_position)) { + ValueStorage *_data = _source PTR_DEREF GetSpecificAppliedPriceValueStorage(_ap, _target); + + if (!_target PTR_DEREF aux_data.KeyExists(_bar_time_prev, data_position)) { // No previous SMMA-based average gain and loss. Calculating SMA-based ones. double sum_gain = 0; double sum_loss = 0; for (i = 1; i < (int)_period; i++) { - double price_new = _indi[(_shift + 1) + i - 1][_mode]; - double price_old = _indi[(_shift + 1) + i][_mode]; + double price_new = PTR_TO_REF(_data)[(_shift + 1) + i - 1].Get(); + double price_old = PTR_TO_REF(_data)[(_shift + 1) + i].Get(); if (price_new == 0.0 || price_old == 0.0) { // Missing history price data, skipping calculations. @@ -205,10 +221,10 @@ class Indi_RSI : public IndicatorTickOrCandleSource { last_data.avg_loss = sum_loss / _period; } else { // Data already exists, retrieving it by position got by KeyExists(). - last_data = _obj.aux_data.GetByPos(data_position); + last_data = _target PTR_DEREF aux_data.GetByPos(data_position); } - diff = _indi[_shift][_mode] - _indi[_shift + 1][_mode]; + diff = PTR_TO_REF(_data)[_shift].Get() - PTR_TO_REF(_data)[_shift + 1].Get(); double curr_gain = 0; double curr_loss = 0; @@ -221,7 +237,7 @@ class Indi_RSI : public IndicatorTickOrCandleSource { 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; - _obj.aux_data.Set(_bar_time_curr, new_data); + _target.aux_data.Set(_bar_time_curr, new_data); if (new_data.avg_loss == 0.0) { // @fixme Why 0 loss? @@ -291,7 +307,7 @@ class Indi_RSI : public IndicatorTickOrCandleSource { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; double _res[]; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); @@ -300,13 +316,15 @@ class Indi_RSI : public IndicatorTickOrCandleSource { _value = Indi_RSI::iRSI(GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), _ishift, THIS_PTR); break; + case IDATA_ONCALCULATE: + // @todo Modify iRSIOnIndicator() to operate on single IndicatorData pointer. + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ iparams.GetPeriod(), iparams.GetAppliedPrice() /* ] */, 0, _ishift); - Print(_value); break; case IDATA_INDICATOR: - _value = Indi_RSI::iRSIOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), iparams.GetPeriod(), + _value = Indi_RSI::iRSIOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), _ishift); break; } diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index a9b041c45..1d9ee3f2e 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -39,27 +39,39 @@ struct IndiRVIParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\RVI"); }; - IndiRVIParams(IndiRVIParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiRVIParams(IndiRVIParams &_params) { THIS_REF = _params; }; }; /** * Implements the Relative Vigor Index indicator. */ -class Indi_RVI : public IndicatorTickOrCandleSource { +class Indi_RVI : public Indicator { public: /** * Class constructor. */ Indi_RVI(const IndiRVIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) {} - Indi_RVI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_RVI, _tf, _shift) {} + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, + _indi_src_mode), + _indi_src) {} + Indi_RVI(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiRVIParams(), + IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, + _indi_src_mode), + _indi_src) {} + + /** + * 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 | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -106,7 +118,7 @@ class Indi_RVI : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index a5fba4459..67296bea3 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -22,8 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" -#include "../Storage/ValueStorage.price.h" +#include "../Indicator.mqh" // Structs. struct IndiRateOfChangeParams : IndicatorParams { @@ -37,35 +36,41 @@ struct IndiRateOfChangeParams : IndicatorParams { period = _period; shift = _shift; }; - IndiRateOfChangeParams(IndiRateOfChangeParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiRateOfChangeParams(IndiRateOfChangeParams &_params) { THIS_REF = _params; }; }; /** * Implements the Rate of Change indicator. */ -class Indi_RateOfChange : public IndicatorTickOrCandleSource { +class Indi_RateOfChange : public Indicator { public: /** * Class constructor. */ Indi_RateOfChange(IndiRateOfChangeParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_RateOfChange(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_RATE_OF_CHANGE, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_RateOfChange(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiRateOfChangeParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_AP; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } /** - * Built-in version of Rate of Change. + * Checks whether given data source satisfies our requirements. */ - static double iROC(string _symbol, ENUM_TIMEFRAMES _tf, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, - int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_symbol, _tf, _ap, - Util::MakeKey("Indi_RateOfChange", _period, (int)_ap)); + double iROC(IndicatorData *_indi, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_indi, _ap, Util::MakeKey(_period, (int)_ap)); return iROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _mode, _shift, _cache); } @@ -93,10 +98,9 @@ class Indi_RateOfChange : public IndicatorTickOrCandleSource= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_RateOfChange::iROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, - _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = iROC(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _ishift); break; case IDATA_INDICATOR: - _value = Indi_RateOfChange::iROCOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), - GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + _value = iROC(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -149,7 +152,7 @@ class Indi_RateOfChange : public IndicatorTickOrCandleSource { +class Indi_SAR : public Indicator { public: /** * Class constructor. */ Indi_SAR(IndiSARParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src) {} - Indi_SAR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_SAR, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + Indi_SAR(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiSARParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } /** * Returns the indicator value. @@ -105,7 +114,7 @@ class Indi_SAR : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 61e04f3f7..5c3334bf7 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickSource.h" +#include "../Indicator.mqh" #include "../Storage/ObjectsCache.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" @@ -63,26 +63,37 @@ struct IndiStdDevParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\StdDev"); }; - IndiStdDevParams(IndiStdDevParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiStdDevParams(IndiStdDevParams &_params) { THIS_REF = _params; }; }; /** * Implements the Standard Deviation indicator. */ -class Indi_StdDev : public IndicatorTickSource { +class Indi_StdDev : public Indicator { public: /** * Class constructor. */ Indi_StdDev(IndiStdDevParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src) {} - Indi_StdDev(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_STDDEV, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_StdDev(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiStdDevParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + /** + * 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_AP; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } /** * Calculates the Standard Deviation indicator and returns its value. @@ -127,20 +138,21 @@ class Indi_StdDev : public IndicatorTickSource { /** * Note that this method operates on current price (set by _applied_price). */ - static double iStdDevOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, - int _ma_shift, ENUM_APPLIED_PRICE _applied_price, int _shift = 0, + static double iStdDevOnIndicator(IndicatorData *_target, IndicatorData *_source, string _symbol, ENUM_TIMEFRAMES _tf, + int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, int _shift = 0, Indi_StdDev *_obj = NULL) { double _indi_value_buffer[]; double _std_dev; int i; - int _mode = _obj != NULL ? _obj.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)) : 0; + + ValueStorage *_data = _source PTR_DEREF GetSpecificAppliedPriceValueStorage(_ap, _target); ArrayResize(_indi_value_buffer, _ma_period); for (i = _shift; i < (int)_shift + (int)_ma_period; i++) { // Getting current indicator value. Input data may be shifted on // the graph, so we need to take that shift into consideration. - _indi_value_buffer[i - _shift] = _indi[i + _ma_shift][_mode]; + _indi_value_buffer[i - _shift] = PTR_TO_REF(_data)[i + _ma_shift].Get(); } double _ma = Indi_MA::SimpleMA(_shift, _ma_period, _indi_value_buffer); @@ -160,8 +172,7 @@ class Indi_StdDev : public IndicatorTickSource { return MathSqrt(std_dev / period); } - static double iStdDevOnArray(double &array[], int total, int ma_period, int ma_shift, ENUM_MA_METHOD ma_method, - int shift) { + static double iStdDevOnArray(double &array[], int total, int ma_period, int ma_shift, int ma_method, int shift) { #ifdef __MQL4__ return ::iStdDevOnArray(array, total, ma_period, ma_shift, ma_method, shift); #endif @@ -216,21 +227,27 @@ class Indi_StdDev : public IndicatorTickSource { _indi_price_feeder.SetPrices(price); IndiMAParams ma_params(period, 0, ma_method, PRICE_OPEN); + + /* Indi_MA *_indi_ma = Indi_MA::GetCached("Indi_StdDev:Unbuffered", (ENUM_TIMEFRAMES)-1, period, 0, ma_method, (ENUM_APPLIED_PRICE)-1); _indi_ma.SetDataSource(_indi_price_feeder, 0); // Using first and only mode from price feeder. - double _result = iStdDevOnIndicator(_indi_ma, NULL, NULL, period, 0, PRICE_OPEN, /*unused*/ 0); + double _result = iStdDevOnIndicator(_indi_ma, NULL, NULL, period, 0, PRICE_OPEN, 0); // Last parameter is unused. // We don't want to store reference to indicator too long. _indi_ma.SetDataSource(NULL, 0); return _result; + */ + Print(__FUNCTION__ + " must be refactored!"); + DebugBreak(); + return 0; } /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -238,13 +255,17 @@ class Indi_StdDev : public IndicatorTickSource { _value = Indi_StdDev::iStdDev(GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), _ishift, THIS_PTR); break; + case IDATA_ONCALCULATE: + _value = Indi_StdDev::iStdDevOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), + GetMAShift(), GetAppliedPrice(), _ishift, THIS_PTR); + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetMAPeriod(), GetMAShift(), GetMAMethod() /*]*/, 0, _ishift); break; case IDATA_INDICATOR: - _value = Indi_StdDev::iStdDevOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), - GetAppliedPrice(), _ishift, THIS_PTR); + _value = Indi_StdDev::iStdDevOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), + GetMAShift(), GetAppliedPrice(), _ishift, THIS_PTR); break; } return _value; @@ -276,7 +297,7 @@ class Indi_StdDev : public IndicatorTickSource { * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index 9aba9ec05..025e94022 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -52,28 +52,38 @@ struct IndiStochParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\Stochastic"); }; - IndiStochParams(IndiStochParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiStochParams(IndiStochParams &_params) { THIS_REF = _params; }; }; /** * Implements the Stochastic Oscillator. */ -class Indi_Stochastic : public IndicatorTickOrCandleSource { +class Indi_Stochastic : public Indicator { public: /** * Class constructor. */ Indi_Stochastic(IndiStochParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_RANGE, _indi_src_mode), - _indi_src) {} - Indi_Stochastic(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_STOCHASTIC, _tf, _shift) {} + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, + _indi_src_mode), + _indi_src) {} + Indi_Stochastic(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiStochParams(), + IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, + _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } /** * Calculates the Stochastic Oscillator and returns its value. @@ -124,7 +134,7 @@ class Indi_Stochastic : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -145,9 +155,7 @@ class Indi_Stochastic : public IndicatorTickOrCandleSource { /** * Checks if indicator entry values are valid. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { - return _entry.IsWithinRange(0, 101); - } + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return _entry.IsWithinRange(0, 101); } /* Getters */ diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index d69d90ffc..0d24d68ed 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -22,8 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" -#include "../Storage/ValueStorage.price.h" +#include "../Indicator.mqh" #include "Indi_MA.mqh" // Structs. @@ -40,27 +39,37 @@ struct IndiTEMAParams : IndicatorParams { shift = _shift; tema_shift = _tema_shift; }; - IndiTEMAParams(IndiTEMAParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiTEMAParams(IndiTEMAParams &_params) { THIS_REF = _params; }; }; /** * Implements the Triple Exponential Moving Average indicator. */ -class Indi_TEMA : public IndicatorTickOrCandleSource { +class Indi_TEMA : public Indicator { public: /** * Class constructor. */ Indi_TEMA(IndiTEMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_TEMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_TEMA, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_TEMA(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiTEMAParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_AP; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } /** * Built-in version of TEMA. @@ -70,9 +79,15 @@ class Indi_TEMA : public IndicatorTickOrCandleSource { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iTEMA(_symbol, _tf, _ma_period, _ma_shift, _ap), _mode, _shift); #else - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_symbol, _tf, _ap, - Util::MakeKey("Indi_TEMA", _ma_period, _ma_shift, (int)_ap)); - return iTEMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ma_period, _ma_shift, _mode, _shift, _cache); + if (_obj == nullptr) { + Print( + "Indi_TEMA::iTEMA() can work without supplying pointer to IndicatorData only in MQL5. In this platform " + "the pointer is required."); + DebugBreak(); + return 0; + } + + return iTEMAOnIndicator(_obj, _ma_period, _ma_shift, _ap, _mode, _shift); #endif } @@ -101,12 +116,9 @@ class Indi_TEMA : public IndicatorTickOrCandleSource { /** * On-indicator version of TEMA. */ - static double iTEMAOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, - int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( - _indi, _symbol, _tf, _ap, - Util::MakeKey("Indi_TEMA_ON_" + _indi.GetFullName(), _ma_period, _ma_shift, (int)_ap)); + static double iTEMAOnIndicator(IndicatorData *_indi, int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, + int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_indi, _ap, Util::MakeKey(_ma_period, _ma_shift, (int)_ap)); return iTEMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ma_period, _ma_shift, _mode, _shift, _cache); } @@ -142,21 +154,22 @@ class Indi_TEMA : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_TEMA::iTEMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetTEMAShift(), GetAppliedPrice() /*]*/, 0, - _ishift, THIS_PTR); + _value = Indi_TEMA::iTEMA(GetSymbol(), GetTf(), GetPeriod(), GetTEMAShift(), GetAppliedPrice(), 0, _ishift, + THIS_PTR); break; + case IDATA_ONCALCULATE: + _value = iTEMAOnIndicator(GetDataSource(), GetPeriod(), GetTEMAShift(), GetAppliedPrice(), _mode, _ishift); case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetTEMAShift() /*]*/, 0, _ishift); break; case IDATA_INDICATOR: - _value = Indi_TEMA::iTEMAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetTEMAShift(), - GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + _value = iTEMAOnIndicator(GetDataSource(), GetPeriod(), GetTEMAShift(), GetAppliedPrice(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -187,7 +200,7 @@ class Indi_TEMA : public IndicatorTickOrCandleSource { /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index 1b3bf67c2..851afe9c1 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -22,8 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" -#include "../Storage/ValueStorage.price.h" +#include "../Indicator.mqh" #include "Indi_MA.mqh" // Structs. @@ -38,27 +37,37 @@ struct IndiTRIXParams : IndicatorParams { period = _period; shift = _shift; }; - IndiTRIXParams(IndiTRIXParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiTRIXParams(IndiTRIXParams &_params) { THIS_REF = _params; }; }; /** * Implements the Triple Exponential Average indicator. */ -class Indi_TRIX : public IndicatorTickOrCandleSource { +class Indi_TRIX : public Indicator { public: /** * Class constructor. */ Indi_TRIX(IndiTRIXParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_TRIX(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_TRIX, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_TRIX(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiTRIXParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_AP; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } /** * Built-in version of TriX. @@ -68,9 +77,15 @@ class Indi_TRIX : public IndicatorTickOrCandleSource { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iTriX(_symbol, _tf, _ma_period, _ap), _mode, _shift); #else - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_symbol, _tf, _ap, - Util::MakeKey("Indi_TRIX", _ma_period, (int)_ap)); - return iTriXOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ma_period, _mode, _shift, _cache); + if (_obj == nullptr) { + Print( + "Indi_TRIX::iTriX() can work without supplying pointer to IndicatorData only in MQL5. In this platform " + "the pointer is required."); + DebugBreak(); + return 0; + } + + return iTriXOnIndicator(_obj, _ma_period, _ap, _mode, _shift); #endif } @@ -99,10 +114,9 @@ class Indi_TRIX : public IndicatorTickOrCandleSource { /** * On-indicator version of TriX. */ - static double iTriXOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, - ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( - _indi, _symbol, _tf, _ap, Util::MakeKey("Indi_TriX_ON_" + _indi.GetFullName(), _ma_period, (int)_ap)); + static double iTriXOnIndicator(IndicatorData *_indi, int _ma_period, ENUM_APPLIED_PRICE _ap, int _mode = 0, + int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_indi, _ap, Util::MakeKey(_ma_period, (int)_ap)); return iTriXOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ma_period, _mode, _shift, _cache); } @@ -140,7 +154,7 @@ class Indi_TRIX : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -148,13 +162,15 @@ class Indi_TRIX : public IndicatorTickOrCandleSource { _value = Indi_TRIX::iTriX(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); break; + case IDATA_ONCALCULATE: + _value = Indi_TRIX::iTriXOnIndicator(GetDataSource(), GetPeriod(), GetAppliedPrice(), _mode, _ishift); + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _ishift); break; case IDATA_INDICATOR: - _value = Indi_TRIX::iTriXOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), - GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + _value = Indi_TRIX::iTriXOnIndicator(GetDataSource(), GetPeriod(), GetAppliedPrice(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -172,7 +188,7 @@ class Indi_TRIX : public IndicatorTickOrCandleSource { /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index 0272f2d80..112319753 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" #include "Indi_ATR.mqh" #include "Indi_MA.mqh" @@ -52,42 +52,61 @@ struct IndiUltimateOscillatorParams : IndicatorParams { slow_k = _slow_k; slow_period = _slow_period; }; - IndiUltimateOscillatorParams(IndiUltimateOscillatorParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiUltimateOscillatorParams(IndiUltimateOscillatorParams &_params) { THIS_REF = _params; }; }; /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_UltimateOscillator : public IndicatorTickOrCandleSource { +class Indi_UltimateOscillator : public Indicator { public: /** * Class constructor. */ Indi_UltimateOscillator(IndiUltimateOscillatorParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_UltimateOscillator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_ULTIMATE_OSCILLATOR, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_UltimateOscillator(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : Indicator(IndiUltimateOscillatorParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // UO uses only low and close prices. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } /** - * Built-in version of Ultimate Oscillator. + * OnCalculate-based version of Ultimate Oscillator as there is no built-in one. */ - static double iUO(string _symbol, ENUM_TIMEFRAMES _tf, int _fast_period, int _middle_period, int _slow_period, - int _fast_k, int _middle_k, int _slow_k, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { + static double iUO(IndicatorData *_indi, int _fast_period, int _middle_period, int _slow_period, int _fast_k, + int _middle_k, int _slow_k, int _mode = 0, int _shift = 0) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( - _symbol, _tf, - Util::MakeKey("Indi_UltimateOscillator", _fast_period, _middle_period, _slow_period, _fast_k, _middle_k, - _slow_k)); + _indi, Util::MakeKey(_fast_period, _middle_period, _slow_period, _fast_k, _middle_k, _slow_k)); - IndicatorData *_indi_atr_fast = Indi_ATR::GetCached(_symbol, _tf, _fast_period); - IndicatorData *_indi_atr_middle = Indi_ATR::GetCached(_symbol, _tf, _middle_period); - IndicatorData *_indi_atr_slow = Indi_ATR::GetCached(_symbol, _tf, _slow_period); + // Will return Indi_ATRs with the same candles source as _indi's. + IndicatorData *_indi_atr_fast = Indi_ATR::GetCached(_indi, _fast_period); + IndicatorData *_indi_atr_middle = Indi_ATR::GetCached(_indi, _middle_period); + IndicatorData *_indi_atr_slow = Indi_ATR::GetCached(_indi, _slow_period); return iUOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _fast_period, _middle_period, _slow_period, _fast_k, _middle_k, _slow_k, _mode, _shift, _cache, _indi_atr_fast, _indi_atr_middle, _indi_atr_slow); @@ -118,26 +137,6 @@ class Indi_UltimateOscillator : public IndicatorTickOrCandleSource(_mode, _shift); } - /** - * On-indicator version of Ultimate Oscillator. - */ - static double iUOOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _fast_period, - int _middle_period, int _slow_period, int _fast_k, int _middle_k, int _slow_k, - int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, - Util::MakeKey("Indi_UltimateOscillator_ON_" + _indi.GetFullName(), _fast_period, _middle_period, _slow_period, - _fast_k, _middle_k, _slow_k)); - - // @fixit This won't work! Find a way to differentiate ATRs. - Indi_ATR *_indi_atr_fast = (Indi_ATR *)_indi.GetDataSource(INDI_ULTIMATE_OSCILLATOR_ATR_FAST); - Indi_ATR *_indi_atr_middle = (Indi_ATR *)_indi.GetDataSource(INDI_ULTIMATE_OSCILLATOR_ATR_MIDDLE); - Indi_ATR *_indi_atr_slow = (Indi_ATR *)_indi.GetDataSource(INDI_ULTIMATE_OSCILLATOR_ATR_SLOW); - - return iUOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _fast_period, _middle_period, _slow_period, _fast_k, - _middle_k, _slow_k, _mode, _shift, _cache, _indi_atr_fast, _indi_atr_middle, _indi_atr_slow); - } - /** * Provides built-in indicators whose can be used as data source. */ @@ -249,14 +248,14 @@ class Indi_UltimateOscillator : public IndicatorTickOrCandleSource= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_UltimateOscillator::iUO(GetSymbol(), GetTf(), /*[*/ GetFastPeriod(), GetMiddlePeriod(), - GetSlowPeriod(), GetFastK(), GetMiddleK(), GetSlowK() /*]*/, _mode, - _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = Indi_UltimateOscillator::iUO(THIS_PTR, GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), + GetMiddleK(), GetSlowK(), _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ @@ -266,9 +265,8 @@ class Indi_UltimateOscillator : public IndicatorTickOrCandleSource { +class Indi_VIDYA : public Indicator { public: /** * Class constructor. */ Indi_VIDYA(IndiVIDYAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_VIDYA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_VIDYA, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_VIDYA(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiVIDYAParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_AP; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { + return IDATA_BUILTIN | IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; + } /** * Built-in version of iVIDyA. @@ -73,10 +82,15 @@ class Indi_VIDYA : public IndicatorTickOrCandleSource { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iVIDyA(_symbol, _tf, _cmo_period, _ema_period, _ma_shift, _ap), _mode, _shift); #else - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT( - _symbol, _tf, _ap, Util::MakeKey("Indi_VIDYA", _cmo_period, _ema_period, _ma_shift, (int)_ap)); - return iVIDyAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _cmo_period, _ema_period, _ma_shift, _mode, _shift, - _cache); + if (_obj == nullptr) { + Print( + "Indi_VIDYA::iVIDyA() can work without supplying pointer to IndicatorData only in MQL5. In this platform " + "the pointer is required."); + DebugBreak(); + return 0; + } + + return iVIDyAOnIndicator(_obj, _symbol, _tf, _cmo_period, _ema_period, _ma_shift, _ap, _mode, _shift); #endif } @@ -108,9 +122,8 @@ class Indi_VIDYA : public IndicatorTickOrCandleSource { static double iVIDyAOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _cmo_period, int _ema_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( - _indi, _symbol, _tf, _ap, - Util::MakeKey("Indi_VIDYA_ON_" + _indi.GetFullName(), _cmo_period, _ema_period, _ma_shift, (int)_ap)); + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_indi, _ap, + Util::MakeKey(_cmo_period, _ema_period, _ma_shift, (int)_ap)); return iVIDyAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _cmo_period, _ema_period, _ma_shift, _mode, _shift, _cache); } @@ -164,7 +177,7 @@ class Indi_VIDYA : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -172,6 +185,11 @@ class Indi_VIDYA : public IndicatorTickOrCandleSource { _value = Indi_VIDYA::iVIDyA(GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift(), GetAppliedPrice() /*]*/, 0, _ishift, THIS_PTR); break; + case IDATA_ONCALCULATE: + _value = + Indi_VIDYA::iVIDyAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), + GetVIDYAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetCMOPeriod(), GetMAPeriod(), @@ -210,7 +228,7 @@ class Indi_VIDYA : public IndicatorTickOrCandleSource { /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return iparams.applied_price; } /* Setters */ diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index 0ee27980b..947090b0c 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" // Structs. @@ -37,34 +37,53 @@ struct IndiVROCParams : IndicatorParams { SetCustomIndicatorName("Examples\\VROC"); shift = _shift; }; - IndiVROCParams(IndiVROCParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiVROCParams(IndiVROCParams &_params) { THIS_REF = _params; }; }; /** * Implements the Volume Rate of Change indicator. */ -class Indi_VROC : public IndicatorTickOrCandleSource { +class Indi_VROC : public Indicator { public: /** * Class constructor. */ Indi_VROC(IndiVROCParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_VROC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_VROC, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_VROC(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiVROCParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // VROC uses volume only. + return _ds PTR_DEREF HasSpecificValueStorage(INDI_VS_TYPE_VOLUME); + } /** - * Built-in version of VROC. + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. */ - static double iVROC(string _symbol, ENUM_TIMEFRAMES _tf, int _period, ENUM_APPLIED_VOLUME _av, int _mode = 0, - int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_VROC", _period, (int)_av)); + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * OnCalculate-based version of VROC as there is no built-in one. + */ + static double iVROC(IndicatorData *_indi, int _period, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_period, (int)_av)); return iVROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _av, _mode, _shift, _cache); } @@ -89,16 +108,6 @@ class Indi_VROC : public IndicatorTickOrCandleSource { return _cache.GetTailValue(_mode, _shift); } - /** - * On-indicator version of VROC indicator. - */ - static double iVROCOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, - ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, Util::MakeKey("Indi_VROC_ON_" + _indi.GetFullName(), _period, (int)_av)); - return iVROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _av, _mode, _shift, _cache); - } - /** * OnCalculate() method for VROC indicator. */ @@ -144,21 +153,20 @@ class Indi_VROC : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_VROC::iVROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _ishift, - THIS_PTR); + case IDATA_ONCALCULATE: + _value = iVROC(THIS_PTR, GetPeriod(), GetAppliedVolume(), _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _ishift); break; case IDATA_INDICATOR: - _value = Indi_VROC::iVROCOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), - GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); + _value = iVROC(THIS_PTR, GetPeriod(), GetAppliedVolume(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index d0632aeda..f68aeddc9 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" // Structs. @@ -34,34 +34,55 @@ struct IndiVolumesParams : IndicatorParams { SetCustomIndicatorName("Examples\\Volumes"); shift = _shift; }; - IndiVolumesParams(IndiVolumesParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiVolumesParams(IndiVolumesParams &_params) { THIS_REF = _params; }; }; /** * Implements the Volumes indicator. */ -class Indi_Volumes : public IndicatorTickOrCandleSource { +class Indi_Volumes : public Indicator { public: /** * Class constructor. */ Indi_Volumes(IndiVolumesParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_Volumes(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_VOLUMES, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_Volumes(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiVolumesParams(), + IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } /** - * Built-in version of Volumes. + * Checks whether given data source satisfies our requirements. */ - static double iVolumes(string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_Volumes", (int)_av)); + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // Volume uses volume only. + return _ds PTR_DEREF HasSpecificValueStorage(INDI_VS_TYPE_VOLUME); + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * OnCalculate-based version of Volumes as there is no built-in one. + */ + static double iVolumes(IndicatorData *_indi, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey((int)_av)); return iVolumesOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _shift, _cache); } @@ -86,16 +107,6 @@ class Indi_Volumes : public IndicatorTickOrCandleSource { return _cache.GetTailValue(_mode, _shift); } - /** - * On-indicator version of Volumes indicator. - */ - static double iVolumesOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_VOLUME _av, - int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, Util::MakeKey("Indi_Volumes_ON_" + _indi.GetFullName(), (int)_av)); - return iVolumesOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _shift, _cache); - } - /** * OnCalculate() method for Volumes indicator. */ @@ -136,20 +147,20 @@ class Indi_Volumes : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_Volumes::iVolumes(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = Indi_Volumes::iVolumes(THIS_PTR, GetAppliedVolume(), _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift); break; case IDATA_INDICATOR: - _value = Indi_Volumes::iVolumesOnIndicator(GetDataSource(), GetSymbol(), GetTf(), - /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); + _value = Indi_Volumes::iVolumes(THIS_PTR, GetAppliedVolume(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_WPR.mqh b/Indicators/Indi_WPR.mqh index a04c6cd8f..afa9bfafd 100644 --- a/Indicators/Indi_WPR.mqh +++ b/Indicators/Indi_WPR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -39,26 +39,40 @@ struct IndiWPRParams : IndicatorParams { shift = _shift; SetCustomIndicatorName("Examples\\WPR"); }; - IndiWPRParams(IndiWPRParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiWPRParams(IndiWPRParams &_params) { THIS_REF = _params; }; }; /** * Implements the Larry Williams' Percent Range. */ -class Indi_WPR : public IndicatorTickOrCandleSource { +class Indi_WPR : public Indicator { public: /** * Class constructor. */ Indi_WPR(IndiWPRParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), - _indi_src) {} - Indi_WPR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_WPR, _tf, _shift) {} + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + Indi_WPR(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiWPRParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + /** + * 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 | IDATA_ICUSTOM; } + + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return _entry.IsWithinRange(-100.0, 0.0); } /** * Calculates the Larry Williams' Percent Range and returns its value. @@ -103,7 +117,7 @@ class Indi_WPR : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index 87bfb5b01..96792d428 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" // Structs. @@ -32,33 +32,55 @@ struct IndiWilliamsADParams : IndicatorParams { SetCustomIndicatorName("Examples\\W_AD"); shift = _shift; }; - IndiWilliamsADParams(IndiWilliamsADParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiWilliamsADParams(IndiWilliamsADParams &_params) { THIS_REF = _params; }; }; /** * Implements the Volume Rate of Change indicator. */ -class Indi_WilliamsAD : public IndicatorTickOrCandleSource { +class Indi_WilliamsAD : public Indicator { public: /** * Class constructor. */ Indi_WilliamsAD(IndiWilliamsADParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_WilliamsAD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_WILLIAMS_AD, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_WilliamsAD(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiWilliamsADParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM; } /** - * Built-in version of Williams' AD. + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. */ - static double iWAD(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_WilliamsAD"); + unsigned int GetPossibleDataModes() override { return IDATA_ONCALCULATE | IDATA_ICUSTOM | IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // WAD use only high, low and close price. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } + + /** + * OnCalculate-based version of Williams' AD as there is no built-in one. + */ + static double iWAD(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); return iWADOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -83,16 +105,6 @@ class Indi_WilliamsAD : public IndicatorTickOrCandleSource return _cache.GetTailValue(_mode, _shift); } - /** - * On-indicator version of Williams' AD. - */ - static double iWADOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, - int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, - Util::MakeKey("Indi_WilliamsAD_ON_" + _indi.GetFullName())); - return iWADOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); - } - /** * OnCalculate() method for Williams' AD indicator. */ @@ -137,18 +149,19 @@ class Indi_WilliamsAD : public IndicatorTickOrCandleSource /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_WilliamsAD::iWAD(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = iWAD(THIS_PTR, _mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), 0, _ishift); break; case IDATA_INDICATOR: - _value = Indi_WilliamsAD::iWADOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + _value = iWAD(THIS_PTR, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index 281664f9a..fbf82f5b5 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -21,9 +21,16 @@ */ // Includes. -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" +// Defines. +#ifdef __MQL4__ +#define INDI_ZIGZAG_PATH "ZigZag" +#else +#define INDI_ZIGZAG_PATH "Examples\\ZigZag" +#endif + // Enums. // Indicator mode identifiers used in ZigZag indicator. enum ENUM_ZIGZAG_LINE { ZIGZAG_BUFFER = 0, ZIGZAG_HIGHMAP = 1, ZIGZAG_LOWMAP = 2, FINAL_ZIGZAG_LINE_ENTRY }; @@ -37,12 +44,9 @@ struct IndiZigZagParams : IndicatorParams { IndiZigZagParams(unsigned int _depth = 12, unsigned int _deviation = 5, unsigned int _backstep = 3, int _shift = 0) : depth(_depth), deviation(_deviation), backstep(_backstep), IndicatorParams(INDI_ZIGZAG) { shift = _shift; - SetCustomIndicatorName("Examples\\ZigZag"); - }; - IndiZigZagParams(IndiZigZagParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; + SetCustomIndicatorName(INDI_ZIGZAG_PATH); }; + IndiZigZagParams(IndiZigZagParams &_params) { THIS_REF = _params; }; }; enum EnSearchMode { @@ -54,19 +58,53 @@ enum EnSearchMode { /** * Implements ZigZag indicator. */ -class Indi_ZigZag : public IndicatorTickOrCandleSource { +class Indi_ZigZag : public Indicator { public: /** * Class constructor. */ Indi_ZigZag(IndiZigZagParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_ZIGZAG_LINE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_PRICE_ON_SIGNAL), - _indi_src) {} - Indi_ZigZag(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_ZIGZAG, _tf, _shift) {} + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_ZIGZAG_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE_ON_SIGNAL), + _indi_src) {} + Indi_ZigZag(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiZigZagParams(), + IndicatorDataParams::GetInstance(FINAL_ZIGZAG_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE_ON_SIGNAL), + _indi_src) {} + /** + * 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_CUSTOM | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { +#ifdef __MQL__ + return IDATA_ICUSTOM | IDATA_ONCALCULATE | IDATA_INDICATOR; +#else + return IDATA_ONCALCULATE | IDATA_INDICATOR | IDATA_ICUSTOM; +#endif + } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // ZigZag uses only high and low prices. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW); + } /** * Returns value for ZigZag indicator. @@ -107,10 +145,9 @@ class Indi_ZigZag : public IndicatorTickOrCandleSource { /** * Returns value for ZigZag indicator. */ - static double iZigZag(string _symbol, ENUM_TIMEFRAMES _tf, int _depth, int _deviation, int _backstep, - ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0, Indi_ZigZag *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, - Util::MakeKey("Indi_ZigZag", _depth, _deviation, _backstep)); + static double iZigZag(IndicatorData *_indi, int _depth, int _deviation, int _backstep, ENUM_ZIGZAG_LINE _mode = 0, + int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_depth, _deviation, _backstep)); return iZigZagOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, _shift, _cache); } @@ -137,18 +174,6 @@ class Indi_ZigZag : public IndicatorTickOrCandleSource { return _cache.GetTailValue(_mode, _shift); } - /** - * On-indicator version of ZigZag indicator. - */ - static double iZigZagOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _depth, - int _deviation, int _backstep, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, Util::MakeKey("Indi_ZigZag_ON_" + _indi.GetFullName(), _depth, _deviation, _backstep)); - return iZigZagOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, _shift, - _cache); - } - /** * OnCalculate() method for ZigZag indicator. */ @@ -211,7 +236,7 @@ class Indi_ZigZag : public IndicatorTickOrCandleSource { if ((low[shift] - val) > InpDeviation * _Point) { val = 0.0; } else { - for (back = 1; back <= InpBackstep; back++) { + for (back = InpBackstep; back >= 1 && shift >= back; back--) { res = LowMapBuffer[shift - back].Get(); if ((res != 0) && (res > val)) LowMapBuffer[shift - back] = 0.0; } @@ -227,7 +252,7 @@ class Indi_ZigZag : public IndicatorTickOrCandleSource { if ((val - high[shift].Get()) > InpDeviation * _Point) { val = 0.0; } else { - for (back = 1; back <= InpBackstep; back++) { + for (back = InpBackstep; back >= 1 && shift >= back; back--) { res = HighMapBuffer[shift - back].Get(); if ((res != 0) && (res < val)) HighMapBuffer[shift - back] = 0.0; } @@ -348,13 +373,13 @@ class Indi_ZigZag : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_ZigZag::iZigZag(GetSymbol(), GetTf(), /*[*/ GetDepth(), GetDeviation(), GetBackstep() /*]*/, - (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = iZigZag(THIS_PTR, GetDepth(), GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, _ishift); break; case IDATA_ICUSTOM: _value = @@ -362,8 +387,7 @@ class Indi_ZigZag : public IndicatorTickOrCandleSource { GetDeviation(), GetBackstep() /*]*/, (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_INDICATOR: - _value = Indi_ZigZag::iZigZagOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetDepth(), - GetDeviation(), GetBackstep() /*]*/, _mode, _ishift, THIS_PTR); + _value = iZigZag(THIS_PTR, GetDepth(), GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -374,9 +398,7 @@ class Indi_ZigZag : public IndicatorTickOrCandleSource { /** * Checks if indicator entry values are valid. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { - return !_entry.HasValue(EMPTY_VALUE); - } + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return !_entry.HasValue(EMPTY_VALUE); } /* Getters */ diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 63a569429..6cd13b0e5 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator.mqh" #include "../Storage/ValueStorage.all.h" #include "Indi_ZigZag.mqh" @@ -42,35 +42,59 @@ struct IndiZigZagColorParams : IndicatorParams { SetCustomIndicatorName("Examples\\ZigZagColor"); shift = _shift; }; - IndiZigZagColorParams(IndiZigZagColorParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiZigZagColorParams(IndiZigZagColorParams &_params) { THIS_REF = _params; }; }; /** * Implements the Volume Rate of Change indicator. */ -class Indi_ZigZagColor : public IndicatorTickOrCandleSource { +class Indi_ZigZagColor : public Indicator { public: /** * Class constructor. */ Indi_ZigZagColor(IndiZigZagColorParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( + : Indicator( _p, IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), _indi_src){}; - Indi_ZigZagColor(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_VROC, _tf, _shift){}; + 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){}; + /** + * 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_CUSTOM | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_ICUSTOM | IDATA_ONCALCULATE; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // ZigZagColor uses only high and low prices. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW); + } /** * Returns value for ZigZag Color indicator. */ - static double iZigZagColor(string _symbol, ENUM_TIMEFRAMES _tf, int _depth, int _deviation, int _backstep, - ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( - _symbol, _tf, Util::MakeKey("Indi_ZigZagColor", _depth, _deviation, _backstep)); + static double iZigZagColor(IndicatorData *_indi, int _depth, int _deviation, int _backstep, + ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_depth, _deviation, _backstep)); return iZigZagColorOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, _shift, _cache); } @@ -99,19 +123,6 @@ class Indi_ZigZagColor : public IndicatorTickOrCandleSource(_mode, _shift); } - /** - * On-indicator version of ZigZag indicator. - */ - static double iZigZagColorOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _depth, - int _deviation, int _backstep, int _mode = 0, int _shift = 0, - IndicatorData *_obj = NULL) { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( - _indi, _symbol, _tf, - Util::MakeKey("Indi_ZigZagColor_ON_" + _indi.GetFullName(), _depth, _deviation, _backstep)); - return iZigZagColorOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, _shift, - _cache); - } - /** * OnCalculate() method for ZigZag Color indicator. */ @@ -174,7 +185,7 @@ class Indi_ZigZagColor : public IndicatorTickOrCandleSource (InpDeviation * _Point)) val = 0.0; else { - for (back = InpBackstep; back >= 1; back--) { + for (back = InpBackstep; back >= 1 && shift >= back; back--) { res = LowMapBuffer[shift - back].Get(); //--- if ((res != 0) && (res > val)) LowMapBuffer[shift - back] = 0.0; @@ -194,7 +205,7 @@ class Indi_ZigZagColor : public IndicatorTickOrCandleSource (InpDeviation * _Point)) val = 0.0; else { - for (back = InpBackstep; back >= 1; back--) { + for (back = InpBackstep; back >= 1 && shift >= back; back--) { res = HighMapBuffer[shift - back].Get(); //--- if ((res != 0) && (res < val)) HighMapBuffer[shift - back] = 0.0; @@ -284,23 +295,18 @@ class Indi_ZigZagColor : public IndicatorTickOrCandleSource= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { - case IDATA_BUILTIN: - _value = Indi_ZigZagColor::iZigZagColor(GetSymbol(), GetTf(), /*[*/ GetDepth(), GetDeviation(), - GetBackstep() /*]*/, (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); + case IDATA_ONCALCULATE: + _value = Indi_ZigZagColor::iZigZagColor(THIS_PTR, GetDepth(), GetDeviation(), GetBackstep(), + (ENUM_ZIGZAG_LINE)_mode, _ishift); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetDepth(), GetDeviation(), GetBackstep() /*]*/, _mode, _ishift); break; - case IDATA_INDICATOR: - _value = - Indi_ZigZagColor::iZigZagColorOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetDepth(), - GetDeviation(), GetBackstep() /*]*/, _mode, _ishift, THIS_PTR); - break; default: SetUserError(ERR_INVALID_PARAMETER); break; @@ -311,9 +317,7 @@ class Indi_ZigZagColor : public IndicatorTickOrCandleSource() != EMPTY_VALUE; - } + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return _entry.values[0].Get() != EMPTY_VALUE; } /* Getters */ diff --git a/Indicators/OHLC/Indi_OHLC.mqh b/Indicators/OHLC/Indi_OHLC.mqh index e1018bfc6..5a013fc73 100644 --- a/Indicators/OHLC/Indi_OHLC.mqh +++ b/Indicators/OHLC/Indi_OHLC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator/IndicatorTickOrCandleSource.h" +#include "../../Indicator.mqh" #include "../../Storage/Objects.h" // Enums. @@ -38,33 +38,58 @@ enum ENUM_INDI_OHLC_MODE { struct IndiOHLCParams : IndicatorParams { // Struct constructor. IndiOHLCParams(int _shift = 0) : IndicatorParams(INDI_OHLC) { SetShift(_shift); }; - IndiOHLCParams(IndiOHLCParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + IndiOHLCParams(IndiOHLCParams &_params) { THIS_REF = _params; }; }; /** * OHLC Indicator. */ -class Indi_OHLC : public IndicatorTickOrCandleSource { +class Indi_OHLC : public Indicator { public: /** * Class constructor. */ Indi_OHLC(IndiOHLCParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource(_p, - IndicatorDataParams::GetInstance(FINAL_INDI_OHLC_MODE_ENTRY, TYPE_DOUBLE, _idstype, - IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src){}; - Indi_OHLC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_PRICE, _tf, _shift){}; + : Indicator(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_OHLC_MODE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, + _indi_src_mode), + _indi_src){}; + Indi_OHLC(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiOHLCParams(), + IndicatorDataParams::GetInstance(FINAL_INDI_OHLC_MODE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, + _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // OHLC are required from data source. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); ENUM_APPLIED_PRICE _ap = PRICE_OPEN; switch (_mode) { @@ -81,25 +106,6 @@ class Indi_OHLC : public IndicatorTickOrCandleSource { _ap = PRICE_LOW; break; } - return ChartStatic::iPrice(_ap, GetSymbol(), GetTf(), _ishift); - } - - /** - * Returns already cached version of Indi_OHLC for a given parameters. - */ - static Indi_OHLC *GetCached(string _symbol, ENUM_TIMEFRAMES _tf, int _shift) { - String _cache_key; - _cache_key.Add(_symbol); - _cache_key.Add((int)_tf); - _cache_key.Add(_shift); - string _key = _cache_key.ToString(); - Indi_OHLC *_indi_ohlc; - if (!Objects::TryGet(_key, _indi_ohlc)) { - IndiOHLCParams _indi_ohlc_params(_shift); - _indi_ohlc_params.SetTf(_tf); - _indi_ohlc = Objects::Set(_key, new Indi_OHLC(_indi_ohlc_params)); - _indi_ohlc.SetSymbol(_symbol); - } - return _indi_ohlc; + return GetDataSource() PTR_DEREF GetPrice(_ap, _shift); } }; diff --git a/Indicators/OHLC/indicators.h b/Indicators/OHLC/indicators.h index 9505d5926..be9752c28 100644 --- a/Indicators/OHLC/indicators.h +++ b/Indicators/OHLC/indicators.h @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2021, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index 87073dc81..a1ee87de2 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -22,7 +22,8 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator/IndicatorTickOrCandleSource.h" +#include "../../Indicator.mqh" +#include "../../Platform.h" #include "../../Storage/Objects.h" // Structs. @@ -32,12 +33,9 @@ struct PriceIndiParams : IndicatorParams { PriceIndiParams(ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) : ap(_ap), IndicatorParams(INDI_PRICE) { SetShift(_shift); }; - PriceIndiParams(PriceIndiParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; + PriceIndiParams(PriceIndiParams &_params) { THIS_REF = _params; }; // Getters. - ENUM_APPLIED_PRICE GetAppliedPrice() { return ap; } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return ap; } // Setters. void SetAppliedPrice(ENUM_APPLIED_PRICE _ap) { ap = _ap; } }; @@ -45,18 +43,27 @@ struct PriceIndiParams : IndicatorParams { /** * Price Indicator. */ -class Indi_Price : public IndicatorTickOrCandleSource { +class Indi_Price : public Indicator { public: /** * Class constructor. */ Indi_Price(PriceIndiParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), - _indi_src){}; - Indi_Price(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_PRICE, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + Indi_Price(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(PriceIndiParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + virtual unsigned int GetSuitableDataSourceTypes() { + // We can work only with Candle-based indicator attached. + return INDI_SUITABLE_DS_TYPE_CANDLE; + } /** * Checks whether indicator has a valid value for a given shift. @@ -66,15 +73,17 @@ class Indi_Price : public IndicatorTickOrCandleSource { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - return ChartStatic::iPrice(iparams.GetAppliedPrice(), GetSymbol(), GetTf(), _ishift); + return GetCandle() PTR_DEREF GetSpecificAppliedPriceValueStorage(iparams.GetAppliedPrice()) + PTR_DEREF Fetch(_ishift); } /** * Returns already cached version of Indi_Price for a given parameters. */ - static Indi_Price *GetCached(string _symbol, ENUM_APPLIED_PRICE _ap, ENUM_TIMEFRAMES _tf, int _shift) { + static Indi_Price *GetPlatformPrices(string _symbol, ENUM_APPLIED_PRICE _ap, ENUM_TIMEFRAMES _tf, int _shift, + IndicatorData *_base_indi = nullptr) { String _cache_key; _cache_key.Add(_symbol); _cache_key.Add((int)_ap); @@ -84,9 +93,13 @@ class Indi_Price : public IndicatorTickOrCandleSource { Indi_Price *_indi_price; if (!Objects::TryGet(_key, _indi_price)) { PriceIndiParams _indi_price_params(_ap, _shift); - _indi_price_params.SetTf(_tf); _indi_price = Objects::Set(_key, new Indi_Price(_indi_price_params)); - _indi_price.SetSymbol(_symbol); + + if (_base_indi == nullptr) { + Platform::BindDefaultDataSource(_indi_price, _symbol, _tf); + } else { + _indi_price PTR_DEREF SetDataSource(_base_indi PTR_DEREF GetCandle()); + } } return _indi_price; } @@ -99,21 +112,22 @@ class Indi_Price : public IndicatorTickOrCandleSource { switch (_type) { case INDI_VS_TYPE_PRICE_ASK: // Tick. case INDI_VS_TYPE_PRICE_BID: // Tick. - return GetCached(GetSymbol(), iparams.GetAppliedPrice(), GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), iparams.GetAppliedPrice(), GetTf(), iparams.GetShift()) + .GetValueStorage(0); case INDI_VS_TYPE_PRICE_OPEN: // Candle. - return GetCached(GetSymbol(), PRICE_OPEN, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_OPEN, GetTf(), iparams.GetShift()).GetValueStorage(0); case INDI_VS_TYPE_PRICE_HIGH: // Candle. - return GetCached(GetSymbol(), PRICE_HIGH, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_HIGH, GetTf(), iparams.GetShift()).GetValueStorage(0); case INDI_VS_TYPE_PRICE_LOW: // Candle. - return GetCached(GetSymbol(), PRICE_LOW, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_LOW, GetTf(), iparams.GetShift()).GetValueStorage(0); case INDI_VS_TYPE_PRICE_CLOSE: // Candle. - return GetCached(GetSymbol(), PRICE_CLOSE, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_CLOSE, GetTf(), iparams.GetShift()).GetValueStorage(0); case INDI_VS_TYPE_PRICE_MEDIAN: // Candle. - return GetCached(GetSymbol(), PRICE_MEDIAN, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_MEDIAN, GetTf(), iparams.GetShift()).GetValueStorage(0); case INDI_VS_TYPE_PRICE_TYPICAL: // Candle. - return GetCached(GetSymbol(), PRICE_TYPICAL, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_TYPICAL, GetTf(), iparams.GetShift()).GetValueStorage(0); case INDI_VS_TYPE_PRICE_WEIGHTED: // Candle. - return GetCached(GetSymbol(), PRICE_WEIGHTED, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_WEIGHTED, GetTf(), iparams.GetShift()).GetValueStorage(0); default: // Trying in parent class. return Indicator::GetSpecificValueStorage(_type); diff --git a/Indicators/Price/indicators.h b/Indicators/Price/indicators.h index 9d03bab40..2186dee41 100644 --- a/Indicators/Price/indicators.h +++ b/Indicators/Price/indicators.h @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2021, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ diff --git a/Indicators/Special/Indi_Custom.mqh b/Indicators/Special/Indi_Custom.mqh index 7820b98b5..4e5a8a676 100644 --- a/Indicators/Special/Indi_Custom.mqh +++ b/Indicators/Special/Indi_Custom.mqh @@ -1,5 +1,5 @@ //+------------------------------------------------------------------+ -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -33,7 +33,7 @@ #endif // Includes. -#include "../../Indicator/IndicatorTickOrCandleSource.h" +#include "../../Indicator.mqh" // Structs. @@ -44,10 +44,7 @@ struct IndiCustomParams : public IndicatorParams { IndiCustomParams(string _filepath = INDI_CUSTOM_PATH, int _shift = 0) : IndicatorParams(INDI_CUSTOM) { custom_indi_name = _filepath; } - IndiCustomParams(IndiCustomParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - } + IndiCustomParams(IndiCustomParams &_params) { THIS_REF = _params; } // Getters. DataParamEntry GetParam(int _index) const { return iargs[_index - 1]; } int GetParamsSize() const { return ArraySize(iargs); } @@ -73,18 +70,30 @@ struct IndiCustomParams : public IndicatorParams { /** * Implements indicator class. */ -class Indi_Custom : public IndicatorTickOrCandleSource { +class Indi_Custom : public Indicator { public: /** * Class constructor. */ Indi_Custom(IndiCustomParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_ICUSTOM, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_UNKNOWN, _indi_src_mode), - _indi_src) {} - Indi_Custom(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_CUSTOM, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_UNKNOWN, _indi_src_mode), + _indi_src) {} + Indi_Custom(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_ICUSTOM, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiCustomParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + + /** + * 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_ICUSTOM; } /** * Returns the indicator's value. diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index 6cf694d13..537b7848e 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator/IndicatorTickOrCandleSource.h" +#include "../../Indicator.mqh" #include "../../Math.enum.h" enum ENUM_MATH_OP_MODE { MATH_OP_MODE_BUILTIN, MATH_OP_MODE_CUSTOM_FUNCTION }; @@ -41,8 +41,7 @@ struct IndiMathParams : IndicatorParams { // Struct constructor. IndiMathParams(ENUM_MATH_OP _op = MATH_OP_SUB, unsigned int _mode_1 = 0, unsigned int _mode_2 = 1, - unsigned int _shift_1 = 0, unsigned int _shift_2 = 0, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + unsigned int _shift_1 = 0, unsigned int _shift_2 = 0, int _shift = 0) : IndicatorParams(INDI_SPECIAL_MATH) { mode_1 = _mode_1; mode_2 = _mode_2; @@ -51,13 +50,11 @@ struct IndiMathParams : IndicatorParams { shift = _shift; shift_1 = _shift_1; shift_2 = _shift_2; - tf = _tf; }; // Struct constructor. IndiMathParams(MathCustomOpFunction _op, unsigned int _mode_1 = 0, unsigned int _mode_2 = 1, - unsigned int _shift_1 = 0, unsigned int _shift_2 = 0, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + unsigned int _shift_1 = 0, unsigned int _shift_2 = 0, int _shift = 0) : IndicatorParams(INDI_SPECIAL_MATH) { mode_1 = _mode_1; mode_2 = _mode_2; @@ -66,34 +63,58 @@ struct IndiMathParams : IndicatorParams { shift = _shift; shift_1 = _shift_1; shift_2 = _shift_2; - tf = _tf; - }; - IndiMathParams(IndiMathParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; }; + IndiMathParams(IndiMathParams &_params) { THIS_REF = _params; }; }; /** * Implements the Volume Rate of Change indicator. */ -class Indi_Math : public IndicatorTickOrCandleSource { +class Indi_Math : public Indicator { public: /** * Class constructor. */ Indi_Math(IndiMathParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_INDICATOR, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) - : IndicatorTickOrCandleSource( - _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), - _indi_src){}; - Indi_Math(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : IndicatorTickOrCandleSource(INDI_SPECIAL_MATH, _tf, _shift){}; + : Indicator(_p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_Math(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_INDICATOR, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(IndiMathParams(), + IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + /** + * 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_CUSTOM | INDI_SUITABLE_DS_TYPE_BASE_ONLY; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_INDICATOR; } + + /** + * Checks whether given data source satisfies our requirements. + */ + bool OnCheckIfSuitableDataSource(IndicatorData *_ds) override { + if (Indicator::OnCheckIfSuitableDataSource(_ds)) { + return true; + } + + // RS uses OHLC. + return _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_OPEN) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_HIGH) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_LOW) && + _ds PTR_DEREF HasSpecificAppliedPriceValueStorage(PRICE_CLOSE); + } /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { diff --git a/Indicators/Special/indicators.h b/Indicators/Special/indicators.h index c93850078..a99faecca 100644 --- a/Indicators/Special/indicators.h +++ b/Indicators/Special/indicators.h @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2021, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ diff --git a/Indicators/Special/tests/Indi_Custom.test.mq4 b/Indicators/Special/tests/Indi_Custom.test.mq4 index 99489217c..bb3fffd61 100644 --- a/Indicators/Special/tests/Indi_Custom.test.mq4 +++ b/Indicators/Special/tests/Indi_Custom.test.mq4 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ diff --git a/Indicators/Special/tests/Indi_Custom.test.mq5 b/Indicators/Special/tests/Indi_Custom.test.mq5 index 1a95c5c96..281fe217d 100644 --- a/Indicators/Special/tests/Indi_Custom.test.mq5 +++ b/Indicators/Special/tests/Indi_Custom.test.mq5 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -20,6 +20,7 @@ */ // Includes. +#include "../../../Platform.h" #include "../../../Test.mqh" #include "../Indi_Custom.mqh" @@ -27,39 +28,4 @@ * @file * Test functionality of Indi_Custom indicator class. */ - -Indi_Custom indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - // Overrides indicator params. - DataParamEntry _iparam_rsi_period = 12; - IndiCustomParams _iparams(INDI_CUSTOM_PATH); - _iparams.AddParam(_iparam_rsi_period); - indi.SetParams(_iparams); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Custom); diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index be6ac8008..e3df265b8 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -20,77 +20,210 @@ * */ +/** + * @file + * Real tick-based indicator. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. +#include "../../Chart.struct.static.h" #include "../../Indicator/IndicatorTick.h" +#define INDICATOR_TICK_REAL_FETCH_HISTORY 1000 + // Structs. -struct IndiTickMtParams : IndicatorParams { - string symbol; - // Struct constructor. - IndiTickMtParams(string _symbol = NULL, int _shift = 0) : IndicatorParams(INDI_TICK) { - SetShift(_shift); - SetSymbol(_symbol); - }; - IndiTickMtParams(IndiTickMtParams &_params, ENUM_TIMEFRAMES _tf) { - THIS_REF = _params; - tf = _tf; - }; - // Getters. - string GetSymbol() { return symbol; } - // Setters. - void SetSymbol(string _symbol) { symbol = _symbol; } +// Params for MT patform's tick-based indicator. +struct Indi_TickMtParams : IndicatorParams { + Indi_TickMtParams() : IndicatorParams(INDI_TICK) {} }; -/** - * Price Indicator. - */ -class Indi_TickMt : public IndicatorTick { +// MT platform's tick-based indicator. +class Indi_TickMt : public IndicatorTick { protected: - MqlTick tick; + bool _fetch_history_on_first_tick; public: + Indi_TickMt(Indi_TickMtParams &_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) { + _fetch_history_on_first_tick = false; + } + Indi_TickMt(string _symbol, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0, string _name = "") + : IndicatorTick(_symbol, Indi_TickMtParams(), + IndicatorDataParams(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), _indi_src) { + _fetch_history_on_first_tick = false; + } + + string GetName() override { return "Indi_TickMt"; } + /** - * Class constructor. + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. */ - Indi_TickMt(IndiTickMtParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, - int _indi_src_mode = 0) - : IndicatorTick(_p, IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype), - _indi_src){}; - Indi_TickMt(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "") - : IndicatorTick(INDI_TICK, _tf, _shift, _name) {} + unsigned int GetSuitableDataSourceTypes() override { return INDI_SUITABLE_DS_TYPE_EXPECT_NONE; } /** - * Returns the indicator's value. + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. */ - IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { - if (_shift == 0) { - // Fetch a current prices of a specified symbol. - tick = SymbolInfoStatic::GetTick(itparams.GetSymbol()); - switch (_mode) { - case 0: - return tick.ask; - case 1: - return tick.bid; - case 2: -#ifdef __MQL4__ - return tick.volume; -#else - return tick.volume_real; + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } + + /** + * Returns the indicator's struct entry for the given shift. + * + * @see: IndicatorDataEntry. + * + * @return + * Returns IndicatorDataEntry struct filled with indicator values. + */ + IndicatorDataEntry GetEntry(long _index = -1) override { + int _ishift = _index >= 0 ? (int)_index : iparams.GetShift(); + long _bar_time; + _bar_time = GetBarTime(_ishift); + + TickAB _tick = itdata.GetByKey(_bar_time); + IndicatorDataEntry _entry = TickToEntry(_bar_time, _tick); + + if (_entry.IsValid()) { + istate.is_changed = false; + istate.is_ready = true; + } + + return _entry; + } + + void OnBecomeDataSourceFor(IndicatorData *_base_indi) override { + // Feeding base indicator with historic entries of this indicator. +#ifdef __debug__ + Print(GetFullName(), " became a data source for ", _base_indi.GetFullName()); #endif + + _fetch_history_on_first_tick = true; + } + + void FetchHistory() { + if (INDICATOR_TICK_REAL_FETCH_HISTORY == 0) { + // No history requested. + return; + } + +#ifndef __MQL4__ + int _ticks_to_emit = 1000; + +#ifdef __debug_verbose__ + Print("Listening indicators will be now filled with ", _ticks_to_emit, + " historical entries generated by " + GetFullName()); +#endif + + static MqlTick _tmp_ticks[]; + ArrayResize(_tmp_ticks, 0); + + // Number of retries for CopyTicksRange(). + int _tries = 10; + + // Number of ticks copied by CopyTicksRange(). + int _num_copied = -1; + + // Number of ticks remaining to copy in order to fulfill number of minimum required ticks (_ticks_to_emit). + int _num_yet_to_copy = _ticks_to_emit; + + // In ms, the period we will be retrieving ticks for. + int _period_msc = 1000 * 60 * 60; // 1 hour distance. + int _max_periods_to_check = 24 * 7; // Two weeks should be enough. + int _periods_checked = 0; + + unsigned long _range_from = TimeCurrent() * 1000 - _period_msc; + unsigned long _range_to = TimeCurrent() * 1000 - 1; + + while (_tries > 0) { + _num_copied = CopyTicksRange(GetSymbol(), _tmp_ticks, COPY_TICKS_INFO, _range_from, _range_to); + + if (_num_copied == -1) { + ResetLastError(); + Sleep(1000); + --_tries; + } else { + _num_yet_to_copy -= _num_copied; + + for (int i = 0; i < _num_copied; ++i) { + TickAB _tick(_tmp_ticks[i].ask, _tmp_ticks[i].bid); + // We can't call EmitEntry() here, as tick would go to multiple sources at the same time! +#ifdef __debug_verbose__ + Print("Tick at ", TimeToString(_tmp_ticks[i].time, TIME_DATE | TIME_MINUTES | TIME_SECONDS), ": ", + _tmp_ticks[i].ask, ", ", _tmp_ticks[i].bid); +#endif + + EmitEntry(TickToEntry(_tmp_ticks[i].time, _tick)); + + if (_num_yet_to_copy <= 0) { + break; + } + } + + _range_from -= _period_msc; + _range_to -= _period_msc; + if (++_periods_checked > _max_periods_to_check) { + break; + } } - SetUserError(ERR_INVALID_PARAMETER); } - return DBL_MAX; + +#ifdef __debug_verbose__ + Print("Listening indicators were filled with ", (_ticks_to_emit - _num_yet_to_copy), " out of ", _ticks_to_emit, + " historical entries requested"); +#endif + +#endif } - /** - * Alters indicator's struct value. - * - * 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 _shift = 0) { - IndicatorTick::GetEntryAlter(_entry, _shift); - _entry.timestamp = _entry.timestamp > 0 ? _entry.timestamp : tick.time; - }; + void OnTick() override { + if (_fetch_history_on_first_tick) { + // We wait for fetching the history for the first tick, as it won't work in OnInit(). + _fetch_history_on_first_tick = false; + FetchHistory(); + } + +#ifdef __MQL4__ + // Refreshes Ask/Bid constants. + RefreshRates(); + double _ask = Ask; + double _bid = Bid; + long _time = TimeCurrent(); +#else + static MqlTick _tmp_ticks[]; + // Copying only the last tick. + int _num_copied = CopyTicks(GetSymbol(), _tmp_ticks, COPY_TICKS_INFO, 0, 1); + + if (_num_copied < 1 || _LastError != 0) { + Print("Error. Cannot copy MT ticks via CopyTicks(). Error " + IntegerToString(_LastError)); + // DebugBreak(); + // Just emitting zeroes in case of error. + TickAB _tick(0, 0); + EmitEntry(TickToEntry(TimeCurrent(), _tick)); + return; + } + +#ifdef __debug_verbose__ + Print("CpyT: ", TimeToString(_tmp_ticks[0].time, TIME_DATE | TIME_MINUTES | TIME_SECONDS), " = ", _tmp_ticks[0].bid, + " (", _tmp_ticks[0].time, ")"); + Print("RlCl: ", TimeToString(::iTime(GetSymbol(), PERIOD_CURRENT, 0), TIME_DATE | TIME_MINUTES | TIME_SECONDS), + " = ", ::iClose(GetSymbol(), PERIOD_CURRENT, 0)); +#endif + + double _ask = _tmp_ticks[0].ask; + double _bid = _tmp_ticks[0].bid; + // long _time = _tmp_ticks[0].time; + long _time = TimeCurrent(); +#endif + TickAB _tick(_ask, _bid); + IndicatorDataEntry _entry(TickToEntry(_time, _tick)); + StoreEntry(_entry); + EmitEntry(_entry); + } }; diff --git a/Indicators/Tick/tests/Indi_TickMt.test.mq5 b/Indicators/Tick/tests/Indi_TickMt.test.mq5 index 81e330ca3..903b56b52 100644 --- a/Indicators/Tick/tests/Indi_TickMt.test.mq5 +++ b/Indicators/Tick/tests/Indi_TickMt.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../../Platform.h" #include "../../../Test.mqh" #include "../Indi_TickMt.mqh" @@ -27,33 +28,4 @@ * @file * Test functionality of Indi_TickMt indicator class. */ - -Indi_TickMt indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = indi.GetTick(); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS_PARAMS(Indi_TickMt, _Symbol); diff --git a/Indicators/indicators.h b/Indicators/indicators.h index 4d4e1821b..027140284 100644 --- a/Indicators/indicators.h +++ b/Indicators/indicators.h @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2021, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ diff --git a/Indicators/tests/Indi_AC.test.mq5 b/Indicators/tests/Indi_AC.test.mq5 index e400f050a..d3167539f 100644 --- a/Indicators/tests/Indi_AC.test.mq5 +++ b/Indicators/tests/Indi_AC.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_AC.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_AC indicator class. */ - -Indi_AC indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_AC); diff --git a/Indicators/tests/Indi_AD.test.mq5 b/Indicators/tests/Indi_AD.test.mq5 index a615bc208..2880c6365 100644 --- a/Indicators/tests/Indi_AD.test.mq5 +++ b/Indicators/tests/Indi_AD.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_AD.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_AD indicator class. */ - -Indi_AD indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_AD); diff --git a/Indicators/tests/Indi_ADX.test.mq5 b/Indicators/tests/Indi_ADX.test.mq5 index d08879ec0..5dd93ce28 100644 --- a/Indicators/tests/Indi_ADX.test.mq5 +++ b/Indicators/tests/Indi_ADX.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_ADX.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_ADX indicator class. */ - -Indi_ADX indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_ADX); diff --git a/Indicators/tests/Indi_ADXW.test.mq5 b/Indicators/tests/Indi_ADXW.test.mq5 index ddd35413e..82edfafca 100644 --- a/Indicators/tests/Indi_ADXW.test.mq5 +++ b/Indicators/tests/Indi_ADXW.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_ADXW.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_ADXW indicator class. */ - -Indi_ADXW indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_ADXW); diff --git a/Indicators/tests/Indi_AMA.test.mq5 b/Indicators/tests/Indi_AMA.test.mq5 index 90ea46f07..4e0e1c9f4 100644 --- a/Indicators/tests/Indi_AMA.test.mq5 +++ b/Indicators/tests/Indi_AMA.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_AMA.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_AMA indicator class. */ - -Indi_AMA indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_AMA); diff --git a/Indicators/tests/Indi_AO.test.mq5 b/Indicators/tests/Indi_AO.test.mq5 index f02e27df3..14649e2da 100644 --- a/Indicators/tests/Indi_AO.test.mq5 +++ b/Indicators/tests/Indi_AO.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_AO.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_AO indicator class. */ - -Indi_AO indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_AO); diff --git a/Indicators/tests/Indi_ASI.test.mq5 b/Indicators/tests/Indi_ASI.test.mq5 index ce94445c2..bae7205f2 100644 --- a/Indicators/tests/Indi_ASI.test.mq5 +++ b/Indicators/tests/Indi_ASI.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_ASI.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_ASI indicator class. */ - -Indi_ASI indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_ASI); diff --git a/Indicators/tests/Indi_ATR.test.mq5 b/Indicators/tests/Indi_ATR.test.mq5 index 203da7ccc..01bad4c9c 100644 --- a/Indicators/tests/Indi_ATR.test.mq5 +++ b/Indicators/tests/Indi_ATR.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_ATR.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_ATR indicator class. */ - -Indi_ATR indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_ATR); diff --git a/Indicators/tests/Indi_Alligator.test.mq5 b/Indicators/tests/Indi_Alligator.test.mq5 index d85cea75b..8ea327c47 100644 --- a/Indicators/tests/Indi_Alligator.test.mq5 +++ b/Indicators/tests/Indi_Alligator.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Alligator.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Alligator indicator class. */ - -Indi_Alligator indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Alligator); diff --git a/Indicators/tests/Indi_AppliedPrice.test.mq5 b/Indicators/tests/Indi_AppliedPrice.test.mq5 index e1b643be8..c41210d81 100644 --- a/Indicators/tests/Indi_AppliedPrice.test.mq5 +++ b/Indicators/tests/Indi_AppliedPrice.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_AppliedPrice.mqh" #include "../Price/Indi_Price.mqh" @@ -28,34 +29,4 @@ * @file * Test functionality of Indi_AppliedPrice indicator class. */ - -Indi_AppliedPrice indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_AppliedPrice); diff --git a/Indicators/tests/Indi_BWMFI.test.mq5 b/Indicators/tests/Indi_BWMFI.test.mq5 index ed6955ed1..a57f75eeb 100644 --- a/Indicators/tests/Indi_BWMFI.test.mq5 +++ b/Indicators/tests/Indi_BWMFI.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_BWMFI.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_BWMFI indicator class. */ - -Indi_BWMFI indi(PERIOD_CURRENT, 1); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_BWMFI); diff --git a/Indicators/tests/Indi_BWZT.test.mq5 b/Indicators/tests/Indi_BWZT.test.mq5 index 2dca14f35..a5a66c0bb 100644 --- a/Indicators/tests/Indi_BWZT.test.mq5 +++ b/Indicators/tests/Indi_BWZT.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_BWZT.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_BWZT indicator class. */ - -Indi_BWZT indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_BWZT); diff --git a/Indicators/tests/Indi_Bands.test.mq5 b/Indicators/tests/Indi_Bands.test.mq5 index 26c1bd4b5..dd91ac2a0 100644 --- a/Indicators/tests/Indi_Bands.test.mq5 +++ b/Indicators/tests/Indi_Bands.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Bands.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Bands indicator class. */ - -Indi_Bands indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Bands); diff --git a/Indicators/tests/Indi_BearsPower.test.mq5 b/Indicators/tests/Indi_BearsPower.test.mq5 index 817e6476c..02eca6d0a 100644 --- a/Indicators/tests/Indi_BearsPower.test.mq5 +++ b/Indicators/tests/Indi_BearsPower.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_BearsPower.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_BearsPower indicator class. */ - -Indi_BearsPower indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_BearsPower); diff --git a/Indicators/tests/Indi_BullsPower.test.mq5 b/Indicators/tests/Indi_BullsPower.test.mq5 index 8b840d95d..08a26bb9f 100644 --- a/Indicators/tests/Indi_BullsPower.test.mq5 +++ b/Indicators/tests/Indi_BullsPower.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_BullsPower.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_BullsPower indicator class. */ - -Indi_BullsPower indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_BullsPower); diff --git a/Indicators/tests/Indi_CCI.test.mq5 b/Indicators/tests/Indi_CCI.test.mq5 index bc0e12b8c..f9073dfac 100644 --- a/Indicators/tests/Indi_CCI.test.mq5 +++ b/Indicators/tests/Indi_CCI.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_CCI.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_CCI indicator class. */ - -Indi_CCI indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_CCI); diff --git a/Indicators/tests/Indi_CHO.test.mq5 b/Indicators/tests/Indi_CHO.test.mq5 index bff8bdcef..75c104994 100644 --- a/Indicators/tests/Indi_CHO.test.mq5 +++ b/Indicators/tests/Indi_CHO.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_CHO.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_CHO indicator class. */ - -Indi_CHO indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_CHO); diff --git a/Indicators/tests/Indi_CHV.test.mq5 b/Indicators/tests/Indi_CHV.test.mq5 index 27c3ae17f..91423902b 100644 --- a/Indicators/tests/Indi_CHV.test.mq5 +++ b/Indicators/tests/Indi_CHV.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_CHV.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_CHV indicator class. */ - -Indi_CHV indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_CHV); diff --git a/Indicators/tests/Indi_ColorBars.test.mq5 b/Indicators/tests/Indi_ColorBars.test.mq5 index c684a8a1e..226bc7dce 100644 --- a/Indicators/tests/Indi_ColorBars.test.mq5 +++ b/Indicators/tests/Indi_ColorBars.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_ColorBars.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_ColorBars indicator class. */ - -Indi_ColorBars indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_ColorBars); diff --git a/Indicators/tests/Indi_ColorCandlesDaily.test.mq5 b/Indicators/tests/Indi_ColorCandlesDaily.test.mq5 index 22a5fdca0..ceb9c7393 100644 --- a/Indicators/tests/Indi_ColorCandlesDaily.test.mq5 +++ b/Indicators/tests/Indi_ColorCandlesDaily.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_ColorCandlesDaily.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_ColorCandlesDaily indicator class. */ - -Indi_ColorCandlesDaily indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_ColorCandlesDaily); diff --git a/Indicators/tests/Indi_ColorLine.test.mq5 b/Indicators/tests/Indi_ColorLine.test.mq5 index 8e8f93004..98a3bd5c3 100644 --- a/Indicators/tests/Indi_ColorLine.test.mq5 +++ b/Indicators/tests/Indi_ColorLine.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_ColorLine.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_ColorLine indicator class. */ - -Indi_ColorLine indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_ColorLine); diff --git a/Indicators/tests/Indi_CustomMovingAverage.test.mq5 b/Indicators/tests/Indi_CustomMovingAverage.test.mq5 index 8ea1924b6..8fc478d8c 100644 --- a/Indicators/tests/Indi_CustomMovingAverage.test.mq5 +++ b/Indicators/tests/Indi_CustomMovingAverage.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_CustomMovingAverage.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_CustomMovingAverage indicator class. */ - -Indi_CustomMovingAverage indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_CustomMovingAverage); diff --git a/Indicators/tests/Indi_DEMA.test.mq5 b/Indicators/tests/Indi_DEMA.test.mq5 index 03f7f50e1..99e30be4e 100644 --- a/Indicators/tests/Indi_DEMA.test.mq5 +++ b/Indicators/tests/Indi_DEMA.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_DEMA.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_DEMA indicator class. */ - -Indi_DEMA indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_DEMA); diff --git a/Indicators/tests/Indi_DeMarker.test.mq5 b/Indicators/tests/Indi_DeMarker.test.mq5 index aba5a71f0..e4085e164 100644 --- a/Indicators/tests/Indi_DeMarker.test.mq5 +++ b/Indicators/tests/Indi_DeMarker.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_DeMarker.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_DeMarker indicator class. */ - -Indi_DeMarker indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_DeMarker); diff --git a/Indicators/tests/Indi_Demo.test.mq5 b/Indicators/tests/Indi_Demo.test.mq5 index e709567b8..e88ba7f3c 100644 --- a/Indicators/tests/Indi_Demo.test.mq5 +++ b/Indicators/tests/Indi_Demo.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Demo.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Demo indicator class. */ - -Indi_Demo indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Demo); diff --git a/Indicators/tests/Indi_DetrendedPrice.test.mq5 b/Indicators/tests/Indi_DetrendedPrice.test.mq5 index afaa2a1a4..1d97e83fb 100644 --- a/Indicators/tests/Indi_DetrendedPrice.test.mq5 +++ b/Indicators/tests/Indi_DetrendedPrice.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_DetrendedPrice.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_DetrendedPrice indicator class. */ - -Indi_DetrendedPrice indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_DetrendedPrice); diff --git a/Indicators/tests/Indi_Drawer.test.mq5 b/Indicators/tests/Indi_Drawer.test.mq5 index 93011f0d4..8ca3a93fe 100644 --- a/Indicators/tests/Indi_Drawer.test.mq5 +++ b/Indicators/tests/Indi_Drawer.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Drawer.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Drawer indicator class. */ - -Indi_Drawer indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Drawer); diff --git a/Indicators/tests/Indi_Envelopes.test.mq5 b/Indicators/tests/Indi_Envelopes.test.mq5 index edd27781b..ef72d25f5 100644 --- a/Indicators/tests/Indi_Envelopes.test.mq5 +++ b/Indicators/tests/Indi_Envelopes.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Envelopes.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Envelopes indicator class. */ - -Indi_Envelopes indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Envelopes); diff --git a/Indicators/tests/Indi_Force.test.mq5 b/Indicators/tests/Indi_Force.test.mq5 index 7162e74dc..2004b799f 100644 --- a/Indicators/tests/Indi_Force.test.mq5 +++ b/Indicators/tests/Indi_Force.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Force.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Force indicator class. */ - -Indi_Force indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Force); diff --git a/Indicators/tests/Indi_FractalAdaptiveMA.test.mq5 b/Indicators/tests/Indi_FractalAdaptiveMA.test.mq5 index 2c4383374..38f5c80ea 100644 --- a/Indicators/tests/Indi_FractalAdaptiveMA.test.mq5 +++ b/Indicators/tests/Indi_FractalAdaptiveMA.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_FractalAdaptiveMA.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_FractalAdaptiveMA indicator class. */ - -Indi_FrAMA indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_FrAMA); diff --git a/Indicators/tests/Indi_Fractals.test.mq5 b/Indicators/tests/Indi_Fractals.test.mq5 index fd2846139..0110e87e6 100644 --- a/Indicators/tests/Indi_Fractals.test.mq5 +++ b/Indicators/tests/Indi_Fractals.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Fractals.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Fractals indicator class. */ - -Indi_Fractals indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Fractals); diff --git a/Indicators/tests/Indi_Gator.test.mq5 b/Indicators/tests/Indi_Gator.test.mq5 index 20e2df7fc..f3cd03836 100644 --- a/Indicators/tests/Indi_Gator.test.mq5 +++ b/Indicators/tests/Indi_Gator.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Gator.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Gator indicator class. */ - -Indi_Gator indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Gator); diff --git a/Indicators/tests/Indi_HeikenAshi.test.mq5 b/Indicators/tests/Indi_HeikenAshi.test.mq5 index fcc580a47..ccefa321f 100644 --- a/Indicators/tests/Indi_HeikenAshi.test.mq5 +++ b/Indicators/tests/Indi_HeikenAshi.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_HeikenAshi.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_HeikenAshi indicator class. */ - -Indi_HeikenAshi indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_HeikenAshi); diff --git a/Indicators/tests/Indi_Ichimoku.test.mq5 b/Indicators/tests/Indi_Ichimoku.test.mq5 index 8b999b69b..31267154f 100644 --- a/Indicators/tests/Indi_Ichimoku.test.mq5 +++ b/Indicators/tests/Indi_Ichimoku.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Ichimoku.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Ichimoku indicator class. */ - -Indi_Ichimoku indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Ichimoku); diff --git a/Indicators/tests/Indi_Killzones.test.mq5 b/Indicators/tests/Indi_Killzones.test.mq5 index 4dbc7668c..11654c88e 100644 --- a/Indicators/tests/Indi_Killzones.test.mq5 +++ b/Indicators/tests/Indi_Killzones.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Killzones.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Killzones indicator class. */ - -Indi_Killzones indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString(1)); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Killzones); diff --git a/Indicators/tests/Indi_MA.test.mq5 b/Indicators/tests/Indi_MA.test.mq5 index fdb9c393a..8fa7858ab 100644 --- a/Indicators/tests/Indi_MA.test.mq5 +++ b/Indicators/tests/Indi_MA.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_MA.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_MA indicator class. */ - -Indi_MA indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_MA); diff --git a/Indicators/tests/Indi_MACD.test.mq5 b/Indicators/tests/Indi_MACD.test.mq5 index 52cacd0ca..a1dcf9f17 100644 --- a/Indicators/tests/Indi_MACD.test.mq5 +++ b/Indicators/tests/Indi_MACD.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_MACD.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_MACD indicator class. */ - -Indi_MACD indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_MACD); diff --git a/Indicators/tests/Indi_MFI.test.mq5 b/Indicators/tests/Indi_MFI.test.mq5 index 6666488a1..e86c7ae3a 100644 --- a/Indicators/tests/Indi_MFI.test.mq5 +++ b/Indicators/tests/Indi_MFI.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_MFI.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_MFI indicator class. */ - -Indi_MFI indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_MFI); diff --git a/Indicators/tests/Indi_MassIndex.test.mq5 b/Indicators/tests/Indi_MassIndex.test.mq5 index 5360b3ad3..8c9f796ef 100644 --- a/Indicators/tests/Indi_MassIndex.test.mq5 +++ b/Indicators/tests/Indi_MassIndex.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_MassIndex.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_MassIndex indicator class. */ - -Indi_MassIndex indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_MassIndex); diff --git a/Indicators/tests/Indi_Momentum.test.mq5 b/Indicators/tests/Indi_Momentum.test.mq5 index 33b154e9d..6321e3670 100644 --- a/Indicators/tests/Indi_Momentum.test.mq5 +++ b/Indicators/tests/Indi_Momentum.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Momentum.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Momentum indicator class. */ - -Indi_Momentum indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Momentum); diff --git a/Indicators/tests/Indi_OBV.test.mq5 b/Indicators/tests/Indi_OBV.test.mq5 index 8fdfacefe..66f357b9e 100644 --- a/Indicators/tests/Indi_OBV.test.mq5 +++ b/Indicators/tests/Indi_OBV.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_OBV.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_OBV indicator class. */ - -Indi_OBV indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_OBV); diff --git a/Indicators/tests/Indi_OHLC.test.mq5 b/Indicators/tests/Indi_OHLC.test.mq5 index 802449028..6c2df2c08 100644 --- a/Indicators/tests/Indi_OHLC.test.mq5 +++ b/Indicators/tests/Indi_OHLC.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../OHLC/Indi_OHLC.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_OHLC indicator class. */ - -Indi_OHLC indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_OHLC); diff --git a/Indicators/tests/Indi_OsMA.test.mq5 b/Indicators/tests/Indi_OsMA.test.mq5 index 0c00d4075..41ced79dd 100644 --- a/Indicators/tests/Indi_OsMA.test.mq5 +++ b/Indicators/tests/Indi_OsMA.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_OsMA.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_OsMA indicator class. */ - -Indi_OsMA indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_OsMA); diff --git a/Indicators/tests/Indi_Pattern.test.mq5 b/Indicators/tests/Indi_Pattern.test.mq5 index 09c978a9e..44e4c4409 100644 --- a/Indicators/tests/Indi_Pattern.test.mq5 +++ b/Indicators/tests/Indi_Pattern.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Bitwise/Indi_Pattern.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Pattern indicator class. */ - -Indi_Pattern indi(PERIOD_CURRENT, 1); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Pattern); diff --git a/Indicators/tests/Indi_Pivot.test.mq5 b/Indicators/tests/Indi_Pivot.test.mq5 index d179212e7..1750b1685 100644 --- a/Indicators/tests/Indi_Pivot.test.mq5 +++ b/Indicators/tests/Indi_Pivot.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Pivot.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Pivot indicator class. */ - -Indi_Pivot indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Pivot); diff --git a/Indicators/tests/Indi_Price.test.mq5 b/Indicators/tests/Indi_Price.test.mq5 index ab22fd38e..d8850076d 100644 --- a/Indicators/tests/Indi_Price.test.mq5 +++ b/Indicators/tests/Indi_Price.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Price/Indi_Price.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Price indicator class. */ - -Indi_Price indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Price); diff --git a/Indicators/tests/Indi_PriceChannel.test.mq5 b/Indicators/tests/Indi_PriceChannel.test.mq5 index 56238d6d8..ed7567358 100644 --- a/Indicators/tests/Indi_PriceChannel.test.mq5 +++ b/Indicators/tests/Indi_PriceChannel.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_PriceChannel.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_PriceChannel indicator class. */ - -Indi_PriceChannel indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_PriceChannel); diff --git a/Indicators/tests/Indi_PriceFeeder.test.mq5 b/Indicators/tests/Indi_PriceFeeder.test.mq5 index 119d633b6..a79c903a1 100644 --- a/Indicators/tests/Indi_PriceFeeder.test.mq5 +++ b/Indicators/tests/Indi_PriceFeeder.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_PriceFeeder.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_PriceFeeder indicator class. */ - -Indi_PriceFeeder indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_PriceFeeder); diff --git a/Indicators/tests/Indi_PriceVolumeTrend.test.mq5 b/Indicators/tests/Indi_PriceVolumeTrend.test.mq5 index bb875c550..6546239fe 100644 --- a/Indicators/tests/Indi_PriceVolumeTrend.test.mq5 +++ b/Indicators/tests/Indi_PriceVolumeTrend.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_PriceVolumeTrend.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_PriceVolumeTrend indicator class. */ - -Indi_PriceVolumeTrend indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_PriceVolumeTrend); diff --git a/Indicators/tests/Indi_RS.test.mq5 b/Indicators/tests/Indi_RS.test.mq5 index 490dba47b..355819ef9 100644 --- a/Indicators/tests/Indi_RS.test.mq5 +++ b/Indicators/tests/Indi_RS.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_RS.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_RS indicator class. */ - -Indi_RS indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_RS); diff --git a/Indicators/tests/Indi_RSI.test.mq5 b/Indicators/tests/Indi_RSI.test.mq5 index f069228f5..d290e3b19 100644 --- a/Indicators/tests/Indi_RSI.test.mq5 +++ b/Indicators/tests/Indi_RSI.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_RSI.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_RSI indicator class. */ - -Indi_RSI indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_RSI); diff --git a/Indicators/tests/Indi_RVI.test.mq5 b/Indicators/tests/Indi_RVI.test.mq5 index 05f2f6f8a..3200c1ad5 100644 --- a/Indicators/tests/Indi_RVI.test.mq5 +++ b/Indicators/tests/Indi_RVI.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_RVI.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_RVI indicator class. */ - -Indi_RVI indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_RVI); diff --git a/Indicators/tests/Indi_RateOfChange.test.mq5 b/Indicators/tests/Indi_RateOfChange.test.mq5 index 260b7ab27..a1b44e416 100644 --- a/Indicators/tests/Indi_RateOfChange.test.mq5 +++ b/Indicators/tests/Indi_RateOfChange.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_RateOfChange.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_RateOfChange indicator class. */ - -Indi_RateOfChange indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_RateOfChange); diff --git a/Indicators/tests/Indi_SAR.test.mq5 b/Indicators/tests/Indi_SAR.test.mq5 index 09ca28513..e46ba8363 100644 --- a/Indicators/tests/Indi_SAR.test.mq5 +++ b/Indicators/tests/Indi_SAR.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_SAR.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_SAR indicator class. */ - -Indi_SAR indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_SAR); diff --git a/Indicators/tests/Indi_StdDev.test.mq5 b/Indicators/tests/Indi_StdDev.test.mq5 index 53dc3720a..358433006 100644 --- a/Indicators/tests/Indi_StdDev.test.mq5 +++ b/Indicators/tests/Indi_StdDev.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_StdDev.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_StdDev indicator class. */ - -Indi_StdDev indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_StdDev); diff --git a/Indicators/tests/Indi_Stochastic.test.mq5 b/Indicators/tests/Indi_Stochastic.test.mq5 index 08cefb694..abf62d07b 100644 --- a/Indicators/tests/Indi_Stochastic.test.mq5 +++ b/Indicators/tests/Indi_Stochastic.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Stochastic.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Stochastic indicator class. */ - -Indi_Stochastic indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Stochastic); diff --git a/Indicators/tests/Indi_TEMA.test.mq5 b/Indicators/tests/Indi_TEMA.test.mq5 index 3d03b442d..1b8e6447f 100644 --- a/Indicators/tests/Indi_TEMA.test.mq5 +++ b/Indicators/tests/Indi_TEMA.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_TEMA.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_TEMA indicator class. */ - -Indi_TEMA indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_TEMA) diff --git a/Indicators/tests/Indi_TRIX.test.mq5 b/Indicators/tests/Indi_TRIX.test.mq5 index 69d9b855f..7fe0ffc0a 100644 --- a/Indicators/tests/Indi_TRIX.test.mq5 +++ b/Indicators/tests/Indi_TRIX.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_TRIX.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_TRIX indicator class. */ - -Indi_TRIX indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_TRIX) diff --git a/Indicators/tests/Indi_UltimateOscillator.test.mq5 b/Indicators/tests/Indi_UltimateOscillator.test.mq5 index 419662594..58b574564 100644 --- a/Indicators/tests/Indi_UltimateOscillator.test.mq5 +++ b/Indicators/tests/Indi_UltimateOscillator.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_UltimateOscillator.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_UltimateOscillator indicator class. */ - -Indi_UltimateOscillator indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_UltimateOscillator) diff --git a/Indicators/tests/Indi_VIDYA.test.mq5 b/Indicators/tests/Indi_VIDYA.test.mq5 index 2fa0eed1d..5d22f6c5d 100644 --- a/Indicators/tests/Indi_VIDYA.test.mq5 +++ b/Indicators/tests/Indi_VIDYA.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_VIDYA.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_VIDYA indicator class. */ - -Indi_VIDYA indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_VIDYA) diff --git a/Indicators/tests/Indi_VROC.test.mq5 b/Indicators/tests/Indi_VROC.test.mq5 index b8a897a70..a7d5f0595 100644 --- a/Indicators/tests/Indi_VROC.test.mq5 +++ b/Indicators/tests/Indi_VROC.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_VROC.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_VROC indicator class. */ - -Indi_VROC indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_VROC) diff --git a/Indicators/tests/Indi_Volumes.test.mq5 b/Indicators/tests/Indi_Volumes.test.mq5 index 5c54e41a7..05842b4b7 100644 --- a/Indicators/tests/Indi_Volumes.test.mq5 +++ b/Indicators/tests/Indi_Volumes.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_Volumes.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_Volumes indicator class. */ - -Indi_Volumes indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_Volumes) diff --git a/Indicators/tests/Indi_WPR.test.mq5 b/Indicators/tests/Indi_WPR.test.mq5 index 9b96369b8..91b31f72f 100644 --- a/Indicators/tests/Indi_WPR.test.mq5 +++ b/Indicators/tests/Indi_WPR.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_WPR.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_WPR indicator class. */ - -Indi_WPR indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_WPR) diff --git a/Indicators/tests/Indi_WilliamsAD.test.mq5 b/Indicators/tests/Indi_WilliamsAD.test.mq5 index 9474ad7ec..7fbce1c5a 100644 --- a/Indicators/tests/Indi_WilliamsAD.test.mq5 +++ b/Indicators/tests/Indi_WilliamsAD.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_WilliamsAD.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_WilliamsAD indicator class. */ - -Indi_WilliamsAD indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_WilliamsAD) diff --git a/Indicators/tests/Indi_ZigZag.test.mq5 b/Indicators/tests/Indi_ZigZag.test.mq5 index d3f49631c..05c50c477 100644 --- a/Indicators/tests/Indi_ZigZag.test.mq5 +++ b/Indicators/tests/Indi_ZigZag.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_ZigZag.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_ZigZag indicator class. */ - -Indi_ZigZag indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_ZigZag) diff --git a/Indicators/tests/Indi_ZigZagColor.test.mq5 b/Indicators/tests/Indi_ZigZagColor.test.mq5 index cc53687e4..f9e346de1 100644 --- a/Indicators/tests/Indi_ZigZagColor.test.mq5 +++ b/Indicators/tests/Indi_ZigZagColor.test.mq5 @@ -20,6 +20,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../Indi_ZigZagColor.mqh" @@ -27,34 +28,4 @@ * @file * Test functionality of Indi_ZigZagColor indicator class. */ - -Indi_ZigZagColor indi(PERIOD_CURRENT); - -/** - * Implements Init event handler. - */ -int OnInit() { - bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); - // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); - return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); -} - -/** - * Implements Tick event handler. - */ -void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - // Process ticks each minute. - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - // Print indicator values every hour. - Print(indi.ToString()); - if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); - } - } - } - _tick_last = _tick_new; -} +TEST_INDICATOR_DEFAULT_BINDINGS(Indi_ZigZagColor) diff --git a/Instances.h b/Instances.h index 4f82a2f66..53c2a7940 100644 --- a/Instances.h +++ b/Instances.h @@ -30,6 +30,10 @@ #pragma once #endif +// Prevents processing this includes file multiple times. +#ifndef INSTANCES_H +#define INSTANCES_H + #include "Dict.mqh" #include "Util.h" @@ -49,3 +53,5 @@ class Instances { template T* Instances::instances[]; + +#endif // INSTANCES_MQH diff --git a/Log.mqh b/Log.mqh index 28130eb4a..4f312b286 100644 --- a/Log.mqh +++ b/Log.mqh @@ -262,7 +262,7 @@ class Log : public Object { } */ - virtual const string ToString() { + string const ToString() override { string result; unsigned int lid; diff --git a/Market.mqh b/Market.mqh index 8f9c4876f..d044e2004 100644 --- a/Market.mqh +++ b/Market.mqh @@ -243,7 +243,7 @@ class Market : public SymbolInfo { /** * Returns Market data in textual representation. */ - string const ToString() { + string const ToString() override { return StringFormat(string("Pip digits/value: %d/%g, Spread: %d pts (%g pips; %.4f%%), Pts/pip: %d, ") + "Volume digits: %d, " + "Delta: %g, Last change: %g pips", GetPipDigits(), GetPipValue(), GetSpreadInPts(), GetSpreadInPips(), GetSpreadInPct(), diff --git a/Object.mqh b/Object.mqh index 5d10f8df2..3c0e90406 100644 --- a/Object.mqh +++ b/Object.mqh @@ -110,7 +110,7 @@ class Object : public Dynamic { /** * Returns text representation of the object. */ - virtual const string ToJSON() { return StringFormat("{ \"type\": \"%s\" }", typename(this)); } + virtual string ToJSON() { return StringFormat("{ \"type\": \"%s\" }", typename(this)); } /** * Safely delete the object. diff --git a/Order.mqh b/Order.mqh index 43d4ffa87..ab0007226 100644 --- a/Order.mqh +++ b/Order.mqh @@ -275,7 +275,7 @@ class Order : public SymbolInfo { bool IsClosed(bool _refresh = false) { if (odata.Get(ORDER_PROP_TIME_CLOSED) == 0) { if (_refresh || ShouldRefresh()) { - if (Order::TryOrderSelect(odata.Get(ORDER_PROP_TICKET), SELECT_BY_TICKET, MODE_HISTORY)) { + if (Order::TryOrderSelect(Order::OrderTicket(), SELECT_BY_TICKET, MODE_HISTORY)) { odata.Set(ORDER_PROP_TIME_CLOSED, Order::OrderCloseTime()); odata.Set(ORDER_PROP_REASON_CLOSE, ORDER_REASON_CLOSED_UNKNOWN); } @@ -422,8 +422,7 @@ class Order : public SymbolInfo { #else // __MQL5__ // @docs https://www.mql5.com/en/docs/trading/HistoryDealGetDouble double _result = 0; - unsigned long _ticket = Order::OrderTicket(); - if (HistorySelectByPosition(_ticket)) { + if (Order::TryOrderSelect(Order::OrderTicket(), SELECT_BY_TICKET, MODE_HISTORY)) { for (int i = HistoryDealsTotal() - 1; i >= 0; i--) { // https://www.mql5.com/en/docs/trading/historydealgetticket const unsigned long _deal_ticket = HistoryDealGetTicket(i); @@ -452,8 +451,7 @@ class Order : public SymbolInfo { return (datetime)Order::OrderGetInteger(ORDER_TIME_SETUP); #else long _result = 0; - unsigned long _ticket = Order::OrderTicket(); - if (HistorySelectByPosition(_ticket)) { + if (Order::TryOrderSelect(Order::OrderTicket(), SELECT_BY_TICKET, MODE_HISTORY)) { for (int i = HistoryDealsTotal() - 1; i >= 0; i--) { // https://www.mql5.com/en/docs/trading/historydealgetticket const unsigned long _deal_ticket = HistoryDealGetTicket(i); @@ -487,8 +485,7 @@ class Order : public SymbolInfo { #else // __MQL5__ // @docs https://www.mql5.com/en/docs/trading/historydealgetinteger long _result = 0; - unsigned long _ticket = Order::OrderTicket(); - if (HistorySelectByPosition(_ticket)) { + if (Order::TryOrderSelect(Order::OrderTicket(), SELECT_BY_TICKET, MODE_HISTORY)) { for (int i = HistoryDealsTotal() - 1; i >= 0; i--) { // https://www.mql5.com/en/docs/trading/historydealgetticket const unsigned long _deal_ticket = HistoryDealGetTicket(i); @@ -525,8 +522,7 @@ class Order : public SymbolInfo { return ::OrderCommission(); #else // __MQL5__ double _result = 0; - unsigned long _ticket = Order::OrderTicket(); - if (HistorySelectByPosition(_ticket)) { + if (Order::TryOrderSelect(Order::OrderTicket(), SELECT_BY_TICKET, MODE_HISTORY)) { for (int i = HistoryDealsTotal() - 1; i >= 0; i--) { // https://www.mql5.com/en/docs/trading/historydealgetticket const unsigned long _deal_ticket = HistoryDealGetTicket(i); @@ -554,8 +550,7 @@ class Order : public SymbolInfo { return Order::OrderCommission() - Order::OrderSwap(); #else // __MQL5__ double _result = 0; - unsigned long _ticket = Order::OrderTicket(); - if (HistorySelectByPosition(_ticket)) { + if (Order::TryOrderSelect(Order::OrderTicket(), SELECT_BY_TICKET, MODE_HISTORY)) { for (int i = HistoryDealsTotal() - 1; i >= 0; i--) { // https://www.mql5.com/en/docs/trading/historydealgetticket const unsigned long _deal_ticket = HistoryDealGetTicket(i); @@ -642,8 +637,7 @@ class Order : public SymbolInfo { return ::OrderProfit(); #else double _result = 0; - unsigned long _ticket = Order::OrderTicket(); - if (HistorySelectByPosition(_ticket)) { + if (Order::TryOrderSelect(Order::OrderTicket(), SELECT_BY_TICKET, MODE_HISTORY)) { for (int i = HistoryDealsTotal() - 1; i >= 0; i--) { // https://www.mql5.com/en/docs/trading/historydealgetticket const unsigned long _deal_ticket = HistoryDealGetTicket(i); @@ -709,8 +703,7 @@ class Order : public SymbolInfo { return ::OrderSwap(); #else double _result = 0; - unsigned long _ticket = Order::OrderTicket(); - if (HistorySelectByPosition(_ticket)) { + if (Order::TryOrderSelect(Order::OrderTicket(), SELECT_BY_TICKET, MODE_HISTORY)) { for (int i = HistoryDealsTotal() - 1; i >= 0; i--) { // https://www.mql5.com/en/docs/trading/historydealgetticket const unsigned long _deal_ticket = HistoryDealGetTicket(i); @@ -1127,6 +1120,49 @@ class Order : public SymbolInfo { return _result; } + /** + * Converts MqlTradeRequest object into text representation. + */ + static string ToString(const MqlTradeRequest &_request) { + string _text; + _text += "+ Order: " + IntegerToString(_request.order); + _text += "\n|-- Action: " + EnumToString(_request.action); + _text += "\n|-- Magic: " + IntegerToString(_request.magic); + _text += "\n|-- Symbol: " + _request.symbol; + _text += "\n|-- Volume: " + DoubleToString(_request.volume); + _text += "\n|-- Price: " + DoubleToString(_request.price); + _text += "\n|-- Stop Limit: " + DoubleToString(_request.stoplimit); + _text += "\n|-- Stop Loss: " + DoubleToString(_request.sl); + _text += "\n|-- Take Profit: " + DoubleToString(_request.tp); + _text += "\n|-- Deviation: " + IntegerToString(_request.deviation); + _text += "\n|-- Type: " + EnumToString(_request.type); + _text += "\n|-- Type Filling: " + EnumToString(_request.type_filling); + _text += "\n|-- Type Time: " + EnumToString(_request.type_time); + _text += "\n|-- Expiration: " + TimeToString(_request.expiration); + _text += "\n|-- Comment: " + _request.comment; + _text += "\n|-- Position: " + IntegerToString(_request.position); + _text += "\n|-- Position By: " + IntegerToString(_request.position_by); + return _text; + } + + /** + * Converts MqlTradeResult object into text representation. + */ + static string ToString(const MqlTradeResult &_result) { + string _text; + _text += "+ Order: " + IntegerToString(_result.order); + _text += "\n|-- Return Code: " + IntegerToString(_result.retcode); + _text += "\n|-- Deal: " + IntegerToString(_result.deal); + _text += "\n|-- Volume: " + DoubleToString(_result.volume); + _text += "\n|-- Price: " + DoubleToString(_result.price); + _text += "\n|-- Bid: " + DoubleToString(_result.bid); + _text += "\n|-- Ask: " + DoubleToString(_result.ask); + _text += "\n|-- Comment: " + _result.comment; + _text += "\n|-- Request Id: " + IntegerToString(_result.request_id); + _text += "\n|-- Return Code External: " + IntegerToString(_result.retcode_external); + return _text; + } + /** * Executes trade operations by sending the request to a trade server. * @@ -1153,6 +1189,20 @@ class Order : public SymbolInfo { color _arrow_color = clrNONE // Color. ) { #ifdef __MQL4__ +#ifdef __debug__ + Print("Sending request:"); + PrintFormat("Symbol: %s", _symbol); + PrintFormat("Cmd: %d", _cmd); + PrintFormat("Volume: %f", _volume); + PrintFormat("Price: %f", _price); + PrintFormat("Deviation: %d", _deviation); + PrintFormat("StopLoss: %f", _stoploss); + PrintFormat("TakeProfit: %f", _takeprofit); + PrintFormat("Comment: %s", _comment); + PrintFormat("Magic: %d", _magic); + PrintFormat("Expiration: %s", TimeToStr(_symbol, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); +#endif + return ::OrderSend(_symbol, _cmd, _volume, _price, (int)_deviation, _stoploss, _takeprofit, _comment, (unsigned int)_magic, _expiration, _arrow_color); #else @@ -1182,6 +1232,9 @@ class Order : public SymbolInfo { static bool OrderSend(const MqlTradeRequest &_request, MqlTradeResult &_result, MqlTradeCheckResult &_result_check, color _color = clrNONE) { _result.retcode = TRADE_RETCODE_ERROR; +#ifdef __debug__ + Print("Sending request:\n", ToString(_request)); +#endif #ifdef __MQL4__ // Convert Trade Request Structure to function parameters. if (_request.position > 0) { @@ -1248,6 +1301,10 @@ class Order : public SymbolInfo { } } +#ifdef __debug__ + Print("Received result:\n", ToString(_result)); +#endif + return _result.retcode == TRADE_RETCODE_DONE; #else // The trade requests go through several stages of checking on a trade server. @@ -1279,7 +1336,13 @@ class Order : public SymbolInfo { // - https://www.mql5.com/en/docs/constants/errorswarnings/enum_trade_return_codes // -- // Sends trade requests to a server. - return ::OrderSend(_request, _result); + bool _success = ::OrderSend(_request, _result); + +#ifdef __debug__ + Print("Received result:\n", ToString(_result)); +#endif + + return _success; // The function execution result is placed to structure MqlTradeResult, // whose retcode field contains the trade server return code. // In order to obtain information about the error, call the GetLastError() function. @@ -1368,6 +1431,7 @@ class Order : public SymbolInfo { } else { odata.Set(ORDER_PROP_LAST_ERROR, fmax(odata.Get(ORDER_PROP_LAST_ERROR), GetLastError())); + oresult.retcode = odata.Get(ORDER_PROP_LAST_ERROR); } return _result; } @@ -1489,7 +1553,6 @@ class Order : public SymbolInfo { selected_ticket_type = ORDER_SELECT_TYPE_HISTORY; } else { selected_ticket_type = ORDER_SELECT_TYPE_NONE; - selected_ticket_id = 0; } selected_ticket_id = selected_ticket_type == ORDER_SELECT_TYPE_NONE ? 0 : _ticket_id; @@ -1500,8 +1563,10 @@ class Order : public SymbolInfo { selected_ticket_type = ORDER_SELECT_TYPE_ACTIVE; } else { ResetLastError(); - if (::PositionSelectByTicket(_index) && GetLastError() == ERR_SUCCESS) { + if (pool == MODE_TRADES && ::PositionSelectByTicket(_index) && GetLastError() == ERR_SUCCESS) { selected_ticket_type = ORDER_SELECT_TYPE_POSITION; + } else if (pool == MODE_HISTORY && HistorySelectByPosition(_index) && GetLastError() == ERR_SUCCESS) { + selected_ticket_type = ORDER_SELECT_TYPE_HISTORY; } else { ResetLastError(); if (::HistoryOrderSelect(_index) && GetLastError() == ERR_SUCCESS) { @@ -2764,7 +2829,7 @@ class Order : public SymbolInfo { /** * Returns order details in text. */ - string const ToString() { + string const ToString() override { SerializerConverter stub(SerializerConverter::MakeStubObject(SERIALIZER_FLAG_SKIP_HIDDEN)); return SerializerConverter::FromObject(THIS_REF, SERIALIZER_FLAG_SKIP_HIDDEN) .ToString(SERIALIZER_FLAG_SKIP_HIDDEN, &stub); diff --git a/Platform.h b/Platform.h new file mode 100644 index 000000000..88ec23736 --- /dev/null +++ b/Platform.h @@ -0,0 +1,342 @@ +//+------------------------------------------------------------------+ +//| 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 . + * + */ + +// Includes. + +/** + * Current platform's static methods. + */ + +#include "Flags.h" +#include "IndicatorBase.h" +#include "Std.h" + +#ifdef __MQLBUILD__ +#include "Indicator/tests/classes/IndicatorTfDummy.h" +#include "Indicators/Tick/Indi_TickMt.mqh" +#define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickMt +#else +#error "Platform not supported! +#endif +#include "SymbolInfo.struct.static.h" + +class Platform { + // Whether Init() was already called. + static bool initialized; + + // Date and time used to determine periods that passed. + static DateTime time; + + // Merged flags from previous Platform::UpdateTime(); + static unsigned int time_flags; + + // Whether to clear passed periods on consecutive Platform::UpdateTime(). + static bool time_clear_flags; + + // List of added indicators. + static DictStruct> indis; + + // List of default Candle/Tick indicators. + static DictStruct> indis_dflt; + + public: + /** + * Initializes platform. + */ + static void Init() { + if (initialized) { + // Already initialized. + return; + } + + initialized = true; + + // Starting from current timestamp. + time.Update(); + } + + /** + * Performs tick on every added indicator. + */ + static void Tick() { + // Checking starting periods and updating time to current one. + time_flags = time.GetStartedPeriods(); + time.Update(); + + DictStructIterator> _iter; + + for (_iter = indis.Begin(); _iter.IsValid(); ++_iter) { + _iter.Value() REF_DEREF Tick(); + } + + for (_iter = indis_dflt.Begin(); _iter.IsValid(); ++_iter) { + _iter.Value() REF_DEREF Tick(); + } + + // Will check for new time periods in consecutive Platform::UpdateTime(). + time_clear_flags = true; + } + + /** + * Returns dictionary of added indicators (keyed by unique id). + */ + static DictStruct> *GetIndicators() { return &indis; } + + /** + * Adds indicator to be processed by platform. + */ + static void Add(IndicatorData *_indi) { + Ref _ref = _indi; + indis.Set(_indi PTR_DEREF GetId(), _ref); + } + + /** + * 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) { + Add(_indi); + BindDefaultDataSource(_indi, _symbol, _tf); + } + + /** + * Removes indicator from being processed by platform. + */ + static void Remove(IndicatorData *_indi) { indis.Unset(_indi PTR_DEREF GetId()); } + + /** + * Returns date and time used to determine periods that passed. + */ + static DateTime Time() { return time; } + + /** + * Returns number of seconds passed from the Unix epoch. + */ + static datetime Timestamp() { return TimeCurrent(); } + + /** + * Checks whether it's a new second. + */ + static bool IsNewSecond() { return (time_flags & DATETIME_SECOND) != 0; } + + /** + * Checks whether it's a new minute. + */ + static bool IsNewMinute() { return (time_flags & DATETIME_MINUTE) != 0; } + + /** + * Checks whether it's a new hour. + */ + static bool IsNewHour() { return (time_flags & DATETIME_HOUR) != 0; } + + /** + * Checks whether it's a new day. + */ + static bool IsNewDay() { return (time_flags & DATETIME_DAY) != 0; } + + /** + * Checks whether it's a new week. + */ + static bool IsNewWeek() { return (time_flags & DATETIME_WEEK) != 0; } + + /** + * Checks whether it's a new month. + */ + static bool IsNewMonth() { return (time_flags & DATETIME_MONTH) != 0; } + + /** + * Checks whether it's a new year. + */ + static bool IsNewYear() { return (time_flags & DATETIME_YEAR) != 0; } + + /** + * Binds Candle and/or Tick indicator as a source of prices or data for given indicator. + * + * Note that some indicators may work on custom set of buffers required from data source and not on Candle or Tick + * indicator. + */ + static void BindDefaultDataSource(IndicatorData *_indi, CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { + Flags _suitable_ds_types = _indi PTR_DEREF GetSuitableDataSourceTypes(); + + IndicatorData *_default_indi_candle = FetchDefaultCandleIndicator(_symbol, _tf); + IndicatorData *_default_indi_tick = FetchDefaultTickIndicator(_symbol); + + if (_suitable_ds_types.HasFlag(INDI_SUITABLE_DS_TYPE_EXPECT_NONE)) { + // There should be no data source, but we have to attach at least a Candle indicator in order to use GetBarTime() + // and similar methods. + _indi PTR_DEREF SetDataSource(_default_indi_candle); + } else if (_suitable_ds_types.HasFlag(INDI_SUITABLE_DS_TYPE_CUSTOM)) { + if (_indi PTR_DEREF OnCheckIfSuitableDataSource(_default_indi_candle)) + _indi PTR_DEREF SetDataSource(_default_indi_candle); + else if (_indi PTR_DEREF OnCheckIfSuitableDataSource(_default_indi_tick)) { + _indi PTR_DEREF SetDataSource(_default_indi_tick); + } else { + // We can't attach any default data source as we don't know what type of indicator to create. + Print("ERROR: Cannot bind default data source for ", _indi PTR_DEREF GetFullName(), + " as we don't know what type of indicator to create!"); + DebugBreak(); + } + } else if (_suitable_ds_types.HasFlag(INDI_SUITABLE_DS_TYPE_AP)) { + // Indicator requires OHLC-compatible data source, Candle indicator would fulfill such requirement. + _indi PTR_DEREF SetDataSource(_default_indi_candle); + } else if (_suitable_ds_types.HasFlag(INDI_SUITABLE_DS_TYPE_CANDLE) || + _suitable_ds_types.HasFlag(INDI_SUITABLE_DS_TYPE_EXPECT_ANY)) { + _indi PTR_DEREF SetDataSource(_default_indi_candle); + } else if (_suitable_ds_types.HasFlag(INDI_SUITABLE_DS_TYPE_TICK)) { + _indi PTR_DEREF SetDataSource(_default_indi_tick); + } else { + Print( + "Error: Could not bind platform's default data source as neither Candle nor Tick-based indicator are " + "compatible with the target one."); + DebugBreak(); + } + } + + /** + * 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; + } + + if (_tf == PERIOD_CURRENT) { + _tf = (ENUM_TIMEFRAMES)Period(); + } + + // Candle is per symbol and TF. Single Candle indicator can't handle multiple TFs. + string _key = Util::MakeKey("PlatformIndicatorCandle", _symbol, (int)_tf); + IndicatorData *_indi_candle; + if (!Objects::TryGet(_key, _indi_candle)) { + _indi_candle = Objects::Set(_key, new IndicatorTfDummy(_tf)); + + // 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)); + } + + return _indi_candle; + } + + /** + * Returns default Tick-compatible indicator for current platform for given symbol. + */ + static IndicatorData *FetchDefaultTickIndicator(string _symbol = "") { + if (_symbol == "") { + _symbol = _Symbol; + } + + string _key = Util::MakeKey("PlatformIndicatorTick", _symbol); + IndicatorData *_indi_tick; + if (!Objects::TryGet(_key, _indi_tick)) { + _indi_tick = Objects::Set(_key, new PLATFORM_DEFAULT_INDICATOR_TICK(_symbol)); + _indi_tick PTR_DEREF SetSymbolProps(Platform::FetchDefaultSymbolProps(_symbol)); + + // Adding indicator to list of default indicators in order to tick it on every Tick() call. + Ref _ref = _indi_tick; + indis_dflt.Set(_indi_tick PTR_DEREF GetId(), _ref); + } + return _indi_tick; + } + + /** + * Returns default properties for given symbol for current platform. + */ + static SymbolInfoProp FetchDefaultSymbolProps(CONST_REF_TO(string) _symbol) { + SymbolInfoProp props; +#ifdef __MQLBUILD__ + props.pip_value = SymbolInfoStatic::GetPipValue(_symbol); + props.digits = SymbolInfoStatic::GetDigits(_symbol); + props.pip_digits = SymbolInfoStatic::GetPipDigits(_symbol); + props.pts_per_pip = SymbolInfoStatic::GetPointsPerPip(_symbol); + props.vol_digits = SymbolInfoStatic::GetVolumeDigits(_symbol); + props.vol_min = SymbolInfoStatic::GetVolumeMin(_symbol); + props.vol_max = SymbolInfoStatic::GetVolumeMax(_symbol); + props.vol_step = SymbolInfoStatic::GetVolumeStep(_symbol); + props.point_size = SymbolInfoStatic::GetPointSize(_symbol); + props.tick_size = SymbolInfoStatic::GetTickSize(_symbol); + props.tick_value = SymbolInfoStatic::GetTickValue(_symbol); + props.swap_long = SymbolInfoStatic::GetSwapLong(_symbol); + props.swap_short = SymbolInfoStatic::GetSwapShort(_symbol); + props.margin_initial = SymbolInfoStatic::GetMarginInit(_symbol); + props.margin_maintenance = SymbolInfoStatic::GetMarginMaintenance(_symbol); + props.freeze_level = SymbolInfoStatic::GetFreezeLevel(_symbol); +#endif + return props; + } + + /** + * Prints indicators' values at the given shift. + */ + static string IndicatorsToString(int _shift = 0) { + string _result; + for (DictStructIterator> _iter = indis.Begin(); _iter.IsValid(); ++_iter) { + IndicatorDataEntry _entry = _iter.Value() REF_DEREF GetEntry(_shift); + _result += _iter.Value() REF_DEREF GetFullName() + " = " + _entry.ToString() + "\n"; + } + return _result; + } +}; + +bool Platform::initialized = false; +DateTime Platform::time = 0; +unsigned int Platform::time_flags = 0; +bool Platform::time_clear_flags = true; +DictStruct> Platform::indis; +DictStruct> Platform::indis_dflt; + +// void OnTimer() { Print("Timer"); Platform::OnTimer(); } + +/** + * Will test given indicator class with platform-default data source bindings. + */ +#define TEST_INDICATOR_DEFAULT_BINDINGS_PARAMS(C, PARAMS) \ + Ref indi = new C(PARAMS); \ + \ + int OnInit() { \ + Platform::Init(); \ + Platform::AddWithDefaultBindings(indi.Ptr()); \ + bool _result = true; \ + assertTrueOrFail(indi REF_DEREF IsValid(), "Error on IsValid!"); \ + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); \ + } \ + \ + void OnTick() { \ + Platform::Tick(); \ + if (Platform::IsNewHour()) { \ + 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)"); \ + if (_is_ready && !_is_valid) { \ + Print(indi REF_DEREF ToString(), " (Invalid entry!)"); \ + assertTrueOrExit(_entry.IsValid(), "Invalid entry!"); \ + } \ + } \ + } + +#define TEST_INDICATOR_DEFAULT_BINDINGS(C) TEST_INDICATOR_DEFAULT_BINDINGS_PARAMS(C, ) diff --git a/Refs.mqh b/Refs.mqh index a99e79405..72f5f3044 100644 --- a/Refs.mqh +++ b/Refs.mqh @@ -63,9 +63,6 @@ * root.childNodes.Push(child2); */ -// Forward class declaration. -class Dynamic; - /** * Base class for reference-counted objects. */ diff --git a/Refs.struct.h b/Refs.struct.h index 329d861ed..1b0649250 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -126,7 +126,7 @@ struct Ref { /** * Returns pointer to target object. */ - X* Ptr() const { return ptr_object; } + X* Ptr() { return ptr_object; } /** * Checks whether any object is referenced. @@ -292,10 +292,10 @@ struct WeakRef { bool ObjectExists() { 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() { return ObjectExists() ? (X*)(PTR_ATTRIB(ptr_ref_counter, ptr_object)) : NULL; } /** - * Makes a strong reference to the given object. + * Makes a weak reference to the given object. */ X* operator=(X* _ptr) { if (ptr_ref_counter == (_ptr == NULL ? NULL : PTR_ATTRIB(_ptr, ptr_ref_counter))) { diff --git a/Serializer.mqh b/Serializer.mqh index 50e605f8b..acecedfb0 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -449,7 +449,7 @@ class Serializer { Convert::StringToType(PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), _string), value); break; default: - Print("Error: Wrong param type!"); + Print("Error: Wrong param type ", paramType, "!"); SetUserError(ERR_INVALID_PARAMETER); DebugBreak(); } diff --git a/SerializerNode.mqh b/SerializerNode.mqh index 5306cd4ad..e130aef88 100644 --- a/SerializerNode.mqh +++ b/SerializerNode.mqh @@ -139,7 +139,7 @@ class SerializerNode { _result += StringLen(PTR_ATTRIB(_value, _string)) + 1; break; default: - Print("Error: Wrong value type!"); + Print("Error: Wrong value type ", GetType(), "!"); SetUserError(ERR_INVALID_PARAMETER); DebugBreak(); } diff --git a/Std.h b/Std.h index dd171ab2b..2ac13ea7a 100644 --- a/Std.h +++ b/Std.h @@ -51,6 +51,7 @@ #define PTR_ATTRIB2(O, A, B) O.A.B #define PTR_TO_REF(PTR) PTR #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE* NAME = PTR +#define REF_DEREF .Ptr(). #else #define GET_PTR(obj) (*obj) #define THIS_ATTR this-> @@ -61,6 +62,7 @@ #define PTR_ATTRIB2(O, A, B) O->A->B #define PTR_TO_REF(PTR) (*PTR) #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE& NAME = PTR +#define REF_DEREF .Ptr()-> #endif // References. @@ -80,6 +82,11 @@ #endif #ifdef __MQL__ +/** + * Reference to object. + */ +#define CONST_REF_TO(T) const T + /** * Reference to the array. * @@ -98,9 +105,13 @@ * @usage * ARRAY(, ) */ -#define ARRAY(T, N) T N[]; +#define ARRAY(T, N) T N[] #else +/** + * Reference to object. + */ +#define CONST_REF_TO(T) const T& /** * Reference to the array. diff --git a/Storage/IValueStorage.h b/Storage/IValueStorage.h index 512a2e640..ab3f5b20a 100644 --- a/Storage/IValueStorage.h +++ b/Storage/IValueStorage.h @@ -29,7 +29,9 @@ #pragma once #endif -class IValueStorage { +#include "../Refs.mqh" + +class IValueStorage : public Dynamic { public: /** * Destructor. @@ -39,7 +41,7 @@ class IValueStorage { /** * Returns number of values available to fetch (size of the values buffer). */ - virtual int Size() const { + virtual int Size() { Alert(__FUNCSIG__, " does not implement Size()!"); DebugBreak(); return 0; @@ -93,4 +95,4 @@ int ArrayResize(IValueStorage& _storage, int _size, int _reserve = 100) { /** * ValueStorage-compatible wrapper for ArraySize. */ -int ArraySize(const IValueStorage& _storage) { return _storage.Size(); } +int ArraySize(IValueStorage& _storage) { return _storage.Size(); } diff --git a/Storage/Objects.h b/Storage/Objects.h index feaadc371..443c6337c 100644 --- a/Storage/Objects.h +++ b/Storage/Objects.h @@ -48,7 +48,7 @@ class Objects { /** * Tries to retrieve pointer to object for a given key. Returns true if object did exist. */ - static bool TryGet(string& key, C*& out_ptr) { + static bool TryGet(CONST_REF_TO(string) key, C*& out_ptr) { int position; if (!GetObjects().KeyExists(key, position)) { out_ptr = NULL; @@ -62,7 +62,7 @@ class Objects { /** * Stores object pointer with a given key. */ - static C* Set(string& key, C* ptr) { + static C* Set(CONST_REF_TO(string) key, C* ptr) { Ref _ref(ptr); GetObjects().Set(key, _ref); return ptr; diff --git a/Storage/ValueStorage.all.h b/Storage/ValueStorage.all.h index 136755612..20cb16163 100644 --- a/Storage/ValueStorage.all.h +++ b/Storage/ValueStorage.all.h @@ -30,11 +30,11 @@ #endif // Includes. +#include "ValueStorage.applied_price.h" #include "ValueStorage.h" #include "ValueStorage.history.h" #include "ValueStorage.indicator.h" #include "ValueStorage.native.h" -#include "ValueStorage.price.h" #include "ValueStorage.spread.h" #include "ValueStorage.tick_volume.h" #include "ValueStorage.time.h" diff --git a/Storage/ValueStorage.price.h b/Storage/ValueStorage.applied_price.h similarity index 64% rename from Storage/ValueStorage.price.h rename to Storage/ValueStorage.applied_price.h index da5c69537..4ae05ec4b 100644 --- a/Storage/ValueStorage.price.h +++ b/Storage/ValueStorage.applied_price.h @@ -29,10 +29,13 @@ #include "ObjectsCache.h" #include "ValueStorage.history.h" +// Forward declarations. +class ChartBase; + /** - * Storage to retrieve OHLC. + * Storage to retrieve OHLC from Candle indicator. */ -class PriceValueStorage : public HistoryValueStorage { +class AppliedPriceValueStorage : public HistoryValueStorage { // Time-frame to fetch price for. ENUM_APPLIED_PRICE ap; @@ -40,35 +43,18 @@ class PriceValueStorage : public HistoryValueStorage { /** * Constructor. */ - PriceValueStorage(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_APPLIED_PRICE _ap = PRICE_OPEN) - : ap(_ap), HistoryValueStorage(_symbol, _tf) {} + AppliedPriceValueStorage(IndicatorBase *_indi_candle, ENUM_APPLIED_PRICE _ap = PRICE_OPEN) + : ap(_ap), HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - PriceValueStorage(const PriceValueStorage &_r) : ap(_r.ap), HistoryValueStorage(_r.symbol, _r.tf) {} - - /** - * Returns pointer to PriceValueStorage of a given symbol and time-frame. - */ - static PriceValueStorage *GetInstance(string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_PRICE _ap) { - PriceValueStorage *_storage; - string _key = Util::MakeKey(_symbol, (int)_tf, (int)_ap); - if (!ObjectsCache::TryGet(_key, _storage)) { - _storage = ObjectsCache::Set(_key, new PriceValueStorage(_symbol, _tf, _ap)); - } - - if (CheckPointer(_storage) == POINTER_INVALID) { - Print("Failure while getting point to object from cache!"); - } - - return _storage; - } + AppliedPriceValueStorage(AppliedPriceValueStorage &_r) : ap(_r.ap), HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - virtual double Fetch(int _shift) { + double Fetch(int _shift) override { switch (ap) { case PRICE_OPEN: case PRICE_HIGH: @@ -88,19 +74,7 @@ class PriceValueStorage : public HistoryValueStorage { return 0.0; } - double Fetch(ENUM_APPLIED_PRICE _ap, int _shift) { - switch (_ap) { - case PRICE_OPEN: - return iOpen(symbol, tf, RealShift(_shift)); - case PRICE_HIGH: - return iHigh(symbol, tf, RealShift(_shift)); - case PRICE_LOW: - return iLow(symbol, tf, RealShift(_shift)); - case PRICE_CLOSE: - return iClose(symbol, tf, RealShift(_shift)); - } - return 0; - } + double Fetch(ENUM_APPLIED_PRICE _ap, int _shift) { return indi_candle REF_DEREF GetPrice(_ap, RealShift(_shift)); } static double GetApplied(ValueStorage &_open, ValueStorage &_high, ValueStorage &_low, ValueStorage &_close, int _shift, ENUM_APPLIED_PRICE _ap) { diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index 410a47726..805f01397 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -34,6 +34,8 @@ #define VALUE_STORAGE_H // Includes. +#include "../SerializerConversions.h" +#include "../Util.h" #include "Objects.h" // Enumeration for iPeak(). @@ -65,55 +67,53 @@ enum ENUM_IPEAK { IPEAK_LOWEST, IPEAK_HIGHEST }; #define INDICATOR_CALCULATE_GET_PARAMS_SHORT _cache.GetTotal(), _cache.GetPrevCalculated(), 0, _cache.GetPriceBuffer() -#define INDICATOR_CALCULATE_POPULATE_CACHE(SYMBOL, TF, KEY) \ +#define INDICATOR_CALCULATE_POPULATE_CACHE(INDI, KEY) \ IndicatorCalculateCache *_cache; \ - string _key = Util::MakeKey(SYMBOL, (int)TF, KEY); \ + string _key = Util::MakeKey(INDI PTR_DEREF GetId(), KEY); \ if (!Objects>::TryGet(_key, _cache)) { \ _cache = Objects>::Set(_key, new IndicatorCalculateCache()); \ } -#define INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(SYMBOL, TF, KEY) \ - ValueStorage *_time = TimeValueStorage::GetInstance(SYMBOL, TF); \ - ValueStorage *_tick_volume = TickVolumeValueStorage::GetInstance(SYMBOL, TF); \ - ValueStorage *_volume = VolumeValueStorage::GetInstance(SYMBOL, TF); \ - ValueStorage *_spread = SpreadValueStorage::GetInstance(SYMBOL, TF); \ - ValueStorage *_price_open = PriceValueStorage::GetInstance(SYMBOL, TF, PRICE_OPEN); \ - ValueStorage *_price_high = PriceValueStorage::GetInstance(SYMBOL, TF, PRICE_HIGH); \ - ValueStorage *_price_low = PriceValueStorage::GetInstance(SYMBOL, TF, PRICE_LOW); \ - ValueStorage *_price_close = PriceValueStorage::GetInstance(SYMBOL, TF, PRICE_CLOSE); \ - INDICATOR_CALCULATE_POPULATE_CACHE(SYMBOL, TF, KEY) - -#define INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(SYMBOL, TF, APPLIED_PRICE, KEY) \ - ValueStorage *_price = PriceValueStorage::GetInstance(SYMBOL, TF, APPLIED_PRICE); \ - INDICATOR_CALCULATE_POPULATE_CACHE(SYMBOL, TF, KEY) - -#define INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS(INDI, SYMBOL, TF, APPLIED_PRICE, KEY) \ - ValueStorage *_price = INDI.GetValueStorage(APPLIED_PRICE); \ - INDICATOR_CALCULATE_POPULATE_CACHE(SYMBOL, TF, KEY) - -#define INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS_SPECIFIC(INDI, SYMBOL, TF, APPLIED_PRICE, KEY) \ +/** + * Note that INDI is used as target indicator and source indicator is searched + * by GetSuitableDataSource(). Would be better to differentiate target and + * source indicator in order user wanted to run INDI on custom data source + * (the one that doesn't exist in the hierarchy). + */ +#define INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(INDI, APPLIED_PRICE, KEY) \ ValueStorage *_price; \ - if (_indi.HasSpecificAppliedPriceValueStorage(APPLIED_PRICE)) { \ - _price = INDI.GetSpecificAppliedPriceValueStorage(APPLIED_PRICE); \ + if (INDI PTR_DEREF GetSuitableDataSource() PTR_DEREF HasSpecificAppliedPriceValueStorage(APPLIED_PRICE, INDI)) { \ + _price = \ + INDI PTR_DEREF GetSuitableDataSource() PTR_DEREF GetSpecificAppliedPriceValueStorage(APPLIED_PRICE, INDI); \ } else { \ - Print("Source indicator ", INDI.GetFullName(), \ + Print("Source indicator ", INDI PTR_DEREF GetFullName(), \ " cannot be used as it doesn't provide a single buffer to be used by target indicator! You may try to set " \ - "applied price/data source mode and try again."); \ + "applied price/data source mode and try again. AP passed by params: ", \ + EnumToString(INDI PTR_DEREF GetAppliedPrice()), \ + ", AP overriden: ", EnumToString(INDI PTR_DEREF GetDataSourceAppliedType())); \ DebugBreak(); \ } \ - \ - INDICATOR_CALCULATE_POPULATE_CACHE(SYMBOL, TF, KEY) - -#define INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(INDI, SYMBOL, TF, KEY) \ - ValueStorage *_time = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_TIME); \ - ValueStorage *_tick_volume = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME); \ - ValueStorage *_volume = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_VOLUME); \ - ValueStorage *_spread = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_SPREAD); \ - ValueStorage *_price_open = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); \ - ValueStorage *_price_high = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); \ - ValueStorage *_price_low = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); \ - ValueStorage *_price_close = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); \ - INDICATOR_CALCULATE_POPULATE_CACHE(SYMBOL, TF, KEY) + INDICATOR_CALCULATE_POPULATE_CACHE(INDI, KEY) + +#define INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(INDI, KEY) \ + IndicatorData *_suitable_ds = INDI PTR_DEREF GetSuitableDataSource(); \ + ValueStorage *_time = \ + (ValueStorage *)_suitable_ds PTR_DEREF GetSpecificValueStorage(INDI_VS_TYPE_TIME); \ + ValueStorage *_tick_volume = \ + (ValueStorage *)_suitable_ds PTR_DEREF GetSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME); \ + ValueStorage *_volume = \ + (ValueStorage *)_suitable_ds PTR_DEREF GetSpecificValueStorage(INDI_VS_TYPE_VOLUME); \ + ValueStorage *_spread = \ + (ValueStorage *)_suitable_ds PTR_DEREF GetSpecificValueStorage(INDI_VS_TYPE_SPREAD); \ + ValueStorage *_price_open = \ + (ValueStorage *)_suitable_ds PTR_DEREF GetSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); \ + ValueStorage *_price_high = \ + (ValueStorage *)_suitable_ds PTR_DEREF GetSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); \ + ValueStorage *_price_low = \ + (ValueStorage *)_suitable_ds PTR_DEREF GetSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); \ + ValueStorage *_price_close = \ + (ValueStorage *)_suitable_ds PTR_DEREF GetSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); \ + INDICATOR_CALCULATE_POPULATE_CACHE(INDI, KEY) #define INDICATOR_CALCULATE_POPULATED_PARAMS_LONG \ _time, _price_open, _price_high, _price_low, _price_close, _tick_volume, _volume, _spread @@ -154,7 +154,16 @@ class ValueStorage : public IValueStorage { * Fetches value from a given shift. Takes into consideration as-series flag. */ virtual C Fetch(int _shift) { - Alert(__FUNCSIG__, " is not supported!"); + Alert("Fetching data by shift is not supported from this value storage!"); + DebugBreak(); + return (C)0; + } + + /** + * Fetches value from a given datetime. Takes into consideration as-series flag. + */ + virtual C Fetch(datetime _dt) { + Alert("Fetching data by datetime is not supported from this value storage!"); DebugBreak(); return (C)0; } @@ -181,6 +190,16 @@ class ValueStorage : public IValueStorage { } }; +template +string StringifyOHLC(ValueStorage &_open, ValueStorage &_high, ValueStorage &_low, ValueStorage &_close, + int _shift = 0) { + C _o = _open[_shift].Get(); + C _h = _high[_shift].Get(); + C _l = _low[_shift].Get(); + C _c = _close[_shift].Get(); + return IntegerToString(_shift) + ": " + Util::MakeKey(_o, _h, _l, _c); +} + /** * ValueStorage-compatible wrapper for ArrayInitialize. */ @@ -295,4 +314,4 @@ int iPeak(ValueStorage &_price, int _count, int _start, ENUM_IPEAK _type return _price_size - _peak_idx - 1; } -#endif // STRATEGY_MQH +#endif // VALUE_STORAGE_H diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index 342ad7ce9..3494b0e41 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -34,6 +34,7 @@ #include "ValueStorage.h" // Forward declarations. +class IndicatorBase; template class ValueStorage; @@ -43,14 +44,8 @@ class ValueStorage; template class HistoryValueStorage : public ValueStorage { protected: - // Symbol to fetch history for. - string symbol; - - // Time-frame to fetch history for. - ENUM_TIMEFRAMES tf; - - // Time of the first bar possible to fetch. - datetime start_bar_time; + // Indicator used as an OHLC source, e.g. IndicatorCandle. + WeakRef indi_candle; // Whether storage operates in as-series mode. bool is_series; @@ -59,9 +54,12 @@ class HistoryValueStorage : public ValueStorage { /** * Constructor. */ - HistoryValueStorage(string _symbol, ENUM_TIMEFRAMES _tf, bool _is_series = false) - : symbol(_symbol), tf(_tf), is_series(_is_series) { - start_bar_time = ChartStatic::iTime(_symbol, _tf, BarsFromStart() - 1); + HistoryValueStorage(IndicatorBase* _indi_candle, bool _is_series = false) + : indi_candle(_indi_candle), is_series(_is_series) { + if (_indi_candle == nullptr) { + Print("You have to pass IndicatorCandle-compatible indicator as parameter to HistoryValueStorage!"); + DebugBreak(); + } } /** @@ -86,17 +84,22 @@ class HistoryValueStorage : public ValueStorage { /** * Number of bars passed from the start. There will be a single bar at the start. */ - int BarsFromStart() const { return Bars(symbol, tf); } + int BarsFromStart() { + if (!indi_candle.ObjectExists()) { + return 0; + } + return indi_candle REF_DEREF GetBars(); + } /** * Returns number of values available to fetch (size of the values buffer). */ - virtual int Size() const { return BarsFromStart(); } + int Size() override { return BarsFromStart(); } /** * Resizes storage to given size. */ - virtual void Resize(int _size, int _reserve) { + void Resize(int _size, int _reserve) override { Print("HistoryValueStorage does not implement Resize()!"); DebugBreak(); } @@ -104,12 +107,12 @@ class HistoryValueStorage : public ValueStorage { /** * Checks whether storage operates in as-series mode. */ - virtual bool IsSeries() const { return is_series; } + bool IsSeries() const override { return is_series; } /** * Sets storage's as-series mode on or off. */ - virtual bool SetSeries(bool _value) { + bool SetSeries(bool _value) override { is_series = _value; return true; } diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 0e008f924..d2a4b97eb 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -41,9 +41,6 @@ class IndicatorData; */ template class IndicatorBufferValueStorage : public HistoryValueStorage { - // Pointer to indicator to access data from. - IndicatorData *indicator; - // Mode of the target indicator. int mode; @@ -51,11 +48,11 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { /** * Constructor. */ - IndicatorBufferValueStorage(IndicatorData *_indi, int _mode = 0, ENUM_TIMEFRAMES _tf = NULL, bool _is_series = false) - : indicator(_indi), mode(_mode), HistoryValueStorage(_indi.GetSymbol(), _tf) {} + IndicatorBufferValueStorage(IndicatorBase *_indi_candle, int _mode = 0, bool _is_series = false) + : mode(_mode), HistoryValueStorage(_indi_candle) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - virtual C Fetch(int _shift) { return indicator.GetValue(mode, RealShift(_shift)); } + C Fetch(int _shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_shift)); } }; diff --git a/Storage/ValueStorage.native.h b/Storage/ValueStorage.native.h index e1bb21d30..d2d2f63cf 100644 --- a/Storage/ValueStorage.native.h +++ b/Storage/ValueStorage.native.h @@ -64,12 +64,12 @@ class NativeValueStorage : public ValueStorage { /** * Initializes storage with given value. */ - virtual void Initialize(C _value) { ArrayInitialize(_values, _value); } + void Initialize(C _value) override { ArrayInitialize(_values, _value); } /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - virtual C Fetch(int _shift) { + C Fetch(int _shift) override { if (_shift < 0 || _shift >= _values_size) { return (C)EMPTY_VALUE; // Print("Invalid buffer data index: ", _shift, ". Buffer size: ", ArraySize(_values)); @@ -82,27 +82,27 @@ class NativeValueStorage : public ValueStorage { /** * Stores value at a given shift. Takes into consideration as-series flag. */ - virtual void Store(int _shift, C _value) { Array::ArrayStore(_values, _shift, _value, 4096); } + void Store(int _shift, C _value) override { Array::ArrayStore(_values, _shift, _value, 4096); } /** * Returns number of values available to fetch (size of the values buffer). */ - virtual int Size() const { return _values_size; } + int Size() override { return _values_size; } /** * Resizes storage to given size. */ - virtual void Resize(int _size, int _reserve) { ArrayResize(_values, _size, _reserve); } + void Resize(int _size, int _reserve) override { ArrayResize(_values, _size, _reserve); } /** * Checks whether storage operates in as-series mode. */ - virtual bool IsSeries() const { return ArrayGetAsSeries(_values); } + bool IsSeries() const override { return ArrayGetAsSeries(_values); } /** * Sets storage's as-series mode on or off. */ - virtual bool SetSeries(bool _value) { + bool SetSeries(bool _value) override { ArraySetAsSeries(_values, _value); return true; } diff --git a/Storage/ValueStorage.price_median.h b/Storage/ValueStorage.price_median.h new file mode 100644 index 000000000..6ba406e46 --- /dev/null +++ b/Storage/ValueStorage.price_median.h @@ -0,0 +1,58 @@ +//+------------------------------------------------------------------+ +//| 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 + * Median price version of ValueStorage. + */ + +// Includes. +#include "ObjectsCache.h" +#include "ValueStorage.history.h" + +/** + * Storage to median price. + */ +class PriceMedianValueStorage : public HistoryValueStorage { + public: + /** + * Constructor. + */ + PriceMedianValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + + /** + * Copy constructor. + */ + PriceMedianValueStorage(PriceMedianValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + + /** + * Fetches value from a given shift. Takes into consideration as-series flag. + */ + double Fetch(int _shift) override { + ResetLastError(); + double _value = indi_candle REF_DEREF GetOHLC(RealShift(_shift)).GetMedian(); + if (_LastError != ERR_NO_ERROR) { + Print("Cannot fetch OHLC! Error: ", _LastError); + DebugBreak(); + } + return _value; + } +}; diff --git a/Storage/ValueStorage.price_typical.h b/Storage/ValueStorage.price_typical.h new file mode 100644 index 000000000..91337dc77 --- /dev/null +++ b/Storage/ValueStorage.price_typical.h @@ -0,0 +1,58 @@ +//+------------------------------------------------------------------+ +//| 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 + * Typical price version of ValueStorage. + */ + +// Includes. +#include "ObjectsCache.h" +#include "ValueStorage.history.h" + +/** + * Storage for typical price. + */ +class PriceTypicalValueStorage : public HistoryValueStorage { + public: + /** + * Constructor. + */ + PriceTypicalValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + + /** + * Copy constructor. + */ + PriceTypicalValueStorage(PriceTypicalValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + + /** + * Fetches value from a given shift. Takes into consideration as-series flag. + */ + double Fetch(int _shift) override { + ResetLastError(); + double _value = indi_candle REF_DEREF GetOHLC(RealShift(_shift)).GetTypical(); + if (_LastError != ERR_NO_ERROR) { + Print("Cannot fetch OHLC! Error: ", _LastError); + DebugBreak(); + } + return _value; + } +}; diff --git a/Storage/ValueStorage.price_weighted.h b/Storage/ValueStorage.price_weighted.h new file mode 100644 index 000000000..1fab60e08 --- /dev/null +++ b/Storage/ValueStorage.price_weighted.h @@ -0,0 +1,58 @@ +//+------------------------------------------------------------------+ +//| 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 + * Weighted price version of ValueStorage. + */ + +// Includes. +#include "ObjectsCache.h" +#include "ValueStorage.history.h" + +/** + * Storage for weighted price. + */ +class PriceWeightedValueStorage : public HistoryValueStorage { + public: + /** + * Constructor. + */ + PriceWeightedValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + + /** + * Copy constructor. + */ + PriceWeightedValueStorage(PriceWeightedValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + + /** + * Fetches value from a given shift. Takes into consideration as-series flag. + */ + double Fetch(int _shift) override { + ResetLastError(); + double _value = indi_candle REF_DEREF GetOHLC(RealShift(_shift)).GetWeighted(); + if (_LastError != ERR_NO_ERROR) { + Print("Cannot fetch OHLC! Error: ", _LastError); + DebugBreak(); + } + return _value; + } +}; diff --git a/Storage/ValueStorage.spread.h b/Storage/ValueStorage.spread.h index 1a8ef74a0..4089d5401 100644 --- a/Storage/ValueStorage.spread.h +++ b/Storage/ValueStorage.spread.h @@ -37,27 +37,15 @@ class SpreadValueStorage : public HistoryValueStorage { /** * Constructor. */ - SpreadValueStorage(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : HistoryValueStorage(_symbol, _tf) {} + SpreadValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - SpreadValueStorage(const SpreadValueStorage &_r) : HistoryValueStorage(_r.symbol, _r.tf) {} - - /** - * Returns pointer to SpreadValueStorage of a given symbol and time-frame. - */ - static SpreadValueStorage *GetInstance(string _symbol, ENUM_TIMEFRAMES _tf) { - SpreadValueStorage *_storage; - string _key = _symbol + "/" + IntegerToString((int)_tf); - if (!ObjectsCache::TryGet(_key, _storage)) { - _storage = ObjectsCache::Set(_key, new SpreadValueStorage(_symbol, _tf)); - } - return _storage; - } + SpreadValueStorage(SpreadValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - virtual long Fetch(int _shift) { return ChartStatic::iVolume(symbol, tf, RealShift(_shift)); } + long Fetch(int _shift) override { return indi_candle REF_DEREF GetSpread(RealShift(_shift)); } }; diff --git a/Storage/ValueStorage.tick_volume.h b/Storage/ValueStorage.tick_volume.h index 1799c92d9..8754c2869 100644 --- a/Storage/ValueStorage.tick_volume.h +++ b/Storage/ValueStorage.tick_volume.h @@ -36,28 +36,15 @@ class TickVolumeValueStorage : public HistoryValueStorage { /** * Constructor. */ - TickVolumeValueStorage(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) - : HistoryValueStorage(_symbol, _tf) {} + TickVolumeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - TickVolumeValueStorage(const TickVolumeValueStorage &_r) : HistoryValueStorage(_r.symbol, _r.tf) {} - - /** - * Returns pointer to TickVolumeValueStorage of a given symbol and time-frame. - */ - static TickVolumeValueStorage *GetInstance(string _symbol, ENUM_TIMEFRAMES _tf) { - TickVolumeValueStorage *_storage; - string _key = _symbol + "/" + IntegerToString((int)_tf); - if (!ObjectsCache::TryGet(_key, _storage)) { - _storage = ObjectsCache::Set(_key, new TickVolumeValueStorage(_symbol, _tf)); - } - return _storage; - } + TickVolumeValueStorage(TickVolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - virtual long Fetch(int _shift) { return ChartStatic::iVolume(symbol, tf, RealShift(_shift)); } + long Fetch(int _shift) override { return indi_candle REF_DEREF GetVolume(RealShift(_shift)); } }; diff --git a/Storage/ValueStorage.time.h b/Storage/ValueStorage.time.h index fdcf22504..1f48a1871 100644 --- a/Storage/ValueStorage.time.h +++ b/Storage/ValueStorage.time.h @@ -37,27 +37,15 @@ class TimeValueStorage : public HistoryValueStorage { /** * Constructor. */ - TimeValueStorage(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : HistoryValueStorage(_symbol, _tf) {} + TimeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - TimeValueStorage(const TimeValueStorage &_r) : HistoryValueStorage(_r.symbol, _r.tf) {} - - /** - * Returns pointer to TimeValueStorage of a given symbol and time-frame. - */ - static TimeValueStorage *GetInstance(string _symbol, ENUM_TIMEFRAMES _tf) { - TimeValueStorage *_storage; - string _key = Util::MakeKey(_symbol, (int)_tf); - if (!ObjectsCache::TryGet(_key, _storage)) { - _storage = ObjectsCache::Set(_key, new TimeValueStorage(_symbol, _tf)); - } - return _storage; - } + TimeValueStorage(TimeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - virtual datetime Fetch(int _shift) { return iTime(symbol, tf, RealShift(_shift)); } + datetime Fetch(int _shift) override { return indi_candle REF_DEREF GetBarTime(RealShift(_shift)); } }; diff --git a/Storage/ValueStorage.volume.h b/Storage/ValueStorage.volume.h index 240987405..d1686366f 100644 --- a/Storage/ValueStorage.volume.h +++ b/Storage/ValueStorage.volume.h @@ -36,31 +36,19 @@ class VolumeValueStorage : public HistoryValueStorage { /** * Constructor. */ - VolumeValueStorage(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : HistoryValueStorage(_symbol, _tf) {} + VolumeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - VolumeValueStorage(const VolumeValueStorage &_r) : HistoryValueStorage(_r.symbol, _r.tf) {} - - /** - * Returns pointer to VolumeValueStorage of a given symbol and time-frame. - */ - static VolumeValueStorage *GetInstance(string _symbol, ENUM_TIMEFRAMES _tf) { - VolumeValueStorage *_storage; - string _key = _symbol + "/" + IntegerToString((int)_tf); - if (!ObjectsCache::TryGet(_key, _storage)) { - _storage = ObjectsCache::Set(_key, new VolumeValueStorage(_symbol, _tf)); - } - return _storage; - } + VolumeValueStorage(VolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - virtual long Fetch(int _shift) { + long Fetch(int _shift) override { ResetLastError(); - long _volume = iVolume(symbol, tf, RealShift(_shift)); + long _volume = indi_candle REF_DEREF GetVolume(RealShift(_shift)); if (_LastError != ERR_NO_ERROR) { Print("Cannot fetch iVolume! Error: ", _LastError); DebugBreak(); diff --git a/Strategy.mqh b/Strategy.mqh index ef9c0d563..6958cf969 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -36,7 +36,6 @@ class Trade; #include "Strategy.enum.h" #include "Strategy.struct.h" #include "String.mqh" -#include "Task/Task.h" #include "Task/TaskManager.h" #include "Task/Taskable.h" #include "Trade.mqh" @@ -95,13 +94,14 @@ class Strategy : public Taskable { Dict ddata; Dict fdata; Dict idata; - DictStruct> indicators; // Indicators list. + Ref indi_source; // Candle or Tick indicator as a price source. + DictStruct> indicators; // Indicators list. Log logger; // Log instance. MqlTick last_tick; StgProcessResult sresult; Strategy *strat_sl, *strat_tp; // Strategy pointers for stop-loss and profit-take. TaskManager tasks; // Tasks. - Trade trade; // Trade instance. + Ref trade; // Trade instance. // TradeSignalEntry last_signal; // Last signals. private: @@ -113,7 +113,7 @@ class Strategy : public Taskable { // Base variables. string name; // Other variables. - int filter_method[]; // Filter method to consider the trade. + int filter_method[]; // Filter method to consider the trade REF_DEREF int open_condition[]; // Open conditions. int close_condition[]; // Close conditions. @@ -123,15 +123,15 @@ class Strategy : public Taskable { /** * Class constructor. */ - Strategy(StgParams &_sparams, TradeParams &_tparams, ChartParams &_cparams, string _name = "") - : sparams(_sparams), trade(_tparams, _cparams) { + Strategy(StgParams &_sparams, TradeParams &_tparams, IndicatorBase *_indi_source, string _name = "") + : sparams(_sparams), trade(new Trade(_tparams, _indi_source)), indi_source(_indi_source) { // Initialize variables. name = _name; MqlTick _tick = {0}; last_tick = _tick; // Link log instances. - logger.Link(trade.GetLogger()); + logger.Link(trade REF_DEREF GetLogger()); // Statistics variables. // UpdateOrderStats(EA_STATS_DAILY); @@ -220,7 +220,7 @@ class Strategy : public Taskable { /** * Returns strategy's indicators. */ - DictStruct> GetIndicators() { return indicators; } + DictStruct> GetIndicators() { return indicators; } /* Struct getters */ @@ -244,7 +244,7 @@ class Strategy : public Taskable { */ template T Get(ENUM_TRADE_PARAM _param) { - return trade.Get(_param); + return trade REF_DEREF Get(_param); } /** @@ -252,7 +252,7 @@ class Strategy : public Taskable { */ template T Get(ENUM_TRADE_STATE _prop) { - return trade.Get(_prop); + return trade REF_DEREF Get(_prop); } /** @@ -276,6 +276,20 @@ class Strategy : public Taskable { */ Strategy *GetStratTp() { return strat_tp; } + /** + * Returns Candle or Tick indicator bound to this strategy. + */ + IndicatorData *GetSource() { return indi_source.Ptr(); } + + /** + * Executes OnTick() on every attached indicator. + */ + void Tick() { + for (DictIterator> it = indicators.Begin(); it.IsValid(); ++it) { + it.Value() REF_DEREF Tick(); + } + } + /** * Get strategy's name. */ @@ -321,11 +335,10 @@ class Strategy : public Taskable { */ string GetOrderOpenComment(string _prefix = "", string _suffix = "") { // @todo: Add spread. - // return StringFormat("%s%s[%s];s:%gp%s", _prefix != "" ? _prefix + ": " : "", name, trade.chart.TfToString(), - // GetCurrSpread(), _suffix != "" ? "| " + _suffix : ""); + // return StringFormat("%s%s[%s];s:%gp%s", _prefix != "" ? _prefix + ": " : "", name, trade REF_DEREF + // chart.TfToString(), GetCurrSpread(), _suffix != "" ? "| " + _suffix : ""); - return StringFormat("%s%s[%s]%s", _prefix, name, ChartTf::TfToString(trade.Get(CHART_PARAM_TF)), - _suffix); + return StringFormat("%s%s[%s]%s", _prefix, name, trade REF_DEREF GetSource() PTR_DEREF GetSymbolTf(), _suffix); } /** @@ -333,8 +346,7 @@ class Strategy : public Taskable { */ string GetOrderCloseComment(string _prefix = "", string _suffix = "") { // @todo: Add spread. - return StringFormat("%s%s[%s]%s", _prefix, name, ChartTf::TfToString(trade.Get(CHART_PARAM_TF)), - _suffix); + return StringFormat("%s%s[%s]%s", _prefix, name, trade REF_DEREF GetSource() PTR_DEREF GetSymbolTf(), _suffix); } /** @@ -358,11 +370,6 @@ class Strategy : public Taskable { Dict *GetDataF() { return &fdata; } Dict *GetDataI() { return &idata; } - /** - * Get strategy's trade instance. - */ - Trade *GetTrade() { return GetPointer(trade); } - /* Statistics */ /** @@ -436,7 +443,7 @@ class Strategy : public Taskable { */ template void Set(ENUM_TRADE_PARAM _param, T _value) { - trade.Set(_param, _value); + trade REF_DEREF Set(_param, _value); } /** @@ -480,8 +487,8 @@ class Strategy : public Taskable { /** * Sets reference to indicator. */ - void SetIndicator(IndicatorBase *_indi, int _id = 0) { - Ref _ref = _indi; + void SetIndicator(IndicatorData *_indi, int _id = 0) { + Ref _ref = _indi; indicators.Set(_id, _ref); } @@ -547,14 +554,10 @@ class Strategy : public Taskable { datetime _order_datetime; for (i = 0; i < Trade::OrdersTotal(); i++) { // @todo: Select order. - if (GetMarket().GetSymbol() == Order::OrderSymbol() && trade.tparams.GetMagicNo() == Order::OrderMagicNumber()) { - _total++; - _order_profit = Order::OrderProfit() - Order::OrderCommission() - Order::OrderSwap(); - _net_profit += _order_profit; - if (Order::OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { - _open++; - } else { - _order_datetime = (datetime)OrderGetInteger(ORDER_TIME_DONE); + if (GetMarket().GetSymbol() == Order::OrderSymbol() && trade REF_DEREF tparams.GetMagicNo() == + Order::OrderMagicNumber()) { _total++; _order_profit = Order::OrderProfit() - Order::OrderCommission() - + Order::OrderSwap(); _net_profit += _order_profit; if (Order::OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { _open++; } + else { _order_datetime = (datetime)OrderGetInteger(ORDER_TIME_DONE); // s_daily_net_profit += @todo; // s_weekly_net_profit += @todo; // s_monhtly_net_profit += @todo; @@ -591,7 +594,7 @@ class Strategy : public Taskable { /** * Get current spread (in pips). */ - // double GetCurrSpread() { return trade.chart.GetSpreadInPips(); } + // double GetCurrSpread() { return trade REF_DEREF chart.GetSpreadInPips(); } /** * Convert timeframe constant to index value. @@ -634,10 +637,10 @@ class Strategy : public Taskable { * Initialize strategy. */ bool Init() { - if (!trade.IsValid()) { + if (!trade REF_DEREF IsValid()) { /* @fixme logger.Warning(StringFormat("Could not initialize %s on %s timeframe!", GetName(), - trade.GetChart().TfToString()), + trade REF_DEREF GetSource() PTR_DEREF TfToString()), __FUNCTION__ + ": "); */ return false; @@ -650,7 +653,7 @@ class Strategy : public Taskable { /** * Prints strategy's details. */ - string const ToString() { return StringFormat("%s: %s", GetName(), sparams.ToString()); } + string const ToString() override { return StringFormat("%s: %s", GetName(), sparams.ToString()); } /* Virtual methods */ @@ -664,19 +667,19 @@ class Strategy : public Taskable { */ virtual void OnInit() { // Link log instances. - logger.Link(trade.GetLogger()); - trade.GetLogger().SetLevel(sparams.Get(STRAT_PARAM_LOG_LEVEL)); + logger.Link(trade.Ptr().GetLogger()); + trade.Ptr().GetLogger().SetLevel(sparams.Get(STRAT_PARAM_LOG_LEVEL)); // Sets strategy stops. SetStops(THIS_PTR, THIS_PTR); // trade.SetStrategy(&this); // @fixme // Sets strategy's trade spread limit. - trade.Set(TRADE_PARAM_MAX_SPREAD, sparams.Get(STRAT_PARAM_MAX_SPREAD)); + trade.Ptr().Set(TRADE_PARAM_MAX_SPREAD, sparams.Get(STRAT_PARAM_MAX_SPREAD)); // Load active trades. if (Get(STRAT_PARAM_ID) > 0) { - trade.OrdersLoadByMagic(Get(STRAT_PARAM_ID)); + trade.Ptr().OrdersLoadByMagic(Get(STRAT_PARAM_ID)); } Ref _order; - for (DictStructIterator> iter = trade.GetOrdersActive().Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator> iter = trade.Ptr().GetOrdersActive().Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); if (_order.IsSet() && _order.Ptr().IsOpen()) { Strategy::OnOrderLoad(_order.Ptr()); @@ -714,6 +717,8 @@ class Strategy : public Taskable { _index++; } _order.Set(ORDER_PARAM_UPDATE_FREQ, _stf_secs); + SetStops(GetPointer(this), GetPointer(this)); + // trade REF_DEREF SetStrategy(&this); // @fixme } /** @@ -723,8 +728,14 @@ class Strategy : public Taskable { * _oparams Order parameters to update before the open. */ virtual void OnOrderOpen(OrderParams &_oparams) { + if (!GetSource() PTR_DEREF HasCandleInHierarchy()) { + Print("In order this method to work, you have to pass Candle-featured indicator as source!"); + DebugBreak(); + return; + } + int _index = 0; - ENUM_TIMEFRAMES _stf = Get(STRAT_PARAM_TF); + ENUM_TIMEFRAMES _stf = GetSource() PTR_DEREF GetTf(); unsigned int _stf_secs = ChartTf::TfToSeconds(_stf); if (sparams.order_close_time != 0) { long _close_time_arg = sparams.order_close_time > 0 ? sparams.order_close_time * 60 @@ -799,6 +810,12 @@ class Strategy : public Taskable { * Returns true when tick should be processed, otherwise false. */ virtual bool TickFilter(const MqlTick &_tick, const int _method) { + if (!GetSource() PTR_DEREF HasCandleInHierarchy()) { + Print("In order this method to work you have to pass Candle-featured indicator as source!"); + DebugBreak(); + return false; + } + bool _res = _method >= 0; bool _val; int _method_abs = fabs(_method); @@ -811,7 +828,8 @@ class Strategy : public Taskable { } if (METHOD(_method_abs, 1)) { // 2 // Process low and high ticks of a bar. - _val = _tick.bid >= trade.GetChart().GetHigh() || _tick.bid <= trade.GetChart().GetLow(); + _val = _tick.bid >= trade REF_DEREF GetSource() PTR_DEREF GetHigh() || + _tick.bid <= trade REF_DEREF GetSource() PTR_DEREF GetLow(); _res = _method > 0 ? _res & _val : _res | _val; } if (METHOD(_method_abs, 2)) { // 4 @@ -835,18 +853,18 @@ class Strategy : public Taskable { } if (METHOD(_method_abs, 4)) { // 16 // Process ticks in the middle of the bar. - _val = (trade.GetChart().GetBarTime() + - (ChartTf::TfToSeconds(trade.Get(CHART_PARAM_TF)) / 2)) == TimeCurrent(); + _val = (trade REF_DEREF GetSource() PTR_DEREF GetBarTime() + + (ChartTf::TfToSeconds(trade REF_DEREF GetSource() PTR_DEREF GetTf()) / 2)) == TimeCurrent(); _res = _method > 0 ? _res & _val : _res | _val; } if (METHOD(_method_abs, 5)) { // 32 // Process bar open price ticks. - _val = last_tick.time < trade.GetChart().GetBarTime(); // @todo: Improve performance. + _val = last_tick.time < trade REF_DEREF GetSource() PTR_DEREF GetBarTime(); // @todo: Improve performance. _res = _method > 0 ? _res & _val : _res | _val; } if (METHOD(_method_abs, 6)) { // 64 // Process every 10th of the bar. - _val = TimeCurrent() % (int)(ChartTf::TfToSeconds(trade.Get(CHART_PARAM_TF)) / 10) == 0; + _val = TimeCurrent() % (int)(ChartTf::TfToSeconds(trade REF_DEREF GetSource() PTR_DEREF GetTf()) / 10) == 0; _res = _method > 0 ? _res & _val : _res | _val; } if (METHOD(_method_abs, 7)) { // 128 @@ -908,15 +926,20 @@ class Strategy : public Taskable { bool _result = true; if (_method != 0) { int _shift = _method / 64; - if (METHOD(_method, 0)) _result &= !trade.HasBarOrder(_cmd, _shift); // 1 - if (METHOD(_method, 1)) _result &= IsTrend(_cmd); // 2 - if (METHOD(_method, 2)) _result &= trade.IsPivot(_cmd, _shift); // 4 - if (METHOD(_method, 3)) _result &= !trade.HasOrderOppositeType(_cmd); // 8 - if (METHOD(_method, 4)) _result &= trade.IsPeak(_cmd, _shift); // 16 - if (METHOD(_method, 5)) _result &= !trade.HasOrderBetter(_cmd); // 32 - if (METHOD(_method, 6)) _result &= trade.CalcActiveProfitInValue() <= 0.0f; // 64 - // if (METHOD(_method, 5)) _result &= Trade().IsRoundNumber(_cmd); - // if (METHOD(_method, 6)) _result &= Trade().IsHedging(_cmd); + if (METHOD(_method, 0)) _result &= !trade REF_DEREF HasBarOrder(_cmd, _shift); // 1 + if (METHOD(_method, 1)) _result &= IsTrend(_cmd); // 2 + if (METHOD(_method, 2)) _result &= trade REF_DEREF IsPivot(_cmd, _shift); // 4 + if (METHOD(_method, 3)) _result &= !trade REF_DEREF HasOrderOppositeType(_cmd); // 8 + if (METHOD(_method, 4)) _result &= trade REF_DEREF IsPeak(_cmd, _shift); // 16 + if (METHOD(_method, 5)) _result &= !trade REF_DEREF HasOrderBetter(_cmd); // 32 + if (METHOD(_method, 6)) _result &= trade REF_DEREF CalcActiveProfitInValue() <= 0.0f; // 64 + /* + if (METHOD(_method, 6)) + _result &= !trade REF_DEREF Check( + TRADE_COND_ACCOUNT, _method > 0 ? ACCOUNT_COND_EQUITY_01PC_LOW : ACCOUNT_COND_EQUITY_01PC_HIGH); // 64 + */ + // if (METHOD(_method, 5)) _result &= Trade() REF_DEREF IsRoundNumber(_cmd); + // if (METHOD(_method, 6)) _result &= Trade() REF_DEREF IsHedging(_cmd); _method = _method > 0 ? _method : !_method; } return _result; @@ -979,17 +1002,23 @@ class Strategy : public Taskable { if (METHOD(_method, 0)) if (IsTrend(_cmd)) _result *= 1.1f; if (METHOD(_method, 1)) - if (trade.GetTrendOp(18, _stf)) _result *= 1.1f; + if (trade.Ptr().GetTrendOp(18, _stf)) _result *= 1.1f; if (METHOD(_method, 2)) - if (!trade.HasOrderBetter(_cmd)) _result *= 1.1f; + if (!trade.Ptr().HasOrderBetter(_cmd)) _result *= 1.1f; if (METHOD(_method, 3)) - if (trade.IsPeak(_cmd, _shift)) _result *= 1.1f; + if (trade.Ptr().IsPeak(_cmd, _shift)) _result *= 1.1f; if (METHOD(_method, 4)) - if (trade.IsPivot(_cmd, _shift)) _result *= 1.1f; + if (trade.Ptr().IsPivot(_cmd, _shift)) _result *= 1.1f; if (METHOD(_method, 5)) - if (trade.HasOrderOppositeType(_cmd)) _result *= 1.1f; + if (trade.Ptr().HasOrderOppositeType(_cmd)) _result *= 1.1f; if (METHOD(_method, 6)) - if (trade.HasBarOrder(_cmd, _shift)) _result *= 1.1f; + if (trade.Ptr().HasBarOrder(_cmd, _shift)) _result *= 1.1f; + // if (METHOD(_method, 0)) if (Trade().IsTrend(_cmd)) _result *= 1.1; + // if (METHOD(_method, 1)) if (Trade().IsPivot(_cmd)) _result *= 1.1; + // if (METHOD(_method, 2)) if (Trade().IsPeakHours(_cmd)) _result *= 1.1; + // if (METHOD(_method, 3)) if (Trade().IsRoundNumber(_cmd)) _result *= 1.1; + // if (METHOD(_method, 4)) if (Trade().IsHedging(_cmd)) _result *= 1.1; + // if (METHOD(_method, 5)) if (Trade().IsPeakBar(_cmd)) _result *= 1.1; // if (METHOD(_method, 7)) if (trade.IsRoundNumber(_cmd)) _result *= 1.1f; // if (METHOD(_method, 8)) if (trade.IsHedging(_cmd)) _result *= 1.1f; // if (METHOD(_method, 9)) if (trade.IsPeakBar(_cmd)) _result *= 1.1f; @@ -1025,14 +1054,27 @@ class Strategy : public Taskable { virtual bool SignalCloseFilter(ENUM_ORDER_TYPE _cmd, int _method = 0, int _shift = 0) { bool _result = _method == 0; if (_method != 0) { - if (METHOD(_method, 0)) _result |= _result || !trade.HasBarOrder(_cmd, _shift); // 1 - if (METHOD(_method, 1)) _result |= _result || !IsTrend(_cmd); // 2 - if (METHOD(_method, 2)) _result |= _result || !trade.IsPivot(_cmd, _shift); // 4 + + if (METHOD(_method, 0)) _result |= _result || !trade REF_DEREF HasBarOrder(_cmd, _shift); // 1 + if (METHOD(_method, 1)) _result |= _result || !IsTrend(_cmd); // 2 + if (METHOD(_method, 2)) _result |= _result || !trade REF_DEREF IsPivot(_cmd, _shift); // 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.IsPeak(_cmd, _shift); // 16 - if (METHOD(_method, 5)) _result |= _result || trade.HasOrderBetter(_cmd); // 32 - if (METHOD(_method, 6)) _result |= _result || trade.CalcActiveProfitInValue() > 0.0f; // 64 + if (METHOD(_method, 4)) _result |= _result || trade REF_DEREF IsPeak(_cmd, _shift); // 16 + if (METHOD(_method, 5)) _result |= _result || trade REF_DEREF HasOrderBetter(_cmd); // 32 + if (METHOD(_method, 6)) _result |= _result || trade REF_DEREF CalcActiveProfitInValue() > 0.0f; // 64 + /* + if (METHOD(_method, 6)) + _result |= + _result || trade.Check(TRADE_COND_ACCOUNT, _method > 0 ? ACCOUNT_COND_EQUITY_01PC_HIGH + : ACCOUNT_COND_EQUITY_01PC_LOW); // 64 + */ + /* + if (METHOD(_method, 6)) + _result |= + _result || trade REF_DEREF Check(TRADE_COND_ACCOUNT, _method > 0 ? ACCOUNT_COND_EQUITY_01PC_HIGH + : ACCOUNT_COND_EQUITY_01PC_LOW); // 64 + */ // if (METHOD(_method, 7)) _result |= _result || Trade().IsRoundNumber(_cmd); // if (METHOD(_method, 8)) _result |= _result || Trade().IsHedging(_cmd); _method = _method > 0 ? _method : !_method; @@ -1060,18 +1102,20 @@ class Strategy : public Taskable { // Ignores calculation when method is 0. return (float)_result; } - float _trade_dist = trade.GetTradeDistanceInValue(); + float _trade_dist = trade REF_DEREF GetTradeDistanceInValue(); int _count = (int)fmax(fabs(_level), fabs(_method)); int _direction = Order::OrderDirection(_cmd, _mode); - Chart *_chart = trade.GetChart(); + IndicatorData *_data_source = trade REF_DEREF GetSource(); IndicatorData *_indi = GetIndicators().Begin().Value().Ptr(); StrategyPriceStop _psm(_method); - _psm.SetChartParams(_chart.GetParams()); + _psm.SetCandleSource(_data_source); if (Object::IsValid(_indi)) { int _ishift = 12; // @todo: Make it dynamic or as variable. - float _value = _indi.GetValuePrice(_ishift, 0, _direction > 0 ? PRICE_HIGH : PRICE_LOW); - _value = _value + (float)Math::ChangeByPct(fabs(_value - _chart.GetCloseOffer(0)), _level) * _direction; - _psm.SetIndicatorPriceValue(_value); + double _value = _indi.GetValuePrice(_ishift, 0, _direction > 0 ? PRICE_HIGH : PRICE_LOW); + _value = + _value + + (float)Math::ChangeByPct(fabs(_value - SymbolInfoStatic::GetCloseOffer(_Symbol, _cmd)), _level) * _direction; + _psm.SetIndicatorPriceValue((float)_value); /* //IndicatorDataEntry _data[]; if (_indi.CopyEntries(_data, 3, 0)) { @@ -1081,7 +1125,7 @@ class Strategy : public Taskable { */ _result = _psm.GetValue(_ishift, _direction, _trade_dist); } else { - int _pshift = _direction > 0 ? _chart.GetHighest(_count) : _chart.GetLowest(_count); + int _pshift = _direction > 0 ? _data_source.GetHighest(_count) : _data_source.GetLowest(_count); _result = _psm.GetValue(_pshift, _direction, _trade_dist); } return (float)_result; @@ -1099,16 +1143,19 @@ class Strategy : public Taskable { */ virtual float TrendStrength(ENUM_TIMEFRAMES _tf = PERIOD_D1, int _shift = 1) { float _result = 0; - Chart *_c = trade.GetChart(); - if (_c.IsValidShift(_shift)) { - ChartEntry _bar1 = _c.GetEntry(_tf, _shift); - float _range = _bar1.bar.ohlc.GetRange(); - if (_range > 0) { - float _open = (float)_c.GetOpen(_tf); - float _pp = _bar1.bar.ohlc.GetPivot(); - _result = 1 / _range * (_open - _pp); - _result = fmin(1, fmax(-1, _result)); - } + IndicatorData *_data_source = trade REF_DEREF GetSource(); + + BarOHLC _bar1 = _data_source.GetOHLC(_shift); + if (!_bar1.IsValid()) { + return 0; + } + + float _range = (float)_bar1.GetRange(); + if (_range > 0) { + float _open = (float)_data_source.GetOpen(_tf); + float _pp = (float)_bar1.GetPivot(); + _result = 1 / _range * (_open - _pp); + _result = fmin(1, fmax(-1, _result)); } return _result; }; diff --git a/Strategy.struct.h b/Strategy.struct.h index 693733d88..f3a5b5e04 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -199,8 +199,6 @@ struct StgParams { return (T)price_profit_method; case STRAT_PARAM_PSM: return (T)price_stop_method; - case STRAT_PARAM_TF: - return (T)tf.GetTf(); case STRAT_PARAM_TFM: return (T)tick_filter_method; case STRAT_PARAM_TYPE: @@ -287,10 +285,6 @@ struct StgParams { case STRAT_PARAM_PSM: // Price stop method price_stop_method = (int)_value; return; - case STRAT_PARAM_TF: - // Main timeframe where strategy operates on. - tf = (ENUM_TIMEFRAMES)_value; - return; case STRAT_PARAM_TFM: // Tick filter method tick_filter_method = (int)_value; return; diff --git a/Strategy.struct.pricestop.h b/Strategy.struct.pricestop.h index 3bf94364c..de4e55118 100644 --- a/Strategy.struct.pricestop.h +++ b/Strategy.struct.pricestop.h @@ -55,7 +55,7 @@ struct StrategyPriceStop { float ivalue; // Indicator price value. unsigned int method; // Store price stop methods (@see: ENUM_STRATEGY_PRICE_STOP). // unsigned int mode[2]; // Indicator modes to use. - ChartParams cparams; + Ref indi_candle; // IndicatorDataEntry idata[]; // IndicatorParams iparams; @@ -64,9 +64,9 @@ struct StrategyPriceStop { // Main methods. // Calculate price stop value. float GetValue(int _shift = 0, int _direction = -1, float _min_trade_dist = 0.0f) { - float _result = ivalue, _trail = _min_trade_dist; - BarOHLC _ohlc0 = Chart::GetOHLC(cparams.tf.GetTf(), 0, cparams.symbol); - BarOHLC _ohlc1 = Chart::GetOHLC(cparams.tf.GetTf(), _shift, cparams.symbol); + double _result = ivalue, _trail = _min_trade_dist; + BarOHLC _ohlc0 = GetCandleSource() PTR_DEREF GetOHLC(0); + BarOHLC _ohlc1 = GetCandleSource() PTR_DEREF GetOHLC(_shift); if (CheckMethod(STRATEGY_PRICE_STOP_INDI_PRICE)) { _result = ivalue; } @@ -78,12 +78,12 @@ struct StrategyPriceStop { // On peak, use low or high prices instead. _ap = _direction > 0 ? PRICE_HIGH : PRICE_LOW; } - _price = (float)ChartStatic::iPrice(_ap, cparams.symbol, cparams.tf.GetTf(), _shift); + _price = (float)GetCandleSource() PTR_DEREF GetPrice(_ap, _shift); _result = _direction > 0 ? fmax(_price, _result) : fmin(_price, _result); } if (CheckMethod(STRATEGY_PRICE_STOP_PRICE_PP)) { - float _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4; - float _prices[4]; + double _pp, _r1, _r2, _r3, _r4, _s1, _s2, _s3, _s4; + double _prices[4]; _prices[0] = _ohlc0.GetClose(); _prices[1] = _direction > 0 ? _ohlc0.GetHigh() : _ohlc0.GetLow(); _prices[2] = _direction > 0 ? _ohlc1.GetHigh() : _ohlc1.GetLow(); @@ -99,10 +99,10 @@ struct StrategyPriceStop { _trail += _ohlc1.GetRange(); } _result = _result > 0 ? (_direction > 0 ? _result + _trail : _result - _trail) : 0; - return _result; + return (float)_result; } /* Setters */ - void SetChartParams(ChartParams &_cparams) { cparams = _cparams; } + void SetCandleSource(IndicatorBase* _indi_candle) { indi_candle = _indi_candle; } void SetIndicatorPriceValue(float _ivalue) { ivalue = _ivalue; } /* void SetIndicatorDataEntry(IndicatorDataEntry &_data[]) { @@ -117,6 +117,9 @@ struct StrategyPriceStop { mode[1] = _m2; } */ + /* Getters */ + IndicatorData* GetCandleSource() { return indi_candle.Ptr(); } + /* Flag getters */ bool CheckMethod(unsigned int _flags) { return (method & _flags) != 0; } bool CheckMethodsXor(unsigned int _flags) { return (method ^ _flags) != 0; } @@ -135,7 +138,7 @@ struct StrategyPriceStop { } void SetMethod(unsigned int _flags) { method = _flags; } /* Serializers */ - SerializerNodeType Serialize(Serializer &_s) { + SerializerNodeType Serialize(Serializer& _s) { int _size = sizeof(int) * 8; for (int i = 0; i < _size; i++) { int _value = CheckMethod(1 << i) ? 1 : 0; diff --git a/SummaryReport.mqh b/SummaryReport.mqh index a2deb6b37..5a448aa38 100644 --- a/SummaryReport.mqh +++ b/SummaryReport.mqh @@ -30,9 +30,7 @@ * Class to provide a summary report. */ class SummaryReport { - protected: - // Variables. double init_deposit; double summary_profit; @@ -69,20 +67,15 @@ class SummaryReport { double init_balance; public: - /** * Default constructor. */ - SummaryReport() { - InitVars(AccountMt::AccountBalance()); - } + SummaryReport() { InitVars(AccountMt::AccountBalance()); } /** * Constructor to initialize starting balance. */ - SummaryReport(double deposit) { - InitVars(deposit); - } + SummaryReport(double deposit) { InitVars(deposit); } /** * Constructor to initialize starting balance. @@ -128,8 +121,7 @@ class SummaryReport { static double deposit = 0; if (deposit > 0) { return deposit; - } - else if (!Terminal::IsRealtime() && init_deposit > 0) { + } else if (!Terminal::IsRealtime() && init_deposit > 0) { deposit = init_deposit; } else { deposit = AccountMt::CalcInitDeposit(); @@ -187,8 +179,7 @@ class SummaryReport { summary_trades++; if (type == ORDER_TYPE_BUY) { long_trades++; - } - else if (type == ORDER_TYPE_SELL) { + } else if (type == ORDER_TYPE_SELL) { short_trades++; } if (profit < 0) { @@ -198,13 +189,11 @@ class SummaryReport { 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)) { + 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)) { + if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { con_profit2 = sequential; con_profit_trades2 = sequence; } @@ -222,13 +211,11 @@ class SummaryReport { 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)) { + 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; } @@ -259,27 +246,22 @@ class SummaryReport { if (prev_profit != EMPTY_VALUE) { profit = prev_profit; if (profit < 0) { - if (con_loss_trades1 < sequence || - (con_loss_trades1 == sequence && con_loss2 > sequential)) { + 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; - } - else { - if (con_profit_trades1 < sequence || - (con_profit_trades1 == sequence && con_profit2 < sequential)) { + } else { + 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)) { + if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { con_profit2 = sequential; con_profit_trades2 = sequence; } @@ -324,24 +306,42 @@ class SummaryReport { 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("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("Short positions (won %%): %d (%.1f%%)", short_trades, short_trades ? 100.0 * win_short_trades / short_trades : 0) + sep; - output += StringFormat("Long positions (won %%): %d (%.1f%%)", long_trades, long_trades ? 100.0 * win_long_trades / long_trades : 0) + sep; - output += StringFormat("Profit trades (%% of total): %d (%.1f%%)", profit_trades, profit_trades ? 100.0 * profit_trades / summary_trades : 0) + sep; - output += StringFormat("Loss trades (%% of total): %d (%.1f%%)", loss_trades, loss_trades ? 100.0 * loss_trades / summary_trades : 0) + sep; + output += StringFormat("Short positions (won %%): %d (%.1f%%)", short_trades, + short_trades ? 100.0 * win_short_trades / short_trades : 0) + + sep; + output += StringFormat("Long positions (won %%): %d (%.1f%%)", long_trades, + long_trades ? 100.0 * win_long_trades / long_trades : 0) + + sep; + output += StringFormat("Profit trades (%% of total): %d (%.1f%%)", profit_trades, + profit_trades ? 100.0 * profit_trades / summary_trades : 0) + + sep; + 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("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 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("Maximum consecutive wins (profit in money): %d (%.2f)", con_profit_trades1, con_profit1) + 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("Maximal consecutive profit (count of wins): %.2f (%d)", con_profit2, con_profit_trades2) + 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; } diff --git a/SymbolInfo.mqh b/SymbolInfo.mqh index bbe6b78b8..d53c2fd47 100644 --- a/SymbolInfo.mqh +++ b/SymbolInfo.mqh @@ -408,7 +408,7 @@ class SymbolInfo : public Object { * * @see: https://book.mql4.com/appendix/limits */ - unsigned int GetFreezeLevel() { return SymbolInfoStatic::GetFreezeLevel(symbol); } + int GetFreezeLevel() { return SymbolInfoStatic::GetFreezeLevel(symbol); } /** * Gets flags of allowed order filling modes. @@ -518,7 +518,7 @@ class SymbolInfo : public Object { /** * Returns symbol information in string format. */ - const string ToString() { + string const ToString() override { return StringFormat( string("Symbol: %s, Last Ask/Bid: %g/%g, Last Price/Session Volume: %d/%g, Point size: %g, Pip size: %g, ") + "Tick size: %g (%g pts), Tick value: %g (%g/%g), " + "Digits: %d, Spread: %d pts, Trade stops level: %d, " + diff --git a/SymbolInfo.struct.h b/SymbolInfo.struct.h index 72cc8e8d4..5e1096ad3 100644 --- a/SymbolInfo.struct.h +++ b/SymbolInfo.struct.h @@ -71,13 +71,82 @@ struct SymbolInfoEntry // Defines structure for SymbolInfo properties. struct SymbolInfoProp { + bool initialized; double pip_value; // Pip value. + unsigned int digits; // Currency digits? @fixit unsigned int pip_digits; // Pip digits (precision). unsigned int pts_per_pip; // Points per pip. unsigned int vol_digits; // Volume digits. + double vol_min; // Minimum volume for a deal. + double vol_max; // Maximum volume for a deal. + double vol_step; // Minimal volume change step for deal execution. + double point_size; // Symbol point value. + double tick_size; // Minimal price change. + double tick_value; // Calculated tick price for a profitable position. + double swap_long; // Swap of the buy order. + double swap_short; // Swap of the sell order. + double margin_initial; // Initial margin means the amount in the margin currency required for opening an order with + // the volume of one lot. + double margin_maintenance; // If it is set, it sets the margin amount in the margin currency of the symbol, charged + // from one lot. + int freeze_level; // Distance to freeze trade operations in points. + // Constructors. - SymbolInfoProp() {} - SymbolInfoProp(const SymbolInfoProp& _sip) {} + SymbolInfoProp() : initialized(false) {} + SymbolInfoProp(const SymbolInfoProp& _sip) { + initialized = _sip.initialized; + pip_value = _sip.pip_value; + digits = _sip.digits; + pip_digits = _sip.pip_digits; + pts_per_pip = _sip.pts_per_pip; + vol_digits = _sip.vol_digits; + vol_min = _sip.vol_min; + vol_max = _sip.vol_max; + vol_step = _sip.vol_step; + point_size = _sip.point_size; + tick_size = _sip.tick_size; + tick_value = _sip.tick_value; + swap_long = _sip.swap_long; + swap_short = _sip.swap_short; + margin_initial = _sip.margin_initial; + margin_maintenance = _sip.margin_maintenance; + freeze_level = _sip.freeze_level; + } + // Getters. + double GetPipValue() { return pip_value; } + unsigned int GetDigits() { return digits; } + unsigned int GetPipDigits() { return pip_digits; } + unsigned int GetPointsPerPip() { return pts_per_pip; } + unsigned int GetVolumeDigits() { return vol_digits; } + double GetVolumeMin() { return vol_min; } + double GetVolumeMax() { return vol_max; } + double GetVolumeStep() { return vol_step; } + double GetPointSize() { return point_size; } + double GetTickSize() { return tick_size; } + double GetTickValue() { return tick_value; } + double GetSwapLong() { return swap_long; } + double GetSwapShort() { return swap_short; } + double GetMarginInit() { return margin_initial; } + double GetMarginMaintenance() { return margin_maintenance; } + int GetFreezeLevel() { return freeze_level; } + + /** + * Normalize price value. + * + * Make sure that the price is a multiple of ticksize. + */ + double NormalizePrice(double p) { + // See: http://forum.mql4.com/47988 + // http://forum.mql4.com/43064#515262 zzuegg reports for non-currency DE30: + // - MarketInfo(chart.symbol,MODE_TICKSIZE) returns 0.5 + // - MarketInfo(chart.symbol,MODE_DIGITS) return 1 + // - Point = 0.1 + // Rare fix when a change in tick size leads to a change in tick value. + double _result = round(p / GetPointSize()) * GetTickSize(); + _result = NormalizeDouble(_result, GetDigits()); + return _result; + } + // Serializers. void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} SerializerNodeType Serialize(Serializer& _s); @@ -99,5 +168,16 @@ SerializerNodeType SymbolInfoProp::Serialize(Serializer& _s) { _s.Pass(THIS_REF, "pip_digits", pip_digits); _s.Pass(THIS_REF, "pts_per_pip", pts_per_pip); _s.Pass(THIS_REF, "vol_digits", vol_digits); + _s.Pass(THIS_REF, "vol_min", vol_min); + _s.Pass(THIS_REF, "vol_max", vol_max); + _s.Pass(THIS_REF, "vol_step", vol_step); + _s.Pass(THIS_REF, "point_size", point_size); + _s.Pass(THIS_REF, "tick_size", tick_size); + _s.Pass(THIS_REF, "tick_value", tick_value); + _s.Pass(THIS_REF, "swap_long", swap_long); + _s.Pass(THIS_REF, "swap_short", swap_short); + _s.Pass(THIS_REF, "margin_initial", margin_initial); + _s.Pass(THIS_REF, "margin_maintenance", margin_maintenance); + _s.Pass(THIS_REF, "freeze_level", freeze_level); return SerializerNodeObject; } diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index b689d055b..4aba73a3c 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -363,8 +363,8 @@ struct SymbolInfoStatic { * * @see: https://book.mql4.com/appendix/limits */ - static unsigned int GetFreezeLevel(string _symbol) { - return (unsigned int)SymbolInfoStatic::SymbolInfoInteger( + static int GetFreezeLevel(string _symbol) { + return (int)SymbolInfoStatic::SymbolInfoInteger( _symbol, SYMBOL_TRADE_FREEZE_LEVEL); // Same as: MarketInfo(symbol, MODE_FREEZELEVEL); } diff --git a/Test.mqh b/Test.mqh index 19fc67e75..9869a50ed 100644 --- a/Test.mqh +++ b/Test.mqh @@ -39,6 +39,13 @@ return (INIT_FAILED); \ } +#define assertEqualOrReturn(current, expected, msg, ret) \ + if ((current) != (expected)) { \ + Alert(msg + " - Assert fail. Expected ", expected, ", but got ", current, \ + " in " + __FILE__ + ":" + (string)__LINE__); \ + return (ret); \ + } + #define assertFalseOrFail(cond, msg) \ if ((cond)) { \ Alert(msg + " - Assert fail on " + #cond + " in " + __FILE__ + ":" + (string)__LINE__); \ diff --git a/Tests.mqh b/Tests.mqh index 95ec460f0..3823fb496 100644 --- a/Tests.mqh +++ b/Tests.mqh @@ -37,6 +37,7 @@ class Tests { double _bands[3] = {}; int _periods[5] = {1, 5, 15, 30, 60}; int _modes[3] = {BAND_LOWER, BAND_BASE, BAND_UPPER}; + /* @fixme Chart *_chart = new Chart(_tf, _symbol); unsigned int _digits = _chart.GetDigits(); double _bid = _chart.GetBid(); @@ -51,6 +52,7 @@ class Tests { PrintFormat("Bid/Ask : %g/%g", NormalizeDouble(_bid, _digits), NormalizeDouble(_ask, _digits)); PrintFormat("Close/Open : %g/%g", NormalizeDouble(_close, _digits), NormalizeDouble(_open, _digits)); } + */ for (int p = 0; p < ArraySize(_periods); p++) { for (int m = 0; m < ArraySize(_modes); m++) { #ifdef __MQL4__ diff --git a/Timer.mqh b/Timer.mqh index ba3d069b8..de6890f0d 100644 --- a/Timer.mqh +++ b/Timer.mqh @@ -132,7 +132,7 @@ class Timer : public Object { /** * Print timer times. */ - virtual const string ToString() { + string const ToString() override { return StringFormat("%s(%d)=%d-%dms,med=%dms,sum=%dms", GetName(), ArraySize(this PTR_DEREF data), GetMin(), GetMax(), GetMedian(), GetSum()); } diff --git a/Trade.mqh b/Trade.mqh index f6d77c861..151063147 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -34,12 +34,11 @@ class Trade; #include "Chart.mqh" #include "Convert.mqh" #include "DictStruct.mqh" +#include "IndicatorData.mqh" #include "Math.h" #include "Object.mqh" #include "Order.mqh" #include "OrderQuery.h" -#include "Task/TaskAction.enum.h" -#include "Task/TaskCondition.enum.h" #include "Task/TaskManager.h" #include "Task/Taskable.h" #include "Trade.enum.h" @@ -48,7 +47,7 @@ class Trade; class Trade : public Taskable { public: AccountMt account; - Ref chart; + Ref indi_candle; DictStruct> orders_active; DictStruct> orders_history; DictStruct> orders_pending; @@ -67,9 +66,6 @@ class Trade : public Taskable { * Initialize class instance. */ void Init() { - if (!chart.IsSet()) { - chart = new Chart(PERIOD_CURRENT, _Symbol); - } SetName(); if (tparams.magic_no > 0) { OrdersLoadByMagic(tparams.magic_no); @@ -81,14 +77,22 @@ class Trade : public Taskable { /** * Class constructor. */ - Trade() : order_last(NULL) { Init(); }; - Trade(TradeParams &_tparams, ChartParams &_cparams) - : chart(new Chart(_cparams)), tparams(_tparams), order_last(NULL) { + Trade(IndicatorBase *_indi_candle) : indi_candle(_indi_candle), order_last(NULL) { + SetName(); + OrdersLoadByMagic(tparams.magic_no); + }; + Trade(TradeParams &_tparams, IndicatorBase *_indi_candle) + : indi_candle(_indi_candle), tparams(_tparams), order_last(NULL) { Init(); }; /** - * Class copy constructor. + * Default constructor. + */ + Trade() {} + + /** + * Copy constructor. */ Trade(const Trade &_trade) { // logger = _trade.GetLogger(); @@ -135,7 +139,7 @@ class Trade : public Taskable { */ template T Get(ENUM_CHART_PARAM _param) { - return GetChart().Get(_param); + return GetSource() PTR_DEREF Get(_param); } /** @@ -209,15 +213,29 @@ class Trade : public Taskable { _request.comment = _comment; _request.deviation = tparams.Get(TRADE_PARAM_SLIPPAGE); // The maximal price deviation, specified in points. _request.magic = _magic > 0 ? _magic : tparams.Get(TRADE_PARAM_MAGIC_NO); - _request.symbol = GetChart().Get(CHART_PARAM_SYMBOL); - _request.price = SymbolInfoStatic::GetOpenOffer(_request.symbol, _type); + _request.symbol = GetSource() PTR_DEREF GetSymbol(); + _request.price = GetSource() PTR_DEREF GetOpenOffer(_type); _request.type = _type; #ifndef __MQL4__ // Filling modes not supported under MQL4. _request.type_filling = Order::GetOrderFilling(_request.symbol); #endif _request.volume = _volume > 0 ? _volume : tparams.Get(TRADE_PARAM_LOT_SIZE); - _request.volume = NormalizeLots(fmax(_request.volume, SymbolInfoStatic::GetVolumeMin(_request.symbol))); + _request.volume = NormalizeLots(fmax(_request.volume, GetSource() PTR_DEREF GetSymbolProps().GetVolumeMin())); + +#ifdef __debug__ + MqlTick _tick; // Structure to get the latest prices. + SymbolInfoTick(GetSource() PTR_DEREF GetSymbol(), _tick); + + Print("------------------------"); + Print("C Price: ", GetSource() PTR_DEREF GetOpenOffer(_type)); + Print("C Ask: ", GetSource() PTR_DEREF GetTick() PTR_DEREF GetAsk()); + Print("C Bid: ", GetSource() PTR_DEREF GetTick() PTR_DEREF GetBid()); + + Print("R Ask: ", _tick.ask); + Print("R Bid: ", _tick.bid); +#endif + return _request; } @@ -235,8 +253,7 @@ class Trade : public Taskable { * Sets default name of trade instance. */ void SetName() { - name = StringFormat("%s@%s", GetChart().Get(CHART_PARAM_SYMBOL), - ChartTf::TfToString(GetChart().Get(CHART_PARAM_TF))); + name = StringFormat("%s@%s", GetSource() PTR_DEREF GetSymbol(), ChartTf::TfToString(GetSource() PTR_DEREF GetTf())); } /** @@ -253,9 +270,9 @@ class Trade : public Taskable { */ bool IsPeak(ENUM_ORDER_TYPE _cmd, int _shift = 0) { bool _result = false; - double _high = GetChart().GetHigh(_shift + 1); - double _low = GetChart().GetLow(_shift + 1); - double _open = GetChart().GetOpenOffer(_cmd); + double _high = GetSource() PTR_DEREF GetHigh(_shift + 1); + double _low = GetSource() PTR_DEREF GetLow(_shift + 1); + double _open = GetSource() PTR_DEREF GetOpenOffer(_cmd); if (_low != _high) { switch (_cmd) { case ORDER_TYPE_BUY: @@ -274,17 +291,17 @@ class Trade : public Taskable { */ bool IsPivot(ENUM_ORDER_TYPE _cmd, int _shift = 0) { bool _result = false; - double _high = GetChart().GetHigh(_shift + 1); - double _low = GetChart().GetLow(_shift + 1); - double _close = GetChart().GetClose(_shift + 1); + double _high = GetSource() PTR_DEREF GetHigh(_shift + 1); + double _low = GetSource() PTR_DEREF GetLow(_shift + 1); + double _close = GetSource() PTR_DEREF GetClose(_shift + 1); if (_close > 0 && _low != _high) { float _pp = (float)(_high + _low + _close) / 3; switch (_cmd) { case ORDER_TYPE_BUY: - _result = GetChart().GetOpenOffer(_cmd) > _pp; + _result = GetSource() PTR_DEREF GetOpenOffer(_cmd) > _pp; break; case ORDER_TYPE_SELL: - _result = GetChart().GetOpenOffer(_cmd) < _pp; + _result = GetSource() PTR_DEREF GetOpenOffer(_cmd) < _pp; break; } } @@ -310,7 +327,7 @@ class Trade : public Taskable { /** * Check if trading instance is valid. */ - bool IsValid() { return GetChart().IsValidTf(); } + bool IsValid() { return GetSource() PTR_DEREF IsValid(); } /** * Check if this trade instance has active orders. @@ -325,7 +342,7 @@ class Trade : public Taskable { Ref _order = order_last; if (_order.IsSet() && _order.Ptr().Get(ORDER_TYPE) == _cmd && - _order.Ptr().Get(ORDER_TIME_SETUP) > GetChart().GetBarTime()) { + _order.Ptr().Get(ORDER_TIME_SETUP) > GetSource() PTR_DEREF GetBarTime()) { _result |= true; } @@ -334,8 +351,8 @@ class Trade : public Taskable { _order = iter.Value(); if (_order.Ptr().Get(ORDER_TYPE) == _cmd) { long _time_opened = _order.Ptr().Get(ORDER_TIME_SETUP); - _result |= _shift > 0 && _time_opened < GetChart().GetBarTime(_shift - 1); - _result |= _time_opened >= GetChart().GetBarTime(_shift); + _result |= _shift > 0 && _time_opened < GetSource() PTR_DEREF GetBarTime(_shift - 1); + _result |= _time_opened >= GetSource() PTR_DEREF GetBarTime(_shift); if (_result) { break; } @@ -352,7 +369,7 @@ class Trade : public Taskable { bool _result = false; Ref _order = order_last; OrderData _odata; - double _price_curr = GetChart().GetOpenOffer(_cmd); + double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); if (_order.IsSet() && _order.Ptr().IsOpen()) { if (_odata.Get(ORDER_TYPE) == _cmd) { @@ -396,7 +413,7 @@ class Trade : public Taskable { bool _result = false; Ref _order = order_last; OrderData _odata; - double _price_curr = GetChart().GetOpenOffer(_cmd); + double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); if (_order.IsSet()) { _result = _odata.Get(ORDER_TYPE) != _cmd; @@ -510,7 +527,7 @@ class Trade : public Taskable { #endif } float GetMarginRequired(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_BUY) { - return (float)GetMarginRequired(GetChart().GetSymbol(), _cmd); + return (float)GetMarginRequired(GetSource() PTR_DEREF GetSymbol(), _cmd); } /* Lot size methods */ @@ -531,11 +548,10 @@ class Trade : public Taskable { double GetMaxLotSize(double _sl, ENUM_ORDER_TYPE _cmd = NULL) { _cmd = _cmd == NULL ? Order::OrderType() : _cmd; double risk_amount = account.GetTotalBalance() / 100 * tparams.risk_margin; - double _ticks = fabs(_sl - GetChart().GetOpenOffer(_cmd)) / GetChart().GetTickSize(); + double _ticks = + fabs(_sl - GetSource() PTR_DEREF GetOpenOffer(_cmd)) / GetSource() PTR_DEREF GetSymbolProps().GetTickSize(); double lot_size1 = fmin(_sl, _ticks) > 0 ? risk_amount / (_sl * (_ticks / 100.0)) : 1; - lot_size1 *= GetChart().GetVolumeMin(); - // double lot_size2 = 1 / (GetChart().GetTickValue() * sl / risk_margin); - // PrintFormat("SL=%g: 1 = %g, 2 = %g", sl, lot_size1, lot_size2); + lot_size1 *= GetSource() PTR_DEREF GetSymbolProps().GetVolumeMin(); return NormalizeLots(lot_size1); } double GetMaxLotSize(unsigned int _pips, ENUM_ORDER_TYPE _cmd = NULL) { @@ -581,7 +597,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. Print(__FUNCTION__, ": Error in history!"); break; } - if (deal.Symbol() != GetChart().GetSymbol()) continue; + if (deal.Symbol() != GetSource() PTR_DEREF GetSymbol()) continue; double profit = deal.Profit(); */ double profit = 0; @@ -624,7 +640,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. unsigned int _method = 0 // Method of calculation (0-3). ) { float _avail_amount = _method % 2 == 0 ? account.GetMarginAvail() : account.GetTotalBalance(); - float _lot_size_min = (float)GetChart().GetVolumeMin(); + float _lot_size_min = (float)GetSource() PTR_DEREF GetSymbolProps().GetVolumeMin(); float _lot_size = _lot_size_min; float _risk_value = (float)account.GetLeverage(); if (_method == 0 || _method == 1) { @@ -635,12 +651,12 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } } else { float _risk_amount = _avail_amount / 100 * _risk_margin; - float _money_value = Convert::MoneyToValue(_risk_amount, _lot_size_min, GetChart().GetSymbol()); - float _tick_value = GetChart().GetTickSize(); + float _money_value = Convert::MoneyToValue(_risk_amount, _lot_size_min, GetSource() PTR_DEREF GetSymbol()); + float _tick_value = (float)GetSource() PTR_DEREF GetSymbolProps().GetTickSize(); // @todo: Improves calculation logic. _lot_size = _money_value * _tick_value * _risk_ratio / _risk_value / 100; } - _lot_size = (float)fmin(_lot_size, GetChart().GetVolumeMax()); + _lot_size = (float)fmin(_lot_size, GetSource() PTR_DEREF GetSymbolProps().GetVolumeMax()); return (float)NormalizeLots(_lot_size); } @@ -1052,7 +1068,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. ) { 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; - float _res = (float)GetChart().NormalizePrice(GetSaferSLTP(_value, _max_value1, _max_value2, _cmd, _mode)); + float _res = (float)GetSource() PTR_DEREF GetSymbolProps().NormalizePrice( + GetSaferSLTP(_value, _max_value1, _max_value2, _cmd, _mode)); // PrintFormat("%s/%s: Value: %g", EnumToString(_cmd), EnumToString(_mode), _value); // PrintFormat("%s/%s: Max value 1: %g", EnumToString(_cmd), EnumToString(_mode), _max_value1); // PrintFormat("%s/%s: Max value 2: %g", EnumToString(_cmd), EnumToString(_mode), _max_value2); @@ -1067,12 +1084,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. ENUM_ORDER_TYPE _cmd, // Order type (e.g. buy or sell). ENUM_ORDER_TYPE_VALUE _mode // Type of value (stop loss or take profit). ) { - double _price = _cmd == NULL ? Order::OrderOpenPrice() : GetChart().GetOpenOffer(_cmd); + 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; - // PrintFormat("#%d: %s/%s: %g (%g/%g) + %g * %g * %g = %g", Order::OrderTicket(), EnumToString(_cmd), - // EnumToString(_mode), _price, Bid, Ask, _value, GetChart().GetPipSize(), Order::OrderDirection(_cmd, _mode), - // GetChart().GetOpenOffer(_cmd) + _value * GetChart().GetPipSize() * Order::OrderDirection(_cmd, _mode)); - return _value > 0 ? float(_price + _value * GetChart().GetPipSize() * Order::OrderDirection(_cmd, _mode)) : 0; + 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); } float CalcOrderTP(float _value, ENUM_ORDER_TYPE _cmd) { return CalcOrderSLTP(_value, _cmd, ORDER_TYPE_TP); } @@ -1091,14 +1106,14 @@ HistorySelect(0, TimeCurrent()); // Select history for access. */ 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() : GetChart().GetOpenOffer(_cmd); + double _price = _cmd == NULL ? 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, - GetChart().GetSymbol()); + GetSource() PTR_DEREF GetSymbol()); _cmd = _cmd == NULL ? Order::OrderType() : _cmd; // @fixme - // _lot_size = _lot_size <= 0 ? fmax(Order::OrderLots(), GetChart().GetVolumeMin()) : _lot_size; + // _lot_size = _lot_size <= 0 ? fmax(Order::OrderLots(), GetSource() PTR_DEREF GetVolumeMin()) : _lot_size; return (float)_price + GetTradeDistanceInValue() // + Convert::MoneyToValue(account.GetTotalBalance() / 100 * _risk_margin, _lot_size) @@ -1181,7 +1196,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. static long GetTradeDistanceInPts(string _symbol) { return fmax(SymbolInfoStatic::GetTradeStopsLevel(_symbol), SymbolInfoStatic::GetFreezeLevel(_symbol)); } - long GetTradeDistanceInPts() { return GetTradeDistanceInPts(GetChart().GetSymbol()); } + long GetTradeDistanceInPts() { return GetTradeDistanceInPts(GetSource() PTR_DEREF GetSymbol()); } /** * Get a market distance in pips. @@ -1194,7 +1209,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. unsigned int _pts_per_pip = SymbolInfoStatic::GetPointsPerPip(_symbol); return (double)(_pts_per_pip > 0 ? (GetTradeDistanceInPts(_symbol) / _pts_per_pip) : 0); } - double GetTradeDistanceInPips() { return GetTradeDistanceInPips(GetChart().GetSymbol()); } + double GetTradeDistanceInPips() { return GetTradeDistanceInPips(GetSource() PTR_DEREF GetSymbol()); } /** * Get a market gap in value. @@ -1206,7 +1221,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. static double GetTradeDistanceInValue(string _symbol) { return Trade::GetTradeDistanceInPts(_symbol) * SymbolInfoStatic::GetPointSize(_symbol); } - float GetTradeDistanceInValue() { return (float)GetTradeDistanceInValue(GetChart().GetSymbol()); } + float GetTradeDistanceInValue() { return (float)GetTradeDistanceInValue(GetSource() PTR_DEREF GetSymbol()); } /* Trend methods */ @@ -1231,8 +1246,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. double GetTrend(int method, ENUM_TIMEFRAMES _tf = NULL, bool simple = false) { static datetime _last_trend_check = 0; static double _last_trend = 0; - string symbol = GetChart().GetSymbol(); - if (_last_trend_check == Chart().GetBarTime(_tf)) { + string symbol = GetSource() PTR_DEREF GetSymbol(); + if (_last_trend_check == ChartStatic::GetBarTime(symbol, _tf, 0)) { return _last_trend; } double bull = 0, bear = 0; @@ -1240,113 +1255,121 @@ HistorySelect(0, TimeCurrent()); // Select history for access. if (simple && method != 0) { if ((method & 1) != 0) { - if (Chart().GetOpen(PERIOD_MN1, 0) > Chart().GetClose(PERIOD_MN1, 1)) bull++; - if (Chart().GetOpen(PERIOD_MN1, 0) < Chart().GetClose(PERIOD_MN1, 1)) bear++; + if (ChartStatic::iOpen(symbol, PERIOD_MN1, 0) > ChartStatic::iClose(symbol, PERIOD_MN1, 1)) bull++; + if (ChartStatic::iOpen(symbol, PERIOD_MN1, 0) < ChartStatic::iClose(symbol, PERIOD_MN1, 1)) bear++; } if ((method & 2) != 0) { - if (Chart().GetOpen(PERIOD_W1, 0) > Chart().GetClose(PERIOD_W1, 1)) bull++; - if (Chart().GetOpen(PERIOD_W1, 0) < Chart().GetClose(PERIOD_W1, 1)) bear++; + if (ChartStatic::iOpen(symbol, PERIOD_W1, 0) > ChartStatic::iClose(symbol, PERIOD_W1, 1)) bull++; + if (ChartStatic::iOpen(symbol, PERIOD_W1, 0) < ChartStatic::iClose(symbol, PERIOD_W1, 1)) bear++; } if ((method & 4) != 0) { - if (Chart().GetOpen(PERIOD_D1, 0) > Chart().GetClose(PERIOD_D1, 1)) bull++; - if (Chart().GetOpen(PERIOD_D1, 0) < Chart().GetClose(PERIOD_D1, 1)) bear++; + if (ChartStatic::iOpen(symbol, PERIOD_D1, 0) > ChartStatic::iClose(symbol, PERIOD_D1, 1)) bull++; + if (ChartStatic::iOpen(symbol, PERIOD_D1, 0) < ChartStatic::iClose(symbol, PERIOD_D1, 1)) bear++; } if ((method & 8) != 0) { - if (Chart().GetOpen(PERIOD_H4, 0) > Chart().GetClose(PERIOD_H4, 1)) bull++; - if (Chart().GetOpen(PERIOD_H4, 0) < Chart().GetClose(PERIOD_H4, 1)) bear++; + if (ChartStatic::iOpen(symbol, PERIOD_H4, 0) > ChartStatic::iClose(symbol, PERIOD_H4, 1)) bull++; + if (ChartStatic::iOpen(symbol, PERIOD_H4, 0) < ChartStatic::iClose(symbol, PERIOD_H4, 1)) bear++; } if ((method & 16) != 0) { - if (Chart().GetOpen(PERIOD_H1, 0) > Chart().GetClose(PERIOD_H1, 1)) bull++; - if (Chart().GetOpen(PERIOD_H1, 0) < Chart().GetClose(PERIOD_H1, 1)) bear++; + if (ChartStatic::iOpen(symbol, PERIOD_H1, 0) > ChartStatic::iClose(symbol, PERIOD_H1, 1)) bull++; + if (ChartStatic::iOpen(symbol, PERIOD_H1, 0) < ChartStatic::iClose(symbol, PERIOD_H1, 1)) bear++; } if ((method & 32) != 0) { - if (Chart().GetOpen(PERIOD_M30, 0) > Chart().GetClose(PERIOD_M30, 1)) bull++; - if (Chart().GetOpen(PERIOD_M30, 0) < Chart().GetClose(PERIOD_M30, 1)) bear++; + if (ChartStatic::iOpen(symbol, PERIOD_M30, 0) > ChartStatic::iClose(symbol, PERIOD_M30, 1)) bull++; + if (ChartStatic::iOpen(symbol, PERIOD_M30, 0) < ChartStatic::iClose(symbol, PERIOD_M30, 1)) bear++; } if ((method & 64) != 0) { - if (Chart().GetOpen(PERIOD_M15, 0) > Chart().GetClose(PERIOD_M15, 1)) bull++; - if (Chart().GetOpen(PERIOD_M15, 0) < Chart().GetClose(PERIOD_M15, 1)) bear++; + if (ChartStatic::iOpen(symbol, PERIOD_M15, 0) > ChartStatic::iClose(symbol, PERIOD_M15, 1)) bull++; + if (ChartStatic::iOpen(symbol, PERIOD_M15, 0) < ChartStatic::iClose(symbol, PERIOD_M15, 1)) bear++; } if ((method & 128) != 0) { - if (Chart().GetOpen(PERIOD_M5, 0) > Chart().GetClose(PERIOD_M5, 1)) bull++; - if (Chart().GetOpen(PERIOD_M5, 0) < Chart().GetClose(PERIOD_M5, 1)) bear++; + if (ChartStatic::iOpen(symbol, PERIOD_M5, 0) > ChartStatic::iClose(symbol, PERIOD_M5, 1)) bull++; + if (ChartStatic::iOpen(symbol, PERIOD_M5, 0) < ChartStatic::iClose(symbol, PERIOD_M5, 1)) bear++; } - // if (Chart().GetOpen(PERIOD_H12, 0) > Chart().GetClose(PERIOD_H12, 1)) bull++; - // if (Chart().GetOpen(PERIOD_H12, 0) < Chart().GetClose(PERIOD_H12, 1)) bear++; - // if (Chart().GetOpen(PERIOD_H8, 0) > Chart().GetClose(PERIOD_H8, 1)) bull++; - // if (Chart().GetOpen(PERIOD_H8, 0) < Chart().GetClose(PERIOD_H8, 1)) bear++; - // if (Chart().GetOpen(PERIOD_H6, 0) > Chart().GetClose(PERIOD_H6, 1)) bull++; - // if (Chart().GetOpen(PERIOD_H6, 0) < Chart().GetClose(PERIOD_H6, 1)) bear++; - // if (Chart().GetOpen(PERIOD_H2, 0) > Chart().GetClose(PERIOD_H2, 1)) bull++; - // if (Chart().GetOpen(PERIOD_H2, 0) < Chart().GetClose(PERIOD_H2, 1)) bear++; + // if (ChartStatic::iOpen(symbol, PERIOD_H12, 0) > ChartStatic::iClose(symbol, PERIOD_H12, 1)) bull++; + // if (ChartStatic::iOpen(symbol, PERIOD_H12, 0) < ChartStatic::iClose(symbol, PERIOD_H12, 1)) bear++; + // if (ChartStatic::iOpen(symbol, PERIOD_H8, 0) > ChartStatic::iClose(symbol, PERIOD_H8, 1)) bull++; + // if (ChartStatic::iOpen(symbol, PERIOD_H8, 0) < ChartStatic::iClose(symbol, PERIOD_H8, 1)) bear++; + // if (ChartStatic::iOpen(symbol, PERIOD_H6, 0) > ChartStatic::iClose(symbol, PERIOD_H6, 1)) bull++; + // if (ChartStatic::iOpen(symbol, PERIOD_H6, 0) < ChartStatic::iClose(symbol, PERIOD_H6, 1)) bear++; + // if (ChartStatic::iOpen(symbol, PERIOD_H2, 0) > ChartStatic::iClose(symbol, PERIOD_H2, 1)) bull++; + // if (ChartStatic::iOpen(symbol, PERIOD_H2, 0) < ChartStatic::iClose(symbol, PERIOD_H2, 1)) bear++; } else if (method != 0) { if ((method % 1) == 0) { for (_counter = 0; _counter < 3; _counter++) { - if (Chart().GetOpen(PERIOD_MN1, _counter) > Chart().GetClose(PERIOD_MN1, _counter + 1)) + if (ChartStatic::iOpen(symbol, PERIOD_MN1, _counter) > ChartStatic::iClose(symbol, PERIOD_MN1, _counter + 1)) bull += 30; - else if (Chart().GetOpen(PERIOD_MN1, _counter) < Chart().GetClose(PERIOD_MN1, _counter + 1)) + else if (ChartStatic::iOpen(symbol, PERIOD_MN1, _counter) < + ChartStatic::iClose(symbol, PERIOD_MN1, _counter + 1)) bear += 30; } } if ((method % 2) == 0) { for (_counter = 0; _counter < 8; _counter++) { - if (Chart().GetOpen(PERIOD_W1, _counter) > Chart().GetClose(PERIOD_W1, _counter + 1)) + if (ChartStatic::iOpen(symbol, PERIOD_W1, _counter) > ChartStatic::iClose(symbol, PERIOD_W1, _counter + 1)) bull += 7; - else if (Chart().GetOpen(PERIOD_W1, _counter) < Chart().GetClose(PERIOD_W1, _counter + 1)) + else if (ChartStatic::iOpen(symbol, PERIOD_W1, _counter) < + ChartStatic::iClose(symbol, PERIOD_W1, _counter + 1)) bear += 7; } } if ((method % 4) == 0) { for (_counter = 0; _counter < 7; _counter++) { - if (Chart().GetOpen(PERIOD_D1, _counter) > Chart().GetClose(PERIOD_D1, _counter + 1)) + if (ChartStatic::iOpen(symbol, PERIOD_D1, _counter) > ChartStatic::iClose(symbol, PERIOD_D1, _counter + 1)) bull += 1440 / 1440; - else if (Chart().GetOpen(PERIOD_D1, _counter) < Chart().GetClose(PERIOD_D1, _counter + 1)) + else if (ChartStatic::iOpen(symbol, PERIOD_D1, _counter) < + ChartStatic::iClose(symbol, PERIOD_D1, _counter + 1)) bear += 1440 / 1440; } } if ((method % 8) == 0) { for (_counter = 0; _counter < 24; _counter++) { - if (Chart().GetOpen(PERIOD_H4, _counter) > Chart().GetClose(PERIOD_H4, _counter + 1)) + if (ChartStatic::iOpen(symbol, PERIOD_H4, _counter) > ChartStatic::iClose(symbol, PERIOD_H4, _counter + 1)) bull += 240 / 1440; - else if (Chart().GetOpen(PERIOD_H4, _counter) < Chart().GetClose(PERIOD_H4, _counter + 1)) + else if (ChartStatic::iOpen(symbol, PERIOD_H4, _counter) < + ChartStatic::iClose(symbol, PERIOD_H4, _counter + 1)) bear += 240 / 1440; } } if ((method % 16) == 0) { for (_counter = 0; _counter < 24; _counter++) { - if (Chart().GetOpen(PERIOD_H1, _counter) > Chart().GetClose(PERIOD_H1, _counter + 1)) + if (ChartStatic::iOpen(symbol, PERIOD_H1, _counter) > ChartStatic::iClose(symbol, PERIOD_H1, _counter + 1)) bull += 60 / 1440; - else if (Chart().GetOpen(PERIOD_H1, _counter) < Chart().GetClose(PERIOD_H1, _counter + 1)) + else if (ChartStatic::iOpen(symbol, PERIOD_H1, _counter) < + ChartStatic::iClose(symbol, PERIOD_H1, _counter + 1)) bear += 60 / 1440; } } if ((method % 32) == 0) { for (_counter = 0; _counter < 48; _counter++) { - if (Chart().GetOpen(PERIOD_M30, _counter) > Chart().GetClose(PERIOD_M30, _counter + 1)) + if (ChartStatic::iOpen(symbol, PERIOD_M30, _counter) > ChartStatic::iClose(symbol, PERIOD_M30, _counter + 1)) bull += 30 / 1440; - else if (Chart().GetOpen(PERIOD_M30, _counter) < Chart().GetClose(PERIOD_M30, _counter + 1)) + else if (ChartStatic::iOpen(symbol, PERIOD_M30, _counter) < + ChartStatic::iClose(symbol, PERIOD_M30, _counter + 1)) bear += 30 / 1440; } } if ((method % 64) == 0) { for (_counter = 0; _counter < 96; _counter++) { - if (Chart().GetOpen(PERIOD_M15, _counter) > Chart().GetClose(PERIOD_M15, _counter + 1)) + if (ChartStatic::iOpen(symbol, PERIOD_M15, _counter) > ChartStatic::iClose(symbol, PERIOD_M15, _counter + 1)) bull += 15 / 1440; - else if (Chart().GetOpen(PERIOD_M15, _counter) < Chart().GetClose(PERIOD_M15, _counter + 1)) + else if (ChartStatic::iOpen(symbol, PERIOD_M15, _counter) < + ChartStatic::iClose(symbol, PERIOD_M15, _counter + 1)) bear += 15 / 1440; } } if ((method % 128) == 0) { for (_counter = 0; _counter < 288; _counter++) { - if (Chart().GetOpen(PERIOD_M5, _counter) > Chart().GetClose(PERIOD_M5, _counter + 1)) + if (ChartStatic::iOpen(symbol, PERIOD_M5, _counter) > ChartStatic::iClose(symbol, PERIOD_M5, _counter + 1)) bull += 5 / 1440; - else if (Chart().GetOpen(PERIOD_M5, _counter) < Chart().GetClose(PERIOD_M5, _counter + 1)) + else if (ChartStatic::iOpen(symbol, PERIOD_M5, _counter) < + ChartStatic::iClose(symbol, PERIOD_M5, _counter + 1)) bear += 5 / 1440; } } } _last_trend = (bull - bear); - _last_trend_check = Chart().GetBarTime(_tf, 0); + _last_trend_check = ChartStatic::GetBarTime(symbol, _tf, 0); logger.Debug(StringFormat("%s: %g", __FUNCTION__, _last_trend)); return _last_trend; } @@ -1404,8 +1427,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // @todo: TRADE_STATE_ORDERS_MAX_SOFT // ... /* Market checks */ - uint _tspread = int(tparams.Get(TRADE_PARAM_MAX_SPREAD) * GetChart().GetPointsPerPip()); - tstates.SetState(TRADE_STATE_SPREAD_TOO_HIGH, _tspread > 0 && GetChart().GetSpread() > _tspread); + // uint _tspread = int(tparams.Get(TRADE_PARAM_MAX_SPREAD) * GetChart().GetPointsPerPip()); + // tstates.SetState(TRADE_STATE_SPREAD_TOO_HIGH, _tspread > 0 && GetChart().GetSpread() > _tspread); /* Terminal checks */ tstates.SetState(TRADE_STATE_TRADE_NOT_POSSIBLE, // Check if the EA trading is enabled. @@ -1415,14 +1438,21 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // Check if auto trading is enabled. && (Terminal::IsRealtime() && !Terminal::IsExpertEnabled())); /* Chart checks */ - tstates.SetState(TRADE_STATE_BARS_NOT_ENOUGH, GetChart().GetBars() < tparams.GetBarsMin()); + // tstates.SetState(TRADE_STATE_BARS_NOT_ENOUGH, GetChart().GetBars() < tparams.GetBarsMin()); /* Symbol trade modes */ + /* ENUM_SYMBOL_TRADE_MODE _trade_mode = GetChart().GetTradeMode(); tstates.SetState(TRADE_STATE_MODE_DISABLED, _trade_mode == SYMBOL_TRADE_MODE_DISABLED); tstates.SetState(TRADE_STATE_MODE_LONGONLY, _trade_mode == SYMBOL_TRADE_MODE_LONGONLY); tstates.SetState(TRADE_STATE_MODE_SHORTONLY, _trade_mode == SYMBOL_TRADE_MODE_SHORTONLY); tstates.SetState(TRADE_STATE_MODE_CLOSEONLY, _trade_mode == SYMBOL_TRADE_MODE_CLOSEONLY); tstates.SetState(TRADE_STATE_MODE_FULL, _trade_mode == SYMBOL_TRADE_MODE_FULL); + */ +#ifdef __debug__ + Print("Trade: Bars in data source: ", GetSource() PTR_DEREF GetBars(), + ", minimum required bars: ", tparams.GetBarsMin()); +#endif + tstates.SetState(TRADE_STATE_BARS_NOT_ENOUGH, GetSource() PTR_DEREF GetBars() < tparams.GetBarsMin()); /* Terminal checks */ tstates.SetState(TRADE_STATE_TRADE_NOT_ALLOWED, // Check if real trading is allowed. @@ -1455,15 +1485,18 @@ HistorySelect(0, TimeCurrent()); // Select history for access. */ double NormalizeLots(double _lots, bool _ceil = false) { double _lot_size = _lots; - double _vol_min = GetChart().GetVolumeMin(); - double _vol_step = GetChart().GetVolumeStep() > 0.0 ? GetChart().GetVolumeStep() : _vol_min; + double _vol_min = GetSource() PTR_DEREF GetSymbolProps().GetVolumeMin(); + double _vol_step = GetSource() PTR_DEREF GetSymbolProps().GetVolumeStep() > 0.0 + ? GetSource() PTR_DEREF GetSymbolProps().GetVolumeStep() + : _vol_min; if (_vol_step > 0) { // Related: https://www.mql5.com/en/forum/139338 double _precision = 1 / _vol_step; // Edge case when step is higher than minimum. _lot_size = _ceil ? ceil(_lots * _precision) / _precision : floor(_lots * _precision) / _precision; - double _min_lot = fmax(GetChart().GetVolumeMin(), GetChart().GetVolumeStep()); - _lot_size = fmin(fmax(_lot_size, _min_lot), GetChart().GetVolumeMax()); + double _min_lot = fmax(GetSource() PTR_DEREF GetSymbolProps().GetVolumeMin(), + GetSource() PTR_DEREF GetSymbolProps().GetVolumeStep()); + _lot_size = fmin(fmax(_lot_size, _min_lot), GetSource() PTR_DEREF GetSymbolProps().GetVolumeMax()); } return NormalizeDouble(_lot_size, Math::FloatDigits(_vol_min)); } @@ -1484,10 +1517,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. switch (_mode) { // Bid - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL (minimum trade distance) case ORDER_TYPE_SL: - return fmin(_value, GetChart().GetBid() - GetTradeDistanceInValue()); + return fmin(_value, GetSource() PTR_DEREF GetBid() - GetTradeDistanceInValue()); // TakeProfit - Bid >= SYMBOL_TRADE_STOPS_LEVEL (minimum trade distance) case ORDER_TYPE_TP: - return fmax(_value, GetChart().GetBid() + GetTradeDistanceInValue()); + return fmax(_value, GetSource() PTR_DEREF GetBid() + GetTradeDistanceInValue()); default: logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); } @@ -1499,10 +1532,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. switch (_mode) { // StopLoss - Ask >= SYMBOL_TRADE_STOPS_LEVEL (minimum trade distance) case ORDER_TYPE_SL: - return fmax(_value, GetChart().GetAsk() + GetTradeDistanceInValue()); + return fmax(_value, GetSource() PTR_DEREF GetAsk() + GetTradeDistanceInValue()); // Ask - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL (minimum trade distance) case ORDER_TYPE_TP: - return fmin(_value, GetChart().GetAsk() - GetTradeDistanceInValue()); + return fmin(_value, GetSource() PTR_DEREF GetAsk() - GetTradeDistanceInValue()); default: logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); } @@ -1512,11 +1545,17 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } return NULL; } + double NormalizeSL(double _value, ENUM_ORDER_TYPE _cmd) { - return _value > 0 ? GetChart().NormalizePrice(NormalizeSLTP(_value, _cmd, ORDER_TYPE_SL)) : 0; + return _value > 0 + ? GetSource() PTR_DEREF GetSymbolProps().NormalizePrice(NormalizeSLTP(_value, _cmd, ORDER_TYPE_SL)) + : 0; } + double NormalizeTP(double _value, ENUM_ORDER_TYPE _cmd) { - return _value > 0 ? GetChart().NormalizePrice(NormalizeSLTP(_value, _cmd, ORDER_TYPE_TP)) : 0; + return _value > 0 + ? GetSource() PTR_DEREF GetSymbolProps().NormalizePrice(NormalizeSLTP(_value, _cmd, ORDER_TYPE_TP)) + : 0; } /* Validation methods */ @@ -1552,7 +1591,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // SL-Ask >= StopLevel && Ask-TP >= StopLevel // OpenPrice-Ask >= StopLevel && OpenPrice-SL >= StopLevel && TP-OpenPrice >= StopLevel // PrintFormat("%g > %g", fmin(fabs(GetBid() - price), fabs(GetAsk() - price)), distance); - return price > 0 && fmin(fabs(GetChart().GetBid() - price), fabs(GetChart().GetAsk() - price)) > distance; + return price > 0 && fmin(fabs(GetSource() PTR_DEREF GetBid() - price), + fabs(GetSource() PTR_DEREF GetAsk() - price)) > distance; default: return (true); } @@ -1567,8 +1607,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. return _is_valid; } double _min_distance = GetTradeDistanceInPips(); - double _price = GetChart().GetOpenOffer(_cmd); - unsigned int _digits = GetChart().GetDigits(); + double _price = GetSource() PTR_DEREF GetOpenOffer(_cmd); + unsigned int _digits = GetSource() PTR_DEREF GetSymbolProps().GetDigits(); switch (_cmd) { case ORDER_TYPE_BUY: _is_valid &= _value < _price && Convert::GetValueDiffInPips(_price, _value, true, _digits) > _min_distance; @@ -1613,10 +1653,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * @see: https://www.mql5.com/en/articles/2555#invalid_SL_TP_for_position */ double IsValidOrderSLTP(ENUM_ORDER_TYPE _cmd, double sl, double tp) { - double ask = GetChart().GetAsk(); - double bid = GetChart().GetBid(); - double openprice = GetChart().GetOpenOffer(_cmd); - double closeprice = GetChart().GetCloseOffer(_cmd); + 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); // The minimum distance of SYMBOL_TRADE_STOPS_LEVEL taken into account. double distance = GetTradeDistanceInValue(); // bool result; @@ -1687,8 +1727,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. return _is_valid; } double _min_distance = GetTradeDistanceInPips(); - double _price = GetChart().GetOpenOffer(_cmd); - unsigned int _digits = GetChart().GetDigits(); + double _price = GetSource() PTR_DEREF GetOpenOffer(_cmd); + unsigned int _digits = GetSource() PTR_DEREF GetSymbolProps().GetDigits(); switch (_cmd) { case ORDER_TYPE_BUY: _is_valid &= _value > _price && Convert::GetValueDiffInPips(_value, _price, true, _digits) > _min_distance; @@ -1937,8 +1977,6 @@ HistorySelect(0, TimeCurrent()); // Select history for access. return Check(_entry); } - /* TaskActions */ - /** * Gets a copy of structure. */ @@ -1951,6 +1989,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. return _result; } + /* TaskActions */ + /** * Runs an action. */ @@ -2009,7 +2049,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case TRADE_ACTION_ORDERS_CLOSE_IN_PROFIT: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { _result = OrdersCloseViaProp( - ORDER_PROP_PROFIT_PIPS, (int)chart.Ptr().GetSpreadInPips(), MATH_COND_GT, + ORDER_PROP_PROFIT_PIPS, (int)GetSource() PTR_DEREF GetSpreadInPips(), MATH_COND_GT, ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } @@ -2093,18 +2133,28 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Returns textual representation of the Trade class. */ - string ToString() const { - // @todo - // return StringFormat("Margin required: %g/lot", GetMarginRequired()); - return ""; - } + string const ToString() { return SerializerConverter::FromObject(THIS_REF).ToString(); } /* Class handlers */ /** - * Returns pointer to Chart class. + * Returns pointer to IndicatorCandle-based class. */ - Chart *GetChart() { return chart.Ptr(); } + IndicatorData *GetSource() { + if (!indi_candle.IsSet()) { + Print( + "Error: Trade has no Candle-based indicator bound. Please pass such object in Trade's constructor or via " + "SetSource() method."); + DebugBreak(); + } + + return indi_candle.Ptr(); + } + + /** + * Binds IndicatorCandle-based class. + */ + void SetSource(IndicatorBase *_indi_candle) { indi_candle = _indi_candle; } /** * Returns pointer to Log class. @@ -2113,12 +2163,16 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /* Serializers */ + SERIALIZER_EMPTY_STUB + /** * Returns serialized representation of the object instance. */ SerializerNodeType Serialize(Serializer &_s) { - // ChartEntry _centry = GetEntry(); - // _s.PassStruct(THIS_REF, "chart-entry", _centry, SERIALIZER_FIELD_FLAG_DYNAMIC); + _s.PassStruct(THIS_REF, "trade-params", tparams); + _s.PassStruct(THIS_REF, "trade-states", tstates); + // @todo + // _s.PassStruct(THIS_REF, "trade-stats", tstats); return SerializerNodeObject; } }; diff --git a/Trade.struct.h b/Trade.struct.h index d0e43913f..b529c2118 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -286,12 +286,12 @@ struct TradeStats { /* 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__ +#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__ +#ifdef __debug_verbose__ Print("GetOrderStats: _periods_started = ", _periods_started); #endif if (_periods_started >= DATETIME_HOUR) { @@ -333,7 +333,7 @@ struct TradeStats { 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__ +#ifdef __debug_verbose__ Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(_period)); #endif dt[(int)t][(int)_period].GetStartedPeriods(true, true); @@ -343,7 +343,7 @@ struct TradeStats { 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__ +#ifdef __debug_vebose__ Print("Resetting trade counter for type ", EnumToString(_type), " and period ", EnumToString(p)); #endif dt[(int)_type][(int)p].GetStartedPeriods(true, true); @@ -354,7 +354,7 @@ struct TradeStats { 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__ +#ifdef __debug_verbose__ Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(p)); #endif dt[(int)t][(int)p].GetStartedPeriods(true, true); diff --git a/Trade/tests/TradeSignalEnumMacro.test.mq4 b/Trade/tests/TradeSignalEnumMacro.test.mq4 index 2dc519fb9..daf14ad8e 100644 --- a/Trade/tests/TradeSignalEnumMacro.test.mq4 +++ b/Trade/tests/TradeSignalEnumMacro.test.mq4 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ diff --git a/Trade/tests/TradeSignalEnumMacro.test.mq5 b/Trade/tests/TradeSignalEnumMacro.test.mq5 index 1e465488f..392da04d3 100644 --- a/Trade/tests/TradeSignalEnumMacro.test.mq5 +++ b/Trade/tests/TradeSignalEnumMacro.test.mq5 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2023, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ diff --git a/Util.h b/Util.h index fd8e09a51..50950b11e 100644 --- a/Util.h +++ b/Util.h @@ -382,7 +382,7 @@ class Util { /** * Creates string with separator if string was not empty. */ - static string SeparatedMaybe(string _value, string _separator = "/") { + static string SeparatedMaybe(string _value, string _separator = ", ") { return _value == "" ? "" : (_value + _separator); } }; diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index ac75d930c..878a2986a 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -42,36 +42,15 @@ #include "../3D/Frontends/MT5Frontend.h" #include "../BufferStruct.mqh" #include "../Chart.mqh" +#include "../Platform.h" #include "../Serializer.mqh" #include "../Test.mqh" -BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { - static Chart _chart(); - static BufferStruct idata; - - long _bar_time = _chart.GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(4); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = _chart.GetBarTime(_shift); - _entry.values[0] = (float)_chart.GetOpen(_shift); - _entry.values[1] = (float)_chart.GetHigh(_shift); - _entry.values[2] = (float)_chart.GetLow(_shift); - _entry.values[3] = (float)_chart.GetClose(_shift); - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, true); - idata.Add(_entry, _bar_time); - } - - return BarOHLC(_entry.GetValue(0), _entry.GetValue(1), _entry.GetValue(2), - _entry.GetValue(3)); -} - /** * Implements OnInit(). */ int OnInit() { + Platform::Init(); Ref gfx_ptr = new MTDXDevice(); // Making a scope to ensure graphics device will be destructed as last. @@ -87,7 +66,7 @@ int OnInit() { _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); _mesh.Ptr().SetShaderPS(_shader_p.Ptr()); - Ref _chart = new Chart3D(ChartPriceFeeder, CHART3D_TYPE_CANDLES); + Ref _chart = new Chart3D(Platform::FetchDefaultCandleIndicator(), CHART3D_TYPE_CANDLES); unsigned int _rand_color = rand() * 1256; @@ -122,6 +101,11 @@ int OnInit() { return (INIT_SUCCEEDED); } + +/** + * Implements OnTick(). + **/ +void OnTick() { Platform::Tick(); } #else /** * Implements OnInit(). diff --git a/tests/BufferFXTTest.mq5 b/tests/BufferFXTTest.mq5 index fc721b91f..4de298ea3 100644 --- a/tests/BufferFXTTest.mq5 +++ b/tests/BufferFXTTest.mq5 @@ -26,6 +26,7 @@ // Includes #include "../BufferFXT.mqh" +#include "../Platform.h" #include "../Test.mqh" BufferFXT *ticks; @@ -34,7 +35,8 @@ BufferFXT *ticks; * Implements OnInit(). */ int OnInit() { - ticks = new BufferFXT(); + Platform::Init(); + ticks = new BufferFXT(Platform::FetchDefaultCandleIndicator()); // Test 1. // @todo return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED); @@ -43,7 +45,7 @@ int OnInit() { /** * Implements OnTick(). */ -void OnTick() {} +void OnTick() { Platform::Tick(); } /** * Implements OnDeinit(). diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index 5b895bf0e..1e05b27b8 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -37,6 +37,9 @@ */ #endif +// Forward declaration. +struct IndicatorParams; + // Includes. #include "../Account/AccountMt.h" #include "../Array.mqh" @@ -64,7 +67,7 @@ #include "../Indicator.mqh" #include "../IndicatorBase.h" #include "../IndicatorData.mqh" -#include "../Inet.mqh" +// #include "../Inet.mqh" #include "../Log.mqh" #include "../MD5.mqh" #include "../Storage/Collection.mqh" @@ -82,7 +85,7 @@ #include "../Order.mqh" #include "../Orders.mqh" #include "../Pattern.mqh" -#include "../Profiler.mqh" +// #include "../Profiler.mqh" #include "../Redis.mqh" #include "../Refs.mqh" #include "../Registry.mqh" @@ -123,6 +126,7 @@ // #include "../Tester.mqh" // @removeme #include "../Storage/ValueStorage.h" #include "../Tests.mqh" +// #include "../Tests.mqh" // @removeme #include "../Timer.mqh" #include "../Trade.mqh" #include "../Util.h" diff --git a/tests/DateTimeTest.mq5 b/tests/DateTimeTest.mq5 index 3a524e29e..838b9aab0 100644 --- a/tests/DateTimeTest.mq5 +++ b/tests/DateTimeTest.mq5 @@ -67,18 +67,26 @@ int OnInit() { entry = dt.GetEntry(); assertTrueOrFail(curr_dt == entry.GetTimestamp(), "Timestamp not match!"); // Test IsNewMinute() method. + entry.SetMinute(0); entry.SetSeconds(1); dt.SetEntry(entry); - assertFalseOrFail(dt.IsNewMinute(false), "IsNewMinute() test failed."); + assertFalseOrFail(dt.IsNewMinute(), "IsNewMinute() test failed."); + entry.SetMinute(0); entry.SetSeconds(10); dt.SetEntry(entry); - assertFalseOrFail(dt.IsNewMinute(false), "IsNewMinute() test failed."); + assertFalseOrFail(dt.IsNewMinute(), "IsNewMinute() test failed."); + entry.SetMinute(1); entry.SetSeconds(0); dt.SetEntry(entry); - assertTrueOrFail(dt.IsNewMinute(false), "IsNewMinute() test failed."); + assertTrueOrFail(dt.IsNewMinute(), "IsNewMinute() test failed."); + entry.SetMinute(1); entry.SetSeconds(1); dt.SetEntry(entry); - assertFalseOrFail(dt.IsNewMinute(false), "IsNewMinute() test failed."); + assertFalseOrFail(dt.IsNewMinute(), "IsNewMinute() test failed."); + entry.SetMinute(1); + entry.SetSeconds(3); + dt.SetEntry(entry); + assertFalseOrFail(dt.IsNewMinute(), "IsNewMinute() test failed."); delete dt; return (GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED); } diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index 1c98147f1..cccedb21c 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -25,8 +25,9 @@ */ // Includes. -#include "../Dict.mqh" +#include "../DictStruct.mqh" #include "../DrawIndicator.mqh" +#include "../Indicator.struct.serialize.h" #include "../Indicators/Indi_Bands.mqh" #include "../Indicators/Indi_Demo.mqh" #include "../Indicators/Indi_MA.mqh" @@ -35,20 +36,19 @@ #include "../Test.mqh" // Global variables. -Chart *chart; -DictStruct> indis; +Ref candles; int bar_processed; /** * Implements Init event handler. */ int OnInit() { + Platform::Init(); + candles = Platform::FetchDefaultCandleIndicator(); bool _result = true; - // Initialize chart. - chart = new Chart(); // Initialize indicators. _result &= InitIndicators(); - Print("Indicators to test: ", indis.Size()); + Print("Indicators to test: ", Platform::GetIndicators().Size()); // Check for any errors. assertTrueOrFail(GetLastError() == ERR_NO_ERROR, StringFormat("Error: %d", GetLastError())); bar_processed = 0; @@ -59,12 +59,13 @@ int OnInit() { * Implements Tick event handler. */ void OnTick() { - chart.OnTick(); + Platform::Tick(); - if (chart.IsNewBar()) { + if (candles REF_DEREF IsNewBar()) { bar_processed++; - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + for (DictIterator> iter = Platform::GetIndicators() PTR_DEREF Begin(); iter.IsValid(); + ++iter) { IndicatorData *_indi = iter.Value().Ptr(); _indi.OnTick(); IndicatorDataEntry _entry = _indi.GetEntry(); @@ -78,7 +79,7 @@ void OnTick() { /** * Implements Deinit event handler. */ -void OnDeinit(const int reason) { delete chart; } +void OnDeinit(const int reason) {} /** * Initialize indicators. @@ -88,48 +89,50 @@ bool InitIndicators() { // Bollinger Bands. IndiBandsParams bands_params(20, 2, 0, PRICE_MEDIAN); - Ref indi_bands = new Indi_Bands(bands_params); - indis.Set(INDI_BANDS, indi_bands); + Platform::AddWithDefaultBindings(new Indi_Bands(bands_params)); // Moving Average. IndiMAParams ma_params(13, 10, MODE_SMA, PRICE_OPEN); - Ref indi_ma = new Indi_MA(ma_params); - indis.Set(INDI_MA, indi_ma); + Platform::AddWithDefaultBindings(new Indi_MA(ma_params)); // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); - Ref indi_rsi = new Indi_RSI(rsi_params); - indis.Set(INDI_RSI, indi_rsi); + Platform::AddWithDefaultBindings(new Indi_RSI(rsi_params)); /* Special indicators */ // Demo/Dummy Indicator. IndiDemoParams demo_params; - Ref indi_demo = new Indi_Demo(demo_params); - indis.Set(INDI_DEMO, indi_demo); + Platform::AddWithDefaultBindings(new Indi_Demo(demo_params)); +#ifndef __MQL4__ + // @fixme: Make it work for MT4. // Current Price (used by custom indicators) . PriceIndiParams price_params(); - price_params.SetDraw(clrGreenYellow); - Ref indi_price = new Indi_Price(price_params); - indis.Set(INDI_PRICE, indi_price); + // price_params.SetDraw(clrGreenYellow); + Platform::AddWithDefaultBindings(new Indi_Price(price_params)); +#endif - /* @fixme: Convert to new syntax. Array out of range. + /* @fixme: Array out of range. // Bollinger Bands over Price indicator. + /* PriceIndiParams price_params_4_bands(); - IndicatorData *indi_price_4_bands = new Indi_Price(price_params_4_bands); + IndicatorBase *indi_price_4_bands = new Indi_Price(price_params_4_bands); IndiBandsParams bands_on_price_params(); bands_on_price_params.SetDraw(clrCadetBlue); - indis.Set(INDI_BANDS_ON_PRICE, new Indi_Bands(bands_on_price_params, IDATA_INDICATOR, indi_price_4_bands)); + // bands_on_price_params.SetDataSource(indi_price_4_bands, true, INDI_PRICE_MODE_OPEN); + Platform::AddWithDefaultBindings(new Indi_Bands(bands_on_price_params, indi_price_4_bands, true)); + */ // Moving Average (MA) over Price indicator. + /* PriceIndiParams price_params_4_ma(); - IndicatorData *indi_price_4_ma = new Indi_Price(price_params_4_ma); + IndicatorBase *indi_price_4_ma = new Indi_Price(price_params_4_ma); IndiMAParams ma_on_price_params(); ma_on_price_params.SetDraw(clrYellowGreen); + // ma_on_price_params.SetDataSource(indi_price_4_ma, true, INDI_PRICE_MODE_OPEN); ma_on_price_params.SetIndicatorType(INDI_MA_ON_PRICE); - IndicatorData *indi_ma_on_price = new Indi_MA(ma_on_price_params, IDATA_INDICATOR, indi_price_4_ma); - indis.Set(INDI_MA_ON_PRICE, indi_ma_on_price); + Platform::AddWithDefaultBindings(new Indi_MA(ma_on_price_params, indi_price_4_ma)); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); @@ -140,6 +143,12 @@ bool InitIndicators() { indis.Set(INDI_RSI_ON_PRICE, indi_rsi_on_price); */ + // We'll be drawing all indicators' values on the chart. + for (DictIterator> iter = Platform::GetIndicators() PTR_DEREF Begin(); iter.IsValid(); + ++iter) { + // iter.Value() REF_DEREF SetDraw(true); // @fixme + } + return _LastError == ERR_NO_ERROR; } @@ -148,7 +157,8 @@ bool InitIndicators() { */ bool PrintIndicators(string _prefix = "") { ResetLastError(); - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + for (DictIterator> iter = Platform::GetIndicators() PTR_DEREF Begin(); iter.IsValid(); + ++iter) { IndicatorData *_indi = iter.Value().Ptr(); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString()); diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index a4184ae5b..ff2158e82 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -32,24 +32,27 @@ struct DataParamEntry; // Includes. +//#include "../ChartMt.h" #include "../Dict.mqh" #include "../DictObject.mqh" #include "../Indicator.mqh" +#include "../Indicator/tests/classes/IndicatorTfDummy.h" #include "../Indicators/Bitwise/indicators.h" +#include "../Indicators/Tick/Indi_TickMt.mqh" #include "../Indicators/indicators.h" +#include "../Platform.h" #include "../SerializerConverter.mqh" #include "../SerializerJson.mqh" +#include "../Std.h" #include "../Test.mqh" // Custom indicator identifiers. enum ENUM_CUSTOM_INDICATORS { INDI_SPECIAL_MATH_CUSTOM = FINAL_INDICATOR_TYPE_ENTRY + 1 }; // Global variables. -Chart* chart; -DictStruct> indis; +DictStruct> indis; DictStruct> whitelisted_indis; -Dict tested; -int bar_processed; +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}; @@ -60,21 +63,29 @@ Ref _indi_test; * Implements Init event handler. */ int OnInit() { + Platform::Init(); bool _result = true; - // Initialize chart. - chart = new Chart(); Print("We have ", Bars(NULL, 0), " bars to analyze"); // Initialize indicators. _result &= InitIndicators(); + Print("Indicators to test: ", indis.Size()); + + 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); + } + // Check for any errors. assertEqualOrFail(_LastError, ERR_NO_ERROR, StringFormat("Error: %d", GetLastError())); ResetLastError(); // Print indicator values. + _result &= PrintIndicators(__FUNCTION__); assertEqualOrFail(_LastError, ERR_NO_ERROR, StringFormat("Error: %d", GetLastError())); ResetLastError(); - bar_processed = 0; + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); } @@ -82,40 +93,38 @@ int OnInit() { * Implements Tick event handler. */ void OnTick() { - chart.OnTick(); + Platform::Tick(); + IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); - // All indicators should execute its OnTick() method for every platform tick. - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - // iter.Value().Ptr().Tick(); // @fixme + if (_candles PTR_DEREF IsNewBar()) { + if (_candles PTR_DEREF GetBarIndex() > 200) { + ExpertRemove(); } - if (chart.IsNewBar()) { - bar_processed++; if (indis.Size() == 0) { return; } - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { if (whitelisted_indis.Size() == 0) { - if (tested.GetByKey(iter.Key())) { + if (tested.Contains(iter.Value())) { // Indicator is already tested, skipping. continue; } } else { if (!whitelisted_indis.Contains(iter.Value())) { - // continue; // @fixme + continue; } } IndicatorData* _indi = iter.Value().Ptr(); - _indi.OnTick(); - IndicatorDataEntry _entry(_indi.GetEntry()); + IndicatorDataEntry _entry(_indi PTR_DEREF GetEntry()); - if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { + if (_indi PTR_DEREF Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { if (_entry.IsValid()) { - PrintFormat("%s: bar %d: %s", _indi.GetFullName(), bar_processed, _indi.ToString()); - tested.Set(iter.Key(), true); // Mark as tested. - indis.Unset(iter.Key()); + PrintFormat("%s: bar %d: %s", _indi PTR_DEREF GetFullName(), _candles PTR_DEREF GetBars(), + _indi PTR_DEREF ToString()); + tested.Push(iter.Value()); // Mark as tested. } } } @@ -127,15 +136,13 @@ void OnTick() { */ void OnDeinit(const int reason) { int num_not_tested = 0; - for (DictIterator iter = tested.Begin(); iter.IsValid(); ++iter) { - if (!iter.Value()) { - PrintFormat("%s: Indicator not tested: %s", __FUNCTION__, indis[iter.Key()].Ptr().GetName()); + for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + if (!tested.Contains(iter.Value())) { + PrintFormat("%s: Indicator not tested: %s", __FUNCTION__, iter.Value().Ptr().GetFullName()); ++num_not_tested; } } - delete chart; - PrintFormat("%s: Indicators not tested: %d", __FUNCTION__, num_not_tested); assertTrueOrExit(num_not_tested == 0, "Not all indicators has been tested!"); } @@ -144,6 +151,12 @@ void OnDeinit(const int reason) { * Initialize indicators. */ bool InitIndicators() { + /* Price/OHLC indicators */ + + // Price indicator. + Ref indi_price = new Indi_Price(PriceIndiParams()); + // indis.Push(indi_price); // @fixme: Make it work with the test? + /* Standard indicators */ // AC. @@ -171,17 +184,16 @@ bool InitIndicators() { IndiATRParams atr_params(14); indis.Push(new Indi_ATR(atr_params)); - // Bollinger Bands. + // 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); - // Bollinger Bands over RSI. - /* @todo: Convert into new syntax. - IndiBandsParams bands_over_rsi_params(20, 2, 0, PRICE_OPEN); - // bands_over_rsi_params.SetDataSource(INDI_RSI); - indis.Push(new Indi_Bands(bands_over_rsi_params)); - */ + // 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); // Bears Power. IndiBearsPowerParams bears_params(13, PRICE_CLOSE); @@ -236,9 +248,9 @@ bool InitIndicators() { indis.Push(indi_ma); // DEMA. - IndiDEIndiMAParams dema_params(13, 2, PRICE_OPEN); - Ref indi_dema = new Indi_DEMA(dema_params); - indis.Push(indi_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 // MACD. IndiMACDParams macd_params(12, 26, 9, PRICE_CLOSE); @@ -262,14 +274,27 @@ bool InitIndicators() { // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); - indis.Push(new Indi_RSI(rsi_params)); + Ref indi_rsi = new Indi_RSI(rsi_params); + indis.Push(indi_rsi.Ptr()); - // Relative Strength Index (RSI). - /* @todo: Convert into new syntax. - IndiRSIParams rsi_over_blt_stddev_params(); - // rsi_over_blt_stddev_params.SetDataSource(INDI_STDDEV); - indis.Push(new Indi_RSI(rsi_over_blt_stddev_params)); - */ + // Bollinger Bands over RSI. + IndiBandsParams indi_bands_over_rsi_params(20, 2, 0, PRICE_OPEN); + Ref indi_bands_over_rsi = new Indi_Bands(indi_bands_over_rsi_params); + // 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); + + // Standard Deviation (StdDev). + IndiStdDevParams stddev_params(13, 10, MODE_SMA, PRICE_OPEN); + Ref indi_stddev = new Indi_StdDev(stddev_params); + indis.Push(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); // Relative Vigor Index (RVI). IndiRVIParams rvi_params(14); @@ -279,16 +304,12 @@ bool InitIndicators() { IndiSARParams sar_params(0.02, 0.2); indis.Push(new Indi_SAR(sar_params)); - // Standard Deviation (StdDev). - IndiStdDevParams stddev_params(13, 10, MODE_SMA, PRICE_OPEN); - indis.Push(new Indi_StdDev(stddev_params)); - // Standard Deviation (StdDev). Ref indi_price_for_stdev = new Indi_Price(PriceIndiParams()); - IndiStdDevParams stddev_on_price_params(); - stddev_on_price_params.SetDraw(clrBlue, 1); - Ref indi_stddev_on_price = new Indi_StdDev(stddev_on_price_params, IDATA_BUILTIN, indi_price_for_stdev.Ptr()); + // 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()); // Stochastic Oscillator. @@ -308,17 +329,11 @@ bool InitIndicators() { // Demo/Dummy Indicator. indis.Push(new Indi_Demo()); - // Current Price. - PriceIndiParams price_params(); - // price_params.SetDraw(clrAzure); - Ref indi_price = new Indi_Price(price_params); - indis.Push(indi_price); - // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); Ref indi_price_4_bands = new Indi_Price(price_params_4_bands); IndiBandsParams bands_on_price_params(); - bands_on_price_params.SetDraw(clrCadetBlue); + // 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()); @@ -329,25 +344,26 @@ bool InitIndicators() { Ref indi_ma_sma_for_stddev = new Indi_MA(ma_sma_params_for_stddev); IndiStdDevParams stddev_params_on_ma_sma(13, 10); - stddev_params_on_ma_sma.SetDraw(true, 1); + // stddev_params_on_ma_sma.SetDraw(true, 1); // @fixme - Ref indi_stddev_on_ma_sma = new Indi_StdDev(stddev_params_on_ma_sma, IDATA_BUILTIN, indi_ma_sma_for_stddev.Ptr()); + 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()); // Standard Deviation (StdDev) in SMA mode over Price. PriceIndiParams price_params_for_stddev_sma(); Ref indi_price_for_stddev_sma = new Indi_Price(price_params_for_stddev_sma); - IndiStdDevParams stddev_sma_on_price_params(); - stddev_sma_on_price_params.SetDraw(true, 1); - Ref indi_stddev_on_sma = new Indi_StdDev(stddev_sma_on_price_params, IDATA_BUILTIN, indi_price_for_stddev_sma.Ptr()); + // 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()); // Moving Average (MA) over Price indicator. PriceIndiParams price_params_4_ma(); Ref indi_price_4_ma = new Indi_Price(price_params_4_ma); IndiMAParams ma_on_price_params(13, 0, MODE_SMA, PRICE_OPEN, 0); - ma_on_price_params.SetDraw(clrYellowGreen); + // 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()); @@ -356,7 +372,7 @@ bool InitIndicators() { PriceIndiParams price_params_4_cci(); Ref indi_price_4_cci = new Indi_Price(price_params_4_cci); IndiCCIParams cci_on_price_params(); - cci_on_price_params.SetDraw(clrYellowGreen, 1); + // 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()); @@ -364,46 +380,48 @@ bool InitIndicators() { PriceIndiParams price_params_4_envelopes(); Ref indi_price_4_envelopes = new Indi_Price(price_params_4_envelopes); IndiEnvelopesParams env_on_price_params(); - env_on_price_params.SetDraw(clrBrown); - Ref indi_envelopes_on_price = new Indi_Envelopes(env_on_price_params, IDATA_BUILTIN, indi_price_4_envelopes.Ptr()); + // 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()); // DEMA over Price indicator. PriceIndiParams price_params_4_dema(); Ref indi_price_4_dema = new Indi_Price(price_params_4_dema); - IndiDEIndiMAParams dema_on_price_params(13, 2, PRICE_OPEN); - dema_on_price_params.SetDraw(clrRed); - Ref indi_dema_on_price = new Indi_DEMA(dema_on_price_params, IDATA_BUILTIN, indi_price_4_dema.Ptr()); - indis.Push(indi_dema_on_price.Ptr()); + IndiDEMAParams dema_on_price_params(13, 2, PRICE_OPEN); + // 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 // Momentum over Price indicator. Ref indi_price_4_momentum = new Indi_Price(); IndiMomentumParams mom_on_price_params(); - mom_on_price_params.SetDraw(clrDarkCyan); - Ref indi_momentum_on_price = new Indi_Momentum(mom_on_price_params, IDATA_BUILTIN, indi_price_4_momentum.Ptr()); + // 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()); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); Ref indi_price_4_rsi = new Indi_Price(price_params_4_rsi); IndiRSIParams rsi_on_price_params(); - rsi_on_price_params.SetDraw(clrBisque, 1); + // 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()); -#ifndef __MQL4__ // @fixme: Fix it for MQL4. // Drawer (socket-based) indicator over RSI over Price. - IndiDrawerParams drawer_params(14, /*unused*/ PRICE_OPEN); - drawer_params.SetDraw(clrBisque, 0); + 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()); -#endif // Applied Price over OHCL indicator. IndiAppliedPriceParams applied_price_params(); - applied_price_params.SetDraw(clrAquamarine, 0); + // applied_price_params.SetDraw(clrAquamarine, 0); // @fixme 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)); + 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()); // ADXW. @@ -411,14 +429,12 @@ bool InitIndicators() { indis.Push(new Indi_ADXW(adxw_params)); // AMA. - /* @fixme IndiAMAParams ama_params(); // Will use Candle indicator by default. - // However, in that case we need to specify applied price (excluding ASK and BID). - Indi_AMA* _indi_ama = new Indi_AMA(ama_params, IDATA_INDICATOR, indi_applied_price_on_price.Ptr()); + // 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); // @fixme - */ + indis.Push(_indi_ama); // Original AMA. IndiAMAParams ama_params_orig(); @@ -511,14 +527,14 @@ bool InitIndicators() { // Math (specialized indicator). IndiMathParams math_params(MATH_OP_SUB, BAND_UPPER, BAND_LOWER, 0, 0); - math_params.SetDraw(clrBlue); + // 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()); // Math (specialized indicator) via custom math method. IndiMathParams math_custom_params(MathCustomOp, BAND_UPPER, BAND_LOWER, 0, 0); - math_custom_params.SetDraw(clrBeige); + // 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()); @@ -539,11 +555,6 @@ bool InitIndicators() { CandleParams candle_params(); indis.Push(new Indi_Candle(candle_params)); - // Mark all as untested. - for (DictIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - tested.Set(iter.Key(), false); - } - // Push white-listed indicators here. // whitelisted_indis.Push(_indi_test); @@ -556,7 +567,7 @@ 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) { + for (DictIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { if (whitelisted_indis.Size() != 0 && !whitelisted_indis.Contains(iter.Value())) { continue; } @@ -565,6 +576,7 @@ bool PrintIndicators(string _prefix = "") { if (_indi.GetModeCount() == 0) { // Indicator has no modes. + PrintFormat("Skipping %s as it has no modes.", _indi.GetFullName()); continue; } @@ -575,7 +587,7 @@ bool PrintIndicators(string _prefix = "") { ResetLastError(); continue; } - if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { + if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString(0)); } } diff --git a/tests/OrderTest.mq5 b/tests/OrderTest.mq5 index e5ad00135..a8a25bfab 100644 --- a/tests/OrderTest.mq5 +++ b/tests/OrderTest.mq5 @@ -27,6 +27,7 @@ // Includes. #include "../Chart.mqh" #include "../Order.mqh" +#include "../Platform.h" #include "../SerializerConverter.mqh" #include "../SerializerJson.mqh" #include "../Test.mqh" @@ -35,10 +36,10 @@ #define MAX_ORDERS 10 // Global variables. +Ref _candles; int bar_processed = 0; bool stop = false; -Chart *chart; Order *orders[MAX_ORDERS]; Order *orders_dummy[MAX_ORDERS]; @@ -46,8 +47,9 @@ Order *orders_dummy[MAX_ORDERS]; * Implements Init event handler. */ int OnInit() { + Platform::Init(); + _candles = Platform::FetchDefaultCandleIndicator(); bool _result = true; - chart = new Chart(PERIOD_M1); bar_processed = 0; assertTrueOrFail(GetLastError() == ERR_NO_ERROR, StringFormat("Error: %d!", GetLastError())); return _result ? INIT_SUCCEEDED : INIT_FAILED; @@ -57,7 +59,9 @@ int OnInit() { * Implements Tick event handler. */ void OnTick() { - if (chart.IsNewBar()) { + Platform::Tick(); + + if (_candles REF_DEREF IsNewBar()) { bool _order_result; if (bar_processed < MAX_ORDERS) { @@ -70,9 +74,10 @@ void OnTick() { switch (_order.Get(ORDER_TYPE)) { case ORDER_TYPE_BUY: if (_order.IsOpen()) { - string order_comment = StringFormat("Closing order: %d", _index + 1); + string order_comment = StringFormat("Closing order %d at index %d", _order.OrderTicket(), _index + 1); _order_result = _order.OrderClose(ORDER_REASON_CLOSED_BY_TEST, order_comment); - assertTrueOrExit(_order_result, StringFormat("Order not closed (last error: %d)!", GetLastError())); + assertTrueOrExit(_order_result, StringFormat("Order %d not closed (last error: %d)!", _order.OrderTicket(), + GetLastError())); } break; case ORDER_TYPE_SELL: @@ -80,8 +85,9 @@ void OnTick() { _order.Refresh(); break; } - assertFalseOrExit(_order.IsOpen(), "Order not closed!"); - assertTrueOrExit(_order.Get(ORDER_PROP_TIME_CLOSED) > 0, "Order close time not correct!"); + assertFalseOrExit(_order.IsOpen(true), StringFormat("Order %d not closed!", _order.OrderTicket())); + assertTrueOrExit(_order.Get(ORDER_PROP_TIME_CLOSED) > 0, + StringFormat("Order %d close time not correct!", _order.OrderTicket())); } bar_processed++; } @@ -99,10 +105,10 @@ bool OpenOrder(int _index, int _order_no) { _request.deviation = 50; _request.magic = _order_no; _request.type = bar_processed % 2 == 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; - _request.price = chart.GetOpenOffer(_request.type); - _request.symbol = chart.GetSymbol(); + _request.price = _candles REF_DEREF GetOpenOffer(_request.type); + _request.symbol = _candles REF_DEREF GetSymbol(); _request.type_filling = Order::GetOrderFilling(_request.symbol); - _request.volume = chart.GetVolumeMin(); + _request.volume = _candles REF_DEREF GetSymbolProps().GetVolumeMin(); // New order params. OrderParams _oparams; if (_request.type == ORDER_TYPE_SELL) { @@ -118,7 +124,7 @@ bool OpenOrder(int _index, int _order_no) { Order *_order; _order = orders[_index] = new Order(_request, _oparams); _result = _order.GetResult(); - assertTrueOrReturn(_result.retcode == TRADE_RETCODE_DONE, "Request not completed!", false); + assertEqualOrReturn(_result.retcode, TRADE_RETCODE_DONE, "Request not completed!", false); // assertTrueOrReturn(_order.GetData().price_current > 0, "Order's symbol price not correct!", false); // @fixme // Assign the closing condition for the buy orders. // Make a dummy order. @@ -128,7 +134,7 @@ bool OpenOrder(int _index, int _order_no) { _request.comment = StringFormat("Order dummy: %d", _order_no); _order_dummy = orders_dummy[_index] = new Order(_request, oparams_dummy); _result_dummy = _order_dummy.GetResult(); - assertTrueOrReturn(_result.retcode == _result.retcode, "Dummy order not completed!", false); + assertEqualOrReturn(_result.retcode, TRADE_RETCODE_DONE, "Dummy order not completed!", false); /* @todo Print("Request: ", SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()); @@ -160,7 +166,6 @@ bool CloseOrder(int _index, int _order_no) { * Implements Deinit event handler. */ void OnDeinit(const int reason) { - delete chart; for (int i = 0; i < fmin(bar_processed, MAX_ORDERS); i++) { if (CheckPointer(orders[i]) == POINTER_DYNAMIC) { delete orders[i]; diff --git a/tests/StrategyTest-RSI.mq4 b/tests/StrategyTest-RSI.mq4 index 19b03e25b..eb6f64ea1 100644 --- a/tests/StrategyTest-RSI.mq4 +++ b/tests/StrategyTest-RSI.mq4 @@ -24,5 +24,7 @@ * Test functionality of Strategy class. */ +#define __debug__ + // Includes. #include "StrategyTest-RSI.mq5" diff --git a/tests/StrategyTest-RSI.mq5 b/tests/StrategyTest-RSI.mq5 index 90a0554fc..532c63442 100644 --- a/tests/StrategyTest-RSI.mq5 +++ b/tests/StrategyTest-RSI.mq5 @@ -24,8 +24,14 @@ * Test functionality of Strategy class. */ +//#define __debug__ +//#define __debug_verbose__ + // Includes. +#include "../ChartMt.h" +#include "../Indicator/tests/classes/IndicatorTfDummy.h" #include "../Indicators/Indi_RSI.mqh" +#include "../Indicators/Tick/Indi_TickMt.mqh" #include "../Strategy.mqh" #include "../Test.mqh" @@ -33,16 +39,17 @@ class Stg_RSI : public Strategy { public: // Class constructor. - void Stg_RSI(StgParams &_sparams, TradeParams &_tparams, ChartParams &_cparams, string _name = "") - : Strategy(_sparams, _tparams, chart_params_defaults, _name) {} + void Stg_RSI(StgParams &_sparams, TradeParams &_tparams, IndicatorData *_indi_source, string _name = "") + : Strategy(_sparams, _tparams, _indi_source, _name) {} - static Stg_RSI *Init(ENUM_TIMEFRAMES _tf = NULL) { - ChartParams _cparams(_tf); + static Stg_RSI *Init(IndicatorData *_indi_source) { IndiRSIParams _indi_params(12, PRICE_OPEN, 0); StgParams _stg_params; TradeParams _tparams; - Strategy *_strat = new Stg_RSI(_stg_params, _tparams, _cparams, "RSI"); - _strat.SetIndicator(new Indi_RSI(_indi_params)); + Strategy *_strat = new Stg_RSI(_stg_params, _tparams, _indi_source, "RSI"); + IndicatorData *_indi_rsi = new Indi_RSI(_indi_params); + _strat.SetIndicator(_indi_rsi); + _indi_rsi PTR_DEREF SetDataSource(_indi_source); return _strat; } @@ -60,7 +67,7 @@ class Stg_RSI : public Strategy { float PriceStop(ENUM_ORDER_TYPE _cmd, ENUM_ORDER_TYPE_VALUE _mode, int _method = 0, float _level = 0.0) { Indi_RSI *_indi = GetIndicator(); - IndiRSIParams _iparams = _indi.GetParams();; + IndiRSIParams _iparams = _indi.GetParams(); double _trail = _level * Market().GetPipSize(); int _direction = Order::OrderDirection(_cmd, _mode); return _direction > 0 ? (float)_indi.GetPrice(PRICE_HIGH, _indi.GetHighest(_iparams.GetPeriod() * 2)) @@ -75,33 +82,35 @@ class Stg_RSI : public Strategy { }; // Global variables. -Strategy *stg_rsi; -Trade *trade; +Ref stg_rsi; +Ref trade; +Ref _candles; /** * Implements OnInit(). */ int OnInit() { + Platform::Init(); + // Initialize strategy instance. - stg_rsi = Stg_RSI::Init(PERIOD_CURRENT); - stg_rsi.SetName("Stg_RSI"); - stg_rsi.Set(STRAT_PARAM_ID, 1234); + stg_rsi = Stg_RSI::Init(_candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_M5)); + stg_rsi REF_DEREF SetName("Stg_RSI"); + stg_rsi REF_DEREF Set(STRAT_PARAM_ID, 1234); // Initialize trade instance. - ChartParams _cparams((ENUM_TIMEFRAMES)_Period, _Symbol); TradeParams _tparams; - trade = new Trade(_tparams, _cparams); + trade = new Trade(_tparams, _candles.Ptr()); - assertTrueOrFail(stg_rsi.GetName() == "Stg_RSI", "Invalid Strategy name!"); - assertTrueOrFail(stg_rsi.IsValid(), "Fail on IsValid()!"); - // assertTrueOrFail(stg_rsi.GetMagicNo() == 1234, "Invalid magic number!"); + assertTrueOrFail(stg_rsi REF_DEREF GetName() == "Stg_RSI", "Invalid Strategy name!"); + assertTrueOrFail(stg_rsi REF_DEREF IsValid(), "Fail on IsValid()!"); + // assertTrueOrFail(stg_rsi REF_DEREF GetMagicNo() == 1234, "Invalid magic number!"); // Test whether strategy is enabled and not suspended. - assertTrueOrFail(stg_rsi.IsEnabled(), "Fail on IsEnabled()!"); - assertFalseOrFail(stg_rsi.IsSuspended(), "Fail on IsSuspended()!"); + assertTrueOrFail(stg_rsi REF_DEREF IsEnabled(), "Fail on IsEnabled()!"); + assertFalseOrFail(stg_rsi REF_DEREF IsSuspended(), "Fail on IsSuspended()!"); // Output. - Print(stg_rsi.ToString()); + Print(stg_rsi REF_DEREF ToString()); // Check for errors. long _last_error = GetLastError(); @@ -115,49 +124,45 @@ int OnInit() { * Implements OnTick(). */ void OnTick() { - static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); - if (_tick_new.time % 60 < _tick_last.time % 60) { - if (stg_rsi.SignalOpen(ORDER_TYPE_BUY)) { - MqlTradeRequest _request = - trade.GetTradeOpenRequest(ORDER_TYPE_BUY, 0, stg_rsi.Get(STRAT_PARAM_ID), stg_rsi.GetName()); - trade.RequestSend(_request); - } else if (stg_rsi.SignalOpen(ORDER_TYPE_SELL)) { - MqlTradeRequest _request = - trade.GetTradeOpenRequest(ORDER_TYPE_SELL, 0, stg_rsi.Get(STRAT_PARAM_ID), stg_rsi.GetName()); - trade.RequestSend(_request); + Platform::Tick(); + + if (Platform::IsNewMinute()) { + if (stg_rsi REF_DEREF SignalOpen(ORDER_TYPE_BUY)) { + MqlTradeRequest _request = trade REF_DEREF GetTradeOpenRequest( + ORDER_TYPE_BUY, 0, stg_rsi REF_DEREF Get(STRAT_PARAM_ID), stg_rsi REF_DEREF GetName()); + trade REF_DEREF RequestSend(_request); + } else if (stg_rsi REF_DEREF SignalOpen(ORDER_TYPE_SELL)) { + MqlTradeRequest _request = trade REF_DEREF GetTradeOpenRequest( + ORDER_TYPE_SELL, 0, stg_rsi REF_DEREF Get(STRAT_PARAM_ID), stg_rsi REF_DEREF GetName()); + trade REF_DEREF RequestSend(_request); } - if (trade.Get(TRADE_STATE_ORDERS_ACTIVE)) { - if (stg_rsi.SignalClose(ORDER_TYPE_BUY)) { + if (trade REF_DEREF Get(TRADE_STATE_ORDERS_ACTIVE)) { + if (stg_rsi REF_DEREF SignalClose(ORDER_TYPE_BUY)) { // Close signal for buy order. - trade.OrdersCloseViaProp2( - ORDER_MAGIC, stg_rsi.Get(STRAT_PARAM_ID), ORDER_TYPE, ORDER_TYPE_BUY, MATH_COND_EQ, - ORDER_REASON_CLOSED_BY_SIGNAL, stg_rsi.GetOrderCloseComment()); + trade REF_DEREF OrdersCloseViaProp2( + ORDER_MAGIC, stg_rsi REF_DEREF Get(STRAT_PARAM_ID), ORDER_TYPE, ORDER_TYPE_BUY, MATH_COND_EQ, + ORDER_REASON_CLOSED_BY_SIGNAL, stg_rsi REF_DEREF GetOrderCloseComment()); } - if (stg_rsi.SignalClose(ORDER_TYPE_SELL)) { - trade.OrdersCloseViaProp2( - ORDER_MAGIC, stg_rsi.Get(STRAT_PARAM_ID), ORDER_TYPE, ORDER_TYPE_SELL, MATH_COND_EQ, - ORDER_REASON_CLOSED_BY_SIGNAL, stg_rsi.GetOrderCloseComment()); + if (stg_rsi REF_DEREF SignalClose(ORDER_TYPE_SELL)) { + trade REF_DEREF OrdersCloseViaProp2( + ORDER_MAGIC, stg_rsi REF_DEREF Get(STRAT_PARAM_ID), ORDER_TYPE, ORDER_TYPE_SELL, MATH_COND_EQ, + ORDER_REASON_CLOSED_BY_SIGNAL, stg_rsi REF_DEREF GetOrderCloseComment()); } } - if (_tick_new.time % 3600 < _tick_last.time % 3600) { - stg_rsi.ProcessTasks(); - trade.UpdateStates(); + if (Platform::IsNewHour()) { + stg_rsi REF_DEREF ProcessTasks(); + trade REF_DEREF UpdateStates(); // Print strategy values every hour. - Print(stg_rsi.ToString()); + Print(stg_rsi REF_DEREF ToString()); } long _last_error = GetLastError(); if (_last_error > 0) { assertTrueOrExit(_last_error == ERR_NO_ERROR, StringFormat("Error occured! Code: %d", _last_error)); } } - _tick_last = _tick_new; } /** * Implements OnDeinit(). */ -void OnDeinit(const int reason) { - delete stg_rsi; - delete trade; -} +void OnDeinit(const int reason) {} diff --git a/tests/StrategyTest.mq5 b/tests/StrategyTest.mq5 index 9f2c95879..06de56370 100644 --- a/tests/StrategyTest.mq5 +++ b/tests/StrategyTest.mq5 @@ -36,9 +36,9 @@ struct DataParamEntry; class Stg1 : public Strategy { public: // Class constructor. - void Stg1(StgParams &_params, string _name = "") - : Strategy(_params, trade_params_defaults, chart_params_defaults, _name) {} - void OnInit() { trade.tparams.SetMagicNo(1234); } + void Stg1(StgParams &_params, IndicatorBase *_source, string _name = "") + : Strategy(_params, trade_params_defaults, _source, _name) {} + void OnInit() { trade REF_DEREF tparams.SetMagicNo(1234); } bool SignalOpen(ENUM_ORDER_TYPE _cmd, int _method, float _level, int _shift) { return _method % 2 == 0; } @@ -56,8 +56,8 @@ class Stg1 : public Strategy { class Stg2 : public Strategy { public: // Class constructor. - void Stg2(StgParams &_params, string _name = "") - : Strategy(_params, trade_params_defaults, chart_params_defaults, _name) {} + void Stg2(StgParams &_params, IndicatorBase *_source, string _name = "") + : Strategy(_params, trade_params_defaults, _source, _name) {} void OnInit() { ddata.Set(1, 1.1); fdata.Set(1, 1.1f); @@ -85,6 +85,9 @@ Strategy *strat2; * Implements OnInit(). */ int OnInit() { + Platform::Init(); + Ref _source = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); + // Initial market tests. assertTrueOrFail(SymbolInfoStatic::GetAsk(_Symbol) > 0, "Invalid Ask price!"); @@ -92,7 +95,7 @@ int OnInit() { // Initialize strategy. StgParams stg1_params; - strat1 = new Stg1(stg1_params, "Stg1"); + strat1 = new Stg1(stg1_params, _source.Ptr(), "Stg1"); assertTrueOrFail(strat1.GetName() == "Stg1", "Invalid Strategy name!"); assertTrueOrFail(strat1.IsValid(), "Fail on IsValid()!"); // assertTrueOrFail(strat1.GetMagicNo() == 1234, "Invalid magic number!"); @@ -112,7 +115,7 @@ int OnInit() { StgParams stg2_params; stg2_params.Enabled(false); stg2_params.Suspended(true); - strat2 = new Stg2(stg2_params); + strat2 = new Stg2(stg2_params, _source.Ptr()); strat2.SetIndicator(new Indi_Demo(iparams)); strat2.SetName("Stg2"); assertTrueOrFail(strat2.GetName() == "Stg2", "Invalid Strategy name!"); diff --git a/tests/TradeTest.mq5 b/tests/TradeTest.mq5 index 022203d7f..0d0de3356 100644 --- a/tests/TradeTest.mq5 +++ b/tests/TradeTest.mq5 @@ -24,56 +24,94 @@ * Test functionality of Trade class. */ +// #define __debug__ +// #define __debug_verbose__ + // Forward declaration. struct DataParamEntry; // Includes. +#include "../ChartMt.h" +#include "../Indicators/Tick/Indi_TickMt.mqh" +#include "../Platform.h" #include "../Test.mqh" #include "../Trade.mqh" +Ref _chart_m1; +Ref _chart_m5; +bool _finish_test = false; + /** * Implements OnInit(). */ 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()); + return INIT_SUCCEEDED; +} + +void OnTick() { + if (_finish_test) { + // We don't need to process further ticks. + return; + } + Platform::Tick(); + // We need some bars in order to make trades. + if (_chart_m5 REF_DEREF GetBarIndex() > trade_params_defaults.GetBarsMin()) { + if (Test() == INIT_FAILED) { + Print("ERROR: Test failed!"); + } + // We only want to test on a single (late) bar. + _finish_test = true; + } +} + +/** + * Testing Trade class. Returns INIT_FAILED on failure. + */ +int Test() { // Initial market tests. assertTrueOrFail(SymbolInfoStatic::GetAsk(_Symbol) > 0, "Invalid Ask price!"); // Test 1. - ChartParams _cparams_m1(PERIOD_M1, _Symbol); - Trade *trade1 = new Trade(trade_params_defaults, _cparams_m1); + + Trade *trade1 = new Trade(trade_params_defaults, _chart_m1.Ptr()); // Test market. - assertTrueOrFail(trade1.IsTradeAllowed(), "Trade not allowed!"); - assertTrueOrFail(trade1.Get(CHART_PARAM_TF) == PERIOD_M1, - StringFormat("Fail on GetTf() => [%s]!", trade1.Get(CHART_PARAM_TF))); - assertTrueOrFail(trade1.GetChart().GetOpen() > 0, "Fail on GetOpen()!"); - assertTrueOrFail(trade1.GetChart().Get(CHART_PARAM_SYMBOL) == _Symbol, "Fail on GetSymbol()!"); + 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())); + 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 - assertTrueOrFail( - trade1.GetTradeDistanceInPts() >= 0 && trade1.GetTradeDistanceInPts() == Trade::GetTradeDistanceInPts(_Symbol), - "Invalid GetTradeDistanceInPts()!"); - assertTrueOrFail( - trade1.GetTradeDistanceInPips() >= 0 && trade1.GetTradeDistanceInPips() == Trade::GetTradeDistanceInPips(_Symbol), - "Invalid GetTradeDistanceInPips()!"); - assertTrueOrFail(trade1.GetTradeDistanceInValue() >= 0 && - (float)trade1.GetTradeDistanceInValue() == (float)Trade::GetTradeDistanceInValue(_Symbol), + assertTrueOrFail(trade1 PTR_DEREF GetTradeDistanceInPts() >= 0 && + trade1 PTR_DEREF GetTradeDistanceInPts() == Trade::GetTradeDistanceInPts(_Symbol), + "Invalid GetTradeDistanceInPts()!"); + assertTrueOrFail(trade1 PTR_DEREF GetTradeDistanceInPips() >= 0 && + trade1 PTR_DEREF GetTradeDistanceInPips() == Trade::GetTradeDistanceInPips(_Symbol), + "Invalid GetTradeDistanceInPips()!"); + assertTrueOrFail(trade1.GetTradeDistanceInValue() >= 0 && (float)trade1 PTR_DEREF GetTradeDistanceInValue() == + (float)Trade::GetTradeDistanceInValue(_Symbol), "Invalid GetTradeDistanceInValue()!"); - Print("Trade1: ", trade1.ToString()); + Print("Trade1: ", trade1 PTR_DEREF ToString()); // Clean up. delete trade1; // Test 2. - ChartParams _cparams_m5(PERIOD_M5, _Symbol); - Trade *trade2 = new Trade(trade_params_defaults, _cparams_m5); + Trade *trade2 = new Trade(trade_params_defaults, _chart_m5.Ptr()); // Test market. - assertTrueOrFail(trade2.Get(CHART_PARAM_TF) == PERIOD_M5, - StringFormat("Fail on GetTf() => [%s]!", EnumToString(trade2.Get(CHART_PARAM_TF)))); - assertTrueOrFail(trade2.GetChart().GetOpen() > 0, "Fail on GetOpen()!"); - assertTrueOrFail(trade2.GetChart().GetSymbol() == _Symbol, "Fail on GetSymbol()!"); - assertTrueOrFail(trade2.IsTradeAllowed(), "Fail on IsTradeAllowed()!"); - Print("Trade2: ", trade2.ToString()); + assertTrueOrFail( + trade2 PTR_DEREF GetSource() PTR_DEREF GetTf() == PERIOD_M5, + StringFormat("Fail on GetTf() => [%s]!", EnumToString(trade2 PTR_DEREF GetSource() PTR_DEREF GetTf()))); + assertTrueOrFail(trade2 PTR_DEREF GetSource() PTR_DEREF GetOpen() > 0, "Fail on GetOpen()!"); + assertTrueOrFail(trade2 PTR_DEREF GetSource() PTR_DEREF GetSymbol() == _Symbol, "Fail on GetSymbol()!"); + assertTrueOrFail(trade2 PTR_DEREF IsTradeAllowed(), "Fail on IsTradeAllowed()!"); + Print("Trade2: ", trade2 PTR_DEREF ToString()); // Clean up. delete trade2; @@ -110,5 +148,10 @@ int OnInit() { // assertTrueOrFail(tstats.GetOrderStats(TRADE_STAT_ORDERS_CLOSED, TRADE_STAT_PER_DAY) == 0, __FUNCTION_LINE__); // assertTrueOrFail(tstats.GetOrderStats(TRADE_STAT_ORDERS_OPENED, TRADE_STAT_PER_DAY) == 0, __FUNCTION_LINE__); - return GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; + if (_LastError != ERR_NO_ERROR) { + Print("Error: ", _LastError); + return INIT_FAILED; + } + + return INIT_SUCCEEDED; }