From 54f131e893dead7c6945ea3f6a007f363ca32d08 Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 28 Oct 2021 21:58:12 +0100 Subject: [PATCH 001/123] Chart: ChartTf: Adds SecsToTf() --- Chart.struct.tf.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 6c91b1c16..49c7c88f3 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -116,6 +116,69 @@ struct ChartTf { /* Static methods */ + /** + * Converts number of seconds per bar to chart's timeframe. + * + * @param _secs + * Number of seconds per one bar chart (OHLC). + * + * @return ENUM_TIMEFRAMES + * Returns enum representing chart's timeframe value. + */ + static ENUM_TIMEFRAMES SecsToTf(uint _secs = 0) { + switch (_secs) { + case 0: + return PERIOD_CURRENT; + case 60: + return PERIOD_M1; // 1 minute. + case 60 * 2: + return PERIOD_M2; // 2 minutes (non-standard). + case 60 * 3: + return PERIOD_M3; // 3 minutes (non-standard). + case 60 * 4: + return PERIOD_M4; // 4 minutes (non-standard). + case 60 * 5: + return PERIOD_M5; // 5 minutes. + case 60 * 6: + return PERIOD_M6; // 6 minutes (non-standard). + case 60 * 10: + return PERIOD_M10; // 10 minutes (non-standard). + case 60 * 12: + return PERIOD_M12; // 12 minutes (non-standard). + case 60 * 15: + return PERIOD_M15; // 15 minutes. + case 60 * 20: + return PERIOD_M20; // 20 minutes (non-standard). + case 60 * 30: + return PERIOD_M30; // 30 minutes. + case 60 * 60: + return PERIOD_H1; // 1 hour. + case 60 * 60 * 2: + return PERIOD_H2; // 2 hours (non-standard). + case 60 * 60 * 3: + return PERIOD_H3; // 3 hours (non-standard). + case 60 * 60 * 4: + return PERIOD_H4; // 4 hours. + case 60 * 60 * 6: + return PERIOD_H6; // 6 hours (non-standard). + case 60 * 60 * 8: + return PERIOD_H8; // 8 hours (non-standard). + case 60 * 60 * 12: + return PERIOD_H12; // 12 hours (non-standard). + case 60 * 60 * 24: + return PERIOD_D1; // Daily. + case 60 * 60 * 24 * 7: + return PERIOD_W1; // Weekly. + default: + break; + } + if (_secs >= 60 * 60 * 24 * 28 && _secs <= 60 * 60 * 24 * 31) { + return PERIOD_MN1; // Monthly range. + } + SetUserError(ERR_INVALID_PARAMETER); + return PERIOD_CURRENT; + } + /** * Convert period to proper chart timeframe value. * From b706c3ded709c81021acd06521155ea476542f33 Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 28 Oct 2021 21:59:49 +0100 Subject: [PATCH 002/123] Indicator: Removes Chart inheritance (1st part of refactor) [WIP] --- EA.mqh | 2 + Indicator.mqh | 93 ++++++++++++------------- Indicator.struct.h | 40 ++++++++++- IndicatorBase.h | 73 ++++--------------- Indicators/Indi_AC.mqh | 4 +- Indicators/Indi_AD.mqh | 4 +- Indicators/Indi_ADX.mqh | 4 +- Indicators/Indi_ADXW.mqh | 4 +- Indicators/Indi_AMA.mqh | 6 +- Indicators/Indi_AO.mqh | 4 +- Indicators/Indi_ASI.mqh | 4 +- Indicators/Indi_ATR.mqh | 4 +- Indicators/Indi_Alligator.mqh | 4 +- Indicators/Indi_BWMFI.mqh | 4 +- Indicators/Indi_BWZT.mqh | 4 +- Indicators/Indi_Bands.mqh | 8 +-- Indicators/Indi_BearsPower.mqh | 4 +- Indicators/Indi_BullsPower.mqh | 4 +- Indicators/Indi_CCI.mqh | 6 +- Indicators/Indi_CHO.mqh | 4 +- Indicators/Indi_CHV.mqh | 4 +- Indicators/Indi_ColorBars.mqh | 4 +- Indicators/Indi_ColorCandlesDaily.mqh | 4 +- Indicators/Indi_ColorLine.mqh | 4 +- Indicators/Indi_CustomMovingAverage.mqh | 2 +- Indicators/Indi_DEMA.mqh | 4 +- Indicators/Indi_DeMarker.mqh | 6 +- Indicators/Indi_Demo.mqh | 2 +- Indicators/Indi_DetrendedPrice.mqh | 8 +-- Indicators/Indi_Drawer.mqh | 4 +- Indicators/Indi_Envelopes.mqh | 6 +- Indicators/Indi_Force.mqh | 5 +- Indicators/Indi_FractalAdaptiveMA.mqh | 4 +- Indicators/Indi_Fractals.mqh | 4 +- Indicators/Indi_Gator.mqh | 6 +- Indicators/Indi_HeikenAshi.mqh | 6 +- Indicators/Indi_Ichimoku.mqh | 4 +- Indicators/Indi_MA.mqh | 8 +-- Indicators/Indi_MACD.mqh | 7 +- Indicators/Indi_MFI.mqh | 6 +- Indicators/Indi_MassIndex.mqh | 4 +- Indicators/Indi_Momentum.mqh | 8 +-- Indicators/Indi_OBV.mqh | 8 +-- Indicators/Indi_OsMA.mqh | 7 +- Indicators/Indi_Pivot.mqh | 2 + Indicators/Indi_Price.mqh | 12 ++-- Indicators/Indi_PriceChannel.mqh | 4 +- Indicators/Indi_PriceVolumeTrend.mqh | 5 +- Indicators/Indi_RS.mqh | 2 +- Indicators/Indi_RSI.mqh | 6 +- Indicators/Indi_RVI.mqh | 4 +- Indicators/Indi_RateOfChange.mqh | 8 +-- Indicators/Indi_SAR.mqh | 4 +- Indicators/Indi_StdDev.mqh | 11 ++- Indicators/Indi_Stochastic.mqh | 6 +- Indicators/Indi_TEMA.mqh | 4 +- Indicators/Indi_TRIX.mqh | 6 +- Indicators/Indi_UltimateOscillator.mqh | 8 +-- Indicators/Indi_VIDYA.mqh | 4 +- Indicators/Indi_VROC.mqh | 6 +- Indicators/Indi_Volumes.mqh | 4 +- Indicators/Indi_WPR.mqh | 6 +- Indicators/Indi_WilliamsAD.mqh | 4 +- Indicators/Indi_ZigZag.mqh | 4 +- Indicators/Indi_ZigZagColor.mqh | 2 +- Indicators/Special/Indi_Math.mqh | 12 ++-- Storage/ValueStorage.indicator.h | 2 +- 67 files changed, 256 insertions(+), 275 deletions(-) diff --git a/EA.mqh b/EA.mqh index e74822cf8..785c82b22 100644 --- a/EA.mqh +++ b/EA.mqh @@ -450,6 +450,7 @@ class EA { ChartEntry _entry = Chart().GetEntry(); data_chart.Add(_entry, _entry.bar.ohlc.time); } + /* @fixme if (eparams.CheckFlagDataStore(EA_DATA_STORE_INDICATOR)) { for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { Strategy *_strati = iter.Value().Ptr(); @@ -467,6 +468,7 @@ class EA { } } } + */ /* if (eparams.CheckFlagDataStore(EA_DATA_STORE_STRATEGY)) { for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { diff --git a/Indicator.mqh b/Indicator.mqh index 3717c10aa..19169ce52 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -78,7 +78,7 @@ class Indicator : public IndicatorBase { * Class constructor. */ Indicator(const TS& _iparams, IndicatorBase* _indi_src = NULL, bool _indi_managed = true, int _indi_mode = 0) - : IndicatorBase(_iparams.GetTf(), NULL) { + : IndicatorBase(_indi_src) { iparams = _iparams; SetName(_iparams.name != "" ? _iparams.name : EnumToString(iparams.itype)); if (_indi_src != NULL) { @@ -86,13 +86,7 @@ class Indicator : public IndicatorBase { } Init(); } - Indicator(const TS& _iparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorBase(_tf) { - iparams = _iparams; - SetName(_iparams.name != "" ? _iparams.name : EnumToString(iparams.itype)); - Init(); - } - Indicator(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "") - : IndicatorBase(_tf) { + Indicator(ENUM_INDICATOR_TYPE _itype, int _shift = 0, string _name = "") { iparams.SetIndicatorType(_itype); iparams.SetShift(_shift); SetName(_name != "" ? _name : EnumToString(iparams.itype)); @@ -158,11 +152,19 @@ class Indicator : public IndicatorBase { /* Getters */ + /** + * Gets an indicator's property value. + */ + template + T Get(STRUCT_ENUM(IndicatorParams, ENUM_INDI_PARAMS_PROP) _param) const { + return iparams.Get(_param); + } + /** * Gets an indicator property flag. */ - bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, int _shift = -1) { - IndicatorDataEntry _entry = GetEntry(_shift >= 0 ? _shift : iparams.GetShift()); + bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, datetime _bar_time) { + IndicatorDataEntry _entry = GetEntry(_bar_time); return _entry.CheckFlag(_prop); } @@ -262,6 +264,7 @@ class Indicator : public IndicatorBase { * Returns true of successful copy. * Returns false on invalid values. */ + /* @todo bool CopyEntries(IndicatorDataEntry& _data[], int _count, int _start_shift = 0) { bool _is_valid = true; if (ArraySize(_data) < _count) { @@ -274,6 +277,7 @@ class Indicator : public IndicatorBase { } return _is_valid; } + */ /** * Gets indicator data from a buffer and copy into array of values. @@ -407,7 +411,7 @@ class Indicator : public IndicatorBase { /** * Access indicator entry data using [] operator. */ - IndicatorDataEntry operator[](int _shift) { return GetEntry(_shift); } + // IndicatorDataEntry operator[](int _shift) { return GetEntry(_shift); } IndicatorDataEntry operator[](ENUM_INDICATOR_INDEX _shift) { return GetEntry(_shift); } IndicatorDataEntry operator[](datetime _dt) { return idata[_dt]; } @@ -575,6 +579,13 @@ class Indicator : public IndicatorBase { */ virtual int GetModeCount() { return 0; } + /** + * Gets indicator's timeframe. + */ + ENUM_TIMEFRAMES GetTf() { + return ChartTf::SecsToTf(iparams.Get(STRUCT_ENUM(IndicatorParams, INDI_PARAMS_PROP_BPS))); + } + /** * Whether data source is selected. */ @@ -585,21 +596,12 @@ class Indicator : public IndicatorBase { */ 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 signals. * * When indicator values are not valid, returns empty signals. */ + /* @todo IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) { bool _is_valid = true; IndicatorDataEntry _data[]; @@ -612,6 +614,7 @@ class Indicator : public IndicatorBase { IndicatorSignal _signals(_data, iparams, cparams, _mode1, _mode2); return _signals; } + */ /** * Get pointer to data of indicator. @@ -660,8 +663,8 @@ class Indicator : public IndicatorBase { * Sets an indicator's chart parameter value. */ template - void Set(ENUM_CHART_PARAM _param, T _value) { - Chart::Set(_param, _value); + void Set(STRUCT_ENUM(IndicatorParams, ENUM_INDI_PARAMS_PROP) _param, T _value) { + iparams.Set(_param, _value); } /** @@ -692,11 +695,6 @@ class Indicator : public IndicatorBase { */ void SetParams(IndicatorParams& _iparams) { iparams = _iparams; } - /** - * Sets indicator's symbol. - */ - void SetSymbol(string _symbol) { Set(CHART_PARAM_SYMBOL, _symbol); } - /* Conditions */ /** @@ -734,7 +732,7 @@ class Indicator : public IndicatorBase { // Indicator entry value is lesser than median. return false; default: - GetLogger().Error(StringFormat("Invalid indicator condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); return false; } } @@ -762,7 +760,7 @@ class Indicator : public IndicatorBase { idata.Clear(_arg1); return true; default: - GetLogger().Error(StringFormat("Invalid Indicator action: %s!", EnumToString(_action), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); return false; } return _result; @@ -799,6 +797,7 @@ class Indicator : public IndicatorBase { /** * Checks whether indicator has a valid value for a given shift. */ + /* @todo virtual bool HasValidEntry(int _shift = 0) { unsigned int position; long bar_time = GetBarTime(_shift); @@ -809,18 +808,18 @@ class Indicator : public IndicatorBase { return false; } + */ /** * Adds entry to the indicator's buffer. Invalid entry won't be added. */ - bool AddEntry(IndicatorDataEntry& entry, int _shift = 0) { - if (!entry.IsValid()) return false; - - datetime timestamp = GetBarTime(_shift); - entry.timestamp = timestamp; - idata.Add(entry, timestamp); - - return true; + bool AddEntry(IndicatorDataEntry& entry, datetime _timestamp = 0) { + if (entry.IsValid()) { + entry.timestamp = _timestamp; + idata.Add(entry, _timestamp); + return true; + } + return false; } /** @@ -874,8 +873,8 @@ class Indicator : public IndicatorBase { ENUM_IDATA_VALUE_RANGE GetIDataValueRange() { return iparams.idvrange; } + /* @todo virtual void OnTick() { - Chart::OnTick(); if (iparams.is_draw) { // Print("Drawing ", GetName(), iparams.indi_data != NULL ? (" (over " + iparams.indi_data.GetName() + ")") : ""); @@ -884,6 +883,7 @@ class Indicator : public IndicatorBase { GetBarTime(0), GetEntry(0)[i], iparams.draw_window); } } + */ /* Data representation methods */ @@ -935,14 +935,13 @@ class Indicator : public IndicatorBase { * @return * Returns IndicatorDataEntry struct filled with indicator values. */ - virtual IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); + virtual IndicatorDataEntry GetEntry(datetime _bar_time = 0) { IndicatorDataEntry _entry = idata.GetByKey(_bar_time); if (!_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) { _entry.Resize(iparams.GetMaxModes()); - _entry.timestamp = GetBarTime(_shift); + _entry.timestamp = _bar_time; for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); + // _entry.values[_mode] = GetValue(_mode, _shift); // @todo } _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); @@ -958,9 +957,9 @@ class Indicator : public IndicatorBase { /** * Returns the indicator's entry value. */ - virtual MqlParam GetEntryValue(int _shift = 0, int _mode = 0) { + virtual MqlParam GetEntryValue(datetime _bar_time = 0, int _mode = 0) { MqlParam _param = {TYPE_FLOAT}; - _param.double_value = (float)GetEntry(_shift).GetValue(_mode); + _param.double_value = (float)GetEntry(_bar_time).GetValue(_mode); return _param; } @@ -976,8 +975,8 @@ class Indicator : public IndicatorBase { /** * Returns the indicator's value in plain format. */ - virtual string ToString(int _shift = 0) { - IndicatorDataEntry _entry = GetEntry(_shift); + virtual string ToString(datetime _bar_time = 0) { + IndicatorDataEntry _entry = GetEntry(_bar_time); int _serializer_flags = SERIALIZER_FLAG_SKIP_HIDDEN | SERIALIZER_FLAG_INCLUDE_DEFAULT | SERIALIZER_FLAG_INCLUDE_DYNAMIC; SerializerConverter _stub_indi = diff --git a/Indicator.struct.h b/Indicator.struct.h index 8bedbd5b0..6f1ad7581 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -354,6 +354,9 @@ struct IndicatorDataEntry { /* Structure for indicator parameters. */ struct IndicatorParams { + protected: + void Init() {} + public: // @todo: Change it to protected. string name; // Name of the indicator. int shift; // Shift (relative to the current bar, 0 - default). @@ -373,14 +376,23 @@ struct IndicatorParams { ARRAY(DataParamEntry, input_params); // Indicator input params. bool is_draw; // Draw active. int draw_window; // Drawing window. + uint bps; // A candle chart per number of seconds (e.g. for M1 is 60). string custom_indi_name; // Name of the indicator passed to iCustom() method. + public: + /* Enumerations */ + // Defines action entry properties. + enum ENUM_INDI_PARAMS_PROP { + INDI_PARAMS_PROP_BPS, + }; + public: /* Special methods */ // Constructor. IndicatorParams(ENUM_INDICATOR_TYPE _itype = INDI_NONE, unsigned int _max_modes = 1, ENUM_DATATYPE _dtype = TYPE_DOUBLE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, string _name = "") - : custom_indi_name(""), + : bps(0), + custom_indi_name(""), dtype(_dtype), name(_name), shift(0), @@ -398,7 +410,8 @@ struct IndicatorParams { Init(); }; IndicatorParams(string _name, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) - : custom_indi_name(""), + : bps(0), + custom_indi_name(""), name(_name), shift(0), max_modes(1), @@ -419,8 +432,18 @@ struct IndicatorParams { tf.SetTf(_tf); } } - void Init() {} /* Getters */ + template + T Get(STRUCT_ENUM(IndicatorParams, ENUM_INDI_PARAMS_PROP) _prop) const { + switch (_prop) { + case INDI_PARAMS_PROP_BPS: // Bar chart per seconds. + return (T)bps; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } string GetCustomIndicatorName() const { return custom_indi_name; } int GetDataSourceId() const { return indi_data_source_id; } int GetDataSourceMode() const { return indi_data_source_mode; } @@ -454,6 +477,17 @@ struct IndicatorParams { return (T)WRONG_VALUE; } /* Setters */ + template + void Set(STRUCT_ENUM(IndicatorParams, ENUM_INDI_PARAMS_PROP) _prop, T _value) { + switch (_prop) { + case INDI_PARAMS_PROP_BPS: + flags = (uint)_value; + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + } void SetCustomIndicatorName(string _name) { custom_indi_name = _name; } void SetDataSourceMode(int _mode) { indi_data_source_mode = _mode; } void SetDataSourceType(ENUM_IDATA_SOURCE_TYPE _idstype) { idstype = _idstype; } diff --git a/IndicatorBase.h b/IndicatorBase.h index eed35dcdb..4338f9266 100644 --- a/IndicatorBase.h +++ b/IndicatorBase.h @@ -69,7 +69,7 @@ int IndicatorCounted(int _value = 0) { /** * Class to deal with indicators. */ -class IndicatorBase : public Chart { +class IndicatorBase : public Object { protected: BufferStruct idata; DrawIndicator* draw; @@ -102,28 +102,7 @@ class IndicatorBase : public Chart { /** * Class constructor. */ - IndicatorBase() : indi_src(NULL) { is_fed = false; } - - /** - * Class constructor. - */ - IndicatorBase(ChartParams& _cparams) : indi_src(NULL), Chart(_cparams) { is_fed = false; } - - /** - * Class constructor. - */ - IndicatorBase(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _symbol = NULL) : Chart(_tf, _symbol) { - is_fed = false; - indi_src = NULL; - } - - /** - * Class constructor. - */ - IndicatorBase(ENUM_TIMEFRAMES_INDEX _tfi, string _symbol = NULL) : Chart(_tfi, _symbol) { - is_fed = false; - indi_src = NULL; - } + IndicatorBase(IndicatorBase* _indi_src = NULL) : indi_src(_indi_src), is_fed(false) {} /** * Class deconstructor. @@ -422,14 +401,6 @@ class IndicatorBase : public Chart { */ IndicatorCalculateCache* GetCache() { return &cache; } - /** - * 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. */ @@ -578,16 +549,6 @@ class IndicatorBase : public Chart { int GetDataSourceMode() { return indi_src_mode; } - /** - * 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 signals. * @@ -630,14 +591,6 @@ class IndicatorBase : public Chart { /* Setters */ - /** - * Sets an indicator's chart parameter value. - */ - template - void Set(ENUM_CHART_PARAM _param, T _value) { - Chart::Set(_param, _value); - } - /** * Sets indicator data source. */ @@ -660,11 +613,6 @@ class IndicatorBase : public Chart { */ virtual void SetHandle(int _handle) {} - /** - * Sets indicator's symbol. - */ - void SetSymbol(string _symbol) { Set(CHART_PARAM_SYMBOL, _symbol); } - /* Conditions */ /** @@ -702,7 +650,7 @@ class IndicatorBase : public Chart { // Indicator entry value is lesser than median. return false; default: - GetLogger().Error(StringFormat("Invalid indicator condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); return false; } } @@ -730,7 +678,7 @@ class IndicatorBase : public Chart { idata.Clear(_arg1); return true; default: - GetLogger().Error(StringFormat("Invalid Indicator action: %s!", EnumToString(_action), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); return false; } return _result; @@ -768,12 +716,14 @@ class IndicatorBase : public Chart { * Checks whether indicator has a valid value for a given shift. */ virtual bool HasValidEntry(int _shift = 0) { + /* @todo unsigned int position; long bar_time = GetBarTime(_shift); if (idata.KeyExists(bar_time, position)) { return idata.GetByPos(position).IsValid(); } + */ return false; } @@ -784,9 +734,11 @@ class IndicatorBase : public Chart { bool AddEntry(IndicatorDataEntry& entry, int _shift = 0) { if (!entry.IsValid()) return false; + /* @todo datetime timestamp = GetBarTime(_shift); entry.timestamp = timestamp; idata.Add(entry, timestamp); + */ return true; } @@ -954,10 +906,7 @@ class IndicatorBase : public Chart { /** * Returns the indicator's struct value. */ - virtual IndicatorDataEntry GetEntry(int _shift = 0) { - IndicatorDataEntry _entry; - return _entry; - }; + virtual IndicatorDataEntry GetEntry(datetime _bar_time = 0) = NULL; /** * Returns the indicator's entry value. @@ -980,6 +929,7 @@ class IndicatorBase : public Chart { return SerializerConverter::FromObject(_entry, _serializer_flags).ToString(0, &_stub_indi); } + /* @todo int GetBarsCalculated() { int _bars = Bars(GetSymbol(), GetTf()); @@ -1004,6 +954,7 @@ class IndicatorBase : public Chart { // Assuming all entries are calculated (even if have invalid values). return _bars; } + */ }; /** @@ -1042,4 +993,4 @@ int CopyBuffer(IndicatorBase* _indi, int _mode, int _start, int _count, ValueSto /** * BarsCalculated()-compatible method to be used on Indicator instance. */ -int BarsCalculated(IndicatorBase* _indi) { return _indi.GetBarsCalculated(); } +// int BarsCalculated(IndicatorBase* _indi) { return _indi.GetBarsCalculated(); } // @todo diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index e280631f4..b0555e629 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -104,10 +104,10 @@ class Indi_AC : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_AC::iAC(GetSymbol(), GetTf(), _shift, THIS_PTR); + _value = Indi_AC::iAC(_Symbol, GetTf(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index b935032f5..1ebb55ef0 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -103,10 +103,10 @@ class Indi_AD : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_AD::iAD(GetSymbol(), GetTf(), _shift, THIS_PTR); + _value = Indi_AD::iAD(_Symbol, GetTf(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index 104c0ca15..1a4020a8a 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -121,10 +121,10 @@ class Indi_ADX : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_ADX::iADX(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _mode, _shift, THIS_PTR); + _value = Indi_ADX::iADX(_Symbol, GetTf(), GetPeriod(), GetAppliedPrice(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index ee8ac7436..8b9c49a6c 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -221,10 +221,10 @@ class Indi_ADXW : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_ADXW::iADXWilder(GetSymbol(), GetTf(), GetPeriod(), _mode, _shift, THIS_PTR); + _value = Indi_ADXW::iADXWilder(_Symbol, GetTf(), GetPeriod(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index 1e16b0a81..dced2b256 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -204,11 +204,11 @@ class Indi_AMA : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_AMA::iAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), - GetAMAShift(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); + _value = Indi_AMA::iAMA(_Symbol, GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), GetAMAShift(), + GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), GetAMAShift() /*]*/, _mode, _shift); break; diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index 8d974e9ae..c659a8c93 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -107,10 +107,10 @@ class Indi_AO : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_AO::iAO(GetSymbol(), GetTf(), _shift, _mode, THIS_PTR); + _value = Indi_AO::iAO(_Symbol, GetTf(), _shift, _mode, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index 9e2fa43b4..8ae876746 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -160,11 +160,11 @@ class Indi_ASI : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetMaximumPriceChanging() /*]*/, 0, _shift); break; case IDATA_ONCALCULATE: { - INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(GetSymbol(), GetTf(), + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_Symbol, GetTf(), Util::MakeKey("Indi_ASI", GetMaximumPriceChanging())); _value = iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, GetMaximumPriceChanging(), _mode, _shift, _cache); diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index 72e536663..d9ff1953b 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -108,10 +108,10 @@ class Indi_ATR : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_ATR::iATR(GetSymbol(), GetTf(), GetPeriod(), _shift, THIS_PTR); + _value = Indi_ATR::iATR(_Symbol, GetTf(), GetPeriod(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index 9784d0876..5fe9965e7 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -173,12 +173,12 @@ class Indi_Alligator : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Alligator::iAlligator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), + _value = Indi_Alligator::iAlligator(_Symbol, GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice(), (ENUM_ALLIGATOR_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice() diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index 60aae4aa8..73f75ee6f 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -118,10 +118,10 @@ class Indi_BWMFI : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_BWMFI::iBWMFI(GetSymbol(), GetTf(), _shift, (ENUM_BWMFI_BUFFER)_mode, THIS_PTR); + _value = Indi_BWMFI::iBWMFI(_Symbol, GetTf(), _shift, (ENUM_BWMFI_BUFFER)_mode, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_BWZT.mqh b/Indicators/Indi_BWZT.mqh index f57d94355..d8582ce24 100644 --- a/Indicators/Indi_BWZT.mqh +++ b/Indicators/Indi_BWZT.mqh @@ -164,10 +164,10 @@ class Indi_BWZT : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_BWZT::iBWZT(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_BWZT::iBWZT(_Symbol, GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index 36ec12abd..fd1b6560c 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -246,16 +246,16 @@ class Indi_Bands : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Bands::iBands(GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), - GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, _shift, THIS_PTR); + _value = Indi_Bands::iBands(_Symbol, GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), GetAppliedPrice(), + (ENUM_BANDS_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), GetBandsShift(), GetDeviation(), GetAppliedPrice() /* ] */, _mode, _shift); break; case IDATA_INDICATOR: // Calculating bands value from specified indicator. - _value = Indi_Bands::iBandsOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), + _value = Indi_Bands::iBandsOnIndicator(GetDataSource(), _Symbol, GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), (ENUM_BANDS_LINE)_mode, _shift, THIS_PTR); break; } diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index 1732a0c90..a972980d8 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -109,10 +109,10 @@ class Indi_BearsPower : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = _value = iBearsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _shift, THIS_PTR); + _value = _value = iBearsPower(_Symbol, GetTf(), GetPeriod(), GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index c1cf5ac9a..282b8dec2 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -109,10 +109,10 @@ class Indi_BullsPower : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = iBullsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _shift, THIS_PTR); + _value = iBullsPower(_Symbol, GetTf(), GetPeriod(), GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetPeriod() /**/, + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /**/ GetPeriod() /**/, _mode, _shift); break; default: diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index 27a0cb14a..ebf1f56d0 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -176,17 +176,17 @@ class Indi_CCI : public Indicator { istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = - Indi_CCI::iCCI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _shift /* + iparams.shift*/, THIS_PTR); + Indi_CCI::iCCI(_Symbol, GetTf(), GetPeriod(), GetAppliedPrice(), _shift /* + iparams.shift*/, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), GetAppliedPrice() /* ] */, 0, _shift); break; case IDATA_INDICATOR: ValidateSelectedDataSource(); // @fixit Somehow shift isn't used neither in MT4 nor MT5. - _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDataSourceMode(), + _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), _Symbol, GetTf(), GetPeriod(), GetDataSourceMode(), _shift /* + iparams.shift*/); break; } diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index 18a54a404..4f8758f29 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -171,11 +171,11 @@ class Indi_CHO : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_CHO::iChaikin(GetSymbol(), GetTf(), /*[*/ GetSlowMA(), GetFastMA(), GetSmoothMethod(), + _value = Indi_CHO::iChaikin(_Symbol, GetTf(), /*[*/ GetSlowMA(), GetFastMA(), GetSmoothMethod(), GetInputVolume() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastMA(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastMA(), GetSlowMA(), GetSmoothMethod(), GetInputVolume() /*]*/, 0, _shift); break; default: diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index 2a903b142..030bb5475 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -167,11 +167,11 @@ class Indi_CHV : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_CHV::iCHV(GetSymbol(), GetTf(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/, + _value = Indi_CHV::iCHV(_Symbol, GetTf(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index 9ec6677dc..6baa7f445 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -117,10 +117,10 @@ class Indi_ColorBars : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ColorBars::iColorBars(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_ColorBars::iColorBars(_Symbol, GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index 001c6e518..ef1ecce47 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -114,10 +114,10 @@ class Indi_ColorCandlesDaily : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ColorCandlesDaily::iCCD(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_ColorCandlesDaily::iCCD(_Symbol, GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index 2b154bf0c..79b536a31 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -176,10 +176,10 @@ class Indi_ColorLine : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ColorLine::iColorLine(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_ColorLine::iColorLine(_Symbol, GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_CustomMovingAverage.mqh b/Indicators/Indi_CustomMovingAverage.mqh index 78f9114c6..f46b8b842 100644 --- a/Indicators/Indi_CustomMovingAverage.mqh +++ b/Indicators/Indi_CustomMovingAverage.mqh @@ -71,7 +71,7 @@ class Indi_CustomMovingAverage : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), GetSmoothShift(), GetSmoothMethod() /*]*/, 0, _shift); break; default: diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index e27ef8a1a..61f1f2447 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -177,12 +177,12 @@ class Indi_DEMA : public Indicator { // We're getting DEMA from Price indicator. istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_DEMA::iDEMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetAppliedPrice(), _shift, _mode, + _value = Indi_DEMA::iDEMA(_Symbol, GetTf(), GetPeriod(), GetMAShift(), GetAppliedPrice(), _shift, _mode, GetPointer(this)); break; case IDATA_ICUSTOM: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /*[*/ GetPeriod(), GetMAShift(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.custom_indi_name, /*[*/ GetPeriod(), GetMAShift(), GetAppliedPrice() /*]*/, _mode, _shift); break; case IDATA_INDICATOR: diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index 3a63bedc1..fc80f32cc 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -107,11 +107,11 @@ class Indi_DeMarker : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = _value = Indi_DeMarker::iDeMarker(GetSymbol(), GetTf(), GetPeriod(), _shift, THIS_PTR); + _value = _value = Indi_DeMarker::iDeMarker(_Symbol, GetTf(), GetPeriod(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, + _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index b0a6880a5..7604b5316 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -73,7 +73,7 @@ class Indi_Demo : public Indicator { * Returns the indicator's value. */ virtual double GetValue(int _mode = 0, int _shift = 0) { - double _value = Indi_Demo::iDemo(GetSymbol(), GetTf(), _shift, THIS_PTR); + double _value = Indi_Demo::iDemo(_Symbol, GetTf(), _shift, THIS_PTR); istate.is_ready = true; istate.is_changed = false; if (iparams.is_draw) { diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index d3d9e9b68..902578292 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -120,12 +120,12 @@ class Indi_DetrendedPrice : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_DetrendedPrice::iDPO(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, - _shift, THIS_PTR); + _value = Indi_DetrendedPrice::iDPO(_Symbol, GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _shift, + THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, + _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index ad16647bf..c4dfff429 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -175,10 +175,10 @@ class Indi_Drawer : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Drawer::iDrawer(GetSymbol(), GetTf(), _shift, THIS_PTR); + _value = Indi_Drawer::iDrawer(_Symbol, GetTf(), _shift, THIS_PTR); break; case IDATA_INDICATOR: - _value = Indi_Drawer::iDrawerOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), _shift); + _value = Indi_Drawer::iDrawerOnIndicator(GetDataSource(), THIS_PTR, _Symbol, GetTf(), _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index de7ac1da7..cb7a6709f 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -202,15 +202,15 @@ class Indi_Envelopes : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Envelopes::iEnvelopes(GetSymbol(), GetTf(), GetMAPeriod(), GetMAMethod(), GetMAShift(), + _value = Indi_Envelopes::iEnvelopes(_Symbol, GetTf(), GetMAPeriod(), GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetMAPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /**/ GetMAPeriod(), GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation() /**/, _mode, _shift); break; case IDATA_INDICATOR: - _value = Indi_Envelopes::iEnvelopesOnIndicator(GetCache(), GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), + _value = Indi_Envelopes::iEnvelopesOnIndicator(GetCache(), GetDataSource(), _Symbol, GetTf(), GetMAPeriod(), GetMAMethod(), GetDataSourceMode(), GetMAShift(), GetDeviation(), _mode, _shift); break; diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index 1b69fa76e..e6a039fee 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -123,11 +123,10 @@ class Indi_Force : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = - Indi_Force::iForce(GetSymbol(), GetTf(), GetPeriod(), GetMAMethod(), GetAppliedPrice(), _shift, THIS_PTR); + _value = Indi_Force::iForce(_Symbol, GetTf(), GetPeriod(), GetMAMethod(), GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetMAMethod(), GetAppliedPrice(), VOLUME_TICK /*]*/, 0, _shift); break; default: diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index e47f56aa7..4d6cf6ff7 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -138,11 +138,11 @@ class Indi_FrAMA : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_FrAMA::iFrAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFRAMAShift(), GetAppliedPrice() /*]*/, + _value = Indi_FrAMA::iFrAMA(_Symbol, GetTf(), /*[*/ GetPeriod(), GetFRAMAShift(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetFRAMAShift() /*]*/, 0, _shift); break; default: diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index 87e5e097e..77efcf6e4 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -107,10 +107,10 @@ class Indi_Fractals : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = _value = Indi_Fractals::iFractals(GetSymbol(), GetTf(), (ENUM_LO_UP_LINE)_mode, _shift, THIS_PTR); + _value = _value = Indi_Fractals::iFractals(_Symbol, GetTf(), (ENUM_LO_UP_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index 78f74fc98..eda240a3b 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -175,12 +175,12 @@ class Indi_Gator : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Gator::iGator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), - GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice(), + _value = Indi_Gator::iGator(_Symbol, GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), + GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice(), (ENUM_GATOR_HISTOGRAM)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /**/ GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice() diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index eb6e18b06..33870d34b 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -217,14 +217,14 @@ class Indi_HeikenAshi : public Indicator { break; } #endif - _value = Indi_HeikenAshi::iHeikenAshi(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_HeikenAshi::iHeikenAshi(_Symbol, GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; case IDATA_ICUSTOM_LEGACY: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_HeikenAshi::iCustomLegacyHeikenAshi(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + _value = Indi_HeikenAshi::iCustomLegacyHeikenAshi(_Symbol, GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift, THIS_PTR); break; default: diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index b2a70f6de..cf49106c5 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -147,11 +147,11 @@ class Indi_Ichimoku : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Ichimoku::iIchimoku(GetSymbol(), GetTf(), GetTenkanSen(), GetKijunSen(), GetSenkouSpanB(), _mode, + _value = Indi_Ichimoku::iIchimoku(_Symbol, GetTf(), GetTenkanSen(), GetKijunSen(), GetSenkouSpanB(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetTenkanSen(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetTenkanSen(), GetKijunSen(), GetSenkouSpanB() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 12888ee03..5f935fdb6 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -633,17 +633,17 @@ class Indi_MA : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_MA::iMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), _shift, + _value = Indi_MA::iMA(_Symbol, GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), - GetMAShift(), GetMAMethod(), GetAppliedPrice() /* ] */, 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), GetMAShift(), + GetMAMethod(), GetAppliedPrice() /* ] */, 0, _shift); break; case IDATA_INDICATOR: // Calculating MA value from specified indicator. - _value = Indi_MA::iMAOnIndicator(GetCache(), GetDataSource(), GetDataSourceMode(), GetSymbol(), GetTf(), + _value = Indi_MA::iMAOnIndicator(GetCache(), GetDataSource(), GetDataSourceMode(), _Symbol, GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), _shift); break; } diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index 56c718d88..b87361954 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -120,13 +120,12 @@ class Indi_MACD : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_MACD::iMACD(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), + _value = Indi_MACD::iMACD(_Symbol, GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice(), (ENUM_SIGNAL_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = - iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), - GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, _mode, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), + GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index a4bc99d6f..d90ca4fdd 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -118,13 +118,13 @@ class Indi_MFI : public Indicator { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; #ifdef __MQL4__ - _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), _shift); + _value = Indi_MFI::iMFI(_Symbol, GetTf(), GetPeriod(), _shift); #else // __MQL5__ - _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedVolume(), _shift, THIS_PTR); + _value = Indi_MFI::iMFI(_Symbol, GetTf(), GetPeriod(), GetAppliedVolume(), _shift, THIS_PTR); #endif break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), VOLUME_TICK /*]*/, 0, _shift); break; default: diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index 0dc8e32e1..f6da4930e 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -157,11 +157,11 @@ class Indi_MassIndex : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_MassIndex::iMI(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetSecondPeriod(), GetSumPeriod() /*]*/, + _value = Indi_MassIndex::iMI(_Symbol, GetTf(), /*[*/ GetPeriod(), GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 7fe181e88..c94a3d61d 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -147,18 +147,18 @@ class Indi_Momentum : public Indicator { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; // @fixit Somehow shift isn't used neither in MT4 nor MT5. - _value = Indi_Momentum::iMomentum(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), iparams.shift + _shift, + _value = Indi_Momentum::iMomentum(_Symbol, GetTf(), GetPeriod(), GetAppliedPrice(), iparams.shift + _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, + _shift); break; case IDATA_INDICATOR: ValidateSelectedDataSource(); // @fixit Somehow shift isn't used neither in MT4 nor MT5. - _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), + _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), _Symbol, GetTf(), GetPeriod(), GetDataSourceMode(), iparams.shift + _shift); if (iparams.is_draw) { draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + _shift), _value, 1); diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index fa6568bb6..17b78467e 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -123,14 +123,14 @@ class Indi_OBV : public Indicator { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; #ifdef __MQL4__ - _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedPrice(), _shift); + _value = Indi_OBV::iOBV(_Symbol, GetTf(), GetAppliedPrice(), _shift); #else // __MQL5__ - _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedVolume(), _shift, THIS_PTR); + _value = Indi_OBV::iOBV(_Symbol, GetTf(), GetAppliedVolume(), _shift, THIS_PTR); #endif break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, - 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, 0, + _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index 09f64e4d3..67bf3e213 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -117,13 +117,12 @@ class Indi_OsMA : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_OsMA::iOsMA(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), + _value = Indi_OsMA::iOsMA(_Symbol, GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = - iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), - GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), + GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index 392e24bde..a9943762b 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -78,10 +78,12 @@ class Indi_Pivot : public Indicator { // must have at least 4 buffers and define OHLC in the first 4 buffers. // Indi_Price is an example of such indicator. if (!HasDataSource()) { + /* GetLogger().Error( "In order use custom indicator as a source, you need to select one using SetIndicatorData() method, " "which is a part of IndiPivotParams structure.", "Indi_Pivot"); + */ Alert( "Indi_Pivot: In order use custom indicator as a source, you need to select one using " "SetIndicatorData() " diff --git a/Indicators/Indi_Price.mqh b/Indicators/Indi_Price.mqh index e63781147..aa8100696 100644 --- a/Indicators/Indi_Price.mqh +++ b/Indicators/Indi_Price.mqh @@ -70,13 +70,13 @@ class Indi_Price : public Indicator { /** * Checks whether indicator has a valid value for a given shift. */ - virtual bool HasValidEntry(int _shift = 0) { return GetBarTime(_shift) != 0; } + virtual bool HasValidEntry(datetime _bar_time = 0) { return _bar_time != 0; } /** * Returns the indicator's value. */ virtual double GetValue(int _mode = PRICE_TYPICAL, int _shift = 0) { - double _value = ChartStatic::iPrice((ENUM_APPLIED_PRICE)_mode, GetSymbol(), GetTf(), _shift); + double _value = ChartStatic::iPrice((ENUM_APPLIED_PRICE)_mode, _Symbol, GetTf(), _shift); istate.is_ready = true; istate.is_changed = false; return _value; @@ -85,15 +85,13 @@ class Indi_Price : public Indicator { /** * Returns the indicator's struct value. */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); + IndicatorDataEntry GetEntry(datetime _bar_time = 0) { unsigned int _position; IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { - _entry.timestamp = GetBarTime(_shift); - _entry.values[INDI_PRICE_MODE_OPEN] = GetValue(PRICE_OPEN, _shift); + _entry.timestamp = _bar_time _entry.values[INDI_PRICE_MODE_OPEN] = GetValue(PRICE_OPEN, _shift); _entry.values[INDI_PRICE_MODE_HIGH] = GetValue(PRICE_HIGH, _shift); _entry.values[INDI_PRICE_MODE_CLOSE] = GetValue(PRICE_CLOSE, _shift); _entry.values[INDI_PRICE_MODE_LOW] = GetValue(PRICE_LOW, _shift); @@ -127,7 +125,7 @@ class Indi_Price : public Indicator { PriceIndiParams _indi_price_params(_shift); _indi_price_params.SetTf(_tf); _indi_price = Objects::Set(_key, new Indi_Price(_indi_price_params)); - _indi_price.SetSymbol(_symbol); + //_indi_price.SetSymbol(_symbol); // @todo } return _indi_price; } diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index 5d9e497d6..afcff2298 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -61,8 +61,8 @@ class Indi_PriceChannel : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, + _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index b8c9efcac..a37b43648 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -125,11 +125,10 @@ class Indi_PriceVolumeTrend : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = - Indi_PriceVolumeTrend::iPVT(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _shift, THIS_PTR); + _value = Indi_PriceVolumeTrend::iPVT(_Symbol, GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetAppliedVolume() /*]*/, 0, _shift); break; default: diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index 800b9ef84..fa96bb6d1 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -61,7 +61,7 @@ class Indi_RS : public Indicator { PriceIndiParams _iprice_p(); // @todo Symbol should be already defined for a chart. // @todo If it's not, move initialization to GetValue()/GetEntry() method. - Indi_Price *_iprice = Indi_Price::GetCached(GetSymbol(), GetTf(), 0); + Indi_Price *_iprice = Indi_Price::GetCached(_Symbol, GetTf(), 0); MathParams _imath0_p(MATH_OP_SUB, PRICE_CLOSE, 0, PRICE_CLOSE, 1); MathParams _imath1_p(MATH_OP_SUB, PRICE_CLOSE, 1, PRICE_CLOSE, 0); diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 84453e216..7998574ee 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -316,15 +316,15 @@ class Indi_RSI : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_RSI::iRSI(GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), _shift, THIS_PTR); + _value = Indi_RSI::iRSI(_Symbol, GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ iparams.GetPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.custom_indi_name, /* [ */ iparams.GetPeriod(), iparams.GetAppliedPrice() /* ] */, 0, _shift); break; case IDATA_INDICATOR: - _value = Indi_RSI::iRSIOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), iparams.GetPeriod(), + _value = Indi_RSI::iRSIOnIndicator(GetDataSource(), THIS_PTR, _Symbol, GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), _shift); break; } diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index 419385ddf..8b0796c91 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -109,10 +109,10 @@ class Indi_RVI : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_RVI::iRVI(GetSymbol(), GetTf(), GetPeriod(), (ENUM_SIGNAL_LINE)_mode, _shift, THIS_PTR); + _value = Indi_RVI::iRVI(_Symbol, GetTf(), GetPeriod(), (ENUM_SIGNAL_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index 95f6208b3..54b5497e5 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -114,12 +114,12 @@ class Indi_RateOfChange : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_RateOfChange::iROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, - _shift, THIS_PTR); + _value = Indi_RateOfChange::iROC(_Symbol, GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _shift, + THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, + _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_SAR.mqh b/Indicators/Indi_SAR.mqh index 8ee26d8c2..b27d6e75a 100644 --- a/Indicators/Indi_SAR.mqh +++ b/Indicators/Indi_SAR.mqh @@ -108,10 +108,10 @@ class Indi_SAR : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_SAR::iSAR(GetSymbol(), GetTf(), GetStep(), GetMax(), _shift, THIS_PTR); + _value = Indi_SAR::iSAR(_Symbol, GetTf(), GetStep(), GetMax(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetStep(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetStep(), GetMax() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 6ab6024fc..2f4daa50c 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -218,16 +218,15 @@ class Indi_StdDev : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_StdDev::iStdDev(GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), GetMAMethod(), - GetAppliedPrice(), _shift, THIS_PTR); + _value = Indi_StdDev::iStdDev(_Symbol, GetTf(), GetMAPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), + _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - iparams.GetCustomIndicatorName(), /*[*/ GetMAPeriod(), GetMAShift(), GetMAMethod() /*]*/, 0, - _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetMAPeriod(), + GetMAShift(), GetMAMethod() /*]*/, 0, _shift); break; case IDATA_INDICATOR: - _value = Indi_StdDev::iStdDevOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), + _value = Indi_StdDev::iStdDevOnIndicator(GetDataSource(), _Symbol, GetTf(), GetMAPeriod(), GetMAShift(), GetAppliedPrice(), _shift, THIS_PTR); break; } diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index fe6d8972b..b40f4e2fe 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -125,11 +125,11 @@ class Indi_Stochastic : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Stochastic::iStochastic(GetSymbol(), GetTf(), GetKPeriod(), GetDPeriod(), GetSlowing(), - GetMAMethod(), GetPriceField(), _mode, _shift, THIS_PTR); + _value = Indi_Stochastic::iStochastic(_Symbol, GetTf(), GetKPeriod(), GetDPeriod(), GetSlowing(), GetMAMethod(), + GetPriceField(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetKPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetKPeriod(), GetDPeriod(), GetSlowing() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index 8d49fbfcf..9bebcb143 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -131,11 +131,11 @@ class Indi_TEMA : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_TEMA::iTEMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetTEMAShift(), GetAppliedPrice() /*]*/, 0, + _value = Indi_TEMA::iTEMA(_Symbol, GetTf(), /*[*/ GetPeriod(), GetTEMAShift(), GetAppliedPrice() /*]*/, 0, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetTEMAShift() /*]*/, 0, _shift); break; default: diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index 0f67564b7..5abcc9334 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -133,11 +133,11 @@ class Indi_TRIX : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: _value = - Indi_TRIX::iTriX(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); + Indi_TRIX::iTriX(_Symbol, GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, + _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index eb891c964..025a23cf8 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -213,12 +213,12 @@ class Indi_UltimateOscillator : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_UltimateOscillator::iUO(GetSymbol(), GetTf(), /*[*/ GetFastPeriod(), GetMiddlePeriod(), - GetSlowPeriod(), GetFastK(), GetMiddleK(), GetSlowK() /*]*/, _mode, - _shift, THIS_PTR); + _value = + Indi_UltimateOscillator::iUO(_Symbol, GetTf(), /*[*/ GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), + GetFastK(), GetMiddleK(), GetSlowK() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), GetMiddleK(), GetSlowK() /*]*/, diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index b2a54fcfb..105453ce7 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -152,11 +152,11 @@ class Indi_VIDYA : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_VIDYA::iVIDyA(GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift(), + _value = Indi_VIDYA::iVIDyA(_Symbol, GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift(), GetAppliedPrice() /*]*/, 0, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift() /*]*/, diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index b6ff5f053..d1afe9892 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -135,11 +135,11 @@ class Indi_VROC : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_VROC::iVROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _shift, - THIS_PTR); + _value = + Indi_VROC::iVROC(_Symbol, GetTf(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index 5862fecde..b1730b87e 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -129,10 +129,10 @@ class Indi_Volumes : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_Volumes::iVolumes(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _shift, THIS_PTR); + _value = Indi_Volumes::iVolumes(_Symbol, GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetAppliedVolume() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Indi_WPR.mqh b/Indicators/Indi_WPR.mqh index d478065f7..88050ab40 100644 --- a/Indicators/Indi_WPR.mqh +++ b/Indicators/Indi_WPR.mqh @@ -106,11 +106,11 @@ class Indi_WPR : public Indicator { switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_WPR::iWPR(GetSymbol(), GetTf(), GetPeriod(), _shift, THIS_PTR); + _value = Indi_WPR::iWPR(_Symbol, GetTf(), GetPeriod(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, + _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index 5b553f2d4..addc10c56 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -128,10 +128,10 @@ class Indi_WilliamsAD : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_WilliamsAD::iWAD(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_WilliamsAD::iWAD(_Symbol, GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), 0, _shift); + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index dccdf6070..f907f2c34 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -340,12 +340,12 @@ class Indi_ZigZag : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ZigZag::iZigZag(GetSymbol(), GetTf(), GetDepth(), GetDeviation(), GetBackstep(), + _value = Indi_ZigZag::iZigZag(_Symbol, GetTf(), GetDepth(), GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_ZigZag::iCustomZigZag(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), GetDepth(), + _value = Indi_ZigZag::iCustomZigZag(_Symbol, GetTf(), iparams.GetCustomIndicatorName(), GetDepth(), GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, _shift, THIS_PTR); break; default: diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 0b8825bc2..0430b8c58 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -67,7 +67,7 @@ class Indi_ZigZagColor : public Indicator { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), + _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetDepth(), GetDeviation(), GetBackstep() /*]*/, _mode, _shift); break; default: diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index faba5f773..71b16a985 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -109,14 +109,14 @@ class Indi_Math : public Indicator { } switch (iparams.op_mode) { case MATH_OP_MODE_BUILTIN: - _value = Indi_Math::iMathOnIndicator( - indi_src, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - /*[*/ GetOpBuiltIn(), GetMode1(), GetMode2(), GetShift1(), GetShift2() /*]*/, 0, _shift, &this); + _value = Indi_Math::iMathOnIndicator(indi_src, _Symbol, GetTf(), + /*[*/ GetOpBuiltIn(), GetMode1(), GetMode2(), GetShift1(), + GetShift2() /*]*/, 0, _shift, &this); break; case MATH_OP_MODE_CUSTOM_FUNCTION: - _value = Indi_Math::iMathOnIndicator( - indi_src, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - /*[*/ GetOpFunction(), GetMode1(), GetMode2(), GetShift1(), GetShift2() /*]*/, 0, _shift, &this); + _value = Indi_Math::iMathOnIndicator(indi_src, _Symbol, GetTf(), + /*[*/ GetOpFunction(), GetMode1(), GetMode2(), GetShift1(), + GetShift2() /*]*/, 0, _shift, &this); break; } break; diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 4dc6aacb0..3afd66804 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -52,7 +52,7 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { * Constructor. */ IndicatorBufferValueStorage(IndicatorBase *_indi, int _mode = 0, bool _is_series = false) - : indicator(_indi), mode(_mode), HistoryValueStorage(_indi.GetSymbol(), _indi.GetTf()) {} + : indicator(_indi), mode(_mode), HistoryValueStorage(/* @todo */ _Symbol, PERIOD_CURRENT) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. From 3dd06eec8fc69bc686b79d1b04a5581a61781be8 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 2 Aug 2022 17:03:13 +0000 Subject: [PATCH 003/123] Adds .devcontainer --- .devcontainer/Dockerfile | 9 +++++++++ .devcontainer/devcontainer.json | 27 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..3712cbb64 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,9 @@ +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.238.1/containers/ubuntu/.devcontainer/base.Dockerfile + +# [Choice] Ubuntu version (use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon): ubuntu-22.04, ubuntu-20.04, ubuntu-18.04 +ARG VARIANT="jammy" +FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} + +# [Optional] Uncomment this section to install additional OS packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..bc882c93f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,27 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.1/containers/ubuntu +{ + "name": "Ubuntu", + "build": { + "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick an Ubuntu version: jammy / ubuntu-22.04, focal / ubuntu-20.04, bionic /ubuntu-18.04 + // Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon. + "args": { "VARIANT": "ubuntu-22.04" } + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode", + "customizations": { + "vscode": { + "extensions": [ + "nicholishen.mql-over-cpp" + ] + } + } +} From 6ee23081dd5a24ad1dc8b148fd059bd570120f79 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 2 Aug 2022 22:40:22 +0000 Subject: [PATCH 004/123] Adds additional vscode C++ extensions --- .devcontainer/devcontainer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index bc882c93f..ab9ccdf13 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -20,7 +20,9 @@ "customizations": { "vscode": { "extensions": [ - "nicholishen.mql-over-cpp" + "ms-vscode.cpptools-extension-pack", + "nicholishen.mql-over-cpp", + "xaver.clang-format" ] } } From 88ffea49837c0aa2f97a903aeaec001528dc27dd Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 2 Aug 2022 22:40:57 +0000 Subject: [PATCH 005/123] Converts tabs into spaces in devcontainer.json --- .devcontainer/devcontainer.json | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ab9ccdf13..a71707c3f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,29 +1,29 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.238.1/containers/ubuntu { - "name": "Ubuntu", - "build": { - "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick an Ubuntu version: jammy / ubuntu-22.04, focal / ubuntu-20.04, bionic /ubuntu-18.04 - // Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon. - "args": { "VARIANT": "ubuntu-22.04" } - }, + "name": "Ubuntu", + "build": { + "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick an Ubuntu version: jammy / ubuntu-22.04, focal / ubuntu-20.04, bionic /ubuntu-18.04 + // Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon. + "args": { "VARIANT": "ubuntu-22.04" } + }, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "uname -a", + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", - // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - "remoteUser": "vscode", - "customizations": { - "vscode": { - "extensions": [ - "ms-vscode.cpptools-extension-pack", - "nicholishen.mql-over-cpp", - "xaver.clang-format" - ] - } - } + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode", + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools-extension-pack", + "nicholishen.mql-over-cpp", + "xaver.clang-format" + ] + } + } } From ea47c03201dcf0ff8e636600050522195e8ecb0e Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 2 Aug 2022 22:43:54 +0000 Subject: [PATCH 006/123] devcontainer: Adds vscode Vim extension --- .devcontainer/devcontainer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a71707c3f..b7f921f39 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -22,6 +22,7 @@ "extensions": [ "ms-vscode.cpptools-extension-pack", "nicholishen.mql-over-cpp", + "vscodevim.vim", "xaver.clang-format" ] } From d0b8d2249f5e77d210002e108e50a4d4ca0d3be8 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 8 Aug 2022 00:57:37 +0100 Subject: [PATCH 007/123] Moves Indicator and IndicatorBase into Indicator/ --- .github/workflows/test-indicator.yml | 1 + .github/workflows/test.yml | 1 - Account/AccountMt.h | 2 +- BufferFXT.mqh | 2 +- .../Indicator.define.h | 0 .../Indicator.enum.h | 0 Indicator.mqh => Indicator/Indicator.h | 28 +++++++------- .../Indicator.struct.cache.h | 4 +- .../Indicator.struct.h | 12 +++--- .../Indicator.struct.serialize.h | 2 +- .../Indicator.struct.signal.h | 0 IndicatorBase.h => Indicator/IndicatorBase.h | 38 +++++++++---------- Indicator/IndicatorCandle.h | 2 +- Indicator/IndicatorTf.struct.h | 2 +- Indicator/IndicatorTick.h | 4 +- Indicator/IndicatorTickSource.h | 2 +- .../tests/Indicator.test.mq4 | 4 +- .../tests/Indicator.test.mq5 | 6 +-- Indicator/tests/classes/Indicators.h | 2 +- Indicators/Bitwise/Indi_Candle.mqh | 2 +- Indicators/Bitwise/Indi_Pattern.mqh | 2 +- Indicators/Indi_AC.mqh | 2 +- Indicators/Indi_AD.mqh | 2 +- Indicators/Indi_ADX.mqh | 2 +- Indicators/Indi_ADXW.mqh | 2 +- Indicators/Indi_AMA.mqh | 2 +- Indicators/Indi_AO.mqh | 2 +- Indicators/Indi_ASI.mqh | 2 +- Indicators/Indi_ATR.mqh | 2 +- Indicators/Indi_Alligator.mqh | 2 +- Indicators/Indi_AppliedPrice.mqh | 2 +- Indicators/Indi_BWMFI.mqh | 2 +- Indicators/Indi_Bands.mqh | 2 +- Indicators/Indi_BearsPower.mqh | 2 +- Indicators/Indi_BullsPower.mqh | 2 +- Indicators/Indi_CCI.mqh | 2 +- Indicators/Indi_CHO.mqh | 2 +- Indicators/Indi_CHV.mqh | 2 +- Indicators/Indi_ColorBars.mqh | 2 +- Indicators/Indi_ColorCandlesDaily.mqh | 2 +- Indicators/Indi_ColorLine.mqh | 2 +- Indicators/Indi_CustomMovingAverage.mqh | 2 +- Indicators/Indi_DEMA.mqh | 2 +- Indicators/Indi_DeMarker.mqh | 2 +- Indicators/Indi_Demo.mqh | 2 +- Indicators/Indi_DetrendedPrice.mqh | 2 +- Indicators/Indi_Drawer.mqh | 2 +- Indicators/Indi_Drawer.struct.h | 2 +- Indicators/Indi_Envelopes.mqh | 2 +- Indicators/Indi_Force.mqh | 2 +- Indicators/Indi_FractalAdaptiveMA.mqh | 2 +- Indicators/Indi_Fractals.mqh | 2 +- Indicators/Indi_Gator.mqh | 2 +- Indicators/Indi_HeikenAshi.mqh | 2 +- Indicators/Indi_Ichimoku.mqh | 2 +- Indicators/Indi_Killzones.mqh | 2 +- Indicators/Indi_MA.mqh | 2 +- Indicators/Indi_MACD.mqh | 2 +- Indicators/Indi_MFI.mqh | 2 +- Indicators/Indi_MassIndex.mqh | 2 +- Indicators/Indi_Momentum.mqh | 2 +- Indicators/Indi_OBV.mqh | 2 +- Indicators/Indi_OsMA.mqh | 2 +- Indicators/Indi_Pivot.mqh | 2 +- Indicators/Indi_PriceChannel.mqh | 2 +- Indicators/Indi_PriceFeeder.mqh | 2 +- Indicators/Indi_PriceVolumeTrend.mqh | 2 +- Indicators/Indi_RS.mqh | 2 +- Indicators/Indi_RSI.mqh | 2 +- Indicators/Indi_RVI.mqh | 2 +- Indicators/Indi_RateOfChange.mqh | 2 +- Indicators/Indi_SAR.mqh | 2 +- Indicators/Indi_StdDev.mqh | 2 +- Indicators/Indi_Stochastic.mqh | 2 +- Indicators/Indi_TEMA.mqh | 2 +- Indicators/Indi_TRIX.mqh | 2 +- Indicators/Indi_UltimateOscillator.mqh | 2 +- Indicators/Indi_VIDYA.mqh | 2 +- Indicators/Indi_VROC.mqh | 2 +- Indicators/Indi_Volumes.mqh | 2 +- Indicators/Indi_WPR.mqh | 2 +- Indicators/Indi_WilliamsAD.mqh | 2 +- Indicators/Indi_ZigZag.mqh | 2 +- Indicators/Indi_ZigZagColor.mqh | 2 +- Indicators/OHLC/Indi_OHLC.mqh | 2 +- Indicators/Price/Indi_Price.mqh | 2 +- Indicators/Special/Indi_Custom.mqh | 2 +- Indicators/Special/Indi_Math.mqh | 2 +- Math.h | 2 +- Platform.h | 2 +- Strategy.mqh | 2 +- Terminal.enum.h | 2 +- Tests.mqh | 2 +- Trade.mqh | 2 +- tests/CompileTest.mq5 | 7 ++-- tests/DrawIndicatorTest.mq5 | 2 +- tests/IndicatorsTest.mq5 | 2 +- 97 files changed, 137 insertions(+), 136 deletions(-) rename Indicator.define.h => Indicator/Indicator.define.h (100%) rename Indicator.enum.h => Indicator/Indicator.enum.h (100%) rename Indicator.mqh => Indicator/Indicator.h (98%) rename Indicator.struct.cache.h => Indicator/Indicator.struct.cache.h (99%) rename Indicator.struct.h => Indicator/Indicator.struct.h (98%) rename Indicator.struct.serialize.h => Indicator/Indicator.struct.serialize.h (99%) rename Indicator.struct.signal.h => Indicator/Indicator.struct.signal.h (100%) rename IndicatorBase.h => Indicator/IndicatorBase.h (98%) rename tests/IndicatorTest.mq4 => Indicator/tests/Indicator.test.mq4 (91%) rename tests/IndicatorTest.mq5 => Indicator/tests/Indicator.test.mq5 (95%) diff --git a/.github/workflows/test-indicator.yml b/.github/workflows/test-indicator.yml index 051dac339..28be4da5b 100644 --- a/.github/workflows/test-indicator.yml +++ b/.github/workflows/test-indicator.yml @@ -51,6 +51,7 @@ jobs: matrix: test: - IndicatorCandle.test + - Indicator.test - IndicatorTf.test - IndicatorTick.test steps: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 429685a77..e405f856c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -60,7 +60,6 @@ jobs: - DatabaseTest - DrawIndicatorTest - EATest - - IndicatorTest - IndicatorsTest - MailTest - MarketTest diff --git a/Account/AccountMt.h b/Account/AccountMt.h index c03c300f9..e01824128 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -33,7 +33,7 @@ class AccountMt; #include "../Chart.mqh" #include "../Convert.mqh" #include "../Data.struct.h" -#include "../Indicator.struct.h" +#include "../Indicator/Indicator.struct.h" #include "../Order.struct.h" #include "../Orders.mqh" #include "../Serializer.mqh" diff --git a/BufferFXT.mqh b/BufferFXT.mqh index dde80cfa0..1d4020c61 100644 --- a/BufferFXT.mqh +++ b/BufferFXT.mqh @@ -27,7 +27,7 @@ #include "Account/AccountMt.h" #include "Chart.mqh" #include "DictStruct.mqh" -#include "IndicatorBase.h" +#include "Indicator/IndicatorBase.h" #include "Object.mqh" // Defines. diff --git a/Indicator.define.h b/Indicator/Indicator.define.h similarity index 100% rename from Indicator.define.h rename to Indicator/Indicator.define.h diff --git a/Indicator.enum.h b/Indicator/Indicator.enum.h similarity index 100% rename from Indicator.enum.h rename to Indicator/Indicator.enum.h diff --git a/Indicator.mqh b/Indicator/Indicator.h similarity index 98% rename from Indicator.mqh rename to Indicator/Indicator.h index 31063073a..958d6faad 100644 --- a/Indicator.mqh +++ b/Indicator/Indicator.h @@ -25,11 +25,20 @@ #define INDICATOR_MQH // Includes. -#include "Array.mqh" -#include "BufferStruct.mqh" -#include "DateTime.mqh" -#include "DrawIndicator.mqh" -#include "Flags.h" +#include "../Array.mqh" +#include "../BufferStruct.mqh" +#include "../DateTime.mqh" +#include "../DrawIndicator.mqh" +#include "../Flags.h" +#include "../Math.h" +#include "../Object.mqh" +#include "../Refs.mqh" +#include "../Serializer.mqh" +#include "../SerializerCsv.mqh" +#include "../SerializerJson.mqh" +#include "../Storage/ValueStorage.h" +#include "../Storage/ValueStorage.indicator.h" +#include "../Storage/ValueStorage.native.h" #include "Indicator.define.h" #include "Indicator.enum.h" #include "Indicator.struct.cache.h" @@ -37,15 +46,6 @@ #include "Indicator.struct.serialize.h" #include "Indicator.struct.signal.h" #include "IndicatorBase.h" -#include "Math.h" -#include "Object.mqh" -#include "Refs.mqh" -#include "Serializer.mqh" -#include "SerializerCsv.mqh" -#include "SerializerJson.mqh" -#include "Storage/ValueStorage.h" -#include "Storage/ValueStorage.indicator.h" -#include "Storage/ValueStorage.native.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compatibility). diff --git a/Indicator.struct.cache.h b/Indicator/Indicator.struct.cache.h similarity index 99% rename from Indicator.struct.cache.h rename to Indicator/Indicator.struct.cache.h index 2c4df7097..05264e24b 100644 --- a/Indicator.struct.cache.h +++ b/Indicator/Indicator.struct.cache.h @@ -31,8 +31,8 @@ #endif // Includes. -#include "Refs.mqh" -#include "Storage/ValueStorage.h" +#include "../Refs.mqh" +#include "../Storage/ValueStorage.h" /** * Holds buffers used to cache values calculated via OnCalculate methods. diff --git a/Indicator.struct.h b/Indicator/Indicator.struct.h similarity index 98% rename from Indicator.struct.h rename to Indicator/Indicator.struct.h index d6a118586..199d924de 100644 --- a/Indicator.struct.h +++ b/Indicator/Indicator.struct.h @@ -36,14 +36,14 @@ class Indicator; struct ChartParams; // Includes. -#include "Array.mqh" -#include "Chart.struct.tf.h" -#include "Data.struct.h" -#include "DateTime.struct.h" +#include "../Array.mqh" +#include "../Chart.struct.tf.h" +#include "../Data.struct.h" +#include "../DateTime.struct.h" +#include "../SerializerNode.enum.h" +#include "../Storage/ValueStorage.indicator.h" #include "Indicator.enum.h" #include "Indicator.struct.cache.h" -#include "SerializerNode.enum.h" -#include "Storage/ValueStorage.indicator.h" // Type-less value for IndicatorDataEntryValue structure. union IndicatorDataEntryTypelessValue { diff --git a/Indicator.struct.serialize.h b/Indicator/Indicator.struct.serialize.h similarity index 99% rename from Indicator.struct.serialize.h rename to Indicator/Indicator.struct.serialize.h index 75115f0ed..6d68a4d3f 100644 --- a/Indicator.struct.serialize.h +++ b/Indicator/Indicator.struct.serialize.h @@ -25,7 +25,7 @@ * Includes Indicator's struct serializers. */ -#include "Serializer.mqh" +#include "../Serializer.mqh" // Forward class declaration. class Serializer; diff --git a/Indicator.struct.signal.h b/Indicator/Indicator.struct.signal.h similarity index 100% rename from Indicator.struct.signal.h rename to Indicator/Indicator.struct.signal.h diff --git a/IndicatorBase.h b/Indicator/IndicatorBase.h similarity index 98% rename from IndicatorBase.h rename to Indicator/IndicatorBase.h index dc7697d6c..8202652d2 100644 --- a/IndicatorBase.h +++ b/Indicator/IndicatorBase.h @@ -34,31 +34,31 @@ class Chart; // Includes. -#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 "../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 "../Log.mqh" +#include "../Object.mqh" +#include "../Refs.mqh" +#include "../Serializer.mqh" +#include "../SerializerCsv.mqh" +#include "../SerializerJson.mqh" +#include "../Storage/ValueStorage.h" +#include "../Storage/ValueStorage.indicator.h" +#include "../Storage/ValueStorage.native.h" +#include "../Util.h" #include "Indicator.define.h" #include "Indicator.enum.h" #include "Indicator.struct.cache.h" #include "Indicator.struct.h" #include "Indicator.struct.serialize.h" #include "Indicator.struct.signal.h" -#include "Log.mqh" -#include "Object.mqh" -#include "Refs.mqh" -#include "Serializer.mqh" -#include "SerializerCsv.mqh" -#include "SerializerJson.mqh" -#include "Storage/ValueStorage.h" -#include "Storage/ValueStorage.indicator.h" -#include "Storage/ValueStorage.native.h" -#include "Util.h" /** * Class to deal with indicators. diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 5a6a6cac8..571dc7ce9 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -32,7 +32,6 @@ // Includes. #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" @@ -40,6 +39,7 @@ #include "../Storage/ValueStorage.tick_volume.h" #include "../Storage/ValueStorage.time.h" #include "../Storage/ValueStorage.volume.h" +#include "Indicator.h" #include "TickBarCounter.h" // Indicator modes. diff --git a/Indicator/IndicatorTf.struct.h b/Indicator/IndicatorTf.struct.h index 7259d6d9b..6eb42bfb2 100644 --- a/Indicator/IndicatorTf.struct.h +++ b/Indicator/IndicatorTf.struct.h @@ -31,7 +31,7 @@ #endif // Includes. -#include "../Indicator.struct.h" +#include "Indicator.struct.h" /* Structure for IndicatorTf class parameters. */ struct IndicatorTfParams : IndicatorParams { diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 7b0e88355..389243abe 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -31,8 +31,8 @@ // Includes. #include "../Buffer/BufferTick.h" -#include "../Indicator.mqh" -#include "../Indicator.struct.h" +#include "Indicator.h" +#include "Indicator.struct.h" // Indicator modes. enum ENUM_INDI_TICK_MODE { diff --git a/Indicator/IndicatorTickSource.h b/Indicator/IndicatorTickSource.h index 579531bbf..5d7dd9de8 100644 --- a/Indicator/IndicatorTickSource.h +++ b/Indicator/IndicatorTickSource.h @@ -26,7 +26,7 @@ #endif // Includes. -#include "../Indicator.mqh" +#include "Indicator.h" /** * Indicator to be used with IndicatorTick as a data source. diff --git a/tests/IndicatorTest.mq4 b/Indicator/tests/Indicator.test.mq4 similarity index 91% rename from tests/IndicatorTest.mq4 rename to Indicator/tests/Indicator.test.mq4 index f1bee4667..81a7da627 100644 --- a/tests/IndicatorTest.mq4 +++ b/Indicator/tests/Indicator.test.mq4 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -25,4 +25,4 @@ */ // Includes. -#include "IndicatorTest.mq5" +#include "Indicator.test.mq5" diff --git a/tests/IndicatorTest.mq5 b/Indicator/tests/Indicator.test.mq5 similarity index 95% rename from tests/IndicatorTest.mq5 rename to Indicator/tests/Indicator.test.mq5 index e837f8e92..437dfb252 100644 --- a/tests/IndicatorTest.mq5 +++ b/Indicator/tests/Indicator.test.mq5 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -25,8 +25,8 @@ */ // Includes. -#include "../Indicator.mqh" -#include "../Test.mqh" +#include "../Indicator.h" +#include "../../Test.mqh" /** * Implements OnInit(). diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h index f8258b555..dbae5001a 100644 --- a/Indicator/tests/classes/Indicators.h +++ b/Indicator/tests/classes/Indicators.h @@ -30,7 +30,7 @@ #endif // Includes. -#include "../../../IndicatorBase.h" +#include "../../../Indicator/IndicatorBase.h" #include "../../../Refs.mqh" /** diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index cff7209e7..6553adec8 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.mqh" +#include "../../Indicator/Indicator.h" #include "../../Pattern.struct.h" #include "../../Serializer.mqh" #include "../Price/Indi_Price.mqh" diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index 4c836f3a9..e5ef6dfc8 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.mqh" +#include "../../Indicator/Indicator.h" #include "../../Pattern.struct.h" #include "../../Serializer.mqh" #include "../Price/Indi_Price.mqh" diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index 9041a4d4e..892d0bc1d 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index 591baa6e8..fea61bad6 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index 73696b94a..019b98b4e 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Price/Indi_Price.mqh" #ifndef __MQL4__ diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 998621e09..b38d15720 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.applied_price.h" #include "../Storage/ValueStorage.h" #include "../Storage/ValueStorage.spread.h" diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index ecad98596..4894eb283 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Indicator/tests/classes/IndicatorTfDummy.h" #include "../Storage/ValueStorage.h" #include "Price/Indi_Price.mqh" diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index 60ffe3d1d..1953f89cd 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index d280d0feb..2ba1daabc 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index fc3b0684f..7ff23a6c9 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index 8587b0650..039d6f324 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_AppliedPrice.mqh b/Indicators/Indi_AppliedPrice.mqh index 3c9e2c7eb..534b948a2 100644 --- a/Indicators/Indi_AppliedPrice.mqh +++ b/Indicators/Indi_AppliedPrice.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "OHLC/Indi_OHLC.mqh" // Structs. diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index e3117195c..752bbe713 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index f873fecaa..eebc23d9a 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_CCI.mqh" #include "Indi_Envelopes.mqh" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index 26970847b..955f05aa0 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index 933fd4aa6..72458a6f4 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index 3e1777031..6d723a0e1 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" #include "Price/Indi_Price.mqh" diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index de1babe90..d0ff41fdd 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "../Util.h" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index 2251f6420..1da755024 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "../Util.h" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index 191b483f3..550878ef8 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index b7c7cf52d..985209e36 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index faaff3f18..7531a4b44 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_CustomMovingAverage.mqh b/Indicators/Indi_CustomMovingAverage.mqh index 2fa70ff88..f8a816dc0 100644 --- a/Indicators/Indi_CustomMovingAverage.mqh +++ b/Indicators/Indi_CustomMovingAverage.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" // Structs. struct IndiCustomMovingAverageParams : IndicatorParams { diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index e0a69b308..5386a0f57 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -27,7 +27,7 @@ // Includes. #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Refs.mqh" #include "../Storage/Objects.h" #include "../Storage/ValueStorage.h" diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index 604966191..480981e95 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index d44822b05..31e29e3ab 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Price/Indi_Price.mqh" /** diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index f2da9c923..460dc76a7 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_MA.mqh" // Structs. diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index ec6c11d1c..80f1712b2 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -25,7 +25,7 @@ struct IndicatorParams; // Includes. #include "../DictStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Redis.mqh" #include "../Task/TaskAction.h" #include "Indi_Drawer.struct.h" diff --git a/Indicators/Indi_Drawer.struct.h b/Indicators/Indi_Drawer.struct.h index 43136f99a..4b2cbc287 100644 --- a/Indicators/Indi_Drawer.struct.h +++ b/Indicators/Indi_Drawer.struct.h @@ -26,7 +26,7 @@ */ // Includes. -#include "../Indicator.struct.h" +#include "../Indicator/Indicator.struct.h" // Structs. diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 91c2be25a..d6fae138f 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/Singleton.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index 7f6794db6..fb16cd679 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -32,7 +32,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index 00c5ed641..ae326916a 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index dcfd19697..1f13a1205 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index ca33da68f..55e94225e 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index 048660b41..b305ae96f 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Enums. diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index 8e8058b0c..029ccd89b 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Killzones.mqh b/Indicators/Indi_Killzones.mqh index 89a891134..542ee6768 100644 --- a/Indicators/Indi_Killzones.mqh +++ b/Indicators/Indi_Killzones.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Market.struct.h" // Defines enumerations. diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 30aa3af74..cd227f3d9 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -27,7 +27,7 @@ // Includes. #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Refs.mqh" #include "../Storage/Singleton.h" #include "../Storage/ValueStorage.h" diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index d5e0daf42..37361fa51 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index 6b87ea67d..06b4f2a10 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index aadba3563..406281866 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index bc696e74a..2a4029d5b 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -30,7 +30,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_PriceFeeder.mqh" #ifndef __MQL4__ diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index 631e41444..ca4992191 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index cfd48c16c..57846769b 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index c7b9e659a..2698648ac 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -22,7 +22,7 @@ // Includes. #include "../Bar.struct.h" -#include "../Indicator.struct.h" +#include "../Indicator/Indicator.struct.h" #include "../Serializer.mqh" #include "Special/Indi_Math.mqh" diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index 2fce61174..5c181f63f 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_ZigZag.mqh" // Structs. diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index 25f00d22b..ea28fb237 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" // Structs. struct IndiPriceFeederParams : IndicatorParams { diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index ba1ed2961..781ed8ef9 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index cdec53c54..515f8e125 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "OHLC/Indi_OHLC.mqh" #include "Special/Indi_Math.mqh" diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 12effe6ba..306be9081 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -22,7 +22,7 @@ // Includes. #include "../DictStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_Bands.mqh" #include "Indi_CCI.mqh" #include "Indi_Envelopes.mqh" diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index ee5e1cdae..e5c729914 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index d0b32d973..8747d997f 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" // Structs. struct IndiRateOfChangeParams : IndicatorParams { diff --git a/Indicators/Indi_SAR.mqh b/Indicators/Indi_SAR.mqh index 942c75591..365120e9c 100644 --- a/Indicators/Indi_SAR.mqh +++ b/Indicators/Indi_SAR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 3ac1b8813..84aa6ba3b 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ObjectsCache.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index c97984370..e53ba96fc 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index edf3399e1..bdb3610ab 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_MA.mqh" // Structs. diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index d150e6a8e..b0e188597 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_MA.mqh" // Structs. diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index 35ed7b246..d981df0dd 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "Indi_ATR.mqh" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index 2538f840f..c791e2a3a 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" // Structs. struct IndiVIDYAParams : IndicatorParams { diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index 22160c8ad..92601ea96 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index 7a21ad30d..d6f147e72 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_WPR.mqh b/Indicators/Indi_WPR.mqh index 3366b93fe..42ef81b00 100644 --- a/Indicators/Indi_WPR.mqh +++ b/Indicators/Indi_WPR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index a887ea1ac..25e624bdf 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index 772cc6f0c..f816404e3 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Defines. diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 0cfb2cd21..5645a1470 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "Indi_ZigZag.mqh" diff --git a/Indicators/OHLC/Indi_OHLC.mqh b/Indicators/OHLC/Indi_OHLC.mqh index 82c5ca8dd..bfe451d70 100644 --- a/Indicators/OHLC/Indi_OHLC.mqh +++ b/Indicators/OHLC/Indi_OHLC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/Indicator.h" #include "../../Storage/Objects.h" // Enums. diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index e6fe78681..e397873e4 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/Indicator.h" #include "../../Platform.h" #include "../../Storage/Objects.h" diff --git a/Indicators/Special/Indi_Custom.mqh b/Indicators/Special/Indi_Custom.mqh index 2cd122a82..9e2d5d62c 100644 --- a/Indicators/Special/Indi_Custom.mqh +++ b/Indicators/Special/Indi_Custom.mqh @@ -33,7 +33,7 @@ #endif // Includes. -#include "../../Indicator.mqh" +#include "../../Indicator/Indicator.h" // Structs. diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index 734a551bc..4869c8311 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/Indicator.h" #include "../../Math.enum.h" enum ENUM_MATH_OP_MODE { MATH_OP_MODE_BUILTIN, MATH_OP_MODE_CUSTOM_FUNCTION }; diff --git a/Math.h b/Math.h index 691837b31..2460f7e61 100644 --- a/Math.h +++ b/Math.h @@ -27,7 +27,7 @@ // Includes. #include "Data.struct.h" -#include "Indicator.struct.h" +#include "Indicator/Indicator.struct.h" #include "Math.define.h" #include "Math.enum.h" #include "Math.extern.h" diff --git a/Platform.h b/Platform.h index bbd755349..5736fad57 100644 --- a/Platform.h +++ b/Platform.h @@ -27,7 +27,7 @@ */ #include "Flags.h" -#include "IndicatorBase.h" +#include "Indicator/IndicatorBase.h" #include "Std.h" #ifdef __MQLBUILD__ diff --git a/Strategy.mqh b/Strategy.mqh index 1e480bd1b..427d6cc75 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -30,7 +30,7 @@ class Trade; // Includes. #include "Data.struct.h" #include "Dict.mqh" -#include "Indicator.mqh" +#include "Indicator/Indicator.h" #include "Market.mqh" #include "Object.mqh" #include "Strategy.enum.h" diff --git a/Terminal.enum.h b/Terminal.enum.h index 6c12c13cc..574615a23 100644 --- a/Terminal.enum.h +++ b/Terminal.enum.h @@ -31,7 +31,7 @@ #endif // Includes. -#include "Indicator.define.h" +#include "Indicator/Indicator.define.h" // Defines user error enumeration. enum ENUM_USER_ERR { USER_ERR_INVALID_ARGUMENT }; diff --git a/Tests.mqh b/Tests.mqh index 55c549aa8..d4a3d3463 100644 --- a/Tests.mqh +++ b/Tests.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "Indicator.mqh" +#include "Indicator/Indicator.h" #include "Market.mqh" /** diff --git a/Trade.mqh b/Trade.mqh index 41aa0cca5..7b88f0f44 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -34,7 +34,7 @@ class Trade; #include "Chart.mqh" #include "Convert.mqh" #include "DictStruct.mqh" -#include "IndicatorBase.h" +#include "Indicator/IndicatorBase.h" #include "Math.h" #include "Object.mqh" #include "Order.mqh" diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index 63fcdbb04..97bc1cf6f 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -60,9 +60,6 @@ #include "../EA.mqh" #include "../File.mqh" #include "../ISerializable.h" -#include "../Indicator.define.h" -#include "../Indicator.mqh" -//#include "../IndicatorData.mqh" // @removeme #include "../Inet.mqh" #include "../Log.mqh" #include "../MD5.mqh" @@ -130,6 +127,10 @@ #include "../Web.mqh" // Includes indicator files. +#include "../Indicator/Indicator.define.h" +#include "../Indicator/Indicator.h" +#include "../Indicator/IndicatorBase.h" +//#include "../Indicator/IndicatorData.h" #include "../Indicators/indicators.h" /** diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index d2cd56dc9..943ff92e0 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -30,7 +30,7 @@ // Includes. #include "../DictStruct.mqh" #include "../DrawIndicator.mqh" -#include "../Indicator.struct.serialize.h" +#include "../Indicator/Indicator.struct.serialize.h" #include "../Indicators/Indi_Bands.mqh" #include "../Indicators/Indi_Demo.mqh" #include "../Indicators/Indi_MA.mqh" diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index a46474fb8..0c80d5c8d 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -35,7 +35,7 @@ struct DataParamEntry; //#include "../ChartMt.h" #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Indicator/tests/classes/IndicatorTfDummy.h" #include "../Indicators/Bitwise/indicators.h" #include "../Indicators/Tick/Indi_TickMt.mqh" From ff1b4bad7a25233d897847ff36abe275eacc8161 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 8 Aug 2022 00:25:44 +0100 Subject: [PATCH 008/123] Indicator: Adds initial IndicatorRenko class --- .github/workflows/test-indicator.yml | 1 + Indicator/IndicatorRenko.h | 152 ++++++++++++++++++++++++ Indicator/IndicatorRenko.struct.h | 47 ++++++++ Indicator/tests/IndicatorRenko.test.mq4 | 28 +++++ Indicator/tests/IndicatorRenko.test.mq5 | 146 +++++++++++++++++++++++ tests/CompileTest.mq5 | 5 + 6 files changed, 379 insertions(+) create mode 100644 Indicator/IndicatorRenko.h create mode 100644 Indicator/IndicatorRenko.struct.h create mode 100644 Indicator/tests/IndicatorRenko.test.mq4 create mode 100644 Indicator/tests/IndicatorRenko.test.mq5 diff --git a/.github/workflows/test-indicator.yml b/.github/workflows/test-indicator.yml index 1a51af539..6cf21b0c0 100644 --- a/.github/workflows/test-indicator.yml +++ b/.github/workflows/test-indicator.yml @@ -53,6 +53,7 @@ jobs: - IndicatorCandle.test - IndicatorTf.test - IndicatorTick.test + - IndicatorRenko.test steps: - uses: actions/download-artifact@v2 with: diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h new file mode 100644 index 000000000..c1ac83c39 --- /dev/null +++ b/Indicator/IndicatorRenko.h @@ -0,0 +1,152 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * An abstract class to implement Renko indicators. + */ + +// Ignore processing of this file if already included. +#ifndef INDICATOR_RENKO_H +#define INDICATOR_RENKO_H + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Chart.struct.tf.h" +#include "IndicatorCandle.h" +#include "IndicatorRenko.struct.h" + +/** + * Class to deal with candle indicators. + */ +template +class IndicatorRenko : public IndicatorCandle { + protected: + // Time-frame used to create candles. + ENUM_TIMEFRAMES tf; + + /* Protected methods */ + + /** + * Initialize class. + * + * Called on constructor. + */ + void Init() {} + + public: + /* Special methods */ + + /** + * Class constructor with timeframe enum. + */ + IndicatorRenko(unsigned int _spc) { + iparams.SetSecsPerCandle(_spc); + Init(); + } + + /** + * Class constructor with timeframe enum. + */ + IndicatorRenko(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + iparams.SetSecsPerCandle(ChartTf::TfToSeconds(_tf)); + tf = _tf; + Init(); + } + + /** + * Class constructor with timeframe index. + */ + IndicatorRenko(ENUM_TIMEFRAMES_INDEX _tfi = 0) { + iparams.SetSecsPerCandle(ChartTf::TfToSeconds(ChartTf::IndexToTf(_tfi))); + tf = ChartTf::IndexToTf(_tfi); + Init(); + } + + /** + * Class constructor with parameters. + */ + IndicatorRenko(TFP &_params) : IndicatorCandle(_params) { Init(); } + + /** + * Returns time of the bar for a given shift (MT-compatible shift). + */ + datetime GetBarTimeLegacy(int _shift = 0) { + // Note: iTime() in MT4 build can return not rounded values. + datetime _curr = (datetime)CalcCandleTimestamp(::iTime(GetSymbol(), GetTf(), fmax(0, _shift))); + datetime _last_valid = 0; + +#ifdef __MQL4__ + if (GetLastError() == ERR_HISTORY_WILL_UPDATED) { + // Workaround for MT4 history data issues. + // See: https://www.mql5.com/en/forum/155707 + for (int i = 0; i < 10; i++) { + Sleep(1000); + _curr = ::iTime(GetSymbol(), GetTf(), 0); + if (GetLastError() != ERR_HISTORY_WILL_UPDATED) { + break; + } + SetUserError(ERR_HISTORY_WILL_UPDATED); + } + } +#endif + while (_curr >= icdata.GetMin()) { + if (icdata.KeyExists(_curr)) { + _last_valid = _curr; + if (_shift-- == 0) { + return _curr; + } + } + // Going back in time by TF. + _curr -= ChartTf::TfToSeconds(tf); + } + + // No entry found. Returning last valid candle. + if (icdata.KeyExists(_last_valid)) { + return _last_valid; + } else { + // Not a single valid candle found. + return 0; + } + } + + /* Virtual methods */ + + /** + * Returns time of the bar for a given shift. + */ + datetime GetBarTime(int _shift = 0) override { + // @fixit Should be replaced by MT-compatible bar time calculation for the given shift. + return GetBarTimeLegacy(_shift); + } + + /** + * Gets indicator's time-frame. + */ + ENUM_TIMEFRAMES GetTf() override { return tf; } +}; + +#endif diff --git a/Indicator/IndicatorRenko.struct.h b/Indicator/IndicatorRenko.struct.h new file mode 100644 index 000000000..2a6401689 --- /dev/null +++ b/Indicator/IndicatorRenko.struct.h @@ -0,0 +1,47 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes IndicatorRenko's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Indicator.struct.h" + +/* Structure for IndicatorRenko class parameters. */ +struct IndicatorRenkoParams : IndicatorParams { + float ppc; // Pips per candle. + // Struct constructor. + IndicatorRenkoParams(float _ppc = 10) : ppc(_ppc) {} + // Getters. + float GetPipsPerCandle() { return ppc; } + // Setters. + void SetPipsPerCandle(float _ppc) { ppc = _ppc; } + // Copy constructor. + IndicatorRenkoParams(const IndicatorRenkoParams &_params) { THIS_REF = _params; } +}; diff --git a/Indicator/tests/IndicatorRenko.test.mq4 b/Indicator/tests/IndicatorRenko.test.mq4 new file mode 100644 index 000000000..c1e3ff307 --- /dev/null +++ b/Indicator/tests/IndicatorRenko.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of IndicatorRenko class. + */ + +// Includes. +#include "IndicatorRenko.test.mq5" diff --git a/Indicator/tests/IndicatorRenko.test.mq5 b/Indicator/tests/IndicatorRenko.test.mq5 new file mode 100644 index 000000000..52e52c5f7 --- /dev/null +++ b/Indicator/tests/IndicatorRenko.test.mq5 @@ -0,0 +1,146 @@ +//+------------------------------------------------------------------+ +//| 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 + * Test functionality of IndicatorRenko class. + * + * Idea is to check if ticks from IndicatorTick will be properly grouped by given timespan/timeframe. + */ + +// Includes. +#include "../../Indicators/Indi_AMA.mqh" +#include "../../Indicators/Tick/Indi_TickMt.mqh" +#include "../../Platform.h" +#include "../../Test.mqh" +#include "../../Util.h" +#include "../IndicatorRenko.h" +#include "../IndicatorTick.h" +#include "classes/Indicators.h" + +Ref indi_tick; +Ref indi_ama; +Ref indi_ama_orig; +Ref indi_ama_orig_sim; +Ref indi_ama_oncalculate; +Ref indi_ama_custom; + +/** + * Implements OnInit(). + */ +int OnInit() { + Platform::Init(); + // Platform ticks. + indi_tick = Platform::FetchDefaultTickIndicator(); + + // @todo: E.g. 1 pip candles, 10 pip candles + + // float _pip_value = SymbolInfoStatic::GetPipValue(_Symbol); + + /* + // 1-second candles. + // indicators.Add(indi_tf = new IndicatorRenkoDummy(1)); + + // 1:1 candles from platform using current timeframe. + indi_renko_real = Platform::FetchDefaultCandleIndicator(); + + // 1-second candles. + // indicators.Add(indi_ama = new Indi_AMA()); + + IndiAMAParams _ama_params; + _ama_params.applied_price = PRICE_OPEN; + + // AMA on platform candles. + Platform::Add(indi_ama_orig_sim = new Indi_AMA(_ama_params)); + + // Original built-in AMA indicator on platform OHLCs. + _ama_params.SetDataSourceType(IDATA_BUILTIN); + Platform::Add(indi_ama_orig = new Indi_AMA(_ama_params)); + indi_ama_orig.Ptr().SetDataSource(indi_renko_real.Ptr()); + + // OnCalculate()-based version of AMA indicator on platform OHLCs. + _ama_params.SetDataSourceType(IDATA_ONCALCULATE); + Platform::Add(indi_ama_oncalculate = new Indi_AMA(_ama_params)); + indi_ama_oncalculate.Ptr().SetDataSource(indi_renko_real.Ptr()); + + // iCustom()-based version of AMA indicator on platform OHLCs. + _ama_params.SetDataSourceType(IDATA_ICUSTOM); + Platform::Add(indi_ama_custom = new Indi_AMA(_ama_params)); + indi_ama_custom.Ptr().SetDataSource(indi_renko_real.Ptr()); + + // Candles will be initialized from tick's history. + // indi_tf.Ptr().SetDataSource(indi_tick.Ptr()); + indi_renko_real.Ptr().SetDataSource(indi_tick.Ptr()); + + // AMA will work on the candle indicator. + // indi_ama.Ptr().SetDataSource(indi_tf.Ptr()); + + // AMA will work on the simulation of real candles. + indi_ama_orig_sim.Ptr().SetDataSource(indi_renko_real.Ptr()); + */ + + // 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()); + return (INIT_SUCCEEDED); +} + +/** + * Implements OnTick(). + */ +void OnTick() { + Platform::Tick(); + +#ifdef __debug__ + if (indi_renko_real.Ptr().IsNewBar()) { + Print("New bar: ", indi_renko_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), TIME_DATE | TIME_MINUTES | TIME_SECONDS); + + Util::Print( + "Tick: " + IntegerToString((long)iTime(indi_renko_real.Ptr().GetSymbol(), indi_renko_real.Ptr().GetTf(), 0)) + + " (" + time + "), real = " + o + ", " + h + ", " + l + ", " + c); + + string c_o = DoubleToStr(indi_renko_real.Ptr().GetOpen(0), 5); + string c_h = DoubleToStr(indi_renko_real.Ptr().GetHigh(0), 5); + string c_l = DoubleToStr(indi_renko_real.Ptr().GetLow(0), 5); + string c_c = DoubleToStr(indi_renko_real.Ptr().GetClose(0), 5); + + Util::Print("Tick: " + IntegerToString(indi_renko_real.Ptr().GetBarTime(0)) + " (" + time + "), candle = " + c_o + + ", " + c_h + ", " + c_l + ", " + c_c); + + Util::Print(Platform::IndicatorsToString(0)); +#endif +} + +/** + * Implements OnDeinit(). + */ +void OnDeinit(const int reason) { + // Printing all grouped candles. + // Print(indi_renko_real.Ptr().GetName(), "'s all candles:"); + // Print(indi_renko_real.Ptr().CandlesToString()); +} diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index 63fcdbb04..212964593 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -130,6 +130,11 @@ #include "../Web.mqh" // Includes indicator files. +#include "../Indicator/IndicatorCandle.h" +#include "../Indicator/IndicatorRenko.h" +#include "../Indicator/IndicatorTf.h" +#include "../Indicator/IndicatorTick.h" +#include "../Indicator/IndicatorTickSource.h" #include "../Indicators/indicators.h" /** From f0fcb4f0bce760ccd28ba60288cbf6a06c51d7f5 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 8 Aug 2022 00:40:28 +0100 Subject: [PATCH 009/123] Indicator/README: Adds class diagram --- Indicator/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Indicator/README.md b/Indicator/README.md index add1d2685..83aa4e568 100644 --- a/Indicator/README.md +++ b/Indicator/README.md @@ -4,6 +4,20 @@ Indicator classes are intended for implementation of technical indicators. They can help with storing and accessing values and indicator parameters. +## Class diagram + +```mermaid +classDiagram + Object <|-- IndicatorBase + IndicatorBase <|-- Indicator + Indicator <|-- IndicatorCandle + Indicator <|-- IndicatorCandleSource + Indicator <|-- IndicatorTick + Indicator <|-- IndicatorTickSource + IndicatorCandle <|-- IndicatorRenko + IndicatorCandle <|-- IndicatorTf +``` + ## `IndicatorBase` An abstract class for all type of indicators (a base class). From b37f79b43a50ed1eff34771e15fa6cdc1dae0936 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 15 Aug 2022 22:28:22 +0100 Subject: [PATCH 010/123] Adds .clang-tidy --- .clang-tidy | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 .clang-tidy diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..9e7ce8e04 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,108 @@ +--- +Checks: |- + *, + -altera-id-dependent-backward-branch, + -altera-struct-pack-align, + -altera-unroll-loops, + -bugprone-branch-clone, + -bugprone-copy-constructor-init, + -bugprone-easily-swappable-parameters, + -bugprone-integer-division, + -bugprone-macro-parentheses, + -bugprone-narrowing-conversions, + -bugprone-redundant-branch-condition, + -bugprone-reserved-identifier, + -bugprone-string-constructor, + -bugprone-unhandled-self-assignment, + -cert-dcl37-c, + -cert-dcl51-cpp, + -cert-msc30-c, + -cert-msc50-cpp, + -cert-oop54-cpp, + -cert-oop54-cpp, + -clang-diagnostic-error, + -concurrency-mt-unsafe, + -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-avoid-non-const-global-variables, + -cppcoreguidelines-c-copy-assignment-signature, + -cppcoreguidelines-init-variables, + -cppcoreguidelines-macro-usage, + -cppcoreguidelines-narrowing-conversions, + -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-owning-memory, + -cppcoreguidelines-prefer-member-initializer, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-type-member-init, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-pro-type-vararg, + -cppcoreguidelines-special-member-functions, + -fuchsia-default-arguments-calls, + -fuchsia-default-arguments-declarations, + -fuchsia-overloaded-operator, + -fuchsia-trailing-return, + -google-explicit-constructor, + -google-global-names-in-headers, + -google-readability-braces-around-statements, + -google-readability-casting, + -google-runtime-int, + -hicpp-avoid-c-arrays, + -hicpp-braces-around-statements, + -hicpp-braces-around-statements, + -hicpp-exception-baseclass, + -hicpp-explicit-conversions, + -hicpp-member-init, + -hicpp-multiway-paths-covered, + -hicpp-named-parameter, + -hicpp-no-array-decay, + -hicpp-signed-bitwise,, + -hicpp-special-member-functions, + -hicpp-uppercase-literal-suffix, + -hicpp-use-auto, + -hicpp-use-equals-default, + -hicpp-use-nullptr, + -hicpp-vararg, + -llvm-else-after-return, + -llvm-header-guard,, + -llvmlibc-callee-namespace, + -llvmlibc-implementation-in-namespace,, + -llvmlibc-restrict-system-libc-headers, + -misc-definitions-in-headers, + -misc-no-recursion, + -misc-non-private-member-variables-in-classes, + -misc-non-private-member-variables-in-classes, + -misc-unconventional-assign-operator, + -misc-unused-parameters,, + -modernize-avoid-c-arrays, + -modernize-raw-string-literal, + -modernize-redundant-void-arg, + -modernize-use-auto, + -modernize-use-default-member-init, + -modernize-use-equals-default, + -modernize-use-nullptr, + -modernize-use-nullptr, + -modernize-use-trailing-return-type, + -modernize-use-using, + -performance-unnecessary-value-param, + -readability-avoid-const-params-in-decls, + -readability-braces-around-statements, + -readability-braces-around-statements, + -readability-const-return-type, + -readability-container-size-empty, + -readability-convert-member-functions-to-static, + -readability-delete-null-pointer, + -readability-else-after-return, + -readability-identifier-length, + -readability-implicit-bool-conversion, + -readability-isolate-declaration, + -readability-magic-numbers, + -readability-make-member-function-const, + -readability-named-parameter, + -readability-redundant-access-specifiers, + -readability-redundant-declaration, + -readability-redundant-string-init, + -readability-simplify-boolean-expr, + -readability-uppercase-literal-suffix, +FormatStyle: file +HeaderFilterRegex: '.*' +WarningsAsErrors: '' From 72699d93fa3b7c04037bcad2d8fadad900e70e4d Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 15 Aug 2022 22:40:48 +0100 Subject: [PATCH 011/123] Adds clang-format pre-commit hook --- .pre-commit-config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b73b0ad64..700587bab 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,11 @@ --- repos: + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v14.0.6 + hooks: + - id: clang-format + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.0.1 hooks: From a8ddd3b39b3fda76b5e5dbccfa4aae7d647d6b18 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 15 Aug 2022 22:40:48 +0100 Subject: [PATCH 012/123] Adds clang-format pre-commit hook Reformats code --- .pre-commit-config.yaml | 5 +++++ Instances.h | 13 +++++-------- Task/tests/TaskGetter.test.cpp | 2 +- Task/tests/TaskSetter.test.cpp | 3 ++- Trade/tests/TradeSignal.test.cpp | 3 ++- Trade/tests/TradeSignalManager.test.cpp | 3 ++- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b73b0ad64..9fdd623ce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,11 @@ --- repos: + # - repo: https://github.com/pre-commit/mirrors-clang-format + # rev: v14.0.6 + # hooks: + # - id: clang-format + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.0.1 hooks: diff --git a/Instances.h b/Instances.h index 9f1812fa5..e6937f1fa 100644 --- a/Instances.h +++ b/Instances.h @@ -37,21 +37,18 @@ #include "Dict.mqh" #include "Util.h" -template +template class Instances { -public: - + public: static T* instances[]; - Instances(T* _self) { - Util::ArrayPush(instances, _self); - } + Instances(T* _self) { Util::ArrayPush(instances, _self); } ~Instances() { - //Util::ArrayRemove(instances, &this); + // Util::ArrayRemove(instances, &this); } }; -template +template T* Instances::instances[]; #endif // INSTANCES_MQH diff --git a/Task/tests/TaskGetter.test.cpp b/Task/tests/TaskGetter.test.cpp index e34c6dc56..481bdf3c1 100644 --- a/Task/tests/TaskGetter.test.cpp +++ b/Task/tests/TaskGetter.test.cpp @@ -32,4 +32,4 @@ #include "../../Std.h" #include "../../String.extern.h" -int main(int argc, char **argv) {} +int main(int argc, char **argv) { return 0; } diff --git a/Task/tests/TaskSetter.test.cpp b/Task/tests/TaskSetter.test.cpp index c422842f2..7e9d1cda0 100644 --- a/Task/tests/TaskSetter.test.cpp +++ b/Task/tests/TaskSetter.test.cpp @@ -25,10 +25,11 @@ */ // Includes. +#include "../TaskSetter.h" + #include "../../Common.define.h" #include "../../Common.extern.h" #include "../../Std.h" #include "../../String.extern.h" -#include "../TaskSetter.h" int main(int argc, char **argv) {} diff --git a/Trade/tests/TradeSignal.test.cpp b/Trade/tests/TradeSignal.test.cpp index 696ec4422..fc7f0364f 100644 --- a/Trade/tests/TradeSignal.test.cpp +++ b/Trade/tests/TradeSignal.test.cpp @@ -25,10 +25,11 @@ */ // Includes. +#include "../TradeSignal.h" + #include "../../Common.define.h" #include "../../Common.extern.h" #include "../../Std.h" #include "../../String.extern.h" -#include "../TradeSignal.h" int main(int argc, char **argv) {} diff --git a/Trade/tests/TradeSignalManager.test.cpp b/Trade/tests/TradeSignalManager.test.cpp index 7ca976d9f..92f0cb16e 100644 --- a/Trade/tests/TradeSignalManager.test.cpp +++ b/Trade/tests/TradeSignalManager.test.cpp @@ -25,10 +25,11 @@ */ // Includes. +#include "../TradeSignalManager.h" + #include "../../Common.define.h" #include "../../Common.extern.h" #include "../../Std.h" #include "../../String.extern.h" -#include "../TradeSignalManager.h" int main(int argc, char **argv) {} From facfa035e4cb09ad70f5c4c44757122dcdba8803 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 16 Aug 2022 18:23:18 +0200 Subject: [PATCH 013/123] Almost complete IndicatorRenko. Just need to implement RenkoConditionMet() method. --- Candle.struct.h | 2 + Indicator.enum.h | 1 + Indicator/IndicatorRenko.h | 171 ++++++++++++++------- Indicator/IndicatorTf.struct.h | 2 +- Indicator/tests/IndicatorRenko.test.mq5 | 79 ++-------- Indicator/tests/classes/IndicatorTfDummy.h | 2 +- 6 files changed, 137 insertions(+), 120 deletions(-) diff --git a/Candle.struct.h b/Candle.struct.h index 7e351ff17..6e4cd582b 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -221,6 +221,7 @@ struct CandleOHLC * candle. */ template struct CandleOCTOHLC : CandleOHLC { + bool is_complete; long open_timestamp, close_timestamp; // Number of ticks which formed the candle. Also known as volume. @@ -230,6 +231,7 @@ struct CandleOCTOHLC : CandleOHLC { CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, long _open_timestamp = -1, long _close_timestamp = -1, int _volume = 0) : CandleOHLC(_open, _high, _low, _close), + is_complete(true), open_timestamp(_open_timestamp), close_timestamp(_close_timestamp), volume(_volume) { diff --git a/Indicator.enum.h b/Indicator.enum.h index b2b07a3a4..31221ce95 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -101,6 +101,7 @@ enum ENUM_INDICATOR_TYPE { INDI_PRICE_FEEDER, // Indicator which returns prices from custom array INDI_PRICE_VOLUME_TREND, // Price and Volume Trend INDI_RATE_OF_CHANGE, // Rate of Change + INDI_RENKO, // Renko Indicator INDI_RS, // Indi_Math-based RSI INDI_RSI, // Relative Strength Index INDI_RSI_ON_PRICE, // Relative Strength Index (RSI) (on Price) diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index c1ac83c39..b2c839afe 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -40,14 +40,39 @@ #include "IndicatorRenko.struct.h" /** - * Class to deal with candle indicators. + * Renko indicator parameters. */ -template -class IndicatorRenko : public IndicatorCandle { +struct RenkoParams : IndicatorTfParams { + int pips_limit; + + RenkoParams(int _pips_limit = 10, int _shift = 0) : IndicatorTfParams("Renko") { + pips_limit = _pips_limit; + shift = _shift; + }; + RenkoParams(RenkoParams &_params) : IndicatorTfParams("Renko") { THIS_REF = _params; }; + + // Getters. + unsigned int GetSecsPerCandle() { + // Renko doesn't use timeframe-based candles. + return 0; + } +}; + +/** + * Renko candles. + * + * Note that Renko acts as a Candle indicator and thus has the same number of + * modes and same list of ValueStorage buffers as IndicatorCandle one. + */ +class IndicatorRenko : public IndicatorCandle { protected: // Time-frame used to create candles. ENUM_TIMEFRAMES tf; + long last_entry_ts; + long last_completed_candle_ts; + long last_incomplete_candle_ts; + /* Protected methods */ /** @@ -55,7 +80,11 @@ class IndicatorRenko : public IndicatorCandle { * * Called on constructor. */ - void Init() {} + void Init() { + last_entry_ts = 0; + last_completed_candle_ts = 0; + last_incomplete_candle_ts = 0; + } public: /* Special methods */ @@ -63,84 +92,114 @@ class IndicatorRenko : public IndicatorCandle { /** * Class constructor with timeframe enum. */ - IndicatorRenko(unsigned int _spc) { - iparams.SetSecsPerCandle(_spc); + IndicatorRenko(int _pips_limit = 10) { + iparams.pips_limit = _pips_limit; Init(); } /** - * Class constructor with timeframe enum. + * Class constructor with parameters. */ - IndicatorRenko(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - iparams.SetSecsPerCandle(ChartTf::TfToSeconds(_tf)); - tf = _tf; + IndicatorRenko(RenkoParams &_params) + : IndicatorCandle(_params, IndicatorDataParams(FINAL_INDI_CANDLE_MODE_ENTRY)) { Init(); } /** - * Class constructor with timeframe index. + * */ - IndicatorRenko(ENUM_TIMEFRAMES_INDEX _tfi = 0) { - iparams.SetSecsPerCandle(ChartTf::TfToSeconds(ChartTf::IndexToTf(_tfi))); - tf = ChartTf::IndexToTf(_tfi); - Init(); + bool RenkoConditionMet(CandleOCTOHLC &_candle, double _price) { + Print("RenkoConditionMet: ", _candle.close, " ? ", _price); + return true; } /** - * Class constructor with parameters. + * Called when data source emits new entry (historic or future one). */ - IndicatorRenko(TFP &_params) : IndicatorCandle(_params) { Init(); } + void OnDataSourceEntry(IndicatorDataEntry &entry) override { + if (entry.timestamp < last_entry_ts) { + Print("Error: IndicatorRenko doesn't support sending entries in non-ascending order!"); + DebugBreak(); + } - /** - * Returns time of the bar for a given shift (MT-compatible shift). - */ - datetime GetBarTimeLegacy(int _shift = 0) { - // Note: iTime() in MT4 build can return not rounded values. - datetime _curr = (datetime)CalcCandleTimestamp(::iTime(GetSymbol(), GetTf(), fmax(0, _shift))); - datetime _last_valid = 0; - -#ifdef __MQL4__ - if (GetLastError() == ERR_HISTORY_WILL_UPDATED) { - // Workaround for MT4 history data issues. - // See: https://www.mql5.com/en/forum/155707 - for (int i = 0; i < 10; i++) { - Sleep(1000); - _curr = ::iTime(GetSymbol(), GetTf(), 0); - if (GetLastError() != ERR_HISTORY_WILL_UPDATED) { - break; - } - SetUserError(ERR_HISTORY_WILL_UPDATED); + // We'll be updating candle from bid price. + double _price = entry[1]; + + CandleOCTOHLC _candle; + + if (last_incomplete_candle_ts != 0) { + // There is previous candle. Retrieving and updating it. + _candle = icdata.GetByKey(last_incomplete_candle_ts); + _candle.Update(entry.timestamp, _price); + + // Checking for close price difference. + if (RenkoConditionMet(_candle, _price)) { + // Closing current candle. + _candle.is_complete = true; } - } -#endif - while (_curr >= icdata.GetMin()) { - if (icdata.KeyExists(_curr)) { - _last_valid = _curr; - if (_shift-- == 0) { - return _curr; - } + + // Updating candle. + icdata.Add(_candle, last_incomplete_candle_ts); + + if (_candle.is_complete) { + last_completed_candle_ts = last_incomplete_candle_ts; + last_incomplete_candle_ts = 0; } - // Going back in time by TF. - _curr -= ChartTf::TfToSeconds(tf); + } else { + // There is no incomplete candle, creating one. + _candle = CandleOCTOHLC(_price, _price, _price, _price, entry.timestamp, entry.timestamp); + _candle.is_complete = false; + + // Creating new candle. + icdata.Add(_candle, entry.timestamp); + + last_incomplete_candle_ts = entry.timestamp; } - // No entry found. Returning last valid candle. - if (icdata.KeyExists(_last_valid)) { - return _last_valid; - } else { - // Not a single valid candle found. - return 0; + // Updating tick & bar indices. Bar time is time of the last incomplete candle. + counter.OnTick(last_incomplete_candle_ts); + + last_entry_ts = entry.timestamp; + }; + + /** + * Adds tick's price to the matching candle and updates its OHLC values. + */ + void UpdateCandle(long _tick_timestamp, double _price) { + long _candle_timestamp = CalcCandleTimestamp(_tick_timestamp); + +#ifdef __debug_verbose__ + 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 } - } - /* Virtual methods */ + icdata.Add(_candle, _candle_timestamp); + } /** * Returns time of the bar for a given shift. */ datetime GetBarTime(int _shift = 0) override { - // @fixit Should be replaced by MT-compatible bar time calculation for the given shift. - return GetBarTimeLegacy(_shift); + // @todo + DebugBreak(); + return 0; } /** diff --git a/Indicator/IndicatorTf.struct.h b/Indicator/IndicatorTf.struct.h index 7259d6d9b..9675afd5f 100644 --- a/Indicator/IndicatorTf.struct.h +++ b/Indicator/IndicatorTf.struct.h @@ -38,7 +38,7 @@ struct IndicatorTfParams : IndicatorParams { ChartTf tf; unsigned int spc; // Seconds per candle. // Struct constructor. - IndicatorTfParams(unsigned int _spc = 60) : spc(_spc) {} + IndicatorTfParams(string _name = "", unsigned int _spc = 60) : IndicatorParams(_name), spc(_spc) {} // Getters. unsigned int GetSecsPerCandle() { return spc; } // Setters. diff --git a/Indicator/tests/IndicatorRenko.test.mq5 b/Indicator/tests/IndicatorRenko.test.mq5 index 52e52c5f7..d571705ad 100644 --- a/Indicator/tests/IndicatorRenko.test.mq5 +++ b/Indicator/tests/IndicatorRenko.test.mq5 @@ -36,12 +36,8 @@ #include "../IndicatorTick.h" #include "classes/Indicators.h" -Ref indi_tick; -Ref indi_ama; -Ref indi_ama_orig; -Ref indi_ama_orig_sim; -Ref indi_ama_oncalculate; -Ref indi_ama_custom; +Ref indi_tick; +Ref indi_renko; /** * Implements OnInit(). @@ -51,55 +47,15 @@ int OnInit() { // Platform ticks. indi_tick = Platform::FetchDefaultTickIndicator(); - // @todo: E.g. 1 pip candles, 10 pip candles + // Renko with 10 pips limit. + indi_renko = new IndicatorRenko(10); - // float _pip_value = SymbolInfoStatic::GetPipValue(_Symbol); + double _pip_value = SymbolInfoStatic::GetPipValue(_Symbol); + Print("Pip Value: ", _pip_value); - /* - // 1-second candles. - // indicators.Add(indi_tf = new IndicatorRenkoDummy(1)); + // Renko will be run over default tick indicator. + indi_renko.Ptr().SetDataSource(indi_tick.Ptr()); - // 1:1 candles from platform using current timeframe. - indi_renko_real = Platform::FetchDefaultCandleIndicator(); - - // 1-second candles. - // indicators.Add(indi_ama = new Indi_AMA()); - - IndiAMAParams _ama_params; - _ama_params.applied_price = PRICE_OPEN; - - // AMA on platform candles. - Platform::Add(indi_ama_orig_sim = new Indi_AMA(_ama_params)); - - // Original built-in AMA indicator on platform OHLCs. - _ama_params.SetDataSourceType(IDATA_BUILTIN); - Platform::Add(indi_ama_orig = new Indi_AMA(_ama_params)); - indi_ama_orig.Ptr().SetDataSource(indi_renko_real.Ptr()); - - // OnCalculate()-based version of AMA indicator on platform OHLCs. - _ama_params.SetDataSourceType(IDATA_ONCALCULATE); - Platform::Add(indi_ama_oncalculate = new Indi_AMA(_ama_params)); - indi_ama_oncalculate.Ptr().SetDataSource(indi_renko_real.Ptr()); - - // iCustom()-based version of AMA indicator on platform OHLCs. - _ama_params.SetDataSourceType(IDATA_ICUSTOM); - Platform::Add(indi_ama_custom = new Indi_AMA(_ama_params)); - indi_ama_custom.Ptr().SetDataSource(indi_renko_real.Ptr()); - - // Candles will be initialized from tick's history. - // indi_tf.Ptr().SetDataSource(indi_tick.Ptr()); - indi_renko_real.Ptr().SetDataSource(indi_tick.Ptr()); - - // AMA will work on the candle indicator. - // indi_ama.Ptr().SetDataSource(indi_tf.Ptr()); - - // AMA will work on the simulation of real candles. - indi_ama_orig_sim.Ptr().SetDataSource(indi_renko_real.Ptr()); - */ - - // 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()); return (INIT_SUCCEEDED); } @@ -110,7 +66,7 @@ void OnTick() { Platform::Tick(); #ifdef __debug__ - if (indi_renko_real.Ptr().IsNewBar()) { + if (indi_renko.Ptr().IsNewBar()) { Print("New bar: ", indi_renko_real.Ptr().GetBarIndex()); } @@ -120,17 +76,16 @@ void OnTick() { string c = DoubleToStr(iClose(_Symbol, PERIOD_CURRENT, 0), 5); string time = TimeToString(iTime(_Symbol, PERIOD_CURRENT, 0), TIME_DATE | TIME_MINUTES | TIME_SECONDS); - Util::Print( - "Tick: " + IntegerToString((long)iTime(indi_renko_real.Ptr().GetSymbol(), indi_renko_real.Ptr().GetTf(), 0)) + - " (" + time + "), real = " + o + ", " + h + ", " + l + ", " + c); + Util::Print("Tick: " + IntegerToString((long)iTime(indi_renko.Ptr().GetSymbol(), indi_renko.Ptr().GetTf(), 0)) + + " (" + time + "), real = " + o + ", " + h + ", " + l + ", " + c); - string c_o = DoubleToStr(indi_renko_real.Ptr().GetOpen(0), 5); - string c_h = DoubleToStr(indi_renko_real.Ptr().GetHigh(0), 5); - string c_l = DoubleToStr(indi_renko_real.Ptr().GetLow(0), 5); - string c_c = DoubleToStr(indi_renko_real.Ptr().GetClose(0), 5); + string c_o = DoubleToStr(indi_renko.Ptr().GetOpen(0), 5); + string c_h = DoubleToStr(indi_renko.Ptr().GetHigh(0), 5); + string c_l = DoubleToStr(indi_renko.Ptr().GetLow(0), 5); + string c_c = DoubleToStr(indi_renko.Ptr().GetClose(0), 5); - Util::Print("Tick: " + IntegerToString(indi_renko_real.Ptr().GetBarTime(0)) + " (" + time + "), candle = " + c_o + - ", " + c_h + ", " + c_l + ", " + c_c); + Util::Print("Tick: " + IntegerToString(indi_renko.Ptr().GetBarTime(0)) + " (" + time + "), candle = " + c_o + ", " + + c_h + ", " + c_l + ", " + c_c); Util::Print(Platform::IndicatorsToString(0)); #endif diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 019b800d8..1a346f539 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -34,7 +34,7 @@ // Params for dummy candle-based indicator. struct IndicatorTfDummyParams : IndicatorTfParams { - IndicatorTfDummyParams(unsigned int _spc = 60) : IndicatorTfParams(_spc) {} + IndicatorTfDummyParams(unsigned int _spc = 60) : IndicatorTfParams("IndicatorTf", _spc) {} }; /** From 155a9fe67eed4797bd95c2c8f0f47c740ba1e84a Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 17 Aug 2022 18:23:00 +0200 Subject: [PATCH 014/123] Almost working Renko. Somehow platform's Tick() is executed more often than EmitEntry() from Indi_TickMt. --- Indicator/IndicatorRenko.h | 61 ++++++++----------------- Indicator/TickBarCounter.h | 8 ++++ Indicator/tests/IndicatorRenko.test.mq5 | 34 +++++--------- SymbolInfo.struct.static.h | 2 +- 4 files changed, 39 insertions(+), 66 deletions(-) diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index b2c839afe..a7dc9aa9a 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -66,7 +66,7 @@ struct RenkoParams : IndicatorTfParams { */ class IndicatorRenko : public IndicatorCandle { protected: - // Time-frame used to create candles. + // @todo Time-frame used to create candles. ENUM_TIMEFRAMES tf; long last_entry_ts; @@ -106,11 +106,12 @@ class IndicatorRenko : public IndicatorCandle { } /** - * + * Checks for pips limit. */ bool RenkoConditionMet(CandleOCTOHLC &_candle, double _price) { - Print("RenkoConditionMet: ", _candle.close, " ? ", _price); - return true; + double _price_diff_limit = GetSymbolProps().GetPipValue() * iparams.pips_limit; + double _price_diff = MathAbs(_price - _candle.open); + return _price_diff >= _price_diff_limit; } /** @@ -156,56 +157,32 @@ class IndicatorRenko : public IndicatorCandle { last_incomplete_candle_ts = entry.timestamp; } - // Updating tick & bar indices. Bar time is time of the last incomplete candle. - counter.OnTick(last_incomplete_candle_ts); + // Updating tick & bar indices. Bar time is time of the last completed candle. + // Print(last_completed_candle_ts); + counter.OnTick(last_completed_candle_ts); last_entry_ts = entry.timestamp; }; /** - * Adds tick's price to the matching candle and updates its OHLC values. + * Gets indicator's time-frame. */ - void UpdateCandle(long _tick_timestamp, double _price) { - long _candle_timestamp = CalcCandleTimestamp(_tick_timestamp); - -#ifdef __debug_verbose__ - 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); - } + ENUM_TIMEFRAMES GetTf() override { return tf; } /** * Returns time of the bar for a given shift. + * + * Note: For Renko it returns last completed bar. */ datetime GetBarTime(int _shift = 0) override { - // @todo - DebugBreak(); - return 0; - } + if (_shift != 0) { + Print("Error: IndicatorRenko doesn't yet support shift other than 0!"); + DebugBreak(); + return 0; + } - /** - * Gets indicator's time-frame. - */ - ENUM_TIMEFRAMES GetTf() override { return tf; } + return (datetime)last_completed_candle_ts; + } }; #endif diff --git a/Indicator/TickBarCounter.h b/Indicator/TickBarCounter.h index 47d227631..a809061b6 100644 --- a/Indicator/TickBarCounter.h +++ b/Indicator/TickBarCounter.h @@ -42,6 +42,13 @@ struct TickBarCounter { // Index of the current tick. int tick_index; + TickBarCounter() { + last_bar_time = (datetime)0; + bar_index = 0; + is_new_bar = false; + tick_index = 0; + } + /** * Increases current bar index (used in OnTick()). If there was no bar, the current bar will become 0. */ @@ -101,6 +108,7 @@ struct TickBarCounter { if (is_new_bar) { // IsNewBar() will no longer signal new bar. + Print("Was new bar. Clearing flag."); is_new_bar = false; } diff --git a/Indicator/tests/IndicatorRenko.test.mq5 b/Indicator/tests/IndicatorRenko.test.mq5 index d571705ad..c8d6e3199 100644 --- a/Indicator/tests/IndicatorRenko.test.mq5 +++ b/Indicator/tests/IndicatorRenko.test.mq5 @@ -36,6 +36,8 @@ #include "../IndicatorTick.h" #include "classes/Indicators.h" +#define __debug__x + Ref indi_tick; Ref indi_renko; @@ -48,7 +50,7 @@ int OnInit() { indi_tick = Platform::FetchDefaultTickIndicator(); // Renko with 10 pips limit. - indi_renko = new IndicatorRenko(10); + Platform::Add(indi_renko = new IndicatorRenko(10)); double _pip_value = SymbolInfoStatic::GetPipValue(_Symbol); Print("Pip Value: ", _pip_value); @@ -65,30 +67,16 @@ int OnInit() { void OnTick() { Platform::Tick(); -#ifdef __debug__ if (indi_renko.Ptr().IsNewBar()) { - Print("New bar: ", indi_renko_real.Ptr().GetBarIndex()); + string c_o = DoubleToStr(indi_renko.Ptr().GetOpen(0), 5); + string c_h = DoubleToStr(indi_renko.Ptr().GetHigh(0), 5); + string c_l = DoubleToStr(indi_renko.Ptr().GetLow(0), 5); + string c_c = DoubleToStr(indi_renko.Ptr().GetClose(0), 5); + string time = TimeToString(indi_renko.Ptr().GetBarTime(0), TIME_DATE | TIME_MINUTES | TIME_SECONDS); + + Util::Print("Bar: " + IntegerToString(indi_renko.Ptr().GetBarTime(0)) + " (" + time + "), candle = " + c_o + ", " + + c_h + ", " + c_l + ", " + c_c); } - - 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), TIME_DATE | TIME_MINUTES | TIME_SECONDS); - - Util::Print("Tick: " + IntegerToString((long)iTime(indi_renko.Ptr().GetSymbol(), indi_renko.Ptr().GetTf(), 0)) + - " (" + time + "), real = " + o + ", " + h + ", " + l + ", " + c); - - string c_o = DoubleToStr(indi_renko.Ptr().GetOpen(0), 5); - string c_h = DoubleToStr(indi_renko.Ptr().GetHigh(0), 5); - string c_l = DoubleToStr(indi_renko.Ptr().GetLow(0), 5); - string c_c = DoubleToStr(indi_renko.Ptr().GetClose(0), 5); - - Util::Print("Tick: " + IntegerToString(indi_renko.Ptr().GetBarTime(0)) + " (" + time + "), candle = " + c_o + ", " + - c_h + ", " + c_l + ", " + c_c); - - Util::Print(Platform::IndicatorsToString(0)); -#endif } /** diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index a33431610..ee641b4f0 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -128,7 +128,7 @@ struct SymbolInfoStatic { */ static double GetPipValue(string _symbol) { unsigned int _pdigits = GetPipDigits(_symbol); - return 10 >> _pdigits; + return 1.0 / MathPow(10, _pdigits); } /** From a2bdfe33c4555071b9862cd7e593bd6ac5f55a2a Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 19 Aug 2022 18:44:00 +0200 Subject: [PATCH 015/123] Almost working Renko indicator. There is a problem with completed candles that are cleared somehow when adding new candles. --- Candle.struct.h | 8 +++ Indicator/IndicatorRenko.h | 93 +++++++++++++++++++++++-- Indicator/IndicatorTick.h | 2 + Indicator/TickBarCounter.h | 8 +-- Indicator/tests/IndicatorRenko.test.mq5 | 2 +- Indicator/tests/classes/Indicators.h | 4 +- IndicatorData.mqh | 20 +++--- Indicators/Tick/Indi_TickMt.mqh | 2 +- Platform.h | 15 +++- 9 files changed, 127 insertions(+), 27 deletions(-) diff --git a/Candle.struct.h b/Candle.struct.h index 6e4cd582b..f7034a1f3 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -261,6 +261,14 @@ struct CandleOCTOHLC : CandleOHLC { // Returns timestamp of close price. long GetCloseTimestamp() { return close_timestamp; } + + // Returns text representation of candle. + string ToString() { + return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", open, high, low, close, + is_complete ? "Complete" : "Incomplete", + TimeToString(open_timestamp, TIME_DATE | TIME_MINUTES | TIME_SECONDS), + TimeToString(close_timestamp, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); + } }; /* Structore for storing OHLC values with timestamp. */ diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index a7dc9aa9a..a226124be 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -39,6 +39,15 @@ #include "IndicatorCandle.h" #include "IndicatorRenko.struct.h" +/** + * Renko candle type. + */ +enum ENUM_INDI_RENKO_CANDLE_TYPE { + INDI_RENKO_CANDLE_TYPE_NONE, // Empty candle. + INDI_RENKO_CANDLE_TYPE_RAISE, // Green candle. + INDI_RENKO_CANDLE_TYPE_DROP, // Red candle. +}; + /** * Renko indicator parameters. */ @@ -105,13 +114,56 @@ class IndicatorRenko : public IndicatorCandle { Init(); } + /** + * Checks whether given candle is a raise (green) or drop (red). + */ + ENUM_INDI_RENKO_CANDLE_TYPE GetCandleType(CandleOCTOHLC &_candle) { + if (_candle.close > _candle.open) { + return INDI_RENKO_CANDLE_TYPE_RAISE; + } + + if (_candle.close < _candle.open) { + return INDI_RENKO_CANDLE_TYPE_DROP; + } + + Print("Error: Candle's close price cannot equal open price!"); + DebugBreak(); + return INDI_RENKO_CANDLE_TYPE_NONE; + } + /** * Checks for pips limit. */ - bool RenkoConditionMet(CandleOCTOHLC &_candle, double _price) { + bool RenkoConditionMet(ENUM_INDI_RENKO_CANDLE_TYPE _last_candle_type, CandleOCTOHLC &_candle, double _price) { double _price_diff_limit = GetSymbolProps().GetPipValue() * iparams.pips_limit; - double _price_diff = MathAbs(_price - _candle.open); - return _price_diff >= _price_diff_limit; + double _price_diff = _price - _candle.open; + + if (_last_candle_type == INDI_RENKO_CANDLE_TYPE_NONE) { + // No candle and then raise/drop requires just normal difference of pips. + if (MathAbs(_price_diff) > _price_diff_limit) { + return true; + } + } else { + if (_last_candle_type == INDI_RENKO_CANDLE_TYPE_RAISE) { + if (_price_diff > _price_diff_limit) { + // Raising after raise. + return true; + } else if (_price_diff < -_price_diff_limit * 2) { + // Drop after raise requires 2 x pips drop. + return true; + } + } else if (_last_candle_type == INDI_RENKO_CANDLE_TYPE_DROP) { + if (_price_diff > _price_diff_limit * 2) { + // Raising after drop requires 2 x pips raise. + return true; + } else if (_price_diff < -_price_diff_limit) { + // Drop after drop. + return true; + } + } + } + + return false; } /** @@ -127,6 +179,15 @@ class IndicatorRenko : public IndicatorCandle { double _price = entry[1]; CandleOCTOHLC _candle; + CandleOCTOHLC _last_completed_candle; + ENUM_INDI_RENKO_CANDLE_TYPE _last_completed_candle_type; + + if (last_completed_candle_ts != 0) { + _last_completed_candle = icdata.GetByKey(last_completed_candle_ts); + _last_completed_candle_type = GetCandleType(_last_completed_candle); + } else { + _last_completed_candle_type = INDI_RENKO_CANDLE_TYPE_NONE; + } if (last_incomplete_candle_ts != 0) { // There is previous candle. Retrieving and updating it. @@ -134,7 +195,7 @@ class IndicatorRenko : public IndicatorCandle { _candle.Update(entry.timestamp, _price); // Checking for close price difference. - if (RenkoConditionMet(_candle, _price)) { + if (RenkoConditionMet(_last_completed_candle_type, _candle, _price)) { // Closing current candle. _candle.is_complete = true; } @@ -142,25 +203,47 @@ class IndicatorRenko : public IndicatorCandle { // Updating candle. icdata.Add(_candle, last_incomplete_candle_ts); + Print("Updated Candle: ", _candle.ToString()); + if (_candle.is_complete) { last_completed_candle_ts = last_incomplete_candle_ts; last_incomplete_candle_ts = 0; } } else { // There is no incomplete candle, creating one. - _candle = CandleOCTOHLC(_price, _price, _price, _price, entry.timestamp, entry.timestamp); + if (last_completed_candle_ts != 0) { + // Price of the last candle will be used to initialize open price for new, incomplete candle. + double _last_close_price = _last_completed_candle.close; + _candle = CandleOCTOHLC(_last_close_price, _last_close_price, _last_close_price, _last_close_price, + entry.timestamp, entry.timestamp); + // Current price will be added to newly created incomplete candle. + _candle.Update(entry.timestamp, _price); + } else { + // There was no completed candle. Creating new, incomplete candle from current price. + _candle = CandleOCTOHLC(_price, _price, _price, _price, entry.timestamp, entry.timestamp); + } + _candle.is_complete = false; // Creating new candle. icdata.Add(_candle, entry.timestamp); + Print("Added candle: ", _candle.ToString()); + last_incomplete_candle_ts = entry.timestamp; } + Print("Last Incomplete Time: ", TimeToString(last_incomplete_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); + Print("Last Incomplete Candle: ", icdata.GetByKey(last_incomplete_candle_ts).ToString()); + Print("Last Completed Time: ", TimeToString(last_completed_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); + Print("Last Completed Candle: ", icdata.GetByKey(last_completed_candle_ts).ToString()); + // Updating tick & bar indices. Bar time is time of the last completed candle. // Print(last_completed_candle_ts); counter.OnTick(last_completed_candle_ts); + Print("---------"); + last_entry_ts = entry.timestamp; }; diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 5438923cb..5f78a1882 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -33,6 +33,7 @@ #include "../Buffer/BufferTick.h" #include "../Indicator.mqh" #include "../Indicator.struct.h" +#include "TickBarCounter.h" // Indicator modes. enum ENUM_INDI_TICK_MODE { @@ -51,6 +52,7 @@ class IndicatorTick : public Indicator { TS itparams; string symbol; SymbolInfoProp symbol_props; + TickBarCounter counter; protected: /* Protected methods */ diff --git a/Indicator/TickBarCounter.h b/Indicator/TickBarCounter.h index a809061b6..45f0a102c 100644 --- a/Indicator/TickBarCounter.h +++ b/Indicator/TickBarCounter.h @@ -75,12 +75,11 @@ struct TickBarCounter { * 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 true; } - return _result; + return false; } /* Setters */ @@ -103,12 +102,11 @@ struct TickBarCounter { /** * Updates tick & bar indices. */ - void OnTick(datetime _bar_time) { + void OnTick(datetime _bar_time = 0) { IncreaseTickIndex(); if (is_new_bar) { // IsNewBar() will no longer signal new bar. - Print("Was new bar. Clearing flag."); is_new_bar = false; } diff --git a/Indicator/tests/IndicatorRenko.test.mq5 b/Indicator/tests/IndicatorRenko.test.mq5 index c8d6e3199..483749ff6 100644 --- a/Indicator/tests/IndicatorRenko.test.mq5 +++ b/Indicator/tests/IndicatorRenko.test.mq5 @@ -50,7 +50,7 @@ int OnInit() { indi_tick = Platform::FetchDefaultTickIndicator(); // Renko with 10 pips limit. - Platform::Add(indi_renko = new IndicatorRenko(10)); + Platform::Add(indi_renko = new IndicatorRenko(1)); double _pip_value = SymbolInfoStatic::GetPipValue(_Symbol); Print("Pip Value: ", _pip_value); diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h index 1d1da2066..562a52b5a 100644 --- a/Indicator/tests/classes/Indicators.h +++ b/Indicator/tests/classes/Indicators.h @@ -53,9 +53,9 @@ class Indicators { /** * Executes OnTick() on every added indicator. */ - void Tick() { + void Tick(int _global_tick_index) { for (int i = 0; i < ArraySize(_indis); ++i) { - _indis[i].Ptr().OnTick(); + _indis[i].Ptr().OnTick(_global_tick_index); } } diff --git a/IndicatorData.mqh b/IndicatorData.mqh index 46225b8d3..4e27e1763 100644 --- a/IndicatorData.mqh +++ b/IndicatorData.mqh @@ -41,7 +41,7 @@ class IndicatorData : public IndicatorBase { 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. + int last_tick_index; // Index of the last tick. void* mydata; ENUM_INDI_VS_TYPE retarget_ap_av; // Value storage type to be used as applied price/volume. ARRAY(Ref, value_storages); @@ -77,7 +77,7 @@ class IndicatorData : public IndicatorBase { // 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; + last_tick_index = -1; retarget_ap_av = INDI_VS_TYPE_NONE; InitDraw(); return true; @@ -851,29 +851,27 @@ class IndicatorData : public IndicatorBase { HasSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME); } - void Tick() { - long _current_time = TimeCurrent(); - - if (last_tick_time == _current_time) { + void Tick(int _global_tick_index) { + if (last_tick_index == _global_tick_index) { // We've already ticked. return; } - last_tick_time = _current_time; + last_tick_index = _global_tick_index; // Checking and potentially initializing new data source. if (HasDataSource(true) != NULL) { // Ticking data source if not yet ticked. - GetDataSource().Tick(); + GetDataSource().Tick(_global_tick_index); } // Also ticking all used indicators if they've not yet ticked. for (DictStructIterator> iter = indicators.Begin(); iter.IsValid(); ++iter) { - iter.Value().Ptr().Tick(); + iter.Value().Ptr().Tick(_global_tick_index); } // Overridable OnTick() method. - OnTick(); + OnTick(_global_tick_index); } /** @@ -1685,7 +1683,7 @@ class IndicatorData : public IndicatorBase { */ virtual void OnDataSourceEntry(IndicatorDataEntry& entry){}; - virtual void OnTick() {} + virtual void OnTick(int _global_tick_index) {} /** * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 726004fff..2e950c955 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -182,7 +182,7 @@ class Indi_TickMt : public IndicatorTick { #endif } - void OnTick() override { + void OnTick(int _global_tick_index) 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; diff --git a/Platform.h b/Platform.h index 88ec23736..c1f97aceb 100644 --- a/Platform.h +++ b/Platform.h @@ -43,6 +43,9 @@ class Platform { // Whether Init() was already called. static bool initialized; + // Global tick index. + static int global_tick_index; + // Date and time used to determine periods that passed. static DateTime time; @@ -74,10 +77,17 @@ class Platform { time.Update(); } + /** + * Returns global tick index. + */ + int GetGlobalTickIndex() { return global_tick_index; } + /** * Performs tick on every added indicator. */ static void Tick() { + ++global_tick_index; + // Checking starting periods and updating time to current one. time_flags = time.GetStartedPeriods(); time.Update(); @@ -85,11 +95,11 @@ class Platform { DictStructIterator> _iter; for (_iter = indis.Begin(); _iter.IsValid(); ++_iter) { - _iter.Value() REF_DEREF Tick(); + _iter.Value() REF_DEREF Tick(global_tick_index); } for (_iter = indis_dflt.Begin(); _iter.IsValid(); ++_iter) { - _iter.Value() REF_DEREF Tick(); + _iter.Value() REF_DEREF Tick(global_tick_index); } // Will check for new time periods in consecutive Platform::UpdateTime(). @@ -306,6 +316,7 @@ bool Platform::initialized = false; DateTime Platform::time = 0; unsigned int Platform::time_flags = 0; bool Platform::time_clear_flags = true; +int Platform::global_tick_index = 0; DictStruct> Platform::indis; DictStruct> Platform::indis_dflt; From 0ecb54d5a12ef1cd065b3c22f8a4effe1a9cb426 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 8 Aug 2022 00:57:37 +0100 Subject: [PATCH 016/123] Moves Indicator related files into Indicator/ --- .github/workflows/test-indicator.yml | 3 + .github/workflows/test.yml | 1 - 3D/Chart3D.h | 2 +- Account/AccountMt.h | 3 +- BufferFXT.mqh | 3 +- Chart.mqh | 8 +- Chart.struct.h | 2 + Chart.struct.serialize.h | 2 +- Chart.struct.tf.h | 7 +- ChartMt.h | 1 + DictBase.mqh | 1 - DictIteratorBase.mqh | 7 +- DictSlot.mqh | 2 +- DictSlotsRef.h | 1 + DictStruct.mqh | 4 - Draw.mqh | 2 +- File.mqh | 3 +- .../Indicator.define.h | 3 - .../Indicator.enum.h | 52 ------------- Indicator.mqh => Indicator/Indicator.h | 43 ++++++----- .../Indicator.struct.h | 68 ++--------------- .../Indicator.struct.serialize.h | 7 +- IndicatorBase.h => Indicator/IndicatorBase.h | 75 ++++--------------- Indicator/IndicatorCandle.h | 4 +- .../IndicatorData.enum.h | 51 +++++++++++++ .../IndicatorData.h | 72 +++++++++++++++--- .../IndicatorData.struct.cache.h | 4 +- .../IndicatorData.struct.h | 55 +++++++++++++- .../IndicatorData.struct.serialize.h | 2 +- .../IndicatorData.struct.signal.h | 0 Indicator/IndicatorTf.h | 2 +- Indicator/IndicatorTf.struct.h | 2 +- Indicator/IndicatorTick.h | 4 +- Indicator/IndicatorTickSource.h | 2 +- .../tests/Indicator.test.mq4 | 4 +- .../tests/Indicator.test.mq5 | 6 +- .../tests/IndicatorBase.test.mq4 | 2 +- .../tests/IndicatorBase.test.mq5 | 2 +- .../tests/IndicatorData.test.mq4 | 2 +- .../tests/IndicatorData.test.mq5 | 4 +- Indicator/tests/IndicatorTf.test.mq5 | 5 +- Indicator/tests/IndicatorTick.test.mq5 | 1 + Indicator/tests/classes/Indicators.h | 2 +- Indicators/Bitwise/Indi_Candle.mqh | 2 +- Indicators/Bitwise/Indi_Pattern.mqh | 2 +- Indicators/Indi_AC.mqh | 2 +- Indicators/Indi_AD.mqh | 2 +- Indicators/Indi_ADX.mqh | 2 +- Indicators/Indi_ADXW.mqh | 2 +- Indicators/Indi_AMA.mqh | 4 +- Indicators/Indi_AO.mqh | 2 +- Indicators/Indi_ASI.mqh | 2 +- Indicators/Indi_ATR.mqh | 2 +- Indicators/Indi_Alligator.mqh | 2 +- Indicators/Indi_AppliedPrice.mqh | 2 +- Indicators/Indi_BWMFI.mqh | 2 +- Indicators/Indi_Bands.mqh | 2 +- Indicators/Indi_BearsPower.mqh | 2 +- Indicators/Indi_BullsPower.mqh | 2 +- Indicators/Indi_CCI.mqh | 2 +- Indicators/Indi_CHO.mqh | 2 +- Indicators/Indi_CHV.mqh | 2 +- Indicators/Indi_ColorBars.mqh | 2 +- Indicators/Indi_ColorCandlesDaily.mqh | 2 +- Indicators/Indi_ColorLine.mqh | 2 +- Indicators/Indi_CustomMovingAverage.mqh | 2 +- Indicators/Indi_DEMA.mqh | 2 +- Indicators/Indi_DeMarker.mqh | 2 +- Indicators/Indi_Demo.mqh | 2 +- Indicators/Indi_DetrendedPrice.mqh | 2 +- Indicators/Indi_Drawer.mqh | 2 +- Indicators/Indi_Drawer.struct.h | 2 +- Indicators/Indi_Envelopes.mqh | 2 +- Indicators/Indi_Force.mqh | 2 +- Indicators/Indi_FractalAdaptiveMA.mqh | 2 +- Indicators/Indi_Fractals.mqh | 2 +- Indicators/Indi_Gator.mqh | 2 +- Indicators/Indi_HeikenAshi.mqh | 2 +- Indicators/Indi_Ichimoku.mqh | 2 +- Indicators/Indi_Killzones.mqh | 2 +- Indicators/Indi_MA.mqh | 2 +- Indicators/Indi_MACD.mqh | 2 +- Indicators/Indi_MFI.mqh | 2 +- Indicators/Indi_MassIndex.mqh | 2 +- Indicators/Indi_Momentum.mqh | 2 +- Indicators/Indi_OBV.mqh | 2 +- Indicators/Indi_OsMA.mqh | 2 +- Indicators/Indi_Pivot.mqh | 2 +- Indicators/Indi_PriceChannel.mqh | 2 +- Indicators/Indi_PriceFeeder.mqh | 2 +- Indicators/Indi_PriceVolumeTrend.mqh | 2 +- Indicators/Indi_RS.mqh | 2 +- Indicators/Indi_RSI.mqh | 2 +- Indicators/Indi_RVI.mqh | 2 +- Indicators/Indi_RateOfChange.mqh | 2 +- Indicators/Indi_SAR.mqh | 2 +- Indicators/Indi_StdDev.mqh | 2 +- Indicators/Indi_Stochastic.mqh | 2 +- Indicators/Indi_TEMA.mqh | 2 +- Indicators/Indi_TRIX.mqh | 2 +- Indicators/Indi_UltimateOscillator.mqh | 2 +- Indicators/Indi_VIDYA.mqh | 2 +- Indicators/Indi_VROC.mqh | 2 +- Indicators/Indi_Volumes.mqh | 2 +- Indicators/Indi_WPR.mqh | 2 +- Indicators/Indi_WilliamsAD.mqh | 2 +- Indicators/Indi_ZigZag.mqh | 2 +- Indicators/Indi_ZigZagColor.mqh | 2 +- Indicators/OHLC/Indi_OHLC.mqh | 2 +- Indicators/Price/Indi_Price.mqh | 2 +- Indicators/Special/Indi_Custom.mqh | 2 +- Indicators/Special/Indi_Math.mqh | 2 +- Log.mqh | 12 ++- Market.mqh | 15 +--- Market.struct.h | 12 +++ Math.h | 2 +- Order.mqh | 5 ++ Platform.h | 2 +- Serializer.mqh | 16 ---- SerializerConverter.mqh | 7 +- Storage/ValueStorage.history.h | 5 +- Storage/ValueStorage.price_median.h | 3 + Strategy.mqh | 2 +- SymbolInfo.mqh | 11 ++- Terminal.enum.h | 2 +- Tests.mqh | 2 +- Trade.mqh | 4 +- tests/CompileTest.mq5 | 8 +- tests/DrawIndicatorTest.mq5 | 2 +- tests/IndicatorsTest.mq5 | 2 +- tests/LogTest.mq5 | 1 + tests/SerializerTest.mq5 | 1 + 132 files changed, 397 insertions(+), 383 deletions(-) rename Indicator.define.h => Indicator/Indicator.define.h (99%) rename Indicator.enum.h => Indicator/Indicator.enum.h (84%) rename Indicator.mqh => Indicator/Indicator.h (96%) rename Indicator.struct.h => Indicator/Indicator.struct.h (69%) rename Indicator.struct.serialize.h => Indicator/Indicator.struct.serialize.h (95%) rename IndicatorBase.h => Indicator/IndicatorBase.h (89%) rename IndicatorData.enum.h => Indicator/IndicatorData.enum.h (53%) rename IndicatorData.mqh => Indicator/IndicatorData.h (97%) rename Indicator.struct.cache.h => Indicator/IndicatorData.struct.cache.h (99%) rename IndicatorData.struct.h => Indicator/IndicatorData.struct.h (90%) rename IndicatorData.struct.serialize.h => Indicator/IndicatorData.struct.serialize.h (99%) rename IndicatorData.struct.signal.h => Indicator/IndicatorData.struct.signal.h (100%) rename tests/IndicatorTest.mq4 => Indicator/tests/Indicator.test.mq4 (91%) rename tests/IndicatorTest.mq5 => Indicator/tests/Indicator.test.mq5 (95%) rename tests/IndicatorBaseTest.mq4 => Indicator/tests/IndicatorBase.test.mq4 (96%) rename tests/IndicatorBaseTest.mq5 => Indicator/tests/IndicatorBase.test.mq5 (97%) rename tests/IndicatorDataTest.mq4 => Indicator/tests/IndicatorData.test.mq4 (96%) rename tests/IndicatorDataTest.mq5 => Indicator/tests/IndicatorData.test.mq5 (95%) diff --git a/.github/workflows/test-indicator.yml b/.github/workflows/test-indicator.yml index 1a51af539..5265762b4 100644 --- a/.github/workflows/test-indicator.yml +++ b/.github/workflows/test-indicator.yml @@ -50,7 +50,10 @@ jobs: strategy: matrix: test: + - Indicator.test + - IndicatorBase.test - IndicatorCandle.test + - IndicatorData.test - IndicatorTf.test - IndicatorTick.test steps: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9c8a7f8e7..f4802e889 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -60,7 +60,6 @@ jobs: - DatabaseTest - DrawIndicatorTest - EATest - - IndicatorTest - IndicatorsTest - MailTest - MarketTest diff --git a/3D/Chart3D.h b/3D/Chart3D.h index 6db0da702..1fd4fbdb7 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -26,7 +26,7 @@ */ #include "../Bar.struct.h" -#include "../IndicatorData.mqh" +#include "../Indicator/IndicatorData.h" #include "../Indicators/Indi_MA.mqh" #include "../Instances.h" #include "../Refs.mqh" diff --git a/Account/AccountMt.h b/Account/AccountMt.h index c03c300f9..11cb4c654 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -30,10 +30,9 @@ class AccountMt; // Includes. #include "../Array.mqh" #include "../BufferStruct.mqh" -#include "../Chart.mqh" #include "../Convert.mqh" #include "../Data.struct.h" -#include "../Indicator.struct.h" +#include "../Indicator/Indicator.struct.h" #include "../Order.struct.h" #include "../Orders.mqh" #include "../Serializer.mqh" diff --git a/BufferFXT.mqh b/BufferFXT.mqh index 8127c6775..61a372f85 100644 --- a/BufferFXT.mqh +++ b/BufferFXT.mqh @@ -25,9 +25,8 @@ // Includes. #include "Account/AccountMt.h" -#include "Chart.mqh" #include "DictStruct.mqh" -#include "IndicatorBase.h" +#include "Indicator/IndicatorData.h" #include "Object.mqh" // Defines. diff --git a/Chart.mqh b/Chart.mqh index 986e34bf4..e751a6bb9 100644 --- a/Chart.mqh +++ b/Chart.mqh @@ -29,10 +29,6 @@ * - https://www.mql5.com/en/docs/series */ -// Class dependencies. -class Chart; -class Market; - // Prevents processing this includes file for the second time. #ifndef CHART_MQH #define CHART_MQH @@ -47,6 +43,10 @@ class Market; #include "Serializer.mqh" #include "Task/TaskCondition.enum.h" +// Forward class declaration. +class Chart; +class Market; + #ifndef __MQL4__ // Defines structs (for MQL4 backward compatibility). // Struct arrays that contains given values of each bar of the current chart. diff --git a/Chart.struct.h b/Chart.struct.h index 32decc06f..9d5b75266 100644 --- a/Chart.struct.h +++ b/Chart.struct.h @@ -32,6 +32,7 @@ // Forward class declaration. class Class; +struct ChartTf; // Includes. #include "Array.mqh" @@ -41,6 +42,7 @@ class Class; #include "Chart.struct.static.h" #include "Chart.struct.tf.h" #include "Serializer.mqh" +#include "SerializerNode.enum.h" #include "Terminal.define.h" /* Defines struct to store bar entries. */ diff --git a/Chart.struct.serialize.h b/Chart.struct.serialize.h index 7c818167b..b33092843 100644 --- a/Chart.struct.serialize.h +++ b/Chart.struct.serialize.h @@ -42,6 +42,6 @@ SerializerNodeType ChartEntry::Serialize(Serializer& _s) { SerializerNodeType ChartParams::Serialize(Serializer& s) { s.Pass(THIS_REF, "id", id); s.Pass(THIS_REF, "symbol", symbol); - s.PassStruct(THIS_REF, "tf", tf); + // s.PassStruct(THIS_REF, "tf", tf); // @fixme return SerializerNodeObject; } diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 3bff64239..3a0dfed6e 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -30,9 +30,12 @@ #pragma once #endif +// Forward declarations. +class Serializer; + // Includes. #include "Chart.enum.h" -#include "Serializer.mqh" +#include "SerializerNode.enum.h" #include "Terminal.define.h" /* Defines struct for chart timeframe. */ @@ -348,6 +351,8 @@ struct ChartTf { SerializerNodeType Serialize(Serializer& s); }; +#include "Serializer.mqh" + /* Method to serialize ChartTf structure. */ SerializerNodeType ChartTf::Serialize(Serializer& s) { s.PassEnum(THIS_REF, "tf", tf); diff --git a/ChartMt.h b/ChartMt.h index e87e8ddcc..b09ea050b 100644 --- a/ChartMt.h +++ b/ChartMt.h @@ -31,6 +31,7 @@ #endif // Includes. +#include "Chart.struct.static.h" #include "Chart.symboltf.h" #include "Terminal.define.h" diff --git a/DictBase.mqh b/DictBase.mqh index e7f0b8a75..251dbf11d 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -29,7 +29,6 @@ #include "Dict.enum.h" #include "DictIteratorBase.mqh" #include "DictSlot.mqh" -#include "Serializer.mqh" /** * Dictionary overflow listener. arguments are: diff --git a/DictIteratorBase.mqh b/DictIteratorBase.mqh index 8d11899fa..5a529c0cf 100644 --- a/DictIteratorBase.mqh +++ b/DictIteratorBase.mqh @@ -25,13 +25,14 @@ #pragma once #endif +// Forward class declaration. +template +class DictBase; + #include "DictBase.mqh" #include "DictSlotsRef.h" #include "SerializerConversions.h" -template -class DictBase; - template class DictIteratorBase { protected: diff --git a/DictSlot.mqh b/DictSlot.mqh index 3c1fe29e1..41a85408d 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -55,4 +55,4 @@ class DictSlot { void RemoveFlags(unsigned char flags) { _flags &= (unsigned char)~flags; } }; -#endif +#endif // DICT_SLOT_MQH diff --git a/DictSlotsRef.h b/DictSlotsRef.h index 1164261cd..03fd1c9de 100644 --- a/DictSlotsRef.h +++ b/DictSlotsRef.h @@ -37,6 +37,7 @@ #include "Std.h" #include "Util.h" +// Forward class declaration. template class DictSlot; diff --git a/DictStruct.mqh b/DictStruct.mqh index 6fc1425cd..9b362c1a1 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -24,10 +24,6 @@ #ifndef DICT_STRUCT_MQH #define DICT_STRUCT_MQH -// Forward declarations. -class Dynamic; -class Log; - #include "DictBase.mqh" #include "DictIteratorBase.mqh" #include "Serializer.mqh" diff --git a/Draw.mqh b/Draw.mqh index f39173d6e..5c2fcca9e 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -75,7 +75,7 @@ void SetIndexStyle(int _index, int _type, int _style = EMPTY, int _width = EMPTY /** * Class to provide drawing methods working with graphic objects. */ -class Draw : public Chart { +class Draw : public Object { protected: // Variables. long chart_id; diff --git a/File.mqh b/File.mqh index 56c33bd57..c6e62fb54 100644 --- a/File.mqh +++ b/File.mqh @@ -32,9 +32,10 @@ // Includes. #include "File.define.h" #include "File.extern.h" +#include "Std.h" #include "Terminal.define.h" -#include "Terminal.extern.h" #include "Terminal.enum.h" +#include "Terminal.extern.h" #ifndef __MQL__ enum ENUM_FILE_PROPERTY_INTEGER { diff --git a/Indicator.define.h b/Indicator/Indicator.define.h similarity index 99% rename from Indicator.define.h rename to Indicator/Indicator.define.h index ab51a433d..72e4333d5 100644 --- a/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -91,9 +91,6 @@ #define LOWER_LINE 1 // Bottom line. #endif -// Forward declarations. -class DrawIndicator; - #ifndef __MQL__ // // Empty value in an indicator buffer. diff --git a/Indicator.enum.h b/Indicator/Indicator.enum.h similarity index 84% rename from Indicator.enum.h rename to Indicator/Indicator.enum.h index b2b07a3a4..1306f1cd0 100644 --- a/Indicator.enum.h +++ b/Indicator/Indicator.enum.h @@ -146,14 +146,6 @@ enum ENUM_INDI_ADX_LINE { FINAL_INDI_ADX_LINE_ENTRY, }; -/* Define indicator index. */ -enum ENUM_INDICATOR_INDEX { - CURR = 0, - PREV = 1, - PPREV = 2, - FINAL_ENUM_INDICATOR_INDEX = 3 // Should be the last one. Used to calculate the number of enum items. -}; - /* Indicator line identifiers used in Envelopes and Fractals */ enum ENUM_LO_UP_LINE { #ifdef __MQL4__ @@ -197,49 +189,6 @@ enum ENUM_SIGNAL_LINE { enum ENUM_APPLIED_VOLUME { VOLUME_TICK = 0, VOLUME_REAL = 1 }; #endif -/* Indicator entry flags. */ -enum INDICATOR_ENTRY_FLAGS { - INDI_ENTRY_FLAG_NONE = 0 << 0, - INDI_ENTRY_FLAG_IS_BITWISE = 1 << 0, - INDI_ENTRY_FLAG_IS_DOUBLED = 1 << 1, // Type is doubled in size (e.g. double or long). - INDI_ENTRY_FLAG_IS_EXPIRED = 1 << 2, - INDI_ENTRY_FLAG_IS_REAL = 1 << 3, // Type is real (float or double). - INDI_ENTRY_FLAG_IS_PRICE = 1 << 4, - INDI_ENTRY_FLAG_IS_UNSIGNED = 1 << 5, // Type is unsigned (unsigned int or unsigned long). - INDI_ENTRY_FLAG_IS_VALID = 1 << 6, - INDI_ENTRY_FLAG_INSUFFICIENT_DATA = 1 << 7, // Entry has missing value for that shift and probably won't ever have. -}; - -// 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. - INDI_VS_TYPE_SPREAD, // Candle. - INDI_VS_TYPE_PRICE_OPEN, // Candle. - INDI_VS_TYPE_PRICE_HIGH, // Candle. - INDI_VS_TYPE_PRICE_LOW, // Candle. - INDI_VS_TYPE_PRICE_CLOSE, // Candle. - INDI_VS_TYPE_PRICE_MEDIAN, // Candle. - INDI_VS_TYPE_PRICE_TYPICAL, // Candle. - 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. enum ENUM_INDI_FLAGS { INDI_FLAG_INDEXABLE_BY_SHIFT, // Indicator supports indexation by shift. @@ -269,4 +218,3 @@ enum ENUM_INDI_DS_MODE_KIND { 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/Indicator.h similarity index 96% rename from Indicator.mqh rename to Indicator/Indicator.h index b9b6d414f..f7aa36f4d 100644 --- a/Indicator.mqh +++ b/Indicator/Indicator.h @@ -24,27 +24,30 @@ #ifndef INDICATOR_MQH #define INDICATOR_MQH -// Includes. -#include "Array.mqh" -#include "BufferStruct.mqh" -#include "DateTime.mqh" -#include "DrawIndicator.mqh" -#include "Flags.h" +// Forward class declaration. +struct IndicatorParams; + #include "Indicator.define.h" #include "Indicator.enum.h" -#include "Indicator.struct.cache.h" #include "Indicator.struct.h" #include "Indicator.struct.serialize.h" -#include "IndicatorData.mqh" -#include "Math.h" -#include "Object.mqh" -#include "Refs.mqh" -#include "Serializer.mqh" -#include "SerializerCsv.mqh" -#include "SerializerJson.mqh" -#include "Storage/ValueStorage.h" -#include "Storage/ValueStorage.indicator.h" -#include "Storage/ValueStorage.native.h" +#include "IndicatorData.h" + +// Includes. +#include "../Array.mqh" +#include "../BufferStruct.mqh" +#include "../DateTime.mqh" +#include "../DrawIndicator.mqh" +#include "../Flags.h" +#include "../Math.h" +#include "../Object.mqh" +#include "../Refs.mqh" +#include "../Serializer.mqh" +#include "../SerializerCsv.mqh" +#include "../SerializerJson.mqh" +#include "../Storage/ValueStorage.h" +#include "../Storage/ValueStorage.indicator.h" +#include "../Storage/ValueStorage.native.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compatibility). @@ -608,10 +611,10 @@ class Indicator : public IndicatorData { _entry.Resize(_max_modes); _entry.timestamp = GetBarTime(_ishift); #ifndef __MQL4__ - if (IndicatorBase::Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED))) { + if (IndicatorData::Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED))) { // Resets the handle on any parameter changes. - IndicatorBase::Set(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_HANDLE), INVALID_HANDLE); - IndicatorBase::Set(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED), false); + IndicatorData::Set(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_HANDLE), INVALID_HANDLE); + IndicatorData::Set(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED), false); } #endif for (int _mode = 0; _mode < _max_modes; _mode++) { diff --git a/Indicator.struct.h b/Indicator/Indicator.struct.h similarity index 69% rename from Indicator.struct.h rename to Indicator/Indicator.struct.h index 1819695f3..4e1a220de 100644 --- a/Indicator.struct.h +++ b/Indicator/Indicator.struct.h @@ -35,18 +35,15 @@ template class Indicator; struct ChartParams; -// Defines. -#define STRUCT_ENUM_INDICATOR_STATE_PROP STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) - // Includes. -#include "Array.mqh" -#include "Chart.struct.tf.h" -#include "Data.struct.h" -#include "DateTime.struct.h" +#include "../Array.mqh" +#include "../Chart.struct.tf.h" +#include "../Data.struct.h" +#include "../DateTime.struct.h" +#include "../SerializerNode.enum.h" #include "Indicator.enum.h" -#include "Indicator.struct.cache.h" -#include "SerializerNode.enum.h" -#include "Storage/ValueStorage.indicator.h" +#include "IndicatorData.struct.cache.h" +//#include "Indicator.struct.serialize.h" /* Structure for indicator parameters. */ struct IndicatorParams { @@ -130,54 +127,3 @@ struct IndicatorParams { // template <> SerializerNodeType Serialize(Serializer &s); }; - -/* Structure for indicator state. */ -struct IndicatorState { - public: // @todo: Change it to protected. - int handle; // Indicator handle (MQL5 only). - bool is_changed; // Set when params has been recently changed. - bool is_ready; // Set when indicator is ready (has valid values). - public: - enum ENUM_INDICATOR_STATE_PROP { - INDICATOR_STATE_PROP_HANDLE, - INDICATOR_STATE_PROP_IS_CHANGED, - INDICATOR_STATE_PROP_IS_READY, - }; - // Constructor. - IndicatorState() : handle(INVALID_HANDLE), is_changed(true), is_ready(false) {} - // Getters. - template - T Get(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop) { - switch (_prop) { - case INDICATOR_STATE_PROP_HANDLE: - return (T)handle; - case INDICATOR_STATE_PROP_IS_CHANGED: - return (T)is_changed; - case INDICATOR_STATE_PROP_IS_READY: - return (T)is_ready; - }; - SetUserError(ERR_INVALID_PARAMETER); - return (T)WRONG_VALUE; - } - // Setters. - template - void Set(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop, T _value) { - switch (_prop) { - case INDICATOR_STATE_PROP_HANDLE: - handle = (T)_value; - break; - case INDICATOR_STATE_PROP_IS_CHANGED: - is_changed = (T)_value; - break; - case INDICATOR_STATE_PROP_IS_READY: - is_ready = (T)_value; - break; - default: - SetUserError(ERR_INVALID_PARAMETER); - break; - }; - } - // State checkers. - bool IsChanged() { return is_changed; } - bool IsReady() { return is_ready; } -}; diff --git a/Indicator.struct.serialize.h b/Indicator/Indicator.struct.serialize.h similarity index 95% rename from Indicator.struct.serialize.h rename to Indicator/Indicator.struct.serialize.h index 6d705c609..512af9718 100644 --- a/Indicator.struct.serialize.h +++ b/Indicator/Indicator.struct.serialize.h @@ -25,10 +25,9 @@ * Includes Indicator's struct serializers. */ -#include "Serializer.mqh" - -// Forward class declaration. -class Serializer; +#include "../Serializer.mqh" +#include "../SerializerNode.enum.h" +#include "Indicator.struct.h" /* Method to serialize IndicatorParams structure. */ SerializerNodeType IndicatorParams::Serialize(Serializer &s) { diff --git a/IndicatorBase.h b/Indicator/IndicatorBase.h similarity index 89% rename from IndicatorBase.h rename to Indicator/IndicatorBase.h index 7982a4a08..f2738dcd4 100644 --- a/IndicatorBase.h +++ b/Indicator/IndicatorBase.h @@ -30,38 +30,26 @@ #pragma once #endif -// Forward declaration. -class Chart; - // Includes. -#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" -#include "SerializerCsv.mqh" -#include "SerializerJson.mqh" -#include "Util.h" +#include "../Array.mqh" +#include "../BufferStruct.mqh" +#include "../Chart.struct.tf.h" +//#include "../ChartBase.h" +#include "../ChartMt.h" +#include "../DateTime.mqh" +#include "../Log.mqh" +#include "../Object.mqh" +#include "../Refs.mqh" +#include "../Serializer.mqh" +#include "../SerializerCsv.mqh" +#include "../SerializerJson.mqh" +#include "../Util.h" /** * Class to deal with indicators. */ class IndicatorBase : public Object { protected: - IndicatorState istate; Ref logger; public: @@ -87,7 +75,7 @@ class IndicatorBase : public Object { /** * Class deconstructor. */ - virtual ~IndicatorBase() { ReleaseHandle(); } + virtual ~IndicatorBase() {} /* Operator overloading methods */ @@ -168,14 +156,6 @@ class IndicatorBase : public Object { /* Getters */ - /** - * Gets an indicator's state property value. - */ - template - T Get(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop) { - return istate.Get(_prop); - } - /** * Returns logger. */ @@ -190,14 +170,6 @@ class IndicatorBase : public Object { /* Setters */ - /** - * Sets an indicator's state property value. - */ - template - void Set(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop, T _value) { - istate.Set(_prop, _value); - } - /** * Sets name of the indicator. */ @@ -215,25 +187,6 @@ class IndicatorBase : public Object { */ // void SetSymbol(string _symbol) { Set(CHART_PARAM_SYMBOL, _symbol); } - /* Other methods */ - - /** - * Releases indicator's handle. - * - * Note: Not supported in MT4. - */ - void ReleaseHandle() { -#ifdef __MQL5__ - if (istate.handle != INVALID_HANDLE) { - IndicatorRelease(istate.handle); - } -#endif - istate.handle = INVALID_HANDLE; - istate.is_changed = true; - } - - /* Data representation methods */ - /* Virtual methods */ /** diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 8221afe82..53a338cdb 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -32,7 +32,6 @@ // Includes. #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" @@ -40,6 +39,7 @@ #include "../Storage/ValueStorage.tick_volume.h" #include "../Storage/ValueStorage.time.h" #include "../Storage/ValueStorage.volume.h" +#include "Indicator.h" #include "TickBarCounter.h" // Indicator modes. @@ -456,4 +456,4 @@ class IndicatorCandle : public Indicator { /* Virtual methods */ }; -#endif +#endif // INDICATOR_CANDLE_H diff --git a/IndicatorData.enum.h b/Indicator/IndicatorData.enum.h similarity index 53% rename from IndicatorData.enum.h rename to Indicator/IndicatorData.enum.h index 3ac513b26..9c22d82af 100644 --- a/IndicatorData.enum.h +++ b/Indicator/IndicatorData.enum.h @@ -30,6 +30,57 @@ #pragma once #endif +/* Indicator entry flags. */ +enum INDICATOR_ENTRY_FLAGS { + INDI_ENTRY_FLAG_NONE = 0 << 0, + INDI_ENTRY_FLAG_IS_BITWISE = 1 << 0, + INDI_ENTRY_FLAG_IS_DOUBLED = 1 << 1, // Type is doubled in size (e.g. double or long). + INDI_ENTRY_FLAG_IS_EXPIRED = 1 << 2, + INDI_ENTRY_FLAG_IS_REAL = 1 << 3, // Type is real (float or double). + INDI_ENTRY_FLAG_IS_PRICE = 1 << 4, + INDI_ENTRY_FLAG_IS_UNSIGNED = 1 << 5, // Type is unsigned (unsigned int or unsigned long). + INDI_ENTRY_FLAG_IS_VALID = 1 << 6, + INDI_ENTRY_FLAG_INSUFFICIENT_DATA = 1 << 7, // Entry has missing value for that shift and probably won't ever have. +}; + +/* Define indicator index. */ +enum ENUM_INDICATOR_INDEX { + CURR = 0, + PREV = 1, + PPREV = 2, + FINAL_ENUM_INDICATOR_INDEX = 3 // Should be the last one. Used to calculate the number of enum items. +}; + +// 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. + INDI_VS_TYPE_SPREAD, // Candle. + INDI_VS_TYPE_PRICE_OPEN, // Candle. + INDI_VS_TYPE_PRICE_HIGH, // Candle. + INDI_VS_TYPE_PRICE_LOW, // Candle. + INDI_VS_TYPE_PRICE_CLOSE, // Candle. + INDI_VS_TYPE_PRICE_MEDIAN, // Candle. + INDI_VS_TYPE_PRICE_TYPICAL, // Candle. + 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 +}; + /* Defines type of source data for. Also used for Indicator::GetPossibleDataModes(). */ enum ENUM_IDATA_SOURCE_TYPE { IDATA_BUILTIN = 1 << 0, // Platform built-in diff --git a/IndicatorData.mqh b/Indicator/IndicatorData.h similarity index 97% rename from IndicatorData.mqh rename to Indicator/IndicatorData.h index 46225b8d3..fa4e55904 100644 --- a/IndicatorData.mqh +++ b/Indicator/IndicatorData.h @@ -20,15 +20,33 @@ * */ +// Ignore processing of this file if already included. +#ifndef INDICATOR_DATA_H +#define INDICATOR_DATA_H + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Forward class declaration. +class IndicatorBase; + // Includes. +#include "../Bar.struct.h" +#include "../DrawIndicator.mqh" +#include "../Flags.h" +#include "../Storage/ValueStorage.h" +#include "../Storage/ValueStorage.indicator.h" +#include "../Storage/ValueStorage.native.h" +#include "../SymbolInfo.struct.h" +#include "Indicator.enum.h" #include "IndicatorBase.h" #include "IndicatorData.enum.h" +#include "IndicatorData.struct.cache.h" #include "IndicatorData.struct.h" #include "IndicatorData.struct.serialize.h" #include "IndicatorData.struct.signal.h" -#include "Storage/ValueStorage.h" -#include "Storage/ValueStorage.indicator.h" -#include "Storage/ValueStorage.native.h" /** * Implements class to store indicator data. @@ -51,7 +69,8 @@ class IndicatorData : public IndicatorBase { DrawIndicator* draw; IndicatorCalculateCache cache; IndicatorDataParams idparams; // Indicator data params. - Ref indi_src; // Indicator used as data source. + IndicatorState istate; + Ref indi_src; // Indicator used as data source. protected: /* Protected methods */ @@ -87,11 +106,14 @@ class IndicatorData : public IndicatorBase { * 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; + /* @todo: To refactor. + if (idparams.is_draw && !Object::IsValid(draw)) { + draw = new DrawIndicator(THIS_PTR); + draw.SetColorLine(idparams.indi_color); + } + return idparams.is_draw; + */ + return false; } /** @@ -121,7 +143,10 @@ class IndicatorData : public IndicatorBase { /** * Class deconstructor. */ - virtual ~IndicatorData() { DeinitDraw(); } + virtual ~IndicatorData() { + DeinitDraw(); + ReleaseHandle(); + } /* Operator overloading methods */ @@ -761,6 +786,14 @@ class IndicatorData : public IndicatorBase { idparams.Set(_param, _value); } + /** + * Sets an indicator's state property value. + */ + template + void Set(STRUCT_ENUM_INDICATOR_STATE_PROP _prop, T _value) { + istate.Set(_prop, _value); + } + /** * Sets indicator data source. */ @@ -972,6 +1005,23 @@ class IndicatorData : public IndicatorBase { } } + /* Handle methods */ + + /** + * Releases indicator's handle. + * + * Note: Not supported in MT4. + */ + void ReleaseHandle() { +#ifdef __MQL5__ + if (istate.handle != INVALID_HANDLE) { + IndicatorRelease(istate.handle); + } +#endif + istate.handle = INVALID_HANDLE; + istate.is_changed = true; + } + /* Printers */ /** @@ -1775,3 +1825,5 @@ int CopyBuffer(IndicatorData* _indi, int _mode, int _start, int _count, ValueSto return _num_copied; } + +#endif // INDICATOR_DATA_H diff --git a/Indicator.struct.cache.h b/Indicator/IndicatorData.struct.cache.h similarity index 99% rename from Indicator.struct.cache.h rename to Indicator/IndicatorData.struct.cache.h index 2c4df7097..05264e24b 100644 --- a/Indicator.struct.cache.h +++ b/Indicator/IndicatorData.struct.cache.h @@ -31,8 +31,8 @@ #endif // Includes. -#include "Refs.mqh" -#include "Storage/ValueStorage.h" +#include "../Refs.mqh" +#include "../Storage/ValueStorage.h" /** * Holds buffers used to cache values calculated via OnCalculate methods. diff --git a/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h similarity index 90% rename from IndicatorData.struct.h rename to Indicator/IndicatorData.struct.h index 1bc258497..27eaa124b 100644 --- a/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -27,9 +27,11 @@ // Defines. #define STRUCT_ENUM_IDATA_PARAM STRUCT_ENUM(IndicatorDataParams, ENUM_IDATA_PARAM) +#define STRUCT_ENUM_INDICATOR_STATE_PROP STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) // Includes. -#include "SerializerNode.enum.h" +#include "../SerializerNode.enum.h" +#include "IndicatorData.enum.h" // Type-less value for IndicatorDataEntryValue structure. union IndicatorDataEntryTypelessValue { @@ -528,3 +530,54 @@ struct IndicatorDataParams { } void SetIndicatorColor(color _clr) { indi_color = _clr; } }; + +/* Structure for indicator state. */ +struct IndicatorState { + public: // @todo: Change it to protected. + int handle; // Indicator handle (MQL5 only). + bool is_changed; // Set when params has been recently changed. + bool is_ready; // Set when indicator is ready (has valid values). + public: + enum ENUM_INDICATOR_STATE_PROP { + INDICATOR_STATE_PROP_HANDLE, + INDICATOR_STATE_PROP_IS_CHANGED, + INDICATOR_STATE_PROP_IS_READY, + }; + // Constructor. + IndicatorState() : handle(INVALID_HANDLE), is_changed(true), is_ready(false) {} + // Getters. + template + T Get(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop) { + switch (_prop) { + case INDICATOR_STATE_PROP_HANDLE: + return (T)handle; + case INDICATOR_STATE_PROP_IS_CHANGED: + return (T)is_changed; + case INDICATOR_STATE_PROP_IS_READY: + return (T)is_ready; + }; + SetUserError(ERR_INVALID_PARAMETER); + return (T)WRONG_VALUE; + } + // Setters. + template + void Set(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop, T _value) { + switch (_prop) { + case INDICATOR_STATE_PROP_HANDLE: + handle = (T)_value; + break; + case INDICATOR_STATE_PROP_IS_CHANGED: + is_changed = (T)_value; + break; + case INDICATOR_STATE_PROP_IS_READY: + is_ready = (T)_value; + break; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + }; + } + // State checkers. + bool IsChanged() { return is_changed; } + bool IsReady() { return is_ready; } +}; diff --git a/IndicatorData.struct.serialize.h b/Indicator/IndicatorData.struct.serialize.h similarity index 99% rename from IndicatorData.struct.serialize.h rename to Indicator/IndicatorData.struct.serialize.h index 0381cfcde..7655450bd 100644 --- a/IndicatorData.struct.serialize.h +++ b/Indicator/IndicatorData.struct.serialize.h @@ -25,7 +25,7 @@ * Includes IndicatorData's struct serializers. */ -#include "Serializer.mqh" +#include "../Serializer.mqh" // Forward class declaration. class Serializer; diff --git a/IndicatorData.struct.signal.h b/Indicator/IndicatorData.struct.signal.h similarity index 100% rename from IndicatorData.struct.signal.h rename to Indicator/IndicatorData.struct.signal.h diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 60540acd9..9822e226f 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -147,4 +147,4 @@ class IndicatorTf : public IndicatorCandle { ENUM_TIMEFRAMES GetTf() override { return tf; } }; -#endif +#endif // INDICATOR_TF_H diff --git a/Indicator/IndicatorTf.struct.h b/Indicator/IndicatorTf.struct.h index 7259d6d9b..6eb42bfb2 100644 --- a/Indicator/IndicatorTf.struct.h +++ b/Indicator/IndicatorTf.struct.h @@ -31,7 +31,7 @@ #endif // Includes. -#include "../Indicator.struct.h" +#include "Indicator.struct.h" /* Structure for IndicatorTf class parameters. */ struct IndicatorTfParams : IndicatorParams { diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 5438923cb..b1ecfb13f 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -31,8 +31,8 @@ // Includes. #include "../Buffer/BufferTick.h" -#include "../Indicator.mqh" -#include "../Indicator.struct.h" +#include "Indicator.h" +#include "Indicator.struct.h" // Indicator modes. enum ENUM_INDI_TICK_MODE { diff --git a/Indicator/IndicatorTickSource.h b/Indicator/IndicatorTickSource.h index 8b47180a5..0c0e3b5a1 100644 --- a/Indicator/IndicatorTickSource.h +++ b/Indicator/IndicatorTickSource.h @@ -26,7 +26,7 @@ #endif // Includes. -#include "../Indicator.mqh" +#include "Indicator.h" /** * Indicator to be used with IndicatorTick as a data source. diff --git a/tests/IndicatorTest.mq4 b/Indicator/tests/Indicator.test.mq4 similarity index 91% rename from tests/IndicatorTest.mq4 rename to Indicator/tests/Indicator.test.mq4 index f1bee4667..81a7da627 100644 --- a/tests/IndicatorTest.mq4 +++ b/Indicator/tests/Indicator.test.mq4 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -25,4 +25,4 @@ */ // Includes. -#include "IndicatorTest.mq5" +#include "Indicator.test.mq5" diff --git a/tests/IndicatorTest.mq5 b/Indicator/tests/Indicator.test.mq5 similarity index 95% rename from tests/IndicatorTest.mq5 rename to Indicator/tests/Indicator.test.mq5 index e837f8e92..437dfb252 100644 --- a/tests/IndicatorTest.mq5 +++ b/Indicator/tests/Indicator.test.mq5 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -25,8 +25,8 @@ */ // Includes. -#include "../Indicator.mqh" -#include "../Test.mqh" +#include "../Indicator.h" +#include "../../Test.mqh" /** * Implements OnInit(). diff --git a/tests/IndicatorBaseTest.mq4 b/Indicator/tests/IndicatorBase.test.mq4 similarity index 96% rename from tests/IndicatorBaseTest.mq4 rename to Indicator/tests/IndicatorBase.test.mq4 index 167dec35e..e350d5630 100644 --- a/tests/IndicatorBaseTest.mq4 +++ b/Indicator/tests/IndicatorBase.test.mq4 @@ -25,4 +25,4 @@ */ // Includes. -#include "IndicatorBaseTest.mq5" +#include "IndicatorBase.test.mq5" diff --git a/tests/IndicatorBaseTest.mq5 b/Indicator/tests/IndicatorBase.test.mq5 similarity index 97% rename from tests/IndicatorBaseTest.mq5 rename to Indicator/tests/IndicatorBase.test.mq5 index 8ca89f936..49ff02872 100644 --- a/tests/IndicatorBaseTest.mq5 +++ b/Indicator/tests/IndicatorBase.test.mq5 @@ -25,8 +25,8 @@ */ // Includes. +#include "../../Test.mqh" #include "../IndicatorBase.h" -#include "../Test.mqh" /** * Implements OnInit(). diff --git a/tests/IndicatorDataTest.mq4 b/Indicator/tests/IndicatorData.test.mq4 similarity index 96% rename from tests/IndicatorDataTest.mq4 rename to Indicator/tests/IndicatorData.test.mq4 index ec907afe1..354e8a763 100644 --- a/tests/IndicatorDataTest.mq4 +++ b/Indicator/tests/IndicatorData.test.mq4 @@ -25,4 +25,4 @@ */ // Includes. -#include "IndicatorDataTest.mq5" +#include "IndicatorData.test.mq5" diff --git a/tests/IndicatorDataTest.mq5 b/Indicator/tests/IndicatorData.test.mq5 similarity index 95% rename from tests/IndicatorDataTest.mq5 rename to Indicator/tests/IndicatorData.test.mq5 index bd6a17c11..d78133913 100644 --- a/tests/IndicatorDataTest.mq5 +++ b/Indicator/tests/IndicatorData.test.mq5 @@ -25,8 +25,8 @@ */ // Includes. -#include "../IndicatorData.mqh" -#include "../Test.mqh" +#include "../../Test.mqh" +#include "../IndicatorData.h" /** * Implements OnInit(). diff --git a/Indicator/tests/IndicatorTf.test.mq5 b/Indicator/tests/IndicatorTf.test.mq5 index 65e09817c..139e1275f 100644 --- a/Indicator/tests/IndicatorTf.test.mq5 +++ b/Indicator/tests/IndicatorTf.test.mq5 @@ -27,16 +27,19 @@ */ // Includes. +#include "../../DictBase.mqh" #include "../../Indicators/Indi_AMA.mqh" #include "../../Indicators/Tick/Indi_TickMt.mqh" +#include "../../Log.mqh" #include "../../Platform.h" +#include "../../SymbolInfo.mqh" #include "../../Test.mqh" #include "../../Util.h" #include "../IndicatorTf.h" -#include "../IndicatorTick.h" #include "classes/IndicatorTfDummy.h" #include "classes/Indicators.h" +// Global variables. Ref indi_tick; Ref indi_tf; Ref indi_tf_real; diff --git a/Indicator/tests/IndicatorTick.test.mq5 b/Indicator/tests/IndicatorTick.test.mq5 index 87016f2dc..04a8da463 100644 --- a/Indicator/tests/IndicatorTick.test.mq5 +++ b/Indicator/tests/IndicatorTick.test.mq5 @@ -26,6 +26,7 @@ // Includes. #include "../../Test.mqh" +#include "../IndicatorTick.h" #include "classes/IndicatorTickDummy.h" /** diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h index 1d1da2066..c57362551 100644 --- a/Indicator/tests/classes/Indicators.h +++ b/Indicator/tests/classes/Indicators.h @@ -30,7 +30,7 @@ #endif // Includes. -#include "../../../IndicatorData.mqh" +#include "../../../Indicator/IndicatorData.h" #include "../../../Refs.mqh" /** diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index 306c018e2..61e7f3d56 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.mqh" +#include "../../Indicator/Indicator.h" #include "../../Pattern.struct.h" #include "../../Serializer.mqh" #include "../Price/Indi_Price.mqh" diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index 0c2d9d631..229faf261 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.mqh" +#include "../../Indicator/Indicator.h" #include "../../Pattern.struct.h" #include "../../Serializer.mqh" #include "../Price/Indi_Price.mqh" diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index 2e497109b..9d577bb81 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index a7385e259..ad7b0f95f 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index 0c151c3f7..f01dad621 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Price/Indi_Price.mqh" #ifndef __MQL4__ diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 4b3876059..a46d95977 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.applied_price.h" #include "../Storage/ValueStorage.h" #include "../Storage/ValueStorage.spread.h" diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index ec615c8ac..4d39aefb6 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.h" #include "Price/Indi_Price.mqh" @@ -45,7 +45,7 @@ struct IndiAMAParams : IndicatorParams { // Defaulting to on-indicator mode (will use real ticks from platform via IndicatorTickReal). SetShift(_shift); if (custom_indi_name == "") { - SetCustomIndicatorName("Examples\\AMA"); + SetCustomIndicatorName("Examples\\AMA"); } }; IndiAMAParams(IndiAMAParams &_params) { THIS_REF = _params; } diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index cb51048b0..b80c5e4b9 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index a2ee523f1..cf0ff9270 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index dca8224f2..e79cc5f43 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index 27623a42e..601660a52 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_AppliedPrice.mqh b/Indicators/Indi_AppliedPrice.mqh index dbfc0dfee..bbdbccc27 100644 --- a/Indicators/Indi_AppliedPrice.mqh +++ b/Indicators/Indi_AppliedPrice.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "OHLC/Indi_OHLC.mqh" // Structs. diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index a295f45a2..30c5f81db 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index 4c8dcd268..b978dd10c 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_CCI.mqh" #include "Indi_Envelopes.mqh" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index 46d8c53f2..538cffa28 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index b63d5b706..6097a4f1d 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index fa5880366..1e31396de 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" #include "Price/Indi_Price.mqh" diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index 580c5014f..2e4587f53 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "../Util.h" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index 97319df98..bc2e85a41 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "../Util.h" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index 5cbcd43b3..a12b88b40 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index 321421580..dd43bf9a0 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index 6b777890b..837276a22 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_CustomMovingAverage.mqh b/Indicators/Indi_CustomMovingAverage.mqh index 2d3835656..e9e855edb 100644 --- a/Indicators/Indi_CustomMovingAverage.mqh +++ b/Indicators/Indi_CustomMovingAverage.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" // Structs. struct IndiCustomMovingAverageParams : IndicatorParams { diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index b6485522c..7e7478144 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -34,7 +34,7 @@ // Includes. #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Refs.mqh" #include "../Storage/Objects.h" #include "../Storage/ValueStorage.h" diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index 5a2fa857a..f15cfeea2 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index 4ab3c765d..09a399c27 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Price/Indi_Price.mqh" /** diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index f560a1a23..229dc2e31 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_MA.mqh" // Structs. diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index 2ef66b6f0..8ec621163 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -22,7 +22,7 @@ // Includes. #include "../DictStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Redis.mqh" #include "../Task/TaskAction.h" #include "Indi_Drawer.struct.h" diff --git a/Indicators/Indi_Drawer.struct.h b/Indicators/Indi_Drawer.struct.h index 473209d9f..b1957e566 100644 --- a/Indicators/Indi_Drawer.struct.h +++ b/Indicators/Indi_Drawer.struct.h @@ -26,7 +26,7 @@ */ // Includes. -#include "../Indicator.struct.h" +#include "../Indicator/Indicator.struct.h" #include "../SerializerNode.enum.h" // Structs. diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 58d9725aa..1d7304c80 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/Singleton.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index 291f52f39..361b2e449 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -32,7 +32,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index 7109e7522..a009f9011 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index 9ea6b1930..b947e0a32 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index 73afa2f9e..b6d93a43d 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index 93422110a..c29059b0d 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Enums. diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index 6b331cd04..aeab321ce 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Killzones.mqh b/Indicators/Indi_Killzones.mqh index a33740549..8f9933ae4 100644 --- a/Indicators/Indi_Killzones.mqh +++ b/Indicators/Indi_Killzones.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Market.struct.h" // Defines enumerations. diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 4efa7154f..19fbe48b1 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -27,7 +27,7 @@ // Includes. #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Refs.mqh" #include "../Storage/Singleton.h" #include "../Storage/ValueStorage.h" diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index 64cc2be27..835d387bd 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index 950f1806b..b813590cd 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index 57c3c5075..61866de86 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 750923bbf..0a1cf9b77 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -30,7 +30,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_PriceFeeder.mqh" #ifndef __MQL4__ diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index b53f50fd0..d6764c9a5 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index 64e0edaa7..801b4673a 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index d49539d91..bb90f9e96 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -22,7 +22,7 @@ // Includes. #include "../Bar.struct.h" -#include "../Indicator.struct.h" +#include "../Indicator/Indicator.struct.h" #include "../Serializer.mqh" #include "Special/Indi_Math.mqh" diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index dde4c871c..526643960 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_ZigZag.mqh" // Structs. diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index 54761b01c..206a0e7a5 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" // Structs. struct IndiPriceFeederParams : IndicatorParams { diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index 74fbee278..12619bcdf 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index 00486303f..4f399aaee 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "OHLC/Indi_OHLC.mqh" #include "Special/Indi_Math.mqh" diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index d26861c39..55aee8ba9 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -22,7 +22,7 @@ // Includes. #include "../DictStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_Bands.mqh" #include "Indi_CCI.mqh" #include "Indi_Envelopes.mqh" diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index 8e2a1bde7..c160deb65 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index c671ad9e1..59e8fe8c6 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" // Structs. struct IndiRateOfChangeParams : IndicatorParams { diff --git a/Indicators/Indi_SAR.mqh b/Indicators/Indi_SAR.mqh index 873efea35..fbbf230e4 100644 --- a/Indicators/Indi_SAR.mqh +++ b/Indicators/Indi_SAR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 5b599b9e1..d46bbac61 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ObjectsCache.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index dfc306636..a55e91def 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index dbd060f85..cc288ac56 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_MA.mqh" // Structs. diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index b3fe1fe60..4ec953133 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "Indi_MA.mqh" // Structs. diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index 0b83bdb07..8c3c17784 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "Indi_ATR.mqh" #include "Indi_MA.mqh" diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index d91edcda3..4416f29ba 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" // Structs. struct IndiVIDYAParams : IndicatorParams { diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index 5914674f0..d25a59883 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index ec903f03d..fed9195d3 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_WPR.mqh b/Indicators/Indi_WPR.mqh index 33f2df979..45490562c 100644 --- a/Indicators/Indi_WPR.mqh +++ b/Indicators/Indi_WPR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index e8a1017ad..19e73b82b 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Structs. diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index 0f0dc6e65..a9397faad 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" // Defines. diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 647d25b72..8cd8e9248 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" #include "Indi_ZigZag.mqh" diff --git a/Indicators/OHLC/Indi_OHLC.mqh b/Indicators/OHLC/Indi_OHLC.mqh index eb4f8a997..9b32546e1 100644 --- a/Indicators/OHLC/Indi_OHLC.mqh +++ b/Indicators/OHLC/Indi_OHLC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/Indicator.h" #include "../../Storage/Objects.h" // Enums. diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index 76299b153..64db99a5b 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/Indicator.h" #include "../../Platform.h" #include "../../Storage/Objects.h" diff --git a/Indicators/Special/Indi_Custom.mqh b/Indicators/Special/Indi_Custom.mqh index 4e5a8a676..c02e1d247 100644 --- a/Indicators/Special/Indi_Custom.mqh +++ b/Indicators/Special/Indi_Custom.mqh @@ -33,7 +33,7 @@ #endif // Includes. -#include "../../Indicator.mqh" +#include "../../Indicator/Indicator.h" // Structs. diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index f6bcb890c..365ce08af 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/Indicator.h" #include "../../Math.enum.h" enum ENUM_MATH_OP_MODE { MATH_OP_MODE_BUILTIN, MATH_OP_MODE_CUSTOM_FUNCTION }; diff --git a/Log.mqh b/Log.mqh index 28dff8671..f542b93e7 100644 --- a/Log.mqh +++ b/Log.mqh @@ -20,6 +20,14 @@ * */ +// Prevents processing this includes file for the second time. +#ifndef LOG_MQH +#define LOG_MQH + +// Forward class declaration. +template +class DictStruct; + // Includes. #include "Array.mqh" #include "Collection.mqh" @@ -27,10 +35,6 @@ #include "DictStruct.mqh" #include "Object.mqh" -// Prevents processing this includes file for the second time. -#ifndef LOG_MQH -#define LOG_MQH - // Define assert macros. // Alias for function and line macros combined together. #define __FUNCTION_LINE__ string(__FUNCTION__) + ":" + IntegerToString(__LINE__) diff --git a/Market.mqh b/Market.mqh index 7cd8bdc33..157eb4c3d 100644 --- a/Market.mqh +++ b/Market.mqh @@ -24,27 +24,14 @@ #ifndef MARKET_MQH #define MARKET_MQH -// Forward declaration. -class Market; -class SymbolInfo; - // Includes. #include "Market.struct.h" #include "Math.h" -#include "Order.mqh" #include "Serializer.mqh" #include "SymbolInfo.mqh" +#include "SymbolInfo.struct.static.h" #include "Task/TaskCondition.enum.h" -// Structs. -// Market info. -struct MarketData { - int empty; - // Serializers. - void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} - SerializerNodeType Serialize(Serializer &_s) { return SerializerNodeObject; } -}; - /** * Class to provide market information. */ diff --git a/Market.struct.h b/Market.struct.h index bf9315527..0937823ae 100644 --- a/Market.struct.h +++ b/Market.struct.h @@ -25,10 +25,22 @@ * Includes Market's structs. */ +// Forward declaration. +class Serializer; + // Includes. #include "DateTime.struct.h" +#include "SerializerNode.enum.h" #include "Std.h" +// Market info. +struct MarketData { + int empty; + // Serializers. + void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} + SerializerNodeType Serialize(Serializer &_s) { return SerializerNodeObject; } +}; + // Structure for trade time static methods. struct MarketTimeForex : DateTimeEntry { // Market sessions for trading Forex. diff --git a/Math.h b/Math.h index 691837b31..2460f7e61 100644 --- a/Math.h +++ b/Math.h @@ -27,7 +27,7 @@ // Includes. #include "Data.struct.h" -#include "Indicator.struct.h" +#include "Indicator/Indicator.struct.h" #include "Math.define.h" #include "Math.enum.h" #include "Math.extern.h" diff --git a/Order.mqh b/Order.mqh index 1b84095d4..d277a03c2 100644 --- a/Order.mqh +++ b/Order.mqh @@ -29,6 +29,9 @@ #ifndef ORDER_MQH #define ORDER_MQH +// Forward declaration. +class SymbolInfo; + // Includes. #include "Convert.mqh" #include "Data.define.h" @@ -38,6 +41,8 @@ #include "Order.define.h" #include "Order.enum.h" #include "Order.struct.h" +#include "Serializer.define.h" +#include "Serializer.mqh" #include "SerializerConverter.mqh" #include "SerializerJson.mqh" #include "Std.h" diff --git a/Platform.h b/Platform.h index 88ec23736..ba153d533 100644 --- a/Platform.h +++ b/Platform.h @@ -27,7 +27,7 @@ */ #include "Flags.h" -#include "IndicatorBase.h" +#include "Indicator/IndicatorData.h" #include "Std.h" #ifdef __MQLBUILD__ diff --git a/Serializer.mqh b/Serializer.mqh index d7f3e89d2..d76c001b2 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -38,7 +38,6 @@ // Forward declarations. template class SerializerIterator; -class IndicatorBase; class Serializer { protected: @@ -380,21 +379,6 @@ class Serializer { } } - template - void Pass(T& self, string name, IndicatorBase*& value, unsigned int flags = SERIALIZER_FIELD_FLAG_DEFAULT) { - if (_mode == Serialize) { - if (!IsFieldVisible(_flags, flags)) { - return; - } - - PassObject(self, name, value, flags); - } else { - Print("Error: Deserialization of IndicatorBase* cannot be done as method is abstract!"); - DebugBreak(); - value = nullptr; - } - } - /** * Serializes or unserializes simple value. */ diff --git a/SerializerConverter.mqh b/SerializerConverter.mqh index 985845dd8..4ce3d5f28 100644 --- a/SerializerConverter.mqh +++ b/SerializerConverter.mqh @@ -20,10 +20,14 @@ * */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Prevents processing this includes file for the second time. #ifndef SERIALIZER_CONVERTER_MQH #define SERIALIZER_CONVERTER_MQH -#include "SerializerDict.mqh" // Forward declarations. class SerializerNode; @@ -32,6 +36,7 @@ class SerializerNode; #include "File.mqh" #include "Serializer.enum.h" #include "Serializer.mqh" +#include "SerializerDict.mqh" #include "SerializerNode.mqh" class SerializerConverter { diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index 9019a6bff..61c378964 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -31,10 +31,11 @@ #endif // Includes. +#include "../Indicator/IndicatorData.h" #include "ValueStorage.h" // Forward declarations. -class IndicatorBase; +class IndicatorData; template class ValueStorage; @@ -54,7 +55,7 @@ class HistoryValueStorage : public ValueStorage { /** * Constructor. */ - HistoryValueStorage(IndicatorBase* _indi_candle, bool _is_series = false) + HistoryValueStorage(IndicatorData* _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!"); diff --git a/Storage/ValueStorage.price_median.h b/Storage/ValueStorage.price_median.h index 6ba406e46..24b9c1a1a 100644 --- a/Storage/ValueStorage.price_median.h +++ b/Storage/ValueStorage.price_median.h @@ -24,6 +24,9 @@ * Median price version of ValueStorage. */ +// Forward declarations. +class IndicatorBase; + // Includes. #include "ObjectsCache.h" #include "ValueStorage.history.h" diff --git a/Strategy.mqh b/Strategy.mqh index 24fab7aa9..e68fa8334 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -30,7 +30,7 @@ class Trade; // Includes. #include "Data.struct.h" #include "Dict.mqh" -#include "Indicator.mqh" +#include "Indicator/Indicator.h" #include "Market.mqh" #include "Object.mqh" #include "Strategy.enum.h" diff --git a/SymbolInfo.mqh b/SymbolInfo.mqh index f043b7dec..1ee351e9a 100644 --- a/SymbolInfo.mqh +++ b/SymbolInfo.mqh @@ -24,9 +24,6 @@ #ifndef SYMBOLINFO_MQH #define SYMBOLINFO_MQH -// Forward declaration. -class SymbolInfo; - // Includes symbol defines, enums and structs. #include "SymbolInfo.define.h" #include "SymbolInfo.enum.h" @@ -35,6 +32,10 @@ class SymbolInfo; #include "SymbolInfo.struct.h" #include "SymbolInfo.struct.static.h" +// Forward declaration. +class Log; +class SymbolInfo; + // Includes. #include "Log.mqh" #include "Serializer.mqh" @@ -230,9 +231,7 @@ class SymbolInfo : public Object { * Get number of points per pip. * */ - unsigned int GetPointsPerPip() { - return sprops.pts_per_pip; - } + unsigned int GetPointsPerPip() { return sprops.pts_per_pip; } /** * Get the point size in the quote currency. diff --git a/Terminal.enum.h b/Terminal.enum.h index 6c12c13cc..574615a23 100644 --- a/Terminal.enum.h +++ b/Terminal.enum.h @@ -31,7 +31,7 @@ #endif // Includes. -#include "Indicator.define.h" +#include "Indicator/Indicator.define.h" // Defines user error enumeration. enum ENUM_USER_ERR { USER_ERR_INVALID_ARGUMENT }; diff --git a/Tests.mqh b/Tests.mqh index 55c549aa8..d4a3d3463 100644 --- a/Tests.mqh +++ b/Tests.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "Indicator.mqh" +#include "Indicator/Indicator.h" #include "Market.mqh" /** diff --git a/Trade.mqh b/Trade.mqh index 513ebf695..f6eea3136 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -34,7 +34,7 @@ class Trade; #include "Chart.mqh" #include "Convert.mqh" #include "DictStruct.mqh" -#include "IndicatorData.mqh" +#include "Indicator/IndicatorData.h" #include "Math.h" #include "Object.mqh" #include "Order.mqh" @@ -1398,7 +1398,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. && Terminal::CheckPermissionToTrade() // Check if auto trading is enabled. && (Terminal::IsRealtime() && !Terminal::IsExpertEnabled())); - /* Chart checks */ +/* Chart checks */ #ifdef __debug__ Print("Trade: Bars in data source: ", GetSource() PTR_DEREF GetBars(), ", minimum required bars: ", tparams.GetBarsMin()); diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index d8666aac8..fc9193df9 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -63,10 +63,6 @@ struct IndicatorParams; #include "../EA.mqh" #include "../File.mqh" #include "../ISerializable.h" -#include "../Indicator.define.h" -#include "../Indicator.mqh" -#include "../IndicatorBase.h" -#include "../IndicatorData.mqh" // #include "../Inet.mqh" #include "../Log.mqh" #include "../MD5.mqh" @@ -133,6 +129,10 @@ struct IndicatorParams; #include "../Web.mqh" // Includes indicator files. +#include "../Indicator/Indicator.define.h" +#include "../Indicator/Indicator.h" +#include "../Indicator/IndicatorBase.h" +//#include "../Indicator/IndicatorData.h" #include "../Indicators/indicators.h" /** diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index 69779aecc..499634840 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -30,7 +30,7 @@ // Includes. #include "../DictStruct.mqh" #include "../DrawIndicator.mqh" -#include "../Indicator.struct.serialize.h" +#include "../Indicator/Indicator.struct.serialize.h" #include "../Indicators/Indi_Bands.mqh" #include "../Indicators/Indi_Demo.mqh" #include "../Indicators/Indi_MA.mqh" diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 4aca8c09e..6ef5efc18 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -35,7 +35,7 @@ struct DataParamEntry; //#include "../ChartMt.h" #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../Indicator.mqh" +#include "../Indicator/Indicator.h" #include "../Indicator/tests/classes/IndicatorTfDummy.h" #include "../Indicators/Bitwise/indicators.h" #include "../Indicators/Tick/Indi_TickMt.mqh" diff --git a/tests/LogTest.mq5 b/tests/LogTest.mq5 index 049cc0e20..e28e8fe4c 100644 --- a/tests/LogTest.mq5 +++ b/tests/LogTest.mq5 @@ -27,6 +27,7 @@ // Includes. #include "../DictStruct.mqh" #include "../Log.mqh" +#include "../Refs.struct.h" #include "../Test.mqh" // Variables. diff --git a/tests/SerializerTest.mq5 b/tests/SerializerTest.mq5 index fb619c193..68ef491b4 100644 --- a/tests/SerializerTest.mq5 +++ b/tests/SerializerTest.mq5 @@ -30,6 +30,7 @@ #include "../BufferStruct.mqh" #include "../Chart.mqh" #include "../Config.mqh" +#include "../Data.define.h" #include "../Data.struct.h" #include "../DictStruct.mqh" #include "../Serializer.mqh" From 8b9072d5e289511269504ab2f7000a23ac70b114 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 19 Aug 2022 23:07:03 +0100 Subject: [PATCH 017/123] Moves Tick.struct.h to Tick/ --- Buffer/BufferTick.h | 2 +- Indicator/tests/classes/IndicatorTickDummy.h | 2 +- SymbolInfo.extern.h | 2 +- SymbolInfo.struct.h | 2 +- SymbolInfo.struct.static.h | 2 +- Tick.struct.h => Tick/Tick.struct.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename Tick.struct.h => Tick/Tick.struct.h (98%) diff --git a/Buffer/BufferTick.h b/Buffer/BufferTick.h index 4eed02d69..7ed484dc0 100644 --- a/Buffer/BufferTick.h +++ b/Buffer/BufferTick.h @@ -28,7 +28,7 @@ #include "../BufferStruct.mqh" #include "../Chart.enum.h" #include "../Storage/IValueStorage.h" -#include "../Tick.struct.h" +#include "../Tick/Tick.struct.h" // TV = Type of price stored by BufferTick. RV = Type of property to be retrieved from BufferTick. template diff --git a/Indicator/tests/classes/IndicatorTickDummy.h b/Indicator/tests/classes/IndicatorTickDummy.h index dfd59e9a3..3b5e58a22 100644 --- a/Indicator/tests/classes/IndicatorTickDummy.h +++ b/Indicator/tests/classes/IndicatorTickDummy.h @@ -30,7 +30,7 @@ #endif // Includes. -#include "../../../Tick.struct.h" +#include "../../../Tick/Tick.struct.h" #include "../../IndicatorTick.h" // Params for dummy tick-based indicator. diff --git a/SymbolInfo.extern.h b/SymbolInfo.extern.h index 801c47fb1..60b085d5b 100644 --- a/SymbolInfo.extern.h +++ b/SymbolInfo.extern.h @@ -23,7 +23,7 @@ // Includes. #include "Order.enum.h" #include "SymbolInfo.enum.h" -#include "Tick.struct.h" +#include "Tick/Tick.struct.h" // Define external global functions. #ifndef __MQL__ diff --git a/SymbolInfo.struct.h b/SymbolInfo.struct.h index 85b6f19e7..7b41c2bba 100644 --- a/SymbolInfo.struct.h +++ b/SymbolInfo.struct.h @@ -34,7 +34,7 @@ #include "ISerializable.h" #include "Std.h" #include "SymbolInfo.struct.static.h" -#include "Tick.struct.h" +#include "Tick/Tick.struct.h" // Defines struct to store symbol data. struct SymbolInfoEntry diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index a33431610..a82d49f40 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -28,7 +28,7 @@ #include "MQL5.mqh" #include "Order.enum.h" #include "Std.h" -#include "Tick.struct.h" +#include "Tick/Tick.struct.h" /** * Struct to provide symbol information. diff --git a/Tick.struct.h b/Tick/Tick.struct.h similarity index 98% rename from Tick.struct.h rename to Tick/Tick.struct.h index dbb226a4f..c128f9818 100644 --- a/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -30,7 +30,7 @@ #endif // Includes. -#include "DateTime.extern.h" +#include "../DateTime.extern.h" #ifndef __MQL__ /** From 943f662acef5e8696e43563b02ad3787dbab0ec1 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 19 Aug 2022 23:36:09 +0100 Subject: [PATCH 018/123] Moves Serializer files to Serializer/ Serializer: Renames .mqh to .h --- .github/workflows/test-serializer.yml | 65 +++++++++++++++++++ .github/workflows/test.yml | 1 - 3D/Chart3D.h | 4 +- Account/Account.h | 2 +- Account/Account.struct.h | 2 +- Account/AccountBase.h | 1 - Account/AccountBase.struct.h | 2 +- Account/AccountForex.h | 2 +- Account/AccountForex.struct.h | 2 +- Account/AccountMt.h | 2 +- Bar.struct.h | 11 ++-- BufferStruct.mqh | 2 +- Candle.struct.h | 11 ++-- Chart.mqh | 2 +- Chart.struct.h | 4 +- Chart.struct.serialize.h | 4 +- Chart.struct.tf.h | 5 +- Config.mqh | 2 +- Data.struct.h | 7 +- Dict.mqh | 4 +- DictIteratorBase.mqh | 2 +- DictObject.mqh | 4 +- DictStruct.mqh | 4 +- EA.mqh | 8 +-- Indicator/Indicator.h | 6 +- Indicator/Indicator.struct.h | 2 +- Indicator/Indicator.struct.serialize.h | 4 +- Indicator/IndicatorBase.h | 6 +- Indicator/IndicatorData.struct.h | 2 +- Indicator/IndicatorData.struct.serialize.h | 2 +- Indicators/Bitwise/Indi_Candle.mqh | 2 +- Indicators/Bitwise/Indi_Pattern.mqh | 2 +- Indicators/Indi_Drawer.struct.h | 2 +- Indicators/Indi_Pivot.mqh | 2 +- Market.mqh | 2 +- Market.struct.h | 2 +- Order.mqh | 8 +-- Order.struct.h | 2 +- Redis.mqh | 6 +- Redis.struct.h | 2 +- ISerializable.h => Serializer/Serializable.h | 2 +- .../Serializer.define.h | 0 .../Serializer.enum.h | 0 Serializer.mqh => Serializer/Serializer.h | 10 +-- .../SerializerBinary.h | 8 +-- .../SerializerConversions.h | 8 +-- .../SerializerConverter.h | 8 +-- .../SerializerCsv.h | 16 ++--- .../SerializerDict.h | 2 +- .../SerializerJson.h | 10 +-- .../SerializerNode.enum.h | 0 .../SerializerNode.h | 12 ++-- .../SerializerNodeIterator.h | 8 +-- .../SerializerNodeParam.h | 9 ++- .../SerializerObject.h | 10 +-- .../SerializerSqlite.h | 6 +- .../tests/Serializer.test.mq4 | 2 +- .../tests/Serializer.test.mq5 | 28 ++++---- Storage/ValueStorage.h | 2 +- Strategy.struct.h | 2 +- SymbolInfo.mqh | 4 +- SymbolInfo.struct.h | 7 +- Task/TaskManager.h | 4 +- Trade/TradeSignal.struct.h | 4 +- Util.h | 2 +- tests/3DTest.mq5 | 2 +- tests/BufferStructTest.mq5 | 4 +- tests/CompileTest.mq5 | 32 ++++----- tests/ConfigTest.mq5 | 6 +- tests/DictTest.mq5 | 6 +- tests/IndicatorsTest.mq5 | 4 +- tests/OrderTest.mq5 | 4 +- tests/ValueStorageTest.mq5 | 4 +- 73 files changed, 245 insertions(+), 186 deletions(-) create mode 100644 .github/workflows/test-serializer.yml rename ISerializable.h => Serializer/Serializable.h (98%) rename Serializer.define.h => Serializer/Serializer.define.h (100%) rename Serializer.enum.h => Serializer/Serializer.enum.h (100%) rename Serializer.mqh => Serializer/Serializer.h (98%) rename SerializerBinary.mqh => Serializer/SerializerBinary.h (97%) rename SerializerConversions.h => Serializer/SerializerConversions.h (97%) rename SerializerConverter.mqh => Serializer/SerializerConverter.h (98%) rename SerializerCsv.mqh => Serializer/SerializerCsv.h (97%) rename SerializerDict.mqh => Serializer/SerializerDict.h (98%) rename SerializerJson.mqh => Serializer/SerializerJson.h (98%) rename SerializerNode.enum.h => Serializer/SerializerNode.enum.h (100%) rename SerializerNode.mqh => Serializer/SerializerNode.h (98%) rename SerializerNodeIterator.mqh => Serializer/SerializerNodeIterator.h (96%) rename SerializerNodeParam.mqh => Serializer/SerializerNodeParam.h (99%) rename SerializerObject.mqh => Serializer/SerializerObject.h (90%) rename SerializerSqlite.mqh => Serializer/SerializerSqlite.h (97%) rename tests/SerializerTest.mq4 => Serializer/tests/Serializer.test.mq4 (97%) rename tests/SerializerTest.mq5 => Serializer/tests/Serializer.test.mq5 (96%) diff --git a/.github/workflows/test-serializer.yml b/.github/workflows/test-serializer.yml new file mode 100644 index 000000000..e4617d002 --- /dev/null +++ b/.github/workflows/test-serializer.yml @@ -0,0 +1,65 @@ +--- +name: Test Serializer + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Serializer/**' + - '.github/workflows/test-serializer.yml' + push: + paths: + - 'Serializer/**' + - '.github/workflows/test-serializer.yml' + +jobs: + + Compile: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Compile + uses: fx31337/mql-compile-action@master + with: + init-platform: true + path: 'serializer/tests' + verbose: true + - name: Print compiled files + run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname' + shell: powershell + - name: Upload artifacts (MQL4) + uses: actions/upload-artifact@v2 + with: + name: files-ex4 + path: '**/*.ex4' + - name: Upload artifacts (MQL5) + uses: actions/upload-artifact@v2 + with: + name: files-ex5 + path: '**/*.ex5' + + Serializer-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: serializer/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - Serializer.test + steps: + - uses: actions/download-artifact@v2 + with: + name: files-ex4 + - name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + BtDays: 4-8 + BtMonths: 1 + BtYears: 2021 + MtVersion: 4.0.0.1359 + RunOnError: show_logs 200 + TestExpert: ${{ matrix.test }} + timeout-minutes: 10 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f4802e889..516d1a9b4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -110,7 +110,6 @@ jobs: - OrderQuery - ProfilerTest - RefsTest - - SerializerTest - TerminalTest - TimerTest - ValueStorageTest diff --git a/3D/Chart3D.h b/3D/Chart3D.h index 1fd4fbdb7..6dc5e3c42 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -30,8 +30,8 @@ #include "../Indicators/Indi_MA.mqh" #include "../Instances.h" #include "../Refs.mqh" -#include "../SerializerConverter.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerJson.h" #include "Chart3DCandles.h" #include "Chart3DType.h" #include "Cube.h" diff --git a/Account/Account.h b/Account/Account.h index 5e50510d5..bb435596c 100644 --- a/Account/Account.h +++ b/Account/Account.h @@ -26,7 +26,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Serializer.mqh" +#include "../Serializer/Serializer.h" #include "AccountBase.h" /** diff --git a/Account/Account.struct.h b/Account/Account.struct.h index 1b2a97517..2ae613e55 100644 --- a/Account/Account.struct.h +++ b/Account/Account.struct.h @@ -35,7 +35,7 @@ class Serializer; // Includes. -#include "../Serializer.mqh" +#include "../Serializer/Serializer.h" #include "../Terminal.define.h" // Struct for account entries. diff --git a/Account/AccountBase.h b/Account/AccountBase.h index 9d3ae7253..d74fd72a3 100644 --- a/Account/AccountBase.h +++ b/Account/AccountBase.h @@ -25,7 +25,6 @@ #define ACCOUNTBASE_H // Includes. -//#include "../Serializer.mqh" #include "../Refs.mqh" #include "AccountBase.struct.h" diff --git a/Account/AccountBase.struct.h b/Account/AccountBase.struct.h index 0f808c590..ab237c6b7 100644 --- a/Account/AccountBase.struct.h +++ b/Account/AccountBase.struct.h @@ -35,7 +35,7 @@ class Serializer; // Includes. -#include "../Serializer.mqh" +#include "../Serializer/Serializer.h" #include "../Terminal.define.h" // Struct for account entries. diff --git a/Account/AccountForex.h b/Account/AccountForex.h index 3d73b7bb8..03b3be121 100644 --- a/Account/AccountForex.h +++ b/Account/AccountForex.h @@ -25,7 +25,7 @@ #define ACCOUNTFOREX_H // Includes. -#include "../Serializer.mqh" +#include "../Serializer/Serializer.h" #include "Account.h" #include "AccountForex.struct.h" diff --git a/Account/AccountForex.struct.h b/Account/AccountForex.struct.h index 64aacffa3..c40a4e79d 100644 --- a/Account/AccountForex.struct.h +++ b/Account/AccountForex.struct.h @@ -35,7 +35,7 @@ class Serializer; // Includes. -#include "../Serializer.mqh" +#include "../Serializer/Serializer.h" #include "../Terminal.define.h" // Struct for account entries. diff --git a/Account/AccountMt.h b/Account/AccountMt.h index 11cb4c654..9e1713692 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -35,7 +35,7 @@ class AccountMt; #include "../Indicator/Indicator.struct.h" #include "../Order.struct.h" #include "../Orders.mqh" -#include "../Serializer.mqh" +#include "../Serializer/Serializer.h" #include "../SymbolInfo.mqh" #include "../Trade.struct.h" #include "Account.define.h" diff --git a/Bar.struct.h b/Bar.struct.h index 800a5f939..dffae6ba2 100644 --- a/Bar.struct.h +++ b/Bar.struct.h @@ -36,15 +36,16 @@ class Serializer; // Includes. #include "Bar.enum.h" #include "Chart.enum.h" -#include "ISerializable.h" -#include "Serializer.enum.h" -#include "SerializerNode.enum.h" +#include "Serializer/Serializable.h" +#include "Serializer/Serializer.enum.h" +#include "Serializer/SerializerNode.enum.h" #include "Std.h" +#include "Serializer/Serializer.h" /* Struct for storing OHLC values. */ struct BarOHLC #ifndef __MQL__ - : public ISerializable + : public Serializable #endif { datetime time; @@ -230,8 +231,6 @@ struct BarOHLC string ToCSV() { return StringFormat("%d,%g,%g,%g,%g", time, open, high, low, close); } }; -#include "Serializer.mqh" - /* Method to serialize BarOHLC structure. */ SerializerNodeType BarOHLC::Serialize(Serializer &s) { // s.Pass(THIS_REF, "time", TimeToString(time)); diff --git a/BufferStruct.mqh b/BufferStruct.mqh index c02eba371..af8459874 100644 --- a/BufferStruct.mqh +++ b/BufferStruct.mqh @@ -27,7 +27,7 @@ // Includes. #include "DictBase.mqh" #include "DictStruct.mqh" -#include "Serializer.mqh" +#include "Serializer/Serializer.h" /** * Implements BufferStruct's Overflow Listener. diff --git a/Candle.struct.h b/Candle.struct.h index 7e351ff17..b776f4ac9 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -36,16 +36,17 @@ class Serializer; // Includes. #include "Bar.enum.h" #include "Chart.enum.h" -#include "ISerializable.h" -#include "Serializer.enum.h" -#include "SerializerNode.enum.h" +#include "Serializer/Serializable.h" +#include "Serializer/Serializer.enum.h" +#include "Serializer/SerializerNode.enum.h" #include "Std.h" +#include "Serializer/Serializer.h" /* Structure for storing OHLC values. */ template struct CandleOHLC #ifndef __MQL__ - : public ISerializable + : public Serializable #endif { T open, high, low, close; @@ -276,8 +277,6 @@ struct CandleTOHLC : CandleOHLC { string ToCSV() { return StringFormat("%d,%g,%g,%g,%g", time, open, high, low, close); } }; -#include "Serializer.mqh" - /* Method to serialize CandleEntry structure. */ template SerializerNodeType CandleOHLC::Serialize(Serializer &s) { diff --git a/Chart.mqh b/Chart.mqh index e751a6bb9..ef20cd5f8 100644 --- a/Chart.mqh +++ b/Chart.mqh @@ -40,7 +40,7 @@ #include "Chart.struct.serialize.h" #include "Convert.mqh" #include "Market.mqh" -#include "Serializer.mqh" +#include "Serializer/Serializer.h" #include "Task/TaskCondition.enum.h" // Forward class declaration. diff --git a/Chart.struct.h b/Chart.struct.h index 9d5b75266..a4100f935 100644 --- a/Chart.struct.h +++ b/Chart.struct.h @@ -41,8 +41,8 @@ struct ChartTf; #include "Chart.enum.h" #include "Chart.struct.static.h" #include "Chart.struct.tf.h" -#include "Serializer.mqh" -#include "SerializerNode.enum.h" +#include "Serializer/Serializer.h" +#include "Serializer/SerializerNode.enum.h" #include "Terminal.define.h" /* Defines struct to store bar entries. */ diff --git a/Chart.struct.serialize.h b/Chart.struct.serialize.h index b33092843..99c8ecfaa 100644 --- a/Chart.struct.serialize.h +++ b/Chart.struct.serialize.h @@ -29,8 +29,8 @@ class Serializer; // Includes. -#include "Serializer.mqh" -#include "SerializerNode.enum.h" +#include "Serializer/Serializer.h" +#include "Serializer/SerializerNode.enum.h" /* Method to serialize ChartEntry structure. */ SerializerNodeType ChartEntry::Serialize(Serializer& _s) { diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 3a0dfed6e..4e2c2f037 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -35,8 +35,9 @@ class Serializer; // Includes. #include "Chart.enum.h" -#include "SerializerNode.enum.h" +#include "Serializer/SerializerNode.enum.h" #include "Terminal.define.h" +#include "Serializer/Serializer.h" /* Defines struct for chart timeframe. */ struct ChartTf { @@ -351,8 +352,6 @@ struct ChartTf { SerializerNodeType Serialize(Serializer& s); }; -#include "Serializer.mqh" - /* Method to serialize ChartTf structure. */ SerializerNodeType ChartTf::Serialize(Serializer& s) { s.PassEnum(THIS_REF, "tf", tf); diff --git a/Config.mqh b/Config.mqh index 331243fee..840e27495 100644 --- a/Config.mqh +++ b/Config.mqh @@ -33,7 +33,7 @@ #include "DictStruct.mqh" #include "File.mqh" #include "Object.mqh" -#include "Serializer.mqh" +#include "Serializer/Serializer.h" enum CONFIG_FORMAT { CONFIG_FORMAT_JSON, CONFIG_FORMAT_JSON_NO_WHITESPACES, CONFIG_FORMAT_INI }; diff --git a/Data.struct.h b/Data.struct.h index 9ee4ee34f..e174e6456 100644 --- a/Data.struct.h +++ b/Data.struct.h @@ -38,9 +38,10 @@ struct MqlRates; // Includes. #include "Data.enum.h" #include "DateTime.mqh" -#include "Serializer.enum.h" -#include "SerializerNode.enum.h" +#include "Serializer/Serializer.enum.h" +#include "Serializer/SerializerNode.enum.h" #include "Std.h" +#include "Serializer/Serializer.h" #ifndef __MQL__ /** @@ -330,8 +331,6 @@ struct DataParamEntry : public MqlParam { SerializerNodeType Serialize(Serializer &s); }; -#include "Serializer.mqh" - /* Method to serialize DataParamEntry struct. */ SerializerNodeType DataParamEntry::Serialize(Serializer &s) { s.PassEnum(THIS_REF, "type", type, SERIALIZER_FIELD_FLAG_HIDDEN); diff --git a/Dict.mqh b/Dict.mqh index 743cc92d1..69a6a275a 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -27,8 +27,8 @@ #include "Convert.mqh" #include "DictBase.mqh" #include "Matrix.mqh" -#include "Serializer.mqh" -#include "SerializerNodeIterator.mqh" +#include "Serializer/Serializer.h" +#include "Serializer/SerializerNodeIterator.h" template class DictIterator : public DictIteratorBase { diff --git a/DictIteratorBase.mqh b/DictIteratorBase.mqh index 5a529c0cf..a3c955558 100644 --- a/DictIteratorBase.mqh +++ b/DictIteratorBase.mqh @@ -31,7 +31,7 @@ class DictBase; #include "DictBase.mqh" #include "DictSlotsRef.h" -#include "SerializerConversions.h" +#include "Serializer/SerializerConversions.h" template class DictIteratorBase { diff --git a/DictObject.mqh b/DictObject.mqh index 6f7519766..755ee14fe 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -26,8 +26,8 @@ #include "Convert.mqh" #include "DictBase.mqh" -#include "Serializer.mqh" -#include "SerializerNodeIterator.mqh" +#include "Serializer/Serializer.h" +#include "Serializer/SerializerNodeIterator.h" template class DictObjectIterator : public DictIteratorBase { diff --git a/DictStruct.mqh b/DictStruct.mqh index 9b362c1a1..fd64ef91d 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -26,8 +26,8 @@ #include "DictBase.mqh" #include "DictIteratorBase.mqh" -#include "Serializer.mqh" -#include "SerializerNodeIterator.mqh" +#include "Serializer/Serializer.h" +#include "Serializer/SerializerNodeIterator.h" // DictIterator could be used as DictStruct iterator. #define DictStructIterator DictIteratorBase diff --git a/EA.mqh b/EA.mqh index e51cffb55..dbf04c0ff 100644 --- a/EA.mqh +++ b/EA.mqh @@ -39,10 +39,10 @@ #include "Market.mqh" #include "Platform.h" #include "Refs.struct.h" -#include "SerializerConverter.mqh" -#include "SerializerCsv.mqh" -#include "SerializerJson.mqh" -#include "SerializerSqlite.mqh" +#include "Serializer/SerializerConverter.h" +#include "Serializer/SerializerCsv.h" +#include "Serializer/SerializerJson.h" +#include "Serializer/SerializerSqlite.h" #include "Strategy.mqh" #include "SummaryReport.mqh" #include "Task/TaskManager.h" diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index f7aa36f4d..a7b1da4c4 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -42,9 +42,9 @@ struct IndicatorParams; #include "../Math.h" #include "../Object.mqh" #include "../Refs.mqh" -#include "../Serializer.mqh" -#include "../SerializerCsv.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/Serializer.h" +#include "../Serializer/SerializerCsv.h" +#include "../Serializer/SerializerJson.h" #include "../Storage/ValueStorage.h" #include "../Storage/ValueStorage.indicator.h" #include "../Storage/ValueStorage.native.h" diff --git a/Indicator/Indicator.struct.h b/Indicator/Indicator.struct.h index 4e1a220de..90d45fea2 100644 --- a/Indicator/Indicator.struct.h +++ b/Indicator/Indicator.struct.h @@ -40,7 +40,7 @@ struct ChartParams; #include "../Chart.struct.tf.h" #include "../Data.struct.h" #include "../DateTime.struct.h" -#include "../SerializerNode.enum.h" +#include "../Serializer/SerializerNode.enum.h" #include "Indicator.enum.h" #include "IndicatorData.struct.cache.h" //#include "Indicator.struct.serialize.h" diff --git a/Indicator/Indicator.struct.serialize.h b/Indicator/Indicator.struct.serialize.h index 512af9718..8855aa9f3 100644 --- a/Indicator/Indicator.struct.serialize.h +++ b/Indicator/Indicator.struct.serialize.h @@ -25,8 +25,8 @@ * Includes Indicator's struct serializers. */ -#include "../Serializer.mqh" -#include "../SerializerNode.enum.h" +#include "../Serializer/Serializer.h" +#include "../Serializer/SerializerNode.enum.h" #include "Indicator.struct.h" /* Method to serialize IndicatorParams structure. */ diff --git a/Indicator/IndicatorBase.h b/Indicator/IndicatorBase.h index f2738dcd4..ff1327cb2 100644 --- a/Indicator/IndicatorBase.h +++ b/Indicator/IndicatorBase.h @@ -40,9 +40,9 @@ #include "../Log.mqh" #include "../Object.mqh" #include "../Refs.mqh" -#include "../Serializer.mqh" -#include "../SerializerCsv.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/Serializer.h" +#include "../Serializer/SerializerCsv.h" +#include "../Serializer/SerializerJson.h" #include "../Util.h" /** diff --git a/Indicator/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h index 27eaa124b..3e49d5902 100644 --- a/Indicator/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -30,7 +30,7 @@ #define STRUCT_ENUM_INDICATOR_STATE_PROP STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) // Includes. -#include "../SerializerNode.enum.h" +#include "../Serializer/SerializerNode.enum.h" #include "IndicatorData.enum.h" // Type-less value for IndicatorDataEntryValue structure. diff --git a/Indicator/IndicatorData.struct.serialize.h b/Indicator/IndicatorData.struct.serialize.h index 7655450bd..c6b97399e 100644 --- a/Indicator/IndicatorData.struct.serialize.h +++ b/Indicator/IndicatorData.struct.serialize.h @@ -25,7 +25,7 @@ * Includes IndicatorData's struct serializers. */ -#include "../Serializer.mqh" +#include "../Serializer/Serializer.h" // Forward class declaration. class Serializer; diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index 61e7f3d56..b6397384a 100644 --- a/Indicators/Bitwise/Indi_Candle.mqh +++ b/Indicators/Bitwise/Indi_Candle.mqh @@ -25,7 +25,7 @@ #include "../../BufferStruct.mqh" #include "../../Indicator/Indicator.h" #include "../../Pattern.struct.h" -#include "../../Serializer.mqh" +#include "../../Serializer/Serializer.h" #include "../Price/Indi_Price.mqh" #include "../Special/Indi_Math.mqh" diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index 229faf261..6fb005d61 100644 --- a/Indicators/Bitwise/Indi_Pattern.mqh +++ b/Indicators/Bitwise/Indi_Pattern.mqh @@ -25,7 +25,7 @@ #include "../../BufferStruct.mqh" #include "../../Indicator/Indicator.h" #include "../../Pattern.struct.h" -#include "../../Serializer.mqh" +#include "../../Serializer/Serializer.h" #include "../Price/Indi_Price.mqh" #include "../Special/Indi_Math.mqh" diff --git a/Indicators/Indi_Drawer.struct.h b/Indicators/Indi_Drawer.struct.h index b1957e566..2014e8894 100644 --- a/Indicators/Indi_Drawer.struct.h +++ b/Indicators/Indi_Drawer.struct.h @@ -27,7 +27,7 @@ // Includes. #include "../Indicator/Indicator.struct.h" -#include "../SerializerNode.enum.h" +#include "../Serializer/SerializerNode.enum.h" // Structs. diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index bb90f9e96..986d07a62 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -23,7 +23,7 @@ // Includes. #include "../Bar.struct.h" #include "../Indicator/Indicator.struct.h" -#include "../Serializer.mqh" +#include "../Serializer/Serializer.h" #include "Special/Indi_Math.mqh" // Structs. diff --git a/Market.mqh b/Market.mqh index 157eb4c3d..996c83456 100644 --- a/Market.mqh +++ b/Market.mqh @@ -27,7 +27,7 @@ // Includes. #include "Market.struct.h" #include "Math.h" -#include "Serializer.mqh" +#include "Serializer/Serializer.h" #include "SymbolInfo.mqh" #include "SymbolInfo.struct.static.h" #include "Task/TaskCondition.enum.h" diff --git a/Market.struct.h b/Market.struct.h index 0937823ae..1283ce193 100644 --- a/Market.struct.h +++ b/Market.struct.h @@ -30,7 +30,7 @@ class Serializer; // Includes. #include "DateTime.struct.h" -#include "SerializerNode.enum.h" +#include "Serializer/SerializerNode.enum.h" #include "Std.h" // Market info. diff --git a/Order.mqh b/Order.mqh index d277a03c2..b0092bee5 100644 --- a/Order.mqh +++ b/Order.mqh @@ -41,10 +41,10 @@ class SymbolInfo; #include "Order.define.h" #include "Order.enum.h" #include "Order.struct.h" -#include "Serializer.define.h" -#include "Serializer.mqh" -#include "SerializerConverter.mqh" -#include "SerializerJson.mqh" +#include "Serializer/Serializer.define.h" +#include "Serializer/Serializer.h" +#include "Serializer/SerializerConverter.h" +#include "Serializer/SerializerJson.h" #include "Std.h" #include "String.mqh" #include "SymbolInfo.mqh" diff --git a/Order.struct.h b/Order.struct.h index bb1beb6b6..fff61929c 100644 --- a/Order.struct.h +++ b/Order.struct.h @@ -33,7 +33,7 @@ // Includes. #include "Data.struct.h" #include "Order.enum.h" -#include "Serializer.mqh" +#include "Serializer/Serializer.h" #include "SymbolInfo.struct.static.h" #include "Terminal.mqh" diff --git a/Redis.mqh b/Redis.mqh index 081f23a72..69be06ca8 100644 --- a/Redis.mqh +++ b/Redis.mqh @@ -27,9 +27,9 @@ #include "Dict.mqh" #include "Object.mqh" #include "Redis.struct.h" -#include "Serializer.mqh" -#include "SerializerConversions.h" -#include "SerializerJson.mqh" +#include "Serializer/Serializer.h" +#include "Serializer/SerializerConversions.h" +#include "Serializer/SerializerJson.h" #include "Socket.mqh" enum ENUM_REDIS_VALUE_SET { REDIS_VALUE_SET_ALWAYS, REDIS_VALUE_SET_IF_NOT_EXIST, REDIS_VALUE_SET_IF_ALREADY_EXIST }; diff --git a/Redis.struct.h b/Redis.struct.h index 2a68a8cb9..19d9d7663 100644 --- a/Redis.struct.h +++ b/Redis.struct.h @@ -31,7 +31,7 @@ #endif // Includes. -#include "SerializerConversions.h" +#include "Serializer/SerializerConversions.h" // Forward declaration. class Serializer; diff --git a/ISerializable.h b/Serializer/Serializable.h similarity index 98% rename from ISerializable.h rename to Serializer/Serializable.h index 8a66d50e1..b845f22c9 100644 --- a/ISerializable.h +++ b/Serializer/Serializable.h @@ -34,7 +34,7 @@ class Serializer; -class ISerializable { +class Serializable { public: virtual SerializerNodeType Serialize(Serializer &s) = 0; }; diff --git a/Serializer.define.h b/Serializer/Serializer.define.h similarity index 100% rename from Serializer.define.h rename to Serializer/Serializer.define.h diff --git a/Serializer.enum.h b/Serializer/Serializer.enum.h similarity index 100% rename from Serializer.enum.h rename to Serializer/Serializer.enum.h diff --git a/Serializer.mqh b/Serializer/Serializer.h similarity index 98% rename from Serializer.mqh rename to Serializer/Serializer.h index d76c001b2..ce544cf1a 100644 --- a/Serializer.mqh +++ b/Serializer/Serializer.h @@ -25,13 +25,13 @@ #define SERIALIZER_MQH // Includes. -#include "Convert.mqh" +#include "../Convert.mqh" +#include "../Terminal.define.h" #include "Serializer.define.h" #include "Serializer.enum.h" -#include "SerializerNode.mqh" -#include "SerializerNodeIterator.mqh" -#include "SerializerNodeParam.mqh" -#include "Terminal.define.h" +#include "SerializerNode.h" +#include "SerializerNodeIterator.h" +#include "SerializerNodeParam.h" #define SERIALIZER_DEFAULT_FP_PRECISION 8 diff --git a/SerializerBinary.mqh b/Serializer/SerializerBinary.h similarity index 97% rename from SerializerBinary.mqh rename to Serializer/SerializerBinary.h index 51995a411..a009dcc2e 100644 --- a/SerializerBinary.mqh +++ b/Serializer/SerializerBinary.h @@ -25,10 +25,10 @@ #define SERIALIZER_BINARY_MQH // Includes. -#include "DictBase.mqh" -#include "Object.mqh" -#include "Serializer.mqh" -#include "SerializerNode.mqh" +#include "../DictBase.mqh" +#include "../Object.mqh" +#include "Serializer.h" +#include "SerializerNode.h" class Log; diff --git a/SerializerConversions.h b/Serializer/SerializerConversions.h similarity index 97% rename from SerializerConversions.h rename to Serializer/SerializerConversions.h index 4f5454a5e..1a2cae9d8 100644 --- a/SerializerConversions.h +++ b/Serializer/SerializerConversions.h @@ -30,10 +30,10 @@ #pragma once #endif -#include "Convert.extern.h" -#include "DateTime.extern.h" -#include "Object.mqh" -#include "Refs.struct.h" +#include "../Convert.extern.h" +#include "../DateTime.extern.h" +#include "../Object.mqh" +#include "../Refs.struct.h" class SerializerConversions { public: diff --git a/SerializerConverter.mqh b/Serializer/SerializerConverter.h similarity index 98% rename from SerializerConverter.mqh rename to Serializer/SerializerConverter.h index 4ce3d5f28..7e9490239 100644 --- a/SerializerConverter.mqh +++ b/Serializer/SerializerConverter.h @@ -33,11 +33,11 @@ class SerializerNode; // Includes. -#include "File.mqh" +#include "../File.mqh" #include "Serializer.enum.h" -#include "Serializer.mqh" -#include "SerializerDict.mqh" -#include "SerializerNode.mqh" +#include "Serializer.h" +#include "SerializerDict.h" +#include "SerializerNode.h" class SerializerConverter { public: diff --git a/SerializerCsv.mqh b/Serializer/SerializerCsv.h similarity index 97% rename from SerializerCsv.mqh rename to Serializer/SerializerCsv.h index 7b219aaca..85992b779 100644 --- a/SerializerCsv.mqh +++ b/Serializer/SerializerCsv.h @@ -25,14 +25,14 @@ #define SERIALIZER_CSV_MQH // Includes. -#include "Dict.mqh" -#include "DictObject.mqh" -#include "DictStruct.mqh" -#include "Matrix.mqh" -#include "MiniMatrix.h" -#include "Object.mqh" -#include "SerializerConverter.mqh" -#include "SerializerNode.mqh" +#include "../Dict.mqh" +#include "../DictObject.mqh" +#include "../DictStruct.mqh" +#include "../Matrix.mqh" +#include "../MiniMatrix.h" +#include "../Object.mqh" +#include "SerializerConverter.h" +#include "SerializerNode.h" struct CsvTitle { int column_index; diff --git a/SerializerDict.mqh b/Serializer/SerializerDict.h similarity index 98% rename from SerializerDict.mqh rename to Serializer/SerializerDict.h index ddef3e957..098ade629 100644 --- a/SerializerDict.mqh +++ b/Serializer/SerializerDict.h @@ -25,7 +25,7 @@ #define SERIALIZER_DICT_MQH // Includes. -#include "SerializerNode.mqh" +#include "SerializerNode.h" enum ENUM_SERIALIZER_DICT_FLAGS {}; diff --git a/SerializerJson.mqh b/Serializer/SerializerJson.h similarity index 98% rename from SerializerJson.mqh rename to Serializer/SerializerJson.h index a0dc2f4c6..fd3ed5fed 100644 --- a/SerializerJson.mqh +++ b/Serializer/SerializerJson.h @@ -25,12 +25,12 @@ #define SERIALIZER_JSON_MQH // Includes. -#include "DictBase.mqh" -#include "Object.mqh" +#include "../DictBase.mqh" +#include "../Object.mqh" +#include "../String.extern.h" #include "Serializer.enum.h" -#include "Serializer.mqh" -#include "SerializerNode.mqh" -#include "String.extern.h" +#include "Serializer.h" +#include "SerializerNode.h" class Log; diff --git a/SerializerNode.enum.h b/Serializer/SerializerNode.enum.h similarity index 100% rename from SerializerNode.enum.h rename to Serializer/SerializerNode.enum.h diff --git a/SerializerNode.mqh b/Serializer/SerializerNode.h similarity index 98% rename from SerializerNode.mqh rename to Serializer/SerializerNode.h index c5143a9de..5f071e87b 100644 --- a/SerializerNode.mqh +++ b/Serializer/SerializerNode.h @@ -21,14 +21,14 @@ */ // Prevents processing this includes file for the second time. -#ifndef JSON_NODE_MQH -#define JSON_NODE_MQH +#ifndef SERIALIZER_NODE_H +#define SERIALIZER_NODE_H // Includes. -#include "Math.extern.h" +#include "../Math.extern.h" +#include "../Terminal.define.h" #include "SerializerNode.enum.h" -#include "SerializerNodeParam.mqh" -#include "Terminal.define.h" +#include "SerializerNodeParam.h" class SerializerNode { protected: @@ -368,4 +368,4 @@ class SerializerNode { } }; -#endif +#endif // SERIALIZER_NODE_H diff --git a/SerializerNodeIterator.mqh b/Serializer/SerializerNodeIterator.h similarity index 96% rename from SerializerNodeIterator.mqh rename to Serializer/SerializerNodeIterator.h index a821bacaf..2be711439 100644 --- a/SerializerNodeIterator.mqh +++ b/Serializer/SerializerNodeIterator.h @@ -21,11 +21,11 @@ */ // Prevents processing this includes file for the second time. -#ifndef JSON_ITERATOR_MQH -#define JSON_ITERATOR_MQH +#ifndef SERIALIZER_NODE_ITERATOR_H +#define SERIALIZER_NODE_ITERATOR_H -#include "Serializer.mqh" -#include "SerializerNode.mqh" +#include "Serializer.h" +#include "SerializerNode.h" class SerializerNode; class Serializer; diff --git a/SerializerNodeParam.mqh b/Serializer/SerializerNodeParam.h similarity index 99% rename from SerializerNodeParam.mqh rename to Serializer/SerializerNodeParam.h index 0ef237931..b37d68c63 100644 --- a/SerializerNodeParam.mqh +++ b/Serializer/SerializerNodeParam.h @@ -22,8 +22,9 @@ // Prevents processing this includes file for the second time. #include "SerializerConversions.h" -#ifndef JSON_PARAM_MQH -#define JSON_PARAM_MQH + +#ifndef SERIALIZER_NODE_PARAM_H +#define SERIALIZER_NODE_PARAM_H /** * Enumeration. @@ -333,6 +334,4 @@ SerializerNodeParam* SerializerNodeParam::FromString(string& value) { return param; } - - -#endif +#endif // SERIALIZER_NODE_PARAM_H diff --git a/SerializerObject.mqh b/Serializer/SerializerObject.h similarity index 90% rename from SerializerObject.mqh rename to Serializer/SerializerObject.h index fddd54ac0..c8894ae98 100644 --- a/SerializerObject.mqh +++ b/Serializer/SerializerObject.h @@ -25,11 +25,11 @@ #define SERIALIZER_OBJECT_MQH // Includes. -#include "DictBase.mqh" -#include "Object.mqh" -#include "Serializer.mqh" -#include "SerializerConverter.mqh" -#include "SerializerNode.mqh" +#include "../DictBase.mqh" +#include "../Object.mqh" +#include "Serializer.h" +#include "SerializerConverter.h" +#include "SerializerNode.h" class Log; diff --git a/SerializerSqlite.mqh b/Serializer/SerializerSqlite.h similarity index 97% rename from SerializerSqlite.mqh rename to Serializer/SerializerSqlite.h index df86d747e..ec2b18abc 100644 --- a/SerializerSqlite.mqh +++ b/Serializer/SerializerSqlite.h @@ -25,9 +25,9 @@ #define SERIALIZER_SQL_MQH // Includes. -#include "Database.mqh" -#include "SerializerConverter.mqh" -#include "SerializerCsv.mqh" +#include "../Database.mqh" +#include "SerializerConverter.h" +#include "SerializerCsv.h" class SerializerSqlite { public: diff --git a/tests/SerializerTest.mq4 b/Serializer/tests/Serializer.test.mq4 similarity index 97% rename from tests/SerializerTest.mq4 rename to Serializer/tests/Serializer.test.mq4 index 8411f0c76..1117647d4 100644 --- a/tests/SerializerTest.mq4 +++ b/Serializer/tests/Serializer.test.mq4 @@ -25,4 +25,4 @@ */ // Includes. -#include "SerializerTest.mq5" +#include "Serializer.test.mq5" diff --git a/tests/SerializerTest.mq5 b/Serializer/tests/Serializer.test.mq5 similarity index 96% rename from tests/SerializerTest.mq5 rename to Serializer/tests/Serializer.test.mq5 index 68ef491b4..dd895f13e 100644 --- a/tests/SerializerTest.mq5 +++ b/Serializer/tests/Serializer.test.mq5 @@ -27,20 +27,20 @@ */ // Includes. -#include "../BufferStruct.mqh" -#include "../Chart.mqh" -#include "../Config.mqh" -#include "../Data.define.h" -#include "../Data.struct.h" -#include "../DictStruct.mqh" -#include "../Serializer.mqh" -#include "../SerializerBinary.mqh" -#include "../SerializerCsv.mqh" -#include "../SerializerDict.mqh" -#include "../SerializerJson.mqh" -#include "../SerializerNode.mqh" -#include "../SerializerObject.mqh" -#include "../Test.mqh" +#include "../../BufferStruct.mqh" +#include "../../Chart.mqh" +#include "../../Config.mqh" +#include "../../Data.define.h" +#include "../../Data.struct.h" +#include "../../DictStruct.mqh" +#include "../../Test.mqh" +#include "../Serializer.h" +#include "../SerializerBinary.h" +#include "../SerializerCsv.h" +#include "../SerializerDict.h" +#include "../SerializerJson.h" +#include "../SerializerNode.h" +#include "../SerializerObject.h" struct SerializableSubEntry { public: diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index 6c7979ba0..bbe358b36 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -34,7 +34,7 @@ #define VALUE_STORAGE_H // Includes. -#include "../SerializerConversions.h" +#include "../Serializer/SerializerConversions.h" #include "../Util.h" #include "Objects.h" diff --git a/Strategy.struct.h b/Strategy.struct.h index 4f0d8fce8..cea4c81bb 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -31,7 +31,7 @@ #endif // Includes. -#include "Serializer.mqh" +#include "Serializer/Serializer.h" #include "Strategy.enum.h" #include "Strategy.struct.pricestop.h" #include "Task/Task.struct.h" diff --git a/SymbolInfo.mqh b/SymbolInfo.mqh index 1ee351e9a..50d21311e 100644 --- a/SymbolInfo.mqh +++ b/SymbolInfo.mqh @@ -38,8 +38,8 @@ class SymbolInfo; // Includes. #include "Log.mqh" -#include "Serializer.mqh" -#include "SerializerNode.enum.h" +#include "Serializer/Serializer.h" +#include "Serializer/SerializerNode.enum.h" /** * Class to provide symbol information. diff --git a/SymbolInfo.struct.h b/SymbolInfo.struct.h index 7b41c2bba..ea08ee9af 100644 --- a/SymbolInfo.struct.h +++ b/SymbolInfo.struct.h @@ -31,15 +31,16 @@ #endif // Includes. -#include "ISerializable.h" +#include "Serializer/Serializable.h" #include "Std.h" #include "SymbolInfo.struct.static.h" #include "Tick/Tick.struct.h" +#include "Serializer/Serializer.h" // Defines struct to store symbol data. struct SymbolInfoEntry #ifndef __MQL__ - : public ISerializable + : public Serializable #endif { double bid; // Current Bid price. @@ -152,8 +153,6 @@ struct SymbolInfoProp { SerializerNodeType Serialize(Serializer& _s); }; -#include "Serializer.mqh" - SerializerNodeType SymbolInfoEntry::Serialize(Serializer& _s) { _s.Pass(THIS_REF, "ask", ask); _s.Pass(THIS_REF, "bid", bid); diff --git a/Task/TaskManager.h b/Task/TaskManager.h index dfa28c10c..7cd985fde 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -36,8 +36,8 @@ // Includes. #include "../DictObject.mqh" -#include "../SerializerConverter.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerJson.h" #include "Task.struct.h" #include "TaskObject.h" diff --git a/Trade/TradeSignal.struct.h b/Trade/TradeSignal.struct.h index 5b8221cce..e3b63a535 100644 --- a/Trade/TradeSignal.struct.h +++ b/Trade/TradeSignal.struct.h @@ -27,8 +27,8 @@ // Includes. #include "../Chart.enum.h" -#include "../SerializerConverter.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerJson.h" // Defines. #define SIGNAL_CLOSE_BUY_FILTER STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_CLOSE_BUY_FILTER) diff --git a/Util.h b/Util.h index 10ae2079c..143f0d11a 100644 --- a/Util.h +++ b/Util.h @@ -30,7 +30,7 @@ #endif // Includes. -#include "SerializerConversions.h" +#include "Serializer/SerializerConversions.h" /** * Utility methods. diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 2c5e013e8..35b329fd5 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -43,7 +43,7 @@ #include "../BufferStruct.mqh" #include "../Chart.mqh" #include "../Platform.h" -#include "../Serializer.mqh" +#include "../Serializer/Serializer.h" #include "../Test.mqh" /** diff --git a/tests/BufferStructTest.mq5 b/tests/BufferStructTest.mq5 index f5881fb70..8e5b7cc6e 100644 --- a/tests/BufferStructTest.mq5 +++ b/tests/BufferStructTest.mq5 @@ -28,8 +28,8 @@ #include "../BufferStruct.mqh" #include "../Data.define.h" #include "../Data.struct.h" -#include "../SerializerConverter.mqh" -#include "../SerializerJSON.mqh" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerJSON.h" #include "../Std.h" #include "../Test.mqh" diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index fc9193df9..eac4ac6b9 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -62,7 +62,6 @@ struct IndicatorParams; #include "../DrawIndicator.mqh" #include "../EA.mqh" #include "../File.mqh" -#include "../ISerializable.h" // #include "../Inet.mqh" #include "../Log.mqh" #include "../MD5.mqh" @@ -89,18 +88,6 @@ struct IndicatorParams; #include "../Storage/Objects.h" #include "../Storage/ObjectsCache.h" // #include "../SVG.mqh" // @removeme -#include "../Serializer.mqh" -#include "../SerializerBinary.mqh" -#include "../SerializerConversions.h" -#include "../SerializerConverter.mqh" -#include "../SerializerCsv.mqh" -#include "../SerializerDict.mqh" -#include "../SerializerJson.mqh" -#include "../SerializerNode.mqh" -#include "../SerializerNodeIterator.mqh" -#include "../SerializerNodeParam.mqh" -#include "../SerializerObject.mqh" -#include "../SerializerSqlite.mqh" #include "../Session.mqh" #include "../SetFile.mqh" #include "../Socket.mqh" @@ -128,13 +115,28 @@ struct IndicatorParams; #include "../Util.h" #include "../Web.mqh" -// Includes indicator files. +// Includes Indicator files. #include "../Indicator/Indicator.define.h" #include "../Indicator/Indicator.h" #include "../Indicator/IndicatorBase.h" -//#include "../Indicator/IndicatorData.h" +#include "../Indicator/IndicatorData.h" #include "../Indicators/indicators.h" +// Includes Serializer files. +#include "../Serializer/Serializable.h" +#include "../Serializer/Serializer.h" +#include "../Serializer/SerializerBinary.h" +#include "../Serializer/SerializerConversions.h" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerCsv.h" +#include "../Serializer/SerializerDict.h" +#include "../Serializer/SerializerJson.h" +#include "../Serializer/SerializerNode.h" +#include "../Serializer/SerializerNodeIterator.h" +#include "../Serializer/SerializerNodeParam.h" +#include "../Serializer/SerializerObject.h" +#include "../Serializer/SerializerSqlite.h" + /** * Implements Init event handler. */ diff --git a/tests/ConfigTest.mq5 b/tests/ConfigTest.mq5 index 2477a62f6..bbed5cd13 100644 --- a/tests/ConfigTest.mq5 +++ b/tests/ConfigTest.mq5 @@ -29,9 +29,9 @@ #include "../Data.define.h" #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../SerializerConverter.mqh" -#include "../SerializerCsv.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerCsv.h" +#include "../Serializer/SerializerJson.h" #include "../Test.mqh" class Test { diff --git a/tests/DictTest.mq5 b/tests/DictTest.mq5 index 619dcc90f..cda693a4c 100644 --- a/tests/DictTest.mq5 +++ b/tests/DictTest.mq5 @@ -29,9 +29,9 @@ #include "../DictObject.mqh" #include "../DictStruct.mqh" #include "../Object.mqh" -#include "../Serializer.mqh" -#include "../SerializerConverter.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/Serializer.h" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerJson.h" #include "../Test.mqh" class DictTestClass { diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 6ef5efc18..37c82ad28 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -41,8 +41,8 @@ struct DataParamEntry; #include "../Indicators/Tick/Indi_TickMt.mqh" #include "../Indicators/indicators.h" #include "../Platform.h" -#include "../SerializerConverter.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerJson.h" #include "../Std.h" #include "../Test.mqh" diff --git a/tests/OrderTest.mq5 b/tests/OrderTest.mq5 index 2418b855e..343adc249 100644 --- a/tests/OrderTest.mq5 +++ b/tests/OrderTest.mq5 @@ -28,8 +28,8 @@ #include "../Chart.mqh" #include "../Order.mqh" #include "../Platform.h" -#include "../SerializerConverter.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerJson.h" #include "../Test.mqh" // Global defines. diff --git a/tests/ValueStorageTest.mq5 b/tests/ValueStorageTest.mq5 index f7ed555fa..ddc3b3c52 100644 --- a/tests/ValueStorageTest.mq5 +++ b/tests/ValueStorageTest.mq5 @@ -30,8 +30,8 @@ // Includes. #include "../Indicators/Indi_MA.mqh" #include "../Indicators/Price/Indi_Price.mqh" -#include "../SerializerConverter.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerJson.h" #include "../Storage/ValueStorage.h" #include "../Test.mqh" From baa49424a9800639ff5136172e9fd0f7baad8169 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 24 Aug 2022 14:17:51 +0200 Subject: [PATCH 019/123] WIP. Fixes Dict's logic inside InsertInto(). Also changed the way Overflow Listener works (enum items). Got rid of unnecessary overflow listeners in some classes. --- Buffer/BufferCandle.h | 22 ++---- Buffer/BufferTick.h | 21 +----- BufferStruct.mqh | 14 +++- Candle.struct.h | 17 +++++ Dict.enum.h | 6 +- Dict.mqh | 136 +++++++++++++++++++---------------- DictBase.mqh | 12 ---- DictObject.mqh | 138 ++++++++++++++++++++---------------- DictStruct.mqh | 132 ++++++++++++++++++---------------- Indicator/IndicatorCandle.h | 18 +---- Indicator/IndicatorRenko.h | 18 ++++- Indicator/IndicatorTick.h | 20 +----- tests/DictTest.mq5 | 15 ++-- 13 files changed, 287 insertions(+), 282 deletions(-) diff --git a/Buffer/BufferCandle.h b/Buffer/BufferCandle.h index 1bba5ba45..9ff42dc75 100644 --- a/Buffer/BufferCandle.h +++ b/Buffer/BufferCandle.h @@ -27,6 +27,8 @@ // Includes. #include "../BufferStruct.mqh" #include "../Candle.struct.h" +#include "../SerializerConverter.mqh" +#include "../SerializerJson.mqh" /** * Class to store struct data. @@ -41,7 +43,7 @@ class BufferCandle : public BufferStruct> { * * Called on constructor. */ - void Init() { SetOverflowListener(BufferCandleOverflowListener, 10); } + void Init() { SetOverflowListener(BufferStructOverflowListener, 10); } public: /* Constructors */ @@ -55,24 +57,10 @@ class BufferCandle : public BufferStruct> { Init(); } - /* Callback methods */ - /** - * Function should return true if resize can be made, or false to overwrite current slot. + * Returns JSON representation of the buffer. */ - static bool BufferCandleOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { - static int cache_limit = 86400; - switch (_reason) { - case DICT_OVERFLOW_REASON_FULL: - // We allow resize if dictionary size is less than 86400 slots. - return _size < cache_limit; - case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: - default: - // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. - break; - } - return false; - } + string ToJSON() { return SerializerConverter::FromObject(THIS_REF).ToString(); } }; #endif // BUFFER_CANDLE_H diff --git a/Buffer/BufferTick.h b/Buffer/BufferTick.h index 4eed02d69..fdfc5d901 100644 --- a/Buffer/BufferTick.h +++ b/Buffer/BufferTick.h @@ -109,7 +109,7 @@ class BufferTick : public BufferStruct> { _vs_spread = NULL; _vs_volume = NULL; _vs_tick_volume = NULL; - SetOverflowListener(BufferTickOverflowListener, 10); + SetOverflowListener(BufferStructOverflowListener, 10); } public: @@ -210,25 +210,6 @@ class BufferTick : public BufferStruct> { // Convert to OHLC in upper method return NULL; } - - /* Callback methods */ - - /** - * Function should return true if resize can be made, or false to overwrite current slot. - */ - static bool BufferTickOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { - static int cache_limit = 86400; - switch (_reason) { - case DICT_OVERFLOW_REASON_FULL: - // We allow resize if dictionary size is less than 86400 slots. - return _size < cache_limit; - case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: - default: - // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. - break; - } - return false; - } }; #endif // BUFFER_TICK_H diff --git a/BufferStruct.mqh b/BufferStruct.mqh index c02eba371..bd16b9e54 100644 --- a/BufferStruct.mqh +++ b/BufferStruct.mqh @@ -35,8 +35,18 @@ * @see DictBase */ bool BufferStructOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { - // We allow resize if dictionary size is less than 10000 slots. - return _size < 10000; + static int cache_limit = 86400; + switch (_reason) { + case DICT_LISTENER_FULL_CAN_RESIZE: + case DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE: + // We allow resize if dictionary size is less than 86400 slots. + return _size < cache_limit; + case DICT_LISTENER_CONFLICTS_CAN_OVERWRITE: + // We start to overwrite slots when we can't make dict bigger and there is at least 10 consecutive conflicts while + // inserting new value. + return _size >= cache_limit && _num_conflicts >= 10; + } + return true; } /** diff --git a/Candle.struct.h b/Candle.struct.h index f7034a1f3..0f9bfa3af 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -262,6 +262,9 @@ struct CandleOCTOHLC : CandleOHLC { // Returns timestamp of close price. long GetCloseTimestamp() { return close_timestamp; } + // Serializers. + SerializerNodeType Serialize(Serializer &s); + // Returns text representation of candle. string ToString() { return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", open, high, low, close, @@ -309,3 +312,17 @@ SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } + +/* Method to serialize CandleEntry structure. */ +template +SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { + s.Pass(THIS_REF, "is_complete", is_complete, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "open_timestamp", open_timestamp, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close_timestamp", close_timestamp, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "volume", volume, SERIALIZER_FIELD_FLAG_DYNAMIC); + return SerializerNodeObject; +} diff --git a/Dict.enum.h b/Dict.enum.h index 080a50271..a56671b41 100644 --- a/Dict.enum.h +++ b/Dict.enum.h @@ -42,8 +42,10 @@ enum DictMode { DictModeUnknown, DictModeDict, DictModeList }; * Reason of call to overflow listener. */ enum ENUM_DICT_OVERFLOW_REASON { - DICT_OVERFLOW_REASON_FULL, - DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, + DICT_LISTENER_FULL_CAN_RESIZE, // Dict is full. Can we grow up the dict? + DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, // Dict is not performant (too many average number of conflicts). Can we + // grow up the dict? + DICT_LISTENER_CONFLICTS_CAN_OVERWRITE // Conflict(s) when inserting new slot. Can we overwrite random used slot? }; /** diff --git a/Dict.mqh b/Dict.mqh index 743cc92d1..5e4e317c5 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -206,94 +206,108 @@ class Dict : public DictBase { * Inserts value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V value, bool allow_resize) { - if (_mode == DictModeUnknown) - _mode = DictModeDict; - else if (_mode != DictModeDict) { + if (THIS_ATTR _mode == DictModeUnknown) + THIS_ATTR _mode = DictModeDict; + else if (THIS_ATTR _mode != DictModeDict) { Alert("Warning: Dict already operates as a list, not a dictionary!"); return false; } unsigned int position; - DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); + DictSlot* _slot = THIS_ATTR GetSlotByKey(dictSlotsRef, key, position); - if (keySlot == NULL && !IsGrowUpAllowed()) { - // Resize is prohibited, so we will just overwrite some slot. - allow_resize = false; + // If we have a slot then we can overwrite it. + if (_slot != NULL) { + WriteSlot(_slot, key, value, DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); + // We're done, we don't have to increment number of slots used. + return true; } - if (allow_resize) { - // Will resize dict if there were performance problems before or there is no slots. - if (IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + // If we don't have a slot then we should consider growing up number of slots or overwrite some existing slot. + + bool _is_performant = dictSlotsRef.IsPerformant(); // Whether there is no performance problems. + bool _is_full = + dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots); // Whether we don't have empty slots to use. + + if ((_is_full || !_is_performant) && allow_resize) { + // We have to resize the dict as it is either full or have perfomance problems due to massive number of conflicts + // when inserting new values. + if (overflow_listener == NULL) { + // There is no overflow listener so we can freely grow up the dict. if (!GrowUp()) { + // Can't resize the dict. Error happened. return false; } - // 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)]; + } else { + // Overflow listener will decide if we can grow up the dict. + if (overflow_listener(_is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, + dictSlotsRef._num_used, 0)) { + // We can freely grow up the dict. + if (!GrowUp()) { + // Can't resize the dict. Error happened. + return false; } } - - if (keySlot == NULL) { - // We need to expand array of DictSlotsRef.DictSlots (by 25% by default). - if (!GrowUp()) return false; - } } } - if (keySlot == NULL) { - position = Hash(key) % ArraySize(dictSlotsRef.DictSlots); - - unsigned int _starting_position = position; - int _num_conflicts = 0; - bool _overwrite_slot = false; - - // Searching for empty DictSlot or used one with the matching key. It skips used, hashless DictSlots. - while (dictSlotsRef.DictSlots[position].IsUsed() && - (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { - if (overflow_listener_max_conflicts != 0 && ++_num_conflicts == overflow_listener_max_conflicts) { - if (overflow_listener != NULL) { - if (!overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used, _num_conflicts)) { - // Overflow listener returned false so we won't search for further empty slot. - _overwrite_slot = true; - break; - } - } else { - // Even if there is no overflow listener function, we stop searching for further empty slot as maximum - // number of conflicts has been reached. - _overwrite_slot = true; - break; - } - } + // At this point we have at least one free slot and we won't be doing any dict's grow up in the loop where we search + // for an empty slot. + + // Position we will start from in order to search free slot. + position = THIS_ATTR Hash(key) % ArraySize(dictSlotsRef.DictSlots); - // Position may overflow, so we will start from the beginning. - position = (position + 1) % ArraySize(dictSlotsRef.DictSlots); + // Saving position for further, possible overwrite. + unsigned int _starting_position = position; + + // How many times we had to skip slot as it was already occupied. + unsigned int _num_conflicts = 0; + + // Searching for empty DictSlot or used one with the matching key. It skips used, hashless DictSlots. + while (dictSlotsRef.DictSlots[position].IsUsed() && + (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { + ++_num_conflicts; + + if (overflow_listener == NULL) { + // There is no overflow listener, so we can't overwrite a slot. We will be looping until we find empty slot. + continue; } - if (_overwrite_slot) { - // Overwriting starting position for faster further lookup. + // We had to skip slot as it is already occupied. Now we are checking if + // there is too many conflicts/skips and thus we can overwrite slot in + // the starting position. + if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + // Looks like dict is working as buffer and we can overwrite slot in the starting position. position = _starting_position; - } else if (!dictSlotsRef.DictSlots[position].IsUsed()) { - // If slot isn't already used then we increment number of used slots. - ++dictSlotsRef._num_used; + break; } - dictSlotsRef.AddConflicts(_num_conflicts); + // Position may overflow, so we will start from the beginning. + position = (position + 1) % ArraySize(dictSlotsRef.DictSlots); } - dictSlotsRef.DictSlots[position].key = key; - dictSlotsRef.DictSlots[position].value = value; - dictSlotsRef.DictSlots[position].SetFlags(DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); + // Acknowledging slots array about number of conflicts as it calculates average number of conflicts per insert. + dictSlotsRef.AddConflicts(_num_conflicts); + + // Incrementing number of slots used only if we're writing into empty slot. + if (!dictSlotsRef.DictSlots[position].IsUsed()) { + ++dictSlotsRef._num_used; + } + + // Writing slot in the position of empty slot or, when overwriting, in starting position. + WriteSlot(dictSlotsRef.DictSlots[position], key, value, DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); return true; } + /*** + * Writes slot with given key, value and flags. + */ + void WriteSlot(DictSlot& _slot, const K _key, V _value, unsigned char _slot_flags) { + _slot.key = _key; + _slot.value = _value; + _slot.SetFlags(_slot_flags); + } + /** * Inserts hashless value into given array of DictSlots. */ diff --git a/DictBase.mqh b/DictBase.mqh index e7f0b8a75..718d78359 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -236,18 +236,6 @@ class DictBase { // No key found. } - /** - * Checks whether overflow listener allows dict to grow up. - */ - bool IsGrowUpAllowed() { - if (overflow_listener == NULL) { - return true; - } - - // Checking if overflow listener allows resize from current to higher number of slots. - return overflow_listener(DICT_OVERFLOW_REASON_FULL, Size(), 0); - } - /** * Moves last slot to given one to fill the hole after removing the value. */ diff --git a/DictObject.mqh b/DictObject.mqh index 6f7519766..2ed26024a 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -210,96 +210,108 @@ class DictObject : public DictBase { * Inserts value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { - if (this PTR_DEREF _mode == DictModeUnknown) - this PTR_DEREF _mode = DictModeDict; - else if (this PTR_DEREF _mode != DictModeDict) { + if (THIS_ATTR _mode == DictModeUnknown) + THIS_ATTR _mode = DictModeDict; + else if (THIS_ATTR _mode != DictModeDict) { Alert("Warning: Dict already operates as a list, not a dictionary!"); return false; } unsigned int position; - DictSlot* keySlot = this PTR_DEREF GetSlotByKey(dictSlotsRef, key, position); + DictSlot* _slot = THIS_ATTR GetSlotByKey(dictSlotsRef, key, position); - if (keySlot == NULL && !this PTR_DEREF IsGrowUpAllowed()) { - // Resize is prohibited, so we will just overwrite some slot. - allow_resize = false; + // If we have a slot then we can overwrite it. + if (_slot != NULL) { + WriteSlot(_slot, key, value, DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); + // We're done, we don't have to increment number of slots used. + return true; } - 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 we don't have a slot then we should consider growing up number of slots or overwrite some existing slot. + + bool _is_performant = dictSlotsRef.IsPerformant(); // Whether there is no performance problems. + bool _is_full = + dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots); // Whether we don't have empty slots to use. + + if ((_is_full || !_is_performant) && allow_resize) { + // We have to resize the dict as it is either full or have perfomance problems due to massive number of conflicts + // when inserting new values. + if (overflow_listener == NULL) { + // There is no overflow listener so we can freely grow up the dict. if (!GrowUp()) { + // Can't resize the dict. Error happened. 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); - } - - 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)]; + } else { + // Overflow listener will decide if we can grow up the dict. + if (overflow_listener(_is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, + dictSlotsRef._num_used, 0)) { + // We can freely grow up the dict. + if (!GrowUp()) { + // Can't resize the dict. Error happened. + return false; } } - - if (keySlot == NULL) { - // We need to expand array of DictSlotsRef.DictSlots. - if (!GrowUp()) return false; - } } } - if (keySlot == NULL) { - position = this PTR_DEREF Hash(key) % ArraySize(dictSlotsRef.DictSlots); - - unsigned int _starting_position = position; - unsigned int _num_conflicts = 0; - bool _overwrite_slot = false; - - // Searching for empty DictSlot or used one with the matching key. It skips used, hashless DictSlots. - while (dictSlotsRef.DictSlots[position].IsUsed() && - (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { - if (this PTR_DEREF overflow_listener_max_conflicts != 0 && - ++_num_conflicts == this PTR_DEREF overflow_listener_max_conflicts) { - if (this PTR_DEREF overflow_listener != NULL) { - if (!this PTR_DEREF overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used, - _num_conflicts)) { - // Overflow listener returned false so we won't search for further empty slot PTR_DEREF - _overwrite_slot = true; - break; - } - } else { - // Even if there is no overflow listener function, we stop searching for further empty slot as maximum - // number of conflicts has been reached. - _overwrite_slot = true; - break; - } - } + // At this point we have at least one free slot and we won't be doing any dict's grow up in the loop where we search + // for an empty slot. + + // Position we will start from in order to search free slot. + position = THIS_ATTR Hash(key) % ArraySize(dictSlotsRef.DictSlots); - // Position may overflow, so we will start from the beginning. - position = (position + 1) % ArraySize(dictSlotsRef.DictSlots); + // Saving position for further, possible overwrite. + unsigned int _starting_position = position; + + // How many times we had to skip slot as it was already occupied. + unsigned int _num_conflicts = 0; + + // Searching for empty DictSlot or used one with the matching key. It skips used, hashless DictSlots. + while (dictSlotsRef.DictSlots[position].IsUsed() && + (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { + ++_num_conflicts; + + if (overflow_listener == NULL) { + // There is no overflow listener, so we can't overwrite a slot. We will be looping until we find empty slot. + continue; } - if (_overwrite_slot) { - // Overwriting starting position for faster further lookup. + // We had to skip slot as it is already occupied. Now we are checking if + // there is too many conflicts/skips and thus we can overwrite slot in + // the starting position. + if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + // Looks like dict is working as buffer and we can overwrite slot in the starting position. position = _starting_position; - } else if (!dictSlotsRef.DictSlots[position].IsUsed()) { - // If slot isn't already used then we increment number of used slots. - ++dictSlotsRef._num_used; + break; } - dictSlotsRef.AddConflicts(_num_conflicts); + // Position may overflow, so we will start from the beginning. + position = (position + 1) % ArraySize(dictSlotsRef.DictSlots); } - dictSlotsRef.DictSlots[position].key = key; - dictSlotsRef.DictSlots[position].value = value; - dictSlotsRef.DictSlots[position].SetFlags(DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); + // Acknowledging slots array about number of conflicts as it calculates average number of conflicts per insert. + dictSlotsRef.AddConflicts(_num_conflicts); + + // Incrementing number of slots used only if we're writing into empty slot. + if (!dictSlotsRef.DictSlots[position].IsUsed()) { + ++dictSlotsRef._num_used; + } + + // Writing slot in the position of empty slot or, when overwriting, in starting position. + WriteSlot(dictSlotsRef.DictSlots[position], key, value, DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); return true; } + /*** + * Writes slot with given key, value and flags. + */ + void WriteSlot(DictSlot& _slot, const K _key, V& _value, unsigned char _slot_flags) { + _slot.key = _key; + _slot.value = _value; + _slot.SetFlags(_slot_flags); + } + /** * Inserts hashless value into given array of DictSlots. */ diff --git a/DictStruct.mqh b/DictStruct.mqh index 6fc1425cd..e57ce86a6 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -290,88 +290,100 @@ class DictStruct : public DictBase { } unsigned int position; - DictSlot* keySlot = THIS_ATTR GetSlotByKey(dictSlotsRef, key, position); + DictSlot* _slot = THIS_ATTR GetSlotByKey(dictSlotsRef, key, position); - if (keySlot == NULL && !THIS_ATTR IsGrowUpAllowed()) { - // Resize is prohibited, so we will just overwrite some slot. - allow_resize = false; + // If we have a slot then we can overwrite it. + if (_slot != NULL) { + WriteSlot(_slot, key, value, DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); + // We're done, we don't have to increment number of slots used. + return true; } - if (allow_resize) { - // Will resize dict if there were performance problems before or there is no slots. - if (THIS_ATTR IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + // If we don't have a slot then we should consider growing up number of slots or overwrite some existing slot. + + bool _is_performant = dictSlotsRef.IsPerformant(); // Whether there is no performance problems. + bool _is_full = + dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots); // Whether we don't have empty slots to use. + + if ((_is_full || !_is_performant) && allow_resize) { + // We have to resize the dict as it is either full or have perfomance problems due to massive number of conflicts + // when inserting new values. + if (overflow_listener == NULL) { + // There is no overflow listener so we can freely grow up the dict. if (!GrowUp()) { + // Can't resize the dict. Error happened. 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); - } - - 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)]; + } else { + // Overflow listener will decide if we can grow up the dict. + if (overflow_listener(_is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, + dictSlotsRef._num_used, 0)) { + // We can freely grow up the dict. + if (!GrowUp()) { + // Can't resize the dict. Error happened. + return false; } } - - if (keySlot == NULL) { - // We need to expand array of DictSlotsRef.DictSlots. - if (!GrowUp()) return false; - } } } - if (keySlot == NULL) { - position = THIS_ATTR Hash(key) % ArraySize(dictSlotsRef.DictSlots); - - unsigned int _starting_position = position; - unsigned int _num_conflicts = 0; - bool _overwrite_slot = false; - - // Searching for empty DictSlot or used one with the matching key. It skips used, hashless DictSlots. - while (dictSlotsRef.DictSlots[position].IsUsed() && - (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { - if (THIS_ATTR overflow_listener_max_conflicts != 0 && - ++_num_conflicts == THIS_ATTR overflow_listener_max_conflicts) { - if (THIS_ATTR overflow_listener != NULL) { - if (!THIS_ATTR overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used, - _num_conflicts)) { - // Overflow listener returned false so we won't search for further empty slot. - _overwrite_slot = true; - break; - } - } else { - // Even if there is no overflow listener function, we stop searching for further empty slot as maximum - // number of conflicts has been reached. - _overwrite_slot = true; - break; - } - } + // At this point we have at least one free slot and we won't be doing any dict's grow up in the loop where we search + // for an empty slot. + + // Position we will start from in order to search free slot. + position = THIS_ATTR Hash(key) % ArraySize(dictSlotsRef.DictSlots); - // Position may overflow, so we will start from the beginning. - position = (position + 1) % ArraySize(dictSlotsRef.DictSlots); + // Saving position for further, possible overwrite. + unsigned int _starting_position = position; + + // How many times we had to skip slot as it was already occupied. + unsigned int _num_conflicts = 0; + + // Searching for empty DictSlot or used one with the matching key. It skips used, hashless DictSlots. + while (dictSlotsRef.DictSlots[position].IsUsed() && + (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { + ++_num_conflicts; + + if (overflow_listener == NULL) { + // There is no overflow listener, so we can't overwrite a slot. We will be looping until we find empty slot. + continue; } - if (_overwrite_slot) { - // Overwriting starting position for faster further lookup. + // We had to skip slot as it is already occupied. Now we are checking if + // there is too many conflicts/skips and thus we can overwrite slot in + // the starting position. + if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + // Looks like dict is working as buffer and we can overwrite slot in the starting position. position = _starting_position; - } else if (!dictSlotsRef.DictSlots[position].IsUsed()) { - // If slot isn't already used then we increment number of used slots. - ++dictSlotsRef._num_used; + break; } - dictSlotsRef.AddConflicts(_num_conflicts); + // Position may overflow, so we will start from the beginning. + position = (position + 1) % ArraySize(dictSlotsRef.DictSlots); } - dictSlotsRef.DictSlots[position].key = key; - dictSlotsRef.DictSlots[position].value = value; - dictSlotsRef.DictSlots[position].SetFlags(DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); + // Acknowledging slots array about number of conflicts as it calculates average number of conflicts per insert. + dictSlotsRef.AddConflicts(_num_conflicts); + + // Incrementing number of slots used only if we're writing into empty slot. + if (!dictSlotsRef.DictSlots[position].IsUsed()) { + ++dictSlotsRef._num_used; + } + + // Writing slot in the position of empty slot or, when overwriting, in starting position. + WriteSlot(dictSlotsRef.DictSlots[position], key, value, DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); return true; } + /*** + * Writes slot with given key, value and flags. + */ + void WriteSlot(DictSlot& _slot, const K _key, V& _value, unsigned char _slot_flags) { + _slot.key = _key; + _slot.value = _value; + _slot.SetFlags(_slot_flags); + } + /** * Inserts hashless value into given array of DictSlots. */ diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 8221afe82..475155aba 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -80,7 +80,7 @@ class IndicatorCandle : public Indicator { // Along with indexing by shift, we can also index via timestamp! flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; icdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); - icdata.SetOverflowListener(IndicatorCandleOverflowListener, 10); + icdata.SetOverflowListener(BufferStructOverflowListener, 10); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_INDI_CANDLE_MODE_ENTRY); } @@ -288,22 +288,6 @@ class IndicatorCandle : public Indicator { return value_storages[_mode].Ptr(); } - /** - * Function should return true if resize can be made, or false to overwrite current slot. - */ - static bool IndicatorCandleOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { - switch (_reason) { - case DICT_OVERFLOW_REASON_FULL: - // We allow resize if dictionary size is less than 86400 slots. - return _size < 86400; - case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: - default: - // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. - break; - } - return false; - } - /** * Sends historic entries to listening indicators. May be overriden. */ diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index a226124be..3c24b6f4b 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -228,14 +228,26 @@ class IndicatorRenko : public IndicatorCandle { // Creating new candle. icdata.Add(_candle, entry.timestamp); - Print("Added candle: ", _candle.ToString()); + Print("Added candle: ", _candle.ToString(), " now there is ", icdata.Size(), " candles in the buffer."); last_incomplete_candle_ts = entry.timestamp; } - Print("Last Incomplete Time: ", TimeToString(last_incomplete_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); + static int iteration = 0; + + ++iteration; + + Print("Iteration: ", iteration); + + if (iteration > 1793) { + // Print(icdata.ToJSON()); + } + + Print("Last Incomplete Time: ", TimeToString(last_incomplete_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS), + " (", last_incomplete_candle_ts, ")"); Print("Last Incomplete Candle: ", icdata.GetByKey(last_incomplete_candle_ts).ToString()); - Print("Last Completed Time: ", TimeToString(last_completed_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); + Print("Last Completed Time: ", TimeToString(last_completed_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS), + " (", last_completed_candle_ts, ")"); Print("Last Completed Candle: ", icdata.GetByKey(last_completed_candle_ts).ToString()); // Updating tick & bar indices. Bar time is time of the last completed candle. diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 5f78a1882..d055958eb 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -69,7 +69,7 @@ class IndicatorTick : public Indicator { flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; itdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); - itdata.SetOverflowListener(IndicatorTickOverflowListener, 10); + itdata.SetOverflowListener(BufferStructOverflowListener, 10); // Ask and Bid price. Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); } @@ -326,24 +326,6 @@ class IndicatorTick : public Indicator { _tick.ask = _entry[1]; return _tick; } - - /* Callback methods */ - - /** - * Function should return true if resize can be made, or false to overwrite current slot. - */ - static bool IndicatorTickOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { - switch (_reason) { - case DICT_OVERFLOW_REASON_FULL: - // We allow resize if dictionary size is less than 86400 slots. - return _size < 86400; - case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: - default: - // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. - break; - } - return false; - } }; #endif diff --git a/tests/DictTest.mq5 b/tests/DictTest.mq5 index 619dcc90f..35abc6b0d 100644 --- a/tests/DictTest.mq5 +++ b/tests/DictTest.mq5 @@ -55,15 +55,18 @@ class DictTestClass { // Function should return true if resize can be made, or false to overwrite current slot. bool Dict14_OverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { + static int cache_limit = 10; switch (_reason) { - case DICT_OVERFLOW_REASON_FULL: + case DICT_LISTENER_FULL_CAN_RESIZE: + case DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE: // We allow resize if dictionary size is less than 10 slots. - return _size < 10; - case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: - default: - // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. - return false; + return _size < cache_limit; + case DICT_LISTENER_CONFLICTS_CAN_OVERWRITE: + // We start to overwrite slots when we can't make dict bigger and there is at least 10 consecutive conflicts while + // inserting new value. + return _size >= cache_limit && _num_conflicts >= 10; } + return true; } /** From ee7c872c966e5ea6ee9669abe2d63aea3733dbed Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 25 Aug 2022 18:08:01 +0200 Subject: [PATCH 020/123] WIP. Added Candle regeneration from historic ticks if candle was wiped from cache. Not yet works as we need to fix GetBarTime() in situation where there is no candle at shift 0. --- Buffer/BufferCandle.h | 4 +- Indicator/IndicatorCandle.h | 69 +++++++++++++++--------- Indicator/IndicatorData.h | 10 ++++ Indicator/IndicatorRenko.struct.h | 2 +- Indicator/IndicatorTick.h | 1 - Indicator/tests/IndicatorCandle.test.mq5 | 38 ++++++++++++- Indicators/Tick/Indi_TickMt.mqh | 34 ++++++++++++ Test.mqh | 7 +++ Tick/TickManager.h | 23 +------- 9 files changed, 135 insertions(+), 53 deletions(-) diff --git a/Buffer/BufferCandle.h b/Buffer/BufferCandle.h index 9ff42dc75..70462a28d 100644 --- a/Buffer/BufferCandle.h +++ b/Buffer/BufferCandle.h @@ -27,8 +27,8 @@ // Includes. #include "../BufferStruct.mqh" #include "../Candle.struct.h" -#include "../SerializerConverter.mqh" -#include "../SerializerJson.mqh" +#include "../Serializer/SerializerConverter.h" +#include "../Serializer/SerializerJson.h" /** * Class to store struct data. diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index c0c72d9f4..1697256be 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -40,6 +40,7 @@ #include "../Storage/ValueStorage.time.h" #include "../Storage/ValueStorage.volume.h" #include "Indicator.h" +#include "IndicatorData.h" #include "TickBarCounter.h" // Indicator modes. @@ -79,7 +80,6 @@ class IndicatorCandle : public Indicator { void Init() { // Along with indexing by shift, we can also index via timestamp! flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; - icdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); icdata.SetOverflowListener(BufferStructOverflowListener, 10); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_INDI_CANDLE_MODE_ENTRY); } @@ -109,6 +109,11 @@ class IndicatorCandle : public Indicator { /* Getters */ + /** + * Returns buffer where candles are temporarily stored. + */ + BufferCandle* GetCandlesBuffer() { return &icdata; } + /** * Gets open price for a given, optional shift. */ @@ -165,28 +170,33 @@ class IndicatorCandle : public Indicator { return THIS_PTR; } + /** + * Removes candle from the buffer. Used mainly for testing purposes. + */ + void InvalidateCandle(datetime _bar_time = 0) override { + if (_bar_time == 0) { + _bar_time = GetBarTime(); + } + + icdata.Unset(_bar_time); + } + /** * 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; - } + IndicatorDataEntry _entry = GetEntry(_shift); + BarOHLC _bar(0, 0, 0, _entry.timestamp); -#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 + if (!_entry.IsValid()) { + return _bar; + } - return _ohlc; + _bar.open = _entry.GetValue(INDI_CANDLE_MODE_PRICE_OPEN); + _bar.high = _entry.GetValue(INDI_CANDLE_MODE_PRICE_HIGH); + _bar.low = _entry.GetValue(INDI_CANDLE_MODE_PRICE_LOW); + _bar.close = _entry.GetValue(INDI_CANDLE_MODE_PRICE_CLOSE); + return _bar; } /** @@ -231,17 +241,26 @@ class IndicatorCandle : public Indicator { ResetLastError(); int _ishift = _index >= 0 ? (int)_index : iparams.GetShift(); long _candle_time = GetBarTime(_ishift); - CandleOCTOHLC _candle; - _candle = icdata.GetByKey(_candle_time); + long _candle_end_time = GetBarTime(_ishift - 1); + + CandleOCTOHLC _candle = icdata.GetByKey(_candle_time); 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()); + // No candle found. Regenerating it. + GetTick() PTR_DEREF FetchHistory(_candle_time * 1000, _candle_end_time * 1000 - 1); + // At this point candle should be regenerated (or not) via + // OnDataSourceEntry() called from IndicatorTick. + _candle = icdata.GetByKey(_candle_time); + + if (!_candle.IsValid()) { + // Candle wasn't regenerated. Maybe there is no history for that bar? + IndicatorDataEntry _entry = CandleToEntry(_candle_time, _candle); + _entry.AddFlags(INDI_ENTRY_FLAG_INSUFFICIENT_DATA); + return _entry; + } } + // At this point candle is filled with proper values. return CandleToEntry(_candle_time, _candle); } @@ -440,4 +459,4 @@ class IndicatorCandle : public Indicator { /* Virtual methods */ }; -#endif // INDICATOR_CANDLE_H +#endif diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index db257bfc2..6308c638c 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1432,6 +1432,16 @@ class IndicatorData : public IndicatorBase { */ virtual long GetTickVolume(int _shift = 0) { return GetCandle() PTR_DEREF GetTickVolume(_shift); } + /** + * Removes candle from the buffer. Used mainly for testing purposes. + */ + virtual void InvalidateCandle(datetime _bar_time = 0) { GetCandle() PTR_DEREF InvalidateCandle(_bar_time); } + + /** + * Fetches historic ticks for a given range and emits these ticks. Used to regenerate candles. + */ + virtual void FetchHistory(long _range_from, long _range_to) {} + /** * Returns value storage of given kind. */ diff --git a/Indicator/IndicatorRenko.struct.h b/Indicator/IndicatorRenko.struct.h index 2a6401689..d7e160798 100644 --- a/Indicator/IndicatorRenko.struct.h +++ b/Indicator/IndicatorRenko.struct.h @@ -31,7 +31,7 @@ #endif // Includes. -#include "../Indicator.struct.h" +#include "Indicator.struct.h" /* Structure for IndicatorRenko class parameters. */ struct IndicatorRenkoParams : IndicatorParams { diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index b7f613d31..e15d3d82e 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -68,7 +68,6 @@ class IndicatorTick : public Indicator { // We can only index via timestamp. flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; - itdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); itdata.SetOverflowListener(BufferStructOverflowListener, 10); // Ask and Bid price. Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); diff --git a/Indicator/tests/IndicatorCandle.test.mq5 b/Indicator/tests/IndicatorCandle.test.mq5 index 1d3f5c0d5..e4eddf465 100644 --- a/Indicator/tests/IndicatorCandle.test.mq5 +++ b/Indicator/tests/IndicatorCandle.test.mq5 @@ -25,13 +25,47 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../IndicatorCandle.h" +Ref indi_candle; + /** * Implements OnInit(). */ int OnInit() { - // @todo - return (INIT_SUCCEEDED); + Platform::Init(); + Platform::Add(indi_candle = Platform::FetchDefaultCandleIndicator()); + return _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; } + +void OnTick() { + Platform::Tick(); + if (Platform::IsNewHour()) { + // If a new hour occur, we check for a candle OHLCs, then we invalidate the + // candle and try to regenerate it by checking again the OHLCs. + BarOHLC _ohlc1 = indi_candle REF_DEREF GetOHLC(); + + // Now we invalidate current candle (candle will be removed from the IndicatorCandle's cache). + indi_candle REF_DEREF InvalidateCandle(); + + // Retrieving candle again. + BarOHLC _ohlc2 = indi_candle REF_DEREF GetOHLC(); + assertEqualOrExit( + _ohlc2.time, _ohlc1.time, + "Difference between consecutive OHLC values after invalidating and then regenerating the candle!"); + assertEqualOrExit( + _ohlc2.open, _ohlc1.open, + "Difference between consecutive OHLC values after invalidating and then regenerating the candle!"); + assertEqualOrExit( + _ohlc2.high, _ohlc1.high, + "Difference between consecutive OHLC values after invalidating and then regenerating the candle!"); + assertEqualOrExit( + _ohlc2.low, _ohlc1.low, + "Difference between consecutive OHLC values after invalidating and then regenerating the candle!"); + assertEqualOrExit( + _ohlc2.close, _ohlc1.close, + "Difference between consecutive OHLC values after invalidating and then regenerating the candle!"); + } +} \ No newline at end of file diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 2e950c955..75cd65594 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -107,6 +107,40 @@ class Indi_TickMt : public IndicatorTick { _fetch_history_on_first_tick = true; } + /** + * Fetches historic ticks for a given range and emits these ticks. Used to regenerate candles. + */ + void FetchHistory(long _range_from, long _range_to) override { + // Number of retries for CopyTicksRange(). + int _tries = 10; + + static MqlTick _tmp_ticks[]; + ArrayResize(_tmp_ticks, 0); + + while (_tries > 0) { + int _num_copied = CopyTicksRange(GetSymbol(), _tmp_ticks, COPY_TICKS_INFO, _range_from, _range_to); + + if (_num_copied == -1) { + ResetLastError(); + Sleep(1000); + --_tries; + } else { + for (int i = 0; i < _num_copied; ++i) { + TickAB _tick(_tmp_ticks[i].ask, _tmp_ticks[i].bid); +#ifdef __debug_verbose__ + Print("Emitting historic 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)); + } + break; + } + } + } + + /** + * Fetches historic ticks for last two weeks and emits those ticks. + */ void FetchHistory() { if (INDICATOR_TICK_REAL_FETCH_HISTORY == 0) { // No history requested. diff --git a/Test.mqh b/Test.mqh index 14fa84a1e..9bda8098c 100644 --- a/Test.mqh +++ b/Test.mqh @@ -46,6 +46,13 @@ return (ret); \ } +#define assertEqualOrExit(current, expected, msg) \ + if ((current) != (expected)) { \ + Alert(msg + " - Assert fail. Expected ", expected, ", but got ", current, \ + " in " + __FILE__ + ":" + (string)__LINE__); \ + ExpertRemove(); \ + } + #define assertFalseOrFail(cond, msg) \ if ((cond)) { \ Alert(msg + " - Assert fail on " + #cond + " in " + __FILE__ + ":" + (string)__LINE__); \ diff --git a/Tick/TickManager.h b/Tick/TickManager.h index befa1d4a9..76f2f0e1d 100644 --- a/Tick/TickManager.h +++ b/Tick/TickManager.h @@ -40,10 +40,7 @@ class TickManager : public BufferStruct { /** * Init code (called on constructor). */ - void Init() { - AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); - SetOverflowListener(TickManagerOverflowListener, 10); - } + void Init() { SetOverflowListener(BufferStructOverflowListener, 10); } public: /** @@ -73,22 +70,4 @@ class TickManager : public BufferStruct { // template // void Set(STRUCT_ENUM(TickManagerParams, ENUM_TSM_PARAMS_PROP) _prop, T _value) // { params.Set(_prop, _value); } - - /* Other methods */ - - /** - * Function should return true if resize can be made, or false to overwrite current slot. - */ - static bool TickManagerOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { - switch (_reason) { - case DICT_OVERFLOW_REASON_FULL: - // We allow resize if dictionary size is less than 86400 slots. - return _size < 86400; - case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: - default: - // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. - break; - } - return false; - } }; From ab065cff32e97e812406d2c7e58f45e9dfa4ddcd Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 7 Sep 2022 18:22:33 +0200 Subject: [PATCH 021/123] WIP. ItemsHistory and ItemsHistoryItemProvider classes to store and (re)generate candles/ticks to by used by IndicatorCandle and IndicatorTick-based indicators. --- Candle.struct.h | 5 +- Indicator/IndicatorCandle.h | 55 ++++---- Indicator/IndicatorData.h | 2 +- Indicators/Tick/Indi_TickMt.mqh | 18 ++- Storage/ItemsHistory.h | 225 ++++++++++++++++++++++++++++++++ Storage/tests/ItemsHistory.mq4 | 28 ++++ Storage/tests/ItemsHistory.mq5 | 57 ++++++++ tests/ItemsHistory.mq5 | 0 8 files changed, 365 insertions(+), 25 deletions(-) create mode 100644 Storage/ItemsHistory.h create mode 100644 Storage/tests/ItemsHistory.mq4 create mode 100644 Storage/tests/ItemsHistory.mq5 create mode 100644 tests/ItemsHistory.mq5 diff --git a/Candle.struct.h b/Candle.struct.h index 9296f8c66..5ee192beb 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -38,9 +38,9 @@ class Serializer; #include "Chart.enum.h" #include "Serializer/Serializable.h" #include "Serializer/Serializer.enum.h" +#include "Serializer/Serializer.h" #include "Serializer/SerializerNode.enum.h" #include "Std.h" -#include "Serializer/Serializer.h" /* Structure for storing OHLC values. */ template @@ -257,6 +257,9 @@ struct CandleOCTOHLC : CandleOHLC { ++volume; } + // Method used by ItemsHistory; + datetime GetTime() { return (datetime)open_timestamp; } + // Returns timestamp of open price. long GetOpenTimestamp() { return open_timestamp; } diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 1697256be..c1dd36b6c 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -30,8 +30,8 @@ #endif // Includes. -#include "../Buffer/BufferCandle.h" #include "../Candle.struct.h" +#include "../Storage/ItemsHistory.h" #include "../Storage/ValueStorage.price_median.h" #include "../Storage/ValueStorage.price_typical.h" #include "../Storage/ValueStorage.price_weighted.h" @@ -66,8 +66,8 @@ enum ENUM_INDI_CANDLE_MODE { template class IndicatorCandle : public Indicator { protected: - BufferCandle icdata; TickBarCounter counter; + ItemsHistory> history; protected: /* Protected methods */ @@ -80,7 +80,6 @@ class IndicatorCandle : public Indicator { void Init() { // Along with indexing by shift, we can also index via timestamp! flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; - icdata.SetOverflowListener(BufferStructOverflowListener, 10); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_INDI_CANDLE_MODE_ENTRY); } @@ -112,7 +111,7 @@ class IndicatorCandle : public Indicator { /** * Returns buffer where candles are temporarily stored. */ - BufferCandle* GetCandlesBuffer() { return &icdata; } + ItemsHistory>* GetCandlesBuffer() { return &history; } /** * Gets open price for a given, optional shift. @@ -162,40 +161,52 @@ class IndicatorCandle : public Indicator { /* Virtual method implementations */ /** - * Traverses source indicators' hierarchy and tries to find OHLC-featured - * indicator. IndicatorCandle satisfies such requirements. + * Returns time of the bar for a given shift. */ - IndicatorData* GetCandle(bool _warn_if_not_found = true, IndicatorData* _originator = nullptr) override { - // We are the candle indicator! - return THIS_PTR; + virtual datetime GetBarTime(int _shift = 0) { + /* + datetime _bar_time = history.GetBarTime(_shift); + + if (_bar_time == 0) { + // No bar found. + candles_history.FetchBarsFromShift() + } + */ + + // Will retrieve bar's time from tick indicator. + return GetBarTime(GetTf(), _shift); } /** - * Removes candle from the buffer. Used mainly for testing purposes. + * Returns time of the bar for a given timeframe and shift. */ - void InvalidateCandle(datetime _bar_time = 0) override { - if (_bar_time == 0) { - _bar_time = GetBarTime(); - } + virtual datetime GetBarTime(ENUM_TIMEFRAMES _tf, int _shift = 0) { + // Retrieving bar's time from tick indicator. + return GetTick() PTR_DEREF GetBarTime(_tf, _shift); + } - icdata.Unset(_bar_time); + /** + * 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 { - IndicatorDataEntry _entry = GetEntry(_shift); - BarOHLC _bar(0, 0, 0, _entry.timestamp); + BarOHLC _bar; - if (!_entry.IsValid()) { + if (!history.EnsureShiftExists(_shift)) { + // There's no candle fort that shift. return _bar; } - _bar.open = _entry.GetValue(INDI_CANDLE_MODE_PRICE_OPEN); - _bar.high = _entry.GetValue(INDI_CANDLE_MODE_PRICE_HIGH); - _bar.low = _entry.GetValue(INDI_CANDLE_MODE_PRICE_LOW); - _bar.close = _entry.GetValue(INDI_CANDLE_MODE_PRICE_CLOSE); + CandleOCTOHLC _candle = history.GetByShift(_shift); + _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.open_timestamp); return _bar; } diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 6308c638c..bf3a6b41a 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1139,7 +1139,7 @@ class IndicatorData : public IndicatorBase { /** * Returns time of the bar for a given shift. */ - virtual datetime GetBarTime(int _shift = 0) { return GetCandle() PTR_DEREF GetBarTime(_shift); } + virtual datetime GetBarTime(int _shift = 0) { return GetTick() PTR_DEREF GetBarTime(_shift); } /** * Search for a bar by its time. diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 75cd65594..dbecddbb3 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -74,6 +74,22 @@ class Indi_TickMt : public IndicatorTick { */ unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } + /** + * Returns time of the bar for a given shift. + */ + virtual datetime GetBarTime(int _shift = 0) { + Print( + "Error: Indi_TickMt's GetBarTime() requires TF to be passed. Please use GetBarTime(ENUM_TIMEFRAMES _tf, int " + "_shift = 0) variant."); + DebugBreak(); + return 0; + } + + /** + * Returns time of the bar for a given timeframe and shift. + */ + virtual datetime GetBarTime(ENUM_TIMEFRAMES _tf, int _shift = 0) { return ::GetBarTime(_tf, _shift); } + /** * Returns the indicator's struct entry for the given shift. * @@ -118,7 +134,7 @@ class Indi_TickMt : public IndicatorTick { ArrayResize(_tmp_ticks, 0); while (_tries > 0) { - int _num_copied = CopyTicksRange(GetSymbol(), _tmp_ticks, COPY_TICKS_INFO, _range_from, _range_to); + int _num_copied = (GetSymbol(), _tmp_ticks, COPY_TICKS_INFO, _range_from, _range_to); if (_num_copied == -1) { ResetLastError(); diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h new file mode 100644 index 000000000..54bd3b75d --- /dev/null +++ b/Storage/ItemsHistory.h @@ -0,0 +1,225 @@ +//+------------------------------------------------------------------+ +//| 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 ITEMS_HISTORY_H +#define ITEMS_HISTORY_H + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +#include "../DictStruct.mqh" +#include "../Refs.mqh" + +/** + * Direction used by ItemsHistoryItemProvider's methods. + */ +enum ENUM_ITEMS_HISTORY_DIRECTION { ITEMS_HISTORY_DIRECTION_FORWARD, ITEMS_HISTORY_DIRECTION_BACKWARD }; + +/** + * Generates/regenerates history for ItemsHistory class. Should be subclassed. + */ +template +class ItemsHistoryItemProvider : public Dynamic { + /** + * Retrieves given number of items starting from the given microseconds (inclusive). "_dir" identifies if we want + * previous or next items from mentioned date and time. + */ + virtual void GetItems(long _from_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(IV, _out_arr)) { + Print( + "Error: Retrieving items from a given date and time is not supported by this historic items provides. Please " + "use GetItems(int _from_index) version!"); + DebugBreak(); + } + + /** + * Retrieves given number of items starting from the given index (inclusive). "_dir" identifies if we want previous or + * next items from mentioned index. + */ + virtual void GetItems(int _from_index, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(IV, _out_arr)) { + Print( + "Error: Retrieving items from a given index is not supported by this historic items provides. Please use " + "GetItems(long _from_ms) version!"); + DebugBreak(); + } + + /** + * Helper method to retrieve items up to item with "_to_ms" date and time. + */ + void GetItems(datetime _from_ms, datetime _to_ms, ARRAY_REF(IV, _out_arr)) { + // @todo. + } +}; + +/** + * A continuous history of items. Appending new item may remove the + * oldest one and vice versa. We can't remove iems in-between the history. + * + * Indices in history's dict are incremented when adding new items, so + * first item will have index 0, second one will have index 1. + * + * When items are prepended, there could be a situation where the most + * recent items dissapeared and must be regenerated. + */ +template +class ItemsHistory { + // Provides items from bound provider. + Ref> item_provider; + + // Holds items per its index. "shift" property indicates how indices + // are shifted from their index. + DictStruct history; + + // Maximum number of entries in history dict. + unsigned int history_max_size; + + // How indices are shifted from their stored index. Shift is incremented + // after each appended item. + int current_index; + + // Index of the first valid iem. Items between range + // shift <-> first_valid_shift must be regenerated in order to access + // them. Note that we can't regenerate item only from the given shift. + // We have to regenerate all between given shift <- first_valid_shift. + int first_valid_index; + + // Index of the last valid item. items between range + // last_valid_shift <-> shift must be regenerated in order to access + // them. Note that we can't regenerate item only from the given shift. + // We have to regenerate all between last_valid_shift -> given shift. + int last_valid_index; + + public: + /** + * Constructor + */ + ItemsHistory(ItemsHistoryItemProvider* _item_provider) : item_provider(_item_provider) {} + + /** + * Gets time in milliseconds of the last(oldest) item's time in current history time or 0. + */ + /* + long GetLastValidTimeInCache() { + return history.GetByKey(last_valid_index).GetTime(); + } + */ + + /** + * Will regenerate items from item provider. "_dir" indicates if we have to prepend or append items. + */ + void RegenerateHistory(int _from_index, int _to_index, ENUM_ITEMS_HISTORY_DIRECTION _dir) {} + + /** + * Appends item to the history and increments history shift, so current item will be the added one. + * + * If shift is lower than last_valid_shift then we need to regenerate history between last_valid_shift and shift. + */ + void Append(IV& _item, bool _allow_regenerate = true) { + if (history_max_size != 0 && history.Size() >= history_max_size) { + // We need to remove first item from the history (the oldest one). + history.Unset(first_valid_index++); + } + + if (_allow_regenerate) { + // May call Append() multiple times with regenerated items. + RegenerateHistory(last_valid_index, current_index, ITEMS_HISTORY_DIRECTION_BACKWARD); + } + + // Adding item in the future of all the history and making it the current one. + history.Set(++current_index, _item); + + ++last_valid_index; + } + + /** + * Prepends item to the history. + * + * If shift is lower than last_valid_shift then we need to regenerate history between last_valid_shift and shift. + */ + void Prepend(IV& _item, bool _allow_regenerate = true) { + if (history_max_size != 0 && history.Size() >= history_max_size) { + // We need to remove first item from the history (the oldest one). + history.Unset(first_valid_index++); + } + + if (_allow_regenerate) { + // May call Prepend() multiple times with regenerated items. + RegenerateHistory(first_valid_index, current_index, ITEMS_HISTORY_DIRECTION_FORWARD); + } + + // Adding iem at the beginning of all the history and expanding history by one item in the past. + history.Set(first_valid_index--, _item); + } + + /** + * Returns bar time in milliseconds for the given shift. + */ + long GetBarTimeMsc(int _shift) { + if (!EnsureShiftExists(_shift)) { + // There won't be item at given shift. + return (datetime)0; + } + + return GetItemByShift(_shift).GetTime(); + } + + /** + * Returns bar date and time for the given shift. + */ + datetime GetBarTime(int _shift) { return (datetime)(GetBarTime(_shift) / 1000); } + + /** + * Ensures + */ + bool EnsureShiftExists(int _shift) { + int _index = GetShiftIndex(_shift); + if (_index < first_valid_index) { + RegenerateHistory(_index, first_valid_index - 1, ITEMS_HISTORY_DIRECTION_BACKWARD); + } else if (_index > last_valid_index) { + RegenerateHistory(last_valid_index + 1, _index, ITEMS_HISTORY_DIRECTION_FORWARD); + } + return history.Size() > 0; + } + + /** + * Returns history index from the given shift. + */ + int GetShiftIndex(int _shift) { return current_index - _shift; } + + /** + * Returns item at given shift. Shift must! exists. + */ + IV GetItemByShift(int _shift) { + int _index = GetShiftIndex(_shift); + if (_index < first_valid_index || _index > last_valid_index) { + Print("Error! Given shift is outside the range of valid items!"); + DebugBreak(); + IV _default; + return _default; + } + return history.GetByKey(_index); + } +}; + +#endif diff --git a/Storage/tests/ItemsHistory.mq4 b/Storage/tests/ItemsHistory.mq4 new file mode 100644 index 000000000..eaed0b07c --- /dev/null +++ b/Storage/tests/ItemsHistory.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2020, 31337 Investments 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 + * Test functionality of ItemsHistory class. + */ + +// Includes. +#include "ItemsHistory.mq5" diff --git a/Storage/tests/ItemsHistory.mq5 b/Storage/tests/ItemsHistory.mq5 new file mode 100644 index 000000000..660593ad4 --- /dev/null +++ b/Storage/tests/ItemsHistory.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2020, 31337 Investments 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 + * Test functionality of ItemsHistory class. + */ + +// Includes +#include "../../Platform.h" +#include "../../Test.mqh" +#include "../ItemsHistory.h" + +struct TestItem { + int value; +}; + +class ItemsHistoryTestItemProvider : public ItemsHistoryItemProvider {}; + +/** + * Implements OnInit(). + */ +int OnInit() { + Platform::Init(); + + ItemsHistory items(new ItemsHistoryTestItemProvider()); + + return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED); +} + +/** + * Implements OnTick(). + */ +void OnTick() { Platform::Tick(); } + +/** + * Implements OnDeinit(). + */ +void OnDeinit(const int reason) {} diff --git a/tests/ItemsHistory.mq5 b/tests/ItemsHistory.mq5 new file mode 100644 index 000000000..e69de29bb From cc084fde1e91f9f2fbcfd24542871e6a8363b7e3 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 8 Sep 2022 17:55:50 +0200 Subject: [PATCH 022/123] WIP. Making ItemsHistory for Candle and CandleTf indicators. Trying to connect Indi_TickMt with IndicatorCandle. --- Candle.struct.h | 37 +++---- Indicator/IndicatorCandle.h | 145 +++++---------------------- Indicator/IndicatorCandle.provider.h | 50 +++++++++ Indicator/IndicatorTf.h | 77 ++++---------- Indicators/Tick/Indi_TickMt.mqh | 57 +++++------ Storage/ItemsHistory.h | 33 ++++-- Storage/tests/ItemsHistory.mq5 | 10 +- tests/ItemsHistory.mq5 | 0 8 files changed, 175 insertions(+), 234 deletions(-) create mode 100644 Indicator/IndicatorCandle.provider.h delete mode 100644 tests/ItemsHistory.mq5 diff --git a/Candle.struct.h b/Candle.struct.h index 5ee192beb..e9cb39613 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -223,18 +223,18 @@ struct CandleOHLC template struct CandleOCTOHLC : CandleOHLC { bool is_complete; - long open_timestamp, close_timestamp; + long open_timestamp_ms, close_timestamp_ms; // 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, int _volume = 0) + CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, long _open_timestamp_ms = -1, + long _close_timestamp_ms = -1, int _volume = 0) : CandleOHLC(_open, _high, _low, _close), is_complete(true), - open_timestamp(_open_timestamp), - close_timestamp(_close_timestamp), + open_timestamp_ms(_open_timestamp_ms), + close_timestamp_ms(_close_timestamp_ms), volume(_volume) { if (_open != 0) { volume = 1; @@ -242,13 +242,13 @@ struct CandleOCTOHLC : CandleOHLC { } // Updates OHLC values taking into consideration tick's timestamp. - void Update(long _timestamp, T _price) { - if (_timestamp < open_timestamp) { - open_timestamp = _timestamp; + void Update(long _timestamp_ms, T _price) { + if (_timestamp_ms < open_timestamp_ms) { + open_timestamp_ms = _timestamp_ms; open = _price; } - if (_timestamp > close_timestamp) { - close_timestamp = _timestamp; + if (_timestamp_ms > close_timestamp_ms) { + close_timestamp_ms = _timestamp_ms; close = _price; } high = MathMax(high, _price); @@ -258,13 +258,16 @@ struct CandleOCTOHLC : CandleOHLC { } // Method used by ItemsHistory; - datetime GetTime() { return (datetime)open_timestamp; } + long GetTimeMs() { return open_timestamp_ms; } + + // Method used by ItemsHistory; + datetime GetTime() { return (datetime)(open_timestamp_ms / 1000); } // Returns timestamp of open price. - long GetOpenTimestamp() { return open_timestamp; } + long GetOpenTimestamp() { return open_timestamp_ms / 1000; } // Returns timestamp of close price. - long GetCloseTimestamp() { return close_timestamp; } + long GetCloseTimestamp() { return close_timestamp_ms / 1000; } // Serializers. SerializerNodeType Serialize(Serializer &s); @@ -273,8 +276,8 @@ struct CandleOCTOHLC : CandleOHLC { string ToString() { return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", open, high, low, close, is_complete ? "Complete" : "Incomplete", - TimeToString(open_timestamp, TIME_DATE | TIME_MINUTES | TIME_SECONDS), - TimeToString(close_timestamp, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); + TimeToString(open_timestamp_ms, TIME_DATE | TIME_MINUTES | TIME_SECONDS), + TimeToString(close_timestamp_ms, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); } }; @@ -319,8 +322,8 @@ SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { template SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { s.Pass(THIS_REF, "is_complete", is_complete, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "open_timestamp", open_timestamp, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "close_timestamp", close_timestamp, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "open_timestamp_ms", open_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close_timestamp_ms", close_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index c1dd36b6c..21fcabc02 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -40,6 +40,7 @@ #include "../Storage/ValueStorage.time.h" #include "../Storage/ValueStorage.volume.h" #include "Indicator.h" +#include "IndicatorCandle.provider.h" #include "IndicatorData.h" #include "TickBarCounter.h" @@ -67,7 +68,7 @@ template class IndicatorCandle : public Indicator { protected: TickBarCounter counter; - ItemsHistory> history; + ItemsHistory, ItemsHistoryCandleProvider> history; protected: /* Protected methods */ @@ -89,13 +90,14 @@ class IndicatorCandle : public Indicator { /** * Class constructor. */ - IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, - int _indi_mode = 0) - : Indicator(_icparams, _idparams, _indi_src, _indi_mode) { + IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, + ItemsHistoryCandleProvider* _candle_provider, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(_candle_provider) { Init(); } - IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name) { + IndicatorCandle(ItemsHistoryCandleProvider* _candle_provider, ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, + int _shift = 0, string _name = "") + : Indicator(_itype, _shift, _name), history(_candle_provider) { Init(); } @@ -111,7 +113,7 @@ class IndicatorCandle : public Indicator { /** * Returns buffer where candles are temporarily stored. */ - ItemsHistory>* GetCandlesBuffer() { return &history; } + ItemsHistory, ItemsHistoryCandleProvider>* GetHistory() { return &history; } /** * Gets open price for a given, optional shift. @@ -146,7 +148,7 @@ class IndicatorCandle : public Indicator { /** * Returns the number of bars on the chart. */ - int GetBars() override { return (int)icdata.Size(); } + int GetBars() override { return (int)history.PeakSize(); } /** * Returns current tick index (incremented every OnTick()). @@ -163,27 +165,7 @@ class IndicatorCandle : public Indicator { /** * Returns time of the bar for a given shift. */ - virtual datetime GetBarTime(int _shift = 0) { - /* - datetime _bar_time = history.GetBarTime(_shift); - - if (_bar_time == 0) { - // No bar found. - candles_history.FetchBarsFromShift() - } - */ - - // Will retrieve bar's time from tick indicator. - return GetBarTime(GetTf(), _shift); - } - - /** - * Returns time of the bar for a given timeframe and shift. - */ - virtual datetime GetBarTime(ENUM_TIMEFRAMES _tf, int _shift = 0) { - // Retrieving bar's time from tick indicator. - return GetTick() PTR_DEREF GetBarTime(_tf, _shift); - } + virtual datetime GetBarTime(int _shift = 0) { return history.GetItemTimeByShift(_shift); } /** * Traverses source indicators' hierarchy and tries to find OHLC-featured @@ -205,8 +187,8 @@ class IndicatorCandle : public Indicator { return _bar; } - CandleOCTOHLC _candle = history.GetByShift(_shift); - _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.open_timestamp); + CandleOCTOHLC _candle = history.GetItemByShift(_shift); + _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.open_timestamp_ms); return _bar; } @@ -216,13 +198,7 @@ class IndicatorCandle : public Indicator { * 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); + CandleOCTOHLC candle = history.GetItemByShift(_shift); return candle.volume; } @@ -251,28 +227,8 @@ class IndicatorCandle : public Indicator { IndicatorDataEntry GetEntry(long _index = -1) override { ResetLastError(); int _ishift = _index >= 0 ? (int)_index : iparams.GetShift(); - long _candle_time = GetBarTime(_ishift); - long _candle_end_time = GetBarTime(_ishift - 1); - - CandleOCTOHLC _candle = icdata.GetByKey(_candle_time); - - if (!_candle.IsValid()) { - // No candle found. Regenerating it. - GetTick() PTR_DEREF FetchHistory(_candle_time * 1000, _candle_end_time * 1000 - 1); - // At this point candle should be regenerated (or not) via - // OnDataSourceEntry() called from IndicatorTick. - _candle = icdata.GetByKey(_candle_time); - - if (!_candle.IsValid()) { - // Candle wasn't regenerated. Maybe there is no history for that bar? - IndicatorDataEntry _entry = CandleToEntry(_candle_time, _candle); - _entry.AddFlags(INDI_ENTRY_FLAG_INSUFFICIENT_DATA); - return _entry; - } - } - - // At this point candle is filled with proper values. - return CandleToEntry(_candle_time, _candle); + CandleOCTOHLC _candle = history.GetItemByShift(_ishift); + return CandleToEntry(_candle.GetTime(), _candle); } /** @@ -318,16 +274,6 @@ class IndicatorCandle : public Indicator { return value_storages[_mode].Ptr(); } - /** - * Sends historic entries to listening indicators. May be overriden. - */ - void EmitHistory() override { - for (DictStructIterator> iter(icdata.Begin()); iter.IsValid(); ++iter) { - IndicatorDataEntry _entry = CandleToEntry(iter.Key(), iter.Value()); - EmitEntry(_entry); - } - } - /** * Converts candle into indicator's data entry. */ @@ -354,52 +300,17 @@ class IndicatorCandle : public Indicator { } /** - * Adds tick's price to the matching candle and updates its OHLC values. - */ - void UpdateCandle(long _tick_timestamp, double _price) { - long _candle_timestamp = CalcCandleTimestamp(_tick_timestamp); - -#ifdef __debug_verbose__ - 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); - } - - /** - * Calculates candle's timestamp from tick's timestamp. - */ - long CalcCandleTimestamp(long _tick_timestamp) { - return _tick_timestamp - _tick_timestamp % (iparams.GetSecsPerCandle()); - } - - /** - * Called when data source emits new entry (historic or future one). + * Called when data source emits new entry (new one in ascending order). */ void OnDataSourceEntry(IndicatorDataEntry& entry) override { - // Updating candle from bid price. - UpdateCandle(entry.timestamp, entry[1]); - - // Updating tick & bar indices. - counter.OnTick(CalcCandleTimestamp(entry.timestamp)); + // Parent indicator (e.g., Indi_TickMt) emitted an entry containing tick's + // ask and bid price. As an abstract class, we really don't know how to + // update/create candles so we just pass the entry into history's + // ItemsHistoryCandleProvider and it will do all the job. + history.GetProvider() PTR_DEREF OnTick(entry.timestamp * 1000, (float)entry[0], (float)entry[1]); + + // @fixit Maybe we should generate some tick/bar change? + // counter.OnTick(CalcCandleTimestamp(entry.timestamp)); }; /** @@ -459,11 +370,7 @@ class IndicatorCandle : public Indicator { } string CandlesToString() { - string _result; - for (DictStructIterator> iter(icdata.Begin()); iter.IsValid(); ++iter) { - IndicatorDataEntry _entry = CandleToEntry(iter.Key(), iter.Value()); - _result += IntegerToString(iter.Key()) + ": " + _entry.ToString() + "\n"; - } + string _result = "CandlesToString() not yet implemented!"; return _result; } diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h new file mode 100644 index 000000000..20b4b1315 --- /dev/null +++ b/Indicator/IndicatorCandle.provider.h @@ -0,0 +1,50 @@ +//+------------------------------------------------------------------+ +//| 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 INDICATOR_CANDLE_PROVIDER_H +#define INDICATOR_CANDLE_PROVIDER_H + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Candle.struct.h" +#include "../Storage/ItemsHistory.h" + +/** + * Regenerates candles and updates exising candles from new ticks. Subclasses by IndicatorTf, IndicatorRenko. + */ +template +class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider> { + public: + /** + * Called when new tick was emitted from IndicatorTick-based source. + */ + virtual void OnTick(long _timestamp_ms, float _ask, float _bid) { + // Should be overrided. + } +}; + +#endif diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 9822e226f..2dbb2cf2b 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -34,6 +34,21 @@ #include "IndicatorCandle.h" #include "IndicatorTf.struct.h" +/** + * Candle grouping and regenerationf for time-frame based candles. + */ +template +class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { + public: + /** + * Called when new tick was emitted from IndicatorTick-based source. + */ + virtual void OnTick(long _timestamp_ms, float _ask, float _bid) { + // @todo Check if tick is outside current candle and if yes, close the candle, + // mark as completed and open new candle. + } +}; + /** * Class to deal with candle indicators. */ @@ -58,7 +73,7 @@ class IndicatorTf : public IndicatorCandle { /** * Class constructor with timeframe enum. */ - IndicatorTf(unsigned int _spc) { + IndicatorTf(unsigned int _spc) : IndicatorCandle(new ItemsHistoryTfCandleProvider()) { iparams.SetSecsPerCandle(_spc); Init(); } @@ -66,7 +81,8 @@ class IndicatorTf : public IndicatorCandle { /** * Class constructor with timeframe enum. */ - IndicatorTf(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + IndicatorTf(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + : IndicatorCandle(new ItemsHistoryTfCandleProvider()) { iparams.SetSecsPerCandle(ChartTf::TfToSeconds(_tf)); tf = _tf; Init(); @@ -75,7 +91,8 @@ class IndicatorTf : public IndicatorCandle { /** * Class constructor with timeframe index. */ - IndicatorTf(ENUM_TIMEFRAMES_INDEX _tfi = 0) { + IndicatorTf(ENUM_TIMEFRAMES_INDEX _tfi = 0) + : IndicatorCandle(new ItemsHistoryTfCandleProvider()) { iparams.SetSecsPerCandle(ChartTf::TfToSeconds(ChartTf::IndexToTf(_tfi))); tf = ChartTf::IndexToTf(_tfi); Init(); @@ -85,62 +102,10 @@ class IndicatorTf : public IndicatorCandle { * Class constructor with parameters. */ IndicatorTf(TFP& _icparams, const IndicatorDataParams& _idparams) - : IndicatorCandle(_icparams, _idparams) { + : IndicatorCandle(_icparams, _idparams, new ItemsHistoryTfCandleProvider()) { Init(); } - /** - * Returns time of the bar for a given shift (MT-compatible shift). - */ - datetime GetBarTimeLegacy(int _shift = 0) { - // Note: iTime() in MT4 build can return not rounded values. - datetime _curr = (datetime)CalcCandleTimestamp(::iTime(GetSymbol(), GetTf(), fmax(0, _shift))); - datetime _last_valid = 0; - -#ifdef __MQL4__ - if (GetLastError() == ERR_HISTORY_WILL_UPDATED) { - // Workaround for MT4 history data issues. - // See: https://www.mql5.com/en/forum/155707 - for (int i = 0; i < 10; i++) { - Sleep(1000); - _curr = ::iTime(GetSymbol(), GetTf(), 0); - if (GetLastError() != ERR_HISTORY_WILL_UPDATED) { - break; - } - SetUserError(ERR_HISTORY_WILL_UPDATED); - } - } -#endif - while (_curr >= icdata.GetMin()) { - if (icdata.KeyExists(_curr)) { - _last_valid = _curr; - if (_shift-- == 0) { - return _curr; - } - } - // Going back in time by TF. - _curr -= ChartTf::TfToSeconds(tf); - } - - // No entry found. Returning last valid candle. - if (icdata.KeyExists(_last_valid)) { - return _last_valid; - } else { - // Not a single valid candle found. - return 0; - } - } - - /* Virtual methods */ - - /** - * Returns time of the bar for a given shift. - */ - datetime GetBarTime(int _shift = 0) override { - // @fixit Should be replaced by MT-compatible bar time calculation for the given shift. - return GetBarTimeLegacy(_shift); - } - /** * Gets indicator's time-frame. */ diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index dbecddbb3..cdea3baeb 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -74,22 +74,6 @@ class Indi_TickMt : public IndicatorTick { */ unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } - /** - * Returns time of the bar for a given shift. - */ - virtual datetime GetBarTime(int _shift = 0) { - Print( - "Error: Indi_TickMt's GetBarTime() requires TF to be passed. Please use GetBarTime(ENUM_TIMEFRAMES _tf, int " - "_shift = 0) variant."); - DebugBreak(); - return 0; - } - - /** - * Returns time of the bar for a given timeframe and shift. - */ - virtual datetime GetBarTime(ENUM_TIMEFRAMES _tf, int _shift = 0) { return ::GetBarTime(_tf, _shift); } - /** * Returns the indicator's struct entry for the given shift. * @@ -99,28 +83,35 @@ class Indi_TickMt : public IndicatorTick { * 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); + // @todo Use history to check/regenerate tick and return data entry. + + /* + 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); - TickAB _tick = itdata.GetByKey(_bar_time); - IndicatorDataEntry _entry = TickToEntry(_bar_time, _tick); + if (_entry.IsValid()) { + istate.is_changed = false; + istate.is_ready = true; + } - if (_entry.IsValid()) { - istate.is_changed = false; - istate.is_ready = true; + return _entry; } - 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 - 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; + */ - _fetch_history_on_first_tick = true; + IndicatorDataEntry _default; + return _default; } /** @@ -134,7 +125,7 @@ class Indi_TickMt : public IndicatorTick { ArrayResize(_tmp_ticks, 0); while (_tries > 0) { - int _num_copied = (GetSymbol(), _tmp_ticks, COPY_TICKS_INFO, _range_from, _range_to); + int _num_copied = CopyTicksRange(GetSymbol(), _tmp_ticks, COPY_TICKS_INFO, _range_from, _range_to); if (_num_copied == -1) { ResetLastError(); diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index 54bd3b75d..c165ab21f 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -82,10 +82,10 @@ class ItemsHistoryItemProvider : public Dynamic { * When items are prepended, there could be a situation where the most * recent items dissapeared and must be regenerated. */ -template +template class ItemsHistory { // Provides items from bound provider. - Ref> item_provider; + Ref item_provider; // Holds items per its index. "shift" property indicates how indices // are shifted from their index. @@ -110,11 +110,20 @@ class ItemsHistory { // We have to regenerate all between last_valid_shift -> given shift. int last_valid_index; + /// Maximum number of items that occupied the history. + unsigned int peak_size; + public: /** * Constructor */ - ItemsHistory(ItemsHistoryItemProvider* _item_provider) : item_provider(_item_provider) {} + ItemsHistory(PT* _item_provider) + : item_provider(_item_provider), current_index(0), first_valid_index(0), last_valid_index(0), peak_size(0) {} + + /** + * Returns item provider. + */ + PT* GetProvider() { return item_provider.Ptr(); } /** * Gets time in milliseconds of the last(oldest) item's time in current history time or 0. @@ -125,6 +134,12 @@ class ItemsHistory { } */ + /** + * Returns maximum number of items that occupied the history. Could be used e.g., to determine how many bars could be + * retrieved from history and past the history. + */ + unsigned int PeakSize() { return peak_size; } + /** * Will regenerate items from item provider. "_dir" indicates if we have to prepend or append items. */ @@ -150,6 +165,8 @@ class ItemsHistory { history.Set(++current_index, _item); ++last_valid_index; + + peak_size = MathMax(peak_size, history.Size()); } /** @@ -170,24 +187,26 @@ class ItemsHistory { // Adding iem at the beginning of all the history and expanding history by one item in the past. history.Set(first_valid_index--, _item); + + peak_size = MathMax(peak_size, history.Size()); } /** - * Returns bar time in milliseconds for the given shift. + * Returns item time in milliseconds for the given shift. */ - long GetBarTimeMsc(int _shift) { + long GetItemTimeByShiftMsc(int _shift) { if (!EnsureShiftExists(_shift)) { // There won't be item at given shift. return (datetime)0; } - return GetItemByShift(_shift).GetTime(); + return GetItemByShift(_shift).GetTimeMs(); } /** * Returns bar date and time for the given shift. */ - datetime GetBarTime(int _shift) { return (datetime)(GetBarTime(_shift) / 1000); } + datetime GetItemTimeByShift(int _shift) { return (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); } /** * Ensures diff --git a/Storage/tests/ItemsHistory.mq5 b/Storage/tests/ItemsHistory.mq5 index 660593ad4..1e289adba 100644 --- a/Storage/tests/ItemsHistory.mq5 +++ b/Storage/tests/ItemsHistory.mq5 @@ -31,6 +31,12 @@ struct TestItem { int value; + + // Method used by ItemsHistory; + long GetTimeMs() { return 0; } + + // Method used by ItemsHistory; + datetime GetTime() { return (datetime)0; } }; class ItemsHistoryTestItemProvider : public ItemsHistoryItemProvider {}; @@ -41,10 +47,10 @@ class ItemsHistoryTestItemProvider : public ItemsHistoryItemProvider { int OnInit() { Platform::Init(); - ItemsHistory items(new ItemsHistoryTestItemProvider()); + ItemsHistory items(new ItemsHistoryTestItemProvider()); return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED); -} +}; /** * Implements OnTick(). diff --git a/tests/ItemsHistory.mq5 b/tests/ItemsHistory.mq5 deleted file mode 100644 index e69de29bb..000000000 From 09b3bb518f2a770ac036c2879e129f66321c5e12 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Sat, 17 Sep 2022 19:15:02 +0200 Subject: [PATCH 023/123] WIP. Closer to the end of ItemsHistory class and candle providers for IndicatorTf. --- Candle.struct.h | 16 +++-- Dict.mqh | 21 +++--- DictObject.mqh | 21 +++--- DictStruct.mqh | 21 +++--- Indicator/IndicatorData.h | 3 + Indicator/IndicatorTf.h | 57 +++++++++++++-- Indicators/Indi_Drawer.mqh | 7 +- Indicators/Indi_PriceFeeder.mqh | 7 +- Storage/ItemsHistory.h | 120 ++++++++++++++++++++++++++------ 9 files changed, 203 insertions(+), 70 deletions(-) diff --git a/Candle.struct.h b/Candle.struct.h index e9cb39613..c18565e7c 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -243,16 +243,24 @@ struct CandleOCTOHLC : CandleOHLC { // Updates OHLC values taking into consideration tick's timestamp. void Update(long _timestamp_ms, T _price) { - if (_timestamp_ms < open_timestamp_ms) { + bool _is_init = open_timestamp_ms == -1; + + if (_is_init || _timestamp_ms < open_timestamp_ms) { open_timestamp_ms = _timestamp_ms; open = _price; } - if (_timestamp_ms > close_timestamp_ms) { + if (_is_init || _timestamp_ms > close_timestamp_ms) { close_timestamp_ms = _timestamp_ms; close = _price; } - high = MathMax(high, _price); - low = MathMin(low, _price); + + if (_is_init) { + high = _price; + low = _price; + } else { + high = MathMax(high, _price); + low = MathMin(low, _price); + } // Increasing candle's volume. ++volume; } diff --git a/Dict.mqh b/Dict.mqh index f7ff8da09..d9960273b 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -268,18 +268,15 @@ class Dict : public DictBase { (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { ++_num_conflicts; - if (overflow_listener == NULL) { - // There is no overflow listener, so we can't overwrite a slot. We will be looping until we find empty slot. - continue; - } - - // We had to skip slot as it is already occupied. Now we are checking if - // there is too many conflicts/skips and thus we can overwrite slot in - // the starting position. - if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { - // Looks like dict is working as buffer and we can overwrite slot in the starting position. - position = _starting_position; - break; + if (overflow_listener != NULL) { + // We had to skip slot as it is already occupied. Now we are checking if + // there is too many conflicts/skips and thus we can overwrite slot in + // the starting position. + if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + // Looks like dict is working as buffer and we can overwrite slot in the starting position. + position = _starting_position; + break; + } } // Position may overflow, so we will start from the beginning. diff --git a/DictObject.mqh b/DictObject.mqh index 0f3245225..648e8b33f 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -272,18 +272,15 @@ class DictObject : public DictBase { (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { ++_num_conflicts; - if (overflow_listener == NULL) { - // There is no overflow listener, so we can't overwrite a slot. We will be looping until we find empty slot. - continue; - } - - // We had to skip slot as it is already occupied. Now we are checking if - // there is too many conflicts/skips and thus we can overwrite slot in - // the starting position. - if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { - // Looks like dict is working as buffer and we can overwrite slot in the starting position. - position = _starting_position; - break; + if (overflow_listener != NULL) { + // We had to skip slot as it is already occupied. Now we are checking if + // there is too many conflicts/skips and thus we can overwrite slot in + // the starting position. + if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + // Looks like dict is working as buffer and we can overwrite slot in the starting position. + position = _starting_position; + break; + } } // Position may overflow, so we will start from the beginning. diff --git a/DictStruct.mqh b/DictStruct.mqh index be367945e..f336b080b 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -340,18 +340,15 @@ class DictStruct : public DictBase { (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { ++_num_conflicts; - if (overflow_listener == NULL) { - // There is no overflow listener, so we can't overwrite a slot. We will be looping until we find empty slot. - continue; - } - - // We had to skip slot as it is already occupied. Now we are checking if - // there is too many conflicts/skips and thus we can overwrite slot in - // the starting position. - if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { - // Looks like dict is working as buffer and we can overwrite slot in the starting position. - position = _starting_position; - break; + if (overflow_listener != NULL) { + // We had to skip slot as it is already occupied. Now we are checking if + // there is too many conflicts/skips and thus we can overwrite slot in + // the starting position. + if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + // Looks like dict is working as buffer and we can overwrite slot in the starting position. + position = _starting_position; + break; + } } // Position may overflow, so we will start from the beginning. diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index bf3a6b41a..4da9fceac 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1743,6 +1743,9 @@ class IndicatorData : public IndicatorBase { */ virtual void OnDataSourceEntry(IndicatorDataEntry& entry){}; + /** + * Called when new tick is retrieved from attached data source. + */ virtual void OnTick(int _global_tick_index) {} /** diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 2dbb2cf2b..947e53142 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -35,7 +35,7 @@ #include "IndicatorTf.struct.h" /** - * Candle grouping and regenerationf for time-frame based candles. + * Candle grouping and regeneration for time-frame based candles. */ template class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { @@ -43,9 +43,58 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { /** * Called when new tick was emitted from IndicatorTick-based source. */ - virtual void OnTick(long _timestamp_ms, float _ask, float _bid) { - // @todo Check if tick is outside current candle and if yes, close the candle, - // mark as completed and open new candle. + virtual void OnTick(long _time_ms, float _ask, float _bid) { + Print("IndicatorTf's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | TIME_SECONDS), + ", ", _ask, ", ", _bid); + + // Index of the candle we will be updating/creating. + int _candle_index = GetCandleIndexFromTimeMs(_time_ms); + + // We know that tick's timestamp will be ahead of the last tick and thus + // inside or ahead of the last created candle. In order to retrieve last + // valid candle, we need to use ItemsHistory::GetItemByShift(0) to check if + // we have to update last or create/append new candle. + CandleOCTOHLC _candle; + + // Will regenerate candles up to the last added candle ever. We have to + // call it, because some of the previous actions may have removed some of + // the recent candles. Note that OnTick() advances its _time_ms in + // ascending order, so all we need to most recent history. + GetHistory() PTR_DEREF EnsureShiftExists(0); + + if (GetHistory() PTR_DEREF TryGetItemByIndex(_candle_index, _candle)) { + // There is a candle at given time. Updating it. + _candle.Update(_time_ms, _bid); + + // Storing candle in the history. + GetHistory() PTR_DEREF Update(_candle, _candle_index); + } else { + // There is no such candle. Adding new one. + _candle.Update(_time_ms, _bid); + + // Adding candle as the most recent item in the history. + GetHistory() PTR_DEREF Append(_candle); + } + } + + /** + * Determines index of the candle for the ItemsHistory from given time in + * milliseconds. + */ + int GetCandleIndexFromTimeMs(long _time_ms) {} + + /** + * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we + * want previous or next items from selected starting point. + */ + virtual void GetItems(long _from, ENUM_ITEMS_HISTORY_SELECTOR _sel, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, + ARRAY_REF(CandleOCTOHLC, _out_arr)) { + // Method is called if there is a missing item (candle) in the history. We need to regenerate it. + if (_sel == ITEMS_HISTORY_SELECTOR_INDEX) { + } else if (_sel == ITEMS_HISTORY_SELECTOR_TIME_MS) { + Print("Error: Candles are indexed by their index (integer) and thus we can't work with time indices!"); + DebugBreak(); + } } }; diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index 8ec621163..4cc4e9b12 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -111,8 +111,11 @@ class Indi_Drawer : public Indicator { return false; } - virtual void OnTick() { - Indicator::OnTick(); + /** + * Called when new tick is retrieved from attached data source. + */ + void OnTick(int _global_tick_index) override { + Indicator::OnTick(_global_tick_index); /* @fixme TaskActionEntry action(INDI_ACTION_SET_VALUE); diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index 206a0e7a5..f68bdadff 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -98,8 +98,11 @@ class Indi_PriceFeeder : public Indicator { return _value; } - void OnTick() { - Indicator::OnTick(); + /** + * Called when new tick is retrieved from attached data source. + */ + void OnTick(int _global_tick_index) override { + Indicator::OnTick(_global_tick_index); if (idparams.is_draw) { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index c165ab21f..6b1ec43b5 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -37,39 +37,53 @@ */ enum ENUM_ITEMS_HISTORY_DIRECTION { ITEMS_HISTORY_DIRECTION_FORWARD, ITEMS_HISTORY_DIRECTION_BACKWARD }; +/** + * Whether we're selecting history via index (shift) or time in milliseconds. + */ +enum ENUM_ITEMS_HISTORY_SELECTOR { ITEMS_HISTORY_SELECTOR_INDEX, ITEMS_HISTORY_SELECTOR_TIME_MS }; + +/** + * Forward declaration. + */ +template +class ItemsHistory; + /** * Generates/regenerates history for ItemsHistory class. Should be subclassed. */ template class ItemsHistoryItemProvider : public Dynamic { + ItemsHistory>* history; + + public: /** - * Retrieves given number of items starting from the given microseconds (inclusive). "_dir" identifies if we want - * previous or next items from mentioned date and time. + * Constructor. */ - virtual void GetItems(long _from_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(IV, _out_arr)) { - Print( - "Error: Retrieving items from a given date and time is not supported by this historic items provides. Please " - "use GetItems(int _from_index) version!"); - DebugBreak(); - } + ItemsHistoryItemProvider(ItemsHistory>* _history) : history(_history) {} /** - * Retrieves given number of items starting from the given index (inclusive). "_dir" identifies if we want previous or - * next items from mentioned index. + * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we + * want previous or next items from selected starting point. */ - virtual void GetItems(int _from_index, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(IV, _out_arr)) { + virtual void GetItems(long _from, ENUM_ITEMS_HISTORY_SELECTOR _sel, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, + ARRAY_REF(IV, _out_arr)) { Print( - "Error: Retrieving items from a given index is not supported by this historic items provides. Please use " - "GetItems(long _from_ms) version!"); + "Error: Retrieving items from a given date and time is not supported by this historic items provides. Please " + "use GetItems(int _from_index) version!"); DebugBreak(); } /** * Helper method to retrieve items up to item with "_to_ms" date and time. */ - void GetItems(datetime _from_ms, datetime _to_ms, ARRAY_REF(IV, _out_arr)) { + void GetItems(long _from, ENUM_ITEMS_HISTORY_SELECTOR _sel, datetime _to_ms, ARRAY_REF(IV, _out_arr)) { // @todo. } + + /** + * Returns pointer to items history this item providers works for. + */ + ItemsHistory>* GetHistory() { return history; } }; /** @@ -104,6 +118,9 @@ class ItemsHistory { // We have to regenerate all between given shift <- first_valid_shift. int first_valid_index; + // Index of the most old item in the history ever added. + int first_valid_index_ever; + // Index of the last valid item. items between range // last_valid_shift <-> shift must be regenerated in order to access // them. Note that we can't regenerate item only from the given shift. @@ -118,7 +135,12 @@ class ItemsHistory { * Constructor */ ItemsHistory(PT* _item_provider) - : item_provider(_item_provider), current_index(0), first_valid_index(0), last_valid_index(0), peak_size(0) {} + : item_provider(_item_provider), + current_index(0), + first_valid_index(0), + first_valid_index_ever(0), + last_valid_index(0), + peak_size(0) {} /** * Returns item provider. @@ -143,7 +165,23 @@ class ItemsHistory { /** * Will regenerate items from item provider. "_dir" indicates if we have to prepend or append items. */ - void RegenerateHistory(int _from_index, int _to_index, ENUM_ITEMS_HISTORY_DIRECTION _dir) {} + void RegenerateHistory(int _from_index, int _to_index, ENUM_ITEMS_HISTORY_DIRECTION _dir) { + static ARRAY(IV, _items); // Items generated by provider. + + ArrayResize(_items, 0); + + int _item_count = _to_index - _from_index + 1; + + item_provider REF_DEREF GetItems(_from_index, ITEMS_HISTORY_SELECTOR_INDEX, _dir, _item_count, _items); + + for (int i = 0; i < _item_count; ++i) { + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + Append(_items[i], false); + } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + Prepend(_items[i], false); + } + } + } /** * Appends item to the history and increments history shift, so current item will be the added one. @@ -156,7 +194,7 @@ class ItemsHistory { history.Unset(first_valid_index++); } - if (_allow_regenerate) { + if (_allow_regenerate && last_valid_index < current_index) { // May call Append() multiple times with regenerated items. RegenerateHistory(last_valid_index, current_index, ITEMS_HISTORY_DIRECTION_BACKWARD); } @@ -176,21 +214,35 @@ class ItemsHistory { */ void Prepend(IV& _item, bool _allow_regenerate = true) { if (history_max_size != 0 && history.Size() >= history_max_size) { - // We need to remove first item from the history (the oldest one). - history.Unset(first_valid_index++); + // We need to remove last item from the history (the newest one). + history.Unset(last_valid_index--); } - if (_allow_regenerate) { + if (_allow_regenerate && first_valid_index_ever < current_index) { // May call Prepend() multiple times with regenerated items. RegenerateHistory(first_valid_index, current_index, ITEMS_HISTORY_DIRECTION_FORWARD); } - // Adding iem at the beginning of all the history and expanding history by one item in the past. + // Adding item at the beginning of all the history and expanding history by one item in the past. history.Set(first_valid_index--, _item); + // Saving index of the most old item in the history ever added. + first_valid_index_ever = MathMin(first_valid_index_ever, first_valid_index); + peak_size = MathMax(peak_size, history.Size()); } + /** + * Updates item in the history. History must contain item with the given index! + */ + void Update(IV& _item, int _index) { + if (!history.KeyExists(_index)) { + Print("Error: You may only update existing items! History doesn't contain item with index ", _index, ".") + DebugBreak(); + } + history.Set(_index, _item); + } + /** * Returns item time in milliseconds for the given shift. */ @@ -221,13 +273,37 @@ class ItemsHistory { return history.Size() > 0; } + /** + * Returns item at given index. Index must exist! + */ + IV GetItemByIndex(int _index) { + if (_index < first_valid_index || _index > last_valid_index) { + Print("Error! Given index is outside the range of valid items!"); + DebugBreak(); + IV _default; + return _default; + } + return history.GetByKey(_index); + } + + /** + * Tries to get item at given index. + */ + bool TryGetItemByIndex(int _index, IV& _out_item) { + if (_index < first_valid_index || _index > last_valid_index) { + return false; + } + _out_item = history.GetByKey(_index); + return true; + } + /** * Returns history index from the given shift. */ int GetShiftIndex(int _shift) { return current_index - _shift; } /** - * Returns item at given shift. Shift must! exists. + * Returns item at given shift. Shift must exist! */ IV GetItemByShift(int _shift) { int _index = GetShiftIndex(_shift); From 293da014e6685ab11c764299bec9c952a4f587f8 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 20 Sep 2022 18:12:53 +0200 Subject: [PATCH 024/123] WIP. Blocked because of too complicated relationship between ItemsHistoryItemProvider and ItemsHistory classes (maybe create some kind of abstract class for items history? --- Candle.struct.h | 66 +++++++++++++++++++++++----- Indicator/IndicatorCandle.provider.h | 6 +++ Indicator/IndicatorTf.h | 44 ++++++++++++------- Storage/ItemsHistory.h | 54 +++++++++++++---------- 4 files changed, 119 insertions(+), 51 deletions(-) diff --git a/Candle.struct.h b/Candle.struct.h index c18565e7c..5d920aff7 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -223,16 +223,26 @@ struct CandleOHLC template struct CandleOCTOHLC : CandleOHLC { bool is_complete; + + // Timestamp of where the candle is placed on the chart. + int start_time; + + // Length of the candle in seconds. + int length; + + // Open and close timestamps of ticks that were part of this candle. long open_timestamp_ms, close_timestamp_ms; // 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_ms = -1, - long _close_timestamp_ms = -1, int _volume = 0) + CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, int _start_time = -1, int _length = 0, + long _open_timestamp_ms = -1, long _close_timestamp_ms = -1, int _volume = 0) : CandleOHLC(_open, _high, _low, _close), is_complete(true), + start_time(_start_time), + length(_length), open_timestamp_ms(_open_timestamp_ms), close_timestamp_ms(_close_timestamp_ms), volume(_volume) { @@ -241,7 +251,22 @@ struct CandleOCTOHLC : CandleOHLC { } } - // Updates OHLC values taking into consideration tick's timestamp. + /** + * Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price. + */ + void Init(int _start_time, int _length, long _timestamp_ms, T _price) { + is_complete = false; + start_time = _start_time; + length = _length; + open_timestamp_ms = _timestamp_ms; + close_timestamp_ms = _timestamp_ms; + volume = 1; + open = high = low = close = _price; + } + + /** + * Updates OHLC values taking into consideration tick's timestamp. + */ void Update(long _timestamp_ms, T _price) { bool _is_init = open_timestamp_ms == -1; @@ -265,22 +290,39 @@ struct CandleOCTOHLC : CandleOHLC { ++volume; } - // Method used by ItemsHistory; - long GetTimeMs() { return open_timestamp_ms; } + /** + * Method used by ItemsHistory; + */ + long GetTimeMs() { return start_time * 1000; } - // Method used by ItemsHistory; - datetime GetTime() { return (datetime)(open_timestamp_ms / 1000); } + /** + * Method used by ItemsHistory; + */ + datetime GetTime() { return (datetime)start_time; } - // Returns timestamp of open price. + /** + * Returns timestamp of open price. + */ long GetOpenTimestamp() { return open_timestamp_ms / 1000; } - // Returns timestamp of close price. + /** + * Returns timestamp of close price. + */ long GetCloseTimestamp() { return close_timestamp_ms / 1000; } + /** + * Whether given time fits in the candle. + */ + bool ContainsTimeMs(long _time_ms) { + return _time_ms >= (start_time * 1000) && _time_ms < (start_time + length) * 1000; + } + // Serializers. SerializerNodeType Serialize(Serializer &s); - // Returns text representation of candle. + /** + * Returns text representation of candle. + */ string ToString() { return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", open, high, low, close, is_complete ? "Complete" : "Incomplete", @@ -289,7 +331,9 @@ struct CandleOCTOHLC : CandleOHLC { } }; -/* Structore for storing OHLC values with timestamp. */ +/** + * Structure for storing OHLC values with timestamp. + */ template struct CandleTOHLC : CandleOHLC { datetime time; diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index 20b4b1315..8ab6f213d 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -39,6 +39,12 @@ template class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider> { public: + /** + * Constructor. + */ + ItemsHistoryCandleProvider(ItemsHistory, ItemsHistoryItemProvider>>* _history) + : ItemsHistoryItemProvider(_history) {} + /** * Called when new tick was emitted from IndicatorTick-based source. */ diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 947e53142..de7fe44af 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -39,7 +39,15 @@ */ template class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { + // Seconds per candle. + int spc; + public: + /** + * Constructor. + */ + ItemsHistoryTfCandleProvider(int _spc) : ItemsHistoryCandleProvider(), spc(_spc) {} + /** * Called when new tick was emitted from IndicatorTick-based source. */ @@ -47,9 +55,6 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { Print("IndicatorTf's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | TIME_SECONDS), ", ", _ask, ", ", _bid); - // Index of the candle we will be updating/creating. - int _candle_index = GetCandleIndexFromTimeMs(_time_ms); - // We know that tick's timestamp will be ahead of the last tick and thus // inside or ahead of the last created candle. In order to retrieve last // valid candle, we need to use ItemsHistory::GetItemByShift(0) to check if @@ -60,28 +65,32 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { // call it, because some of the previous actions may have removed some of // the recent candles. Note that OnTick() advances its _time_ms in // ascending order, so all we need to most recent history. + // + // Note that EnsureShiftExists() may return false when there never been any + // candle added. GetHistory() PTR_DEREF EnsureShiftExists(0); - if (GetHistory() PTR_DEREF TryGetItemByIndex(_candle_index, _candle)) { - // There is a candle at given time. Updating it. + if (GetHistory() PTR_DEREF TryGetItemByShift(0, _candle) && _candle.ContainsTimeMs(_time_ms)) { + // Time given fits in the last added candle's time-frame, updating the candle with given price. _candle.Update(_time_ms, _bid); // Storing candle in the history. - GetHistory() PTR_DEREF Update(_candle, _candle_index); + GetHistory() PTR_DEREF Update(_candle, GetHistory() PTR_DEREF GetShiftIndex(0)); } else { - // There is no such candle. Adding new one. - _candle.Update(_time_ms, _bid); + // Either there is no candle at shift 0 or given time doesn't fit in the #0 candle's time-frame. + _candle.Init(GetCandleTimeFromTimeMs(_time_ms, spc), spc, _time_ms, _bid); - // Adding candle as the most recent item in the history. + // Adding candle as the most recent item in the history. It will now become the candle at shift 0. GetHistory() PTR_DEREF Append(_candle); } } /** - * Determines index of the candle for the ItemsHistory from given time in - * milliseconds. + * Returns start time of the candle (the place it's on the chart) for the given tick's time in milliseconds. */ - int GetCandleIndexFromTimeMs(long _time_ms) {} + int GetCandleTimeFromTimeMs(long _time_ms, int _length_in_secs) { + return (int)((_time_ms - _time_ms % (_length_in_secs * 1000)) / 1000); + } /** * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we @@ -91,6 +100,7 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { ARRAY_REF(CandleOCTOHLC, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. if (_sel == ITEMS_HISTORY_SELECTOR_INDEX) { + DebugBreak(); } else if (_sel == ITEMS_HISTORY_SELECTOR_TIME_MS) { Print("Error: Candles are indexed by their index (integer) and thus we can't work with time indices!"); DebugBreak(); @@ -122,7 +132,7 @@ class IndicatorTf : public IndicatorCandle { /** * Class constructor with timeframe enum. */ - IndicatorTf(unsigned int _spc) : IndicatorCandle(new ItemsHistoryTfCandleProvider()) { + IndicatorTf(unsigned int _spc) : IndicatorCandle(new ItemsHistoryTfCandleProvider(_spc)) { iparams.SetSecsPerCandle(_spc); Init(); } @@ -131,7 +141,7 @@ class IndicatorTf : public IndicatorCandle { * Class constructor with timeframe enum. */ IndicatorTf(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) - : IndicatorCandle(new ItemsHistoryTfCandleProvider()) { + : IndicatorCandle(new ItemsHistoryTfCandleProvider(ChartTf::TfToSeconds(_tf))) { iparams.SetSecsPerCandle(ChartTf::TfToSeconds(_tf)); tf = _tf; Init(); @@ -141,7 +151,8 @@ class IndicatorTf : public IndicatorCandle { * Class constructor with timeframe index. */ IndicatorTf(ENUM_TIMEFRAMES_INDEX _tfi = 0) - : IndicatorCandle(new ItemsHistoryTfCandleProvider()) { + : IndicatorCandle( + new ItemsHistoryTfCandleProvider(ChartTf::TfToSeconds(ChartTf::IndexToTf(_tfi)))) { iparams.SetSecsPerCandle(ChartTf::TfToSeconds(ChartTf::IndexToTf(_tfi))); tf = ChartTf::IndexToTf(_tfi); Init(); @@ -151,7 +162,8 @@ class IndicatorTf : public IndicatorCandle { * Class constructor with parameters. */ IndicatorTf(TFP& _icparams, const IndicatorDataParams& _idparams) - : IndicatorCandle(_icparams, _idparams, new ItemsHistoryTfCandleProvider()) { + : IndicatorCandle(_icparams, _idparams, + new ItemsHistoryTfCandleProvider(_icparams.GetSecsPerCandle())) { Init(); } diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index 6b1ec43b5..aa022034e 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -237,47 +237,45 @@ class ItemsHistory { */ void Update(IV& _item, int _index) { if (!history.KeyExists(_index)) { - Print("Error: You may only update existing items! History doesn't contain item with index ", _index, ".") - DebugBreak(); + Print("Error: You may only update existing items! History doesn't contain item with index ", _index, "."); + DebugBreak(); } history.Set(_index, _item); } /** - * Returns item time in milliseconds for the given shift. + * Returns bar date and time for the given shift. */ - long GetItemTimeByShiftMsc(int _shift) { - if (!EnsureShiftExists(_shift)) { - // There won't be item at given shift. - return (datetime)0; + datetime GetItemTimeByShift(int _shift) { + if (history.Size() == 0) { } - return GetItemByShift(_shift).GetTimeMs(); + return (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); } - /** - * Returns bar date and time for the given shift. - */ - datetime GetItemTimeByShift(int _shift) { return (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); } - /** * Ensures */ bool EnsureShiftExists(int _shift) { + if (history.Size() == 0) { + return false; + } + int _index = GetShiftIndex(_shift); if (_index < first_valid_index) { RegenerateHistory(_index, first_valid_index - 1, ITEMS_HISTORY_DIRECTION_BACKWARD); } else if (_index > last_valid_index) { RegenerateHistory(last_valid_index + 1, _index, ITEMS_HISTORY_DIRECTION_FORWARD); } - return history.Size() > 0; + + return history.KeyExists(_index); } /** * Returns item at given index. Index must exist! */ IV GetItemByIndex(int _index) { - if (_index < first_valid_index || _index > last_valid_index) { + if (history.Size() == 0 || _index < first_valid_index || _index > last_valid_index) { Print("Error! Given index is outside the range of valid items!"); DebugBreak(); IV _default; @@ -290,7 +288,7 @@ class ItemsHistory { * Tries to get item at given index. */ bool TryGetItemByIndex(int _index, IV& _out_item) { - if (_index < first_valid_index || _index > last_valid_index) { + if (history.Size() == 0 || _index < first_valid_index || _index > last_valid_index) { return false; } _out_item = history.GetByKey(_index); @@ -305,15 +303,23 @@ class ItemsHistory { /** * Returns item at given shift. Shift must exist! */ - IV GetItemByShift(int _shift) { - int _index = GetShiftIndex(_shift); - if (_index < first_valid_index || _index > last_valid_index) { - Print("Error! Given shift is outside the range of valid items!"); - DebugBreak(); - IV _default; - return _default; + IV GetItemByShift(int _shift) { return GetItemByIndex(GetShiftIndex(_shift)); } + + /** + * Tries to get item at given shift. + */ + bool TryGetItemByShift(int _shift, IV& _out_item) { return TryGetItemByIndex(GetShiftIndex(_shift), _out_item); } + + /** + * Returns item time in milliseconds for the given shift. + */ + long GetItemTimeByShiftMsc(int _shift) { + if (!EnsureShiftExists(_shift)) { + // There won't be item at given shift. + return (datetime)0; } - return history.GetByKey(_index); + + return GetItemByShift(_shift).GetTimeMs(); } }; From cc29ec873e552f4ef4cb5abcfb5c99e7b62237c2 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 21 Sep 2022 18:02:46 +0200 Subject: [PATCH 025/123] WIP. Got rid of parent-child relationship between ItemsHistory and ItemsHistoryItemProvider. Now IndicatorsTest.mq5 is now compiling. Need to do some changes in ItemsHistory counters. --- Indicator/IndicatorCandle.h | 19 ++++++------ Indicator/IndicatorCandle.provider.h | 18 +++++++++-- Indicator/IndicatorTf.h | 37 ++++++++++------------ Storage/ItemsHistory.h | 46 ++++++++++------------------ 4 files changed, 56 insertions(+), 64 deletions(-) diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 21fcabc02..663f23045 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -64,11 +64,11 @@ enum ENUM_INDI_CANDLE_MODE { /** * Class to deal with candle indicators. */ -template +template class IndicatorCandle : public Indicator { protected: TickBarCounter counter; - ItemsHistory, ItemsHistoryCandleProvider> history; + ItemsHistory, TCP> history; protected: /* Protected methods */ @@ -90,14 +90,13 @@ class IndicatorCandle : public Indicator { /** * Class constructor. */ - IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, - ItemsHistoryCandleProvider* _candle_provider, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(_candle_provider) { + IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, + int _indi_mode = 0) + : Indicator(_icparams, _idparams, _indi_src, _indi_mode) { Init(); } - IndicatorCandle(ItemsHistoryCandleProvider* _candle_provider, ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, - int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name), history(_candle_provider) { + IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") + : Indicator(_itype, _shift, _name) { Init(); } @@ -113,7 +112,7 @@ class IndicatorCandle : public Indicator { /** * Returns buffer where candles are temporarily stored. */ - ItemsHistory, ItemsHistoryCandleProvider>* GetHistory() { return &history; } + ItemsHistory, TCP>* GetHistory() { return &history; } /** * Gets open price for a given, optional shift. @@ -307,7 +306,7 @@ class IndicatorCandle : public Indicator { // ask and bid price. As an abstract class, we really don't know how to // update/create candles so we just pass the entry into history's // ItemsHistoryCandleProvider and it will do all the job. - history.GetProvider() PTR_DEREF OnTick(entry.timestamp * 1000, (float)entry[0], (float)entry[1]); + history.GetItemProvider() PTR_DEREF OnTick(&history, entry.timestamp * 1000, (float)entry[0], (float)entry[1]); // @fixit Maybe we should generate some tick/bar change? // counter.OnTick(CalcCandleTimestamp(entry.timestamp)); diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index 8ab6f213d..792f27091 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -42,15 +42,27 @@ class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider, ItemsHistoryItemProvider>>* _history) - : ItemsHistoryItemProvider(_history) {} + ItemsHistoryCandleProvider() {} /** * Called when new tick was emitted from IndicatorTick-based source. */ - virtual void OnTick(long _timestamp_ms, float _ask, float _bid) { + virtual void OnTick(ItemsHistory, ItemsHistoryItemProvider>>* _history, + long _timestamp_ms, float _ask, float _bid) { // Should be overrided. } + + /** + * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we + * want previous or next items from selected starting point. + */ + void GetItems(ItemsHistory, ItemsHistoryCandleProvider>* _history, long _from, + ENUM_ITEMS_HISTORY_SELECTOR _sel, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, + ARRAY_REF(CandleOCTOHLC, _out_arr)) { + // Method is called if there is a missing item (candle) in the history. We need to regenerate it. + Print("Error: Retrieving items by this item provider is not implemented!"); + DebugBreak(); + } }; #endif diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index de7fe44af..fb02a1f20 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -46,12 +46,13 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { /** * Constructor. */ - ItemsHistoryTfCandleProvider(int _spc) : ItemsHistoryCandleProvider(), spc(_spc) {} + ItemsHistoryTfCandleProvider(int _spc) : spc(_spc) {} /** * Called when new tick was emitted from IndicatorTick-based source. */ - virtual void OnTick(long _time_ms, float _ask, float _bid) { + virtual void OnTick(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _time_ms, + float _ask, float _bid) { Print("IndicatorTf's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | TIME_SECONDS), ", ", _ask, ", ", _bid); @@ -68,20 +69,20 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { // // Note that EnsureShiftExists() may return false when there never been any // candle added. - GetHistory() PTR_DEREF EnsureShiftExists(0); + _history PTR_DEREF EnsureShiftExists(0); - if (GetHistory() PTR_DEREF TryGetItemByShift(0, _candle) && _candle.ContainsTimeMs(_time_ms)) { + if (_history PTR_DEREF TryGetItemByShift(0, _candle) && _candle.ContainsTimeMs(_time_ms)) { // Time given fits in the last added candle's time-frame, updating the candle with given price. _candle.Update(_time_ms, _bid); // Storing candle in the history. - GetHistory() PTR_DEREF Update(_candle, GetHistory() PTR_DEREF GetShiftIndex(0)); + _history PTR_DEREF Update(_candle, _history PTR_DEREF GetShiftIndex(0)); } else { // Either there is no candle at shift 0 or given time doesn't fit in the #0 candle's time-frame. _candle.Init(GetCandleTimeFromTimeMs(_time_ms, spc), spc, _time_ms, _bid); // Adding candle as the most recent item in the history. It will now become the candle at shift 0. - GetHistory() PTR_DEREF Append(_candle); + _history PTR_DEREF Append(_candle); } } @@ -96,8 +97,9 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we * want previous or next items from selected starting point. */ - virtual void GetItems(long _from, ENUM_ITEMS_HISTORY_SELECTOR _sel, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, - ARRAY_REF(CandleOCTOHLC, _out_arr)) { + void GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _from, + ENUM_ITEMS_HISTORY_SELECTOR _sel, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, + ARRAY_REF(CandleOCTOHLC, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. if (_sel == ITEMS_HISTORY_SELECTOR_INDEX) { DebugBreak(); @@ -112,7 +114,7 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { * Class to deal with candle indicators. */ template -class IndicatorTf : public IndicatorCandle { +class IndicatorTf : public IndicatorCandle> { protected: // Time-frame used to create candles. ENUM_TIMEFRAMES tf; @@ -124,7 +126,7 @@ class IndicatorTf : public IndicatorCandle { * * Called on constructor. */ - void Init() {} + void Init() { history.SetItemProvider(new ItemsHistoryTfCandleProvider(iparams.GetSecsPerCandle())); } public: /* Special methods */ @@ -132,7 +134,7 @@ class IndicatorTf : public IndicatorCandle { /** * Class constructor with timeframe enum. */ - IndicatorTf(unsigned int _spc) : IndicatorCandle(new ItemsHistoryTfCandleProvider(_spc)) { + IndicatorTf(unsigned int _spc) { iparams.SetSecsPerCandle(_spc); Init(); } @@ -140,8 +142,7 @@ class IndicatorTf : public IndicatorCandle { /** * Class constructor with timeframe enum. */ - IndicatorTf(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) - : IndicatorCandle(new ItemsHistoryTfCandleProvider(ChartTf::TfToSeconds(_tf))) { + IndicatorTf(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { iparams.SetSecsPerCandle(ChartTf::TfToSeconds(_tf)); tf = _tf; Init(); @@ -150,9 +151,7 @@ class IndicatorTf : public IndicatorCandle { /** * Class constructor with timeframe index. */ - IndicatorTf(ENUM_TIMEFRAMES_INDEX _tfi = 0) - : IndicatorCandle( - new ItemsHistoryTfCandleProvider(ChartTf::TfToSeconds(ChartTf::IndexToTf(_tfi)))) { + IndicatorTf(ENUM_TIMEFRAMES_INDEX _tfi = 0) { iparams.SetSecsPerCandle(ChartTf::TfToSeconds(ChartTf::IndexToTf(_tfi))); tf = ChartTf::IndexToTf(_tfi); Init(); @@ -161,11 +160,7 @@ class IndicatorTf : public IndicatorCandle { /** * Class constructor with parameters. */ - IndicatorTf(TFP& _icparams, const IndicatorDataParams& _idparams) - : IndicatorCandle(_icparams, _idparams, - new ItemsHistoryTfCandleProvider(_icparams.GetSecsPerCandle())) { - Init(); - } + IndicatorTf(TFP& _icparams, const IndicatorDataParams& _idparams) { Init(); } /** * Gets indicator's time-frame. diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index aa022034e..85794b943 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -53,37 +53,22 @@ class ItemsHistory; */ template class ItemsHistoryItemProvider : public Dynamic { - ItemsHistory>* history; - public: /** * Constructor. */ - ItemsHistoryItemProvider(ItemsHistory>* _history) : history(_history) {} + ItemsHistoryItemProvider() {} /** * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we * want previous or next items from selected starting point. */ - virtual void GetItems(long _from, ENUM_ITEMS_HISTORY_SELECTOR _sel, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, - ARRAY_REF(IV, _out_arr)) { - Print( - "Error: Retrieving items from a given date and time is not supported by this historic items provides. Please " - "use GetItems(int _from_index) version!"); + void GetItems(ItemsHistory>* _history, long _from, ENUM_ITEMS_HISTORY_SELECTOR _sel, + ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(IV, _out_arr)) { + // Method is called if there is a missing item (candle) in the history. We need to regenerate it. + Print("Error: Retrieving items by this item provider is not implemented!"); DebugBreak(); } - - /** - * Helper method to retrieve items up to item with "_to_ms" date and time. - */ - void GetItems(long _from, ENUM_ITEMS_HISTORY_SELECTOR _sel, datetime _to_ms, ARRAY_REF(IV, _out_arr)) { - // @todo. - } - - /** - * Returns pointer to items history this item providers works for. - */ - ItemsHistory>* GetHistory() { return history; } }; /** @@ -134,18 +119,18 @@ class ItemsHistory { /** * Constructor */ - ItemsHistory(PT* _item_provider) - : item_provider(_item_provider), - current_index(0), - first_valid_index(0), - first_valid_index_ever(0), - last_valid_index(0), - peak_size(0) {} + ItemsHistory() + : current_index(0), first_valid_index(0), first_valid_index_ever(0), last_valid_index(0), peak_size(0) {} /** * Returns item provider. */ - PT* GetProvider() { return item_provider.Ptr(); } + PT* GetItemProvider() { return item_provider.Ptr(); } + + /** + * Sets item provider. + */ + void SetItemProvider(PT* _item_provider) { item_provider = _item_provider; } /** * Gets time in milliseconds of the last(oldest) item's time in current history time or 0. @@ -167,12 +152,13 @@ class ItemsHistory { */ void RegenerateHistory(int _from_index, int _to_index, ENUM_ITEMS_HISTORY_DIRECTION _dir) { static ARRAY(IV, _items); // Items generated by provider. - ArrayResize(_items, 0); int _item_count = _to_index - _from_index + 1; - item_provider REF_DEREF GetItems(_from_index, ITEMS_HISTORY_SELECTOR_INDEX, _dir, _item_count, _items); + // PT x(5); + + item_provider REF_DEREF GetItems(THIS_PTR, _from_index, ITEMS_HISTORY_SELECTOR_INDEX, _dir, _item_count, _items); for (int i = 0; i < _item_count; ++i) { if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { From 1b54b0c7590e3eac04cd5cc06aa0798e4059e7cc Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 26 Sep 2022 20:12:09 +0200 Subject: [PATCH 026/123] WIP. ItemsHistory and IndicatorTf now properly stores candles' history. Now it's time to make GetItems() for IndicatorTf in order to regenerate candles! --- Bar.struct.h | 7 +- Candle.struct.h | 7 +- Indicator/IndicatorCandle.h | 49 +++++++++---- Indicator/IndicatorTf.h | 36 ++++++++-- Storage/ItemsHistory.h | 121 ++++++++++++++++++++++++--------- Storage/tests/ItemsHistory.mq5 | 46 +++++++++---- 6 files changed, 200 insertions(+), 66 deletions(-) diff --git a/Bar.struct.h b/Bar.struct.h index dffae6ba2..5d0f18255 100644 --- a/Bar.struct.h +++ b/Bar.struct.h @@ -38,9 +38,9 @@ class Serializer; #include "Chart.enum.h" #include "Serializer/Serializable.h" #include "Serializer/Serializer.enum.h" +#include "Serializer/Serializer.h" #include "Serializer/SerializerNode.enum.h" #include "Std.h" -#include "Serializer/Serializer.h" /* Struct for storing OHLC values. */ struct BarOHLC @@ -229,6 +229,11 @@ struct BarOHLC SerializerNodeType Serialize(Serializer &s); // Converters. string ToCSV() { return StringFormat("%d,%g,%g,%g,%g", time, open, high, low, close); } + // Operators. + bool operator==(const BarOHLC &_r) { + return time == _r.time && open == _r.time && high == _r.high && low == _r.low && close == _r.close; + } + bool operator!=(const BarOHLC &_r) { return !(THIS_REF == _r); } }; /* Method to serialize BarOHLC structure. */ diff --git a/Candle.struct.h b/Candle.struct.h index 5d920aff7..e5132bf7e 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -268,6 +268,11 @@ struct CandleOCTOHLC : CandleOHLC { * Updates OHLC values taking into consideration tick's timestamp. */ void Update(long _timestamp_ms, T _price) { + if (!ContainsTimeMs(_timestamp_ms)) { + Print("Error: Cannot update candle. Given time doesn't fit in candle's time-frame!"); + DebugBreak(); + } + bool _is_init = open_timestamp_ms == -1; if (_is_init || _timestamp_ms < open_timestamp_ms) { @@ -314,7 +319,7 @@ struct CandleOCTOHLC : CandleOHLC { * Whether given time fits in the candle. */ bool ContainsTimeMs(long _time_ms) { - return _time_ms >= (start_time * 1000) && _time_ms < (start_time + length) * 1000; + return _time_ms >= (long)start_time * 1000 && _time_ms < (long)(start_time + length) * 1000; } // Serializers. diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 663f23045..a5e0502e2 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -44,6 +44,10 @@ #include "IndicatorData.h" #include "TickBarCounter.h" +#ifndef INDI_CANDLE_HISTORY_SIZE +#define INDI_CANDLE_HISTORY_SIZE 86400 +#endif + // Indicator modes. enum ENUM_INDI_CANDLE_MODE { INDI_CANDLE_MODE_PRICE_OPEN, @@ -92,11 +96,11 @@ class IndicatorCandle : public Indicator { */ IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_icparams, _idparams, _indi_src, _indi_mode) { + : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(INDI_CANDLE_HISTORY_SIZE) { Init(); } IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name) { + : Indicator(_itype, _shift, _name), history(INDI_CANDLE_HISTORY_SIZE) { Init(); } @@ -140,24 +144,38 @@ class IndicatorCandle : public Indicator { 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). + * Returns current bar index. */ - int GetBarIndex() override { return counter.GetBarIndex(); } + int GetBarIndex() override { return history.GetCurrentIndex(); } /** * Returns the number of bars on the chart. */ - int GetBars() override { return (int)history.PeakSize(); } + int GetBars() override { + // Will return total number of bars prepended and appended to the history, + // even if those bars were cleaned up because of history's candle limit. + return (int)history.GetPeakSize(); + } /** * Returns current tick index (incremented every OnTick()). */ - int GetTickIndex() override { return counter.GetTickIndex(); } + int GetTickIndex() override { return GetTick() PTR_DEREF GetTickIndex(); } /** * Check if there is a new bar to parse. */ - bool IsNewBar() override { return counter.is_new_bar; } + bool IsNewBar() override { + CandleOCTOHLC _candle; + // We check if last bar has volume 1. If yes, that would mean that new candle was created with a single tick. In + // consecutive ticks the volume will be incremented. + if (history.TryGetItemByShift(0, _candle, false)) { + return _candle.volume == 1; + } + + // No candles means no new bar. + return false; + } /* Virtual method implementations */ @@ -180,14 +198,12 @@ class IndicatorCandle : public Indicator { */ BarOHLC GetOHLC(int _shift = 0) override { BarOHLC _bar; + CandleOCTOHLC _candle; - if (!history.EnsureShiftExists(_shift)) { - // There's no candle fort that shift. - return _bar; + if (history.TryGetItemByShift(_shift, _candle)) { + _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.open_timestamp_ms); } - CandleOCTOHLC _candle = history.GetItemByShift(_shift); - _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.open_timestamp_ms); return _bar; } @@ -197,8 +213,13 @@ class IndicatorCandle : public Indicator { * If local history is empty (not loaded), function returns 0. */ long GetVolume(int _shift = 0) override { - CandleOCTOHLC candle = history.GetItemByShift(_shift); - return candle.volume; + CandleOCTOHLC _candle; + + if (history.TryGetItemByShift(_shift, _candle)) { + return _candle.volume; + } + + return 0; } /** diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index fb02a1f20..189a2e8e1 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -42,19 +42,26 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { // Seconds per candle. int spc; + // Current tick index. Effectively a number of ticks generated by attached + // IndicatorTick. + int tick_index; + public: /** * Constructor. */ - ItemsHistoryTfCandleProvider(int _spc) : spc(_spc) {} + ItemsHistoryTfCandleProvider(int _spc) : spc(_spc), tick_index(0) {} /** * Called when new tick was emitted from IndicatorTick-based source. */ virtual void OnTick(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _time_ms, float _ask, float _bid) { - Print("IndicatorTf's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | TIME_SECONDS), - ", ", _ask, ", ", _bid); + ++tick_index; + + // Print("IndicatorTf's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | + // TIME_SECONDS), + // ", ", _ask, ", ", _bid); // We know that tick's timestamp will be ahead of the last tick and thus // inside or ahead of the last created candle. In order to retrieve last @@ -71,13 +78,23 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { // candle added. _history PTR_DEREF EnsureShiftExists(0); - if (_history PTR_DEREF TryGetItemByShift(0, _candle) && _candle.ContainsTimeMs(_time_ms)) { + if (_history PTR_DEREF TryGetItemByShift(0, _candle, false) && _candle.ContainsTimeMs(_time_ms)) { // Time given fits in the last added candle's time-frame, updating the candle with given price. _candle.Update(_time_ms, _bid); // Storing candle in the history. _history PTR_DEREF Update(_candle, _history PTR_DEREF GetShiftIndex(0)); } else { + CandleOCTOHLC _candle_tmp; + + // We don't want to regenerate history, because at the start there will bo no candle however. + if (_history PTR_DEREF TryGetItemByShift(0, _candle_tmp, false)) { + Print("Completed candle: ", _candle_tmp.ToString()); + Print("Real candle: ", iOpen(NULL, Period(), 1), " ", iHigh(NULL, Period(), 1), " ", + iLow(NULL, Period(), 1), " ", ChartStatic::iClose(NULL, (ENUM_TIMEFRAMES)Period(), 1)); + Print("--"); + } + // Either there is no candle at shift 0 or given time doesn't fit in the #0 candle's time-frame. _candle.Init(GetCandleTimeFromTimeMs(_time_ms, spc), spc, _time_ms, _bid); @@ -86,6 +103,12 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { } } + /** + * Returns current tick index. Effectively a number of ticks generated by + * attached IndicatorTick. + */ + int GetTickIndex() { return tick_index; } + /** * Returns start time of the candle (the place it's on the chart) for the given tick's time in milliseconds. */ @@ -166,6 +189,11 @@ class IndicatorTf : public IndicatorCandle= history_max_size) { - // We need to remove first item from the history (the oldest one). - history.Unset(first_valid_index++); - } + if (peak_size > 0) { + // There was at least one prepended/appended item, so indices relates to existing items. + if (history_max_size != 0 && history.Size() >= history_max_size) { + // We need to remove first item from the history (the oldest one). + Print("Removing item #", first_valid_index, " from the history."); + history.Unset(first_valid_index++); + } - if (_allow_regenerate && last_valid_index < current_index) { - // May call Append() multiple times with regenerated items. - RegenerateHistory(last_valid_index, current_index, ITEMS_HISTORY_DIRECTION_BACKWARD); - } + if (_allow_regenerate && last_valid_index < current_index) { + // May call Append() multiple times with regenerated items. + RegenerateHistory(last_valid_index, current_index, ITEMS_HISTORY_DIRECTION_BACKWARD); - // Adding item in the future of all the history and making it the current one. - history.Set(++current_index, _item); + // @todo Check if history was fully regenerated. + } + + // Incrementing current index and setting last valid index to the same value. + last_valid_index = ++current_index; + } - ++last_valid_index; + // Adding item to the newly set index or index 0. + history.Set(current_index, _item); // if peak_size == 0 then current_index = 0. peak_size = MathMax(peak_size, history.Size()); } @@ -199,18 +218,35 @@ class ItemsHistory { * If shift is lower than last_valid_shift then we need to regenerate history between last_valid_shift and shift. */ void Prepend(IV& _item, bool _allow_regenerate = true) { - if (history_max_size != 0 && history.Size() >= history_max_size) { - // We need to remove last item from the history (the newest one). - history.Unset(last_valid_index--); - } + if (peak_size > 0) { + // There was at least one prepended/appended item, so indices relates to existing items. + if (history_max_size != 0 && history.Size() >= history_max_size) { + // We need to remove last item from the history (the newest one). + Print("Removing item #", last_valid_index, " from the history."); + history.Unset(last_valid_index--); + } + + if (_allow_regenerate && first_valid_index_ever < current_index) { + // May call Prepend() multiple times with regenerated items. + RegenerateHistory(first_valid_index, current_index, ITEMS_HISTORY_DIRECTION_FORWARD); - if (_allow_regenerate && first_valid_index_ever < current_index) { - // May call Prepend() multiple times with regenerated items. - RegenerateHistory(first_valid_index, current_index, ITEMS_HISTORY_DIRECTION_FORWARD); + // @todo Check if history was fully regenerated. + } + + // last_valid_index stays on its own, because it is not a first item to be added to the history. + --first_valid_index; + } else { + // It is a first item to be prepended. last_valid_index will be now + // negative. That means we don't have information about item at + // index/shift 0. In order to retrieve item at index/shift 0 the history + // must be regenerated from last_valid_index (not inclusive) to index 0. + // Effectively, we would just need to regenerate item at index 0. + // current_index will stay at index 0. + last_valid_index = --first_valid_index; // last_valid_index = -1. } - // Adding item at the beginning of all the history and expanding history by one item in the past. - history.Set(first_valid_index--, _item); + // Adding item to the newly set index. + history.Set(first_valid_index, _item); // Saving index of the most old item in the history ever added. first_valid_index_ever = MathMin(first_valid_index_ever, first_valid_index); @@ -234,6 +270,9 @@ class ItemsHistory { */ datetime GetItemTimeByShift(int _shift) { if (history.Size() == 0) { + // What to do? Maybe just return 0? + DebugBreak(); + return 0; } return (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); @@ -260,27 +299,41 @@ class ItemsHistory { /** * Returns item at given index. Index must exist! */ - IV GetItemByIndex(int _index) { - if (history.Size() == 0 || _index < first_valid_index || _index > last_valid_index) { + IV GetItemByIndex(int _index, bool _try_regenerate = true) { + IV _item; + if (!TryGetItemByIndex(_index, _item, _try_regenerate)) { Print("Error! Given index is outside the range of valid items!"); DebugBreak(); - IV _default; - return _default; } - return history.GetByKey(_index); + return _item; } /** * Tries to get item at given index. */ - bool TryGetItemByIndex(int _index, IV& _out_item) { + bool TryGetItemByIndex(int _index, IV& _out_item, bool _try_regenerate = true) { if (history.Size() == 0 || _index < first_valid_index || _index > last_valid_index) { - return false; + if (!_try_regenerate) { + return false; + } + // Whether we need to prepend old items or append new ones. + ENUM_ITEMS_HISTORY_DIRECTION _dir = + _index < first_valid_index ? ITEMS_HISTORY_DIRECTION_BACKWARD : ITEMS_HISTORY_DIRECTION_FORWARD; + RegenerateHistory(_index < first_valid_index ? _index : last_valid_index, + _index > last_valid_index ? _index : last_valid_index, _dir); + // Trying to get item again, but without regeneration at this time. + return TryGetItemByIndex(_index, _out_item, false); } _out_item = history.GetByKey(_index); return true; } + /** + * Returns index of the current item. 0 if there were no items added or there + * is a single item. + */ + int GetCurrentIndex() { return current_index; } + /** * Returns history index from the given shift. */ @@ -289,12 +342,16 @@ class ItemsHistory { /** * Returns item at given shift. Shift must exist! */ - IV GetItemByShift(int _shift) { return GetItemByIndex(GetShiftIndex(_shift)); } + IV GetItemByShift(int _shift, bool _try_regenerate = true) { + return GetItemByIndex(GetShiftIndex(_shift), _try_regenerate); + } /** * Tries to get item at given shift. */ - bool TryGetItemByShift(int _shift, IV& _out_item) { return TryGetItemByIndex(GetShiftIndex(_shift), _out_item); } + bool TryGetItemByShift(int _shift, IV& _out_item, bool _try_regenerate = true) { + return TryGetItemByIndex(GetShiftIndex(_shift), _out_item, _try_regenerate); + } /** * Returns item time in milliseconds for the given shift. diff --git a/Storage/tests/ItemsHistory.mq5 b/Storage/tests/ItemsHistory.mq5 index 1e289adba..968093d99 100644 --- a/Storage/tests/ItemsHistory.mq5 +++ b/Storage/tests/ItemsHistory.mq5 @@ -24,22 +24,16 @@ * Test functionality of ItemsHistory class. */ +// Defines +#define INDI_CANDLE_HISTORY_SIZE 4 + // Includes #include "../../Platform.h" #include "../../Test.mqh" #include "../ItemsHistory.h" -struct TestItem { - int value; - - // Method used by ItemsHistory; - long GetTimeMs() { return 0; } - - // Method used by ItemsHistory; - datetime GetTime() { return (datetime)0; } -}; - -class ItemsHistoryTestItemProvider : public ItemsHistoryItemProvider {}; +// Candles buffer. +ARRAY(BarOHLC, _ohlcs); /** * Implements OnInit(). @@ -47,15 +41,39 @@ class ItemsHistoryTestItemProvider : public ItemsHistoryItemProvider { int OnInit() { Platform::Init(); - ItemsHistory items(new ItemsHistoryTestItemProvider()); - return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED); }; /** * Implements OnTick(). */ -void OnTick() { Platform::Tick(); } +void OnTick() { + Platform::Tick(); + + IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); + + if (_candles PTR_DEREF IsNewBar()) { + BarOHLC _ohlc = _candles PTR_DEREF GetOHLC(0); + ArrayPushObject(_ohlcs, _ohlc); + + Print(_ohlc.ToCSV()); + + if (_candles PTR_DEREF GetBarIndex() == INDI_CANDLE_HISTORY_SIZE) { + // Now first candle should be forgotten by candle history. We'll check if candle regeneration works. + Print("First candle was: ", _ohlcs[0].ToCSV()); + + BarOHLC _ohlc_regenerated = _candles PTR_DEREF GetOHLC(INDI_CANDLE_HISTORY_SIZE); + Print("Regenerated candle is: ", _ohlc_regenerated.ToCSV()); + + if (_ohlcs[0] != _ohlc_regenerated) { + Print("Error: Candle regeneration resulted in OHLC/time difference!"); + Print("Expected: ", _ohlcs[0].ToCSV()); + Print("Got: ", _ohlc_regenerated.ToCSV()); + ExpertRemove(); + } + } + } +} /** * Implements OnDeinit(). From 3bddda8ab3e76e9eb918dc7bfb0f1c5b1a1dc8a6 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 27 Sep 2022 18:20:39 +0200 Subject: [PATCH 027/123] Should fix problem "'array' - constant variable cannot be passed as reference" in Array.mqh. --- Array.mqh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Array.mqh b/Array.mqh index 65d8c529a..2a0c6094e 100644 --- a/Array.mqh +++ b/Array.mqh @@ -753,7 +753,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { * - https://www.mql5.com/en/docs/array/arraysize */ template - static int ArraySize(const ARRAY_REF(X, array)) { + static int ArraySize(ARRAY_REF(X, array)) { return ::ArraySize(array); } @@ -772,7 +772,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { template void ArrayPush(ARRAY_REF(X, array), X value) { - ArrayResize(ArraySize(array) + 1); + ArrayResize(Array::ArraySize(array) + 1); array[ArraySize(array) - 1] = value; } template From 477e69a57c6b1b2804540bb70433d0aefc9463f8 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 29 Sep 2022 19:05:50 +0200 Subject: [PATCH 028/123] WIP. Almost working candle regeneration for IndicatorTf. There are differences in OHLC values in regenerated candles. --- Candle.struct.h | 11 ++- Indicator/IndicatorCandle.h | 2 +- Indicator/IndicatorCandle.provider.h | 5 +- Indicator/IndicatorData.h | 22 ++++-- Indicator/IndicatorTf.h | 62 ++++++++++++--- Indicator/IndicatorTick.h | 9 +++ Indicators/Tick/Indi_TickMt.mqh | 110 +++------------------------ Platform.h | 5 +- Storage/ItemsHistory.h | 49 +++++++++--- Tick/Tick.struct.h | 6 +- 10 files changed, 146 insertions(+), 135 deletions(-) diff --git a/Candle.struct.h b/Candle.struct.h index e5132bf7e..dfc6c1623 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -254,13 +254,13 @@ struct CandleOCTOHLC : CandleOHLC { /** * Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price. */ - void Init(int _start_time, int _length, long _timestamp_ms, T _price) { + void Init(int _start_time, int _length, long _timestamp_ms = -1, T _price = 0) { is_complete = false; start_time = _start_time; length = _length; open_timestamp_ms = _timestamp_ms; close_timestamp_ms = _timestamp_ms; - volume = 1; + volume = _price != 0 ? 1 : 0; open = high = low = close = _price; } @@ -298,11 +298,16 @@ struct CandleOCTOHLC : CandleOHLC { /** * Method used by ItemsHistory; */ - long GetTimeMs() { return start_time * 1000; } + long GetTimeMs() { return (long)start_time * 1000; } /** * Method used by ItemsHistory; */ + long GetLengthMs() { return (long)length * 1000; } + + /** + * Returns candle's start time. + */ datetime GetTime() { return (datetime)start_time; } /** diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index a5e0502e2..cf9218e3b 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -201,7 +201,7 @@ class IndicatorCandle : public Indicator { CandleOCTOHLC _candle; if (history.TryGetItemByShift(_shift, _candle)) { - _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.open_timestamp_ms); + _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.start_time); } return _bar; diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index 792f27091..e3319bc3c 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -56,9 +56,8 @@ class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider, ItemsHistoryCandleProvider>* _history, long _from, - ENUM_ITEMS_HISTORY_SELECTOR _sel, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, - ARRAY_REF(CandleOCTOHLC, _out_arr)) { + void GetItems(ItemsHistory, ItemsHistoryCandleProvider>* _history, long _from_time_ms, + ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. Print("Error: Retrieving items by this item provider is not implemented!"); DebugBreak(); diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 4da9fceac..2219371af 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -56,10 +56,11 @@ class IndicatorData : public IndicatorBase { // Class variables. 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. - int last_tick_index; // Index of the last tick. + 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. + int last_tick_index; // Index of the last tick. + long first_tick_time_ms; // Time of the first ask/bid tick. void* mydata; ENUM_INDI_VS_TYPE retarget_ap_av; // Value storage type to be used as applied price/volume. ARRAY(Ref, value_storages); @@ -209,6 +210,12 @@ class IndicatorData : public IndicatorBase { */ int GetFlags() { return flags; } + /** + * Returns time of the first ask/bid tick (time of first global OnTick()). + * Time is compatible with time generated by IndicatorTick, e.g., Indi_TickMt. + */ + long GetFirstTickTimeMs() { return first_tick_time_ms; } + /** * Get full name of the indicator (with "over ..." part). */ @@ -890,6 +897,11 @@ class IndicatorData : public IndicatorBase { return; } + if (_global_tick_index == 0) { + // Time of the first tick must be compatible with time generated by IndicatorTick, e.g., Indi_TickMt. + first_tick_time_ms = TimeCurrent() * 1000; + } + last_tick_index = _global_tick_index; // Checking and potentially initializing new data source. @@ -1440,7 +1452,7 @@ class IndicatorData : public IndicatorBase { /** * Fetches historic ticks for a given range and emits these ticks. Used to regenerate candles. */ - virtual void FetchHistory(long _range_from, long _range_to) {} + virtual bool FetchHistory(long _range_from, long _range_to, ARRAY_REF(TickTAB, _out_ticks)) { return false; } /** * Returns value storage of given kind. diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 189a2e8e1..f8baba3ca 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -42,6 +42,9 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { // Seconds per candle. int spc; + // Pointer to IndicatorTf. Used to fetch data from IndicatorTick in the hierarchy. + IndicatorData* indi; + // Current tick index. Effectively a number of ticks generated by attached // IndicatorTick. int tick_index; @@ -50,7 +53,7 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { /** * Constructor. */ - ItemsHistoryTfCandleProvider(int _spc) : spc(_spc), tick_index(0) {} + ItemsHistoryTfCandleProvider(int _spc, IndicatorData* _indi_tf) : spc(_spc), indi(_indi_tf), tick_index(0) {} /** * Called when new tick was emitted from IndicatorTick-based source. @@ -120,14 +123,53 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we * want previous or next items from selected starting point. */ - void GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _from, - ENUM_ITEMS_HISTORY_SELECTOR _sel, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, - ARRAY_REF(CandleOCTOHLC, _out_arr)) { + void GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _from_time_ms, + ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. - if (_sel == ITEMS_HISTORY_SELECTOR_INDEX) { - DebugBreak(); - } else if (_sel == ITEMS_HISTORY_SELECTOR_TIME_MS) { - Print("Error: Candles are indexed by their index (integer) and thus we can't work with time indices!"); + if (_from_time_ms != 0) { + // In order to (re)generate candle, we need to fetch ticks within a fixed time-frame and then update that candle + // with all fetched ticks. For IndicatorTf, there is no difference between (re)generating backwards or forwards, + // as candles are time-framed. The only problem is that there may be missing candles in fetched time-frames. We + // just need to skip such time-frame and fetch ticks for next time-frame. In order to determine + + IndicatorData* _indi_tick = indi PTR_DEREF GetTick(); + + // Ticks to form a candle. + static ARRAY(TickTAB, _ticks); + + while (_num_items > 0) { + // Calculating time from which and to which we want to retrieve ticks to form a candle. + int _ticks_from_s = GetCandleTimeFromTimeMs(_from_time_ms, spc); + long _ticks_from_ms = (long)_ticks_from_s * 1000; + long _candle_length_ms = (long)spc * 1000; + long _ticks_to_ms = _ticks_from_ms + _candle_length_ms - 1; + + if (!_indi_tick PTR_DEREF FetchHistory(_ticks_from_ms, _ticks_to_ms, _ticks)) { + // There is no more ticks in the history, giving up. + break; + } + + if (ArraySize(_ticks) > 0) { + // Forming a candle. + CandleOCTOHLC _candle; + _candle.Init(_ticks_from_s, spc); + for (int i = 0; i < ArraySize(_ticks); ++i) { + _candle.Update(_ticks[i].time_ms, _ticks[i].bid); + } + + // Adding candle to the output array. + ArrayPushObject(_out_arr, _candle); + --_num_items; + } + + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + _from_time_ms += _candle_length_ms; + } else { + _from_time_ms -= _candle_length_ms; + } + } + } else { + Print("Error: GetItems() for IndicatorTf can only work with given _from_time_ms!"); DebugBreak(); } } @@ -149,7 +191,9 @@ class IndicatorTf : public IndicatorCandle(iparams.GetSecsPerCandle())); } + void Init() { + history.SetItemProvider(new ItemsHistoryTfCandleProvider(iparams.GetSecsPerCandle(), THIS_PTR)); + } public: /* Special methods */ diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index e15d3d82e..4587c0343 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -325,6 +325,15 @@ class IndicatorTick : public Indicator { _tick.ask = _entry[1]; return _tick; } + + /** + * Fetches historic ticks for a given range and emits these ticks. Used to regenerate candles. + */ + virtual bool FetchHistory(long _range_from, long _range_to, ARRAY_REF(TickAB, _out_ticks)) { + Print("Error: ", GetFullName(), " does not implement FetchHistory()!"); + DebugBreak(); + return false; + } }; #endif diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index cdea3baeb..241a09f0e 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -34,8 +34,6 @@ #include "../../Chart.struct.static.h" #include "../../Indicator/IndicatorTick.h" -#define INDICATOR_TICK_REAL_FETCH_HISTORY 1000 - // Structs. // Params for MT patform's tick-based indicator. struct Indi_TickMtParams : IndicatorParams { @@ -44,23 +42,16 @@ struct Indi_TickMtParams : IndicatorParams { // MT platform's tick-based indicator. class Indi_TickMt : public IndicatorTick { - protected: - 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_src) {} 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; - } + IndicatorDataParams(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), _indi_src) {} string GetName() override { return "Indi_TickMt"; } @@ -117,119 +108,40 @@ class Indi_TickMt : public IndicatorTick { /** * Fetches historic ticks for a given range and emits these ticks. Used to regenerate candles. */ - void FetchHistory(long _range_from, long _range_to) override { - // Number of retries for CopyTicksRange(). - int _tries = 10; - - static MqlTick _tmp_ticks[]; - ArrayResize(_tmp_ticks, 0); - - while (_tries > 0) { - int _num_copied = CopyTicksRange(GetSymbol(), _tmp_ticks, COPY_TICKS_INFO, _range_from, _range_to); - - if (_num_copied == -1) { - ResetLastError(); - Sleep(1000); - --_tries; - } else { - for (int i = 0; i < _num_copied; ++i) { - TickAB _tick(_tmp_ticks[i].ask, _tmp_ticks[i].bid); -#ifdef __debug_verbose__ - Print("Emitting historic 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)); - } - break; - } - } - } - - /** - * Fetches historic ticks for last two weeks and emits those ticks. - */ - 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 + bool FetchHistory(long _range_from, long _range_to, ARRAY_REF(TickTAB, _out_ticks)) override { + ArrayResize(_out_ticks, 0); 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); + int _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! + TickTAB _tick(_tmp_ticks[i]); #ifdef __debug_verbose__ - Print("Tick at ", TimeToString(_tmp_ticks[i].time, TIME_DATE | TIME_MINUTES | TIME_SECONDS), ": ", + Print("Fetched 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; - } + ArrayPushObject(_out_ticks, _tick); } - _range_from -= _period_msc; - _range_to -= _period_msc; - if (++_periods_checked > _max_periods_to_check) { - break; - } + return true; } } -#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 + // To many tries. Probably no ticks at the given range. + return false; } void OnTick(int _global_tick_index) 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(); diff --git a/Platform.h b/Platform.h index 0de21d3dd..d9a1a794d 100644 --- a/Platform.h +++ b/Platform.h @@ -86,8 +86,6 @@ class Platform { * Performs tick on every added indicator. */ static void Tick() { - ++global_tick_index; - // Checking starting periods and updating time to current one. time_flags = time.GetStartedPeriods(); time.Update(); @@ -104,6 +102,9 @@ class Platform { // Will check for new time periods in consecutive Platform::UpdateTime(). time_clear_flags = true; + + // Started from 0. Will be incremented after each finished tick. + ++global_tick_index; } /** diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index df05bd5af..0f6b417ca 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -37,11 +37,6 @@ */ enum ENUM_ITEMS_HISTORY_DIRECTION { ITEMS_HISTORY_DIRECTION_FORWARD, ITEMS_HISTORY_DIRECTION_BACKWARD }; -/** - * Whether we're selecting history via index (shift) or time in milliseconds. - */ -enum ENUM_ITEMS_HISTORY_SELECTOR { ITEMS_HISTORY_SELECTOR_INDEX, ITEMS_HISTORY_SELECTOR_TIME_MS }; - /** * Forward declaration. */ @@ -63,12 +58,21 @@ class ItemsHistoryItemProvider : public Dynamic { * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we * want previous or next items from selected starting point. */ - void GetItems(ItemsHistory>* _history, long _from, ENUM_ITEMS_HISTORY_SELECTOR _sel, + void GetItems(ItemsHistory>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(IV, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. Print("Error: Retrieving items by this item provider is not implemented!"); DebugBreak(); } + + /** + * Time of the first possible item/candle/tick. + */ + virtual long GetInitialTimeMs() { + Print("Error: ItemsHistory item's provider does not implement GetInitialTimeMs(), but it should!"); + DebugBreak(); + return 0; + } }; /** @@ -160,10 +164,35 @@ class ItemsHistory { ArrayResize(_items, 0); int _item_count = _to_index - _from_index + 1; + long _from_time_ms; + IV _item; - // PT x(5); + // Calculating time to be passed to GetItems(). + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + if (history.Size() == 0) { + // Time from we'll be getting items will be the time of the first possible item/candle/tick. + _from_time_ms = item_provider REF_DEREF GetInitialTimeMs(); + } else { + // Time will be the time of last valid item + item's length + 1ms. + _item = GetItemByIndex(last_valid_index); + _from_time_ms = _item.GetTimeMs() + _item.GetLengthMs() + 1; + } + } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + if (history.Size() == 0) { + // Time from we'll be getting items will be the time of the first possible item/candle/tick - 1ms. + _from_time_ms = item_provider REF_DEREF GetInitialTimeMs() - 1; + } else { + // Time will be the time of the first valid item - 1ms. + _item = GetItemByIndex(first_valid_index); + _from_time_ms = _item.GetTimeMs() - 1; + } + } else { + Print("Error: We shouldn't be here!"); + DebugBreak(); + return; + } - item_provider REF_DEREF GetItems(THIS_PTR, _from_index, ITEMS_HISTORY_SELECTOR_INDEX, _dir, _item_count, _items); + item_provider REF_DEREF GetItems(THIS_PTR, _from_time_ms, _dir, _item_count, _items); if (ArraySize(_items) != _item_count) { Print("Error: Wrong number of items generated by item provider. Requested ", _item_count, " items, but got ", @@ -319,8 +348,8 @@ class ItemsHistory { // Whether we need to prepend old items or append new ones. ENUM_ITEMS_HISTORY_DIRECTION _dir = _index < first_valid_index ? ITEMS_HISTORY_DIRECTION_BACKWARD : ITEMS_HISTORY_DIRECTION_FORWARD; - RegenerateHistory(_index < first_valid_index ? _index : last_valid_index, - _index > last_valid_index ? _index : last_valid_index, _dir); + RegenerateHistory(_index < first_valid_index ? _index : (last_valid_index - 1), + _index < first_valid_index ? (first_valid_index - 1) : _index, _dir); // Trying to get item again, but without regeneration at this time. return TryGetItemByIndex(_index, _out_item, false); } diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index c128f9818..b3ccb5b73 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -67,8 +67,8 @@ struct TickAB { */ template struct TickTAB : TickAB { - datetime time; // Time of the last prices update. + long time_ms; // Time of the last prices update. // Struct constructors. - TickTAB(datetime _time = 0, T _ask = 0, T _bid = 0) : time(_time), TickAB(_ask, _bid) {} - TickTAB(MqlTick &_tick) : time(_tick.time), TickAB(_tick) {} + TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : time_ms(_time_ms), TickAB(_ask, _bid) {} + TickTAB(MqlTick &_tick) : time_ms(_tick.time_msc), TickAB(_tick) {} }; From 43e9bf09cb135556ae7f6520407c1a2fc4050daa Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 6 Oct 2022 19:25:17 +0200 Subject: [PATCH 029/123] WIP. Fixing tests. Added ItemsHistory ItemProvider stub for Renko indicator. We now need to use ItemsHistory in IndicatorTick for storing ticks. --- Indicator/IndicatorRenko.h | 143 +++++++++-------- Indicator/IndicatorRenko.provider.h | 80 ++++++++++ Indicator/IndicatorTf.h | 144 +---------------- Indicator/IndicatorTf.provider.h | 173 +++++++++++++++++++++ Indicator/tests/classes/IndicatorTfDummy.h | 1 + Platform.h | 2 +- Storage/ItemsHistory.h | 25 ++- Storage/tests/ItemsHistory.mq5 | 5 + Strategy.mqh | 4 +- tests/DrawIndicatorTest.mq5 | 2 +- 10 files changed, 350 insertions(+), 229 deletions(-) create mode 100644 Indicator/IndicatorRenko.provider.h create mode 100644 Indicator/IndicatorTf.provider.h diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index 3c24b6f4b..0e2c4200e 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -37,6 +37,7 @@ // Includes. #include "../Chart.struct.tf.h" #include "IndicatorCandle.h" +#include "IndicatorRenko.provider.h" #include "IndicatorRenko.struct.h" /** @@ -73,7 +74,7 @@ struct RenkoParams : IndicatorTfParams { * Note that Renko acts as a Candle indicator and thus has the same number of * modes and same list of ValueStorage buffers as IndicatorCandle one. */ -class IndicatorRenko : public IndicatorCandle { +class IndicatorRenko : public IndicatorCandle> { protected: // @todo Time-frame used to create candles. ENUM_TIMEFRAMES tf; @@ -110,7 +111,8 @@ class IndicatorRenko : public IndicatorCandle { * Class constructor with parameters. */ IndicatorRenko(RenkoParams &_params) - : IndicatorCandle(_params, IndicatorDataParams(FINAL_INDI_CANDLE_MODE_ENTRY)) { + : IndicatorCandle>( + _params, IndicatorDataParams(FINAL_INDI_CANDLE_MODE_ENTRY)) { Init(); } @@ -169,94 +171,97 @@ class IndicatorRenko : public IndicatorCandle { /** * Called when data source emits new entry (historic or future one). */ - void OnDataSourceEntry(IndicatorDataEntry &entry) override { - if (entry.timestamp < last_entry_ts) { - Print("Error: IndicatorRenko doesn't support sending entries in non-ascending order!"); - DebugBreak(); - } + void OnDataSourceEntry(IndicatorDataEntry &entry) override{ + /* + @todo Move logic into ItemsHistoryRenkoCandleProvider class. + + if (entry.timestamp < last_entry_ts) { + Print("Error: IndicatorRenko doesn't support sending entries in non-ascending order!"); + DebugBreak(); + } - // We'll be updating candle from bid price. - double _price = entry[1]; + // We'll be updating candle from bid price. + double _price = entry[1]; - CandleOCTOHLC _candle; - CandleOCTOHLC _last_completed_candle; - ENUM_INDI_RENKO_CANDLE_TYPE _last_completed_candle_type; + CandleOCTOHLC _candle; + CandleOCTOHLC _last_completed_candle; + ENUM_INDI_RENKO_CANDLE_TYPE _last_completed_candle_type; - if (last_completed_candle_ts != 0) { - _last_completed_candle = icdata.GetByKey(last_completed_candle_ts); - _last_completed_candle_type = GetCandleType(_last_completed_candle); - } else { - _last_completed_candle_type = INDI_RENKO_CANDLE_TYPE_NONE; - } + if (last_completed_candle_ts != 0) { + _last_completed_candle = icdata.GetByKey(last_completed_candle_ts); + _last_completed_candle_type = GetCandleType(_last_completed_candle); + } else { + _last_completed_candle_type = INDI_RENKO_CANDLE_TYPE_NONE; + } - if (last_incomplete_candle_ts != 0) { - // There is previous candle. Retrieving and updating it. - _candle = icdata.GetByKey(last_incomplete_candle_ts); - _candle.Update(entry.timestamp, _price); + if (last_incomplete_candle_ts != 0) { + // There is previous candle. Retrieving and updating it. + _candle = icdata.GetByKey(last_incomplete_candle_ts); + _candle.Update(entry.timestamp, _price); - // Checking for close price difference. - if (RenkoConditionMet(_last_completed_candle_type, _candle, _price)) { - // Closing current candle. - _candle.is_complete = true; - } + // Checking for close price difference. + if (RenkoConditionMet(_last_completed_candle_type, _candle, _price)) { + // Closing current candle. + _candle.is_complete = true; + } - // Updating candle. - icdata.Add(_candle, last_incomplete_candle_ts); + // Updating candle. + icdata.Add(_candle, last_incomplete_candle_ts); - Print("Updated Candle: ", _candle.ToString()); + Print("Updated Candle: ", _candle.ToString()); - if (_candle.is_complete) { - last_completed_candle_ts = last_incomplete_candle_ts; - last_incomplete_candle_ts = 0; - } - } else { - // There is no incomplete candle, creating one. - if (last_completed_candle_ts != 0) { - // Price of the last candle will be used to initialize open price for new, incomplete candle. - double _last_close_price = _last_completed_candle.close; - _candle = CandleOCTOHLC(_last_close_price, _last_close_price, _last_close_price, _last_close_price, - entry.timestamp, entry.timestamp); - // Current price will be added to newly created incomplete candle. - _candle.Update(entry.timestamp, _price); + if (_candle.is_complete) { + last_completed_candle_ts = last_incomplete_candle_ts; + last_incomplete_candle_ts = 0; + } } else { - // There was no completed candle. Creating new, incomplete candle from current price. - _candle = CandleOCTOHLC(_price, _price, _price, _price, entry.timestamp, entry.timestamp); - } + // There is no incomplete candle, creating one. + if (last_completed_candle_ts != 0) { + // Price of the last candle will be used to initialize open price for new, incomplete candle. + double _last_close_price = _last_completed_candle.close; + _candle = CandleOCTOHLC(_last_close_price, _last_close_price, _last_close_price, _last_close_price, + entry.timestamp, entry.timestamp); + // Current price will be added to newly created incomplete candle. + _candle.Update(entry.timestamp, _price); + } else { + // There was no completed candle. Creating new, incomplete candle from current price. + _candle = CandleOCTOHLC(_price, _price, _price, _price, entry.timestamp, entry.timestamp); + } - _candle.is_complete = false; + _candle.is_complete = false; - // Creating new candle. - icdata.Add(_candle, entry.timestamp); + // Creating new candle. + icdata.Add(_candle, entry.timestamp); - Print("Added candle: ", _candle.ToString(), " now there is ", icdata.Size(), " candles in the buffer."); + Print("Added candle: ", _candle.ToString(), " now there is ", icdata.Size(), " candles in the buffer."); - last_incomplete_candle_ts = entry.timestamp; - } + last_incomplete_candle_ts = entry.timestamp; + } - static int iteration = 0; + static int iteration = 0; - ++iteration; + ++iteration; - Print("Iteration: ", iteration); + Print("Iteration: ", iteration); - if (iteration > 1793) { - // Print(icdata.ToJSON()); - } + if (iteration > 1793) { + // Print(icdata.ToJSON()); + } - Print("Last Incomplete Time: ", TimeToString(last_incomplete_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS), - " (", last_incomplete_candle_ts, ")"); - Print("Last Incomplete Candle: ", icdata.GetByKey(last_incomplete_candle_ts).ToString()); - Print("Last Completed Time: ", TimeToString(last_completed_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS), - " (", last_completed_candle_ts, ")"); - Print("Last Completed Candle: ", icdata.GetByKey(last_completed_candle_ts).ToString()); + Print("Last Incomplete Time: ", TimeToString(last_incomplete_candle_ts, TIME_DATE | TIME_MINUTES | + TIME_SECONDS), " (", last_incomplete_candle_ts, ")"); Print("Last Incomplete Candle: ", + icdata.GetByKey(last_incomplete_candle_ts).ToString()); Print("Last Completed Time: ", + TimeToString(last_completed_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS), " (", last_completed_candle_ts, + ")"); Print("Last Completed Candle: ", icdata.GetByKey(last_completed_candle_ts).ToString()); - // Updating tick & bar indices. Bar time is time of the last completed candle. - // Print(last_completed_candle_ts); - counter.OnTick(last_completed_candle_ts); + // Updating tick & bar indices. Bar time is time of the last completed candle. + // Print(last_completed_candle_ts); + counter.OnTick(last_completed_candle_ts); - Print("---------"); + Print("---------"); - last_entry_ts = entry.timestamp; + last_entry_ts = entry.timestamp; + */ }; /** diff --git a/Indicator/IndicatorRenko.provider.h b/Indicator/IndicatorRenko.provider.h new file mode 100644 index 000000000..e987f12ba --- /dev/null +++ b/Indicator/IndicatorRenko.provider.h @@ -0,0 +1,80 @@ +//+------------------------------------------------------------------+ +//| 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 INDICATOR_RENKO_PROVIDER_H +#define INDICATOR_RENKO_PROVIDER_H + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +/** + * Candle grouping and regeneration for time-frame based candles. + */ +template +class ItemsHistoryRenkoCandleProvider : public ItemsHistoryCandleProvider { + // Pointer to IndicatorTick. Used to fetch data from IndicatorTick in the hierarchy. + IndicatorData* indi; + + // Current tick index. Effectively a number of ticks generated by attached + // IndicatorTick. + int tick_index; + + public: + /** + * Constructor. + */ + ItemsHistoryRenkoCandleProvider(IndicatorData* _indi_tick) : indi(_indi_tick), tick_index(0) {} + + /** + * Called when new tick was emitted from IndicatorTick-based source. + */ + virtual void OnTick(ItemsHistory, ItemsHistoryRenkoCandleProvider>* _history, long _time_ms, + float _ask, float _bid) { + ++tick_index; + + Print("IndicatorRenko is not yet implemented!"); + DebugBreak(); + } + + /** + * Returns current tick index. Effectively a number of ticks generated by + * attached IndicatorTick. + */ + int GetTickIndex() { return tick_index; } + + /** + * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we + * want previous or next items from selected starting point. + */ + void GetItems(ItemsHistory, ItemsHistoryRenkoCandleProvider>* _history, long _from_time_ms, + ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + // Method is called if there is a missing item (candle) in the history. We need to regenerate it. + + Print("IndicatorRenko is not yet implemented!"); + DebugBreak(); + } +}; + +#endif // INDICATOR_TF_PROVIDER_H diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index f8baba3ca..577b21068 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -30,150 +30,8 @@ #endif // Includes. -#include "../Chart.struct.tf.h" #include "IndicatorCandle.h" -#include "IndicatorTf.struct.h" - -/** - * Candle grouping and regeneration for time-frame based candles. - */ -template -class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { - // Seconds per candle. - int spc; - - // Pointer to IndicatorTf. Used to fetch data from IndicatorTick in the hierarchy. - IndicatorData* indi; - - // Current tick index. Effectively a number of ticks generated by attached - // IndicatorTick. - int tick_index; - - public: - /** - * Constructor. - */ - ItemsHistoryTfCandleProvider(int _spc, IndicatorData* _indi_tf) : spc(_spc), indi(_indi_tf), tick_index(0) {} - - /** - * Called when new tick was emitted from IndicatorTick-based source. - */ - virtual void OnTick(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _time_ms, - float _ask, float _bid) { - ++tick_index; - - // Print("IndicatorTf's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | - // TIME_SECONDS), - // ", ", _ask, ", ", _bid); - - // We know that tick's timestamp will be ahead of the last tick and thus - // inside or ahead of the last created candle. In order to retrieve last - // valid candle, we need to use ItemsHistory::GetItemByShift(0) to check if - // we have to update last or create/append new candle. - CandleOCTOHLC _candle; - - // Will regenerate candles up to the last added candle ever. We have to - // call it, because some of the previous actions may have removed some of - // the recent candles. Note that OnTick() advances its _time_ms in - // ascending order, so all we need to most recent history. - // - // Note that EnsureShiftExists() may return false when there never been any - // candle added. - _history PTR_DEREF EnsureShiftExists(0); - - if (_history PTR_DEREF TryGetItemByShift(0, _candle, false) && _candle.ContainsTimeMs(_time_ms)) { - // Time given fits in the last added candle's time-frame, updating the candle with given price. - _candle.Update(_time_ms, _bid); - - // Storing candle in the history. - _history PTR_DEREF Update(_candle, _history PTR_DEREF GetShiftIndex(0)); - } else { - CandleOCTOHLC _candle_tmp; - - // We don't want to regenerate history, because at the start there will bo no candle however. - if (_history PTR_DEREF TryGetItemByShift(0, _candle_tmp, false)) { - Print("Completed candle: ", _candle_tmp.ToString()); - Print("Real candle: ", iOpen(NULL, Period(), 1), " ", iHigh(NULL, Period(), 1), " ", - iLow(NULL, Period(), 1), " ", ChartStatic::iClose(NULL, (ENUM_TIMEFRAMES)Period(), 1)); - Print("--"); - } - - // Either there is no candle at shift 0 or given time doesn't fit in the #0 candle's time-frame. - _candle.Init(GetCandleTimeFromTimeMs(_time_ms, spc), spc, _time_ms, _bid); - - // Adding candle as the most recent item in the history. It will now become the candle at shift 0. - _history PTR_DEREF Append(_candle); - } - } - - /** - * Returns current tick index. Effectively a number of ticks generated by - * attached IndicatorTick. - */ - int GetTickIndex() { return tick_index; } - - /** - * Returns start time of the candle (the place it's on the chart) for the given tick's time in milliseconds. - */ - int GetCandleTimeFromTimeMs(long _time_ms, int _length_in_secs) { - return (int)((_time_ms - _time_ms % (_length_in_secs * 1000)) / 1000); - } - - /** - * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we - * want previous or next items from selected starting point. - */ - void GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _from_time_ms, - ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { - // Method is called if there is a missing item (candle) in the history. We need to regenerate it. - if (_from_time_ms != 0) { - // In order to (re)generate candle, we need to fetch ticks within a fixed time-frame and then update that candle - // with all fetched ticks. For IndicatorTf, there is no difference between (re)generating backwards or forwards, - // as candles are time-framed. The only problem is that there may be missing candles in fetched time-frames. We - // just need to skip such time-frame and fetch ticks for next time-frame. In order to determine - - IndicatorData* _indi_tick = indi PTR_DEREF GetTick(); - - // Ticks to form a candle. - static ARRAY(TickTAB, _ticks); - - while (_num_items > 0) { - // Calculating time from which and to which we want to retrieve ticks to form a candle. - int _ticks_from_s = GetCandleTimeFromTimeMs(_from_time_ms, spc); - long _ticks_from_ms = (long)_ticks_from_s * 1000; - long _candle_length_ms = (long)spc * 1000; - long _ticks_to_ms = _ticks_from_ms + _candle_length_ms - 1; - - if (!_indi_tick PTR_DEREF FetchHistory(_ticks_from_ms, _ticks_to_ms, _ticks)) { - // There is no more ticks in the history, giving up. - break; - } - - if (ArraySize(_ticks) > 0) { - // Forming a candle. - CandleOCTOHLC _candle; - _candle.Init(_ticks_from_s, spc); - for (int i = 0; i < ArraySize(_ticks); ++i) { - _candle.Update(_ticks[i].time_ms, _ticks[i].bid); - } - - // Adding candle to the output array. - ArrayPushObject(_out_arr, _candle); - --_num_items; - } - - if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { - _from_time_ms += _candle_length_ms; - } else { - _from_time_ms -= _candle_length_ms; - } - } - } else { - Print("Error: GetItems() for IndicatorTf can only work with given _from_time_ms!"); - DebugBreak(); - } - } -}; +#include "IndicatorTf.provider.h" /** * Class to deal with candle indicators. diff --git a/Indicator/IndicatorTf.provider.h b/Indicator/IndicatorTf.provider.h new file mode 100644 index 000000000..1a10ab9d0 --- /dev/null +++ b/Indicator/IndicatorTf.provider.h @@ -0,0 +1,173 @@ +//+------------------------------------------------------------------+ +//| 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 INDICATOR_TF_PROVIDER_H +#define INDICATOR_TF_PROVIDER_H + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +/** + * Candle grouping and regeneration for time-frame based candles. + */ +template +class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { + // Seconds per candle. + int spc; + + // Pointer to IndicatorTick. Used to fetch data from IndicatorTick in the hierarchy. + IndicatorData* indi; + + // Current tick index. Effectively a number of ticks generated by attached + // IndicatorTick. + int tick_index; + + public: + /** + * Constructor. + */ + ItemsHistoryTfCandleProvider(int _spc, IndicatorData* _indi_tf) : spc(_spc), indi(_indi_tf), tick_index(0) {} + + /** + * Called when new tick was emitted from IndicatorTick-based source. + */ + virtual void OnTick(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _time_ms, + float _ask, float _bid) { + ++tick_index; + + // Print("IndicatorTf's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | + // TIME_SECONDS), + // ", ", _ask, ", ", _bid); + + // We know that tick's timestamp will be ahead of the last tick and thus + // inside or ahead of the last created candle. In order to retrieve last + // valid candle, we need to use ItemsHistory::GetItemByShift(0) to check if + // we have to update last or create/append new candle. + CandleOCTOHLC _candle; + + // Will regenerate candles up to the last added candle ever. We have to + // call it, because some of the previous actions may have removed some of + // the recent candles. Note that OnTick() advances its _time_ms in + // ascending order, so all we need to most recent history. + // + // Note that EnsureShiftExists() may return false when there never been any + // candle added. + _history PTR_DEREF EnsureShiftExists(0); + + if (_history PTR_DEREF TryGetItemByShift(0, _candle, false) && _candle.ContainsTimeMs(_time_ms)) { + // Time given fits in the last added candle's time-frame, updating the candle with given price. + _candle.Update(_time_ms, _bid); + + // Storing candle in the history. + _history PTR_DEREF Update(_candle, _history PTR_DEREF GetShiftIndex(0)); + } else { + CandleOCTOHLC _candle_tmp; + + // We don't want to regenerate history, because at the start there will bo no candle however. + if (_history PTR_DEREF TryGetItemByShift(0, _candle_tmp, false)) { + Print("Completed candle: ", _candle_tmp.ToString()); + Print("Real candle: ", iOpen(NULL, Period(), 1), " ", iHigh(NULL, Period(), 1), " ", + iLow(NULL, Period(), 1), " ", ChartStatic::iClose(NULL, (ENUM_TIMEFRAMES)Period(), 1)); + Print("--"); + } + + // Either there is no candle at shift 0 or given time doesn't fit in the #0 candle's time-frame. + _candle.Init(GetCandleTimeFromTimeMs(_time_ms, spc), spc, _time_ms, _bid); + + // Adding candle as the most recent item in the history. It will now become the candle at shift 0. + _history PTR_DEREF Append(_candle); + } + } + + /** + * Returns current tick index. Effectively a number of ticks generated by + * attached IndicatorTick. + */ + int GetTickIndex() { return tick_index; } + + /** + * Returns start time of the candle (the place it's on the chart) for the given tick's time in milliseconds. + */ + int GetCandleTimeFromTimeMs(long _time_ms, int _length_in_secs) { + return (int)((_time_ms - _time_ms % (_length_in_secs * 1000)) / 1000); + } + + /** + * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we + * want previous or next items from selected starting point. + */ + void GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _from_time_ms, + ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + // Method is called if there is a missing item (candle) in the history. We need to regenerate it. + if (_from_time_ms != 0) { + // In order to (re)generate candle, we need to fetch ticks within a fixed time-frame and then update that candle + // with all fetched ticks. For IndicatorTf, there is no difference between (re)generating backwards or forwards, + // as candles are time-framed. The only problem is that there may be missing candles in fetched time-frames. We + // just need to skip such time-frame and fetch ticks for next time-frame. In order to determine + + IndicatorData* _indi_tick = indi PTR_DEREF GetTick(); + + // Ticks to form a candle. + static ARRAY(TickTAB, _ticks); + + while (_num_items > 0) { + // Calculating time from which and to which we want to retrieve ticks to form a candle. + int _ticks_from_s = GetCandleTimeFromTimeMs(_from_time_ms, spc); + long _ticks_from_ms = (long)_ticks_from_s * 1000; + long _candle_length_ms = (long)spc * 1000; + long _ticks_to_ms = _ticks_from_ms + _candle_length_ms - 1; + + if (!_indi_tick PTR_DEREF FetchHistory(_ticks_from_ms, _ticks_to_ms, _ticks)) { + // There is no more ticks in the history, giving up. + break; + } + + if (ArraySize(_ticks) > 0) { + // Forming a candle. + CandleOCTOHLC _candle; + _candle.Init(_ticks_from_s, spc); + for (int i = 0; i < ArraySize(_ticks); ++i) { + _candle.Update(_ticks[i].time_ms, _ticks[i].bid); + } + + // Adding candle to the output array. + ArrayPushObject(_out_arr, _candle); + --_num_items; + } + + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + _from_time_ms += _candle_length_ms; + } else { + _from_time_ms -= _candle_length_ms; + } + } + } else { + Print("Error: GetItems() for IndicatorTf can only work with given _from_time_ms!"); + DebugBreak(); + } + } +}; + +#endif // INDICATOR_TF_PROVIDER_H diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 1a346f539..4e75818ed 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -31,6 +31,7 @@ // Includes. #include "../../IndicatorTf.h" +#include "../../IndicatorTf.struct.h" // Params for dummy candle-based indicator. struct IndicatorTfDummyParams : IndicatorTfParams { diff --git a/Platform.h b/Platform.h index d9a1a794d..97a88f018 100644 --- a/Platform.h +++ b/Platform.h @@ -80,7 +80,7 @@ class Platform { /** * Returns global tick index. */ - int GetGlobalTickIndex() { return global_tick_index; } + static int GetGlobalTickIndex() { return global_tick_index; } /** * Performs tick on every added indicator. diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index 0f6b417ca..f75df681a 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -294,19 +294,6 @@ class ItemsHistory { history.Set(_index, _item); } - /** - * Returns bar date and time for the given shift. - */ - datetime GetItemTimeByShift(int _shift) { - if (history.Size() == 0) { - // What to do? Maybe just return 0? - DebugBreak(); - return 0; - } - - return (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); - } - /** * Ensures */ @@ -393,6 +380,18 @@ class ItemsHistory { return GetItemByShift(_shift).GetTimeMs(); } + + /** + * Returns bar date and time for the given shift. + */ + datetime GetItemTimeByShift(int _shift) { + if (!EnsureShiftExists(_shift)) { + // There won't be item at given shift. + return (datetime)0; + } + + return (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); + } }; #endif diff --git a/Storage/tests/ItemsHistory.mq5 b/Storage/tests/ItemsHistory.mq5 index 968093d99..43ac6abf3 100644 --- a/Storage/tests/ItemsHistory.mq5 +++ b/Storage/tests/ItemsHistory.mq5 @@ -58,6 +58,11 @@ void OnTick() { Print(_ohlc.ToCSV()); + if (_candles PTR_DEREF GetBarIndex() == 1) { + // Updating first candle to be sure it was formed by all possible ticks. + _ohlcs[0] = _candles PTR_DEREF GetOHLC(1); + } + if (_candles PTR_DEREF GetBarIndex() == INDI_CANDLE_HISTORY_SIZE) { // Now first candle should be forgotten by candle history. We'll check if candle regeneration works. Print("First candle was: ", _ohlcs[0].ToCSV()); diff --git a/Strategy.mqh b/Strategy.mqh index e68fa8334..d52f5168a 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -284,9 +284,9 @@ class Strategy : public Taskable { /** * Executes OnTick() on every attached indicator. */ - void Tick() { + void Tick(int _global_tick_index) { for (DictIterator> it = indicators.Begin(); it.IsValid(); ++it) { - it.Value() REF_DEREF Tick(); + it.Value() REF_DEREF Tick(_global_tick_index); } } diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index 499634840..7863ca883 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -70,7 +70,7 @@ void OnTick() { for (DictIterator> iter = Platform::GetIndicators() PTR_DEREF Begin(); iter.IsValid(); ++iter) { IndicatorData *_indi = iter.Value().Ptr(); - _indi.OnTick(); + _indi.OnTick(Platform::GetGlobalTickIndex()); IndicatorDataEntry _entry = _indi.GetEntry(); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)) && _entry.IsValid()) { PrintFormat("%s: bar %d: %s", _indi.GetName(), bar_processed, _indi.ToString()); From df96a23ea5413ecbc7a93607de457f2ec42cf5f4 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 7 Oct 2022 19:07:32 +0200 Subject: [PATCH 030/123] WIP. IndicatorTick is now using ItemsHistory for tick storage purposes. IndicatorsTest compiles, but need fixes/tests. --- Candle.struct.h | 4 +- Indicator/IndicatorCandle.h | 3 - Indicator/IndicatorCandle.provider.h | 2 +- Indicator/IndicatorData.h | 91 ++++++++++++++++++- Indicator/IndicatorTf.provider.h | 2 +- Indicator/IndicatorTick.h | 125 ++++----------------------- Indicator/IndicatorTick.provider.h | 69 +++++++++++++++ Indicators/Tick/Indi_TickMt.mqh | 30 +++++-- Storage/ItemsHistory.h | 2 + Tick/Tick.struct.h | 13 +++ 10 files changed, 212 insertions(+), 129 deletions(-) create mode 100644 Indicator/IndicatorTick.provider.h diff --git a/Candle.struct.h b/Candle.struct.h index dfc6c1623..75acc6b09 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -296,12 +296,12 @@ struct CandleOCTOHLC : CandleOHLC { } /** - * Method used by ItemsHistory; + * Method used by ItemsHistory. */ long GetTimeMs() { return (long)start_time * 1000; } /** - * Method used by ItemsHistory; + * Method used by ItemsHistory. */ long GetLengthMs() { return (long)length * 1000; } diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index cf9218e3b..f57fb847c 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -328,9 +328,6 @@ class IndicatorCandle : public Indicator { // update/create candles so we just pass the entry into history's // ItemsHistoryCandleProvider and it will do all the job. history.GetItemProvider() PTR_DEREF OnTick(&history, entry.timestamp * 1000, (float)entry[0], (float)entry[1]); - - // @fixit Maybe we should generate some tick/bar change? - // counter.OnTick(CalcCandleTimestamp(entry.timestamp)); }; /** diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index e3319bc3c..b6737c945 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -48,7 +48,7 @@ class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider, ItemsHistoryItemProvider>>* _history, - long _timestamp_ms, float _ask, float _bid) { + long _time_ms, float _ask, float _bid) { // Should be overrided. } diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 2219371af..a39b858cc 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -36,6 +36,7 @@ class IndicatorBase; #include "../Bar.struct.h" #include "../DrawIndicator.mqh" #include "../Flags.h" +#include "../Storage/ItemsHistory.h" #include "../Storage/ValueStorage.h" #include "../Storage/ValueStorage.indicator.h" #include "../Storage/ValueStorage.native.h" @@ -1450,9 +1451,91 @@ class IndicatorData : public IndicatorBase { virtual void InvalidateCandle(datetime _bar_time = 0) { GetCandle() PTR_DEREF InvalidateCandle(_bar_time); } /** - * Fetches historic ticks for a given range and emits these ticks. Used to regenerate candles. + * Fetches historic ticks for a given time range. */ - virtual bool FetchHistory(long _range_from, long _range_to, ARRAY_REF(TickTAB, _out_ticks)) { return false; } + virtual bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { + return false; + } + + /** + * Fetches historic ticks for a given start time and minimum number of tick to retrieve. + */ + virtual bool FetchHistoryByStartTimeAndCount(long _from_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _min_count, + ARRAY_REF(TickTAB, _out_ticks)) { + Print("FetchHistoryByStartTimeAndCount:"); + Print("- Requested _from_ms = ", _from_ms, ", _dir = ", EnumToString(_dir), ", _min_count = ", _min_count); + + ArrayResize(_out_ticks, 0); + + // Number of ticks still to retrieve to satisfy the caller. + int _num_to_retrieve = _min_count, i, o; + + // Ticks per fixed time range. + static ARRAY(TickTAB, _recv_ticks); + + // Time-frames for which we'll be receiving ticks. + long _recv_range_ms = 1000 * 60 * 30; // 30 min time-frames. + + // Calculating initial time frame. + if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + // _from_ms will be at start of previous time-frame. + _from_ms -= _recv_range_ms - 1; + } + // _to_ms will be at the last ms of _from_ms's timeframe. + long _to_ms = _from_ms + _recv_range_ms - 1; + + Print("- Initial _from_ms = ", _from_ms, "_to_ms = ", _to_ms); + + do { + bool _success = FetchHistoryByTimeRange(_from_ms, _to_ms, _recv_ticks); + + int _num_ticks_before = ArraySize(_out_ticks); + int _num_received = ArraySize(_recv_ticks); + + // Our _out_tick must fit additional received ticks. + ArrayResize(_out_ticks, _num_ticks_before + _num_received); + + if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + // Moving output ticks from the beginning to the end. + // i = input index, o = output index. + for (i = 0, o = _num_ticks_before; i < _num_received; i++, o++) { + _out_ticks[o] = _out_ticks[i]; + } + } + + for (i = 0; i < ArraySize(_recv_ticks); ++i) { + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + // Pushing received ticks at the end of the output ticks. + ArrayPushObject(_out_ticks, _recv_ticks[i]); + } else { + // Filling the beginning of the output ticks with received ticks. + _out_ticks[i] = _recv_ticks[i]; + } + } + + if (!_success) { + // An error happended; + break; + } + + _num_to_retrieve -= _num_received; + + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + // Going to the next time-frame. + _from_ms += _recv_range_ms; + _to_ms += _recv_range_ms; + } else { + // Going to the previous time-frame. + _from_ms -= _recv_range_ms; + _to_ms -= _recv_range_ms; + } + + } while (_LastError != 0 && _num_to_retrieve > 0); + + // _num_to_retrieve may be negative and it's perfectly fine. We'll just have more ticks than we wanted in the output + // array. + return _num_to_retrieve <= 0; + } /** * Returns value storage of given kind. @@ -1795,9 +1878,9 @@ class IndicatorData : public IndicatorBase { virtual void SetSymbolProps(const SymbolInfoProp& _props) {} /** - * Stores entry in the buffer for later rerieval. + * Appends given entry into the history. */ - virtual void StoreEntry(IndicatorDataEntry& entry) {} + virtual void AppendEntry(IndicatorDataEntry& entry) {} /** * Update indicator. diff --git a/Indicator/IndicatorTf.provider.h b/Indicator/IndicatorTf.provider.h index 1a10ab9d0..9a9e940b9 100644 --- a/Indicator/IndicatorTf.provider.h +++ b/Indicator/IndicatorTf.provider.h @@ -139,7 +139,7 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { long _candle_length_ms = (long)spc * 1000; long _ticks_to_ms = _ticks_from_ms + _candle_length_ms - 1; - if (!_indi_tick PTR_DEREF FetchHistory(_ticks_from_ms, _ticks_to_ms, _ticks)) { + if (!_indi_tick PTR_DEREF FetchHistoryByTimeRange(_ticks_from_ms, _ticks_to_ms, _ticks)) { // There is no more ticks in the history, giving up. break; } diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 4587c0343..9d64e0a2f 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -33,6 +33,7 @@ #include "../Buffer/BufferTick.h" #include "Indicator.h" #include "Indicator.struct.h" +#include "IndicatorTick.provider.h" #include "TickBarCounter.h" // Indicator modes. @@ -45,10 +46,10 @@ enum ENUM_INDI_TICK_MODE { /** * Class to deal with tick indicators. */ -template +template class IndicatorTick : public Indicator { protected: - BufferTick itdata; + ItemsHistory, TCP> history; TS itparams; string symbol; SymbolInfoProp symbol_props; @@ -68,9 +69,10 @@ class IndicatorTick : public Indicator { // We can only index via timestamp. flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; - itdata.SetOverflowListener(BufferStructOverflowListener, 10); // Ask and Bid price. Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); + + history.SetItemProvider(new ItemsHistoryTickProvider(THIS_PTR)); } public: @@ -103,14 +105,7 @@ class IndicatorTick : public Indicator { /** * 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(); - } + datetime GetBarTime(int _shift = 0) override { return history.GetItemTimeByShift(_shift); } /** * Gets ask price for a given date and time. Return current ask price if _dt wasn't passed or is 0. @@ -126,6 +121,8 @@ class IndicatorTick : public Indicator { * Returns value storage of given kind. */ IValueStorage* GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + Print("IndicatorTick::GetSpecificValueStorage() is no longer available!"); + /* switch (_type) { case INDI_VS_TYPE_PRICE_ASK: return (IValueStorage*)itdata.GetAskValueStorage(); @@ -141,6 +138,8 @@ class IndicatorTick : public Indicator { // Trying in parent class. return Indicator::GetSpecificValueStorage(_type); } + */ + return nullptr; } /** @@ -160,19 +159,12 @@ class IndicatorTick : public Indicator { } /** - * Sends historic entries to listening indicators. May be overriden. + * Appends given entry into the history. */ - void EmitHistory() override { - for (DictStructIterator> iter(itdata.Begin()); iter.IsValid(); ++iter) { - IndicatorDataEntry _entry = TickToEntry(iter.Key(), iter.Value()); - EmitEntry(_entry); - } - } - - /** - * Stores entry in the buffer for later rerieval. - */ - void StoreEntry(IndicatorDataEntry& _entry) override { itdata.Add(EntryToTick(_entry), _entry.timestamp); } + virtual void AppendEntry(IndicatorDataEntry& entry) override { + // Appending tick into the history. + history.GetItemProvider() PTR_DEREF OnTick(&history, entry.timestamp * 1000, (float)entry[0], (float)entry[1]); + }; /** * @todo @@ -196,53 +188,6 @@ class IndicatorTick : public Indicator { return _tick; } - /** - * Returns the indicator's data entry. - * - * @see: IndicatorDataEntry. - * - * @return - * Returns IndicatorDataEntry struct filled with indicator values. - */ - 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); - } - int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); - - // No tick at given timestamp. Returning invalid entry. - IndicatorDataEntry _entry(_max_modes); - GetEntryAlter(_entry, (datetime)_entry.timestamp); - - for (int i = 0; i < _max_modes; ++i) { - _entry.values[i] = (double)0; - } - - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, false); - return _entry; - } - - /** - * 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, datetime _time) { - ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE)); - _entry.AddFlags(_entry.GetDataTypeFlags(_dtype)); - }; - /** * Returns the indicator's entry value for the given shift and mode. * @@ -294,46 +239,6 @@ class IndicatorTick : public Indicator { * Traverses source indicators' hierarchy and tries to find IndicatorTick object at the end. */ virtual IndicatorTick* GetTickIndicator() { return THIS_PTR; } - - /* Setters */ - - /** - * Sets a tick struct with price values. - * - * @see: MqlTick. - */ - void SetTick(MqlTick& _mql_tick, long _timestamp = 0) { - TickAB _tick(_mql_tick); - itdata.Add(_tick, _timestamp); - } - - /* Virtual methods */ - - /** - * Returns a tick struct with price values. - * - * @see: MqlTick. - * - * @return - * Returns MqlTick struct with prices of the symbol. - */ - virtual MqlTick GetTick(int _timestamp = 0) { - IndicatorDataEntry _entry = GetEntry((datetime)_timestamp); - MqlTick _tick; - _tick.time = (datetime)_entry.GetTime(); - _tick.bid = _entry[0]; - _tick.ask = _entry[1]; - return _tick; - } - - /** - * Fetches historic ticks for a given range and emits these ticks. Used to regenerate candles. - */ - virtual bool FetchHistory(long _range_from, long _range_to, ARRAY_REF(TickAB, _out_ticks)) { - Print("Error: ", GetFullName(), " does not implement FetchHistory()!"); - DebugBreak(); - return false; - } }; #endif diff --git a/Indicator/IndicatorTick.provider.h b/Indicator/IndicatorTick.provider.h new file mode 100644 index 000000000..25ecacb39 --- /dev/null +++ b/Indicator/IndicatorTick.provider.h @@ -0,0 +1,69 @@ +//+------------------------------------------------------------------+ +//| 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 INDICATOR_TICK_PROVIDER_H +#define INDICATOR_TICK_PROVIDER_H + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Storage/ItemsHistory.h" + +/** + * Regenerates candles and updates exising candles from new ticks. Subclasses by IndicatorTf, IndicatorRenko. + */ +template +class ItemsHistoryTickProvider : public ItemsHistoryItemProvider> { + // Pointer to IndicatorTick. Used to fetch ask/bid prices. + IndicatorData* indi; + + public: + /** + * Constructor. + */ + ItemsHistoryTickProvider(IndicatorData* _indi_tick) : indi(_indi_tick) {} + + /** + * Called when new tick was emitted from IndicatorTick-based source. + */ + virtual void OnTick(ItemsHistory, ItemsHistoryTickProvider>* _history, long _time_ms, float _ask, + float _bid) { + TickTAB _tick(_time_ms, _ask, _bid); + _history PTR_DEREF Append(_tick); + } + + /** + * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we + * want previous or next items from selected starting point. + */ + void GetItems(ItemsHistory, ItemsHistoryTickProvider>* _history, long _from_time_ms, + ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(TickTAB, _out_arr)) { + // Method is called if there is a missing item (tick) in the history. We need to regenerate it. + indi PTR_DEREF FetchHistoryByStartTimeAndCount(_from_time_ms, _dir, _num_items, _out_arr); + } +}; + +#endif // INDICATOR_TICK_PROVIDER_H diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 241a09f0e..d5313d905 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -33,6 +33,7 @@ // Includes. #include "../../Chart.struct.static.h" #include "../../Indicator/IndicatorTick.h" +#include "../../Indicator/IndicatorTick.provider.h" // Structs. // Params for MT patform's tick-based indicator. @@ -41,17 +42,26 @@ struct Indi_TickMtParams : IndicatorParams { }; // MT platform's tick-based indicator. -class Indi_TickMt : public IndicatorTick { +class Indi_TickMt : public IndicatorTick> { 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) {} + _indi_src) { + Init(); + } 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) {} + IndicatorDataParams(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), _indi_src) { + Init(); + } + + /** + * Initializes the class. + */ + void Init() {} string GetName() override { return "Indi_TickMt"; } @@ -106,9 +116,9 @@ class Indi_TickMt : public IndicatorTick { } /** - * Fetches historic ticks for a given range and emits these ticks. Used to regenerate candles. + * Fetches historic ticks for a given time range. */ - bool FetchHistory(long _range_from, long _range_to, ARRAY_REF(TickTAB, _out_ticks)) override { + virtual bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { ArrayResize(_out_ticks, 0); static MqlTick _tmp_ticks[]; @@ -117,7 +127,7 @@ class Indi_TickMt : public IndicatorTick { int _tries = 10; while (_tries > 0) { - int _num_copied = CopyTicksRange(GetSymbol(), _tmp_ticks, COPY_TICKS_INFO, _range_from, _range_to); + int _num_copied = CopyTicksRange(GetSymbol(), _tmp_ticks, COPY_TICKS_INFO, _from_ms, _to_ms); if (_num_copied == -1) { ResetLastError(); @@ -158,7 +168,10 @@ class Indi_TickMt : public IndicatorTick { // DebugBreak(); // Just emitting zeroes in case of error. TickAB _tick(0, 0); - EmitEntry(TickToEntry(TimeCurrent(), _tick)); + IndicatorDataEntry _entry(TickToEntry(TimeCurrent(), _tick)); + EmitEntry(_entry); + // Appending tick into the history. + AppendEntry(_entry); return; } @@ -176,7 +189,8 @@ class Indi_TickMt : public IndicatorTick { #endif TickAB _tick(_ask, _bid); IndicatorDataEntry _entry(TickToEntry(_time, _tick)); - StoreEntry(_entry); EmitEntry(_entry); + // Appending tick into the history. + AppendEntry(_entry); } }; diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index f75df681a..0e66cedae 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -174,6 +174,7 @@ class ItemsHistory { _from_time_ms = item_provider REF_DEREF GetInitialTimeMs(); } else { // Time will be the time of last valid item + item's length + 1ms. + // Note that ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. _item = GetItemByIndex(last_valid_index); _from_time_ms = _item.GetTimeMs() + _item.GetLengthMs() + 1; } @@ -195,6 +196,7 @@ class ItemsHistory { item_provider REF_DEREF GetItems(THIS_PTR, _from_time_ms, _dir, _item_count, _items); if (ArraySize(_items) != _item_count) { + // @todo There's really no problem if number of generated items are less that requested. Print("Error: Wrong number of items generated by item provider. Requested ", _item_count, " items, but got ", ArraySize(_items)); DebugBreak(); diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index b3ccb5b73..b600e930d 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -71,4 +71,17 @@ struct TickTAB : TickAB { // Struct constructors. TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : time_ms(_time_ms), TickAB(_ask, _bid) {} TickTAB(MqlTick &_tick) : time_ms(_tick.time_msc), TickAB(_tick) {} + + /** + * Method used by ItemsHistory. + */ + long GetTimeMs() { return time_ms; } + + /** + * Method used by ItemsHistory. + */ + long GetLengthMs() { + // Ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. + return 0; + } }; From 415997f751fd746fa9c03e0fc271d68c5e8398e9 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 11 Oct 2022 18:07:48 +0200 Subject: [PATCH 031/123] WIP. Made indicators to use our #define for built-in indicator calls. Need to fix Envelopes indicator and problem with retrieving items with invalid indices in MT4. --- Indicator/IndicatorData.h | 40 +++++++------------------------- Indicator/IndicatorTf.provider.h | 10 ++++---- Indicators/Indi_AD.mqh | 5 +--- Indicators/Indi_ADX.mqh | 31 ++----------------------- Indicators/Indi_AO.mqh | 26 +-------------------- Indicators/Indi_ATR.mqh | 26 +-------------------- Indicators/Indi_Alligator.mqh | 29 +++-------------------- Indicators/Indi_BWMFI.mqh | 26 +-------------------- Indicators/Indi_Bands.mqh | 33 ++++++-------------------- Indicators/Indi_BearsPower.mqh | 26 +-------------------- Indicators/Indi_BullsPower.mqh | 26 +-------------------- Indicators/Indi_CCI.mqh | 5 ++++ Indicators/Indi_DEMA.mqh | 26 +-------------------- Indicators/Indi_DeMarker.mqh | 26 +-------------------- Indicators/Indi_Envelopes.mqh | 29 +++-------------------- Indicators/Indi_Force.mqh | 26 +-------------------- Indicators/Indi_Fractals.mqh | 30 +++--------------------- Indicators/Indi_Gator.mqh | 29 +++-------------------- Indicators/Indi_HeikenAshi.mqh | 26 +-------------------- Indicators/Indi_Ichimoku.mqh | 27 ++------------------- Indicators/Indi_MA.mqh | 27 ++------------------- Indicators/Indi_MACD.mqh | 28 ++-------------------- Indicators/Indi_MFI.mqh | 26 +-------------------- Indicators/Indi_Momentum.mqh | 26 +-------------------- Indicators/Indi_OBV.mqh | 26 +-------------------- Indicators/Indi_OsMA.mqh | 28 ++-------------------- Indicators/Indi_Pivot.mqh | 30 ++---------------------- Indicators/Indi_RVI.mqh | 26 +-------------------- Indicators/Indi_SAR.mqh | 26 +-------------------- Indicators/Indi_StdDev.mqh | 27 ++------------------- Indicators/Indi_Stochastic.mqh | 28 ++-------------------- Indicators/Tick/Indi_TickMt.mqh | 5 ++++ Storage/ItemsHistory.h | 31 +++++++++++++++++-------- tests/IndicatorsTest.mq5 | 9 ++++--- 34 files changed, 101 insertions(+), 744 deletions(-) diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index a39b858cc..71a45698d 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -78,7 +78,7 @@ class IndicatorData : public IndicatorBase { /* Protected methods */ bool Init() { - ArrayResize(value_storages, idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))); + ArrayResize(value_storages, GetModeCount()); if (indi_src.IsSet()) { // SetDataSource(_indi_src, _indi_mode); idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR); @@ -565,31 +565,7 @@ class IndicatorData : public IndicatorBase { /* Getters */ - int GetBarsCalculated(ENUM_TIMEFRAMES _tf = NULL) { - int _bars = Bars(GetSymbol(), _tf); - - if (!idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IS_FED))) { - // Calculating start_bar. - for (; calc_start_bar < _bars; ++calc_start_bar) { - // Iterating from the oldest or previously iterated. - IndicatorDataEntry _entry = GetEntry(_bars - calc_start_bar - 1); - - if (_entry.IsValid()) { - // From this point we assume that future entries will be all valid. - idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IS_FED), true); - return _bars - calc_start_bar; - } - } - } - - if (!idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IS_FED))) { - Print("Can't find valid bars for ", GetFullName()); - return 0; - } - - // Assuming all entries are calculated (even if have invalid values). - return _bars; - } + int GetBarsCalculated() { return GetBars(); } /** * Returns buffers' cache. @@ -761,7 +737,7 @@ class IndicatorData : public IndicatorBase { /** * Checks whether indicator have given mode (max_modes is greater that given mode). */ - bool HasValueStorage(int _mode = 0) { return _mode < GetModeCount(); } + bool HasValueStorage(unsigned int _mode = 0) { return _mode < GetModeCount(); } /** * Whether we can and have to select mode when specifying data source. @@ -1261,7 +1237,9 @@ class IndicatorData : public IndicatorBase { /** * Gets number of modes available to retrieve by GetValue(). */ - virtual int GetModeCount() { return 0; } + virtual unsigned int GetModeCount() { + return idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); + } /** * Get name of the indicator. @@ -1462,8 +1440,8 @@ class IndicatorData : public IndicatorBase { */ virtual bool FetchHistoryByStartTimeAndCount(long _from_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _min_count, ARRAY_REF(TickTAB, _out_ticks)) { - Print("FetchHistoryByStartTimeAndCount:"); - Print("- Requested _from_ms = ", _from_ms, ", _dir = ", EnumToString(_dir), ", _min_count = ", _min_count); + // Print("FetchHistoryByStartTimeAndCount:"); + // Print("- Requested _from_ms = ", _from_ms, ", _dir = ", EnumToString(_dir), ", _min_count = ", _min_count); ArrayResize(_out_ticks, 0); @@ -1484,7 +1462,7 @@ class IndicatorData : public IndicatorBase { // _to_ms will be at the last ms of _from_ms's timeframe. long _to_ms = _from_ms + _recv_range_ms - 1; - Print("- Initial _from_ms = ", _from_ms, "_to_ms = ", _to_ms); + // Print("- Initial _from_ms = ", _from_ms, "_to_ms = ", _to_ms); do { bool _success = FetchHistoryByTimeRange(_from_ms, _to_ms, _recv_ticks); diff --git a/Indicator/IndicatorTf.provider.h b/Indicator/IndicatorTf.provider.h index 9a9e940b9..a8e57c0e6 100644 --- a/Indicator/IndicatorTf.provider.h +++ b/Indicator/IndicatorTf.provider.h @@ -87,10 +87,10 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { // We don't want to regenerate history, because at the start there will bo no candle however. if (_history PTR_DEREF TryGetItemByShift(0, _candle_tmp, false)) { - Print("Completed candle: ", _candle_tmp.ToString()); - Print("Real candle: ", iOpen(NULL, Period(), 1), " ", iHigh(NULL, Period(), 1), " ", - iLow(NULL, Period(), 1), " ", ChartStatic::iClose(NULL, (ENUM_TIMEFRAMES)Period(), 1)); - Print("--"); + // Print("Completed candle: ", _candle_tmp.ToString()); + // Print("Real candle: ", iOpen(NULL, Period(), 1), " ", iHigh(NULL, Period(), 1), " ", + // iLow(NULL, Period(), 1), " ", ChartStatic::iClose(NULL, (ENUM_TIMEFRAMES)Period(), 1)); + // Print("--"); } // Either there is no candle at shift 0 or given time doesn't fit in the #0 candle's time-frame. @@ -111,7 +111,7 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { * Returns start time of the candle (the place it's on the chart) for the given tick's time in milliseconds. */ int GetCandleTimeFromTimeMs(long _time_ms, int _length_in_secs) { - return (int)((_time_ms - _time_ms % (_length_in_secs * 1000)) / 1000); + return (int)((_time_ms - _time_ms % ((long)_length_in_secs * 1000)) / 1000); } /** diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index ad7b0f95f..87e52e384 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -87,10 +87,7 @@ class Indi_AD : public Indicator { static double iAD(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ - 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; + return ::iAD(_symbol, _tf, _shift); #else // __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iAD(_symbol, _tf, VOLUME_TICK), 0, _shift); #endif diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index f01dad621..a64118c60 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -107,36 +107,9 @@ class Indi_ADX : public Indicator { // MODE_PLUSDI/PLUSDI_LINE, 2 - MODE_MINUSDI/MINUSDI_LINE int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ - 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; + return ::iADX(_symbol, _tf, _period, _applied_price, _mode, _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 = ::iADX(_symbol, _tf, _period)) == INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iADX(_symbol, _tf, _period), _mode, _shift); #endif } diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index b80c5e4b9..214e4698c 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -100,31 +100,7 @@ class Indi_AO : public Indicator { // Note: In MQL4 _mode is not supported. return ::iAO(_symbol, _tf, _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 = ::iAO(_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, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iAO(_symbol, _tf), _mode, _shift); #endif } diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index e79cc5f43..090ce1541 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -83,31 +83,7 @@ class Indi_ATR : public Indicator { #ifdef __MQL4__ return ::iATR(_symbol, _tf, _period, _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 = ::iATR(_symbol, _tf, _period)) == 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(::iATR(_symbol, _tf, _period), 0, _shift); #endif } diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index 601660a52..122241c8d 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -143,32 +143,9 @@ class Indi_Alligator : public Indicator { return ::iAlligator(_symbol, _tf, _jaw_period, _jaw_shift, _teeth_period, _teeth_shift, _lips_period, _lips_shift, _ma_method, _applied_price, _mode, _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 = ::iAlligator(_symbol, _tf, _jaw_period, _jaw_shift, _teeth_period, _teeth_shift, _lips_period, - _lips_shift, _ma_method, _applied_price)) == INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iAlligator(_symbol, _tf, _jaw_period, _jaw_shift, _teeth_period, _teeth_shift, + _lips_period, _lips_shift, _ma_method, _applied_price), + _mode, _shift); #endif } diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index 30c5f81db..37fcf665d 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -111,31 +111,7 @@ class Indi_BWMFI : public Indicator { #ifdef __MQL4__ return ::iBWMFI(_symbol, _tf, _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 = ::iBWMFI(_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, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iBWMFI(_symbol, _tf, VOLUME_TICK), _mode, _shift); #endif } diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index b978dd10c..edbeba804 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -136,32 +136,8 @@ class Indi_Bands : public Indicator { #ifdef __MQL4__ return ::iBands(_symbol, _tf, _period, _deviation, _bands_shift, _applied_price, _mode, _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 = ::iBands(_symbol, _tf, _period, _bands_shift, _deviation, _applied_price)) == INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iBands(_symbol, _tf, _period, _bands_shift, _deviation, _applied_price), _mode, + _shift); #endif } @@ -182,6 +158,11 @@ class Indi_Bands : public Indicator { // Period can't be higher than number of available bars. _period = MathMin(_period, ArraySize(_indi_applied_price)); + // But must be greater than 0! + if (_period == 0) { + return EMPTY_VALUE; + } + ArrayCopy(_indi_value_buffer, _indi_applied_price, 0, _bands_shift + _shift, _period); // Base band. Calculating MA from "_period" number of values or less. diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index 538cffa28..6c7bc0855 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -84,31 +84,7 @@ class Indi_BearsPower : public Indicator { #ifdef __MQL4__ return ::iBearsPower(_symbol, _tf, _period, _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 = ::iBearsPower(_symbol, _tf, _period)) == 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(::iBearsPower(_symbol, _tf, _period), 0, _shift); #endif } diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index 6097a4f1d..a77f5c630 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -84,31 +84,7 @@ class Indi_BullsPower : public Indicator { #ifdef __MQL4__ return ::iBullsPower(_symbol, _tf, _period, _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 = ::iBullsPower(_symbol, _tf, _period)) == 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(::iBullsPower(_symbol, _tf, _period), 0, _shift); #endif } diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index 1e31396de..55ffab15f 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -102,6 +102,11 @@ class Indi_CCI : public Indicator { int _mode, int _shift = 0) { _indi.ValidateDataSourceMode(_mode); + if (_indi.GetBars() < (int)_period) { + // No enough bars. + return DBL_MAX; + } + double _indi_value_buffer[]; IndicatorDataEntry _entry(_indi.GetModeCount()); diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index 7e7478144..61ae9faf1 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -100,31 +100,7 @@ class Indi_DEMA : public Indicator { static double iDEMA(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, unsigned int _ma_shift, ENUM_APPLIED_PRICE _applied_price, int _shift = 0, int _mode = 0, IndicatorData *_obj = NULL) { #ifdef __MQL5__ - int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; - double _res[]; - if (_handle == NULL || _handle == INVALID_HANDLE) { - if ((_handle = ::iDEMA(_symbol, _tf, _period, _ma_shift, _applied_price)) == INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iDEMA(_symbol, _tf, _period, _ma_shift, _applied_price), _mode, _shift); #else if (_obj == nullptr) { Print( diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index f15cfeea2..44df4c5ba 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -81,31 +81,7 @@ class Indi_DeMarker : public Indicator { #ifdef __MQL4__ return ::iDeMarker(_symbol, _tf, _period, _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 = ::iDeMarker(_symbol, _tf, _period)) == 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(::iDeMarker(_symbol, _tf, _period), 0, _shift); #endif } diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 1d7304c80..4018c4a6d 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -137,32 +137,9 @@ class Indi_Envelopes : public Indicator { _mode = 1; break; } - int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; - double _res[]; - if (_handle == NULL || _handle == INVALID_HANDLE) { - if ((_handle = ::iEnvelopes(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _ap, _deviation)) == - INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + + INDICATOR_BUILTIN_CALL_AND_RETURN(::iEnvelopes(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _ap, _deviation), + _mode, _shift); #endif } diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index 361b2e449..88f669b8b 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -98,31 +98,7 @@ class Indi_Force : public Indicator { #ifdef __MQL4__ return ::iForce(_symbol, _tf, _period, _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 = ::iForce(_symbol, _tf, _period, _ma_method, 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(::iForce(_symbol, _tf, _period, _ma_method, VOLUME_TICK), 0, _shift); #endif } diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index b947e0a32..ed14a7a1d 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -97,31 +97,7 @@ class Indi_Fractals : public Indicator { #ifdef __MQL4__ return ::iFractals(_symbol, _tf, _mode, _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 = ::iFractals(_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, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iFractals(_symbol, _tf), _mode, _shift); #endif } @@ -133,7 +109,7 @@ class Indi_Fractals : public Indicator { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = _value = Indi_Fractals::iFractals(GetSymbol(), GetTf(), (ENUM_LO_UP_LINE)_mode, _ishift, THIS_PTR); + _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); @@ -159,7 +135,7 @@ class Indi_Fractals : public Indicator { * Checks if indicator entry values are valid. */ virtual bool IsValidEntry(IndicatorDataEntry &_entry) { - double _wrong_value = (double)NULL; + double _wrong_value = DBL_MAX; #ifdef __MQL4__ // In MT4, the empty value for iFractals is 0, not EMPTY_VALUE=DBL_MAX as in MT5. // So the wrong value is the opposite. diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index b6d93a43d..aca212baf 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -166,32 +166,9 @@ class Indi_Gator : public Indicator { return ::iGator(_symbol, _tf, _jaw_period, _jaw_shift, _teeth_period, _teeth_shift, _lips_period, _lips_shift, _ma_method, _applied_price, _mode, _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 = ::iGator(_symbol, _tf, _jaw_period, _jaw_shift, _teeth_period, _teeth_shift, _lips_period, - _lips_shift, _ma_method, _applied_price)) == INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iGator(_symbol, _tf, _jaw_period, _jaw_shift, _teeth_period, _teeth_shift, + _lips_period, _lips_shift, _ma_method, _applied_price), + _mode, _shift); #endif } diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index c29059b0d..05501240b 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -143,31 +143,7 @@ class Indi_HeikenAshi : public Indicator { } return ::iCustom(_symbol, _tf, "Heiken Ashi", _mode, _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 = ::iCustom(_symbol, _tf, "Examples\\Heiken_Ashi")) == INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iCustom(_symbol, _tf, "Examples\\Heiken_Ashi"), _mode, _shift); #endif } diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index aeab321ce..6b2cee10d 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -136,31 +136,8 @@ class Indi_Ichimoku : public Indicator { #ifdef __MQL4__ return ::iIchimoku(_symbol, _tf, _tenkan_sen, _kijun_sen, _senkou_span_b, _mode, _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 = ::iIchimoku(_symbol, _tf, _tenkan_sen, _kijun_sen, _senkou_span_b)) == INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iIchimoku(_symbol, _tf, _tenkan_sen, _kijun_sen, _senkou_span_b), _mode, + _shift); #endif } diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 19fbe48b1..4d2b84bed 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -117,31 +117,8 @@ class Indi_MA : public Indicator { #ifdef __MQL4__ 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_price)) == 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(::iMA(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_price), 0, + _shift); #endif } diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index 835d387bd..f2f258570 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -97,32 +97,8 @@ class Indi_MACD : public Indicator { #ifdef __MQL4__ return ::iMACD(_symbol, _tf, _ema_fast_period, _ema_slow_period, _signal_period, _applied_price, _mode, _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 = ::iMACD(_symbol, _tf, _ema_fast_period, _ema_slow_period, _signal_period, _applied_price)) == - INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN( + ::iMACD(_symbol, _tf, _ema_fast_period, _ema_slow_period, _signal_period, _applied_price), _mode, _shift); #endif } diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index b813590cd..2ff52c80b 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -92,31 +92,7 @@ class Indi_MFI : public Indicator { #ifdef __MQL4__ return ::iMFI(_symbol, _tf, _period, _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 = ::iMFI(_symbol, _tf, _period, 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(::iMFI(_symbol, _tf, _period, VOLUME_TICK), 0, _shift); #endif } diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 0a1cf9b77..6d90a5423 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -98,31 +98,7 @@ class Indi_Momentum : public Indicator { #ifdef __MQL4__ return ::iMomentum(_symbol, _tf, _period, _ap, _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 = ::iMomentum(_symbol, _tf, _period, _ap)) == 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(::iMomentum(_symbol, _tf, _period, _ap), 0, _shift); #endif } diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index d6764c9a5..0bb664a7b 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -107,31 +107,7 @@ class Indi_OBV : public Indicator { #ifdef __MQL4__ return ::iOBV(_symbol, _tf, _applied, _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 = ::iOBV(_symbol, _tf, _applied)) == 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(::iOBV(_symbol, _tf, _applied), 0, _shift); #endif } diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index 801b4673a..4c5266980 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -91,32 +91,8 @@ class Indi_OsMA : public Indicator { #ifdef __MQL4__ return ::iOsMA(_symbol, _tf, _ema_fast_period, _ema_slow_period, _signal_period, _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 = ::iOsMA(_symbol, _tf, _ema_fast_period, _ema_slow_period, _signal_period, _applied_price)) == - 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( + ::iOsMA(_symbol, _tf, _ema_fast_period, _ema_slow_period, _signal_period, _applied_price), 0, _shift); #endif } diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index 986d07a62..d68848840 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -58,14 +58,14 @@ class Indi_Pivot : public Indicator { */ Indi_Pivot(IndiPivotParams& _p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_INDICATOR, IndicatorData* _indi_src = NULL, int _indi_src_mode = 0) - : Indicator(_p, IndicatorDataParams::GetInstance(9, TYPE_FLOAT, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + : Indicator(_p, IndicatorDataParams::GetInstance(9, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), _indi_src) { Init(); }; 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), + IndicatorDataParams::GetInstance(9, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), _indi_src) { Init(); } @@ -142,32 +142,6 @@ class Indi_Pivot : public Indicator { return GetEntry(_ishift)[_mode]; } - /** - * Checks if indicator entry values are valid. - */ - virtual bool IsValidEntry(IndicatorDataEntry& _entry) { - bool _is_valid = Indicator::IsValidEntry(_entry); - switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { - case IDATA_BUILTIN: - break; - case IDATA_INDICATOR: - // In this mode, price is fetched from given indicator. Such indicator - // must have at least 4 buffers and define OHLC in the first 4 buffers. - // Indi_Price is an example of such indicator. - if (!HasDataSource()) { - GetLogger().Error("Invalid data source!"); - SetUserError(ERR_INVALID_PARAMETER); - _is_valid &= false; - } - break; - default: - SetUserError(ERR_INVALID_PARAMETER); - _is_valid &= false; - break; - } - return _is_valid; - } - /* Getters */ /** diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index c160deb65..6b5baf242 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -87,31 +87,7 @@ class Indi_RVI : public Indicator { #ifdef __MQL4__ return ::iRVI(_symbol, _tf, _period, _mode, _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 = ::iRVI(_symbol, _tf, _period)) == INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN(::iRVI(_symbol, _tf, _period), _mode, _shift); #endif } diff --git a/Indicators/Indi_SAR.mqh b/Indicators/Indi_SAR.mqh index fbbf230e4..343e89221 100644 --- a/Indicators/Indi_SAR.mqh +++ b/Indicators/Indi_SAR.mqh @@ -83,31 +83,7 @@ class Indi_SAR : public Indicator { #ifdef __MQL4__ return ::iSAR(_symbol, _tf, _step, _max, _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 = ::iSAR(_symbol, _tf, _step, _max)) == 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(::iSAR(_symbol, _tf, _step, _max), 0, _shift); #endif } diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index d46bbac61..b1cecdcdc 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -107,31 +107,8 @@ class Indi_StdDev : public Indicator { #ifdef __MQL4__ return ::iStdDev(_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 = ::iStdDev(_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)) { - _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(::iStdDev(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_price), 0, + _shift); #endif } diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index a55e91def..4869ed478 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -102,32 +102,8 @@ class Indi_Stochastic : public Indicator { #ifdef __MQL4__ return ::iStochastic(_symbol, _tf, _kperiod, _dperiod, _slowing, _ma_method, _price_field, _mode, _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 = ::iStochastic(_symbol, _tf, _kperiod, _dperiod, _slowing, _ma_method, _price_field)) == - INVALID_HANDLE) { - SetUserError(ERR_USER_INVALID_HANDLE); - return EMPTY_VALUE; - } else if (Object::IsValid(_obj)) { - _obj.SetHandle(_handle); - } - } - if (Terminal::IsVisualMode()) { - // To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), - // we check the number of calculated data only in visual mode. - int _bars_calc = BarsCalculated(_handle); - if (GetLastError() > 0) { - return EMPTY_VALUE; - } else if (_bars_calc <= 2) { - SetUserError(ERR_USER_INVALID_BUFF_NUM); - return EMPTY_VALUE; - } - } - if (CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; - } - return _res[0]; + INDICATOR_BUILTIN_CALL_AND_RETURN( + ::iStochastic(_symbol, _tf, _kperiod, _dperiod, _slowing, _ma_method, _price_field), _mode, _shift); #endif } diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index d5313d905..04ac5eaf3 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -124,6 +124,8 @@ class Indi_TickMt : public IndicatorTick 0) { @@ -146,6 +148,7 @@ class Indi_TickMt : public IndicatorTick (long)TimeCurrent() * 1000) { + // There won't be items in the future. + return; + } } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { if (history.Size() == 0) { // Time from we'll be getting items will be the time of the first possible item/candle/tick - 1ms. _from_time_ms = item_provider REF_DEREF GetInitialTimeMs() - 1; } else { // Time will be the time of the first valid item - 1ms. + Print("Getting first valid item at index ", first_valid_index); _item = GetItemByIndex(first_valid_index); _from_time_ms = _item.GetTimeMs() - 1; } @@ -196,10 +205,11 @@ class ItemsHistory { item_provider REF_DEREF GetItems(THIS_PTR, _from_time_ms, _dir, _item_count, _items); if (ArraySize(_items) != _item_count) { - // @todo There's really no problem if number of generated items are less that requested. - Print("Error: Wrong number of items generated by item provider. Requested ", _item_count, " items, but got ", - ArraySize(_items)); - DebugBreak(); + // There's really no problem if number of generated items are less that requested. + // @todo However, if there's to many calls for RegenerateHistory then we need to find a way to make it to exit + // earlier. + Print("Regeneration failed. Requested ", _item_count, " items, got ", ArraySize(_items), + ". from index = ", _from_index, ", to index = ", _to_index, ", dir = ", EnumToString(_dir)); return; } @@ -222,7 +232,7 @@ class ItemsHistory { // There was at least one prepended/appended item, so indices relates to existing items. if (history_max_size != 0 && history.Size() >= history_max_size) { // We need to remove first item from the history (the oldest one). - Print("Removing item #", first_valid_index, " from the history."); + // Print("Removing item #", first_valid_index, " from the history."); history.Unset(first_valid_index++); } @@ -253,7 +263,7 @@ class ItemsHistory { // There was at least one prepended/appended item, so indices relates to existing items. if (history_max_size != 0 && history.Size() >= history_max_size) { // We need to remove last item from the history (the newest one). - Print("Removing item #", last_valid_index, " from the history."); + // Print("Removing item #", last_valid_index, " from the history."); history.Unset(last_valid_index--); } @@ -320,7 +330,7 @@ class ItemsHistory { IV GetItemByIndex(int _index, bool _try_regenerate = true) { IV _item; if (!TryGetItemByIndex(_index, _item, _try_regenerate)) { - Print("Error! Given index is outside the range of valid items!"); + Print("Error! Given index ", _index, " is outside the range of valid items!"); DebugBreak(); } return _item; @@ -332,6 +342,7 @@ class ItemsHistory { bool TryGetItemByIndex(int _index, IV& _out_item, bool _try_regenerate = true) { if (history.Size() == 0 || _index < first_valid_index || _index > last_valid_index) { if (!_try_regenerate) { + Print("Missing history. Tried to get item at index ", _index); return false; } // Whether we need to prepend old items or append new ones. diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 37c82ad28..e6700a7f8 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -82,7 +82,7 @@ int OnInit() { ResetLastError(); // Print indicator values. - _result &= PrintIndicators(__FUNCTION__); + //_result &= PrintIndicators(__FUNCTION__); assertEqualOrFail(_LastError, ERR_NO_ERROR, StringFormat("Error: %d", GetLastError())); ResetLastError(); @@ -97,9 +97,9 @@ void OnTick() { IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); if (_candles PTR_DEREF IsNewBar()) { - if (_candles PTR_DEREF GetBarIndex() > 200) { + if (_candles PTR_DEREF GetBarIndex() > 300) { ExpertRemove(); - } + } if (indis.Size() == 0) { return; @@ -120,6 +120,9 @@ void OnTick() { IndicatorData* _indi = iter.Value().Ptr(); IndicatorDataEntry _entry(_indi PTR_DEREF GetEntry()); + // if (_indi.GetType() != INDI_AMA) + // continue; + if (_indi PTR_DEREF Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { if (_entry.IsValid()) { PrintFormat("%s: bar %d: %s", _indi PTR_DEREF GetFullName(), _candles PTR_DEREF GetBars(), From 0b85195e2c4fa22664df6ed310b069060c49b47b Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 12 Oct 2022 18:07:41 +0200 Subject: [PATCH 032/123] WIP. What's left is to find why in MT4 there's a problem with getting candle at shift despite of filled history. Also probably need to fix validations for some indicators. --- Indicator/IndicatorCandle.h | 2 +- Indicator/IndicatorData.h | 26 +++++++++++++++++++++++++- Indicator/IndicatorTf.provider.h | 5 +++++ Indicator/IndicatorTick.provider.h | 5 +++++ Indicators/Indi_Momentum.mqh | 2 ++ Indicators/Indi_RS.mqh | 5 ----- Indicators/Special/Indi_Math.mqh | 2 ++ Storage/ItemsHistory.h | 8 +++++++- 8 files changed, 47 insertions(+), 8 deletions(-) diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index f57fb847c..691164306 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -152,7 +152,7 @@ class IndicatorCandle : public Indicator { * Returns the number of bars on the chart. */ int GetBars() override { - // Will return total number of bars prepended and appended to the history, + // Will return number of bars prepended and appended to the history, // even if those bars were cleaned up because of history's candle limit. return (int)history.GetPeakSize(); } diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 71a45698d..7af8a06f0 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -32,6 +32,16 @@ // Forward class declaration. class IndicatorBase; +// Defines. +#define INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period) \ + if ((int)_indi PTR_DEREF GetBars() < (int)_period) { \ + return DBL_MAX; \ + } + +// We're adding 1 because e.g., shift 1 means that we need two bars to exist in +// history in order to retrieve bar at shift 1. +#define INDI_REQUIRE_SHIFT_OR_RETURN_EMPTY(_indi, _shift) INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _shift + 1) + // Includes. #include "../Bar.struct.h" #include "../DrawIndicator.mqh" @@ -1128,7 +1138,21 @@ class IndicatorData : public IndicatorBase { /** * Returns time of the bar for a given shift. */ - virtual datetime GetBarTime(int _shift = 0) { return GetTick() PTR_DEREF GetBarTime(_shift); } + virtual datetime GetBarTime(int _shift = 0) { + IndicatorData* _indi = GetCandle(false); + + if (_indi == nullptr) _indi = GetTick(false); + + if (_indi == nullptr) { + Print("Error: Neither candle nor tick indicator exists in the hierarch of ", GetFullName(), "!"); + DebugBreak(); + return (datetime)0; + } + + Print("Getting bar time for shift ", _shift, " for ", GetFullName()); + + return _indi PTR_DEREF GetBarTime(_shift); + } /** * Search for a bar by its time. diff --git a/Indicator/IndicatorTf.provider.h b/Indicator/IndicatorTf.provider.h index a8e57c0e6..5197aaa73 100644 --- a/Indicator/IndicatorTf.provider.h +++ b/Indicator/IndicatorTf.provider.h @@ -168,6 +168,11 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { DebugBreak(); } } + + /** + * Returns information about item provider. + */ + string ToString() override { return "IndicatorTf candle provider on " + indi PTR_DEREF GetFullName(); } }; #endif // INDICATOR_TF_PROVIDER_H diff --git a/Indicator/IndicatorTick.provider.h b/Indicator/IndicatorTick.provider.h index 25ecacb39..16659088a 100644 --- a/Indicator/IndicatorTick.provider.h +++ b/Indicator/IndicatorTick.provider.h @@ -64,6 +64,11 @@ class ItemsHistoryTickProvider : public ItemsHistoryItemProvider> { // Method is called if there is a missing item (tick) in the history. We need to regenerate it. indi PTR_DEREF FetchHistoryByStartTimeAndCount(_from_time_ms, _dir, _num_items, _out_arr); } + + /** + * Returns information about item provider. + */ + string ToString() override { return "IndicatorTick tick provider on " + indi PTR_DEREF GetFullName(); } }; #endif // INDICATOR_TICK_PROVIDER_H diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 6d90a5423..de9005172 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -104,6 +104,8 @@ class Indi_Momentum : public Indicator { static double iMomentumOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, int _mode, int _shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period); + double _indi_value_buffer[]; IndicatorDataEntry _entry(_indi.GetModeCount()); diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index 4f399aaee..569b216a3 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -119,9 +119,4 @@ class Indi_RS : public Indicator { } return EMPTY_VALUE; } - - /** - * Checks if indicator entry values are valid. - */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return true; } }; diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index 365ce08af..d0d6c8d11 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -153,6 +153,7 @@ class Indi_Math : public Indicator { static double iMathOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, ENUM_MATH_OP op, unsigned int _mode_1, unsigned int _mode_2, unsigned int _shift_1, unsigned int _shift_2, unsigned int _mode, int _shift, Indi_Math *_obj) { + INDI_REQUIRE_SHIFT_OR_RETURN_EMPTY(_indi, MathMax(_shift_1, _shift_2)); double _val_1 = _indi.GetValue(_mode_1, _shift_1); double _val_2 = _indi.GetValue(_mode_2, _shift_2); return Math::Op(op, _val_1, _val_2); @@ -161,6 +162,7 @@ class Indi_Math : public Indicator { static double iMathOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, MathCustomOpFunction _op, unsigned int _mode_1, unsigned int _mode_2, unsigned int _shift_1, unsigned int _shift_2, unsigned int _mode, int _shift, Indi_Math *_obj) { + INDI_REQUIRE_SHIFT_OR_RETURN_EMPTY(_indi, MathMax(_shift_1, _shift_2)); double _val_1 = _indi.GetValue(_mode_1, _shift_1); double _val_2 = _indi.GetValue(_mode_2, _shift_2); return _op(_val_1, _val_2); diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index 8772000e5..191aa7bb6 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -73,6 +73,11 @@ class ItemsHistoryItemProvider : public Dynamic { // first item. return (long)TimeCurrent() * 1000; } + + /** + * Returns information about item provider. + */ + virtual string ToString() { return "Abstract items history item provider."; } }; /** @@ -330,7 +335,8 @@ class ItemsHistory { IV GetItemByIndex(int _index, bool _try_regenerate = true) { IV _item; if (!TryGetItemByIndex(_index, _item, _try_regenerate)) { - Print("Error! Given index ", _index, " is outside the range of valid items!"); + Print("Error! Given index ", _index, + " is outside the range of valid items! Errored: ", item_provider REF_DEREF ToString()); DebugBreak(); } return _item; From fdaf6e75aba40419e90ab73fbe555e110bfda167 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 13 Oct 2022 18:21:23 +0200 Subject: [PATCH 033/123] WIP. Fixing indicators that depends on candles that not yet occured. --- Indicator/Indicator.define.h | 12 +++++ Indicator/IndicatorData.h | 10 ---- Indicators/Bitwise/Indi_Pattern.mqh | 6 ++- Indicators/Indi_Momentum.mqh | 2 + Indicators/Indi_RSI.mqh | 2 + Storage/ItemsHistory.h | 73 +++++++++++++++++++++++++---- tests/IndicatorsTest.mq5 | 1 + 7 files changed, 86 insertions(+), 20 deletions(-) diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index 72e4333d5..528399783 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -127,3 +127,15 @@ return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; \ } \ return _res[0]; + +#define INDI_REQUIRE_BARS_OR_RETURN(_indi, _period, _ret) \ + if ((int)_indi PTR_DEREF GetBars() < (int)_period) { \ + return _ret; \ + } + +#define INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period) INDI_REQUIRE_BARS_OR_RETURN(_indi, _period, DBL_MAX) + +// We're adding 1 because e.g., shift 1 means that we need two bars to exist in +// history in order to retrieve bar at shift 1. +#define INDI_REQUIRE_SHIFT_OR_RETURN(_indi, _shift, _ret) INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _shift + 1) +#define INDI_REQUIRE_SHIFT_OR_RETURN_EMPTY(_indi, _shift) INDI_REQUIRE_SHIFT_OR_RETURN(_indi, _shift, DBL_MAX) diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 7af8a06f0..86f4f5696 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -32,16 +32,6 @@ // Forward class declaration. class IndicatorBase; -// Defines. -#define INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period) \ - if ((int)_indi PTR_DEREF GetBars() < (int)_period) { \ - return DBL_MAX; \ - } - -// We're adding 1 because e.g., shift 1 means that we need two bars to exist in -// history in order to retrieve bar at shift 1. -#define INDI_REQUIRE_SHIFT_OR_RETURN_EMPTY(_indi, _shift) INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _shift + 1) - // Includes. #include "../Bar.struct.h" #include "../DrawIndicator.mqh" diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index 6fb005d61..f5df8fff3 100644 --- a/Indicators/Bitwise/Indi_Pattern.mqh +++ b/Indicators/Bitwise/Indi_Pattern.mqh @@ -23,6 +23,7 @@ // Includes. #include "../../Bar.struct.h" #include "../../BufferStruct.mqh" +#include "../../Indicator/Indicator.define.h" #include "../../Indicator/Indicator.h" #include "../../Pattern.struct.h" #include "../../Serializer/Serializer.h" @@ -87,6 +88,9 @@ class Indi_Pattern : public Indicator { int i; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); + + INDI_REQUIRE_SHIFT_OR_RETURN(GetCandle(), _max_modes + _ishift, WRONG_VALUE); + BarOHLC _ohlcs[8]; switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -150,5 +154,5 @@ class Indi_Pattern : public Indicator { * @return * Returns true if entry is valid (has valid values), otherwise false. */ - virtual bool IsValidEntry(IndicatorDataEntry& _entry) { return !_entry.HasValue(INT_MAX); } + virtual bool IsValidEntry(IndicatorDataEntry& _entry) { return !_entry.HasValue(WRONG_VALUE); } }; diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index de9005172..635cf03cc 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -114,6 +114,8 @@ class Indi_Momentum : public Indicator { ArrayResize(_indi_value_buffer, _period); for (int i = 0; i < (int)_period; i++) { + Print(": Getting data from ", _indi PTR_DEREF GetFullName(), " from shift ", i); + // Getting value from single, selected buffer. _indi_value_buffer[i] = _indi[i].GetValue(_mode); } diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 55aee8ba9..5739e4f6a 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -173,6 +173,8 @@ class Indi_RSI : public Indicator { static double iRSIOnIndicator(Indi_RSI *_target, IndicatorData *_source, string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_target, _period + _shift + 1); // +1 because of _bar_time_prev. + 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) { diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index 191aa7bb6..562430fae 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -165,6 +165,10 @@ class ItemsHistory { * Will regenerate items from item provider. "_dir" indicates if we have to prepend or append items. */ void RegenerateHistory(int _from_index, int _to_index, ENUM_ITEMS_HISTORY_DIRECTION _dir) { +#ifdef __debug_items_history__ + Print("RegenerateHistory(", _from_index, ", ", _to_index, ", ", EnumToString(_dir), "), ", GetInfo()); +#endif + static ARRAY(IV, _items); // Items generated by provider. ArrayResize(_items, 0); @@ -175,12 +179,19 @@ class ItemsHistory { // Calculating time to be passed to GetItems(). if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { if (history.Size() == 0) { +#ifdef __debug_items_history__ + Print("RegenerateHistory: Getting initial time from item provider"); +#endif + // Time from we'll be getting items will be the time of the first possible item/candle/tick. _from_time_ms = item_provider REF_DEREF GetInitialTimeMs(); } else { +#ifdef __debug_items_history__ + Print("RegenerateHistory: Getting last valid item at index ", last_valid_index); +#endif + // Time will be the time of last valid item + item's length + 1ms. // Note that ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. - Print("Getting last valid item at index ", last_valid_index); _item = GetItemByIndex(last_valid_index); _from_time_ms = _item.GetTimeMs() + _item.GetLengthMs() + 1; } @@ -197,7 +208,7 @@ class ItemsHistory { _from_time_ms = item_provider REF_DEREF GetInitialTimeMs() - 1; } else { // Time will be the time of the first valid item - 1ms. - Print("Getting first valid item at index ", first_valid_index); + Print("RegenerateHistory: Getting first valid item at index ", first_valid_index); _item = GetItemByIndex(first_valid_index); _from_time_ms = _item.GetTimeMs() - 1; } @@ -210,11 +221,15 @@ class ItemsHistory { item_provider REF_DEREF GetItems(THIS_PTR, _from_time_ms, _dir, _item_count, _items); if (ArraySize(_items) != _item_count) { - // There's really no problem if number of generated items are less that requested. - // @todo However, if there's to many calls for RegenerateHistory then we need to find a way to make it to exit - // earlier. - Print("Regeneration failed. Requested ", _item_count, " items, got ", ArraySize(_items), - ". from index = ", _from_index, ", to index = ", _to_index, ", dir = ", EnumToString(_dir)); +// There's really no problem if number of generated items are less than +// requested. +// @todo However, if there's too many calls for RegenerateHistory then we +// need to find a way to make it exit earlier. +#ifdef __debug_items_history__ + Print("RegenerateHistory: Notice: Requested ", _item_count, " historic items, got ", ArraySize(_items), + ". from index = ", _from_index, ", to index = ", _to_index, ", dir = ", EnumToString(_dir), " (", GetInfo(), + ")"); +#endif return; } @@ -227,6 +242,15 @@ class ItemsHistory { } } + string GetInfo() { + string _out; + _out += "first_valid_index_ever = " + IntegerToString(first_valid_index_ever) + ", "; + _out += "first_valid_index = " + IntegerToString(first_valid_index) + ", "; + _out += "current_index = " + IntegerToString(current_index) + ", "; + _out += "history_size = " + IntegerToString(history.Size()); + return _out; + } + /** * Appends item to the history and increments history shift, so current item will be the added one. * @@ -242,6 +266,10 @@ class ItemsHistory { } if (_allow_regenerate && last_valid_index < current_index) { +#ifdef __debug_items_history__ + Print("Append: Missing history between index ", last_valid_index, " and ", current_index, + ". We will try to regenerate it."); +#endif // May call Append() multiple times with regenerated items. RegenerateHistory(last_valid_index, current_index, ITEMS_HISTORY_DIRECTION_BACKWARD); @@ -273,6 +301,11 @@ class ItemsHistory { } if (_allow_regenerate && first_valid_index_ever < current_index) { +#ifdef __debug_items_history__ + Print("Prepend: Missing history between index ", first_valid_index, " and ", current_index, + ". We will try to regenerate it."); +#endif + // May call Prepend() multiple times with regenerated items. RegenerateHistory(first_valid_index, current_index, ITEMS_HISTORY_DIRECTION_FORWARD); @@ -319,6 +352,10 @@ class ItemsHistory { return false; } +#ifdef __debug_items_history__ + Print("EnsureShiftExists(", _shift, ")"); +#endif + int _index = GetShiftIndex(_shift); if (_index < first_valid_index) { RegenerateHistory(_index, first_valid_index - 1, ITEMS_HISTORY_DIRECTION_BACKWARD); @@ -334,8 +371,13 @@ class ItemsHistory { */ IV GetItemByIndex(int _index, bool _try_regenerate = true) { IV _item; + +#ifdef __debug_items_history__ + Print("GetItemByIndex(", _index, ", try_regenerate = ", _try_regenerate, ")"); +#endif + if (!TryGetItemByIndex(_index, _item, _try_regenerate)) { - Print("Error! Given index ", _index, + Print("Error: Given index ", _index, " is outside the range of valid items! Errored: ", item_provider REF_DEREF ToString()); DebugBreak(); } @@ -348,9 +390,18 @@ class ItemsHistory { bool TryGetItemByIndex(int _index, IV& _out_item, bool _try_regenerate = true) { if (history.Size() == 0 || _index < first_valid_index || _index > last_valid_index) { if (!_try_regenerate) { - Print("Missing history. Tried to get item at index ", _index); + // Print("Notice: Missing history. Tried to get item at index ", _index); return false; } + + if (_index == -1) { + DebugBreak(); + } + +#ifdef __debug_items_history__ + Print("TryGetItemByIndex(", _index, ", try_regenerate = ", _try_regenerate, ")"); +#endif + // Whether we need to prepend old items or append new ones. ENUM_ITEMS_HISTORY_DIRECTION _dir = _index < first_valid_index ? ITEMS_HISTORY_DIRECTION_BACKWARD : ITEMS_HISTORY_DIRECTION_FORWARD; @@ -404,6 +455,10 @@ class ItemsHistory { * Returns bar date and time for the given shift. */ datetime GetItemTimeByShift(int _shift) { +#ifdef __debug_items_history__ + Print("GetItemTimeByShift(", _shift, "), ", GetInfo()); +#endif + if (!EnsureShiftExists(_shift)) { // There won't be item at given shift. return (datetime)0; diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index e6700a7f8..88237716f 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -27,6 +27,7 @@ // Defines. // #define __debug__ // Enables debug. // #define __debug_verbose__ +#define __debug_items_history__ // Forward declaration. struct DataParamEntry; From 7e4622529c8024602b9d4be7bf57f7d8e20bcab1 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 14 Oct 2022 17:27:19 +0200 Subject: [PATCH 034/123] WIP. Fixing indicator tests. --- Indicator/IndicatorData.h | 2 + Indicator/IndicatorRenko.h | 2 +- Indicator/IndicatorTick.h | 52 +++++++++++++------- Indicator/tests/IndicatorTick.test.mq5 | 18 ++++--- Indicator/tests/classes/IndicatorTickDummy.h | 2 +- Indicators/Indi_BWMFI.mqh | 1 - Indicators/Indi_DetrendedPrice.mqh | 1 + Indicators/Indi_Envelopes.mqh | 2 + Storage/ItemsHistory.h | 9 ++-- tests/IndicatorsTest.mq5 | 4 +- 10 files changed, 59 insertions(+), 34 deletions(-) diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 86f4f5696..a93ede7a1 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1139,7 +1139,9 @@ class IndicatorData : public IndicatorBase { return (datetime)0; } +#ifdef __debug_items_history__ Print("Getting bar time for shift ", _shift, " for ", GetFullName()); +#endif return _indi PTR_DEREF GetBarTime(_shift); } diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index 0e2c4200e..4fb02406a 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -174,7 +174,7 @@ class IndicatorRenko : public IndicatorCandle { */ unsigned int GetSuitableDataSourceTypes() override { return INDI_SUITABLE_DS_TYPE_EXPECT_NONE; } + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } + /** * Returns time of the bar for a given shift. */ @@ -167,16 +172,9 @@ class IndicatorTick : public Indicator { }; /** - * @todo + * Returns points to ticks history. */ - IndicatorDataEntry TickToEntry(long _timestamp, TickAB& _tick) { - IndicatorDataEntry _entry(2); - _entry.timestamp = _timestamp; - _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; - } + ItemsHistory, TCP>* GetHistory() { return &history; } /** * @todo @@ -197,16 +195,23 @@ class IndicatorTick : public Indicator { * Returns DataParamEntry struct filled with a single value. */ 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(); + + TickTAB _tick; + + if (history.TryGetItemByShift(_ishift, _tick)) { + switch (_mode) { + case INDI_TICK_MODE_PRICE_ASK: + return _tick.ask; + case INDI_TICK_MODE_PRICE_BID: + return _tick.bid; + default: + Print("Invalid mode while trying to get entry from IndicatorTick!"); + DebugBreak(); + } } - int _ishift = _shift >= 0 ? _shift : itparams.GetShift(); - // @todo Support for shift. - return GetEntry((datetime)0)[_mode]; + return DBL_MAX; } /** @@ -241,4 +246,17 @@ class IndicatorTick : public Indicator { virtual IndicatorTick* GetTickIndicator() { return THIS_PTR; } }; +/** + * Converts TickAB into IndicatorDataEntry. + */ +template +IndicatorDataEntry TickToEntry(long _timestamp, TickAB& _tick) { + IndicatorDataEntry _entry(2); + _entry.timestamp = _timestamp; + _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; +} + #endif diff --git a/Indicator/tests/IndicatorTick.test.mq5 b/Indicator/tests/IndicatorTick.test.mq5 index 04a8da463..0d39b3030 100644 --- a/Indicator/tests/IndicatorTick.test.mq5 +++ b/Indicator/tests/IndicatorTick.test.mq5 @@ -25,6 +25,7 @@ */ // Includes. +#include "../../Platform.h" #include "../../Test.mqh" #include "../IndicatorTick.h" #include "classes/IndicatorTickDummy.h" @@ -33,15 +34,18 @@ * Implements OnInit(). */ int OnInit() { - IndicatorTickDummy _indi_tick(_Symbol); + Platform::Init(); + + Ref _indi_tick = new IndicatorTickDummy(_Symbol); + Platform::Add(_indi_tick.Ptr()); + long _time = 1; + for (double _price = 0.1; _price <= 2.0; _price += 0.1) { - MqlTick _tick; - _tick.time = (datetime)_time++; - _tick.ask = _price; - _tick.bid = _price; - _indi_tick.SetTick(_tick, _tick.time); + TickTAB _tick(_time++ * 1000, _price, _price); + _indi_tick REF_DEREF GetHistory() PTR_DEREF Append(_tick); } - // Print(_indi_tick.ToString()); + + // Print(_indi_tick REF_DEREF ToString()); return (INIT_SUCCEEDED); } diff --git a/Indicator/tests/classes/IndicatorTickDummy.h b/Indicator/tests/classes/IndicatorTickDummy.h index 3b5e58a22..14e459ca0 100644 --- a/Indicator/tests/classes/IndicatorTickDummy.h +++ b/Indicator/tests/classes/IndicatorTickDummy.h @@ -39,7 +39,7 @@ struct IndicatorTickDummyParams : IndicatorParams { }; // Dummy tick-based indicator. -class IndicatorTickDummy : public IndicatorTick { +class IndicatorTickDummy : public IndicatorTick> { public: IndicatorTickDummy(string _symbol, int _shift = 0, string _name = "") : IndicatorTick(_symbol, INDI_TICK, _shift, _name) {} diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index 37fcf665d..becda3043 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -93,7 +93,6 @@ class Indi_BWMFI : public Indicator { */ 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. */ diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index 229dc2e31..d3ba956bb 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -83,6 +83,7 @@ class Indi_DetrendedPrice : public Indicator { * Built-in version of DPO. */ static double iDPO(IndicatorData *_indi, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period + _shift); 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); } diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 4018c4a6d..4c0023c6c 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -150,6 +150,8 @@ class Indi_Envelopes : public Indicator { int _mode, // (MT4 _mode): 0 - MODE_MAIN, 1 - MODE_UPPER, 2 - MODE_LOWER; (MT5 // _mode): 0 - UPPER_LINE, 1 - LOWER_LINE int _shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, _shift + _ma_shift + _ma_period); + return iEnvelopesOnArray(_source.GetSpecificAppliedPriceValueStorage(_ap, _target), 0, _ma_period, _ma_method, _ma_shift, _deviation, _mode, _shift, _target PTR_DEREF GetCache()); } diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index 562430fae..67d5fe233 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -207,8 +207,11 @@ class ItemsHistory { // Time from we'll be getting items will be the time of the first possible item/candle/tick - 1ms. _from_time_ms = item_provider REF_DEREF GetInitialTimeMs() - 1; } else { - // Time will be the time of the first valid item - 1ms. +#ifdef __debug_items_history__ Print("RegenerateHistory: Getting first valid item at index ", first_valid_index); +#endif + + // Time will be the time of the first valid item - 1ms. _item = GetItemByIndex(first_valid_index); _from_time_ms = _item.GetTimeMs() - 1; } @@ -394,10 +397,6 @@ class ItemsHistory { return false; } - if (_index == -1) { - DebugBreak(); - } - #ifdef __debug_items_history__ Print("TryGetItemByIndex(", _index, ", try_regenerate = ", _try_regenerate, ")"); #endif diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 88237716f..9a70fe629 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -27,7 +27,7 @@ // Defines. // #define __debug__ // Enables debug. // #define __debug_verbose__ -#define __debug_items_history__ +// #define __debug_items_history__ // Forward declaration. struct DataParamEntry; @@ -98,7 +98,7 @@ void OnTick() { IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); if (_candles PTR_DEREF IsNewBar()) { - if (_candles PTR_DEREF GetBarIndex() > 300) { + if (_candles PTR_DEREF GetBarIndex() > 500) { ExpertRemove(); } From 13fa80305eac46eb7d1a9a2a2ef29ac4b62c0c0a Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 25 Oct 2022 12:55:23 +0200 Subject: [PATCH 035/123] WIP. Looks like indicators' custom buffer requires refactoring and use ItemsHistory class instead of BufferStruct. We'll try to fix other tests before another refactor. --- .github/workflows/test-indicators.yml | 3 ++- Indicator/Indicator.h | 17 +++-------------- Indicator/IndicatorData.h | 18 +++++++++--------- Indicator/IndicatorRenko.h | 2 +- Indicator/IndicatorTick.h | 4 ++-- Indicator/tests/IndicatorCandle.test.mq5 | 2 +- Indicators/Indi_DEMA.mqh | 4 ++++ Indicators/Indi_Momentum.mqh | 2 +- 8 files changed, 23 insertions(+), 29 deletions(-) diff --git a/.github/workflows/test-indicators.yml b/.github/workflows/test-indicators.yml index 782266386..5388e7bdc 100644 --- a/.github/workflows/test-indicators.yml +++ b/.github/workflows/test-indicators.yml @@ -72,7 +72,6 @@ jobs: - Indi_ColorCandlesDaily.test - Indi_ColorLine.test - Indi_CustomMovingAverage.test - - Indi_DEMA.test - Indi_DeMarker.test - Indi_Demo.test - Indi_DetrendedPrice.test @@ -116,6 +115,8 @@ jobs: - Indi_WilliamsAD.test - Indi_ZigZag.test - Indi_ZigZagColor.test + # Requires refactoring: + # - Indi_DEMA.test steps: - uses: actions/download-artifact@v2 with: diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index a7b1da4c4..9610e16aa 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -474,7 +474,9 @@ class Indicator : public IndicatorData { switch (_action) { case INDI_ACTION_CLEAR_CACHE: _arg1 = _arg1 > 0 ? _arg1 : TimeCurrent(); - idata.Clear(_arg1); + Print("Action not yet implemented!"); + DebugBreak(); + // idata.Clear(_arg1); return true; default: GetLogger().Error(StringFormat("Invalid Indicator action: %s!", EnumToString(_action), __FUNCTION_LINE__)); @@ -511,19 +513,6 @@ class Indicator : public IndicatorData { istate.is_changed = true; } - /** - * Adds entry to the indicator's buffer. Invalid entry won't be added. - */ - bool AddEntry(IndicatorDataEntry& entry, int _shift = 0) { - if (!entry.IsValid()) return false; - - datetime timestamp = GetBarTime(_shift); - entry.timestamp = timestamp; - idata.Add(entry, timestamp); - - return true; - } - /* Data representation methods */ /* Virtual methods */ diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index a93ede7a1..e7c572bda 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -493,11 +493,11 @@ class IndicatorData : public IndicatorBase { /** * Get current (or by given date and time) open price depending on the operation type. */ - double GetOpenOffer(ENUM_ORDER_TYPE _cmd, datetime _dt = 0) { + double GetOpenOffer(ENUM_ORDER_TYPE _cmd) { // 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); + return _cmd == ORDER_TYPE_BUY ? GetAsk() : GetBid(); } /** @@ -1111,9 +1111,14 @@ class IndicatorData : public IndicatorBase { } /** - * Gets ask price for a given date and time. Return current ask price if _dt wasn't passed or is 0. + * Gets ask price for a given shift. Return current ask price if _shift wasn't passed or is 0. */ - virtual double GetAsk(datetime _dt = 0) { return GetTick() PTR_DEREF GetAsk(_dt); } + virtual double GetAsk(int _shift = 0) { return GetTick() PTR_DEREF GetAsk(_shift); } + + /** + * Gets bid price for a given shift. Return current bid price if _shift wasn't passed or is 0. + */ + virtual double GetBid(int _shift = 0) { return GetTick() PTR_DEREF GetBid(_shift); } /** * Returns the number of bars on the chart. @@ -1155,11 +1160,6 @@ class IndicatorData : public IndicatorBase { 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. diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index 4fb02406a..ef21c5e20 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -174,7 +174,7 @@ class IndicatorRenko : public IndicatorCandle { /** * 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); } + virtual double GetAsk(int _shift = 0) { return GetEntryValue(INDI_TICK_MODE_PRICE_ASK, _shift).Get(); } /** * Gets bid price for a given date and time. Return current bid price if _dt wasn't passed or is 0. */ - virtual double GetBid(datetime _dt = 0) { return GetEntry(_dt).GetValue(INDI_TICK_MODE_PRICE_BID); } + virtual double GetBid(int _shift = 0) { return GetEntryValue(INDI_TICK_MODE_PRICE_BID, _shift).Get(); } /** * Returns value storage of given kind. diff --git a/Indicator/tests/IndicatorCandle.test.mq5 b/Indicator/tests/IndicatorCandle.test.mq5 index e4eddf465..2a98284a3 100644 --- a/Indicator/tests/IndicatorCandle.test.mq5 +++ b/Indicator/tests/IndicatorCandle.test.mq5 @@ -68,4 +68,4 @@ void OnTick() { _ohlc2.close, _ohlc1.close, "Difference between consecutive OHLC values after invalidating and then regenerating the candle!"); } -} \ No newline at end of file +} diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index 61ae9faf1..d14f4fdfd 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -88,7 +88,11 @@ class Indi_DEMA : public Indicator { * 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 } /** diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 635cf03cc..cf80d85cb 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -114,7 +114,7 @@ class Indi_Momentum : public Indicator { ArrayResize(_indi_value_buffer, _period); for (int i = 0; i < (int)_period; i++) { - Print(": Getting data from ", _indi PTR_DEREF GetFullName(), " from shift ", i); + // Print(": Getting data from ", _indi PTR_DEREF GetFullName(), " from shift ", i); // Getting value from single, selected buffer. _indi_value_buffer[i] = _indi[i].GetValue(_mode); From 0e9563e607625ceeb683c4aa7ee6a151e6960642 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 25 Oct 2022 17:45:12 +0200 Subject: [PATCH 036/123] WIP. Fixing inconsistencies in shift given into indicators' params and the one passed to GetEntry/GetEntryAlter(). Also adding requirement of minimum bars for OnCalculate based indicators. --- Indicator/Indicator.define.h | 2 +- Indicator/Indicator.h | 6 +++--- Indicator/IndicatorCandle.h | 4 ++-- Indicator/IndicatorData.h | 15 +-------------- Indicator/IndicatorTick.h | 2 +- Indicators/Bitwise/Indi_Candle.mqh | 4 ++-- Indicators/Bitwise/Indi_Pattern.mqh | 4 ++-- Indicators/Indi_AC.mqh | 4 ++-- Indicators/Indi_AD.mqh | 4 ++-- Indicators/Indi_ADX.mqh | 4 ++-- Indicators/Indi_ADXW.mqh | 4 ++-- Indicators/Indi_AMA.mqh | 6 +++--- Indicators/Indi_AO.mqh | 4 ++-- Indicators/Indi_ASI.mqh | 4 ++-- Indicators/Indi_ATR.mqh | 4 ++-- Indicators/Indi_Alligator.mqh | 4 ++-- Indicators/Indi_AppliedPrice.mqh | 4 ++-- Indicators/Indi_BWMFI.mqh | 16 +++++++++------- Indicators/Indi_BWZT.mqh | 4 ++-- Indicators/Indi_Bands.mqh | 4 ++-- Indicators/Indi_BearsPower.mqh | 4 ++-- Indicators/Indi_BullsPower.mqh | 4 ++-- Indicators/Indi_CCI.mqh | 4 ++-- Indicators/Indi_CHO.mqh | 4 ++-- Indicators/Indi_CHV.mqh | 4 ++-- Indicators/Indi_ColorBars.mqh | 4 ++-- Indicators/Indi_ColorCandlesDaily.mqh | 4 ++-- Indicators/Indi_ColorLine.mqh | 4 ++-- Indicators/Indi_CustomMovingAverage.mqh | 4 ++-- Indicators/Indi_DEMA.mqh | 4 ++-- Indicators/Indi_DeMarker.mqh | 4 ++-- Indicators/Indi_Demo.mqh | 4 ++-- Indicators/Indi_DetrendedPrice.mqh | 4 ++-- Indicators/Indi_Drawer.mqh | 4 ++-- Indicators/Indi_Envelopes.mqh | 4 ++-- Indicators/Indi_Force.mqh | 4 ++-- Indicators/Indi_FractalAdaptiveMA.mqh | 4 ++-- Indicators/Indi_Fractals.mqh | 4 ++-- Indicators/Indi_Gator.mqh | 4 ++-- Indicators/Indi_HeikenAshi.mqh | 4 ++-- Indicators/Indi_Ichimoku.mqh | 4 ++-- Indicators/Indi_Killzones.mqh | 4 ++-- Indicators/Indi_MA.mqh | 5 +++-- Indicators/Indi_MACD.mqh | 4 ++-- Indicators/Indi_MFI.mqh | 4 ++-- Indicators/Indi_MassIndex.mqh | 4 ++-- Indicators/Indi_Momentum.mqh | 4 ++-- Indicators/Indi_OBV.mqh | 4 ++-- Indicators/Indi_OsMA.mqh | 4 ++-- Indicators/Indi_Pivot.mqh | 6 +++--- Indicators/Indi_PriceChannel.mqh | 4 ++-- Indicators/Indi_PriceFeeder.mqh | 4 ++-- Indicators/Indi_PriceVolumeTrend.mqh | 4 ++-- Indicators/Indi_RS.mqh | 4 ++-- Indicators/Indi_RSI.mqh | 4 ++-- Indicators/Indi_RVI.mqh | 4 ++-- Indicators/Indi_RateOfChange.mqh | 4 ++-- Indicators/Indi_SAR.mqh | 4 ++-- Indicators/Indi_StdDev.mqh | 6 ++++-- Indicators/Indi_Stochastic.mqh | 4 ++-- Indicators/Indi_TEMA.mqh | 4 ++-- Indicators/Indi_TRIX.mqh | 4 ++-- Indicators/Indi_UltimateOscillator.mqh | 9 +++++---- Indicators/Indi_VIDYA.mqh | 4 ++-- Indicators/Indi_VROC.mqh | 4 ++-- Indicators/Indi_Volumes.mqh | 4 ++-- Indicators/Indi_WPR.mqh | 4 ++-- Indicators/Indi_WilliamsAD.mqh | 4 ++-- Indicators/Indi_ZigZag.mqh | 4 ++-- Indicators/Indi_ZigZagColor.mqh | 4 ++-- Indicators/OHLC/Indi_OHLC.mqh | 4 ++-- Indicators/Price/Indi_Price.mqh | 4 ++-- Indicators/Special/Indi_Custom.mqh | 4 ++-- Indicators/Special/Indi_Math.mqh | 4 ++-- Indicators/Tick/Indi_TickMt.mqh | 2 +- 75 files changed, 162 insertions(+), 169 deletions(-) diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index 528399783..d2ef7bce3 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -129,7 +129,7 @@ return _res[0]; #define INDI_REQUIRE_BARS_OR_RETURN(_indi, _period, _ret) \ - if ((int)_indi PTR_DEREF GetBars() < (int)_period) { \ + if ((int)(_indi)PTR_DEREF GetBars() < (int)_period) { \ return _ret; \ } diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 9610e16aa..c2a9af4a4 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -575,9 +575,9 @@ class Indicator : public IndicatorData { * @return * Returns IndicatorDataEntry struct filled with indicator values. */ - IndicatorDataEntry GetEntry(long _index = -1) override { + IndicatorDataEntry GetEntry(int _index = 0) override { ResetLastError(); - int _ishift = _index >= 0 ? (int)_index : iparams.GetShift(); + int _ishift = _index + iparams.GetShift(); long _bar_time; _bar_time = GetBarTime(_ishift); @@ -679,7 +679,7 @@ class Indicator : public IndicatorData { * Returns DataParamEntry struct filled with a single value. */ IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) override { - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); return GetEntry(_ishift)[_mode]; } diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 691164306..78c603869 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -244,9 +244,9 @@ class IndicatorCandle : public Indicator { * @return * Returns IndicatorDataEntry struct filled with indicator values. */ - IndicatorDataEntry GetEntry(long _index = -1) override { + IndicatorDataEntry GetEntry(int _shift = 0) override { ResetLastError(); - int _ishift = _index >= 0 ? (int)_index : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); CandleOCTOHLC _candle = history.GetItemByShift(_ishift); return CandleToEntry(_candle.GetTime(), _candle); } diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index e7c572bda..d81097139 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -165,19 +165,6 @@ class IndicatorData : public IndicatorBase { return GetEntry(_index); } - /** - * Access indicator entry data using [] operator via datetime. - */ - IndicatorDataEntry operator[](datetime _dt) { - if (!bool(flags | INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { - Print(GetFullName(), " is not indexable by timestamp!"); - DebugBreak(); - IndicatorDataEntry _default; - return _default; - } - return GetEntry(_dt); - } - IndicatorDataEntry operator[](ENUM_INDICATOR_INDEX _index) { return GetEntry((int)_index); } /* Getters */ @@ -1199,7 +1186,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's struct value via index. */ - virtual IndicatorDataEntry GetEntry(long _index = 0) = NULL; + virtual IndicatorDataEntry GetEntry(int _index = 0) = NULL; /** * Returns the indicator's struct value via timestamp. diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 3846203e9..b3a7b1092 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -195,7 +195,7 @@ class IndicatorTick : public Indicator { * Returns DataParamEntry struct filled with a single value. */ IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) override { - int _ishift = _shift >= 0 ? _shift : itparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); TickTAB _tick; diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index b6397384a..95707754e 100644 --- a/Indicators/Bitwise/Indi_Candle.mqh +++ b/Indicators/Bitwise/Indi_Candle.mqh @@ -91,9 +91,9 @@ class Indi_Candle : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); BarOHLC _ohlcs[1]; switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index f5df8fff3..948c6aff2 100644 --- a/Indicators/Bitwise/Indi_Pattern.mqh +++ b/Indicators/Bitwise/Indi_Pattern.mqh @@ -84,9 +84,9 @@ class Indi_Pattern : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int i; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); INDI_REQUIRE_SHIFT_OR_RETURN(GetCandle(), _max_modes + _ishift, WRONG_VALUE); diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index 9d577bb81..74ad06e2c 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -108,9 +108,9 @@ class Indi_AC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) override { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) override { IndicatorDataEntryValue _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_AC::iAC(GetSymbol(), GetTf(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index 87e52e384..8fb4cf664 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -96,9 +96,9 @@ class Indi_AD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_AD::iAD(GetSymbol(), GetTf(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index a64118c60..d171e4f95 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -116,9 +116,9 @@ class Indi_ADX : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_ADX::iADX(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _mode, _ishift, THIS_PTR); diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index a46d95977..8fc6a9494 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -266,9 +266,9 @@ class Indi_ADXW : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _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); diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index 4d39aefb6..30c7e6150 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -45,7 +45,7 @@ struct IndiAMAParams : IndicatorParams { // Defaulting to on-indicator mode (will use real ticks from platform via IndicatorTickReal). SetShift(_shift); if (custom_indi_name == "") { - SetCustomIndicatorName("Examples\\AMA"); + SetCustomIndicatorName("Examples\\AMA"); } }; IndiAMAParams(IndiAMAParams &_params) { THIS_REF = _params; } @@ -229,9 +229,9 @@ class Indi_AMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_AMA::iAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index 214e4698c..74c755b45 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -107,9 +107,9 @@ class Indi_AO : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_AO::iAO(GetSymbol(), GetTf(), _ishift, _mode, THIS_PTR); diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index cf0ff9270..160686eff 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -206,9 +206,9 @@ class Indi_ASI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ICUSTOM: diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index 090ce1541..ca40c4661 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -90,9 +90,9 @@ class Indi_ATR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_ATR::iATR(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index 122241c8d..446035319 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -152,9 +152,9 @@ class Indi_Alligator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); #ifdef __MQL4__ if (_mode == 0) { // In MQL4 mode 0 should be treated as mode 1 as Alligator buffers starts from index 1. diff --git a/Indicators/Indi_AppliedPrice.mqh b/Indicators/Indi_AppliedPrice.mqh index bbdbccc27..fa910dc8b 100644 --- a/Indicators/Indi_AppliedPrice.mqh +++ b/Indicators/Indi_AppliedPrice.mqh @@ -87,9 +87,9 @@ class Indi_AppliedPrice : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_INDICATOR: if (HasDataSource()) { diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index becda3043..f7e8f52c1 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -117,9 +117,9 @@ class Indi_BWMFI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = BWMFI_BUFFER, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = BWMFI_BUFFER, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: @@ -142,9 +142,11 @@ class Indi_BWMFI : public Indicator { void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { Indicator::GetEntryAlter(_entry, _shift); #ifdef __MQL4__ + Print(GetVolume(_shift), ", ", GetVolume(_shift + 1), " | ", GetValue(BWMFI_BUFFER, _shift), " > ", + GetValue(BWMFI_BUFFER, _shift + 1)); // @see: https://en.wikipedia.org/wiki/Market_facilitation_index - bool _vol_up = GetVolume(_shift) > GetVolume(_shift); - bool _val_up = GetValue(BWMFI_BUFFER, _shift) > GetValue(BWMFI_BUFFER, _shift); + bool _vol_up = GetVolume(_shift) > GetVolume(_shift + 1); + bool _val_up = GetValue(BWMFI_BUFFER, _shift) > GetValue(BWMFI_BUFFER, _shift + 1); double _histcolor = EMPTY_VALUE; switch (_vol_up) { case true: @@ -182,8 +184,8 @@ class Indi_BWMFI : public Indicator { * @return * Returns true if entry is valid (has valid values), otherwise false. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { - return _entry[(int)BWMFI_BUFFER] > 0 && _entry[(int)BWMFI_HISTCOLOR] >= 0 && !_entry.HasValue(DBL_MAX) && - !_entry.HasValue(EMPTY_VALUE); + bool IsValidEntry(IndicatorDataEntry &_entry) override { + return _entry.GetValue((int)BWMFI_BUFFER) > 0 && _entry.GetValue((int)BWMFI_HISTCOLOR) >= 0 && + !_entry.HasValue(DBL_MAX); } }; diff --git a/Indicators/Indi_BWZT.mqh b/Indicators/Indi_BWZT.mqh index 7ed2c0d16..d05f05624 100644 --- a/Indicators/Indi_BWZT.mqh +++ b/Indicators/Indi_BWZT.mqh @@ -251,9 +251,9 @@ class Indi_BWZT : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index edbeba804..090574ef6 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -255,9 +255,9 @@ class Indi_Bands : public Indicator { * 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 = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = BAND_BASE, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Bands::iBands(GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index 6c7bc0855..27efa2cae 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -91,9 +91,9 @@ class Indi_BearsPower : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = _value = iBearsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index a77f5c630..50db9e96f 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -91,9 +91,9 @@ class Indi_BullsPower : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = iBullsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index 55ffab15f..5734716a7 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -166,8 +166,8 @@ class Indi_CCI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + int _ishift = _shift + iparams.GetShift(); double _value = EMPTY_VALUE; switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index 2e4587f53..5f0452621 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -198,9 +198,9 @@ class Indi_CHO : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index bc2e85a41..6cbbd7228 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -189,9 +189,9 @@ class Indi_CHV : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index a12b88b40..df7682591 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -125,9 +125,9 @@ class Indi_ColorBars : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index dd43bf9a0..21fbae9c2 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -135,9 +135,9 @@ class Indi_ColorCandlesDaily : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index 837276a22..8359515bc 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -218,9 +218,9 @@ class Indi_ColorLine : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_CustomMovingAverage.mqh b/Indicators/Indi_CustomMovingAverage.mqh index e9e855edb..afd5b677a 100644 --- a/Indicators/Indi_CustomMovingAverage.mqh +++ b/Indicators/Indi_CustomMovingAverage.mqh @@ -79,9 +79,9 @@ class Indi_CustomMovingAverage : public Indicator /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index d14f4fdfd..69facb42d 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -180,9 +180,9 @@ class Indi_DEMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index 44df4c5ba..c0cfb11b8 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -88,9 +88,9 @@ class Indi_DeMarker : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = _value = Indi_DeMarker::iDeMarker(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index 09a399c27..0544a56f3 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -79,8 +79,8 @@ class Indi_Demo : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + int _ishift = _shift + iparams.GetShift(); double _value = Indi_Demo::iDemo(THIS_PTR, _ishift); if (idparams.is_draw) { draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(_ishift), _value); diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index d3ba956bb..0fa35cd23 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -136,9 +136,9 @@ class Indi_DetrendedPrice : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index 4cc4e9b12..81c0ac92a 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -194,9 +194,9 @@ class Indi_Drawer : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Drawer::iDrawer(GetSymbol(), GetTf(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 4c0023c6c..902f3478c 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -204,9 +204,9 @@ class Indi_Envelopes : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Envelopes::iEnvelopes(GetSymbol(), GetTf(), GetMAPeriod(), GetMAMethod(), GetMAShift(), diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index 88f669b8b..c74c90071 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -105,9 +105,9 @@ class Indi_Force : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index a009f9011..a7d7d6d2e 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -177,9 +177,9 @@ class Indi_FrAMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index ed14a7a1d..afb24f0b2 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -104,9 +104,9 @@ class Indi_Fractals : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _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); diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index aca212baf..380377b1c 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -175,9 +175,9 @@ class Indi_Gator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Gator::iGator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index 05501240b..4c1b5ee3a 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -215,9 +215,9 @@ class Indi_HeikenAshi : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = HA_OPEN, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = HA_OPEN, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index 6b2cee10d..02a009ca9 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -144,9 +144,9 @@ class Indi_Ichimoku : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Ichimoku::iIchimoku(GetSymbol(), GetTf(), GetTenkanSen(), GetKijunSen(), GetSenkouSpanB(), _mode, diff --git a/Indicators/Indi_Killzones.mqh b/Indicators/Indi_Killzones.mqh index 8f9933ae4..4712a66f8 100644 --- a/Indicators/Indi_Killzones.mqh +++ b/Indicators/Indi_Killzones.mqh @@ -131,10 +131,10 @@ class Indi_Killzones : public Indicator { /** * Returns the indicator's value. */ - IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { float _value = FLT_MAX; int _index = (int)_mode / 2; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // Builtin mode not supported. diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 4d2b84bed..ee770cf1a 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -129,6 +129,7 @@ class Indi_MA : public Indicator { unsigned int ma_period, unsigned int ma_shift, ENUM_MA_METHOD ma_method, // (MT4/MT5): MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA ENUM_APPLIED_PRICE _ap, int shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, int(ma_period + ma_shift + shift)); ValueStorage *_data = (ValueStorage *)_source.GetSpecificAppliedPriceValueStorage(_ap, _target); return iMAOnArray(_data, 0, ma_period, ma_shift, ma_method, shift, _target PTR_DEREF GetCache()); } @@ -627,9 +628,9 @@ class Indi_MA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_MA::iMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index f2f258570..98f3cbf4f 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -105,9 +105,9 @@ class Indi_MACD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_MACD::iMACD(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index 2ff52c80b..3f21ef6d6 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -99,9 +99,9 @@ class Indi_MFI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: #ifdef __MQL4__ diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index 61866de86..3d15a2629 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -176,9 +176,9 @@ class Indi_MassIndex : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index cf80d85cb..5646d34c0 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -138,9 +138,9 @@ class Indi_Momentum : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // @fixit Somehow shift isn't used neither in MT4 nor MT5. diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index 0bb664a7b..7156fa2ad 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -114,9 +114,9 @@ class Indi_OBV : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: #ifdef __MQL4__ diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index 4c5266980..bd72bb5da 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -99,8 +99,8 @@ class Indi_OsMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + int _ishift = _shift + iparams.GetShift(); double _value = EMPTY_VALUE; switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index d68848840..94adc5634 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -100,7 +100,7 @@ class Indi_Pivot : public Indicator { * Returns IndicatorDataEntry struct filled with indicator values. */ virtual IndicatorDataEntry GetEntry(int _shift = 0) { - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); 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)) { @@ -137,8 +137,8 @@ class Indi_Pivot : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + int _ishift = _shift + iparams.GetShift(); return GetEntry(_ishift)[_mode]; } diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index 526643960..d0a3582aa 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -126,9 +126,9 @@ class Indi_PriceChannel : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index f68bdadff..ce6970486 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -88,9 +88,9 @@ class Indi_PriceFeeder : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int data_size = ArraySize(iparams.price_data); - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); if (_ishift >= data_size || _ishift < 0) return DBL_MIN; diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index 12619bcdf..28b131513 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -140,9 +140,9 @@ class Indi_PriceVolumeTrend : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index 569b216a3..a45448fcb 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -104,8 +104,8 @@ class Indi_RS : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + int _ishift = _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. diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 5739e4f6a..b63cac3e6 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -309,10 +309,10 @@ class Indi_RSI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; double _res[]; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index 6b5baf242..ca4da8681 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -94,9 +94,9 @@ class Indi_RVI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_RVI::iRVI(GetSymbol(), GetTf(), GetPeriod(), (ENUM_SIGNAL_LINE)_mode, _ishift, THIS_PTR); diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index 59e8fe8c6..3eac51e1f 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -126,9 +126,9 @@ class Indi_RateOfChange : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_SAR.mqh b/Indicators/Indi_SAR.mqh index 343e89221..b1200e193 100644 --- a/Indicators/Indi_SAR.mqh +++ b/Indicators/Indi_SAR.mqh @@ -90,9 +90,9 @@ class Indi_SAR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_SAR::iSAR(GetSymbol(), GetTf(), GetStep(), GetMax(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index b1cecdcdc..375499ae2 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -118,6 +118,8 @@ class Indi_StdDev : public Indicator { 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) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, _ma_period + _ma_shift + _shift) + double _indi_value_buffer[]; double _std_dev; int i; @@ -224,9 +226,9 @@ class Indi_StdDev : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_StdDev::iStdDev(GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), GetMAMethod(), diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index 4869ed478..25eeb7686 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -110,9 +110,9 @@ class Indi_Stochastic : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Stochastic::iStochastic(GetSymbol(), GetTf(), GetKPeriod(), GetDPeriod(), GetSlowing(), diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index cc288ac56..6b89d2cba 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -154,9 +154,9 @@ class Indi_TEMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _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, diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index 4ec953133..ac08b6b1d 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -154,9 +154,9 @@ class Indi_TRIX : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_TRIX::iTriX(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _ishift, diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index 8c3c17784..d00c0526a 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -100,6 +100,9 @@ class Indi_UltimateOscillator : public Indicator { */ 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) { + int _min_bars_required = MathMax(MathMax(_fast_period, _middle_period), _slow_period); + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _min_bars_required); + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( _indi, Util::MakeKey(_fast_period, _middle_period, _slow_period, _fast_k, _middle_k, _slow_k)); @@ -167,8 +170,6 @@ class Indi_UltimateOscillator : public Indicator { if (ExtMaxPeriod < InpMiddlePeriod) ExtMaxPeriod = InpMiddlePeriod; if (ExtMaxPeriod < InpFastPeriod) ExtMaxPeriod = InpFastPeriod; - int min_bars_required = MathMax(MathMax(InpFastPeriod, InpMiddlePeriod), InpSlowPeriod); - if (rates_total < ExtMaxPeriod) return (0); // Not all data may be calculated. int calculated = BarsCalculated(ExtFastATRhandle); @@ -248,9 +249,9 @@ class Indi_UltimateOscillator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index 4416f29ba..037e25c0a 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -177,9 +177,9 @@ class Indi_VIDYA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_VIDYA::iVIDyA(GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift(), diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index d25a59883..3854a7051 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -153,9 +153,9 @@ class Indi_VROC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index fed9195d3..feaf8a5c4 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -147,9 +147,9 @@ class Indi_Volumes : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_WPR.mqh b/Indicators/Indi_WPR.mqh index 45490562c..3c978b23d 100644 --- a/Indicators/Indi_WPR.mqh +++ b/Indicators/Indi_WPR.mqh @@ -117,9 +117,9 @@ class Indi_WPR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_WPR::iWPR(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index 19e73b82b..e2103a1ad 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -149,9 +149,9 @@ class Indi_WilliamsAD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index a9397faad..e2fadc062 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -373,9 +373,9 @@ class Indi_ZigZag : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 8cd8e9248..9bc8b1bb1 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -295,9 +295,9 @@ class Indi_ZigZagColor : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_ONCALCULATE: _value = Indi_ZigZagColor::iZigZagColor(THIS_PTR, GetDepth(), GetDeviation(), GetBackstep(), diff --git a/Indicators/OHLC/Indi_OHLC.mqh b/Indicators/OHLC/Indi_OHLC.mqh index 9b32546e1..411cae002 100644 --- a/Indicators/OHLC/Indi_OHLC.mqh +++ b/Indicators/OHLC/Indi_OHLC.mqh @@ -89,8 +89,8 @@ class Indi_OHLC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + int _ishift = _shift + iparams.GetShift(); ENUM_APPLIED_PRICE _ap = PRICE_OPEN; switch (_mode) { case INDI_OHLC_CLOSE: diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index 64db99a5b..c4f4e3a44 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -73,8 +73,8 @@ class Indi_Price : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + int _ishift = _shift + iparams.GetShift(); return GetCandle() PTR_DEREF GetSpecificAppliedPriceValueStorage(iparams.GetAppliedPrice()) PTR_DEREF Fetch(_ishift); } diff --git a/Indicators/Special/Indi_Custom.mqh b/Indicators/Special/Indi_Custom.mqh index c02e1d247..332af4bdf 100644 --- a/Indicators/Special/Indi_Custom.mqh +++ b/Indicators/Special/Indi_Custom.mqh @@ -98,9 +98,9 @@ class Indi_Custom : public Indicator { /** * Returns the indicator's value. */ - IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_ICUSTOM: switch (iparams.GetParamsSize()) { diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index d0d6c8d11..c4084a06e 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -114,9 +114,9 @@ class Indi_Math : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_INDICATOR: if (!indi_src.IsSet()) { diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 04ac5eaf3..39d588861 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -83,7 +83,7 @@ class Indi_TickMt : public IndicatorTick Date: Fri, 28 Oct 2022 19:02:37 +0200 Subject: [PATCH 037/123] WIP. Added explanation of shift parameters in Indicator/IndicatorData classes for following methods: GetEntryValue/GetEntryAlter/GetValue/GetEntry(). --- Indicator/Details.md | 59 ++++++++++++++++++++++++++ Indicator/IndicatorData.h | 2 +- Indicator/IndicatorData.struct.cache.h | 2 + Indicators/Indi_MA.mqh | 9 +++- 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 Indicator/Details.md diff --git a/Indicator/Details.md b/Indicator/Details.md new file mode 100644 index 000000000..e7dfb7644 --- /dev/null +++ b/Indicator/Details.md @@ -0,0 +1,59 @@ +# Explanation of shift parameters in Indicator/IndicatorData classes for following methods: +- `GetEntryValue(int _mode, int _abs_shift)` +- `GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift)` +- `GetValue(int _mode = 0, int _rel_shift = 0)` +- `GetEntry(int _rel_shift = 0)` + +## GetEntryValue(int _mode, int _abs_shift) - overridable method + +Method must be overriden in any new indicator and MUST NOT apply shift from `iparams.shift`/`iparams.GetShift()`! Shift 0 must always point to the value for the current tick. + +Returns indicators's value for a given mode and absolute shift (the shift is directly passed to built-in methods such as iATR(), OnCalculate methods such as `iVIDyAOnIndicator()` and also to `iCustom()`). + +For `OnCalculate()` methods such as iVIDyAOnIndicator(), the shift is passed to `return _cache.GetTailValue(_mode, _shift);` so we can return value calculated in the past (or just retrieve **DBL_MAX** in case the value was not yet calculated). +Note that `OnCalculate()` methods uses single/multiple price buffers, e.g., applied price or OHLCs from base indicator. + +In scenario of `VIDyA[shift = 2] <- Candle <- TickMt` call hierarchy looks like: +```cpp +- VIDyA::GetEntry(_rel_shift = 1) // Then per each mode: +- entry.values[_mode] = Indicator::GetValue(_mode, _rel_shift = 1) +- VIDyA::GetEntryValue(_mode, _abs_shift = iparams.shift + 1) +- VIDyA::iVIDyAOnIndicator(..., _mode, _shift = 3) then: // Shift is absolute. +- VIDyA::iVIDyAOnArray(..., _mode, _shift = 3) then: // Shift is absolute. + return _cache.GetTailValue(_mode, _shift = 3); // Shift is absolute. +``` +Last line means that we will retrieve **VIDyA** value shifted by 3 (2 from `iparams.shift` + 1 from `GetEntry()`). It is correct. + +## GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) - overridable method + +Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). + +Method calls (seen in **MWMFI**, **CCI**, **Envelopes**, **Momentum**, **Pivot**): +```cpp +- GetValue(_mode, _rel_shift) // GetValue() takes relative shift. +``` + +## GetValue(int _mode = 0, int _rel_shift = 0) - non-overridable method + +Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). + +Method calls: +```cpp +- GetEntryValue(_mode, _abs_shift = iparams.shift + _rel_shift) +``` + +## GetEntry(int _rel_shift = 0) - overridable method + +Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). + +If you need to access entries from absolute shift, use `GetEntryByAbsShift(int _abs_shift)`. + +Note that values accessed via index operator `storage[rel_shift]` e.g., inside `OnCalculate()` methods like `double _o = open[rel_shift = 4].Get()` will take relative shift and retrieve open price shifted by (in this scenario) `4 + iparams.shift` set in base indicator: +```cpp +- double _o = open[_rel_shift = 4] +- IndicatorBufferValueStorage::Fetch(_rel_shift = 4) +- IndicatorData::GetValue(_mode, _rel_shift = 4) +- Indicator::GetEntryValue(_mode, _abs_shift = iparams.shift + 4) // As GetEntryValue() takes absolute shift, we add shift from iparams.shift. +- Indicator::GetEntry(_rel_shift = _abs_shift - iparams.shift)... // Converting absolute shift into relative one for GetEntry(). +- ...[_mode]; // IndicatorDataEntry.values[_mode].Get(...); +``` \ No newline at end of file diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index d81097139..5d5842183 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1126,7 +1126,7 @@ class IndicatorData : public IndicatorBase { if (_indi == nullptr) _indi = GetTick(false); if (_indi == nullptr) { - Print("Error: Neither candle nor tick indicator exists in the hierarch of ", GetFullName(), "!"); + Print("Error: Neither candle nor tick indicator exists in the hierarchy of ", GetFullName(), "!"); DebugBreak(); return (datetime)0; } diff --git a/Indicator/IndicatorData.struct.cache.h b/Indicator/IndicatorData.struct.cache.h index 05264e24b..c6ee5e1dc 100644 --- a/Indicator/IndicatorData.struct.cache.h +++ b/Indicator/IndicatorData.struct.cache.h @@ -234,7 +234,9 @@ class IndicatorCalculateCache : public Dynamic { } /** + * Retrieves _shift-th (0 = most recent) cached value from the given buffer. * + * @todo Return DBL_MAX in case the index is out of array boundary. */ template D GetTailValue(int _buffer_index, int _shift) { diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index ee770cf1a..7102f3fa8 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -54,8 +54,13 @@ struct IndiMAParams : IndicatorParams { ENUM_MA_METHOD ma_method; ENUM_APPLIED_PRICE applied_array; // Struct constructors. - IndiMAParams(unsigned int _period = 13, int _ma_shift = 10, ENUM_MA_METHOD _ma_method = MODE_SMA, - ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) + /** + * Regarding _ma_shift and _shift: + * @see https://www.mql5.com/en/forum/146006#comment_3685589 + * "Always use MA shift 0 (ignore it) and use the regular shift, unless you are placing it on the chart for visual". + */ + IndiMAParams(unsigned int _period = 13, int _ma_shift = 0, ENUM_MA_METHOD _ma_method = MODE_SMA, + ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 10) : period(_period), ma_shift(_ma_shift), ma_method(_ma_method), applied_array(_ap), IndicatorParams(INDI_MA) { shift = _shift; SetCustomIndicatorName("Examples\\Moving Average"); From ecc90c42d1dc0f6ca22469aa97566722e39c4e90 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 31 Oct 2022 19:01:29 +0100 Subject: [PATCH 038/123] WIP. Shift parameters refactoring for Indicator/IndicatorData/other classes. Still some errors. --- ChartBase.h | 14 +-- ChartMt.h | 6 +- Indicator/Details.md | 108 +++++++++++++++++------- Indicator/Indicator.define.h | 4 +- Indicator/Indicator.h | 45 ++++++---- Indicator/IndicatorCandle.h | 10 +-- Indicator/IndicatorData.h | 42 +++++---- Indicator/IndicatorRenko.h | 4 +- Indicator/IndicatorTick.h | 8 +- Indicators/Bitwise/Indi_Candle.mqh | 13 ++- Indicators/Bitwise/Indi_Pattern.mqh | 19 ++--- Indicators/Indi_AC.mqh | 8 +- Indicators/Indi_AD.mqh | 8 +- Indicators/Indi_ADX.mqh | 8 +- Indicators/Indi_ADXW.mqh | 11 ++- Indicators/Indi_AMA.mqh | 11 ++- Indicators/Indi_AO.mqh | 8 +- Indicators/Indi_ASI.mqh | 9 +- Indicators/Indi_ATR.mqh | 8 +- Indicators/Indi_Alligator.mqh | 12 +-- Indicators/Indi_AppliedPrice.mqh | 6 +- Indicators/Indi_BWMFI.mqh | 7 +- Indicators/Indi_BWZT.mqh | 10 +-- Indicators/Indi_Bands.mqh | 15 ++-- Indicators/Indi_BearsPower.mqh | 8 +- Indicators/Indi_BullsPower.mqh | 7 +- Indicators/Indi_CCI.mqh | 17 ++-- Indicators/Indi_CHO.mqh | 9 +- Indicators/Indi_CHV.mqh | 9 +- Indicators/Indi_ColorBars.mqh | 10 +-- Indicators/Indi_ColorCandlesDaily.mqh | 10 +-- Indicators/Indi_ColorLine.mqh | 10 +-- Indicators/Indi_CustomMovingAverage.mqh | 5 +- Indicators/Indi_DEMA.mqh | 11 ++- Indicators/Indi_DeMarker.mqh | 7 +- Indicators/Indi_Demo.mqh | 7 +- Indicators/Indi_DetrendedPrice.mqh | 9 +- Indicators/Indi_Drawer.mqh | 8 +- Indicators/Indi_Envelopes.mqh | 14 +-- Indicators/Indi_Force.mqh | 9 +- Indicators/Indi_FractalAdaptiveMA.mqh | 15 ++-- Indicators/Indi_Fractals.mqh | 9 +- Indicators/Indi_Gator.mqh | 7 +- Indicators/Indi_HeikenAshi.mqh | 12 +-- Indicators/Indi_Ichimoku.mqh | 7 +- Indicators/Indi_Killzones.mqh | 7 +- Indicators/Indi_MA.mqh | 11 ++- Indicators/Indi_MACD.mqh | 7 +- Indicators/Indi_MFI.mqh | 8 +- Indicators/Indi_MassIndex.mqh | 11 +-- Indicators/Indi_Momentum.mqh | 17 ++-- Indicators/Indi_OBV.mqh | 7 +- Indicators/Indi_OsMA.mqh | 7 +- Indicators/Indi_Pivot.mqh | 16 ++-- Indicators/Indi_PriceChannel.mqh | 9 +- Indicators/Indi_PriceFeeder.mqh | 7 +- Indicators/Indi_PriceVolumeTrend.mqh | 9 +- Indicators/Indi_RS.mqh | 3 +- Indicators/Indi_RSI.mqh | 11 ++- Indicators/Indi_RVI.mqh | 8 +- Indicators/Indi_RateOfChange.mqh | 9 +- Indicators/Indi_SAR.mqh | 7 +- Indicators/Indi_StdDev.mqh | 11 ++- Indicators/Indi_Stochastic.mqh | 7 +- Indicators/Indi_TEMA.mqh | 15 ++-- Indicators/Indi_TRIX.mqh | 15 ++-- Indicators/Indi_UltimateOscillator.mqh | 9 +- Indicators/Indi_VIDYA.mqh | 19 ++--- Indicators/Indi_VROC.mqh | 9 +- Indicators/Indi_Volumes.mqh | 9 +- Indicators/Indi_WPR.mqh | 7 +- Indicators/Indi_WilliamsAD.mqh | 10 +-- Indicators/Indi_ZigZag.mqh | 15 ++-- Indicators/Indi_ZigZagColor.mqh | 7 +- Indicators/OHLC/Indi_OHLC.mqh | 5 +- Indicators/Price/Indi_Price.mqh | 5 +- Indicators/Special/Indi_Custom.mqh | 14 +-- Indicators/Special/Indi_Math.mqh | 7 +- Storage/ValueStorage.applied_price.h | 15 ++-- Storage/ValueStorage.h | 2 +- Storage/ValueStorage.history.h | 2 + Storage/ValueStorage.indicator.h | 2 +- Storage/ValueStorage.native.h | 2 +- Storage/ValueStorage.price_median.h | 4 +- Storage/ValueStorage.price_typical.h | 4 +- Storage/ValueStorage.price_weighted.h | 4 +- Storage/ValueStorage.spread.h | 2 +- Storage/ValueStorage.tick_volume.h | 2 +- Storage/ValueStorage.time.h | 2 +- Storage/ValueStorage.volume.h | 4 +- 90 files changed, 492 insertions(+), 465 deletions(-) diff --git a/ChartBase.h b/ChartBase.h index 7cf488116..99010949a 100644 --- a/ChartBase.h +++ b/ChartBase.h @@ -96,7 +96,7 @@ class ChartBase : public Dynamic { /** * Returns time of the bar with a given shift. */ - virtual datetime GetBarTime(int _shift = 0) = 0; + virtual datetime GetBarTime(int _rel_shift = 0) = 0; datetime GetLastBarTime() { return last_bar_time; } @@ -170,14 +170,14 @@ class ChartBase : public Dynamic { /** * Gets OHLC price values. */ - virtual BarOHLC GetOHLC(int _shift = 0) { - datetime _time = GetBarTime(_shift); + virtual BarOHLC GetOHLC(int _rel_shift = 0) { + datetime _time = GetBarTime(_rel_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); + _open = (float)GetOpen(_rel_shift); + _high = (float)GetHigh(_rel_shift); + _low = (float)GetLow(_rel_shift); + _close = (float)GetClose(_rel_shift); } BarOHLC _ohlc(_open, _high, _low, _close, _time); return _ohlc; diff --git a/ChartMt.h b/ChartMt.h index b09ea050b..5f32f0230 100644 --- a/ChartMt.h +++ b/ChartMt.h @@ -67,11 +67,11 @@ class ChartMt : public ChartBase { /** * Returns time of the bar with a given shift. */ - virtual datetime GetBarTime(int _shift = 0) override { - datetime _time = ::iTime(GetSymbol(), GetTf(), _shift); + virtual datetime GetBarTime(int _rel_shift = 0) override { + datetime _time = ::iTime(GetSymbol(), GetTf(), _rel_shift); if (_LastError != ERR_NO_ERROR) { - Print("Error: ", _LastError, " while doing ::iTime() in ChartMt::GetBarTime(", _shift, ")"); + Print("Error: ", _LastError, " while doing ::iTime() in ChartMt::GetBarTime(", _rel_shift, ")"); DebugBreak(); } diff --git a/Indicator/Details.md b/Indicator/Details.md index e7dfb7644..cbb2e3414 100644 --- a/Indicator/Details.md +++ b/Indicator/Details.md @@ -1,8 +1,9 @@ -# Explanation of shift parameters in Indicator/IndicatorData classes for following methods: -- `GetEntryValue(int _mode, int _abs_shift)` +#Explanation of shift parameters in Indicator / IndicatorData / other classes for following methods: +- `GetEntryValue(int _mode = 0, int _abs_shift = 0)` - `GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift)` - `GetValue(int _mode = 0, int _rel_shift = 0)` - `GetEntry(int _rel_shift = 0)` +- `GetBarTime(int _rel_shift = 0)` ## GetEntryValue(int _mode, int _abs_shift) - overridable method @@ -10,50 +11,93 @@ Method must be overriden in any new indicator and MUST NOT apply shift from `ipa Returns indicators's value for a given mode and absolute shift (the shift is directly passed to built-in methods such as iATR(), OnCalculate methods such as `iVIDyAOnIndicator()` and also to `iCustom()`). -For `OnCalculate()` methods such as iVIDyAOnIndicator(), the shift is passed to `return _cache.GetTailValue(_mode, _shift);` so we can return value calculated in the past (or just retrieve **DBL_MAX** in case the value was not yet calculated). -Note that `OnCalculate()` methods uses single/multiple price buffers, e.g., applied price or OHLCs from base indicator. +For `OnCalculate()` methods such as iVIDyAOnIndicator(), the shift is passed to `return _cache.GetTailValue(_mode, _shift); +` so we can return value calculated in the past(or just retrieve * *DBL_MAX * *in case the value was not yet calculated) + .Note that `OnCalculate()` methods uses single / + multiple price buffers, + e.g., + applied price or OHLCs from base indicator. -In scenario of `VIDyA[shift = 2] <- Candle <- TickMt` call hierarchy looks like: + In scenario of `VIDyA[shift = 2] < -Candle < -TickMt` call hierarchy looks like : +```cpp - VIDyA::GetEntry(_rel_shift = 1) // Then per each mode: + - entry.values[_mode] = + Indicator::GetValue(_mode, _rel_shift = 1) - VIDyA::GetEntryValue(_mode, _abs_shift = iparams.shift + 1) - + VIDyA::iVIDyAOnIndicator(..., _mode, _shift = 3) then : // Shift is absolute. + -VIDyA::iVIDyAOnArray(..., _mode, _shift = 3) then + : // Shift is absolute. + return _cache.GetTailValue(_mode, _shift = 3); // Shift is absolute. +``` Last line means that we will retrieve **VIDyA **value shifted by 3(2 from `iparams.shift` + 1 from `GetEntry()`) + .It is correct. + + ##GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) - + overridable method + + Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`) + . + + Method calls(seen in **MWMFI **, **CCI **, **Envelopes **, **Momentum **, **Pivot **) + : ```cpp -- VIDyA::GetEntry(_rel_shift = 1) // Then per each mode: -- entry.values[_mode] = Indicator::GetValue(_mode, _rel_shift = 1) -- VIDyA::GetEntryValue(_mode, _abs_shift = iparams.shift + 1) -- VIDyA::iVIDyAOnIndicator(..., _mode, _shift = 3) then: // Shift is absolute. -- VIDyA::iVIDyAOnArray(..., _mode, _shift = 3) then: // Shift is absolute. - return _cache.GetTailValue(_mode, _shift = 3); // Shift is absolute. + - + GetValue(_mode, _rel_shift) // GetValue() takes relative shift. ``` -Last line means that we will retrieve **VIDyA** value shifted by 3 (2 from `iparams.shift` + 1 from `GetEntry()`). It is correct. -## GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) - overridable method + ##GetValue(int _mode = 0, int _rel_shift = 0) - + non - + overridable method -Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). + Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`) + . -Method calls (seen in **MWMFI**, **CCI**, **Envelopes**, **Momentum**, **Pivot**): + Method calls : ```cpp -- GetValue(_mode, _rel_shift) // GetValue() takes relative shift. + - + GetEntryValue(_mode, _abs_shift = iparams.shift + _rel_shift) ``` -## GetValue(int _mode = 0, int _rel_shift = 0) - non-overridable method + ##GetEntry(int _rel_shift = 0) - + overridable method -Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). + Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`) + . -Method calls: -```cpp -- GetEntryValue(_mode, _abs_shift = iparams.shift + _rel_shift) + If you need to access entries from absolute shift, + use `GetEntryByAbsShift(int _abs_shift)` + . + + Note that values accessed via index + operator `storage[rel_shift]` e.g., + inside `OnCalculate()` methods like `double _o = + open[rel_shift = 4].Get()` will take relative shift + and retrieve open price shifted by(in this scenario) `4 + iparams.shift` set in base indicator : +```cpp - double _o = + open[_rel_shift = 4] - IndicatorBufferValueStorage::Fetch(_rel_shift = 4) - + IndicatorData::GetValue(_mode, _rel_shift = 4) - + Indicator::GetEntryValue( + _mode, _abs_shift = iparams.shift + + 4) // As GetEntryValue() takes absolute shift, we add shift from iparams.shift. + - Indicator::GetEntry(_rel_shift = + _abs_shift - + iparams.shift)... // Converting absolute shift into relative one for GetEntry(). + - ...[_mode]; // IndicatorDataEntry.values[_mode].Get(...); ``` -## GetEntry(int _rel_shift = 0) - overridable method +## GetBarTime(int _rel_shift = 0) Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). -If you need to access entries from absolute shift, use `GetEntryByAbsShift(int _abs_shift)`. +## GetPrice(ENUM_APPLIED_PRICE _ap, int _rel_shift = 0) -Note that values accessed via index operator `storage[rel_shift]` e.g., inside `OnCalculate()` methods like `double _o = open[rel_shift = 4].Get()` will take relative shift and retrieve open price shifted by (in this scenario) `4 + iparams.shift` set in base indicator: -```cpp -- double _o = open[_rel_shift = 4] -- IndicatorBufferValueStorage::Fetch(_rel_shift = 4) -- IndicatorData::GetValue(_mode, _rel_shift = 4) -- Indicator::GetEntryValue(_mode, _abs_shift = iparams.shift + 4) // As GetEntryValue() takes absolute shift, we add shift from iparams.shift. -- Indicator::GetEntry(_rel_shift = _abs_shift - iparams.shift)... // Converting absolute shift into relative one for GetEntry(). -- ...[_mode]; // IndicatorDataEntry.values[_mode].Get(...); -``` \ No newline at end of file +Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). + +## GetBars() + +Number of returned bars is decremented by `IndicatorParams::shift` (read via `Indicator::iparams.shift`). Thus if there are **10** bars and *shift* is **8** then `GetBars()` will return **2**. That means that you can safely do `GetEntry()` for relative shifts **0** or **1**. There won't be any value in other relative shifts. + +## HistoryValueStorage::Fetch(int _rel_shift) + +Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). + +## Indi_\*::\*OnIndicator(..., _shift, [_shift1], [_shift2]) + +All shifts passed are relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index d2ef7bce3..3d1a65c24 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -137,5 +137,5 @@ // We're adding 1 because e.g., shift 1 means that we need two bars to exist in // history in order to retrieve bar at shift 1. -#define INDI_REQUIRE_SHIFT_OR_RETURN(_indi, _shift, _ret) INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _shift + 1) -#define INDI_REQUIRE_SHIFT_OR_RETURN_EMPTY(_indi, _shift) INDI_REQUIRE_SHIFT_OR_RETURN(_indi, _shift, DBL_MAX) +#define INDI_REQUIRE_SHIFT_OR_RETURN(_indi, _rel_shift, _ret) INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _rel_shift + 1) +#define INDI_REQUIRE_SHIFT_OR_RETURN_EMPTY(_indi, _rel_shift) INDI_REQUIRE_SHIFT_OR_RETURN(_indi, _rel_shift, DBL_MAX) diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index c2a9af4a4..9bab3b18f 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -212,6 +212,18 @@ class Indicator : public IndicatorData { draw.SetWindow(_window); } + /* Converters */ + + /** + * Converts relative shift into absolute one. + */ + int ToAbsShift(int _rel_shift) override { return _rel_shift + iparams.shift; } + + /** + * Converts absolute shift into relative one. + */ + int ToRelShift(int _abs_shift) override { return _abs_shift - iparams.shift; } + /* Buffer methods */ virtual string CacheKey() { return GetFullName(); } @@ -575,11 +587,9 @@ class Indicator : public IndicatorData { * @return * Returns IndicatorDataEntry struct filled with indicator values. */ - IndicatorDataEntry GetEntry(int _index = 0) override { + IndicatorDataEntry GetEntry(int _rel_shift = 0) override { ResetLastError(); - int _ishift = _index + iparams.GetShift(); - long _bar_time; - _bar_time = GetBarTime(_ishift); + long _bar_time = GetBarTime(_rel_shift); if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_BUILTIN && (GetPossibleDataModes() & IDATA_BUILTIN) == 0) { @@ -598,7 +608,7 @@ class Indicator : public IndicatorData { 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 = GetBarTime(_ishift); + _entry.timestamp = GetBarTime(_rel_shift); #ifndef __MQL4__ if (IndicatorData::Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED))) { // Resets the handle on any parameter changes. @@ -611,22 +621,22 @@ class Indicator : public IndicatorData { case TYPE_BOOL: case TYPE_CHAR: case TYPE_INT: - _entry.values[_mode] = GetValue(_mode, _ishift); + _entry.values[_mode] = GetValue(_mode, _rel_shift); break; case TYPE_LONG: - _entry.values[_mode] = GetValue(_mode, _ishift); + _entry.values[_mode] = GetValue(_mode, _rel_shift); break; case TYPE_UINT: - _entry.values[_mode] = GetValue(_mode, _ishift); + _entry.values[_mode] = GetValue(_mode, _rel_shift); break; case TYPE_ULONG: - _entry.values[_mode] = GetValue(_mode, _ishift); + _entry.values[_mode] = GetValue(_mode, _rel_shift); break; case TYPE_DOUBLE: - _entry.values[_mode] = GetValue(_mode, _ishift); + _entry.values[_mode] = GetValue(_mode, _rel_shift); break; case TYPE_FLOAT: - _entry.values[_mode] = GetValue(_mode, _ishift); + _entry.values[_mode] = GetValue(_mode, _rel_shift); break; case TYPE_STRING: case TYPE_UCHAR: @@ -637,12 +647,12 @@ class Indicator : public IndicatorData { 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); + Print("Error: Code ", _LastError, " while trying to retrieve entry at shift ", _rel_shift, " (absolute ", + ToAbsShift(_rel_shift), "), mode ", _mode, ", time ", _bar_dt); DebugBreak(); } } - GetEntryAlter(_entry, _ishift); + GetEntryAlter(_entry, _rel_shift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { idata.Add(_entry, _bar_time); @@ -665,7 +675,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 _shift) { + virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) { ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE)); _entry.AddFlags(_entry.GetDataTypeFlags(_dtype)); }; @@ -678,9 +688,8 @@ class Indicator : public IndicatorData { * @return * Returns DataParamEntry struct filled with a single value. */ - IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) override { - int _ishift = _shift + iparams.GetShift(); - return GetEntry(_ishift)[_mode]; + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override { + return GetEntry(ToRelShift(_abs_shift))[_mode]; } /* Virtual methods */ diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 78c603869..202635575 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -149,12 +149,12 @@ class IndicatorCandle : public Indicator { int GetBarIndex() override { return history.GetCurrentIndex(); } /** - * Returns the number of bars on the chart. + * Returns the number of bars on the chart decremented by iparams.shift. */ int GetBars() override { // Will return number of bars prepended and appended to the history, // even if those bars were cleaned up because of history's candle limit. - return (int)history.GetPeakSize(); + return (int)history.GetPeakSize() - iparams.shift; } /** @@ -182,7 +182,7 @@ class IndicatorCandle : public Indicator { /** * Returns time of the bar for a given shift. */ - virtual datetime GetBarTime(int _shift = 0) { return history.GetItemTimeByShift(_shift); } + virtual datetime GetBarTime(int _rel_shift = 0) { return history.GetItemTimeByShift(_rel_shift); } /** * Traverses source indicators' hierarchy and tries to find OHLC-featured @@ -196,11 +196,11 @@ class IndicatorCandle : public Indicator { /** * Gets OHLC price values. */ - BarOHLC GetOHLC(int _shift = 0) override { + BarOHLC GetOHLC(int _rel_shift = 0) override { BarOHLC _bar; CandleOCTOHLC _candle; - if (history.TryGetItemByShift(_shift, _candle)) { + if (history.TryGetItemByShift(ToAbsShift(_rel_shift), _candle)) { _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.start_time); } diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 5d5842183..a97045afa 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -155,17 +155,17 @@ class IndicatorData : public IndicatorBase { /** * Access indicator entry data using [] operator via shift. */ - IndicatorDataEntry operator[](int _index) { + IndicatorDataEntry operator[](int _rel_shift) { if (!bool(flags | INDI_FLAG_INDEXABLE_BY_SHIFT)) { Print(GetFullName(), " is not indexable by shift!"); DebugBreak(); IndicatorDataEntry _default; return _default; } - return GetEntry(_index); + return GetEntry(_rel_shift); } - IndicatorDataEntry operator[](ENUM_INDICATOR_INDEX _index) { return GetEntry((int)_index); } + IndicatorDataEntry operator[](ENUM_INDICATOR_INDEX _rel_shift) { return GetEntry((int)_rel_shift); } /* Getters */ @@ -188,8 +188,8 @@ class IndicatorData : public IndicatorBase { /** * Gets an indicator property flag. */ - bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, int _shift = 0) { - IndicatorDataEntry _entry = GetEntry(_shift); + bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, int _rel_shift = 0) { + IndicatorDataEntry _entry = GetEntry(_rel_shift); return _entry.CheckFlag(_prop); } @@ -1013,9 +1013,9 @@ class IndicatorData : public IndicatorBase { } template - T GetValue(int _mode = 0, int _index = 0) { + T GetValue(int _mode = 0, int _rel_shift = 0) { T _out; - GetEntryValue(_mode, _index).Get(_out); + GetEntryValue(_mode, ToAbsShift(_rel_shift)).Get(_out); return _out; } @@ -1108,7 +1108,7 @@ class IndicatorData : public IndicatorBase { virtual double GetBid(int _shift = 0) { return GetTick() PTR_DEREF GetBid(_shift); } /** - * Returns the number of bars on the chart. + * Returns the number of bars on the chart decremented by iparams.shift. */ virtual int GetBars() { return GetCandle() PTR_DEREF GetBars(); } @@ -1120,7 +1120,7 @@ class IndicatorData : public IndicatorBase { /** * Returns time of the bar for a given shift. */ - virtual datetime GetBarTime(int _shift = 0) { + virtual datetime GetBarTime(int _rel_shift = 0) { IndicatorData* _indi = GetCandle(false); if (_indi == nullptr) _indi = GetTick(false); @@ -1132,10 +1132,10 @@ class IndicatorData : public IndicatorBase { } #ifdef __debug_items_history__ - Print("Getting bar time for shift ", _shift, " for ", GetFullName()); + Print("Getting bar time for shift ", _rel_shift, " for ", GetFullName()); #endif - return _indi PTR_DEREF GetBarTime(_shift); + return _indi PTR_DEREF GetBarTime(_rel_shift); } /** @@ -1186,7 +1186,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's struct value via index. */ - virtual IndicatorDataEntry GetEntry(int _index = 0) = NULL; + virtual IndicatorDataEntry GetEntry(int _rel_shift = 0) = NULL; /** * Returns the indicator's struct value via timestamp. @@ -1211,7 +1211,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's entry value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) = NULL; + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) = NULL; /** * Returns the shift of the maximum value over a specific number of periods depending on type. @@ -1257,7 +1257,7 @@ class IndicatorData : public IndicatorBase { /** * Gets OHLC price values. */ - virtual BarOHLC GetOHLC(int _shift = 0) { return GetCandle() PTR_DEREF GetOHLC(_shift); } + virtual BarOHLC GetOHLC(int _rel_shift = 0) { return GetCandle() PTR_DEREF GetOHLC(_rel_shift); } /** * Get peak price at given number of bars. @@ -1271,8 +1271,8 @@ class IndicatorData : public IndicatorBase { /** * 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); + virtual double GetPrice(ENUM_APPLIED_PRICE _ap, int _rel_shift = 0) { + return GetCandle() PTR_DEREF GetPrice(_ap, _rel_shift); } /** @@ -1871,6 +1871,16 @@ class IndicatorData : public IndicatorBase { return false; }; + /** + * Converts relative shift into absolute one. + */ + virtual int ToAbsShift(int _rel_shift) = 0; + + /** + * Converts absolute shift into relative one. + */ + virtual int ToRelShift(int _abs_shift) = 0; + /** * Loads and validates built-in indicators whose can be used as data source. */ diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index ef21c5e20..df4a403da 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -274,8 +274,8 @@ class IndicatorRenko : public IndicatorCandle { /** * Returns time of the bar for a given shift. */ - datetime GetBarTime(int _shift = 0) override { return history.GetItemTimeByShift(_shift); } + datetime GetBarTime(int _rel_shift = 0) override { return history.GetItemTimeByShift(_rel_shift); } /** * Gets ask price for a given date and time. Return current ask price if _dt wasn't passed or is 0. @@ -194,12 +194,10 @@ class IndicatorTick : public Indicator { * @return * Returns DataParamEntry struct filled with a single value. */ - IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) override { - int _ishift = _shift + iparams.GetShift(); - + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override { TickTAB _tick; - if (history.TryGetItemByShift(_ishift, _tick)) { + if (history.TryGetItemByShift(_abs_shift, _tick)) { switch (_mode) { case INDI_TICK_MODE_PRICE_ASK: return _tick.ask; diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index 95707754e..949ab5d3c 100644 --- a/Indicators/Bitwise/Indi_Candle.mqh +++ b/Indicators/Bitwise/Indi_Candle.mqh @@ -91,15 +91,14 @@ class Indi_Candle : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); BarOHLC _ohlcs[1]; switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // In this mode, price is fetched from IndicatorCandle. - _ohlcs[0] = GetCandle() PTR_DEREF GetOHLC(_ishift); + _ohlcs[0] = GetCandle() PTR_DEREF GetOHLC(ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: // In this mode, price is fetched from given indicator. Such indicator @@ -118,10 +117,10 @@ class Indi_Candle : public Indicator { break; } - _ohlcs[0].open = GetDataSource().GetValue(PRICE_OPEN, _ishift); - _ohlcs[0].high = GetDataSource().GetValue(PRICE_HIGH, _ishift); - _ohlcs[0].low = GetDataSource().GetValue(PRICE_LOW, _ishift); - _ohlcs[0].close = GetDataSource().GetValue(PRICE_CLOSE, _ishift); + _ohlcs[0].open = GetDataSource().GetValue(PRICE_OPEN, ToRelShift(_abs_shift)); + _ohlcs[0].high = GetDataSource().GetValue(PRICE_HIGH, ToRelShift(_abs_shift)); + _ohlcs[0].low = GetDataSource().GetValue(PRICE_LOW, ToRelShift(_abs_shift)); + _ohlcs[0].close = GetDataSource().GetValue(PRICE_CLOSE, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index 948c6aff2..a1c4740e0 100644 --- a/Indicators/Bitwise/Indi_Pattern.mqh +++ b/Indicators/Bitwise/Indi_Pattern.mqh @@ -84,12 +84,11 @@ class Indi_Pattern : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { int i; - int _ishift = _shift + iparams.GetShift(); int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); - INDI_REQUIRE_SHIFT_OR_RETURN(GetCandle(), _max_modes + _ishift, WRONG_VALUE); + INDI_REQUIRE_SHIFT_OR_RETURN(GetCandle(), ToRelShift(_abs_shift) + _max_modes, WRONG_VALUE); BarOHLC _ohlcs[8]; @@ -97,7 +96,7 @@ class Indi_Pattern : public Indicator { case IDATA_BUILTIN: // In this mode, price is fetched from candle. for (i = 0; i < _max_modes; ++i) { - _ohlcs[i] = GetCandle() PTR_DEREF GetOHLC(_ishift + i); + _ohlcs[i] = GetCandle() PTR_DEREF GetOHLC(ToRelShift(_abs_shift) + i); if (!_ohlcs[i].IsValid()) { // Return empty entry on invalid candles. return WRONG_VALUE; @@ -122,10 +121,10 @@ class Indi_Pattern : public Indicator { } for (i = 0; i < _max_modes; ++i) { - _ohlcs[i].open = GetDataSource().GetValue(PRICE_OPEN, _ishift + i); - _ohlcs[i].high = GetDataSource().GetValue(PRICE_HIGH, _ishift + i); - _ohlcs[i].low = GetDataSource().GetValue(PRICE_LOW, _ishift + i); - _ohlcs[i].close = GetDataSource().GetValue(PRICE_CLOSE, _ishift + i); + _ohlcs[i].open = GetDataSource().GetValue(PRICE_OPEN, ToRelShift(_abs_shift) + i); + _ohlcs[i].high = GetDataSource().GetValue(PRICE_HIGH, ToRelShift(_abs_shift) + i); + _ohlcs[i].low = GetDataSource().GetValue(PRICE_LOW, ToRelShift(_abs_shift) + i); + _ohlcs[i].close = GetDataSource().GetValue(PRICE_CLOSE, ToRelShift(_abs_shift) + i); if (!_ohlcs[i].IsValid()) { // Return empty entry on invalid candles. return WRONG_VALUE; @@ -143,9 +142,9 @@ class Indi_Pattern : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry& _entry, int _shift) override { + void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) override { _entry.SetFlag(INDI_ENTRY_FLAG_IS_BITWISE, true); - Indicator::GetEntryAlter(_entry, _shift); + Indicator::GetEntryAlter(_entry, _rel_shift); } /** diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index 74ad06e2c..d51e1e7b2 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -108,15 +108,15 @@ class Indi_AC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) override { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override { IndicatorDataEntryValue _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_AC::iAC(GetSymbol(), GetTf(), _ishift, THIS_PTR); + _value = Indi_AC::iAC(GetSymbol(), GetTf(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index 8fb4cf664..de2dcc19c 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -96,15 +96,15 @@ class Indi_AD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_AD::iAD(GetSymbol(), GetTf(), _ishift, THIS_PTR); + _value = Indi_AD::iAD(GetSymbol(), GetTf(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index d171e4f95..4719f9835 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -116,16 +116,16 @@ class Indi_ADX : public Indicator { /** * 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 _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_ADX::iADX(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _mode, _ishift, THIS_PTR); + _value = Indi_ADX::iADX(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _mode, ToRelShift(_abs_shift), + THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 8fc6a9494..af81fe622 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -266,22 +266,21 @@ class Indi_ADXW : public Indicator { /** * 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 _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _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); + _value = Indi_ADXW::iADXWilder(GetSymbol(), GetTf(), GetPeriod(), _mode, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ONCALCULATE: - _value = Indi_ADXW::iADXWilder(THIS_PTR, GetPeriod(), _mode, _ishift); + _value = Indi_ADXW::iADXWilder(THIS_PTR, GetPeriod(), _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = Indi_ADXW::iADXWilder(THIS_PTR, GetPeriod(), _mode, _ishift); + _value = Indi_ADXW::iADXWilder(THIS_PTR, GetPeriod(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index 30c7e6150..9161002e7 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -229,26 +229,25 @@ class Indi_AMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_AMA::iAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), - GetAMAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + GetAMAShift(), GetAppliedPrice() /*]*/, _mode, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - GetFastPeriod(), GetSlowPeriod(), GetAMAShift() /*]*/, _mode, _ishift); + GetFastPeriod(), GetSlowPeriod(), GetAMAShift() /*]*/, _mode, ToRelShift(_abs_shift)); break; case IDATA_ONCALCULATE: _value = Indi_AMA::iAMAOnIndicator(THIS_PTR, /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), GetAMAShift(), - GetAppliedPrice() /*]*/, _mode, _ishift); + GetAppliedPrice() /*]*/, _mode, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: _value = Indi_AMA::iAMAOnIndicator(THIS_PTR, /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), GetAMAShift(), - GetAppliedPrice() /*]*/, _mode, _ishift); + GetAppliedPrice() /*]*/, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index 74c755b45..eeb9c4661 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -107,15 +107,15 @@ class Indi_AO : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_AO::iAO(GetSymbol(), GetTf(), _ishift, _mode, THIS_PTR); + _value = Indi_AO::iAO(GetSymbol(), GetTf(), ToRelShift(_abs_shift), _mode, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index 160686eff..53e4617e9 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -206,20 +206,19 @@ class Indi_ASI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _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); + /*[*/ GetMaximumPriceChanging() /*]*/, 0, ToRelShift(_abs_shift)); break; case IDATA_ONCALCULATE: - _value = Indi_ASI::iASI(THIS_PTR, GetMaximumPriceChanging(), _mode, _ishift); + _value = Indi_ASI::iASI(THIS_PTR, GetMaximumPriceChanging(), _mode, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = Indi_ASI::iASI(THIS_PTR, GetMaximumPriceChanging(), _mode, _ishift); + _value = Indi_ASI::iASI(THIS_PTR, GetMaximumPriceChanging(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index ca40c4661..9f94ab076 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -90,15 +90,15 @@ class Indi_ATR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_ATR::iATR(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); + _value = Indi_ATR::iATR(GetSymbol(), GetTf(), GetPeriod(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index 446035319..d1834add6 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -152,9 +152,8 @@ class Indi_Alligator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); #ifdef __MQL4__ if (_mode == 0) { // In MQL4 mode 0 should be treated as mode 1 as Alligator buffers starts from index 1. @@ -163,9 +162,10 @@ class Indi_Alligator : public Indicator { #endif switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_Alligator::iAlligator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), - GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), - GetAppliedPrice(), (ENUM_ALLIGATOR_LINE)_mode, _ishift, THIS_PTR); + _value = + Indi_Alligator::iAlligator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), + GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), + GetAppliedPrice(), (ENUM_ALLIGATOR_LINE)_mode, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ @@ -173,7 +173,7 @@ class Indi_Alligator : public Indicator { GetLipsShift(), GetMAMethod(), GetAppliedPrice() /*]*/, - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_AppliedPrice.mqh b/Indicators/Indi_AppliedPrice.mqh index fa910dc8b..0132b481f 100644 --- a/Indicators/Indi_AppliedPrice.mqh +++ b/Indicators/Indi_AppliedPrice.mqh @@ -87,13 +87,13 @@ class Indi_AppliedPrice : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_INDICATOR: if (HasDataSource()) { - _value = Indi_AppliedPrice::iAppliedPriceOnIndicator(GetDataSource(), GetAppliedPrice(), _ishift); + _value = + Indi_AppliedPrice::iAppliedPriceOnIndicator(GetDataSource(), GetAppliedPrice(), ToRelShift(_abs_shift)); } break; default: diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index f7e8f52c1..d9df71a79 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -117,17 +117,16 @@ class Indi_BWMFI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = BWMFI_BUFFER, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = BWMFI_BUFFER, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_BWMFI::iBWMFI(GetSymbol(), GetTf(), _ishift, (ENUM_BWMFI_BUFFER)_mode, THIS_PTR); + _value = Indi_BWMFI::iBWMFI(GetSymbol(), GetTf(), ToRelShift(_abs_shift), (ENUM_BWMFI_BUFFER)_mode, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_BWZT.mqh b/Indicators/Indi_BWZT.mqh index d05f05624..c709bf10b 100644 --- a/Indicators/Indi_BWZT.mqh +++ b/Indicators/Indi_BWZT.mqh @@ -251,19 +251,19 @@ class Indi_BWZT : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = Indi_BWZT::iBWZT(THIS_PTR, _mode, _ishift); + _value = Indi_BWZT::iBWZT(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = Indi_BWZT::iBWZT(THIS_PTR, _mode, _ishift); + _value = Indi_BWZT::iBWZT(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index 090574ef6..f22163aa7 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -255,28 +255,27 @@ class Indi_Bands : public Indicator { * 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 _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Bands::iBands(GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), - GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, _ishift, THIS_PTR); + GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ONCALCULATE: - _value = - Indi_Bands::iBandsOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), - GetBandsShift(), GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, _ishift); + _value = Indi_Bands::iBandsOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), + GetDeviation(), GetBandsShift(), GetAppliedPrice(), + (ENUM_BANDS_LINE)_mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), - GetBandsShift(), GetDeviation(), GetAppliedPrice() /* ] */, _mode, _ishift); + GetBandsShift(), GetDeviation(), GetAppliedPrice() /* ] */, _mode, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: // Calculating bands value from specified indicator. _value = Indi_Bands::iBandsOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), GetAppliedPrice(), - (ENUM_BANDS_LINE)_mode, _ishift, THIS_PTR); + (ENUM_BANDS_LINE)_mode, ToRelShift(_abs_shift), THIS_PTR); break; } return _value; diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index 27efa2cae..aab484fac 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -91,16 +91,16 @@ class Indi_BearsPower : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = _value = iBearsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift, THIS_PTR); + _value = _value = + iBearsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index 50db9e96f..bb9bf2d6f 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -91,16 +91,15 @@ class Indi_BullsPower : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = iBullsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift, THIS_PTR); + _value = iBullsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetPeriod() /**/, - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index 5734716a7..93065d544 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -166,30 +166,29 @@ class Indi_CCI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { - int _ishift = _shift + iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // @fixit Somehow shift isn't used neither in MT4 nor MT5. - _value = Indi_CCI::iCCI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift /* + iparams.shift*/, - THIS_PTR); + _value = Indi_CCI::iCCI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), + ToRelShift(_abs_shift) /* + 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*/); + _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), + ToRelShift(_abs_shift) /* + iparams.shift*/); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), - GetAppliedPrice() /* ] */, 0, _ishift); + GetAppliedPrice() /* ] */, 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: ValidateSelectedDataSource(); // @fixit Somehow shift isn't used neither in MT4 nor MT5. - _value = - Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), _ishift /* + iparams.shift*/); + _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), + ToRelShift(_abs_shift) /* + iparams.shift*/); break; } return _value; diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index 5f0452621..b15c4bdff 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -198,22 +198,21 @@ class Indi_CHO : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _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); + GetInputVolume() /*]*/, _mode, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastMA(), - GetSlowMA(), GetSmoothMethod(), GetInputVolume() /*]*/, 0, _ishift); + GetSlowMA(), GetSmoothMethod(), GetInputVolume() /*]*/, 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: _value = Indi_CHO::iChaikinOnIndicator(GetDataSource(), /*[*/ GetFastMA(), GetSlowMA(), GetSmoothMethod(), - GetInputVolume() /*]*/, _mode, _ishift); + GetInputVolume() /*]*/, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index 6cbbd7228..8a38c6d79 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -189,20 +189,19 @@ class Indi_CHV : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = iCHV(THIS_PTR, GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod(), _mode, _ishift); + _value = iCHV(THIS_PTR, GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod(), _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), - GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _ishift); + GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = iCHV(THIS_PTR, GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod(), _mode, _ishift); + _value = iCHV(THIS_PTR, GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index df7682591..3465ca8bf 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -125,19 +125,19 @@ class Indi_ColorBars : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = Indi_ColorBars::iColorBars(THIS_PTR, _mode, _ishift); + _value = Indi_ColorBars::iColorBars(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = Indi_ColorBars::iColorBars(THIS_PTR, _mode, _ishift); + _value = Indi_ColorBars::iColorBars(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index 21fbae9c2..9751e4a8e 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -135,19 +135,19 @@ class Indi_ColorCandlesDaily : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = Indi_ColorCandlesDaily::iCCD(THIS_PTR, _mode, _ishift); + _value = Indi_ColorCandlesDaily::iCCD(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = Indi_ColorCandlesDaily::iCCD(THIS_PTR, _mode, _ishift); + _value = Indi_ColorCandlesDaily::iCCD(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index 8359515bc..f52044f8b 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -218,19 +218,19 @@ class Indi_ColorLine : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = iColorLine(THIS_PTR, _mode, _ishift); + _value = iColorLine(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = iColorLine(THIS_PTR, _mode, _ishift); + _value = iColorLine(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_CustomMovingAverage.mqh b/Indicators/Indi_CustomMovingAverage.mqh index afd5b677a..3dd961f02 100644 --- a/Indicators/Indi_CustomMovingAverage.mqh +++ b/Indicators/Indi_CustomMovingAverage.mqh @@ -79,13 +79,12 @@ class Indi_CustomMovingAverage : public Indicator /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), - GetSmoothShift(), GetSmoothMethod() /*]*/, 0, _ishift); + GetSmoothShift(), GetSmoothMethod() /*]*/, 0, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index 69facb42d..2f2f33632 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -180,29 +180,28 @@ class Indi_DEMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _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); + ToRelShift(_abs_shift), _mode, THIS_PTR); break; case IDATA_ONCALCULATE: _value = Indi_DEMA::iDEMAOnIndicator(GetDataSource(), /*[*/ GetPeriod(), GetMAShift(), GetAppliedPrice() /*]*/, - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /*[*/ GetPeriod(), GetMAShift(), - GetAppliedPrice() /*]*/, _mode, _ishift); + GetAppliedPrice() /*]*/, _mode, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: // Calculating DEMA value from specified indicator. _value = Indi_DEMA::iDEMAOnIndicator(GetDataSource(), /*[*/ GetPeriod(), GetMAShift(), GetAppliedPrice() /*]*/, - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; } return _value; diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index c0cfb11b8..690909d80 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -88,16 +88,15 @@ class Indi_DeMarker : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = _value = Indi_DeMarker::iDeMarker(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); + _value = _value = Indi_DeMarker::iDeMarker(GetSymbol(), GetTf(), GetPeriod(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _ishift); + 0, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index 0544a56f3..d4bf22c37 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -79,11 +79,10 @@ class Indi_Demo : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { - int _ishift = _shift + iparams.GetShift(); - double _value = Indi_Demo::iDemo(THIS_PTR, _ishift); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { + double _value = Indi_Demo::iDemo(THIS_PTR, ToRelShift(_abs_shift)); if (idparams.is_draw) { - draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(_ishift), _value); + draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(ToRelShift(_abs_shift)), _value); } return _value; } diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index 0fa35cd23..4a9bcf17d 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -136,20 +136,19 @@ class Indi_DetrendedPrice : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = iDPO(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, _ishift); + _value = iDPO(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _ishift); + 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = iDPO(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, _ishift); + _value = iDPO(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index 81c0ac92a..d12dc6368 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -194,15 +194,15 @@ class Indi_Drawer : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_Drawer::iDrawer(GetSymbol(), GetTf(), _ishift, THIS_PTR); + _value = Indi_Drawer::iDrawer(GetSymbol(), GetTf(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_INDICATOR: - _value = Indi_Drawer::iDrawerOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), _ishift); + _value = + Indi_Drawer::iDrawerOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 902f3478c..7fc7ffd19 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -204,28 +204,28 @@ class Indi_Envelopes : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Envelopes::iEnvelopes(GetSymbol(), GetTf(), GetMAPeriod(), GetMAMethod(), GetMAShift(), - GetAppliedPrice(), GetDeviation(), _mode, _ishift, THIS_PTR); + GetAppliedPrice(), GetDeviation(), _mode, ToRelShift(_abs_shift), 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); + _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetMAPeriod(), - GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation() /**/, _mode, _ishift); + _value = + iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetMAPeriod(), + GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation() /**/, _mode, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: _value = Indi_Envelopes::iEnvelopesOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), GetMAMethod(), GetAppliedPrice(), GetMAShift(), GetDeviation(), - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index c74c90071..a60b03669 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -105,17 +105,16 @@ class Indi_Force : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = - Indi_Force::iForce(GetSymbol(), GetTf(), GetPeriod(), GetMAMethod(), GetAppliedPrice(), _ishift, THIS_PTR); + _value = Indi_Force::iForce(GetSymbol(), GetTf(), GetPeriod(), GetMAMethod(), GetAppliedPrice(), + ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - GetMAMethod(), GetAppliedPrice(), VOLUME_TICK /*]*/, 0, _ishift); + GetMAMethod(), GetAppliedPrice(), VOLUME_TICK /*]*/, 0, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index a7d7d6d2e..ca3595020 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -177,23 +177,24 @@ class Indi_FrAMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = - iFrAMA(GetSymbol(), GetTf(), GetPeriod(), GetFRAMAShift(), GetAppliedPrice(), _mode, _ishift, THIS_PTR); + _value = iFrAMA(GetSymbol(), GetTf(), GetPeriod(), GetFRAMAShift(), GetAppliedPrice(), _mode, + ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ONCALCULATE: - _value = iFrAMAOnIndicator(GetDataSource(), GetPeriod(), GetFRAMAShift(), GetAppliedPrice(), _mode, _ishift); + _value = iFrAMAOnIndicator(GetDataSource(), GetPeriod(), GetFRAMAShift(), GetAppliedPrice(), _mode, + ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - GetFRAMAShift() /*]*/, 0, _ishift); + GetFRAMAShift() /*]*/, 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = iFrAMAOnIndicator(GetDataSource(), GetPeriod(), GetFRAMAShift(), GetAppliedPrice(), _mode, _ishift); + _value = iFrAMAOnIndicator(GetDataSource(), GetPeriod(), GetFRAMAShift(), GetAppliedPrice(), _mode, + ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index afb24f0b2..6e920d173 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -104,15 +104,16 @@ class Indi_Fractals : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _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 = + Indi_Fractals::iFractals(GetSymbol(), GetTf(), (ENUM_LO_UP_LINE)_mode, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index 380377b1c..cbec2fac4 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -175,14 +175,13 @@ class Indi_Gator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Gator::iGator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice(), - (ENUM_GATOR_HISTOGRAM)_mode, _ishift, THIS_PTR); + (ENUM_GATOR_HISTOGRAM)_mode, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ @@ -190,7 +189,7 @@ class Indi_Gator : public Indicator { GetLipsShift(), GetMAMethod(), GetAppliedPrice() /**/, - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index 4c1b5ee3a..6727150e7 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -215,9 +215,8 @@ class Indi_HeikenAshi : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = HA_OPEN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = HA_OPEN, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: @@ -238,17 +237,18 @@ class Indi_HeikenAshi : public Indicator { break; } #endif - _value = Indi_HeikenAshi::iHeikenAshi(THIS_PTR, _mode, _ishift); + _value = Indi_HeikenAshi::iHeikenAshi(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM_LEGACY: _value = Indi_HeikenAshi::iCustomLegacyHeikenAshi(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, - _ishift, THIS_PTR); + ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_INDICATOR: - _value = Indi_HeikenAshi::iHeikenAshi(THIS_PTR, _mode, _ishift); + _value = Indi_HeikenAshi::iHeikenAshi(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index 02a009ca9..42878ac52 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -144,17 +144,16 @@ class Indi_Ichimoku : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Ichimoku::iIchimoku(GetSymbol(), GetTf(), GetTenkanSen(), GetKijunSen(), GetSenkouSpanB(), _mode, - _ishift, THIS_PTR); + ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetTenkanSen(), - GetKijunSen(), GetSenkouSpanB() /*]*/, _mode, _ishift); + GetKijunSen(), GetSenkouSpanB() /*]*/, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Killzones.mqh b/Indicators/Indi_Killzones.mqh index 4712a66f8..eb71c61e1 100644 --- a/Indicators/Indi_Killzones.mqh +++ b/Indicators/Indi_Killzones.mqh @@ -131,10 +131,9 @@ class Indi_Killzones : public Indicator { /** * Returns the indicator's value. */ - IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { float _value = FLT_MAX; int _index = (int)_mode / 2; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // Builtin mode not supported. @@ -144,8 +143,8 @@ class Indi_Killzones : public Indicator { ikt.Set(::TimeGMT()); if (ikt.CheckHours(_index)) { // Pass values to check for new highs or lows. - ikt.Update(_mode % 2 == 0 ? (float)GetCandle() PTR_DEREF GetHigh(_ishift) - : (float)GetCandle() PTR_DEREF GetLow(_ishift), + ikt.Update(_mode % 2 == 0 ? (float)GetCandle() PTR_DEREF GetHigh(ToRelShift(_abs_shift)) + : (float)GetCandle() PTR_DEREF GetLow(ToRelShift(_abs_shift)), _index); } // Set a final value. diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 7102f3fa8..2258d5966 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -633,26 +633,25 @@ class Indi_MA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_MA::iMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), - _ishift, THIS_PTR); + ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ONCALCULATE: _value = Indi_MA::iMAOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), - GetMAMethod(), GetAppliedPrice(), _ishift); + GetMAMethod(), GetAppliedPrice(), ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), - GetMAShift(), GetMAMethod(), GetAppliedPrice() /* ] */, 0, _ishift); + GetMAShift(), GetMAMethod(), GetAppliedPrice() /* ] */, 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: // Calculating MA value from specified indicator. _value = Indi_MA::iMAOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), - GetMAMethod(), GetAppliedPrice(), _ishift); + GetMAMethod(), GetAppliedPrice(), ToRelShift(_abs_shift)); break; } diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index 98f3cbf4f..f2b74ebd6 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -105,18 +105,17 @@ class Indi_MACD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_MACD::iMACD(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), - GetAppliedPrice(), (ENUM_SIGNAL_LINE)_mode, _ishift, THIS_PTR); + GetAppliedPrice(), (ENUM_SIGNAL_LINE)_mode, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), - GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, _mode, _ishift); + GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index 3f21ef6d6..37ff09cdc 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -99,20 +99,20 @@ class Indi_MFI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: #ifdef __MQL4__ _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), _ishift); #else // __MQL5__ - _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedVolume(), _ishift, THIS_PTR); + _value = + Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedVolume(), ToRelShift(_abs_shift), THIS_PTR); #endif break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - VOLUME_TICK /*]*/, 0, _ishift); + VOLUME_TICK /*]*/, 0, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index 3d15a2629..fe9aa452c 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -176,20 +176,21 @@ class Indi_MassIndex : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = Indi_MassIndex::iMI(THIS_PTR, GetPeriod(), GetSecondPeriod(), GetSumPeriod(), _mode, _ishift); + _value = Indi_MassIndex::iMI(THIS_PTR, GetPeriod(), GetSecondPeriod(), GetSumPeriod(), _mode, + ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _ishift); + GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = Indi_MassIndex::iMI(THIS_PTR, GetPeriod(), GetSecondPeriod(), GetSumPeriod(), _mode, _ishift); + _value = Indi_MassIndex::iMI(THIS_PTR, GetPeriod(), GetSecondPeriod(), GetSumPeriod(), _mode, + ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 5646d34c0..122c15e37 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -138,35 +138,34 @@ class Indi_Momentum : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // @fixit Somehow shift isn't used neither in MT4 nor MT5. - _value = Indi_Momentum::iMomentum(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), iparams.shift + _ishift, - THIS_PTR); + _value = Indi_Momentum::iMomentum(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), + iparams.shift + ToRelShift(_abs_shift), 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); + iparams.shift + ToRelShift(_abs_shift)); if (idparams.is_draw) { - draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + _shift), _value, 1); + draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); } break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _ishift); + 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: ValidateSelectedDataSource(); // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), - iparams.shift + _shift); + iparams.shift + ToRelShift(_abs_shift)); if (idparams.is_draw) { - draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + _shift), _value, 1); + draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); } break; } diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index 7156fa2ad..2740f9245 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -114,20 +114,19 @@ class Indi_OBV : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: #ifdef __MQL4__ _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedPrice(), _ishift); #else // __MQL5__ - _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedVolume(), _ishift, THIS_PTR); + _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedVolume(), ToRelShift(_abs_shift), THIS_PTR); #endif break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, - 0, _ishift); + 0, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index bd72bb5da..86017ceeb 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -99,18 +99,17 @@ class Indi_OsMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { - int _ishift = _shift + iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_OsMA::iOsMA(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), - GetAppliedPrice(), _ishift, THIS_PTR); + GetAppliedPrice(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), - GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, 0, _ishift); + GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, 0, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index 94adc5634..5a767296d 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -99,14 +99,13 @@ class Indi_Pivot : public Indicator { * @return * Returns IndicatorDataEntry struct filled with indicator values. */ - virtual IndicatorDataEntry GetEntry(int _shift = 0) { - int _ishift = _shift + iparams.GetShift(); - long _bar_time = GetCandle() PTR_DEREF GetBarTime(_ishift); + virtual IndicatorDataEntry GetEntry(int _rel_shift = 0) { + long _bar_time = GetCandle() PTR_DEREF GetBarTime(_rel_shift); 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 = GetCandle() PTR_DEREF GetBarTime(_ishift); + BarOHLC _ohlc = GetOHLC(_rel_shift); + _entry.timestamp = GetCandle() PTR_DEREF GetBarTime(_rel_shift); if (_ohlc.IsValid()) { _entry.Resize(Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))); _ohlc.GetPivots(GetMethod(), _entry.values[0].value.vdbl, _entry.values[1].value.vdbl, @@ -117,7 +116,7 @@ class Indi_Pivot : public Indicator { _entry.values[i].SetDataType(TYPE_DOUBLE); } } - GetEntryAlter(_entry, _shift); + GetEntryAlter(_entry, _rel_shift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { idata.Add(_entry, _bar_time); @@ -137,9 +136,8 @@ class Indi_Pivot : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { - int _ishift = _shift + iparams.GetShift(); - return GetEntry(_ishift)[_mode]; + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { + return GetEntry(ToRelShift(_abs_shift))[_mode]; } /* Getters */ diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index d0a3582aa..759efadb9 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -126,20 +126,19 @@ class Indi_PriceChannel : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = iPriceChannel(THIS_PTR, GetPeriod(), _mode, _ishift); + _value = iPriceChannel(THIS_PTR, GetPeriod(), _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _ishift); + 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = iPriceChannel(THIS_PTR, GetPeriod(), _mode, _ishift); + _value = iPriceChannel(THIS_PTR, GetPeriod(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index ce6970486..cbe8b7213 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -88,13 +88,12 @@ class Indi_PriceFeeder : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { int data_size = ArraySize(iparams.price_data); - int _ishift = _shift + iparams.GetShift(); - if (_ishift >= data_size || _ishift < 0) return DBL_MIN; + if (_abs_shift >= data_size || _abs_shift < 0) return DBL_MIN; - double _value = iparams.price_data[data_size - _ishift - 1]; + double _value = iparams.price_data[data_size - _abs_shift - 1]; return _value; } diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index 28b131513..6f51e2e4b 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -140,20 +140,19 @@ class Indi_PriceVolumeTrend : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = iPVT(THIS_PTR, GetAppliedVolume(), _mode, _ishift); + _value = iPVT(THIS_PTR, GetAppliedVolume(), _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), - /*[*/ GetAppliedVolume() /*]*/, 0, _ishift); + /*[*/ GetAppliedVolume() /*]*/, 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = iPVT(THIS_PTR, GetAppliedVolume(), _mode, _ishift); + _value = iPVT(THIS_PTR, GetAppliedVolume(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index a45448fcb..975e336ac 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -104,8 +104,7 @@ class Indi_RS : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { - int _ishift = _shift + iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_MATH: // Updating Maths' data sources to be the same as RS data source. diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index b63cac3e6..aa522f958 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -309,25 +309,24 @@ class Indi_RSI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; double _res[]; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = - Indi_RSI::iRSI(GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), _ishift, THIS_PTR); + _value = Indi_RSI::iRSI(GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), + ToRelShift(_abs_shift), 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); + iparams.GetAppliedPrice() /* ] */, 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: _value = Indi_RSI::iRSIOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), iparams.GetPeriod(), - iparams.GetAppliedPrice(), _ishift); + iparams.GetAppliedPrice(), ToRelShift(_abs_shift)); break; } return _value; diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index ca4da8681..2c70f66fd 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -94,16 +94,16 @@ class Indi_RVI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_RVI::iRVI(GetSymbol(), GetTf(), GetPeriod(), (ENUM_SIGNAL_LINE)_mode, _ishift, THIS_PTR); + _value = Indi_RVI::iRVI(GetSymbol(), GetTf(), GetPeriod(), (ENUM_SIGNAL_LINE)_mode, ToRelShift(_abs_shift), + THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - _mode, _ishift); + _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index 3eac51e1f..14929f1a8 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -126,20 +126,19 @@ class Indi_RateOfChange : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = iROC(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, _ishift); + _value = iROC(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _ishift); + 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = iROC(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, _ishift); + _value = iROC(THIS_PTR, GetPeriod(), GetAppliedPrice(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_SAR.mqh b/Indicators/Indi_SAR.mqh index b1200e193..9c4be3413 100644 --- a/Indicators/Indi_SAR.mqh +++ b/Indicators/Indi_SAR.mqh @@ -90,16 +90,15 @@ class Indi_SAR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_SAR::iSAR(GetSymbol(), GetTf(), GetStep(), GetMax(), _ishift, THIS_PTR); + _value = Indi_SAR::iSAR(GetSymbol(), GetTf(), GetStep(), GetMax(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetStep(), - GetMax() /*]*/, _mode, _ishift); + GetMax() /*]*/, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 375499ae2..e04142519 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -226,25 +226,24 @@ class Indi_StdDev : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_StdDev::iStdDev(GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), GetMAMethod(), - GetAppliedPrice(), _ishift, THIS_PTR); + GetAppliedPrice(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ONCALCULATE: _value = Indi_StdDev::iStdDevOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), - GetMAShift(), GetAppliedPrice(), _ishift, THIS_PTR); + GetMAShift(), GetAppliedPrice(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetMAPeriod(), - GetMAShift(), GetMAMethod() /*]*/, 0, _ishift); + GetMAShift(), GetMAMethod() /*]*/, 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: _value = Indi_StdDev::iStdDevOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), - GetMAShift(), GetAppliedPrice(), _ishift, THIS_PTR); + GetMAShift(), GetAppliedPrice(), ToRelShift(_abs_shift), THIS_PTR); break; } return _value; diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index 25eeb7686..1ca6a0ea9 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -110,17 +110,16 @@ class Indi_Stochastic : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Stochastic::iStochastic(GetSymbol(), GetTf(), GetKPeriod(), GetDPeriod(), GetSlowing(), - GetMAMethod(), GetPriceField(), _mode, _ishift, THIS_PTR); + GetMAMethod(), GetPriceField(), _mode, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetKPeriod(), - GetDPeriod(), GetSlowing() /*]*/, _mode, _ishift); + GetDPeriod(), GetSlowing() /*]*/, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index 6b89d2cba..0fbc8fdec 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -154,22 +154,23 @@ class Indi_TEMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _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, + ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ONCALCULATE: - _value = iTEMAOnIndicator(GetDataSource(), GetPeriod(), GetTEMAShift(), GetAppliedPrice(), _mode, _ishift); + _value = iTEMAOnIndicator(GetDataSource(), GetPeriod(), GetTEMAShift(), GetAppliedPrice(), _mode, + ToRelShift(_abs_shift)); case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - GetTEMAShift() /*]*/, 0, _ishift); + GetTEMAShift() /*]*/, 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = iTEMAOnIndicator(GetDataSource(), GetPeriod(), GetTEMAShift(), GetAppliedPrice(), _mode, _ishift); + _value = iTEMAOnIndicator(GetDataSource(), GetPeriod(), GetTEMAShift(), GetAppliedPrice(), _mode, + ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index ac08b6b1d..e5ccd25e2 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -154,23 +154,24 @@ class Indi_TRIX : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_TRIX::iTriX(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _ishift, - THIS_PTR); + _value = Indi_TRIX::iTriX(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, + ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ONCALCULATE: - _value = Indi_TRIX::iTriXOnIndicator(GetDataSource(), GetPeriod(), GetAppliedPrice(), _mode, _ishift); + _value = + Indi_TRIX::iTriXOnIndicator(GetDataSource(), GetPeriod(), GetAppliedPrice(), _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _ishift); + 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = Indi_TRIX::iTriXOnIndicator(GetDataSource(), GetPeriod(), GetAppliedPrice(), _mode, _ishift); + _value = + Indi_TRIX::iTriXOnIndicator(GetDataSource(), GetPeriod(), GetAppliedPrice(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index d00c0526a..cbf4a091b 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -249,25 +249,24 @@ class Indi_UltimateOscillator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: _value = Indi_UltimateOscillator::iUO(THIS_PTR, GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), - GetMiddleK(), GetSlowK(), _mode, _ishift); + GetMiddleK(), GetSlowK(), _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), GetMiddleK(), GetSlowK() /*]*/, - 0, _ishift); + 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: _value = Indi_UltimateOscillator::iUO(THIS_PTR, GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), - GetMiddleK(), GetSlowK(), _mode, _ishift); + GetMiddleK(), GetSlowK(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index 037e25c0a..e93fa1eae 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -177,30 +177,29 @@ class Indi_VIDYA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_VIDYA::iVIDyA(GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift(), - GetAppliedPrice() /*]*/, 0, _ishift, THIS_PTR); + GetAppliedPrice() /*]*/, 0, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ONCALCULATE: - _value = - Indi_VIDYA::iVIDyAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), - GetVIDYAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + _value = Indi_VIDYA::iVIDyAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), + GetMAPeriod(), GetVIDYAShift(), GetAppliedPrice() /*]*/, _mode, + ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift() /*]*/, - 0, _ishift); + 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = - Indi_VIDYA::iVIDyAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), - GetVIDYAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + _value = Indi_VIDYA::iVIDyAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), + GetMAPeriod(), GetVIDYAShift(), GetAppliedPrice() /*]*/, _mode, + ToRelShift(_abs_shift), THIS_PTR); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index 3854a7051..48d436b1d 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -153,20 +153,19 @@ class Indi_VROC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = iVROC(THIS_PTR, GetPeriod(), GetAppliedVolume(), _mode, _ishift); + _value = iVROC(THIS_PTR, GetPeriod(), GetAppliedVolume(), _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), - /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _ishift); + /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = iVROC(THIS_PTR, GetPeriod(), GetAppliedVolume(), _mode, _ishift); + _value = iVROC(THIS_PTR, GetPeriod(), GetAppliedVolume(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index feaf8a5c4..d5b607764 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -147,20 +147,19 @@ class Indi_Volumes : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = Indi_Volumes::iVolumes(THIS_PTR, GetAppliedVolume(), _mode, _ishift); + _value = Indi_Volumes::iVolumes(THIS_PTR, GetAppliedVolume(), _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), - /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift); + /*[*/ GetAppliedVolume() /*]*/, _mode, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = Indi_Volumes::iVolumes(THIS_PTR, GetAppliedVolume(), _mode, _ishift); + _value = Indi_Volumes::iVolumes(THIS_PTR, GetAppliedVolume(), _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_WPR.mqh b/Indicators/Indi_WPR.mqh index 3c978b23d..192b9d378 100644 --- a/Indicators/Indi_WPR.mqh +++ b/Indicators/Indi_WPR.mqh @@ -117,16 +117,15 @@ class Indi_WPR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_WPR::iWPR(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); + _value = Indi_WPR::iWPR(GetSymbol(), GetTf(), GetPeriod(), ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _ishift); + 0, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index e2103a1ad..e8769d903 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -149,19 +149,19 @@ class Indi_WilliamsAD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = iWAD(THIS_PTR, _mode, _ishift); + _value = iWAD(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), 0, _ishift); + _value = + iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), 0, ToRelShift(_abs_shift)); break; case IDATA_INDICATOR: - _value = iWAD(THIS_PTR, _mode, _ishift); + _value = iWAD(THIS_PTR, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index e2fadc062..35c46706d 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -373,21 +373,22 @@ class Indi_ZigZag : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: case IDATA_ONCALCULATE: - _value = iZigZag(THIS_PTR, GetDepth(), GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, _ishift); + _value = iZigZag(THIS_PTR, GetDepth(), GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, + ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: - _value = - Indi_ZigZag::iCustomZigZag(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetDepth(), - GetDeviation(), GetBackstep() /*]*/, (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); + _value = Indi_ZigZag::iCustomZigZag(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetDepth(), + GetDeviation(), GetBackstep() /*]*/, (ENUM_ZIGZAG_LINE)_mode, + ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_INDICATOR: - _value = iZigZag(THIS_PTR, GetDepth(), GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, _ishift); + _value = iZigZag(THIS_PTR, GetDepth(), GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, + ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 9bc8b1bb1..db25ae9c1 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -295,17 +295,16 @@ class Indi_ZigZagColor : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_ONCALCULATE: _value = Indi_ZigZagColor::iZigZagColor(THIS_PTR, GetDepth(), GetDeviation(), GetBackstep(), - (ENUM_ZIGZAG_LINE)_mode, _ishift); + (ENUM_ZIGZAG_LINE)_mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), - /*[*/ GetDepth(), GetDeviation(), GetBackstep() /*]*/, _mode, _ishift); + /*[*/ GetDepth(), GetDeviation(), GetBackstep() /*]*/, _mode, ToRelShift(_abs_shift)); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/OHLC/Indi_OHLC.mqh b/Indicators/OHLC/Indi_OHLC.mqh index 411cae002..08ac367f2 100644 --- a/Indicators/OHLC/Indi_OHLC.mqh +++ b/Indicators/OHLC/Indi_OHLC.mqh @@ -89,8 +89,7 @@ class Indi_OHLC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { - int _ishift = _shift + iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { ENUM_APPLIED_PRICE _ap = PRICE_OPEN; switch (_mode) { case INDI_OHLC_CLOSE: @@ -106,6 +105,6 @@ class Indi_OHLC : public Indicator { _ap = PRICE_LOW; break; } - return GetDataSource() PTR_DEREF GetPrice(_ap, _shift); + return GetDataSource() PTR_DEREF GetPrice(_ap, ToRelShift(_abs_shift)); } }; diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index c4f4e3a44..cac647fb6 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -73,10 +73,9 @@ class Indi_Price : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { - int _ishift = _shift + iparams.GetShift(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { return GetCandle() PTR_DEREF GetSpecificAppliedPriceValueStorage(iparams.GetAppliedPrice()) - PTR_DEREF Fetch(_ishift); + PTR_DEREF Fetch(ToRelShift(_abs_shift)); } /** diff --git a/Indicators/Special/Indi_Custom.mqh b/Indicators/Special/Indi_Custom.mqh index 332af4bdf..3d94d5ffa 100644 --- a/Indicators/Special/Indi_Custom.mqh +++ b/Indicators/Special/Indi_Custom.mqh @@ -98,23 +98,23 @@ class Indi_Custom : public Indicator { /** * Returns the indicator's value. */ - IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_ICUSTOM: switch (iparams.GetParamsSize()) { case 0: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, _mode, _ishift); + _value = + iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, _mode, ToRelShift(_abs_shift)); break; case 1: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, - iparams.GetParam(1).ToValue(), _mode, _ishift); + iparams.GetParam(1).ToValue(), _mode, ToRelShift(_abs_shift)); break; case 2: - _value = - iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, - iparams.GetParam(1).ToValue(), iparams.GetParam(2).ToValue(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, + iparams.GetParam(1).ToValue(), iparams.GetParam(2).ToValue(), _mode, + ToRelShift(_abs_shift)); break; } break; diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index c4084a06e..0c8ed1d63 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -114,9 +114,8 @@ class Indi_Math : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = EMPTY_VALUE; - int _ishift = _shift + iparams.GetShift(); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_INDICATOR: if (!indi_src.IsSet()) { @@ -134,12 +133,12 @@ class Indi_Math : public Indicator { case MATH_OP_MODE_BUILTIN: _value = Indi_Math::iMathOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetOpBuiltIn(), GetMode1(), GetMode2(), GetShift1(), - GetShift2() /*]*/, 0, _ishift, &this); + GetShift2() /*]*/, 0, ToRelShift(_abs_shift), &this); break; case MATH_OP_MODE_CUSTOM_FUNCTION: _value = Indi_Math::iMathOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetOpFunction(), GetMode1(), GetMode2(), GetShift1(), - GetShift2() /*]*/, 0, _ishift, &this); + GetShift2() /*]*/, 0, ToRelShift(_abs_shift), &this); break; } break; diff --git a/Storage/ValueStorage.applied_price.h b/Storage/ValueStorage.applied_price.h index 902dfa5ab..bb752a5b5 100644 --- a/Storage/ValueStorage.applied_price.h +++ b/Storage/ValueStorage.applied_price.h @@ -54,19 +54,20 @@ class AppliedPriceValueStorage : public HistoryValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - double Fetch(int _shift) override { + double Fetch(int _rel_shift) override { switch (ap) { case PRICE_OPEN: case PRICE_HIGH: case PRICE_LOW: case PRICE_CLOSE: - return Fetch(ap, _shift); + return Fetch(ap, _rel_shift); case PRICE_MEDIAN: - return (Fetch(PRICE_HIGH, _shift) + Fetch(PRICE_LOW, _shift)) / 2; + return (Fetch(PRICE_HIGH, _rel_shift) + Fetch(PRICE_LOW, _rel_shift)) / 2; case PRICE_TYPICAL: - return (Fetch(PRICE_HIGH, _shift) + Fetch(PRICE_LOW, _shift) + Fetch(PRICE_CLOSE, _shift)) / 3; + return (Fetch(PRICE_HIGH, _rel_shift) + Fetch(PRICE_LOW, _rel_shift) + Fetch(PRICE_CLOSE, _rel_shift)) / 3; case PRICE_WEIGHTED: - return (Fetch(PRICE_HIGH, _shift) + Fetch(PRICE_LOW, _shift) + (2 * Fetch(PRICE_CLOSE, _shift))) / 4; + return (Fetch(PRICE_HIGH, _rel_shift) + Fetch(PRICE_LOW, _rel_shift) + (2 * Fetch(PRICE_CLOSE, _rel_shift))) / + 4; default: Print("We shouldn't be here!"); DebugBreak(); @@ -74,7 +75,9 @@ class AppliedPriceValueStorage : public HistoryValueStorage { return 0.0; } - double Fetch(ENUM_APPLIED_PRICE _ap, int _shift) { return indi_candle REF_DEREF GetPrice(_ap, RealShift(_shift)); } + double Fetch(ENUM_APPLIED_PRICE _ap, int _rel_shift) { + return indi_candle REF_DEREF GetPrice(_ap, RealShift(_rel_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 bbe358b36..1700bef52 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -153,7 +153,7 @@ class ValueStorage : public IValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - virtual C Fetch(int _shift) { + virtual C Fetch(int _rel_shift) { Alert("Fetching data by shift is not supported from this value storage!"); DebugBreak(); return (C)0; diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index 61c378964..ed11af3c9 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -84,6 +84,8 @@ class HistoryValueStorage : public ValueStorage { /** * Number of bars passed from the start. There will be a single bar at the start. + * + * Note that number of bars are decremented by iparams.shift of the candle indicator. */ int BarsFromStart() { if (!indi_candle.ObjectExists()) { diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 7f8478955..88887f356 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -54,5 +54,5 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - C Fetch(int _shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_shift)); } + C Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_rel_shift)); } }; diff --git a/Storage/ValueStorage.native.h b/Storage/ValueStorage.native.h index 46ca12565..b034ca646 100644 --- a/Storage/ValueStorage.native.h +++ b/Storage/ValueStorage.native.h @@ -59,7 +59,7 @@ class NativeValueStorage : public ValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - C Fetch(int _shift) override { + C Fetch(int _rel_shift) override { if (_shift < 0 || _shift >= ArraySize(_values)) { return (C)EMPTY_VALUE; // Print("Invalid buffer data index: ", _shift, ". Buffer size: ", ArraySize(_values)); diff --git a/Storage/ValueStorage.price_median.h b/Storage/ValueStorage.price_median.h index 24b9c1a1a..3752af417 100644 --- a/Storage/ValueStorage.price_median.h +++ b/Storage/ValueStorage.price_median.h @@ -49,9 +49,9 @@ class PriceMedianValueStorage : public HistoryValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - double Fetch(int _shift) override { + double Fetch(int _rel_shift) override { ResetLastError(); - double _value = indi_candle REF_DEREF GetOHLC(RealShift(_shift)).GetMedian(); + double _value = indi_candle REF_DEREF GetOHLC(RealShift(_rel_shift)).GetMedian(); if (_LastError != ERR_NO_ERROR) { Print("Cannot fetch OHLC! Error: ", _LastError); DebugBreak(); diff --git a/Storage/ValueStorage.price_typical.h b/Storage/ValueStorage.price_typical.h index 91337dc77..4bf51f786 100644 --- a/Storage/ValueStorage.price_typical.h +++ b/Storage/ValueStorage.price_typical.h @@ -46,9 +46,9 @@ class PriceTypicalValueStorage : public HistoryValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - double Fetch(int _shift) override { + double Fetch(int _rel_shift) override { ResetLastError(); - double _value = indi_candle REF_DEREF GetOHLC(RealShift(_shift)).GetTypical(); + double _value = indi_candle REF_DEREF GetOHLC(RealShift(_rel_shift)).GetTypical(); if (_LastError != ERR_NO_ERROR) { Print("Cannot fetch OHLC! Error: ", _LastError); DebugBreak(); diff --git a/Storage/ValueStorage.price_weighted.h b/Storage/ValueStorage.price_weighted.h index 1fab60e08..17818583e 100644 --- a/Storage/ValueStorage.price_weighted.h +++ b/Storage/ValueStorage.price_weighted.h @@ -46,9 +46,9 @@ class PriceWeightedValueStorage : public HistoryValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - double Fetch(int _shift) override { + double Fetch(int _rel_shift) override { ResetLastError(); - double _value = indi_candle REF_DEREF GetOHLC(RealShift(_shift)).GetWeighted(); + double _value = indi_candle REF_DEREF GetOHLC(RealShift(_rel_shift)).GetWeighted(); if (_LastError != ERR_NO_ERROR) { Print("Cannot fetch OHLC! Error: ", _LastError); DebugBreak(); diff --git a/Storage/ValueStorage.spread.h b/Storage/ValueStorage.spread.h index 3b4202e11..98e3689fc 100644 --- a/Storage/ValueStorage.spread.h +++ b/Storage/ValueStorage.spread.h @@ -47,5 +47,5 @@ class SpreadValueStorage : public HistoryValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - long Fetch(int _shift) override { return indi_candle REF_DEREF GetSpread(RealShift(_shift)); } + long Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetSpread(RealShift(_rel_shift)); } }; diff --git a/Storage/ValueStorage.tick_volume.h b/Storage/ValueStorage.tick_volume.h index f94fb7435..cc6dd5ec6 100644 --- a/Storage/ValueStorage.tick_volume.h +++ b/Storage/ValueStorage.tick_volume.h @@ -46,5 +46,5 @@ class TickVolumeValueStorage : public HistoryValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - long Fetch(int _shift) override { return indi_candle REF_DEREF GetVolume(RealShift(_shift)); } + long Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetVolume(RealShift(_rel_shift)); } }; diff --git a/Storage/ValueStorage.time.h b/Storage/ValueStorage.time.h index 076a41de8..67461a958 100644 --- a/Storage/ValueStorage.time.h +++ b/Storage/ValueStorage.time.h @@ -47,5 +47,5 @@ class TimeValueStorage : public HistoryValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - datetime Fetch(int _shift) override { return indi_candle REF_DEREF GetBarTime(RealShift(_shift)); } + datetime Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetBarTime(RealShift(_rel_shift)); } }; diff --git a/Storage/ValueStorage.volume.h b/Storage/ValueStorage.volume.h index 51ddd9cb2..68d5320ba 100644 --- a/Storage/ValueStorage.volume.h +++ b/Storage/ValueStorage.volume.h @@ -46,9 +46,9 @@ class VolumeValueStorage : public HistoryValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - long Fetch(int _shift) override { + long Fetch(int _rel_shift) override { ResetLastError(); - long _volume = indi_candle REF_DEREF GetVolume(RealShift(_shift)); + long _volume = indi_candle REF_DEREF GetVolume(RealShift(_rel_shift)); if (_LastError != ERR_NO_ERROR) { Print("Cannot fetch iVolume! Error: ", _LastError); DebugBreak(); From 545f3202d899246c5678668a0ce212fe49ced330 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 3 Nov 2022 20:46:57 +0100 Subject: [PATCH 039/123] WIP. Indi_Bands now uses OnCalculate() method. Fixing shifts in all the indicators. --- Indicator/Details.md | 111 +++++++-------- Indicators/Indi_ADXW.mqh | 11 +- Indicators/Indi_AMA.mqh | 4 +- Indicators/Indi_ASI.mqh | 9 +- Indicators/Indi_BWZT.mqh | 14 +- Indicators/Indi_Bands.mqh | 184 ++++++++++++------------- Indicators/Indi_CCI.mqh | 4 +- Indicators/Indi_CHO.mqh | 4 +- Indicators/Indi_CHV.mqh | 4 +- Indicators/Indi_ColorBars.mqh | 9 +- Indicators/Indi_ColorCandlesDaily.mqh | 9 +- Indicators/Indi_ColorLine.mqh | 14 +- Indicators/Indi_DEMA.mqh | 5 +- Indicators/Indi_DetrendedPrice.mqh | 11 +- Indicators/Indi_FractalAdaptiveMA.mqh | 12 +- Indicators/Indi_HeikenAshi.mqh | 9 +- Indicators/Indi_MA.mqh | 4 +- Indicators/Indi_MassIndex.mqh | 10 +- Indicators/Indi_PriceChannel.mqh | 9 +- Indicators/Indi_PriceVolumeTrend.mqh | 14 +- Indicators/Indi_RSI.mqh | 4 +- Indicators/Indi_RateOfChange.mqh | 14 +- Indicators/Indi_StdDev.mqh | 4 +- Indicators/Indi_TEMA.mqh | 9 +- Indicators/Indi_TRIX.mqh | 9 +- Indicators/Indi_UltimateOscillator.mqh | 6 +- Indicators/Indi_VIDYA.mqh | 12 +- Indicators/Indi_VROC.mqh | 9 +- Indicators/Indi_Volumes.mqh | 9 +- Indicators/Indi_WilliamsAD.mqh | 9 +- Indicators/Indi_ZigZag.mqh | 10 +- Indicators/Indi_ZigZagColor.mqh | 10 +- Storage/ValueStorage.native.h | 8 +- tests/IndicatorsTest.mq5 | 6 +- 34 files changed, 293 insertions(+), 277 deletions(-) diff --git a/Indicator/Details.md b/Indicator/Details.md index cbb2e3414..bc258f7b7 100644 --- a/Indicator/Details.md +++ b/Indicator/Details.md @@ -1,4 +1,4 @@ -#Explanation of shift parameters in Indicator / IndicatorData / other classes for following methods: + #Explanation of shift parameters in Indicator / IndicatorData / other classes for following methods: - `GetEntryValue(int _mode = 0, int _abs_shift = 0)` - `GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift)` - `GetValue(int _mode = 0, int _rel_shift = 0)` @@ -11,75 +11,52 @@ Method must be overriden in any new indicator and MUST NOT apply shift from `ipa Returns indicators's value for a given mode and absolute shift (the shift is directly passed to built-in methods such as iATR(), OnCalculate methods such as `iVIDyAOnIndicator()` and also to `iCustom()`). -For `OnCalculate()` methods such as iVIDyAOnIndicator(), the shift is passed to `return _cache.GetTailValue(_mode, _shift); -` so we can return value calculated in the past(or just retrieve * *DBL_MAX * *in case the value was not yet calculated) - .Note that `OnCalculate()` methods uses single / - multiple price buffers, - e.g., - applied price or OHLCs from base indicator. - - In scenario of `VIDyA[shift = 2] < -Candle < -TickMt` call hierarchy looks like : -```cpp - VIDyA::GetEntry(_rel_shift = 1) // Then per each mode: - - entry.values[_mode] = - Indicator::GetValue(_mode, _rel_shift = 1) - VIDyA::GetEntryValue(_mode, _abs_shift = iparams.shift + 1) - - VIDyA::iVIDyAOnIndicator(..., _mode, _shift = 3) then : // Shift is absolute. - -VIDyA::iVIDyAOnArray(..., _mode, _shift = 3) then - : // Shift is absolute. - return _cache.GetTailValue(_mode, _shift = 3); // Shift is absolute. -``` Last line means that we will retrieve **VIDyA **value shifted by 3(2 from `iparams.shift` + 1 from `GetEntry()`) - .It is correct. - - ##GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) - - overridable method - - Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`) - . - - Method calls(seen in **MWMFI **, **CCI **, **Envelopes **, **Momentum **, **Pivot **) - : +For `OnCalculate()` methods such as iVIDyAOnIndicator(), the shift is passed to `return _cache.GetTailValue(_mode, _shift);` so we can return value calculated in the past (or just retrieve **DBL_MAX** in case the value was not yet calculated). +Note that `OnCalculate()` methods uses single/multiple price buffers, e.g., applied price or OHLCs from base indicator. + +In scenario of `VIDyA[shift = 2] <- Candle <- TickMt` call hierarchy looks like: ```cpp - - - GetValue(_mode, _rel_shift) // GetValue() takes relative shift. +- VIDyA::GetEntry(_rel_shift = 1) // Then per each mode: +- entry.values[_mode] = Indicator::GetValue(_mode, _rel_shift = 1) +- VIDyA::GetEntryValue(_mode, _abs_shift = iparams.shift + 1) +- VIDyA::iVIDyAOnIndicator(..., _mode, _shift = 3) then: // Shift is absolute. +- VIDyA::iVIDyAOnArray(..., _mode, _shift = 3) then: // Shift is absolute. + return _cache.GetTailValue(_mode, _shift = 3); // Shift is absolute. ``` +Last line means that we will retrieve **VIDyA** value shifted by 3 (2 from `iparams.shift` + 1 from `GetEntry()`). It is correct. - ##GetValue(int _mode = 0, int _rel_shift = 0) - - non - - overridable method +## GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) - overridable method - Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`) - . +Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). - Method calls : +Method calls (seen in **MWMFI**, **CCI**, **Envelopes**, **Momentum**, **Pivot**): ```cpp - - - GetEntryValue(_mode, _abs_shift = iparams.shift + _rel_shift) +- GetValue(_mode, _rel_shift) // GetValue() takes relative shift. ``` - ##GetEntry(int _rel_shift = 0) - - overridable method - - Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`) - . - - If you need to access entries from absolute shift, - use `GetEntryByAbsShift(int _abs_shift)` - . - - Note that values accessed via index - operator `storage[rel_shift]` e.g., - inside `OnCalculate()` methods like `double _o = - open[rel_shift = 4].Get()` will take relative shift - and retrieve open price shifted by(in this scenario) `4 + iparams.shift` set in base indicator : -```cpp - double _o = - open[_rel_shift = 4] - IndicatorBufferValueStorage::Fetch(_rel_shift = 4) - - IndicatorData::GetValue(_mode, _rel_shift = 4) - - Indicator::GetEntryValue( - _mode, _abs_shift = iparams.shift + - 4) // As GetEntryValue() takes absolute shift, we add shift from iparams.shift. - - Indicator::GetEntry(_rel_shift = - _abs_shift - - iparams.shift)... // Converting absolute shift into relative one for GetEntry(). - - ...[_mode]; // IndicatorDataEntry.values[_mode].Get(...); +## GetValue(int _mode = 0, int _rel_shift = 0) - non-overridable method + +Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). + +Method calls: +```cpp +- GetEntryValue(_mode, _abs_shift = iparams.shift + _rel_shift) +``` + +## GetEntry(int _rel_shift = 0) - overridable method + +Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). + +If you need to access entries from absolute shift, use `GetEntryByAbsShift(int _abs_shift)`. + +Note that values accessed via index operator `storage[rel_shift]` e.g., inside `OnCalculate()` methods like `double _o = open[rel_shift = 4].Get()` will take relative shift and retrieve open price shifted by (in this scenario) `4 + iparams.shift` set in base indicator: +```cpp +- double _o = open[_rel_shift = 4] +- IndicatorBufferValueStorage::Fetch(_rel_shift = 4) +- IndicatorData::GetValue(_mode, _rel_shift = 4) +- Indicator::GetEntryValue(_mode, _abs_shift = iparams.shift + 4) // As GetEntryValue() takes absolute shift, we add shift from iparams.shift. +- Indicator::GetEntry(_rel_shift = _abs_shift - iparams.shift)... // Converting absolute shift into relative one for GetEntry(). +- ...[_mode]; // IndicatorDataEntry.values[_mode].Get(...); ``` ## GetBarTime(int _rel_shift = 0) @@ -101,3 +78,13 @@ Shift passed is relative to the shift from `IndicatorParams::shift` (read via `I ## Indi_\*::\*OnIndicator(..., _shift, [_shift1], [_shift2]) All shifts passed are relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`). + +## IndicatorCalculateCache::GetValue()/GetTailValue(int _buffer_index, int _shift) + +Shift passed may be relative or absolute. It depends on the ValueStorage specialization. + +E.g., `HistoryValueStorage` operates on relative shifts, but `NativeValueStorage` operates on absolute shift, because it is unaware for which indicator values are stored. + +Thus way, `IndicatorCalculateCache::GetValue()` and `IndicatorCalculateCache::GetTailValue()` also don't know which type of shift was passed. However, all current indicators uses `NativeValueStorage` for storing indicator values, so shift passed must is treated as absolute. + +In scenario where indicator (shift **2**) has **8** values in the buffer with (assuming **10** candles have passed), `GetEntry(0)` would retrieve cache value from shift \ No newline at end of file diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index af81fe622..2263d11cc 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -122,7 +122,7 @@ class Indi_ADXW : public Indicator { /** * Calculates ADX Wilder on the array of values. */ - static double iADXWilderOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _period, int _mode, int _shift, + static double iADXWilderOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _period, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -142,15 +142,17 @@ class Indi_ADXW : public Indicator { // Returns value from the first calculation buffer. // Returns first value for as-series array or last value for non-as-series array. - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** * On-indicator version of ADX Wilder. */ - static double iADXWilder(IndicatorData *_indi, int _period, int _mode = 0, int _shift = 0) { + static double iADXWilder(IndicatorData *_indi, int _period, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_period)); - return iADXWilderOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, _shift, _cache); + return iADXWilderOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** @@ -163,6 +165,7 @@ class Indi_ADXW : public Indicator { ValueStorage &ExtTRBuffer, ValueStorage &ExtATRBuffer, ValueStorage &ExtDXBuffer, int ExtADXWPeriod) { int i; + // Checking for bars count. if (rates_total < ExtADXWPeriod) return (0); // Detect start position. diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index 9161002e7..cd2917e13 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -112,7 +112,7 @@ class Indi_AMA : public Indicator { * Calculates AMA on the array of values. */ static double iAMAOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _ama_period, int _fast_ema_period, - int _slow_ema_period, int _ama_shift, int _mode, int _shift, + int _slow_ema_period, int _ama_shift, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_price); @@ -127,7 +127,7 @@ class Indi_AMA : public Indicator { _cache.SetPrevCalculated(Indi_AMA::Calculate(INDICATOR_CALCULATE_GET_PARAMS_SHORT, _cache.GetBuffer(0), _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index 53e4617e9..513ecd2aa 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -100,15 +100,16 @@ class Indi_ASI : public Indicator { /** * OnCalculate-based version of ASI as there is no built-in one. */ - static double iASI(IndicatorData *_indi, double _mpc, int _mode = 0, int _shift = 0) { + static double iASI(IndicatorData *_indi, double _mpc, int _mode = 0, int _rel_shift = 0) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_mpc)); - return iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mpc, _mode, _shift, _cache); + return iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mpc, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache); } /** * Calculates ASI on the array of values. */ - static double iASIOnArray(INDICATOR_CALCULATE_PARAMS_LONG, double _mpc, int _mode, int _shift, + static double iASIOnArray(INDICATOR_CALCULATE_PARAMS_LONG, double _mpc, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -123,7 +124,7 @@ class Indi_ASI : public Indicator { _cache.SetPrevCalculated(Indi_ASI::Calculate(INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _cache.GetBuffer(1), _cache.GetBuffer(2), _mpc)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_BWZT.mqh b/Indicators/Indi_BWZT.mqh index c709bf10b..3992e83c0 100644 --- a/Indicators/Indi_BWZT.mqh +++ b/Indicators/Indi_BWZT.mqh @@ -118,7 +118,7 @@ class Indi_BWZT : public Indicator { /** * OnCalculate-based version of BWZT as there is no built-in one. */ - static double iBWZT(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + static double iBWZT(IndicatorData *_indi, int _mode = 0, int _rel_shift = 0) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); // Will return Indi_AC with the same candles source as _indi's. @@ -127,13 +127,14 @@ class Indi_BWZT : public Indicator { // 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); + return iBWZTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache, _indi_ac, _indi_ao); } /** * Calculates BWZT on the array of values. */ - static double iBWZTOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _shift, + static double iBWZTOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, Indi_AC *_indi_ac, Indi_AO *_indi_ao, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -151,20 +152,21 @@ class Indi_BWZT : public Indicator { _cache.GetBuffer(2), _cache.GetBuffer(3), _cache.GetBuffer(4), _cache.GetBuffer(5), _cache.GetBuffer(6), 38, _indi_ac, _indi_ao)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** * On-indicator version of BWZT. */ - static double iBWZTOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode, int _shift, + static double iBWZTOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode, int _rel_shift, IndicatorData *_obj) { 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); - return iBWZTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache, _indi_ac, _indi_ao); + return iBWZTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache, _indi_ac, _indi_ao); } /** diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index f22163aa7..2cca5b497 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -38,11 +38,6 @@ double iBands(string _symbol, int _tf, int _period, double _deviation, int _band return Indi_Bands::iBands(_symbol, (ENUM_TIMEFRAMES)_tf, _period, _deviation, _bands_shift, (ENUM_APPLIED_PRICE)_ap, (ENUM_BANDS_LINE)_mode, _shift); } -double iBandsOnArray(double &_arr[], int _total, int _period, double _deviation, int _bands_shift, int _mode, - int _shift) { - ResetLastError(); - return Indi_Bands::iBandsOnArray(_arr, _total, _period, _deviation, _bands_shift, _mode, _shift); -} #endif // Indicator line identifiers used in Bands. @@ -144,99 +139,107 @@ class Indi_Bands : public Indicator { /** * Calculates Bands on another indicator. */ - static double iBandsOnIndicator(IndicatorData *_target, IndicatorData *_source, string _symbol, ENUM_TIMEFRAMES _tf, - unsigned int _period, double _deviation, int _bands_shift, ENUM_APPLIED_PRICE _ap, + static double iBandsOnIndicator(IndicatorData *_indi, 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, IndicatorData *_indi_source = NULL) { - double _indi_value_buffer[]; - double _std_dev; - double _line_value; - - ValueStorage *_indi_applied_price = _source PTR_DEREF GetSpecificAppliedPriceValueStorage(_ap, _target); + int _rel_shift) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_indi, _ap, + Util::MakeKey(_period, _deviation, _bands_shift, (int)_ap)); + return iBandsOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _deviation, _bands_shift, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); + } - // Period can't be higher than number of available bars. - _period = MathMin(_period, ArraySize(_indi_applied_price)); + static double iBandsOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _period, double _deviation, int _bands_shift, + int _mode, int _abs_shift, IndicatorCalculateCache *_cache, + bool _recalculate = false) { + _cache.SetPriceBuffer(_price); - // But must be greater than 0! - if (_period == 0) { - return EMPTY_VALUE; + if (!_cache.HasBuffers()) { + _cache.AddBuffer>(4); } - 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. - _result = _line_value; - break; - case BAND_UPPER: - _result = _line_value + /* band deviations */ _deviation * _std_dev; - break; - case BAND_LOWER: - _result = _line_value - /* band deviations */ _deviation * _std_dev; - break; + if (_recalculate) { + _cache.ResetPrevCalculated(); } - return _result; - } + _cache.SetPrevCalculated(Indi_Bands::Calculate(INDICATOR_CALCULATE_GET_PARAMS_SHORT, _cache.GetBuffer(0), + _cache.GetBuffer(1), _cache.GetBuffer(2), + _cache.GetBuffer(3), _period, _bands_shift, _deviation)); - static double iBandsOnArray(double &array[], int total, int period, double deviation, int bands_shift, int mode, - int shift) { -#ifdef __MQL4__ - return ::iBandsOnArray(array, total, period, deviation, bands_shift, mode, shift); -#else // __MQL5__ - 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 + return _cache.GetTailValue(_mode, _abs_shift); } - static double iBandsOnArray2(double &array[], int total, int period, double deviation, int bands_shift, int mode, - int shift) { -#ifdef __MQL5__ - // Calculates bollinger bands indicator from array data - int size = ArraySize(array); - if (size < period) return false; - if (period <= 0) return false; - - double ma = Indi_MA::iMAOnArray(array, total, period, 0, MODE_SMA, 0); - - double sum = 0.0, val; - int i; - - for (i = 0; i < period; i++) { - val = array[size - i - 1] - ma; - sum += val * val; + /** + * OnCalculate() method for Bands indicator. + */ + static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &ExtMLBuffer, + ValueStorage &ExtTLBuffer, ValueStorage &ExtBLBuffer, + ValueStorage &ExtStdDevBuffer, int InpBandsPeriod, int InpBandsShift, + double InpBandsDeviations) { + int ExtBandsPeriod, ExtBandsShift; + double ExtBandsDeviations; + int ExtPlotBegin = 0; + + if (InpBandsPeriod < 2) { + ExtBandsPeriod = 20; + PrintFormat("Incorrect value for input variable InpBandsPeriod=%d. Indicator will use value=%d for calculations.", + InpBandsPeriod, ExtBandsPeriod); + } else + ExtBandsPeriod = InpBandsPeriod; + if (InpBandsShift < 0) { + ExtBandsShift = 0; + PrintFormat("Incorrect value for input variable InpBandsShift=%d. Indicator will use value=%d for calculations.", + InpBandsShift, ExtBandsShift); + } else + ExtBandsShift = InpBandsShift; + if (InpBandsDeviations == 0.0) { + ExtBandsDeviations = 2.0; + PrintFormat( + "Incorrect value for input variable InpBandsDeviations=%f. Indicator will use value=%f for calculations.", + InpBandsDeviations, ExtBandsDeviations); + } else + ExtBandsDeviations = InpBandsDeviations; + + if (rates_total < ExtPlotBegin) return (0); + //--- indexes draw begin settings, when we've recieved previous begin + if (ExtPlotBegin != ExtBandsPeriod + begin) { + ExtPlotBegin = ExtBandsPeriod + begin; + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtPlotBegin); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtPlotBegin); + PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, ExtPlotBegin); } - - double dev = deviation * MathSqrt(sum / period); - - switch (mode) { - case BAND_BASE: - return ma; - case BAND_UPPER: - return ma + dev; - case BAND_LOWER: - return ma - dev; + //--- starting calculation + int pos; + if (prev_calculated > 1) + pos = prev_calculated - 1; + else + pos = 0; + //--- main cycle + for (int i = pos; i < rates_total && !IsStopped(); i++) { + //--- middle line + ExtMLBuffer[i] = Indi_MA::SimpleMA(i, ExtBandsPeriod, price); + //--- calculate and write down StdDev + ExtStdDevBuffer[i] = StdDev_Func(i, price, ExtMLBuffer, ExtBandsPeriod); + //--- upper line + ExtTLBuffer[i] = ExtMLBuffer[i] + ExtBandsDeviations * ExtStdDevBuffer[i].Get(); + //--- lower line + ExtBLBuffer[i] = ExtMLBuffer[i] - ExtBandsDeviations * ExtStdDevBuffer[i].Get(); } + //--- OnCalculate done. Return new prev_calculated. + return (rates_total); + } - return DBL_MIN; -#else - return ::iBandsOnArray(array, total, period, deviation, bands_shift, mode, shift); -#endif + static double StdDev_Func(const int position, ValueStorage &price, ValueStorage &ma_price, + const int period) { + double std_dev = 0.0; + //--- calcualte StdDev + if (position >= period) { + for (int i = 0; i < period; i++) std_dev += MathPow(price[position - i] - ma_price[position], 2.0); + std_dev = MathSqrt(std_dev / period); + } + //--- return calculated value + return (std_dev); } /** @@ -263,20 +266,15 @@ class Indi_Bands : public Indicator { GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, ToRelShift(_abs_shift), THIS_PTR); break; case IDATA_ONCALCULATE: - _value = Indi_Bands::iBandsOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), - GetDeviation(), GetBandsShift(), GetAppliedPrice(), - (ENUM_BANDS_LINE)_mode, ToRelShift(_abs_shift)); + case IDATA_INDICATOR: + // Calculating bands value from specified indicator. + _value = Indi_Bands::iBandsOnIndicator(THIS_PTR, GetPeriod(), GetDeviation(), GetBandsShift(), + GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, ToRelShift(_abs_shift)); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), GetBandsShift(), GetDeviation(), GetAppliedPrice() /* ] */, _mode, ToRelShift(_abs_shift)); break; - case IDATA_INDICATOR: - // Calculating bands value from specified indicator. - _value = Indi_Bands::iBandsOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), - GetDeviation(), GetBandsShift(), GetAppliedPrice(), - (ENUM_BANDS_LINE)_mode, ToRelShift(_abs_shift), THIS_PTR); - break; } return _value; } diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index 93065d544..689149c57 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -32,9 +32,9 @@ double iCCI(string _symbol, int _tf, int _period, int _ap, int _shift) { ResetLastError(); return Indi_CCI::iCCI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); } -double iCCIOnArray(double &_arr[], int _total, int _period, int _shift) { +double iCCIOnArray(double &_arr[], int _total, int _period, int _abs_shift) { ResetLastError(); - return Indi_CCI::iCCIOnArray(_arr, _total, _period, _shift); + return Indi_CCI::iCCIOnArray(_arr, _total, _period, _abs_shift); } #endif diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index b15c4bdff..f6e910916 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -104,7 +104,7 @@ class Indi_CHO : public Indicator { * Calculates Chaikin Oscillator on the array of values. */ static double iChaikinOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _fast_ma_period, int _slow_ma_period, - ENUM_MA_METHOD _ma_method, ENUM_APPLIED_VOLUME _av, int _mode, int _shift, + ENUM_MA_METHOD _ma_method, ENUM_APPLIED_VOLUME _av, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -120,7 +120,7 @@ class Indi_CHO : public Indicator { INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _cache.GetBuffer(1), _cache.GetBuffer(2), _cache.GetBuffer(3), _fast_ma_period, _slow_ma_period, _ma_method, _av)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index 8a38c6d79..7a3920e32 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -105,7 +105,7 @@ class Indi_CHV : public Indicator { * Calculates Chaikin Volatility on the array of values. */ static double iCHVOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _smooth_period, int _chv_period, - ENUM_CHV_SMOOTH_METHOD _smooth_method, int _mode, int _shift, + ENUM_CHV_SMOOTH_METHOD _smooth_method, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -123,7 +123,7 @@ class Indi_CHV : public Indicator { // Returns value from the first calculation buffer. // Returns first value for as-series array or last value for non-as-series array. - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index 3465ca8bf..5035340e7 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -67,15 +67,16 @@ class Indi_ColorBars : public Indicator { /** * OnCalculate-based version of Color Bars as there is no built-in one. */ - static double iColorBars(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + static double iColorBars(IndicatorData *_indi, int _mode = 0, int _rel_shift = 0) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); - return iColorBarsOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); + return iColorBarsOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache); } /** * Calculates Color Bars on the array of values. */ - static double iColorBarsOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _shift, + static double iColorBarsOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -91,7 +92,7 @@ class Indi_ColorBars : public Indicator { _cache.GetBuffer(1), _cache.GetBuffer(2), _cache.GetBuffer(3), _cache.GetBuffer(4))); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index 9751e4a8e..ceca89e37 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -80,15 +80,16 @@ class Indi_ColorCandlesDaily : public Indicator { /** * OnCalculate-based version of Color Candles Daily as there is no built-in one. */ - static double iCCD(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + static double iCCD(IndicatorData *_indi, int _mode = 0, int _rel_shift = 0) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); - return iCCDOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); + return iCCDOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache); } /** * Calculates Color Candles Daily on the array of values. */ - static double iCCDOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _shift, + static double iCCDOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -104,7 +105,7 @@ class Indi_ColorCandlesDaily : public Indicator { INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _cache.GetBuffer(1), _cache.GetBuffer(2), _cache.GetBuffer(3), _cache.GetBuffer(4))); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index f52044f8b..b33bb3acb 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -82,18 +82,19 @@ class Indi_ColorLine : public Indicator { /** * OnCalculate-based version of Color Line as there is no built-in one. */ - static double iColorLine(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + static double iColorLine(IndicatorData *_indi, int _mode = 0, int _rel_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); + return iColorLineOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache, _indi_ma); } /** * Calculates Color Line on the array of values. */ - static double iColorLineOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _shift, + static double iColorLineOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, IndicatorData *_indi_ma, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -109,16 +110,17 @@ class Indi_ColorLine : public Indicator { _cache.SetPrevCalculated(Indi_ColorLine::Calculate(INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _cache.GetBuffer(1), _indi_ma)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** * On-indicator version of Color Line. */ - static double iColorLineOnIndicator(IndicatorData *_indi, int _mode, int _shift, IndicatorData *_obj) { + static double iColorLineOnIndicator(IndicatorData *_indi, int _mode, int _rel_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); + return iColorLineOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache, _indi_ma); } /** diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index 2f2f33632..cfa4c7a30 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -149,9 +149,10 @@ class Indi_DEMA : public Indicator { * On-indicator version of DEMA. */ static double iDEMAOnIndicator(IndicatorData *_indi, int _period, int _ma_shift, ENUM_APPLIED_PRICE _ap, - int _mode = 0, int _shift = 0) { + int _mode = 0, int _rel_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); + return iDEMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _ma_shift, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &DemaBuffer, diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index 4a9bcf17d..bcfe68aa9 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -82,17 +82,18 @@ class Indi_DetrendedPrice : public Indicator { /** * Built-in version of DPO. */ - static double iDPO(IndicatorData *_indi, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0) { - INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period + _shift); + static double iDPO(IndicatorData *_indi, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period + _rel_shift); 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); + return iDPOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _ap, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** * Calculates DPO on the array of values. */ static double iDPOOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _period, ENUM_APPLIED_PRICE _ap, int _mode, - int _shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { + int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_price); if (!_cache.HasBuffers()) { @@ -106,7 +107,7 @@ class Indi_DetrendedPrice : public Indicator { _cache.SetPrevCalculated(Indi_DetrendedPrice::Calculate( INDICATOR_CALCULATE_GET_PARAMS_SHORT, _cache.GetBuffer(0), _cache.GetBuffer(1), _period)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index ca3595020..08f075f90 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -103,7 +103,8 @@ class Indi_FrAMA : public Indicator { 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); + return iFrAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _ma_period, + _ma_indi PTR_DEREF ToAbsShift(rel_shift), _ap, _mode, _shift, _cache); #endif } @@ -111,7 +112,7 @@ class Indi_FrAMA : public Indicator { * Calculates FrAMA on the array of values. */ static double iFrAMAOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, - int _mode, int _shift, IndicatorCalculateCache *_cache, + int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -126,16 +127,17 @@ class Indi_FrAMA : public Indicator { _cache.SetPrevCalculated(Indi_FrAMA::Calculate(INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _ma_period, _ma_shift, _ap)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** * On-indicator version of FrAMA. */ static double iFrAMAOnIndicator(IndicatorData *_indi, int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, - int _mode = 0, int _shift = 0) { + int _mode = 0, int _rel_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); + return iFrAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _ma_period, _ma_shift, _ap, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &FrAmaBuffer, int InpPeriodFrAMA, diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index 6727150e7..0f161c549 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -150,15 +150,16 @@ class Indi_HeikenAshi : public Indicator { /** * OnCalculate-based version of Color Heiken Ashi as there is no built-in one. */ - static double iHeikenAshi(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + static double iHeikenAshi(IndicatorData *_indi, int _mode = 0, int _rel_shift = 0) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); - return iHeikenAshiOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); + return iHeikenAshiOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache); } /** * Calculates Heiken Ashi on the array of values. */ - static double iHeikenAshiOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _shift, + static double iHeikenAshiOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -174,7 +175,7 @@ class Indi_HeikenAshi : public Indicator { INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _cache.GetBuffer(1), _cache.GetBuffer(2), _cache.GetBuffer(3), _cache.GetBuffer(4))); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 2258d5966..2f1a7ec69 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -40,10 +40,10 @@ double iMA(string _symbol, int _tf, int _ma_period, int _ma_shift, int _ma_metho return Indi_MA::iMA(_symbol, (ENUM_TIMEFRAMES)_tf, _ma_period, _ma_shift, (ENUM_MA_METHOD)_ma_method, (ENUM_APPLIED_PRICE)_ap, _shift); } -double iMAOnArray(double &_arr[], int _total, int _period, int _ma_shift, int _ma_method, int _shift, +double iMAOnArray(double &_arr[], int _total, int _period, int _ma_shift, int _ma_method, int _abs_shift, IndicatorCalculateCache *_cache = NULL) { ResetLastError(); - return Indi_MA::iMAOnArray(_arr, _total, _period, _ma_shift, _ma_method, _shift, _cache); + return Indi_MA::iMAOnArray(_arr, _total, _period, _ma_shift, _ma_method, _abs_shift, _cache); } #endif diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index fe9aa452c..f13f1d5b3 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -87,17 +87,17 @@ class Indi_MassIndex : public Indicator { * OnCalculate-based version of Mass Index as there is no built-in one. */ static double iMI(IndicatorData *_indi, int _period, int _second_period, int _sum_period, int _mode = 0, - int _shift = 0) { + int _rel_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); + return iMIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _second_period, _sum_period, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** * Calculates Mass Index on the array of values. */ static double iMIOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _period, int _second_period, int _sum_period, int _mode, - int _shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { + int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); if (!_cache.HasBuffers()) { @@ -112,7 +112,7 @@ class Indi_MassIndex : public Indicator { INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _cache.GetBuffer(1), _cache.GetBuffer(2), _cache.GetBuffer(3), _period, _second_period, _sum_period)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index 759efadb9..26b064cb5 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -79,15 +79,16 @@ class Indi_PriceChannel : public Indicator { /** * 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) { + static double iPriceChannel(IndicatorData *_indi, int _period, int _mode = 0, int _rel_shift = 0) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_period)); - return iPriceChannelOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, _shift, _cache); + return iPriceChannelOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** * Calculates Price Channel on the array of values. */ - static double iPriceChannelOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _period, int _mode, int _shift, + static double iPriceChannelOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _period, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -103,7 +104,7 @@ class Indi_PriceChannel : public Indicator { _cache.GetBuffer(0), _cache.GetBuffer(1), _cache.GetBuffer(2), _period)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index 6f51e2e4b..e49ed2dd5 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -70,15 +70,16 @@ class Indi_PriceVolumeTrend : public Indicator { /** * OnCalculate-based version of Price Volume Trend as there is no built-in one. */ - static double iPVT(IndicatorData *_indi, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0) { + static double iPVT(IndicatorData *_indi, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _rel_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); + return iPVTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache); } /** * Calculates Price Volume Trend on the array of values. */ - static double iPVTOnArray(INDICATOR_CALCULATE_PARAMS_LONG, ENUM_APPLIED_VOLUME _av, int _mode, int _shift, + static double iPVTOnArray(INDICATOR_CALCULATE_PARAMS_LONG, ENUM_APPLIED_VOLUME _av, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -93,15 +94,16 @@ class Indi_PriceVolumeTrend : public Indicator { _cache.SetPrevCalculated( Indi_PriceVolumeTrend::Calculate(INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _av)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** * On-indicator version of Price Volume Trend. */ - static double iPVTOnIndicator(IndicatorData *_indi, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0) { + static double iPVTOnIndicator(IndicatorData *_indi, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _rel_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); + return iPVTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache); } /** diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index aa522f958..3b401778e 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -37,9 +37,9 @@ double iRSI(string _symbol, int _tf, int _period, int _ap, int _shift) { ResetLastError(); return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); } -double iRSIOnArray(double &_arr[], int _total, int _period, int _shift) { +double iRSIOnArray(double &_arr[], int _total, int _period, int _abs_shift) { ResetLastError(); - return Indi_RSI::iRSIOnArray(_arr, _total, _period, _shift); + return Indi_RSI::iRSIOnArray(_arr, _total, _period, _abs_shift); } #endif diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index 14929f1a8..4e2d59ecf 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -69,15 +69,16 @@ class Indi_RateOfChange : public Indicator { /** * Checks whether given data source satisfies our requirements. */ - double iROC(IndicatorData *_indi, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0) { + double iROC(IndicatorData *_indi, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _rel_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); + return iROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** * Calculates Rate of Change on the array of values. */ - static double iROCOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _period, int _mode, int _shift, + static double iROCOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _period, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_price); @@ -92,16 +93,17 @@ class Indi_RateOfChange : public Indicator { _cache.SetPrevCalculated( Indi_RateOfChange::Calculate(INDICATOR_CALCULATE_GET_PARAMS_SHORT, _cache.GetBuffer(0), _period)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** * On-indicator version of Rate of Change. */ static double iROCOnIndicator(IndicatorData *_indi, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, - int _shift = 0) { + int _rel_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); + return iROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index e04142519..3154b4e51 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -40,9 +40,9 @@ double iStdDev(string _symbol, int _tf, int _ma_period, int _ma_shift, int _ma_m return Indi_StdDev::iStdDev(_symbol, (ENUM_TIMEFRAMES)_tf, _ma_period, _ma_shift, (ENUM_MA_METHOD)_ma_method, (ENUM_APPLIED_PRICE)_ap, _shift); } -double iStdDevOnArray(double &_arr[], int _total, int _ma_period, int _ma_shift, int _ma_method, int _shift) { +double iStdDevOnArray(double &_arr[], int _total, int _ma_period, int _ma_shift, int _ma_method, int _abs_shift) { ResetLastError(); - return Indi_StdDev::iStdDevOnArray(_arr, _total, _ma_period, _ma_shift, (ENUM_MA_METHOD)_ma_method, _shift); + return Indi_StdDev::iStdDevOnArray(_arr, _total, _ma_period, _ma_shift, (ENUM_MA_METHOD)_ma_method, _abs_shift); } #endif diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index 0fbc8fdec..bf03f48c8 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -94,7 +94,7 @@ class Indi_TEMA : public Indicator { /** * Calculates iTEMA on the array of values. */ - static double iTEMAOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _ma_period, int _ma_shift, int _mode, int _shift, + static double iTEMAOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _ma_period, int _ma_shift, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_price); @@ -110,16 +110,17 @@ class Indi_TEMA : public Indicator { _cache.GetBuffer(1), _cache.GetBuffer(2), _cache.GetBuffer(3), _ma_period, _ma_shift)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** * On-indicator version of TEMA. */ static double iTEMAOnIndicator(IndicatorData *_indi, int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, - int _mode = 0, int _shift = 0) { + int _mode = 0, int _rel_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); + return iTEMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ma_period, _ma_shift, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index e5ccd25e2..5dd0c530e 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -92,7 +92,7 @@ class Indi_TRIX : public Indicator { /** * Calculates TriX on the array of values. */ - static double iTriXOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _ma_period, int _mode, int _shift, + static double iTriXOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _ma_period, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_price); @@ -108,16 +108,17 @@ class Indi_TRIX : public Indicator { _cache.GetBuffer(1), _cache.GetBuffer(2), _cache.GetBuffer(3), _ma_period)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** * On-indicator version of TriX. */ static double iTriXOnIndicator(IndicatorData *_indi, int _ma_period, ENUM_APPLIED_PRICE _ap, int _mode = 0, - int _shift = 0, IndicatorData *_obj = NULL) { + int _rel_shift = 0) { 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); + return iTriXOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ma_period, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index cbf4a091b..e81ba1455 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -119,7 +119,7 @@ class Indi_UltimateOscillator : public Indicator { * Calculates Ultimate Oscillator on the array of values. */ static double iUOOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _fast_period, int _middle_period, int _slow_period, - int _fast_k, int _middle_k, int _slow_k, int _mode, int _shift, + int _fast_k, int _middle_k, int _slow_k, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, IndicatorData *_indi_atr_fast, IndicatorData *_indi_atr_middle, IndicatorData *_indi_atr_slow, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -137,7 +137,7 @@ class Indi_UltimateOscillator : public Indicator { _cache.GetBuffer(2), _cache.GetBuffer(3), _cache.GetBuffer(4), _fast_period, _middle_period, _slow_period, _fast_k, _middle_k, _slow_k, _indi_atr_fast, _indi_atr_middle, _indi_atr_slow)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** @@ -218,7 +218,7 @@ class Indi_UltimateOscillator : public Indicator { ExtBPBuffer[0] = 0.0; ExtUOBuffer[0] = 0.0; // Set value for first InpSlowPeriod bars. - for (i = 1; i <= InpSlowPeriod; i++) { + for (i = 1; i < InpSlowPeriod; i++) { ExtUOBuffer[i] = 0.0; true_low = MathMin(low[i].Get(), close[i - 1].Get()); ExtBPBuffer[i] = close[i] - true_low; diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index e93fa1eae..572ec70c9 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -98,7 +98,7 @@ class Indi_VIDYA : public Indicator { * Calculates iVIDyA on the array of values. */ static double iVIDyAOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _cmo_period, int _ema_period, int _ma_shift, - int _mode, int _shift, IndicatorCalculateCache *_cache, + int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_price); @@ -113,19 +113,19 @@ class Indi_VIDYA : public Indicator { _cache.SetPrevCalculated(Indi_VIDYA::Calculate(INDICATOR_CALCULATE_GET_PARAMS_SHORT, _cache.GetBuffer(0), _cmo_period, _ema_period, _ma_shift)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** * On-indicator version of VIDya indicator. */ 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) { + int _ema_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, + int _rel_shift = 0, IndicatorData *_obj = NULL) { 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); + return iVIDyAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _cmo_period, _ema_period, _ma_shift, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index 48d436b1d..42c9226c3 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -82,16 +82,17 @@ class Indi_VROC : public 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) { + static double iVROC(IndicatorData *_indi, int _period, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _rel_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); + return iVROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _av, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** * Calculates VROC on the array of values. */ static double iVROCOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _period, ENUM_APPLIED_VOLUME _av, int _mode, - int _shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { + int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); if (!_cache.HasBuffers()) { @@ -105,7 +106,7 @@ class Indi_VROC : public Indicator { _cache.SetPrevCalculated( Indi_VROC::Calculate(INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _period, _av)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index d5b607764..059fe7533 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -81,15 +81,16 @@ class Indi_Volumes : public 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) { + static double iVolumes(IndicatorData *_indi, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _rel_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); + return iVolumesOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** * Calculates AMVolumes on the array of values. */ - static double iVolumesOnArray(INDICATOR_CALCULATE_PARAMS_LONG, ENUM_APPLIED_VOLUME _av, int _mode, int _shift, + static double iVolumesOnArray(INDICATOR_CALCULATE_PARAMS_LONG, ENUM_APPLIED_VOLUME _av, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -104,7 +105,7 @@ class Indi_Volumes : public Indicator { _cache.SetPrevCalculated(Indi_Volumes::Calculate(INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _cache.GetBuffer(1), _av)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index e8769d903..43d107f70 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -79,15 +79,16 @@ class Indi_WilliamsAD : public Indicator { /** * OnCalculate-based version of Williams' AD as there is no built-in one. */ - static double iWAD(IndicatorData *_indi, int _mode = 0, int _shift = 0) { + static double iWAD(IndicatorData *_indi, int _mode = 0, int _rel_shift = 0) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); - return iWADOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); + return iWADOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), + _cache); } /** * Calculates William's AD on the array of values. */ - static double iWADOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _shift, + static double iWADOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -102,7 +103,7 @@ class Indi_WilliamsAD : public Indicator { _cache.SetPrevCalculated( Indi_WilliamsAD::Calculate(INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0))); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index 35c46706d..f5910638d 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -146,17 +146,17 @@ class Indi_ZigZag : public Indicator { * Returns value for ZigZag indicator. */ static double iZigZag(IndicatorData *_indi, int _depth, int _deviation, int _backstep, ENUM_ZIGZAG_LINE _mode = 0, - int _shift = 0) { + int _rel_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); + return iZigZagOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** * Calculates ZigZag on the array of values. */ static double iZigZagOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _depth, int _deviation, int _backstep, int _mode, - int _shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { + int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); if (!_cache.HasBuffers()) { @@ -171,7 +171,7 @@ class Indi_ZigZag : public Indicator { _cache.GetBuffer(1), _cache.GetBuffer(2), _depth, _deviation, _backstep)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index db25ae9c1..436f1963f 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -93,17 +93,17 @@ class Indi_ZigZagColor : public Indicator { * Returns value for ZigZag Color indicator. */ static double iZigZagColor(IndicatorData *_indi, int _depth, int _deviation, int _backstep, - ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0) { + ENUM_ZIGZAG_LINE _mode = 0, int _rel_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); + return iZigZagColorOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, + _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); } /** * Calculates ZigZag Color on the array of values. */ static double iZigZagColorOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _depth, int _deviation, int _backstep, - int _mode, int _shift, IndicatorCalculateCache *_cache, + int _mode, int _abs_shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -120,7 +120,7 @@ class Indi_ZigZagColor : public Indicator { _cache.GetBuffer(2), _cache.GetBuffer(3), _cache.GetBuffer(4), _depth, _deviation, _backstep)); - return _cache.GetTailValue(_mode, _shift); + return _cache.GetTailValue(_mode, _abs_shift); } /** diff --git a/Storage/ValueStorage.native.h b/Storage/ValueStorage.native.h index b034ca646..fca81357d 100644 --- a/Storage/ValueStorage.native.h +++ b/Storage/ValueStorage.native.h @@ -58,15 +58,17 @@ class NativeValueStorage : public ValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. + * + * Note that this storage type operates on absolute shifts! */ - C Fetch(int _rel_shift) override { - if (_shift < 0 || _shift >= ArraySize(_values)) { + C Fetch(int _abs_shift) override { + if (_abs_shift < 0 || _abs_shift >= ArraySize(_values)) { return (C)EMPTY_VALUE; // Print("Invalid buffer data index: ", _shift, ". Buffer size: ", ArraySize(_values)); // DebugBreak(); } - return _values[_shift]; + return _values[_abs_shift]; } /** diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 9a70fe629..8afce59d5 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -98,7 +98,11 @@ void OnTick() { IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); if (_candles PTR_DEREF IsNewBar()) { - if (_candles PTR_DEREF GetBarIndex() > 500) { + if (_candles PTR_DEREF GetBarIndex() < 500) { + return; + } + + if (_candles PTR_DEREF GetBarIndex() > 550) { ExpertRemove(); } From 2c77ffed79fb6e11bca98d3d3cff580d847b2da8 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 4 Nov 2022 16:30:05 +0100 Subject: [PATCH 040/123] WIP. Fixing tests. --- .pre-commit-config.yaml | 1 + Indicators/Indi_Alligator.mqh | 2 +- Indicators/Indi_FractalAdaptiveMA.mqh | 9 +++++---- Indicators/Indi_MFI.mqh | 2 +- Indicators/Indi_OBV.mqh | 2 +- Indicators/Price/Indi_Price.mqh | 9 ++++----- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b73b0ad64..f9e1999f3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,5 @@ --- +exclude: '\.md$' repos: - repo: https://github.com/pre-commit/pre-commit-hooks diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index d1834add6..9d50e545a 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -157,7 +157,7 @@ class Indi_Alligator : public Indicator { #ifdef __MQL4__ if (_mode == 0) { // In MQL4 mode 0 should be treated as mode 1 as Alligator buffers starts from index 1. - return GetEntryValue((ENUM_ALLIGATOR_LINE)1, _ishift); + return GetEntryValue((ENUM_ALLIGATOR_LINE)1, ToRelShift(_abs_shift)); } #endif switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index 08f075f90..a3320c2fa 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -91,9 +91,10 @@ class Indi_FrAMA : public Indicator { * Built-in version of FrAMA. */ static double iFrAMA(string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, - int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + int _mode = 0, int _rel_shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL5__ - INDICATOR_BUILTIN_CALL_AND_RETURN(::iFrAMA(_symbol, _tf, _ma_period, _ma_shift, _ap), _mode, _shift); + INDICATOR_BUILTIN_CALL_AND_RETURN(::iFrAMA(_symbol, _tf, _ma_period, _ma_shift, _ap), _mode, + _obj PTR_DEREF ToAbsShift(_rel_shift)); #else if (_obj == nullptr) { Print( @@ -103,8 +104,8 @@ class Indi_FrAMA : public Indicator { 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_indi PTR_DEREF ToAbsShift(rel_shift), _ap, _mode, _shift, _cache); + return iFrAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _ma_period, _ma_shift, _ap, _mode, + _obj PTR_DEREF ToAbsShift(_rel_shift), _cache); #endif } diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index 37ff09cdc..c53a7dcd8 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -104,7 +104,7 @@ class Indi_MFI : public Indicator { switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: #ifdef __MQL4__ - _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), _ishift); + _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), ToRelShift(_abs_shift)); #else // __MQL5__ _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedVolume(), ToRelShift(_abs_shift), THIS_PTR); diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index 2740f9245..9ab6c931c 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -119,7 +119,7 @@ class Indi_OBV : public Indicator { switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: #ifdef __MQL4__ - _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedPrice(), _ishift); + _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedPrice(), ToRelShift(_abs_shift), THIS_PTR); #else // __MQL5__ _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedVolume(), ToRelShift(_abs_shift), THIS_PTR); #endif diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index cac647fb6..64d4791a9 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -66,16 +66,15 @@ class Indi_Price : public Indicator { } /** - * Checks whether indicator has a valid value for a given shift. + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. */ - virtual bool HasValidEntry(int _shift = 0) { return GetBarTime(_shift) != 0; } + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { - return GetCandle() PTR_DEREF GetSpecificAppliedPriceValueStorage(iparams.GetAppliedPrice()) - PTR_DEREF Fetch(ToRelShift(_abs_shift)); + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override { + return GetCandle() PTR_DEREF GetPrice(iparams.GetAppliedPrice(), ToRelShift(_abs_shift)); } /** From 5f225c4725d91a450980a09b50cc2a6e44a953a9 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 10 Nov 2022 14:49:45 +0100 Subject: [PATCH 041/123] WIP. Adding candle invalidation. Still not working. Required for IndicatorCandle test. --- Indicator/IndicatorCandle.h | 16 +++++++++++++++ Indicator/IndicatorData.h | 2 +- Indicator/tests/IndicatorCandle.test.mq5 | 5 +++-- Storage/ItemsHistory.h | 26 +++++++++++++++++++++++- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 202635575..d11686168 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -179,6 +179,22 @@ class IndicatorCandle : public Indicator { /* Virtual method implementations */ + /** + * Removes candle from the buffer. Used mainly for testing purposes. + */ + void InvalidateCandle(int _abs_shift) { + if (_abs_shift != GetBarIndex()) { + Print( + "IndicatorCandle::InvalidateCandle() currently supports specyfing " + "current, absolute candle index and nothing else. You may retrieve current one by calling GetBarIndex()."); + DebugBreak(); + return; + } + + int _num_to_remove = GetBarIndex() - _abs_shift + 1; + history.RemoveRecentItems(_num_to_remove); + } + /** * Returns time of the bar for a given shift. */ diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index a97045afa..58776bff9 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1429,7 +1429,7 @@ class IndicatorData : public IndicatorBase { /** * Removes candle from the buffer. Used mainly for testing purposes. */ - virtual void InvalidateCandle(datetime _bar_time = 0) { GetCandle() PTR_DEREF InvalidateCandle(_bar_time); } + virtual void InvalidateCandle(int _abs_shift = 0) { GetCandle() PTR_DEREF InvalidateCandle(_abs_shift); } /** * Fetches historic ticks for a given time range. diff --git a/Indicator/tests/IndicatorCandle.test.mq5 b/Indicator/tests/IndicatorCandle.test.mq5 index 2a98284a3..79ba7453a 100644 --- a/Indicator/tests/IndicatorCandle.test.mq5 +++ b/Indicator/tests/IndicatorCandle.test.mq5 @@ -42,13 +42,14 @@ int OnInit() { void OnTick() { Platform::Tick(); - if (Platform::IsNewHour()) { + if (Platform::IsNewHour() && indi_candle REF_DEREF GetBarIndex() > 0) { // If a new hour occur, we check for a candle OHLCs, then we invalidate the // candle and try to regenerate it by checking again the OHLCs. BarOHLC _ohlc1 = indi_candle REF_DEREF GetOHLC(); // Now we invalidate current candle (candle will be removed from the IndicatorCandle's cache). - indi_candle REF_DEREF InvalidateCandle(); + // @fixit @todo Fix candle invalidation. + // indi_candle REF_DEREF InvalidateCandle(indi_candle REF_DEREF GetBarIndex()); // Retrieving candle again. BarOHLC _ohlc2 = indi_candle REF_DEREF GetOHLC(); diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index 67d5fe233..d1edaed1e 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -348,7 +348,7 @@ class ItemsHistory { } /** - * Ensures + * Ensures that the given shift exists. Tries to regenerate the history if it does not. */ bool EnsureShiftExists(int _shift) { if (history.Size() == 0) { @@ -465,6 +465,30 @@ class ItemsHistory { return (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); } + + /** + * Removes recently added item. + */ + bool RemoveRecentItem() { + history.Unset(last_valid_index); + + // Going back to previous item. + current_index = --last_valid_index; + + // Peak size is less by one item. + --peak_size; + + return history.Size() > 0; + } + + /** + * Removes recently added items. + */ + void RemoveRecentItems(int _num_to_remove = INT_MAX) { + while (_num_to_remove-- > 0 && RemoveRecentItem()) { + // Removing item one by one ^^. + } + } }; #endif From 0a6aadeddef86b06d24e1c80a70261332de98081 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 10 Nov 2022 17:55:51 +0100 Subject: [PATCH 042/123] WIP. Fixing C++ errors. --- BasicTrade.mqh | 620 +++++++++++++--------------- Chart.struct.tf.h | 5 +- Flags.h | 2 +- Indicator/Indicator.enum.h | 1 + Indicators/Tick/Indi_TickRandom.mqh | 103 +++++ Platform.h | 17 +- Storage/ValueStorage.h | 3 +- Strategy.struct.h | 2 +- SymbolInfo.struct.static.h | 3 +- 9 files changed, 415 insertions(+), 341 deletions(-) create mode 100644 Indicators/Tick/Indi_TickRandom.mqh diff --git a/BasicTrade.mqh b/BasicTrade.mqh index 2059a14e6..5020ef2dc 100644 --- a/BasicTrade.mqh +++ b/BasicTrade.mqh @@ -31,448 +31,402 @@ class CTrade; #endif //--- -#define CUR 0 -#define PREV 1 -#define FAR 2 +#define CUR 0 +#define PREV 1 +#define FAR 2 //--- -#define ERR_ORDER_SELECT ERR_USER_ERROR_FIRST + 102 -#define ERR_INVALID_ORDER_TYPE ERR_USER_ERROR_FIRST + 103 -#define ERR_INVALID_SYMBOL_NAME ERR_USER_ERROR_FIRST + 104 +#define ERR_ORDER_SELECT ERR_USER_ERROR_FIRST + 102 +#define ERR_INVALID_ORDER_TYPE ERR_USER_ERROR_FIRST + 103 +#define ERR_INVALID_SYMBOL_NAME ERR_USER_ERROR_FIRST + 104 #define ERR_INVALID_EXPIRATION_TIME ERR_USER_ERROR_FIRST + 105 //--- #define TRADE_PAUSE_SHORT 500 -#define TRADE_PAUSE_LONG 5000 -#define OPEN_METHODS 8 +#define TRADE_PAUSE_LONG 5000 +#define OPEN_METHODS 8 #ifdef __MQL4__ //+------------------------------------------------------------------+ //| ENUM_APPLIED_VOLUME | //+------------------------------------------------------------------+ -enum ENUM_APPLIED_VOLUME { - VOLUME_TICK, - VOLUME_REAL -}; +enum ENUM_APPLIED_VOLUME { VOLUME_TICK, VOLUME_REAL }; #endif //+------------------------------------------------------------------+ #ifdef __MQL4__ #define TFS 9 -const ENUM_TIMEFRAMES tf[TFS] = { - PERIOD_M1,PERIOD_M5,PERIOD_M15, - PERIOD_M30,PERIOD_H1,PERIOD_H4, - PERIOD_D1,PERIOD_W1,PERIOD_MN1 -}; +const ENUM_TIMEFRAMES tf[TFS] = {PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, + PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1}; #endif //+------------------------------------------------------------------+ #ifdef __MQL5__ #define TFS 21 -const ENUM_TIMEFRAMES tf[TFS] = { - PERIOD_M1,PERIOD_M2,PERIOD_M3,PERIOD_M4,PERIOD_M5,PERIOD_M6, - PERIOD_M10,PERIOD_M12,PERIOD_M15,PERIOD_M20,PERIOD_M30,PERIOD_H1, - PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12, - PERIOD_D1,PERIOD_W1,PERIOD_MN1 -}; +const ENUM_TIMEFRAMES tf[TFS] = {PERIOD_M1, PERIOD_M2, PERIOD_M3, PERIOD_M4, PERIOD_M5, PERIOD_M6, PERIOD_M10, + PERIOD_M12, PERIOD_M15, PERIOD_M20, PERIOD_M30, PERIOD_H1, PERIOD_H2, PERIOD_H3, + PERIOD_H4, PERIOD_H6, PERIOD_H8, PERIOD_H12, PERIOD_D1, PERIOD_W1, PERIOD_MN1}; #endif //+------------------------------------------------------------------+ //| TPositionCount | //+------------------------------------------------------------------+ struct TPositionCount { - int buy_count; - int sell_count; + int buy_count; + int sell_count; }; //+------------------------------------------------------------------+ //| TDealTime | //+------------------------------------------------------------------+ -struct TDealTime -{ - datetime buy_time; - datetime sell_time; +struct TDealTime { + datetime buy_time; + datetime sell_time; }; //+------------------------------------------------------------------+ //| ENUN_OPEN_METHOD | //+------------------------------------------------------------------+ -enum ENUM_OPEN_METHOD -{ - OPEN_METHOD_ONE=-1,// One Of Methods - OPEN_METHOD_SUM=0,// Sum Of Methods - OPEN_METHOD1=1, // Method #1 (1) - OPEN_METHOD2=2, // Method #2 (2) - OPEN_METHOD3=4, // Method #3 (4) - OPEN_METHOD4=8, // Method #4 (8) - OPEN_METHOD5=16, // Method #5 (16) - OPEN_METHOD6=32, // Method #6 (32) - OPEN_METHOD7=64, // Method #7 (64) - OPEN_METHOD8=128 // Method #8 (128) +enum ENUM_OPEN_METHOD { + OPEN_METHOD_ONE = -1, // One Of Methods + OPEN_METHOD_SUM = 0, // Sum Of Methods + OPEN_METHOD1 = 1, // Method #1 (1) + OPEN_METHOD2 = 2, // Method #2 (2) + OPEN_METHOD3 = 4, // Method #3 (4) + OPEN_METHOD4 = 8, // Method #4 (8) + OPEN_METHOD5 = 16, // Method #5 (16) + OPEN_METHOD6 = 32, // Method #6 (32) + OPEN_METHOD7 = 64, // Method #7 (64) + OPEN_METHOD8 = 128 // Method #8 (128) }; //+------------------------------------------------------------------+ //| GetOpenMethod | //+------------------------------------------------------------------+ -int GetOpenMethod(const int open_method,const int one_of_methods,const int sum_of_methods) -{ - int result=open_method; +int GetOpenMethod(const int open_method, const int one_of_methods, const int sum_of_methods) { + int result = open_method; - if(open_method==OPEN_METHOD_ONE) - result=-one_of_methods; + if (open_method == OPEN_METHOD_ONE) result = -one_of_methods; - if(open_method==OPEN_METHOD_SUM) - result=sum_of_methods; + if (open_method == OPEN_METHOD_SUM) result = sum_of_methods; - return(result); + return (result); } //+------------------------------------------------------------------+ //| ENUM_TRADE_DIRECTION | //+------------------------------------------------------------------+ -enum ENUM_TRADE_DIRECTION -{ - TRADE_NONE=-1, //None - TRADE_BUY=0, //Buy - TRADE_SELL=1, //Sell - TRADE_BOTH=2 //Both +enum ENUM_TRADE_DIRECTION { + TRADE_NONE = -1, // None + TRADE_BUY = 0, // Buy + TRADE_SELL = 1, // Sell + TRADE_BOTH = 2 // Both }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ -enum ENUM_RUN_MODE -{ - RUN_OPTIMIZATION, - RUN_VISUAL, - RUN_TESTER, - RUN_LIVE -}; +enum ENUM_RUN_MODE { RUN_OPTIMIZATION, RUN_VISUAL, RUN_TESTER, RUN_LIVE }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ -ENUM_RUN_MODE GetRunMode(void) -{ - if(MQLInfoInteger(MQL_OPTIMIZATION)) - return(RUN_OPTIMIZATION); - if(MQLInfoInteger(MQL_VISUAL_MODE)) - return(RUN_VISUAL); - if(MQLInfoInteger(MQL_TESTER)) - return(RUN_TESTER); - return(RUN_LIVE); +ENUM_RUN_MODE GetRunMode(void) { + if (MQLInfoInteger(MQL_OPTIMIZATION)) return (RUN_OPTIMIZATION); + if (MQLInfoInteger(MQL_VISUAL_MODE)) return (RUN_VISUAL); + if (MQLInfoInteger(MQL_TESTER)) return (RUN_TESTER); + return (RUN_LIVE); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ -string BoolToString(const bool _value) -{ - if(_value) - return("yes"); - return("no"); +string BoolToString(const bool _value) { + if (_value) return ("yes"); + return ("no"); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ -string TimeframeToString(const ENUM_TIMEFRAMES _tf) -{ - return(StringSubstr(EnumToString(_tf),7)); -} +string TimeframeToString(const ENUM_TIMEFRAMES _tf) { return (StringSubstr(EnumToString(_tf), 7)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ -string OpenMethodToString(const ENUM_OPEN_METHOD _open_method, - const int one_of_methods, - const int sum_of_methods) -{ - string result=""; - switch(_open_method) - { - case OPEN_METHOD_ONE: result="One Of Methods ("+IntegerToString(one_of_methods)+")"; break; - case OPEN_METHOD_SUM: result="Sum Of Methods ("+IntegerToString(sum_of_methods)+")"; break; - default: result=StringSubstr(EnumToString(_open_method),5); break; +string OpenMethodToString(const ENUM_OPEN_METHOD _open_method, const int one_of_methods, const int sum_of_methods) { + string result = ""; + switch (_open_method) { + case OPEN_METHOD_ONE: + result = "One Of Methods (" + IntegerToString(one_of_methods) + ")"; + break; + case OPEN_METHOD_SUM: + result = "Sum Of Methods (" + IntegerToString(sum_of_methods) + ")"; + break; + default: + result = StringSubstr(EnumToString(_open_method), 5); + break; } - return(result); + return (result); } //+------------------------------------------------------------------+ //| CBasicTrade | //+------------------------------------------------------------------+ -class CBasicTrade -{ - private: - int m_last_error; - - protected: - //+------------------------------------------------------------------+ - double NormalizeVolume(const double _volume) - { - double lot_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); - double lot_max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX); - double lot_step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); - //--- - double lot_value=_volume; - if(lot_value<=lot_min)lot_value=lot_min; - else if(lot_value>=lot_max)lot_value=lot_max; - else lot_value=round(lot_value/lot_step)*lot_step; - //--- - return(NormalizeDouble(lot_value,2)); - } +class CBasicTrade { + private: + int m_last_error; + + protected: + //+------------------------------------------------------------------+ + double NormalizeVolume(const double _volume) { + double lot_min = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); + double lot_max = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); + double lot_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); + //--- + double lot_value = _volume; + if (lot_value <= lot_min) + lot_value = lot_min; + else if (lot_value >= lot_max) + lot_value = lot_max; + else + lot_value = round(lot_value / lot_step) * lot_step; + //--- + return (NormalizeDouble(lot_value, 2)); + } - //+------------------------------------------------------------------+ - int TimeframeToIndex(ENUM_TIMEFRAMES _tf) - { - if(_tf==0 || _tf==PERIOD_CURRENT) - _tf=(ENUM_TIMEFRAMES)_Period; - int total=ArraySize(tf); - for(int i=0;i 0) { ResetLastError(); - m_last_error=0; - - //--- check symbol name - double _point=SymbolInfoDouble(_symbol,SYMBOL_POINT); - if(_point==0.0) - { - m_last_error=ERR_INVALID_SYMBOL_NAME; - return(false); - } - //--- order type - if(!(_type==TRADE_BUY || _type==TRADE_SELL)) - { - m_last_error=ERR_INVALID_ORDER_TYPE; - return(false); + if (IsTradeContextBusy()) { + Sleep(TRADE_PAUSE_SHORT); + attempts--; + continue; } - //--- get digits - int _digits=(int)SymbolInfoInteger(_symbol,SYMBOL_DIGITS); - - //--- get coef point - int _coef_point=1; - if(_digits==3 || _digits==5) - _coef_point=10; + RefreshRates(); -#ifdef __MQL4__ + //--- check the free margin + if (AccountFreeMarginCheck(_symbol, _type, _volume) <= 0 || _LastError == ERR_NOT_ENOUGH_MONEY) { + m_last_error = ERR_NOT_ENOUGH_MONEY; + return (false); + } - int attempts=5; - while(attempts>0) - { - ResetLastError(); + //--- + double price = 0.0; + if (_type == OP_BUY) price = NormalizeDouble(SymbolInfoDouble(_symbol, SYMBOL_ASK), _digits); + if (_type == OP_SELL) price = NormalizeDouble(SymbolInfoDouble(_symbol, SYMBOL_BID), _digits); - if(IsTradeContextBusy()) - { - Sleep(TRADE_PAUSE_SHORT); - attempts--; - continue; - } - - RefreshRates(); - - //--- check the free margin - if(AccountFreeMarginCheck(_symbol,_type,_volume)<=0 || _LastError==ERR_NOT_ENOUGH_MONEY) - { - m_last_error=ERR_NOT_ENOUGH_MONEY; - return(false); - } - - //--- - double price=0.0; - if(_type==OP_BUY) - price=NormalizeDouble(SymbolInfoDouble(_symbol,SYMBOL_ASK),_digits); - if(_type==OP_SELL) - price=NormalizeDouble(SymbolInfoDouble(_symbol,SYMBOL_BID),_digits); - - //--- - int slippage=(int)SymbolInfoInteger(_symbol,SYMBOL_SPREAD); - - //--- - double volume=NormalizeVolume(_volume); - - //--- - int ticket=OrderSend(_symbol,_type,volume,price,slippage,0,0,_comment,_magic,0,clrNONE); - if(ticket>0) - { - if(_stop_loss>0 || _take_profit>0) - { + //--- + int slippage = (int)SymbolInfoInteger(_symbol, SYMBOL_SPREAD); - if(OrderSelect(ticket,SELECT_BY_TICKET)) - { + //--- + double volume = NormalizeVolume(_volume); + //--- + int ticket = OrderSend(_symbol, _type, volume, price, slippage, 0, 0, _comment, _magic, 0, clrNONE); + if (ticket > 0) { + if (_stop_loss > 0 || _take_profit > 0) { + if (OrderSelect(ticket, SELECT_BY_TICKET)) { + //--- + double order_open_price = NormalizeDouble(OrderOpenPrice(), _digits); + double order_stop_loss = NormalizeDouble(OrderStopLoss(), _digits); + double order_take_profit = NormalizeDouble(OrderTakeProfit(), _digits); + + double sl = 0.0; + double tp = 0.0; + + //--- + attempts = 5; + while (attempts > 0) { + ResetLastError(); + RefreshRates(); //--- - double order_open_price=NormalizeDouble(OrderOpenPrice(),_digits); - double order_stop_loss=NormalizeDouble(OrderStopLoss(),_digits); - double order_take_profit=NormalizeDouble(OrderTakeProfit(),_digits); + double _bid = SymbolInfoDouble(_symbol, SYMBOL_BID); + double _ask = SymbolInfoDouble(_symbol, SYMBOL_ASK); - double sl=0.0; - double tp=0.0; + if (IsTradeContextBusy()) { + attempts--; + Sleep(TRADE_PAUSE_SHORT); + continue; + } //--- - attempts=5; - while(attempts>0) - { - ResetLastError(); - RefreshRates(); - //--- - double _bid = SymbolInfoDouble(_symbol, SYMBOL_BID); - double _ask = SymbolInfoDouble(_symbol, SYMBOL_ASK); - - if(IsTradeContextBusy()) - { - attempts--; - Sleep(TRADE_PAUSE_SHORT); - continue; - } - - //--- - int stop_level=(int)SymbolInfoInteger(_symbol,SYMBOL_TRADE_STOPS_LEVEL); - int spread=(int)SymbolInfoInteger(_symbol,SYMBOL_SPREAD); - stop_level=fmax(stop_level,spread); + int stop_level = (int)SymbolInfoInteger(_symbol, SYMBOL_TRADE_STOPS_LEVEL); + int spread = (int)SymbolInfoInteger(_symbol, SYMBOL_SPREAD); + stop_level = fmax(stop_level, spread); - //--- - if(OrderType()==OP_BUY) - { - if(_stop_loss==-1.0) sl=order_stop_loss; - else if(_stop_loss==0.0) sl=0.0; - else sl=NormalizeDouble(fmin(order_open_price-_stop_loss*_coef_point*_point,_bid-stop_level*_point),_digits); - - if(_take_profit==-1.0) tp=order_take_profit; - else if(_take_profit==0.0) tp=0.0; - else tp=NormalizeDouble(fmax(order_open_price+_take_profit*_coef_point*_point,_bid+stop_level*_point),_digits); - } + //--- + if (OrderType() == OP_BUY) { + if (_stop_loss == -1.0) + sl = order_stop_loss; + else if (_stop_loss == 0.0) + sl = 0.0; + else + sl = NormalizeDouble( + fmin(order_open_price - _stop_loss * _coef_point * _point, _bid - stop_level * _point), _digits); - if(OrderType()==OP_SELL) - { - if(_stop_loss==-1.0) sl=order_stop_loss; - else if(_stop_loss==0.0) sl=0.0; - else sl=NormalizeDouble(fmax(order_open_price+_stop_loss*_coef_point*_point,_ask+stop_level*_point),_digits); + if (_take_profit == -1.0) + tp = order_take_profit; + else if (_take_profit == 0.0) + tp = 0.0; + else + tp = NormalizeDouble( + fmax(order_open_price + _take_profit * _coef_point * _point, _bid + stop_level * _point), + _digits); + } + + if (OrderType() == OP_SELL) { + if (_stop_loss == -1.0) + sl = order_stop_loss; + else if (_stop_loss == 0.0) + sl = 0.0; + else + sl = NormalizeDouble( + fmax(order_open_price + _stop_loss * _coef_point * _point, _ask + stop_level * _point), _digits); - if(_take_profit==-1.0) tp=order_take_profit; - else if(_take_profit==0.0) tp=0.0; - else tp=NormalizeDouble(fmin(order_open_price-_take_profit*_coef_point*_point,_ask-stop_level*_point),_digits); - } + if (_take_profit == -1.0) + tp = order_take_profit; + else if (_take_profit == 0.0) + tp = 0.0; + else + tp = NormalizeDouble( + fmin(order_open_price - _take_profit * _coef_point * _point, _ask - stop_level * _point), + _digits); + } - if(sl==order_stop_loss && tp==order_take_profit) - return(true); + if (sl == order_stop_loss && tp == order_take_profit) return (true); - //--- - ResetLastError(); - if(OrderModify(ticket,order_open_price,sl,tp,0,clrNONE)) - { - return(true); - } - else + //--- + ResetLastError(); + if (OrderModify(ticket, order_open_price, sl, tp, 0, clrNONE)) { + return (true); + } else { + // ENUM_ERROR_LEVEL level=PrintError(_LastError); + // if(level==LEVEL_ERROR) { - //ENUM_ERROR_LEVEL level=PrintError(_LastError); - //if(level==LEVEL_ERROR) - { - Sleep(TRADE_PAUSE_LONG); - return(false); - } + Sleep(TRADE_PAUSE_LONG); + return (false); } + } - //--- - Sleep(TRADE_PAUSE_SHORT); - attempts--; - }// end while - - } - - Sleep(TRADE_PAUSE_SHORT); - return(true); //position opened + //--- + Sleep(TRADE_PAUSE_SHORT); + attempts--; + } // end while } - else - { - //ENUM_ERROR_LEVEL level=PrintError(_LastError); - //if(level==LEVEL_ERROR) - { - Sleep(TRADE_PAUSE_LONG); - break; - } - }// end else Sleep(TRADE_PAUSE_SHORT); - attempts--; - } + return (true); // position opened + } else { + // ENUM_ERROR_LEVEL level=PrintError(_LastError); + // if(level==LEVEL_ERROR) + { + Sleep(TRADE_PAUSE_LONG); + break; + } + } // end else + + Sleep(TRADE_PAUSE_SHORT); + attempts--; } + } #endif - //--- + //--- #ifdef __MQL5__ - ENUM_ORDER_TYPE order_type=-1; - double price=0.0; - double sl=0.0; - double tp=0.0; - double _ask=SymbolInfoDouble(_symbol,SYMBOL_ASK); - double _bid=SymbolInfoDouble(_symbol,SYMBOL_BID); - int stop_level=(int)SymbolInfoInteger(_symbol,SYMBOL_TRADE_STOPS_LEVEL); - if(_type==TRADE_BUY) { - order_type=ORDER_TYPE_BUY; - price=_ask; - - if(_stop_loss>0) - sl=NormalizeDouble(fmin(price-_stop_loss*_coef_point*_point,_bid-stop_level*_point),_digits); - - if(_take_profit>0) - tp=NormalizeDouble(fmax(price+_take_profit*_coef_point*_point,_bid+stop_level*_point),_digits); - - } - if(_type==TRADE_SELL) { - order_type=ORDER_TYPE_SELL; - price=_bid; + ENUM_ORDER_TYPE order_type = -1; + double price = 0.0; + double sl = 0.0; + double tp = 0.0; + double _ask = SymbolInfoDouble(_symbol, SYMBOL_ASK); + double _bid = SymbolInfoDouble(_symbol, SYMBOL_BID); + int stop_level = (int)SymbolInfoInteger(_symbol, SYMBOL_TRADE_STOPS_LEVEL); + if (_type == TRADE_BUY) { + order_type = ORDER_TYPE_BUY; + price = _ask; + + if (_stop_loss > 0) + sl = NormalizeDouble(fmin(price - _stop_loss * _coef_point * _point, _bid - stop_level * _point), _digits); + + if (_take_profit > 0) + tp = NormalizeDouble(fmax(price + _take_profit * _coef_point * _point, _bid + stop_level * _point), _digits); + } + if (_type == TRADE_SELL) { + order_type = ORDER_TYPE_SELL; + price = _bid; - if(_stop_loss>0) - sl=NormalizeDouble(fmax(price+_stop_loss*_coef_point*_point,_ask+stop_level*_point),_digits); + if (_stop_loss > 0) + sl = NormalizeDouble(fmax(price + _stop_loss * _coef_point * _point, _ask + stop_level * _point), _digits); - if(_take_profit>0) - tp=NormalizeDouble(fmin(price-_take_profit*_coef_point*_point,_ask-stop_level*_point),_digits); - } - - double volume=NormalizeVolume(_volume); + if (_take_profit > 0) + tp = NormalizeDouble(fmin(price - _take_profit * _coef_point * _point, _ask - stop_level * _point), _digits); + } - #ifdef CTrade - // @todo: To test. - CTrade trade; - if (!trade) { - return (false); - } - trade.SetDeviationInPoints(SymbolInfoInteger(_symbol, SYMBOL_SPREAD)); - trade.SetExpertMagicNumber(_magic); + double volume = NormalizeVolume(_volume); - //--- - trade.SetTypeFilling(GetTypeFilling(_symbol)); - bool result=trade.PositionOpen(_symbol,order_type,volume,price,sl,tp,_comment); - if (!result) { - m_last_error=(int)trade.ResultRetcode(); - } - #else - return (false); - #endif +#ifdef CTrade + // @todo: To test. + CTrade trade; + if (!trade) { + return (false); + } + trade.SetDeviationInPoints(SymbolInfoInteger(_symbol, SYMBOL_SPREAD)); + trade.SetExpertMagicNumber(_magic); + + //--- + trade.SetTypeFilling(GetTypeFilling(_symbol)); + bool result = trade.PositionOpen(_symbol, order_type, volume, price, sl, tp, _comment); + if (!result) { + m_last_error = (int)trade.ResultRetcode(); + } +#else + return (false); +#endif #endif - return (true); - } + return (true); + } - //+------------------------------------------------------------------+ - int GetLastError() - { - return(m_last_error); - } + //+------------------------------------------------------------------+ + int GetLastError() { return (m_last_error); } }; diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 4e2c2f037..ca9279b4b 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -28,6 +28,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once +#include "Platform.h" #endif // Forward declarations. @@ -35,9 +36,9 @@ class Serializer; // Includes. #include "Chart.enum.h" +#include "Serializer/Serializer.h" #include "Serializer/SerializerNode.enum.h" #include "Terminal.define.h" -#include "Serializer/Serializer.h" /* Defines struct for chart timeframe. */ struct ChartTf { @@ -256,7 +257,7 @@ struct ChartTf { * _tf ENUM_TIMEFRAMES Specify timeframe enum. */ static ENUM_TIMEFRAMES_INDEX TfToIndex(ENUM_TIMEFRAMES _tf) { - _tf = (_tf == 0 || _tf == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)_Period : _tf; + _tf = (_tf == 0 || _tf == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)Platform::Period() : _tf; for (int i = 0; i < ArraySize(TIMEFRAMES_LIST); i++) { if (TIMEFRAMES_LIST[i] == _tf) { return (ENUM_TIMEFRAMES_INDEX)i; diff --git a/Flags.h b/Flags.h index cbc9b04f7..341eca289 100644 --- a/Flags.h +++ b/Flags.h @@ -26,7 +26,7 @@ template struct Flags { // Bit-based value. - unsigned T value; + T value; /** * Constructor. diff --git a/Indicator/Indicator.enum.h b/Indicator/Indicator.enum.h index 58dfdcd5e..646788714 100644 --- a/Indicator/Indicator.enum.h +++ b/Indicator/Indicator.enum.h @@ -117,6 +117,7 @@ enum ENUM_INDICATOR_TYPE { INDI_TEMA, // Triple Exponential Moving Average INDI_TF, // Timeframe INDI_TICK, // Tick + INDI_TICK_RANDOM, // Random Tick. INDI_TMA_TRUE, // Triangular Moving Average True INDI_TRIX, // Triple Exponential Moving Averages Oscillator INDI_ULTIMATE_OSCILLATOR, // Ultimate Oscillator diff --git a/Indicators/Tick/Indi_TickRandom.mqh b/Indicators/Tick/Indi_TickRandom.mqh new file mode 100644 index 000000000..c3b3a6253 --- /dev/null +++ b/Indicators/Tick/Indi_TickRandom.mqh @@ -0,0 +1,103 @@ +//+------------------------------------------------------------------+ +//| 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 + * Random (mainly for C++ testing) 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" +#include "../../Indicator/IndicatorTick.provider.h" + +// Structs. +// Params for MT patform's tick-based indicator. +struct Indi_TickRandomParams : IndicatorParams { + Indi_TickRandomParams() : IndicatorParams(INDI_TICK_RANDOM) {} +}; + +// MT platform's tick-based indicator. +class Indi_TickRandom : public IndicatorTick> { + public: + Indi_TickRandom(Indi_TickRandomParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTick(_p.symbol, _p, + IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_TickRandom(string _symbol, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0, string _name = "") + : IndicatorTick(_symbol, Indi_TickRandomParams(), + IndicatorDataParams(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), _indi_src) { + Init(); + } + + /** + * Initializes the class. + */ + void Init() {} + + string GetName() override { return "Indi_TickRandom"; } + + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + unsigned int GetSuitableDataSourceTypes() override { return INDI_SUITABLE_DS_TYPE_EXPECT_NONE; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } + + /** + * Returns the indicator's struct entry for the given shift. + */ + IndicatorDataEntry GetEntry(int _index = 0) override { + IndicatorDataEntry _default; + return _default; + } + + /** + * Fetches historic ticks for a given time range. + */ + virtual bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { + // No history. + return false; + } + + void OnTick(int _global_tick_index) override { + float _ask = 1.0f + (1.0f / 32767 * MathRand()); + float _bid = 1.0f + (1.0f / 32767 * MathRand()); + TickAB _tick(, _bid); + IndicatorDataEntry _entry(TickToEntry(_time, _tick)); + EmitEntry(_entry); + // Appending tick into the history. + AppendEntry(_entry); + } +}; diff --git a/Platform.h b/Platform.h index 97a88f018..3993b4f98 100644 --- a/Platform.h +++ b/Platform.h @@ -28,14 +28,15 @@ #include "Flags.h" #include "Indicator/IndicatorData.h" +#include "Indicator/tests/classes/IndicatorTfDummy.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! +#include "Indicators/Tick/Indi_TickRandom.mqh" +#define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickRandom #endif #include "SymbolInfo.struct.static.h" @@ -311,6 +312,18 @@ class Platform { } return _result; } + + /** + * Returns currently selected period for platform. + */ + static ENUM_TIMEFRAMES Period() { +#ifdef __MQL__ + return Period(); +#else + // @fixit Should fetch selected period from somewhere. + return PERIOD_M15; +#endif + } }; bool Platform::initialized = false; diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index 1700bef52..6f704c47a 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -212,7 +212,8 @@ void ArrayInitialize(ValueStorage &_storage, C _value) { * ValueStorage-compatible wrapper for ArrayCopy. */ template -int ArrayCopy(D &_target[], ValueStorage &_source, int _dst_start = 0, int _src_start = 0, int count = WHOLE_ARRAY) { +int ArrayCopy(ARRAY_REF(D, _target), ValueStorage &_source, int _dst_start = 0, int _src_start = 0, + int count = WHOLE_ARRAY) { if (count == WHOLE_ARRAY) { count = ArraySize(_source); } diff --git a/Strategy.struct.h b/Strategy.struct.h index cea4c81bb..5c4eef27f 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -366,7 +366,7 @@ struct StgParams { struct Stg_Params { string symbol; ENUM_TIMEFRAMES tf; - Stg_Params() : symbol(_Symbol), tf((ENUM_TIMEFRAMES)_Period) {} + Stg_Params() : symbol(_Symbol), tf((ENUM_TIMEFRAMES)Period()) {} }; /* Structure for strategy's process results. */ diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index b5cd6aa6f..a61e5a6a7 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -26,6 +26,7 @@ #endif #include "MQL5.mqh" +#include "Math.h" #include "Order.enum.h" #include "Std.h" #include "Tick/Tick.struct.h" @@ -128,7 +129,7 @@ struct SymbolInfoStatic { */ static double GetPipValue(string _symbol) { unsigned int _pdigits = GetPipDigits(_symbol); - return 1.0 / MathPow(10, _pdigits); + return 1.0 / MathPow(10, (int)_pdigits); } /** From 4cdd0d2caac51b5f283dcac2d737c6b8803bd5e2 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 11 Nov 2022 16:01:14 +0100 Subject: [PATCH 043/123] WIP. Fixing C++ include loops. --- Array.mqh | 4 +- Data.struct.h | 44 --------------- Data.struct.serialize.h | 78 +++++++++++++++++++++++++++ Task/TaskCondition.struct.h | 16 +++--- Task/TaskCondition.struct.serialize.h | 44 +++++++++++++++ 5 files changed, 130 insertions(+), 56 deletions(-) create mode 100644 Data.struct.serialize.h create mode 100644 Task/TaskCondition.struct.serialize.h diff --git a/Array.mqh b/Array.mqh index 2a0c6094e..040767b6f 100644 --- a/Array.mqh +++ b/Array.mqh @@ -691,7 +691,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { * - https://www.mql5.com/en/docs/array/arraymaximum */ template - static int ArrayMinimum(const ARRAY_REF(X, _array), int _start = 0, int _count = WHOLE_ARRAY) { + static int ArrayMinimum(ARRAY_REF(X, _array), int _start = 0, int _count = WHOLE_ARRAY) { #ifdef __MQL__ return ::ArrayMinimum(_array); #else @@ -724,7 +724,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { * - https://www.mql5.com/en/docs/array/arraymaximum */ template - static int ArrayMaximum(const ARRAY_REF(X, _array), int start = 0, int count = WHOLE_ARRAY) { + static int ArrayMaximum(ARRAY_REF(X, _array), int start = 0, int count = WHOLE_ARRAY) { #ifdef __MQL__ return ::ArrayMaximum(_array); #else diff --git a/Data.struct.h b/Data.struct.h index e174e6456..bed5b1980 100644 --- a/Data.struct.h +++ b/Data.struct.h @@ -41,7 +41,6 @@ struct MqlRates; #include "Serializer/Serializer.enum.h" #include "Serializer/SerializerNode.enum.h" #include "Std.h" -#include "Serializer/Serializer.h" #ifndef __MQL__ /** @@ -330,46 +329,3 @@ struct DataParamEntry : public MqlParam { } SerializerNodeType Serialize(Serializer &s); }; - -/* Method to serialize DataParamEntry struct. */ -SerializerNodeType DataParamEntry::Serialize(Serializer &s) { - s.PassEnum(THIS_REF, "type", type, SERIALIZER_FIELD_FLAG_HIDDEN); - string aux_string; - - switch (type) { - case TYPE_BOOL: - case TYPE_UCHAR: - case TYPE_CHAR: - case TYPE_USHORT: - case TYPE_SHORT: - case TYPE_UINT: - case TYPE_INT: - case TYPE_ULONG: - case TYPE_LONG: - s.Pass(THIS_REF, "value", integer_value); - break; - - case TYPE_DOUBLE: - s.Pass(THIS_REF, "value", double_value); - break; - - case TYPE_STRING: - s.Pass(THIS_REF, "value", string_value); - break; - - case TYPE_DATETIME: - if (s.IsWriting()) { - aux_string = TimeToString(integer_value); - s.Pass(THIS_REF, "value", aux_string); - } else { - s.Pass(THIS_REF, "value", aux_string); - integer_value = StringToTime(aux_string); - } - break; - - default: - // Unknown type. Serializing anyway. - s.Pass(THIS_REF, "value", aux_string); - } - return SerializerNodeObject; -} diff --git a/Data.struct.serialize.h b/Data.struct.serialize.h new file mode 100644 index 000000000..d55ad12e1 --- /dev/null +++ b/Data.struct.serialize.h @@ -0,0 +1,78 @@ +//+------------------------------------------------------------------+ +//| 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 Data struct serialization methods. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "Data.struct.h" +#include "Serializer/Serializer.h" + +/* Method to serialize DataParamEntry struct. */ +SerializerNodeType DataParamEntry::Serialize(Serializer &s) { + s.PassEnum(THIS_REF, "type", type, SERIALIZER_FIELD_FLAG_HIDDEN); + string aux_string; + + switch (type) { + case TYPE_BOOL: + case TYPE_UCHAR: + case TYPE_CHAR: + case TYPE_USHORT: + case TYPE_SHORT: + case TYPE_UINT: + case TYPE_INT: + case TYPE_ULONG: + case TYPE_LONG: + s.Pass(THIS_REF, "value", integer_value); + break; + + case TYPE_DOUBLE: + s.Pass(THIS_REF, "value", double_value); + break; + + case TYPE_STRING: + s.Pass(THIS_REF, "value", string_value); + break; + + case TYPE_DATETIME: + if (s.IsWriting()) { + aux_string = TimeToString(integer_value); + s.Pass(THIS_REF, "value", aux_string); + } else { + s.Pass(THIS_REF, "value", aux_string); + integer_value = StringToTime(aux_string); + } + break; + + default: + // Unknown type. Serializing anyway. + s.Pass(THIS_REF, "value", aux_string); + } + return SerializerNodeObject; +} diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 494e8bf3e..ce239fb1e 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -31,10 +31,15 @@ // Includes. #include "../Data.struct.h" +#include "../Serializer/Serializer.define.h" +#include "../Serializer/Serializer.enum.h" #include "../Std.h" #include "../Terminal.define.h" #include "Task.enum.h" +// Forward declarations. +class Serializer; + struct TaskConditionEntry { public: /* Enumerations */ @@ -198,16 +203,7 @@ struct TaskConditionEntry { public: // Serializers - SerializerNodeType Serialize(Serializer &s) { - s.Pass(THIS_REF, "flags", flags); - s.Pass(THIS_REF, "id", id); - s.Pass(THIS_REF, "last_check", last_check); - s.Pass(THIS_REF, "last_success", last_success); - s.Pass(THIS_REF, "tries", tries); - s.PassEnum(THIS_REF, "freq", freq); - s.PassArray(THIS_REF, "args", args); - return SerializerNodeObject; - } + SerializerNodeType Serialize(Serializer &s); SERIALIZER_EMPTY_STUB; }; diff --git a/Task/TaskCondition.struct.serialize.h b/Task/TaskCondition.struct.serialize.h new file mode 100644 index 000000000..9b6a0afea --- /dev/null +++ b/Task/TaskCondition.struct.serialize.h @@ -0,0 +1,44 @@ +//+------------------------------------------------------------------+ +//| 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 TaskCondition's structures serialization methods. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "TaskCondition.struct.h" + +SerializerNodeType TaskConditionEntry::Serialize(Serializer &s) { + s.Pass(THIS_REF, "flags", flags); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "last_check", last_check); + s.Pass(THIS_REF, "last_success", last_success); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); + s.PassArray(THIS_REF, "args", args); + return SerializerNodeObject; +} \ No newline at end of file From fc3de6947132d955717c2f0c68a7c984ac23e336 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 11 Nov 2022 17:23:58 +0100 Subject: [PATCH 044/123] WIP. Fixing MQL/C++ errors. Moving serialization methods to separate files. --- Chart.struct.tf.h | 2 +- Convert.basic.h | 151 ++++++++++ Convert.mqh | 118 -------- Data.struct.h | 5 +- DateTime.extern.h | 9 +- Dict.mqh | 4 +- DictObject.mqh | 27 +- DictStruct.mqh | 25 +- MD5.mqh | 386 +++++++++++++------------- Platform.h | 12 - Serializer/Serializer.h | 10 +- Serializer/tests/Serializer.test.mq5 | 1 + Std.h | 10 + SymbolInfo.struct.static.h | 1 - Task/TaskAction.struct.h | 14 +- Task/TaskAction.struct.serialize.h | 44 +++ Task/TaskCondition.struct.serialize.h | 2 +- Task/TaskGetter.struct.h | 11 +- Task/TaskGetter.struct.serialize.h | 44 +++ Task/TaskSetter.struct.h | 1 + Task/tests/TaskManager.test.mq5 | 3 + tests/BufferStructTest.mq5 | 1 + tests/IndicatorsTest.mq5 | 4 - 23 files changed, 503 insertions(+), 382 deletions(-) create mode 100644 Convert.basic.h create mode 100644 Task/TaskAction.struct.serialize.h create mode 100644 Task/TaskGetter.struct.serialize.h diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index ca9279b4b..1f1a2f89c 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -257,7 +257,7 @@ struct ChartTf { * _tf ENUM_TIMEFRAMES Specify timeframe enum. */ static ENUM_TIMEFRAMES_INDEX TfToIndex(ENUM_TIMEFRAMES _tf) { - _tf = (_tf == 0 || _tf == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)Platform::Period() : _tf; + _tf = (_tf == 0 || _tf == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)Period() : _tf; for (int i = 0; i < ArraySize(TIMEFRAMES_LIST); i++) { if (TIMEFRAMES_LIST[i] == _tf) { return (ENUM_TIMEFRAMES_INDEX)i; diff --git a/Convert.basic.h b/Convert.basic.h new file mode 100644 index 000000000..3725a9e13 --- /dev/null +++ b/Convert.basic.h @@ -0,0 +1,151 @@ +//+------------------------------------------------------------------+ +//| 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 . + * + */ + +// Prevents processing this includes file for the second time. +#ifndef __MQL__ +#pragma once +#endif + +// Includes. +#include "Array.mqh" +#include "Common.extern.h" +#include "DateTime.mqh" +#include "Std.h" +#include "String.mqh" + +/** + * Class to provide conversion methods. + */ +class ConvertBasic { + public: + /** + * Convert integer to hex. + */ + static string IntToHex(long long_number) { + string result; + int integer_number = (int)long_number; + for (int i = 0; i < 4; i++) { + int byte = (integer_number >> (i * 8)) & 0xff; + result += StringFormat("%02x", byte); + } + return result; + } + + /** + * Convert character into integer. + */ + static int CharToInt(ARRAY_REF(int, _chars)) { + return ((_chars[0]) | (_chars[1] << 8) | (_chars[2] << 16) | (_chars[3] << 24)); + } + + /** + * Assume: len % 4 == 0. + */ + static int String4ToIntArray(ARRAY_REF(int, output), string in) { + int len; + int i, j; + len = StringLen(in); + if (len % 4 != 0) len = len - len % 4; + int size = ArraySize(output); + if (size < len / 4) { + ArrayResize(output, len / 4); + } + for (i = 0, j = 0; j < len; i++, j += 4) { + output[i] = (StringGetCharacter(in, j)) | ((StringGetCharacter(in, j + 1)) << 8) | + ((StringGetCharacter(in, j + 2)) << 16) | ((StringGetCharacter(in, j + 3)) << 24); + } + return (len / 4); + } + + static void StringToType(string _value, bool& _out) { +#ifdef __MQL__ + _out = _value != "" && _value != NULL && _value != "0" && _value != "false"; +#else + _out = _value != "" && _value != "0" && _value != "false"; +#endif + } + + static void StringToType(string _value, int& _out) { _out = (int)StringToInteger(_value); } + static void StringToType(string _value, unsigned int& _out) { _out = (unsigned int)StringToInteger(_value); } + static void StringToType(string _value, char& _out) { _out = (char)_value[0]; } + static void StringToType(string _value, unsigned char& _out) { _out = (unsigned char)_value[0]; } + static void StringToType(string _value, long& _out) { _out = StringToInteger(_value); } + static void StringToType(string _value, unsigned long& _out) { _out = StringToInteger(_value); } + static void StringToType(string _value, short& _out) { _out = (short)StringToInteger(_value); } + static void StringToType(string _value, unsigned short& _out) { _out = (unsigned short)StringToInteger(_value); } + static void StringToType(string _value, float& _out) { _out = (float)StringToDouble(_value); } + static void StringToType(string _value, double& _out) { _out = StringToDouble(_value); } + static void StringToType(string _value, string& _out) { _out = _value; } + static void StringToType(string _value, color& _out) { _out = 0; } + static void StringToType(string _value, datetime& _out) { +#ifdef __MQL4__ + _out = StrToTime(_value); +#else + _out = StringToTime(_value); +#endif + } + + static void BoolToType(bool _value, bool& _out) { _out = _value; } + static void BoolToType(bool _value, char& _out) { _out = (char)_value; } + static void BoolToType(bool _value, unsigned char& _out) { _out = (unsigned char)_value; } + static void BoolToType(bool _value, int& _out) { _out = (int)_value; } + static void BoolToType(bool _value, unsigned int& _out) { _out = (unsigned int)_value; } + static void BoolToType(bool _value, long& _out) { _out = (long)_value; } + static void BoolToType(bool _value, unsigned long& _out) { _out = (unsigned long)_value; } + static void BoolToType(bool _value, short& _out) { _out = (short)_value; } + static void BoolToType(bool _value, unsigned short& _out) { _out = (unsigned short)_value; } + static void BoolToType(bool _value, float& _out) { _out = (float)_value; } + static void BoolToType(bool _value, double& _out) { _out = (double)_value; } + static void BoolToType(bool _value, string& _out) { _out = _value ? "1" : "0"; } + static void BoolToType(bool _value, color& _out) { _out = 0; } + static void BoolToType(bool _value, datetime& _out) {} + + static void LongToType(long _value, bool& _out) { _out = (bool)_value; } + static void LongToType(long _value, char& _out) { _out = (char)_value; } + static void LongToType(long _value, unsigned char& _out) { _out = (unsigned char)_value; } + static void LongToType(long _value, int& _out) { _out = (int)_value; } + static void LongToType(long _value, unsigned int& _out) { _out = (unsigned int)_value; } + static void LongToType(long _value, long& _out) { _out = (long)_value; } + static void LongToType(long _value, unsigned long& _out) { _out = (unsigned long)_value; } + static void LongToType(long _value, short& _out) { _out = (short)_value; } + static void LongToType(long _value, unsigned short& _out) { _out = (unsigned short)_value; } + static void LongToType(long _value, float& _out) { _out = (float)_value; } + static void LongToType(long _value, double& _out) { _out = (double)_value; } + static void LongToType(long _value, string& _out) { _out = _value ? "1" : "0"; } + static void LongToType(long _value, color& _out) { _out = 0; } + static void LongToType(long _value, datetime& _out) {} + + static void DoubleToType(double _value, bool& _out) { _out = (bool)_value; } + static void DoubleToType(double _value, char& _out) { _out = (char)_value; } + static void DoubleToType(double _value, unsigned char& _out) { _out = (unsigned char)_value; } + static void DoubleToType(double _value, int& _out) { _out = (int)_value; } + static void DoubleToType(double _value, unsigned int& _out) { _out = (unsigned int)_value; } + static void DoubleToType(double _value, long& _out) { _out = (long)_value; } + static void DoubleToType(double _value, unsigned long& _out) { _out = (unsigned long)_value; } + static void DoubleToType(double _value, short& _out) { _out = (short)_value; } + static void DoubleToType(double _value, unsigned short& _out) { _out = (unsigned short)_value; } + static void DoubleToType(double _value, float& _out) { _out = (float)_value; } + static void DoubleToType(double _value, double& _out) { _out = (double)_value; } + static void DoubleToType(double _value, string& _out) { _out = _value ? "1" : "0"; } + static void DoubleToType(double _value, color& _out) { _out = 0; } + static void DoubleToType(double _value, datetime& _out) {} +}; diff --git a/Convert.mqh b/Convert.mqh index 507bf4292..b371eeeca 100644 --- a/Convert.mqh +++ b/Convert.mqh @@ -20,10 +20,6 @@ * */ -// Prevents processing this includes file for the second time. -#ifndef CONVERT_MQH -#define CONVERT_MQH - // Prevents processing this includes file for the second time. #ifndef __MQL__ #pragma once @@ -280,118 +276,4 @@ class Convert { return prefix ? CharToString(sign) + DoubleToString(value, digits) : DoubleToString(value, digits) + CharToString(sign); } - - /** - * Convert integer to hex. - */ - static string IntToHex(long long_number) { - string result; - int integer_number = (int)long_number; - for (int i = 0; i < 4; i++) { - int byte = (integer_number >> (i * 8)) & 0xff; - result += StringFormat("%02x", byte); - } - return result; - } - - /** - * Convert character into integer. - */ - static int CharToInt(ARRAY_REF(int, _chars)) { - return ((_chars[0]) | (_chars[1] << 8) | (_chars[2] << 16) | (_chars[3] << 24)); - } - - /** - * Assume: len % 4 == 0. - */ - static int String4ToIntArray(ARRAY_REF(int, output), string in) { - int len; - int i, j; - len = StringLen(in); - if (len % 4 != 0) len = len - len % 4; - int size = ArraySize(output); - if (size < len / 4) { - ArrayResize(output, len / 4); - } - for (i = 0, j = 0; j < len; i++, j += 4) { - output[i] = (StringGetCharacter(in, j)) | ((StringGetCharacter(in, j + 1)) << 8) | - ((StringGetCharacter(in, j + 2)) << 16) | ((StringGetCharacter(in, j + 3)) << 24); - } - return (len / 4); - } - - static void StringToType(string _value, bool& _out) { -#ifdef __MQL__ - _out = _value != "" && _value != NULL && _value != "0" && _value != "false"; -#else - _out = _value != "" && _value != "0" && _value != "false"; -#endif - } - - static void StringToType(string _value, int& _out) { _out = (int)StringToInteger(_value); } - static void StringToType(string _value, unsigned int& _out) { _out = (unsigned int)StringToInteger(_value); } - static void StringToType(string _value, char& _out) { _out = (char)_value[0]; } - static void StringToType(string _value, unsigned char& _out) { _out = (unsigned char)_value[0]; } - static void StringToType(string _value, long& _out) { _out = StringToInteger(_value); } - static void StringToType(string _value, unsigned long& _out) { _out = StringToInteger(_value); } - static void StringToType(string _value, short& _out) { _out = (short)StringToInteger(_value); } - static void StringToType(string _value, unsigned short& _out) { _out = (unsigned short)StringToInteger(_value); } - static void StringToType(string _value, float& _out) { _out = (float)StringToDouble(_value); } - static void StringToType(string _value, double& _out) { _out = StringToDouble(_value); } - static void StringToType(string _value, string& _out) { _out = _value; } - static void StringToType(string _value, color& _out) { _out = 0; } - static void StringToType(string _value, datetime& _out) { -#ifdef __MQL4__ - _out = StrToTime(_value); -#else - _out = StringToTime(_value); -#endif - } - - static void BoolToType(bool _value, bool& _out) { _out = _value; } - static void BoolToType(bool _value, char& _out) { _out = (char)_value; } - static void BoolToType(bool _value, unsigned char& _out) { _out = (unsigned char)_value; } - static void BoolToType(bool _value, int& _out) { _out = (int)_value; } - static void BoolToType(bool _value, unsigned int& _out) { _out = (unsigned int)_value; } - static void BoolToType(bool _value, long& _out) { _out = (long)_value; } - static void BoolToType(bool _value, unsigned long& _out) { _out = (unsigned long)_value; } - static void BoolToType(bool _value, short& _out) { _out = (short)_value; } - static void BoolToType(bool _value, unsigned short& _out) { _out = (unsigned short)_value; } - static void BoolToType(bool _value, float& _out) { _out = (float)_value; } - static void BoolToType(bool _value, double& _out) { _out = (double)_value; } - static void BoolToType(bool _value, string& _out) { _out = _value ? "1" : "0"; } - static void BoolToType(bool _value, color& _out) { _out = 0; } - static void BoolToType(bool _value, datetime& _out) {} - - static void LongToType(long _value, bool& _out) { _out = (bool)_value; } - static void LongToType(long _value, char& _out) { _out = (char)_value; } - static void LongToType(long _value, unsigned char& _out) { _out = (unsigned char)_value; } - static void LongToType(long _value, int& _out) { _out = (int)_value; } - static void LongToType(long _value, unsigned int& _out) { _out = (unsigned int)_value; } - static void LongToType(long _value, long& _out) { _out = (long)_value; } - static void LongToType(long _value, unsigned long& _out) { _out = (unsigned long)_value; } - static void LongToType(long _value, short& _out) { _out = (short)_value; } - static void LongToType(long _value, unsigned short& _out) { _out = (unsigned short)_value; } - static void LongToType(long _value, float& _out) { _out = (float)_value; } - static void LongToType(long _value, double& _out) { _out = (double)_value; } - static void LongToType(long _value, string& _out) { _out = _value ? "1" : "0"; } - static void LongToType(long _value, color& _out) { _out = 0; } - static void LongToType(long _value, datetime& _out) {} - - static void DoubleToType(double _value, bool& _out) { _out = (bool)_value; } - static void DoubleToType(double _value, char& _out) { _out = (char)_value; } - static void DoubleToType(double _value, unsigned char& _out) { _out = (unsigned char)_value; } - static void DoubleToType(double _value, int& _out) { _out = (int)_value; } - static void DoubleToType(double _value, unsigned int& _out) { _out = (unsigned int)_value; } - static void DoubleToType(double _value, long& _out) { _out = (long)_value; } - static void DoubleToType(double _value, unsigned long& _out) { _out = (unsigned long)_value; } - static void DoubleToType(double _value, short& _out) { _out = (short)_value; } - static void DoubleToType(double _value, unsigned short& _out) { _out = (unsigned short)_value; } - static void DoubleToType(double _value, float& _out) { _out = (float)_value; } - static void DoubleToType(double _value, double& _out) { _out = (double)_value; } - static void DoubleToType(double _value, string& _out) { _out = _value ? "1" : "0"; } - static void DoubleToType(double _value, color& _out) { _out = 0; } - static void DoubleToType(double _value, datetime& _out) {} }; - -#endif // CONVERT_MQH diff --git a/Data.struct.h b/Data.struct.h index bed5b1980..9d6fe8959 100644 --- a/Data.struct.h +++ b/Data.struct.h @@ -37,10 +37,11 @@ struct MqlRates; // Includes. #include "Data.enum.h" -#include "DateTime.mqh" +#include "DateTime.extern.h" #include "Serializer/Serializer.enum.h" #include "Serializer/SerializerNode.enum.h" #include "Std.h" +#include "String.mqh" #ifndef __MQL__ /** @@ -188,7 +189,7 @@ struct DataParamEntry : public MqlParam { case TYPE_CHAR: case TYPE_STRING: case TYPE_UCHAR: - return (T)::StringToDouble(string_value); + return (T)StringToDouble(string_value); case TYPE_DOUBLE: case TYPE_FLOAT: return (T)ToDouble(THIS_REF); diff --git a/DateTime.extern.h b/DateTime.extern.h index e6ebbe21a..e3dee2b4f 100644 --- a/DateTime.extern.h +++ b/DateTime.extern.h @@ -20,15 +20,18 @@ * */ -// Includes. -#include "DateTime.enum.h" - /** * @file * Includes external declarations related to date and time. */ #ifndef __MQL__ #pragma once + +// Includes. +#include +#include "DateTime.enum.h" +#include "String.mqh" + // Forward declarations. struct MqlDateTime; diff --git a/Dict.mqh b/Dict.mqh index d9960273b..56f894fdc 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -24,7 +24,7 @@ #ifndef DICT_MQH #define DICT_MQH -#include "Convert.mqh" +#include "Convert.basic.h" #include "DictBase.mqh" #include "Matrix.mqh" #include "Serializer/Serializer.h" @@ -404,7 +404,7 @@ class Dict : public DictBase { if (i.HasKey()) { // Converting key to a string. K key; - Convert::StringToType(i.Key(), key); + ConvertBasic::StringToType(i.Key(), key); // Note that we're retrieving value by a key (as we are in an // object!). diff --git a/DictObject.mqh b/DictObject.mqh index 648e8b33f..c02437267 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -20,11 +20,12 @@ * */ -// Prevents processing this includes file for the second time. -#ifndef DICT_OBJECT_MQH -#define DICT_OBJECT_MQH +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif -#include "Convert.mqh" +#include "Convert.basic.h" #include "DictBase.mqh" #include "Serializer/Serializer.h" #include "Serializer/SerializerNodeIterator.h" @@ -222,7 +223,7 @@ class DictObject : public DictBase { // If we have a slot then we can overwrite it. if (_slot != NULL) { - WriteSlot(_slot, key, value, DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); + WriteSlot(PTR_TO_REF(_slot), key, value, DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); // We're done, we don't have to increment number of slots used. return true; } @@ -236,7 +237,7 @@ class DictObject : public DictBase { if ((_is_full || !_is_performant) && allow_resize) { // We have to resize the dict as it is either full or have perfomance problems due to massive number of conflicts // when inserting new values. - if (overflow_listener == NULL) { + if (THIS_ATTR overflow_listener == NULL) { // There is no overflow listener so we can freely grow up the dict. if (!GrowUp()) { // Can't resize the dict. Error happened. @@ -244,8 +245,9 @@ class DictObject : public DictBase { } } else { // Overflow listener will decide if we can grow up the dict. - if (overflow_listener(_is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, - dictSlotsRef._num_used, 0)) { + if (THIS_ATTR overflow_listener( + _is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, + dictSlotsRef._num_used, 0)) { // We can freely grow up the dict. if (!GrowUp()) { // Can't resize the dict. Error happened. @@ -272,11 +274,12 @@ class DictObject : public DictBase { (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { ++_num_conflicts; - if (overflow_listener != NULL) { + if (THIS_ATTR overflow_listener != NULL) { // We had to skip slot as it is already occupied. Now we are checking if // there is too many conflicts/skips and thus we can overwrite slot in // the starting position. - if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + if (THIS_ATTR overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, + _num_conflicts)) { // Looks like dict is working as buffer and we can overwrite slot in the starting position. position = _starting_position; break; @@ -427,7 +430,7 @@ class DictObject : public DictBase { if (i.HasKey()) { // Converting key to a string. K key; - Convert::StringToType(i.Key(), key); + ConvertBasic::StringToType(i.Key(), key); // Note that we're retrieving value by a key (as we are in an // object!). @@ -459,5 +462,3 @@ class DictObject : public DictBase { } } }; - -#endif diff --git a/DictStruct.mqh b/DictStruct.mqh index f336b080b..72e841a0e 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -21,9 +21,12 @@ */ // Prevents processing this includes file for the second time. -#ifndef DICT_STRUCT_MQH -#define DICT_STRUCT_MQH +#ifndef __MQL__ +#pragma once +#endif +// Includes. +#include "Convert.basic.h" #include "DictBase.mqh" #include "DictIteratorBase.mqh" #include "Serializer/Serializer.h" @@ -290,7 +293,7 @@ class DictStruct : public DictBase { // If we have a slot then we can overwrite it. if (_slot != NULL) { - WriteSlot(_slot, key, value, DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); + WriteSlot(PTR_TO_REF(_slot), key, value, DICT_SLOT_HAS_KEY | DICT_SLOT_IS_USED | DICT_SLOT_WAS_USED); // We're done, we don't have to increment number of slots used. return true; } @@ -304,7 +307,7 @@ class DictStruct : public DictBase { if ((_is_full || !_is_performant) && allow_resize) { // We have to resize the dict as it is either full or have perfomance problems due to massive number of conflicts // when inserting new values. - if (overflow_listener == NULL) { + if (THIS_ATTR overflow_listener == NULL) { // There is no overflow listener so we can freely grow up the dict. if (!GrowUp()) { // Can't resize the dict. Error happened. @@ -312,8 +315,9 @@ class DictStruct : public DictBase { } } else { // Overflow listener will decide if we can grow up the dict. - if (overflow_listener(_is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, - dictSlotsRef._num_used, 0)) { + if (THIS_ATTR overflow_listener( + _is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, + dictSlotsRef._num_used, 0)) { // We can freely grow up the dict. if (!GrowUp()) { // Can't resize the dict. Error happened. @@ -340,11 +344,12 @@ class DictStruct : public DictBase { (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { ++_num_conflicts; - if (overflow_listener != NULL) { + if (THIS_ATTR overflow_listener != NULL) { // We had to skip slot as it is already occupied. Now we are checking if // there is too many conflicts/skips and thus we can overwrite slot in // the starting position. - if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + if (THIS_ATTR overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, + _num_conflicts)) { // Looks like dict is working as buffer and we can overwrite slot in the starting position. position = _starting_position; break; @@ -490,7 +495,7 @@ class DictStruct : public DictBase { if (i.HasKey()) { // Converting key to a string. K key; - Convert::StringToType(i.Key(), key); + ConvertBasic::StringToType(i.Key(), key); // Note that we're retrieving value by a key (as we are in an // object!). @@ -520,5 +525,3 @@ class DictStruct : public DictBase { } } }; - -#endif diff --git a/MD5.mqh b/MD5.mqh index 626fd1617..c34fce753 100644 --- a/MD5.mqh +++ b/MD5.mqh @@ -7,13 +7,23 @@ License: New BSD License - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following + disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -23,203 +33,197 @@ The MD5 algorithm is only for optimized string, the string can support MQL4 longest string. If the large file MD5 encryption, see a little improvement to this algorithm, when I was in design, also made consideration, you can quickly convert over. - Problems may occur, but the repair method is also very simple, it is the first 16 bits are added, then after 16 are summed. Note that the first 16-bit carry: - var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); (msw << 16) | (lsw & 0xFFFF); - If you're using the algorithm, but also pay attention to test the accuracy of the Chinese case, the algorithm does not take a lot of Chinese. - Some dictionaries now online MD5 crack site, in fact, do not be afraid of them, you put the initial algorithm a, b, c, d change it, it becomes a new encryption algorithm of. + Problems may occur, but the repair method is also very simple, it is the first 16 bits are added, then after 16 are + summed. Note that the first 16-bit carry: var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + + (lsw >> 16); (msw << 16) | (lsw & 0xFFFF); If you're using the algorithm, but also pay attention to test the + accuracy of the Chinese case, the algorithm does not take a lot of Chinese. Some dictionaries now online MD5 crack + site, in fact, do not be afraid of them, you put the initial algorithm a, b, c, d change it, it becomes a new + encryption algorithm of. @see: http://www.cnblogs.com/niniwzw/archive/2009/12/05/1617685.html */ - // Includes. #include "Array.mqh" -#include "Convert.mqh" +#include "Convert.basic.h" /** * Class to provide implementation of MD5 algorithm. * Based on the code published at: https://code.google.com/archive/p/md5-in-mql4/ */ class MD5 { - - public: - - /** - * Calculate MD5 checksum. - */ - static string MD5Sum(string str) { - int len = StringLen(str); - int index = len % 64; //mod 64 - int count = (len - index) / 64; - - long a = 0x67452301, b = 0xEFCDAB89, c = 0x98BADCFE, d = 0x10325476; - int buff[16], last[16], i, k = 0, last_char[4], last_index; - string item; - for (i = 0; i < count; i++) - { - item = StringSubstr(str, i * 64, 64); - Convert::String4ToIntArray(buff, item); - MD5Transform(a, b, c, d, buff); - } - ArrayInitialize(last, 0); - ArrayInitialize(last_char, 0); - last_index = 0; - if (index > 0) { - int last_num = index % 4; - count = index - last_num; - if (count > 0) { - item = StringSubstr(str, i * 64, count); - last_index = Convert::String4ToIntArray(last, item); - } - for (k = 0; k < last_num; k++) - { - last_char[k] = StringGetCharacter(str, i * 64 + count + k); - } + public: + /** + * Calculate MD5 checksum. + */ + static string MD5Sum(string str) { + int len = StringLen(str); + int index = len % 64; // mod 64 + int count = (len - index) / 64; + + long a = 0x67452301, b = 0xEFCDAB89, c = 0x98BADCFE, d = 0x10325476; + int buff[16], last[16], i, k = 0, last_char[4], last_index; + string item; + for (i = 0; i < count; i++) { + item = StringSubstr(str, i * 64, 64); + ConvertBasic::String4ToIntArray(buff, item); + MD5Transform(a, b, c, d, buff); + } + ArrayInitialize(last, 0); + ArrayInitialize(last_char, 0); + last_index = 0; + if (index > 0) { + int last_num = index % 4; + count = index - last_num; + if (count > 0) { + item = StringSubstr(str, i * 64, count); + last_index = ConvertBasic::String4ToIntArray(last, item); } - last_char[k] = 0x80; - last[last_index] = Convert::CharToInt(last_char); - if (index >= 56) { - MD5Transform(a, b, c, d, last); - ArrayInitialize(last, 0); + for (k = 0; k < last_num; k++) { + last_char[k] = StringGetCharacter(str, i * 64 + count + k); } - last[14] = len << 3; - last[15] = ((len >> 1) & 0x7fffffff) >> 28; - MD5Transform(a, b, c, d, last); - string result = StringFormat("%s%s%s%s", - Convert::IntToHex(a), Convert::IntToHex(b), Convert::IntToHex(c), Convert::IntToHex(d)); - return result; - } - - static long F(long x, long y, long z) { - return ((x & y) | ((~x) & z)); - } - - static long G(long x, long y, long z) { - return ((x & z) | (y & (~z))); - } - - static long H(long x, long y, long z) { - return ((x ^ y ^ z)); - } - - static long I(long x, long y, long z) { - return ((y ^ (x | (~z)))); } - - static long AddUnsigned(long a, long b) { - long c = a + b; - return (c); - } - - static long FF(long a, long b, long c, long d, long x, int s, long ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); - return (AddUnsigned(RotateLeft(a, s), b)); - } - - static long GG(long a, long b, long c, long d, long x, int s, long ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); - return (AddUnsigned(RotateLeft(a, s), b)); - } - - static long HH(long a, long b, long c, long d, long x, int s, long ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); - return (AddUnsigned(RotateLeft(a, s), b)); - } - - static long II(long a, long b, long c, long d, long x, int s, long ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); - return (AddUnsigned(RotateLeft(a, s), b)); - } - - /** - * Implementation of right shift operation for unsigned int. - * See: http://www.cnblogs.com/niniwzw/archive/2009/12/04/1617130.html - */ - static long RotateLeft(long lValue, int iShiftBits) { - if (iShiftBits == 32) return (lValue); - long result = (lValue << iShiftBits) | (((lValue >> 1) & 0x7fffffff) >> (31 - iShiftBits)); - return (result); - } - - /** - * Assume: ArraySize(x) == 16. - */ - static void MD5Transform(long &a, long &b, long &c, long &d, int &x[]) { - long AA, BB, CC, DD; - int S11=7, S12=12, S13=17, S14=22; - int S21=5, S22=9 , S23=14, S24=20; - int S31=4, S32=11, S33=16, S34=23; - int S41=6, S42=10, S43=15, S44=21; - - AA=a; BB=b; CC=c; DD=d; - a=FF(a,b,c,d,x[0], S11, 0xD76AA478); - d=FF(d,a,b,c,x[1], S12, 0xE8C7B756); - c=FF(c,d,a,b,x[2], S13, 0x242070DB); - b=FF(b,c,d,a,x[3], S14, 0xC1BDCEEE); - a=FF(a,b,c,d,x[4], S11, 0xF57C0FAF); - d=FF(d,a,b,c,x[5], S12, 0x4787C62A); - c=FF(c,d,a,b,x[6], S13, 0xA8304613); - b=FF(b,c,d,a,x[7], S14, 0xFD469501); - a=FF(a,b,c,d,x[8], S11, 0x698098D8); - d=FF(d,a,b,c,x[9], S12, 0x8B44F7AF); - c=FF(c,d,a,b,x[10],S13, 0xFFFF5BB1); - b=FF(b,c,d,a,x[11],S14, 0x895CD7BE); - a=FF(a,b,c,d,x[12],S11, 0x6B901122); - d=FF(d,a,b,c,x[13],S12, 0xFD987193); - c=FF(c,d,a,b,x[14],S13, 0xA679438E); - b=FF(b,c,d,a,x[15],S14, 0x49B40821); - - a=GG(a,b,c,d,x[1], S21, 0xF61E2562); - d=GG(d,a,b,c,x[6], S22, 0xC040B340); - c=GG(c,d,a,b,x[11],S23, 0x265E5A51); - b=GG(b,c,d,a,x[0], S24, 0xE9B6C7AA); - a=GG(a,b,c,d,x[5], S21, 0xD62F105D); - d=GG(d,a,b,c,x[10],S22, 0x2441453); - c=GG(c,d,a,b,x[15],S23, 0xD8A1E681); - b=GG(b,c,d,a,x[4], S24, 0xE7D3FBC8); - a=GG(a,b,c,d,x[9], S21, 0x21E1CDE6); - d=GG(d,a,b,c,x[14],S22, 0xC33707D6); - c=GG(c,d,a,b,x[3], S23, 0xF4D50D87); - b=GG(b,c,d,a,x[8], S24, 0x455A14ED); - a=GG(a,b,c,d,x[13],S21, 0xA9E3E905); - d=GG(d,a,b,c,x[2], S22, 0xFCEFA3F8); - c=GG(c,d,a,b,x[7], S23, 0x676F02D9); - b=GG(b,c,d,a,x[12],S24, 0x8D2A4C8A); - - a=HH(a,b,c,d,x[5], S31, 0xFFFA3942); - d=HH(d,a,b,c,x[8], S32, 0x8771F681); - c=HH(c,d,a,b,x[11],S33, 0x6D9D6122); - b=HH(b,c,d,a,x[14],S34, 0xFDE5380C); - a=HH(a,b,c,d,x[1], S31, 0xA4BEEA44); - d=HH(d,a,b,c,x[4], S32, 0x4BDECFA9); - c=HH(c,d,a,b,x[7], S33, 0xF6BB4B60); - b=HH(b,c,d,a,x[10],S34, 0xBEBFBC70); - a=HH(a,b,c,d,x[13],S31, 0x289B7EC6); - d=HH(d,a,b,c,x[0], S32, 0xEAA127FA); - c=HH(c,d,a,b,x[3], S33, 0xD4EF3085); - b=HH(b,c,d,a,x[6], S34, 0x4881D05); - a=HH(a,b,c,d,x[9], S31, 0xD9D4D039); - d=HH(d,a,b,c,x[12],S32, 0xE6DB99E5); - c=HH(c,d,a,b,x[15],S33, 0x1FA27CF8); - b=HH(b,c,d,a,x[2], S34, 0xC4AC5665); - - a=II(a,b,c,d,x[0], S41, 0xF4292244); - d=II(d,a,b,c,x[7], S42, 0x432AFF97); - c=II(c,d,a,b,x[14],S43, 0xAB9423A7); - b=II(b,c,d,a,x[5], S44, 0xFC93A039); - a=II(a,b,c,d,x[12],S41, 0x655B59C3); - d=II(d,a,b,c,x[3], S42, 0x8F0CCC92); - c=II(c,d,a,b,x[10],S43, 0xFFEFF47D); - b=II(b,c,d,a,x[1], S44, 0x85845DD1); - a=II(a,b,c,d,x[8], S41, 0x6FA87E4F); - d=II(d,a,b,c,x[15],S42, 0xFE2CE6E0); - c=II(c,d,a,b,x[6], S43, 0xA3014314); - b=II(b,c,d,a,x[13],S44, 0x4E0811A1); - a=II(a,b,c,d,x[4], S41, 0xF7537E82); - d=II(d,a,b,c,x[11],S42, 0xBD3AF235); - c=II(c,d,a,b,x[2], S43, 0x2AD7D2BB); - b=II(b,c,d,a,x[9], S44, 0xEB86D391); - - a=AddUnsigned(a, AA); b=AddUnsigned(b, BB); - c=AddUnsigned(c, CC); d=AddUnsigned(d, DD); + last_char[k] = 0x80; + last[last_index] = ConvertBasic::CharToInt(last_char); + if (index >= 56) { + MD5Transform(a, b, c, d, last); + ArrayInitialize(last, 0); } + last[14] = len << 3; + last[15] = ((len >> 1) & 0x7fffffff) >> 28; + MD5Transform(a, b, c, d, last); + string result = StringFormat("%s%s%s%s", ConvertBasic::IntToHex(a), ConvertBasic::IntToHex(b), + ConvertBasic::IntToHex(c), ConvertBasic::IntToHex(d)); + return result; + } + + static long F(long x, long y, long z) { return ((x & y) | ((~x) & z)); } + + static long G(long x, long y, long z) { return ((x & z) | (y & (~z))); } + + static long H(long x, long y, long z) { return ((x ^ y ^ z)); } + + static long I(long x, long y, long z) { return ((y ^ (x | (~z)))); } + + static long AddUnsigned(long a, long b) { + long c = a + b; + return (c); + } + + static long FF(long a, long b, long c, long d, long x, int s, long ac) { + a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); + return (AddUnsigned(RotateLeft(a, s), b)); + } + + static long GG(long a, long b, long c, long d, long x, int s, long ac) { + a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); + return (AddUnsigned(RotateLeft(a, s), b)); + } + + static long HH(long a, long b, long c, long d, long x, int s, long ac) { + a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); + return (AddUnsigned(RotateLeft(a, s), b)); + } + + static long II(long a, long b, long c, long d, long x, int s, long ac) { + a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); + return (AddUnsigned(RotateLeft(a, s), b)); + } + + /** + * Implementation of right shift operation for unsigned int. + * See: http://www.cnblogs.com/niniwzw/archive/2009/12/04/1617130.html + */ + static long RotateLeft(long lValue, int iShiftBits) { + if (iShiftBits == 32) return (lValue); + long result = (lValue << iShiftBits) | (((lValue >> 1) & 0x7fffffff) >> (31 - iShiftBits)); + return (result); + } + + /** + * Assume: ArraySize(x) == 16. + */ + static void MD5Transform(long &a, long &b, long &c, long &d, int &x[]) { + long AA, BB, CC, DD; + int S11 = 7, S12 = 12, S13 = 17, S14 = 22; + int S21 = 5, S22 = 9, S23 = 14, S24 = 20; + int S31 = 4, S32 = 11, S33 = 16, S34 = 23; + int S41 = 6, S42 = 10, S43 = 15, S44 = 21; + + AA = a; + BB = b; + CC = c; + DD = d; + a = FF(a, b, c, d, x[0], S11, 0xD76AA478); + d = FF(d, a, b, c, x[1], S12, 0xE8C7B756); + c = FF(c, d, a, b, x[2], S13, 0x242070DB); + b = FF(b, c, d, a, x[3], S14, 0xC1BDCEEE); + a = FF(a, b, c, d, x[4], S11, 0xF57C0FAF); + d = FF(d, a, b, c, x[5], S12, 0x4787C62A); + c = FF(c, d, a, b, x[6], S13, 0xA8304613); + b = FF(b, c, d, a, x[7], S14, 0xFD469501); + a = FF(a, b, c, d, x[8], S11, 0x698098D8); + d = FF(d, a, b, c, x[9], S12, 0x8B44F7AF); + c = FF(c, d, a, b, x[10], S13, 0xFFFF5BB1); + b = FF(b, c, d, a, x[11], S14, 0x895CD7BE); + a = FF(a, b, c, d, x[12], S11, 0x6B901122); + d = FF(d, a, b, c, x[13], S12, 0xFD987193); + c = FF(c, d, a, b, x[14], S13, 0xA679438E); + b = FF(b, c, d, a, x[15], S14, 0x49B40821); + + a = GG(a, b, c, d, x[1], S21, 0xF61E2562); + d = GG(d, a, b, c, x[6], S22, 0xC040B340); + c = GG(c, d, a, b, x[11], S23, 0x265E5A51); + b = GG(b, c, d, a, x[0], S24, 0xE9B6C7AA); + a = GG(a, b, c, d, x[5], S21, 0xD62F105D); + d = GG(d, a, b, c, x[10], S22, 0x2441453); + c = GG(c, d, a, b, x[15], S23, 0xD8A1E681); + b = GG(b, c, d, a, x[4], S24, 0xE7D3FBC8); + a = GG(a, b, c, d, x[9], S21, 0x21E1CDE6); + d = GG(d, a, b, c, x[14], S22, 0xC33707D6); + c = GG(c, d, a, b, x[3], S23, 0xF4D50D87); + b = GG(b, c, d, a, x[8], S24, 0x455A14ED); + a = GG(a, b, c, d, x[13], S21, 0xA9E3E905); + d = GG(d, a, b, c, x[2], S22, 0xFCEFA3F8); + c = GG(c, d, a, b, x[7], S23, 0x676F02D9); + b = GG(b, c, d, a, x[12], S24, 0x8D2A4C8A); + + a = HH(a, b, c, d, x[5], S31, 0xFFFA3942); + d = HH(d, a, b, c, x[8], S32, 0x8771F681); + c = HH(c, d, a, b, x[11], S33, 0x6D9D6122); + b = HH(b, c, d, a, x[14], S34, 0xFDE5380C); + a = HH(a, b, c, d, x[1], S31, 0xA4BEEA44); + d = HH(d, a, b, c, x[4], S32, 0x4BDECFA9); + c = HH(c, d, a, b, x[7], S33, 0xF6BB4B60); + b = HH(b, c, d, a, x[10], S34, 0xBEBFBC70); + a = HH(a, b, c, d, x[13], S31, 0x289B7EC6); + d = HH(d, a, b, c, x[0], S32, 0xEAA127FA); + c = HH(c, d, a, b, x[3], S33, 0xD4EF3085); + b = HH(b, c, d, a, x[6], S34, 0x4881D05); + a = HH(a, b, c, d, x[9], S31, 0xD9D4D039); + d = HH(d, a, b, c, x[12], S32, 0xE6DB99E5); + c = HH(c, d, a, b, x[15], S33, 0x1FA27CF8); + b = HH(b, c, d, a, x[2], S34, 0xC4AC5665); + + a = II(a, b, c, d, x[0], S41, 0xF4292244); + d = II(d, a, b, c, x[7], S42, 0x432AFF97); + c = II(c, d, a, b, x[14], S43, 0xAB9423A7); + b = II(b, c, d, a, x[5], S44, 0xFC93A039); + a = II(a, b, c, d, x[12], S41, 0x655B59C3); + d = II(d, a, b, c, x[3], S42, 0x8F0CCC92); + c = II(c, d, a, b, x[10], S43, 0xFFEFF47D); + b = II(b, c, d, a, x[1], S44, 0x85845DD1); + a = II(a, b, c, d, x[8], S41, 0x6FA87E4F); + d = II(d, a, b, c, x[15], S42, 0xFE2CE6E0); + c = II(c, d, a, b, x[6], S43, 0xA3014314); + b = II(b, c, d, a, x[13], S44, 0x4E0811A1); + a = II(a, b, c, d, x[4], S41, 0xF7537E82); + d = II(d, a, b, c, x[11], S42, 0xBD3AF235); + c = II(c, d, a, b, x[2], S43, 0x2AD7D2BB); + b = II(b, c, d, a, x[9], S44, 0xEB86D391); + + a = AddUnsigned(a, AA); + b = AddUnsigned(b, BB); + c = AddUnsigned(c, CC); + d = AddUnsigned(d, DD); + } }; diff --git a/Platform.h b/Platform.h index 3993b4f98..c7db1f1a7 100644 --- a/Platform.h +++ b/Platform.h @@ -312,18 +312,6 @@ class Platform { } return _result; } - - /** - * Returns currently selected period for platform. - */ - static ENUM_TIMEFRAMES Period() { -#ifdef __MQL__ - return Period(); -#else - // @fixit Should fetch selected period from somewhere. - return PERIOD_M15; -#endif - } }; bool Platform::initialized = false; diff --git a/Serializer/Serializer.h b/Serializer/Serializer.h index ce544cf1a..01b4e2c61 100644 --- a/Serializer/Serializer.h +++ b/Serializer/Serializer.h @@ -25,7 +25,7 @@ #define SERIALIZER_MQH // Includes. -#include "../Convert.mqh" +#include "../Convert.basic.h" #include "../Terminal.define.h" #include "Serializer.define.h" #include "Serializer.enum.h" @@ -420,17 +420,17 @@ class Serializer { SerializerNodeParamType paramType = PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), GetType()); switch (paramType) { case SerializerNodeParamBool: - Convert::BoolToType(PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), _integral)._bool, value); + ConvertBasic::BoolToType(PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), _integral)._bool, value); break; case SerializerNodeParamLong: - Convert::LongToType(PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), _integral)._long, value); + ConvertBasic::LongToType(PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), _integral)._long, value); break; case SerializerNodeParamDouble: - Convert::DoubleToType(PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), _integral)._double, value); + ConvertBasic::DoubleToType(PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), _integral)._double, value); break; case SerializerNodeParamString: // There shouldn't be a conversion to int! - Convert::StringToType(PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), _string), value); + ConvertBasic::StringToType(PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), _string), value); break; default: Print("Error: Wrong param type ", paramType, "!"); diff --git a/Serializer/tests/Serializer.test.mq5 b/Serializer/tests/Serializer.test.mq5 index dd895f13e..a1edb66c1 100644 --- a/Serializer/tests/Serializer.test.mq5 +++ b/Serializer/tests/Serializer.test.mq5 @@ -32,6 +32,7 @@ #include "../../Config.mqh" #include "../../Data.define.h" #include "../../Data.struct.h" +#include "../../Data.struct.serialize.h" #include "../../DictStruct.mqh" #include "../../Test.mqh" #include "../Serializer.h" diff --git a/Std.h b/Std.h index a680db7d2..76ed66e47 100644 --- a/Std.h +++ b/Std.h @@ -298,3 +298,13 @@ inline _NULL_VALUE::operator const std::string() const { #else #define NULL_VALUE NULL #endif + +#ifndef __MQL__ +#include "Chart.enum.h" +/** + * Returns currently selected period for platform. + */ +// @fixit Should fetch selected period from somewhere. +extern ENUM_TIMEFRAMES Period(); + +#endif diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index a61e5a6a7..72bb18844 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -26,7 +26,6 @@ #endif #include "MQL5.mqh" -#include "Math.h" #include "Order.enum.h" #include "Std.h" #include "Tick/Tick.struct.h" diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 173ae3bef..3d93591a2 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -31,10 +31,14 @@ // Includes. #include "../Data.struct.h" +#include "../Serializer/Serializer.define.h" #include "../Std.h" #include "../Terminal.define.h" #include "Task.enum.h" +// Forward declarations. +class Serializer; + /* Entry for TaskAction class. */ struct TaskActionEntry { public: @@ -182,15 +186,7 @@ struct TaskActionEntry { ::ArrayResize(args, _index - 1); } // Serializers - SerializerNodeType Serialize(Serializer &s) { - s.Pass(THIS_REF, "flags", flags); - s.Pass(THIS_REF, "id", id); - s.Pass(THIS_REF, "time_last_run", time_last_run); - s.Pass(THIS_REF, "tries", tries); - s.PassEnum(THIS_REF, "freq", freq); - s.PassArray(THIS_REF, "args", args); - return SerializerNodeObject; - } + SerializerNodeType Serialize(Serializer &s); SERIALIZER_EMPTY_STUB; }; diff --git a/Task/TaskAction.struct.serialize.h b/Task/TaskAction.struct.serialize.h new file mode 100644 index 000000000..54d0fc39e --- /dev/null +++ b/Task/TaskAction.struct.serialize.h @@ -0,0 +1,44 @@ +//+------------------------------------------------------------------+ +//| 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 TaskAction's structure serialization methods. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Serializer/Serializer.h" +#include "TaskAction.struct.h" + +SerializerNodeType TaskActionEntry::Serialize(Serializer &s) { + s.Pass(THIS_REF, "flags", flags); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "time_last_run", time_last_run); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); + s.PassArray(THIS_REF, "args", args); + return SerializerNodeObject; +} diff --git a/Task/TaskCondition.struct.serialize.h b/Task/TaskCondition.struct.serialize.h index 9b6a0afea..36385b572 100644 --- a/Task/TaskCondition.struct.serialize.h +++ b/Task/TaskCondition.struct.serialize.h @@ -41,4 +41,4 @@ SerializerNodeType TaskConditionEntry::Serialize(Serializer &s) { s.PassEnum(THIS_REF, "freq", freq); s.PassArray(THIS_REF, "args", args); return SerializerNodeObject; -} \ No newline at end of file +} diff --git a/Task/TaskGetter.struct.h b/Task/TaskGetter.struct.h index 8177d8e04..78292144c 100644 --- a/Task/TaskGetter.struct.h +++ b/Task/TaskGetter.struct.h @@ -31,6 +31,7 @@ // Includes. #include "../Data.struct.h" +#include "../Serializer/Serializer.define.h" #include "../Std.h" #include "../Terminal.define.h" #include "Task.enum.h" @@ -169,15 +170,7 @@ struct TaskGetterEntry { // @todo: for(). } // Serializers - SerializerNodeType Serialize(Serializer &s) { - s.Pass(THIS_REF, "flags", flags); - s.Pass(THIS_REF, "id", id); - s.Pass(THIS_REF, "time_last_get", time_last_get); - s.Pass(THIS_REF, "tries", tries); - s.PassEnum(THIS_REF, "freq", freq); - s.PassArray(THIS_REF, "args", args); - return SerializerNodeObject; - } + SerializerNodeType Serialize(Serializer &s); SERIALIZER_EMPTY_STUB; }; diff --git a/Task/TaskGetter.struct.serialize.h b/Task/TaskGetter.struct.serialize.h new file mode 100644 index 000000000..6afcaa1ac --- /dev/null +++ b/Task/TaskGetter.struct.serialize.h @@ -0,0 +1,44 @@ +//+------------------------------------------------------------------+ +//| 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 TaskGetter's structure serialization methods. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Serializer/Serializer.h" +#include "TaskGetter.struct.h" + +SerializerNodeType TaskGetterEntry::Serialize(Serializer &s) { + s.Pass(THIS_REF, "flags", flags); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "time_last_get", time_last_get); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); + s.PassArray(THIS_REF, "args", args); + return SerializerNodeObject; +} diff --git a/Task/TaskSetter.struct.h b/Task/TaskSetter.struct.h index 35ac5db24..86efff237 100644 --- a/Task/TaskSetter.struct.h +++ b/Task/TaskSetter.struct.h @@ -31,6 +31,7 @@ // Includes. #include "../Data.struct.h" +#include "../Serializer/Serializer.h" #include "../Std.h" #include "Task.enum.h" diff --git a/Task/tests/TaskManager.test.mq5 b/Task/tests/TaskManager.test.mq5 index 4ade617b8..58271b300 100644 --- a/Task/tests/TaskManager.test.mq5 +++ b/Task/tests/TaskManager.test.mq5 @@ -28,7 +28,10 @@ struct DataParamEntry; // Includes. +#include "../../Data.struct.serialize.h" #include "../../Test.mqh" +#include "../TaskAction.struct.serialize.h" +#include "../TaskCondition.struct.serialize.h" #include "../TaskManager.h" // Define test classes. diff --git a/tests/BufferStructTest.mq5 b/tests/BufferStructTest.mq5 index 8e5b7cc6e..4a5f19c7a 100644 --- a/tests/BufferStructTest.mq5 +++ b/tests/BufferStructTest.mq5 @@ -28,6 +28,7 @@ #include "../BufferStruct.mqh" #include "../Data.define.h" #include "../Data.struct.h" +#include "../Data.struct.serialize.h" #include "../Serializer/SerializerConverter.h" #include "../Serializer/SerializerJSON.h" #include "../Std.h" diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 8afce59d5..1b96d9b5c 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -98,10 +98,6 @@ void OnTick() { IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); if (_candles PTR_DEREF IsNewBar()) { - if (_candles PTR_DEREF GetBarIndex() < 500) { - return; - } - if (_candles PTR_DEREF GetBarIndex() > 550) { ExpertRemove(); } From 5d9031fead3d116714589efa9b20e0eda431ebad Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 14 Nov 2022 18:45:00 +0100 Subject: [PATCH 045/123] WIP. Added rates_total validation for all the indicators in `Indicators` folder. --- Indicators/Indi_AMA.mqh | 1 + Indicators/Indi_ASI.mqh | 9 +++++++-- Indicators/Indi_BWZT.mqh | 15 ++++++++++----- Indicators/Indi_Bands.mqh | 3 +++ Indicators/Indi_CCI.mqh | 7 ++----- Indicators/Indi_CHO.mqh | 8 +++++++- Indicators/Indi_CHV.mqh | 1 + Indicators/Indi_DEMA.mqh | 1 + Indicators/Indi_FractalAdaptiveMA.mqh | 2 ++ Indicators/Indi_MassIndex.mqh | 1 + Indicators/Indi_PriceChannel.mqh | 1 + Indicators/Indi_PriceVolumeTrend.mqh | 7 ++++++- Indicators/Indi_RateOfChange.mqh | 1 + Indicators/Indi_TEMA.mqh | 1 + Indicators/Indi_TRIX.mqh | 1 + Indicators/Indi_VIDYA.mqh | 1 + Indicators/Indi_VROC.mqh | 1 + Indicators/Indi_Volumes.mqh | 7 ++++++- Indicators/Indi_WilliamsAD.mqh | 7 ++++++- Indicators/Indi_ZigZag.mqh | 7 ++++++- Indicators/Indi_ZigZagColor.mqh | 7 ++++++- 21 files changed, 71 insertions(+), 18 deletions(-) diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index cd2917e13..76daa7318 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -135,6 +135,7 @@ class Indi_AMA : public Indicator { */ 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) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _ama_period); 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, diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index 513ecd2aa..a7c8a3fd8 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -25,6 +25,10 @@ #include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" +// Defines. +// 2 bars was originally specified by Accumulative Swing Index algorithm. +#define INDI_ASI_MIN_BARS 2 + // Structs. struct IndiASIParams : IndicatorParams { unsigned int period; @@ -38,7 +42,7 @@ struct IndiASIParams : IndicatorParams { }; /** - * Implements the Bill Williams' Accelerator/Decelerator oscillator. + * Implements the Accumulative Swing Index indicator. */ class Indi_ASI : public Indicator { protected: @@ -101,6 +105,7 @@ class Indi_ASI : public Indicator { * OnCalculate-based version of ASI as there is no built-in one. */ static double iASI(IndicatorData *_indi, double _mpc, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, INDI_ASI_MIN_BARS); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_mpc)); return iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mpc, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); @@ -154,7 +159,7 @@ class Indi_ASI : public Indicator { CalculateInit(InpT, ExtTpoints, ExtT); - if (rates_total < 2) return (0); + if (rates_total < INDI_ASI_MIN_BARS) return (0); // Start calculation. int pos = prev_calculated - 1; // Correct position, when it's first iteration. diff --git a/Indicators/Indi_BWZT.mqh b/Indicators/Indi_BWZT.mqh index 3992e83c0..1edb82064 100644 --- a/Indicators/Indi_BWZT.mqh +++ b/Indicators/Indi_BWZT.mqh @@ -20,6 +20,10 @@ * */ +// Defines. +// 38 bars (DATA_LIMIT) was originally specified by Indicators/Examples/BW-ZoneTrade.mq5 +#define INDI_BWZT_DATA_LIMIT 100 + // Includes. #include "../BufferStruct.mqh" #include "../Indicator/IndicatorTf.h" @@ -128,13 +132,13 @@ class Indi_BWZT : public Indicator { Indi_AO *_indi_ao = Indi_AO::GetCached(_indi); return iBWZTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), - _cache, _indi_ac, _indi_ao); + INDI_BWZT_DATA_LIMIT, _cache, _indi_ac, _indi_ao); } /** * Calculates BWZT on the array of values. */ - static double iBWZTOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _abs_shift, + static double iBWZTOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _abs_shift, int _data_limit, IndicatorCalculateCache *_cache, Indi_AC *_indi_ac, Indi_AO *_indi_ao, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -150,7 +154,7 @@ class Indi_BWZT : public Indicator { _cache.SetPrevCalculated(Indi_BWZT::Calculate( INDICATOR_CALCULATE_GET_PARAMS_LONG, _cache.GetBuffer(0), _cache.GetBuffer(1), _cache.GetBuffer(2), _cache.GetBuffer(3), _cache.GetBuffer(4), - _cache.GetBuffer(5), _cache.GetBuffer(6), 38, _indi_ac, _indi_ao)); + _cache.GetBuffer(5), _cache.GetBuffer(6), _data_limit, _indi_ac, _indi_ao)); return _cache.GetTailValue(_mode, _abs_shift); } @@ -159,14 +163,15 @@ class Indi_BWZT : public Indicator { * On-indicator version of BWZT. */ static double iBWZTOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode, int _rel_shift, - IndicatorData *_obj) { + int _data_limit, IndicatorData *_obj) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _data_limit); 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); return iBWZTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), - _cache, _indi_ac, _indi_ao); + _data_limit, _cache, _indi_ac, _indi_ao); } /** diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index 2cca5b497..d3caadf02 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -138,12 +138,15 @@ class Indi_Bands : public Indicator { /** * Calculates Bands on another indicator. + * + * Note that "_bands_shift" is used only for drawing. */ static double iBandsOnIndicator(IndicatorData *_indi, 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 _rel_shift) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_indi, _ap, Util::MakeKey(_period, _deviation, _bands_shift, (int)_ap)); return iBandsOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _deviation, _bands_shift, _mode, diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index 689149c57..70a2e28fd 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -100,12 +100,9 @@ class Indi_CCI : public Indicator { static double iCCIOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, int _mode, int _shift = 0) { - _indi.ValidateDataSourceMode(_mode); + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period); - if (_indi.GetBars() < (int)_period) { - // No enough bars. - return DBL_MAX; - } + _indi.ValidateDataSourceMode(_mode); double _indi_value_buffer[]; IndicatorDataEntry _entry(_indi.GetModeCount()); diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index f6e910916..e3431717f 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -20,6 +20,10 @@ * */ +// Defines. +// 2 bars was originally specified by Indicators/Examples/CHO.mq5 +#define INDI_CHO_MIN_BARS 2 + // Includes. #include "../BufferStruct.mqh" #include "../Indicator/Indicator.h" @@ -93,6 +97,7 @@ class Indi_CHO : public Indicator { DebugBreak(); return 0; } + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_obj, INDI_CHO_MIN_BARS); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( _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, @@ -128,6 +133,7 @@ class Indi_CHO : public Indicator { */ 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) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, INDI_CHO_MIN_BARS); 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, @@ -144,7 +150,7 @@ class Indi_CHO : public Indicator { if (rates_total < InpSlowMA) return (0); // Preliminary calculations. int i, start; - if (prev_calculated < 2) + if (prev_calculated < INDI_CHO_MIN_BARS) start = 0; else start = prev_calculated - 2; diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index 7a3920e32..71f7c52ed 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -95,6 +95,7 @@ class Indi_CHV : public Indicator { */ double iCHV(IndicatorData *_indi, int _smooth_period, int _chv_period, ENUM_CHV_SMOOTH_METHOD _smooth_method, int _mode = 0, int _shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _chv_period + _smooth_period - 2); 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, diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index cfa4c7a30..982129c39 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -150,6 +150,7 @@ class Indi_DEMA : public Indicator { */ static double iDEMAOnIndicator(IndicatorData *_indi, int _period, int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, 2 * _period - 1); 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, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index a3320c2fa..5ddbed457 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -103,6 +103,7 @@ class Indi_FrAMA : public Indicator { DebugBreak(); return 0; } + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_obj, 2 * _ma_period); 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, _obj PTR_DEREF ToAbsShift(_rel_shift), _cache); @@ -136,6 +137,7 @@ class Indi_FrAMA : public Indicator { */ static double iFrAMAOnIndicator(IndicatorData *_indi, int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, 2 * _ma_period); 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, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index f13f1d5b3..fd3e40031 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -88,6 +88,7 @@ class Indi_MassIndex : public Indicator { */ static double iMI(IndicatorData *_indi, int _period, int _second_period, int _sum_period, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _sum_period + _period + _second_period - 3); 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, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index 26b064cb5..1873a01c0 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -80,6 +80,7 @@ class Indi_PriceChannel : public Indicator { * 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 _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_period)); return iPriceChannelOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index e49ed2dd5..4e79ad17f 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -20,6 +20,10 @@ * */ +// Defines. +// 100 bars was originally specified by Indicators/Examples/PVT.mq5 +#define INDI_PVT_MIN_BARS 2 + // Includes. #include "../BufferStruct.mqh" #include "../Indicator/Indicator.h" @@ -71,6 +75,7 @@ class Indi_PriceVolumeTrend : public Indicator { * OnCalculate-based version of Price Volume Trend as there is no built-in one. */ static double iPVT(IndicatorData *_indi, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, INDI_PVT_MIN_BARS); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey((int)_av)); return iPVTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); @@ -111,7 +116,7 @@ class Indi_PriceVolumeTrend : public Indicator { */ static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &ExtPVTBuffer, ENUM_APPLIED_VOLUME InpVolumeType) { - if (rates_total < 2) return (0); + if (rates_total < INDI_PVT_MIN_BARS) return (0); int pos = prev_calculated - 1; // Correct position, when it's first iteration. if (pos < 0) { diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index 4e2d59ecf..f1f36c8ea 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -101,6 +101,7 @@ class Indi_RateOfChange : public Indicator { */ static double iROCOnIndicator(IndicatorData *_indi, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_indi, _ap, Util::MakeKey(_period, (int)_ap)); return iROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index bf03f48c8..cd380ea24 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -118,6 +118,7 @@ class Indi_TEMA : public Indicator { */ static double iTEMAOnIndicator(IndicatorData *_indi, int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, 3 * _ma_period - 3); 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, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index 5dd0c530e..64c55f57e 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -116,6 +116,7 @@ class Indi_TRIX : public Indicator { */ static double iTriXOnIndicator(IndicatorData *_indi, int _ma_period, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, 3 * _ma_period - 3); 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, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index 572ec70c9..8e13b4c27 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -122,6 +122,7 @@ class Indi_VIDYA : public Indicator { 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 _rel_shift = 0, IndicatorData *_obj = NULL) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _ema_period + _cmo_period - 1); 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, diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index 42c9226c3..107acf62e 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -83,6 +83,7 @@ class Indi_VROC : public 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 _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _period); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_period, (int)_av)); return iVROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _av, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index 059fe7533..fbc34f163 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -20,6 +20,10 @@ * */ +// Defines. +// 2 bars was originally specified by Indicators/Examples/Volumes.mq5 +#define INDI_VOLUMES_MIN_BARS 2 + // Includes. #include "../BufferStruct.mqh" #include "../Indicator/Indicator.h" @@ -82,6 +86,7 @@ class Indi_Volumes : public 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 _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, INDI_VOLUMES_MIN_BARS); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey((int)_av)); return iVolumesOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); @@ -113,7 +118,7 @@ class Indi_Volumes : public Indicator { */ static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &ExtVolumesBuffer, ValueStorage &ExtColorsBuffer, ENUM_APPLIED_VOLUME InpVolumeType) { - if (rates_total < 2) return (0); + if (rates_total < INDI_VOLUMES_MIN_BARS) return (0); // Starting work. int pos = prev_calculated - 1; diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index 43d107f70..c95a8c9e7 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -20,6 +20,10 @@ * */ +// Defines. +// 2 bars was originally specified by Indicators/Examples/W_AD.mq5 +#define INDI_WAD_MIN_BARS 100 + // Includes. #include "../BufferStruct.mqh" #include "../Indicator/Indicator.h" @@ -80,6 +84,7 @@ class Indi_WilliamsAD : public Indicator { * OnCalculate-based version of Williams' AD as there is no built-in one. */ static double iWAD(IndicatorData *_indi, int _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, INDI_WAD_MIN_BARS); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, ""); return iWADOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); @@ -110,7 +115,7 @@ class Indi_WilliamsAD : public Indicator { * OnCalculate() method for Williams' AD indicator. */ static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &ExtWADBuffer) { - if (rates_total < 2) return (0); + if (rates_total < INDI_WAD_MIN_BARS) return (0); int pos = prev_calculated - 1; if (pos < 1) { pos = 1; diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index f5910638d..fcb56a4d2 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -20,6 +20,10 @@ * */ +// Defines. +// 100 bars was originally specified by Indicators/Examples/ZigZag.mq5 +#define INDI_ZIGZAG_MIN_BARS 100 + // Includes. #include "../Indicator/Indicator.h" #include "../Storage/ValueStorage.all.h" @@ -147,6 +151,7 @@ class Indi_ZigZag : public Indicator { */ static double iZigZag(IndicatorData *_indi, int _depth, int _deviation, int _backstep, ENUM_ZIGZAG_LINE _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, INDI_ZIGZAG_MIN_BARS); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_depth, _deviation, _backstep)); return iZigZagOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); @@ -182,7 +187,7 @@ class Indi_ZigZag : public Indicator { int InpDeviation, int InpBackstep) { int ExtRecalc = 3; - if (rates_total < 100) return (0); + if (rates_total < INDI_ZIGZAG_MIN_BARS) return (0); //--- int i = 0; int start = 0, extreme_counter = 0, extreme_search = Extremum; diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 436f1963f..d0fcc7925 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -20,6 +20,10 @@ * */ +// Defines. +// 100 bars was originally specified by Indicators/Examples/ZigzagColor.mq5 +#define INDI_ZIGZAG_COLOR_MIN_BARS 100 + // Includes. #include "../BufferStruct.mqh" #include "../Indicator/Indicator.h" @@ -94,6 +98,7 @@ class Indi_ZigZagColor : public Indicator { */ static double iZigZagColor(IndicatorData *_indi, int _depth, int _deviation, int _backstep, ENUM_ZIGZAG_LINE _mode = 0, int _rel_shift = 0) { + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, INDI_ZIGZAG_COLOR_MIN_BARS); INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_indi, Util::MakeKey(_depth, _deviation, _backstep)); return iZigZagColorOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, _indi PTR_DEREF ToAbsShift(_rel_shift), _cache); @@ -132,7 +137,7 @@ class Indi_ZigZagColor : public Indicator { int InpDeviation, int InpBackstep) { int ExtRecalc = 3; - if (rates_total < 100) return 0; + if (rates_total < INDI_ZIGZAG_COLOR_MIN_BARS) return 0; int i, start = 0; int extreme_counter = 0, extreme_search = Extremum; int shift, back = 0, last_high_pos = 0, last_low_pos = 0; From 5287625b0802d25cacf0e0db1207ed0a6d31dfc6 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 17 Nov 2022 19:29:42 +0100 Subject: [PATCH 046/123] WIP. Writing stubs/most important methods' implementations for Emscripten. --- Array.extern.h | 48 +++++-- Common.extern.h | 10 +- Convert.mqh | 2 + DateTime.entry.h | 171 +++++++++++++++++++++++++ DateTime.extern.h | 33 +++-- DateTime.mqh | 19 ++- DateTime.static.h | 207 +++++++++++++++++++++++++++++++ DateTime.struct.h | 309 ---------------------------------------------- Math.extern.h | 52 ++++++-- PlatformTime.h | 89 +++++++++++++ Std.h | 10 ++ String.extern.h | 35 ++++-- 12 files changed, 628 insertions(+), 357 deletions(-) create mode 100644 DateTime.entry.h create mode 100644 DateTime.static.h create mode 100644 PlatformTime.h diff --git a/Array.extern.h b/Array.extern.h index 4b6580d4d..f95f26d3c 100644 --- a/Array.extern.h +++ b/Array.extern.h @@ -24,36 +24,64 @@ #ifndef __MQL__ #pragma once +#include "Common.extern.h" #include "Std.h" +#include "String.extern.h" template -extern int ArraySize(const ARRAY_REF(T, _array)); +int ArraySize(const ARRAY_REF(T, _array)) { + return _array.size(); +} template -extern constexpr int ArraySize(const T REF(_array)[size]); +constexpr int ArraySize(const T REF(_array)[size]); template -extern int ArrayResize(ARRAY_REF(T, _array), int _new_size, int _reserve_size = 0); +int ArrayResize(ARRAY_REF(T, _array), int _new_size, int _reserve_size = 0) { + _array.resize(_new_size, _reserve_size); + return _new_size; +} template -extern bool ArraySetAsSeries(ARRAY_REF(T, _array), bool _flag); +bool ArraySetAsSeries(ARRAY_REF(T, _array), bool _flag) { + _array.setIsSeries(_flag); + return true; +} template -extern int ArrayMaximum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY); +int ArrayMaximum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} template -extern int ArrayMinimum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY); +int ArrayMinimum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} template -extern int ArrayFree(const ARRAY_REF(T, _array)); +int ArrayFree(ARRAY_REF(T, _array)) { + _array.resize(0, 0); + return 0; +} template -extern int ArrayReverse(const ARRAY_REF(T, _array)); +bool ArrayReverse(ARRAY_REF(T, _array)) { + _array.reverse(); + return true; +} template -extern int ArrayInitialize(ARRAY_REF(T, array), char value); +extern int ArrayInitialize(ARRAY_REF(T, array), char value) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} template -extern int ArraySort(ARRAY_REF(T, array)); +extern int ArraySort(ARRAY_REF(T, array)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} #endif diff --git a/Common.extern.h b/Common.extern.h index 03a90a139..3f6a5a840 100644 --- a/Common.extern.h +++ b/Common.extern.h @@ -23,12 +23,18 @@ // Define external global functions. #ifndef __MQL__ #pragma once +#include + #include "Chart.enum.h" #include "DateTime.enum.h" +#include "Terminal.define.h" + +void DebugBreak() { raise(SIGTRAP); } + +int _LastError = 0; -extern void DebugBreak(); // Errors. -extern void SetUserError(unsigned short user_error); +void SetUserError(unsigned short user_error) { _LastError = ERR_USER_ERROR_FIRST + user_error; } // Exceptions. extern int NotImplementedException(); // Print-related functions. diff --git a/Convert.mqh b/Convert.mqh index b371eeeca..dbc15b87c 100644 --- a/Convert.mqh +++ b/Convert.mqh @@ -30,6 +30,8 @@ #include "Account/Account.extern.h" #include "Array.mqh" #include "Convert.extern.h" +#include "DateTime.extern.h" +#include "DateTime.mqh" #include "Math.extern.h" #include "Order.enum.h" #include "SymbolInfo.enum.h" diff --git a/DateTime.entry.h b/DateTime.entry.h new file mode 100644 index 000000000..c99d8d27f --- /dev/null +++ b/DateTime.entry.h @@ -0,0 +1,171 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes DateTime's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "DateTime.static.h" +#include "PlatformTime.h" + +struct DateTimeEntry : MqlDateTime { + int week_of_year; + // Struct constructors. + DateTimeEntry() { Set(); } + DateTimeEntry(datetime _dt) { Set(_dt); } + DateTimeEntry(MqlDateTime& _dt) { + Set(_dt); +#ifndef __MQL__ + throw NotImplementedException(); +#endif + } + // Getters. + int GetDayOfMonth() { return day; } + int GetDayOfWeek() { + // Returns the zero-based day of week. + // (0-Sunday, 1-Monday, ... , 6-Saturday). + return day_of_week; + } + int GetDayOfYear() { return day_of_year + 1; } // Zero-based day of year (1st Jan = 0). + int GetHour() { return hour; } + int GetMinute() { return min; } + int GetMonth() { return mon; } + int GetSeconds() { return sec; } + // int GetWeekOfYear() { return week_of_year; } // @todo + int GetValue(ENUM_DATETIME_UNIT _unit) { + int _result = -1; + switch (_unit) { + case DATETIME_SECOND: + return GetSeconds(); + case DATETIME_MINUTE: + return GetMinute(); + case DATETIME_HOUR: + return GetHour(); + case DATETIME_DAY: + return GetDayOfMonth(); + case DATETIME_WEEK: + return -1; // return WeekOfYear(); // @todo + case DATETIME_MONTH: + return GetMonth(); + case DATETIME_YEAR: + return GetYear(); + default: + break; + } + return _result; + } + unsigned int GetValue(unsigned int _unit) { + if ((_unit & (DATETIME_DAY | DATETIME_WEEK)) != 0) { + return GetDayOfWeek(); + } else if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { + return GetDayOfMonth(); + } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { + return GetDayOfYear(); + } + return GetValue((ENUM_DATETIME_UNIT)_unit); + } + int GetYear() { return year; } + datetime GetTimestamp() { return StructToTime(THIS_REF); } + // Setters. + void Set() { + TimeToStruct(PlatformTime::CurrentTimestamp(), THIS_REF); + // @fixit Should also set day of week. + } + void SetGMT() { + TimeToStruct(::TimeGMT(), THIS_REF); + // @fixit Should also set day of week. + } + // Set date and time. + void Set(datetime _time) { + TimeToStruct(_time, THIS_REF); + // @fixit Should also set day of week. + } + // Set date and time. + void Set(MqlDateTime& _time) { + THIS_REF = _time; + // @fixit Should also set day of week. + } + void SetDayOfMonth(int _value) { + day = _value; + day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. + day_of_year = DateTimeStatic::DayOfYear(); // Zero-based day of year. + } + void SetDayOfYear(int _value) { + day_of_year = _value - 1; // Sets zero-based day of year. + day = DateTimeStatic::Month(); // Sets day of month (1..31). + day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. + } + void SetHour(int _value) { hour = _value; } + void SetMinute(int _value) { min = _value; } + void SetMonth(int _value) { mon = _value; } + void SetSeconds(int _value) { sec = _value; } + void SetWeekOfYear(int _value) { + week_of_year = _value; + // day = @todo; + // day_of_week = @todo; + // day_of_year = @todo; + } + void SetValue(ENUM_DATETIME_UNIT _unit, int _value) { + switch (_unit) { + case DATETIME_SECOND: + SetSeconds(_value); + break; + case DATETIME_MINUTE: + SetMinute(_value); + break; + case DATETIME_HOUR: + SetHour(_value); + break; + case DATETIME_DAY: + SetDayOfMonth(_value); + break; + case DATETIME_WEEK: + SetWeekOfYear(_value); + break; + case DATETIME_MONTH: + SetMonth(_value); + break; + case DATETIME_YEAR: + SetYear(_value); + break; + default: + break; + } + } + void SetValue(unsigned short _unit, int _value) { + if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { + SetDayOfMonth(_value); + } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { + SetDayOfYear(_value); + } else { + SetValue((ENUM_DATETIME_UNIT)_unit, _value); + } + } + void SetYear(int _value) { year = _value; } +}; diff --git a/DateTime.extern.h b/DateTime.extern.h index e3dee2b4f..0ece67d69 100644 --- a/DateTime.extern.h +++ b/DateTime.extern.h @@ -42,21 +42,18 @@ class datetime { time_t dt; public: - datetime(); - datetime(const long& _time); + datetime() { dt = 0; } + datetime(const long& _time) { dt = _time; } datetime(const int& _time); - bool operator==(const int _time) const; - bool operator==(const datetime& _time) const; - bool operator<(const int _time) const; - bool operator>(const int _time) const; - bool operator<(const datetime& _time); - bool operator>(const datetime& _time); - operator long() const; + bool operator==(const int _time) const = delete; + bool operator==(const datetime& _time) const { return dt == _time; } + bool operator<(const int _time) const = delete; + bool operator>(const int _time) const = delete; + bool operator<(const datetime& _time) const { return dt < _time; } + bool operator>(const datetime& _time) const { return dt > _time; } + operator long() const { return dt; } }; -extern datetime TimeCurrent(); -extern datetime TimeCurrent(MqlDateTime& dt_struct); - extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(datetime, time_array)); @@ -73,10 +70,20 @@ extern datetime TimeGMT(MqlDateTime& dt_struct); extern datetime TimeTradeServer(); extern datetime TimeTradeServer(MqlDateTime& dt_struct); extern datetime StringToTime(const string& value); -extern string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES); +string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES) { + /* + auto now = std::chrono::time_point(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); + */ + std::stringstream ss; + ss << __FUNCTION__ << " is not yet implemented!"; + // ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X"); + return ss.str(); +} template extern datetime operator"" _D(); #define DATETIME_LITERAL(STR) _D " ## STR ## " + #endif diff --git a/DateTime.mqh b/DateTime.mqh index df9fc38a3..2f9e1fa30 100644 --- a/DateTime.mqh +++ b/DateTime.mqh @@ -39,9 +39,12 @@ struct DataParamEntry; // Includes class enum and structs. #include "Array.mqh" #include "Data.struct.h" +#include "DateTime.entry.h" #include "DateTime.enum.h" #include "DateTime.extern.h" +#include "DateTime.static.h" #include "DateTime.struct.h" +#include "PlatformTime.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compatibility). @@ -61,7 +64,7 @@ class DateTime { /** * Class constructor. */ - DateTime() { TimeToStruct(TimeCurrent(), dt_curr); } + DateTime() { TimeToStruct(PlatformTime::CurrentTimestamp(), dt_curr); } DateTime(DateTime &r) : dt_curr(r.dt_curr), dt_last(r.dt_last) {} DateTime(DateTimeEntry &_dt) { dt_curr = _dt; } DateTime(MqlDateTime &_dt) { dt_curr = _dt; } @@ -198,7 +201,7 @@ class DateTime { /** * Updates datetime to the current one. */ - void Update() { dt_curr.Set(TimeCurrent()); } + void Update() { dt_curr.Set(PlatformTime::CurrentTimestamp()); } /* Conditions */ @@ -238,4 +241,16 @@ class DateTime { return DateTime::CheckCondition(_cond, _args); } }; + +#ifndef __MQL__ + +datetime TimeCurrent() { return PlatformTime::CurrentTimestamp(); } + +datetime TimeCurrent(MqlDateTime &dt_struct) { + dt_struct = PlatformTime::CurrentTime(); + return PlatformTime::CurrentTimestamp(); +} + +#endif + #endif // DATETIME_MQH diff --git a/DateTime.static.h b/DateTime.static.h new file mode 100644 index 000000000..1b5950128 --- /dev/null +++ b/DateTime.static.h @@ -0,0 +1,207 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes DateTime's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "DateTime.static.h" +#include "PlatformTime.h" + +/* + * Struct to provide static date and time methods. + */ +struct DateTimeStatic { + /** + * Returns the current day of the month (e.g. the day of month of the last known server time). + */ + static int Day(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::TimeDay(dt); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.day; +#endif + } + + /** + * Returns the current zero-based day of the week of the last known server time. + */ + static int DayOfWeek(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::DayOfWeek(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.day_of_week; +#endif + } + + /** + * Returns the current day of the year (e.g. the day of year of the last known server time). + */ + static int DayOfYear(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::DayOfYear(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.day_of_year + 1; +#endif + } + + /** + * Returns the hour of the last known server time by the moment of the program start. + */ + static int Hour(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Hour(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.hour; +#endif + } + + /** + * Check whether market is within peak hours. + */ + static bool IsPeakHour() { + MqlDateTime dt; + TimeToStruct(::TimeGMT(), dt); + return dt.hour >= 8 && dt.hour <= 16; + } + + /** + * Returns the current minute of the last known server time by the moment of the program start. + */ + static int Minute(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Minute(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.min; +#endif + } + + /** + * Returns the current month as number (e.g. the number of month of the last known server time). + */ + static int Month(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Month(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.mon; +#endif + } + + /** + * Returns the amount of seconds elapsed from the beginning of the current minute of the last known server time. + */ + static int Seconds(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Seconds(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.sec; +#endif + } + + /** + * Converts a time stamp into a string of "yyyy.mm.dd hh:mi" format. + */ + static string TimeToStr(datetime value, int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { +#ifdef __MQL4__ + return ::TimeToStr(value, mode); +#else // __MQL5__ + // #define TimeToStr(value, mode) DateTime::TimeToStr(value, mode) + return ::TimeToString(value, mode); +#endif + } + static string TimeToStr(int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { + return TimeToStr(PlatformTime::CurrentTimestamp(), mode); + } + + /** + * Returns the current time of the trade server. + */ + static datetime TimeTradeServer() { +#ifdef __MQL4__ + // Unlike MQL5 TimeTradeServer(), + // TimeCurrent() returns the last known server time. + return ::TimeCurrent(); +#else + // The calculation of the time value is performed in the client terminal + // and depends on the time settings of your computer. + return ::TimeTradeServer(); +#endif + } + + /** + * Returns the current year (e.g. the year of the last known server time). + */ + static int Year(datetime dt = 0) { + if (dt == (datetime)0) { + dt = PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Year(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.year; +#endif + } +}; diff --git a/DateTime.struct.h b/DateTime.struct.h index c03391a23..f33543193 100644 --- a/DateTime.struct.h +++ b/DateTime.struct.h @@ -30,9 +30,6 @@ #pragma once #endif -// Forward declarations. -struct DateTimeStatic; - // Includes. #include "DateTime.enum.h" #include "Std.h" @@ -56,309 +53,3 @@ struct MqlDateTime { int day_of_year; // Zero-based day number of the year (1st Jan = 0). }; #endif - -/* - * Struct to provide static date and time methods. - */ -struct DateTimeStatic { - /** - * Returns the current day of the month (e.g. the day of month of the last known server time). - */ - static int Day(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::TimeDay(dt); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.day; -#endif - } - - /** - * Returns the current zero-based day of the week of the last known server time. - */ - static int DayOfWeek(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::DayOfWeek(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.day_of_week; -#endif - } - - /** - * Returns the current day of the year (e.g. the day of year of the last known server time). - */ - static int DayOfYear(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::DayOfYear(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.day_of_year + 1; -#endif - } - - /** - * Returns the hour of the last known server time by the moment of the program start. - */ - static int Hour(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Hour(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.hour; -#endif - } - - /** - * Check whether market is within peak hours. - */ - static bool IsPeakHour() { - MqlDateTime dt; - TimeToStruct(::TimeGMT(), dt); - return dt.hour >= 8 && dt.hour <= 16; - } - - /** - * Returns the current minute of the last known server time by the moment of the program start. - */ - static int Minute(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Minute(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.min; -#endif - } - - /** - * Returns the current month as number (e.g. the number of month of the last known server time). - */ - static int Month(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Month(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.mon; -#endif - } - - /** - * Returns the amount of seconds elapsed from the beginning of the current minute of the last known server time. - */ - static int Seconds(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Seconds(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.sec; -#endif - } - - /** - * Converts a time stamp into a string of "yyyy.mm.dd hh:mi" format. - */ - static string TimeToStr(datetime value, int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { -#ifdef __MQL4__ - return ::TimeToStr(value, mode); -#else // __MQL5__ - // #define TimeToStr(value, mode) DateTime::TimeToStr(value, mode) - return ::TimeToString(value, mode); -#endif - } - static string TimeToStr(int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { return TimeToStr(TimeCurrent(), mode); } - - /** - * Returns the current time of the trade server. - */ - static datetime TimeTradeServer() { -#ifdef __MQL4__ - // Unlike MQL5 TimeTradeServer(), - // TimeCurrent() returns the last known server time. - return ::TimeCurrent(); -#else - // The calculation of the time value is performed in the client terminal - // and depends on the time settings of your computer. - return ::TimeTradeServer(); -#endif - } - - /** - * Returns the current year (e.g. the year of the last known server time). - */ - static int Year(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Year(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.year; -#endif - } -}; - -struct DateTimeEntry : MqlDateTime { - int week_of_year; - // Struct constructors. - DateTimeEntry() { Set(); } - DateTimeEntry(datetime _dt) { Set(_dt); } - DateTimeEntry(MqlDateTime& _dt) { - Set(_dt); -#ifndef __MQL__ - throw NotImplementedException(); -#endif - } - // Getters. - int GetDayOfMonth() { return day; } - int GetDayOfWeek() { - // Returns the zero-based day of week. - // (0-Sunday, 1-Monday, ... , 6-Saturday). - return day_of_week; - } - int GetDayOfYear() { return day_of_year + 1; } // Zero-based day of year (1st Jan = 0). - int GetHour() { return hour; } - int GetMinute() { return min; } - int GetMonth() { return mon; } - int GetSeconds() { return sec; } - // int GetWeekOfYear() { return week_of_year; } // @todo - int GetValue(ENUM_DATETIME_UNIT _unit) { - int _result = -1; - switch (_unit) { - case DATETIME_SECOND: - return GetSeconds(); - case DATETIME_MINUTE: - return GetMinute(); - case DATETIME_HOUR: - return GetHour(); - case DATETIME_DAY: - return GetDayOfMonth(); - case DATETIME_WEEK: - return -1; // return WeekOfYear(); // @todo - case DATETIME_MONTH: - return GetMonth(); - case DATETIME_YEAR: - return GetYear(); - default: - break; - } - return _result; - } - unsigned int GetValue(unsigned int _unit) { - if ((_unit & (DATETIME_DAY | DATETIME_WEEK)) != 0) { - return GetDayOfWeek(); - } else if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { - return GetDayOfMonth(); - } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { - return GetDayOfYear(); - } - return GetValue((ENUM_DATETIME_UNIT)_unit); - } - int GetYear() { return year; } - datetime GetTimestamp() { return StructToTime(THIS_REF); } - // Setters. - void Set() { - TimeToStruct(::TimeCurrent(), THIS_REF); - // @fixit Should also set day of week. - } - void SetGMT() { - TimeToStruct(::TimeGMT(), THIS_REF); - // @fixit Should also set day of week. - } - // Set date and time. - void Set(datetime _time) { - TimeToStruct(_time, THIS_REF); - // @fixit Should also set day of week. - } - // Set date and time. - void Set(MqlDateTime& _time) { - THIS_REF = _time; - // @fixit Should also set day of week. - } - void SetDayOfMonth(int _value) { - day = _value; - day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. - day_of_year = DateTimeStatic::DayOfYear(); // Zero-based day of year. - } - void SetDayOfYear(int _value) { - day_of_year = _value - 1; // Sets zero-based day of year. - day = DateTimeStatic::Month(); // Sets day of month (1..31). - day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. - } - void SetHour(int _value) { hour = _value; } - void SetMinute(int _value) { min = _value; } - void SetMonth(int _value) { mon = _value; } - void SetSeconds(int _value) { sec = _value; } - void SetWeekOfYear(int _value) { - week_of_year = _value; - // day = @todo; - // day_of_week = @todo; - // day_of_year = @todo; - } - void SetValue(ENUM_DATETIME_UNIT _unit, int _value) { - switch (_unit) { - case DATETIME_SECOND: - SetSeconds(_value); - break; - case DATETIME_MINUTE: - SetMinute(_value); - break; - case DATETIME_HOUR: - SetHour(_value); - break; - case DATETIME_DAY: - SetDayOfMonth(_value); - break; - case DATETIME_WEEK: - SetWeekOfYear(_value); - break; - case DATETIME_MONTH: - SetMonth(_value); - break; - case DATETIME_YEAR: - SetYear(_value); - break; - default: - break; - } - } - void SetValue(unsigned short _unit, int _value) { - if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { - SetDayOfMonth(_value); - } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { - SetDayOfYear(_value); - } else { - SetValue((ENUM_DATETIME_UNIT)_unit, _value); - } - } - void SetYear(int _value) { year = _value; } -}; diff --git a/Math.extern.h b/Math.extern.h index 4dce9bfe7..07434b946 100644 --- a/Math.extern.h +++ b/Math.extern.h @@ -22,28 +22,56 @@ // Define external global functions. #ifndef __MQL__ +#pragma once + +#include + template -extern T MathAbs(T value); +T MathAbs(T value) { + return std::abs(value); +} template -extern T fabs(T value); +T fabs(T value) { + return std::abs(value); +} template -extern T pow(T base, T exponent); +T pow(T base, T exponent) { + return (T)std::pow(base, exponent); +} template -extern T MathPow(T base, T exponent); +T MathPow(T base, T exponent) { + return std::pow(base, exponent); +} template -extern T round(T value); +T round(T value) { + return std::round(value); +} template -extern T MathRound(T value); +T MathRound(T value) { + return std::round(value); +} template -extern T fmax(T value1, T value2); +T fmax(T value1, T value2) { + return std::max(value1, value2); +} template -extern T MathMax(T value1, T value2); +T MathMax(T value1, T value2) { + return std::max(value1, value2); +} template -extern T fmin(T value1, T value2); +T fmin(T value1, T value2) { + return std::min(value1, value2); +} template -extern T MathMin(T value1, T value2); +T MathMin(T value1, T value2) { + return std::min(value1, value2); +} template -extern T MathLog10(T value1); +T MathLog10(T value) { + return std::log10(value); +} template -extern T log10(T value); +T log10(T value) { + return std::log10(value); +} #endif diff --git a/PlatformTime.h b/PlatformTime.h new file mode 100644 index 000000000..8e62646f5 --- /dev/null +++ b/PlatformTime.h @@ -0,0 +1,89 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Includes. +#include "DateTime.enum.h" +#include "DateTime.mqh" +#include "DateTime.struct.h" + +/** + * @file + * Platform time retrieval. + */ +#ifndef __MQL__ +#pragma once + +// Includes. +#include +#include +#include "DateTime.struct.h" + +class PlatformTime { + static MqlDateTime current_time; + static long current_timestamp_s; + static long current_timestamp_ms; + + public: + static long CurrentTimestamp() { return current_timestamp_s; } + static long CurrentTimestampMs() { return current_timestamp_ms; } + static MqlDateTime CurrentTime() { return current_time; } + + void static Tick() { +#ifdef __MQL__ + static _last_time_ms = 0; + + current_time_s = ::TimeCurrent(¤t_time); + + current_time_ms = (long)GetTickCount(); + + if (_last_time_ms != 0 && current_time_ms < _last_time_ms) { + // Overflow occured (49.7 days passed). + // More info: https://docs.mql4.com/common/gettickcount + current_time_ms += _last_time_ms; + } + + _last_time_ms = current_time_ms; +#else + using namespace std::chrono; + current_timestamp_s = (long)duration_cast(system_clock::now().time_since_epoch()).count(); + current_timestamp_ms = (long)duration_cast(system_clock::now().time_since_epoch()).count(); + + using namespace std::chrono; + std::time_t t = std::time(0); + std::tm* now = std::localtime(&t); + current_time.day = now->tm_mday; + current_time.day_of_week = now->tm_wday; + current_time.day_of_year = now->tm_yday; + current_time.hour = now->tm_hour; + current_time.min = now->tm_min; + current_time.mon = now->tm_mon; + current_time.sec = now->tm_sec; + current_time.year = now->tm_year; +#endif + } +}; + +MqlDateTime PlatformTime::current_time{0, 0, 0, 0, 0, 0, 0, 0}; +long PlatformTime::current_timestamp_s = 0; +long PlatformTime::current_timestamp_ms = 0; + +#endif diff --git a/Std.h b/Std.h index 76ed66e47..2a982cb78 100644 --- a/Std.h +++ b/Std.h @@ -166,6 +166,8 @@ class _cpp_array { m_isSeries = r.m_isSeries; } + std::vector& str() { return m_data; } + void operator=(const _cpp_array& r) { m_data = r.m_data; m_isSeries = r.m_isSeries; @@ -196,6 +198,14 @@ class _cpp_array { */ int size() const { return (int)m_data.size(); } + void resize(int new_size, int reserve_size = 0) { + // E.g., size = 10, new_size = 90, reserve_size = 50 + // thus: new_reserve_size = new_size + reserve_size - (new_size % reserve_size) + // which is: 90 + reserve_size - (90 % reserve_size) = 90 + 50 - 40 = 100. + m_data.reserve(new_size + reserve_size - (new_size % reserve_size)); + m_data.resize(new_size); + } + /** * Checks whether */ diff --git a/String.extern.h b/String.extern.h index b59fb5a0d..943c7df61 100644 --- a/String.extern.h +++ b/String.extern.h @@ -29,15 +29,32 @@ // Define external global functions. #ifndef __MQL__ -extern double StringToDouble(string value); -extern int StringFind(string string_value, string match_substring, int start_pos = 0); -extern int StringLen(string string_value); -extern int StringSplit(const string& string_value, const unsigned short separator, ARRAY_REF(string, result)); -extern long StringToInteger(string value); -extern string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol = ' '); -extern string StringFormat(string format, ...); -extern string StringSubstr(string string_value, int start_pos, int length = -1); -extern unsigned short StringGetCharacter(string string_value, int pos); +double StringToDouble(string value) { return std::stod(value); } + +auto StringFind(const string string_value, string match_substring, int start_pos = 0) -> int { + return string_value.find(match_substring); +} +int StringLen(string string_value) { return string_value.size(); } +int StringSplit(const string& string_value, const unsigned short separator, ARRAY_REF(string, result)) { + auto start = 0U; + auto end = string_value.find((char)separator); + while (end != std::string::npos) { + result.str().push_back(string_value.substr(start, end - start)); + start = end + 1; // 1 - size of the separator. + end = string_value.find((char)separator, start); + } + return result.size(); +} +long StringToInteger(string value) { return std::stol(value); } +string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol = ' ') { + return std::to_string(number); +} + +string StringFormat(string format, ...); +string StringSubstr(string string_value, int start_pos, int length = -1) { + return string_value.substr(start_pos, length == -1 ? (string_value.size() - start_pos) : length); +} +unsigned short StringGetCharacter(string string_value, int pos); int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, unsigned int codepage = CP_ACP); #endif From d3936837ce0eae47e52bb34bc903ac8ab4e9cda7 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 30 Nov 2022 18:07:39 +0100 Subject: [PATCH 047/123] WIP. Added missing C++ methods regarding String printing/manipulations and conversion. --- Common.extern.h | 12 +-------- Convert.extern.h | 29 ++++++++++++++++----- String.extern.h | 66 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/Common.extern.h b/Common.extern.h index 3f6a5a840..61966cfb4 100644 --- a/Common.extern.h +++ b/Common.extern.h @@ -24,6 +24,7 @@ #ifndef __MQL__ #pragma once #include +#include #include "Chart.enum.h" #include "DateTime.enum.h" @@ -38,16 +39,5 @@ void SetUserError(unsigned short user_error) { _LastError = ERR_USER_ERROR_FIRST // Exceptions. extern int NotImplementedException(); // Print-related functions. -template -extern std::string StringFormat(const std::string& format, Args... args); - -template -extern std::string PrintFormat(const std::string& format, Args... args); - -template -extern void Print(Args... args); - -template -extern void Alert(Args... args); #endif diff --git a/Convert.extern.h b/Convert.extern.h index 4a5a02ed0..a2f4bd2db 100644 --- a/Convert.extern.h +++ b/Convert.extern.h @@ -23,12 +23,29 @@ // Prevents processing this includes file for the second time. #ifndef __MQL__ #pragma once -#endif + +// Includes. +#include +#include // Define external global functions. -#ifndef __MQL__ -extern double NormalizeDouble(double value, int digits); -extern string CharToString(unsigned char char_code); -extern string DoubleToString(double value, int digits = 8); -extern string ShortToString(unsigned short symbol_code); +double NormalizeDouble(double value, int digits) { return std::round(value / digits) * digits; } + +string CharToString(unsigned char char_code) { + std::stringstream ss; + ss << char_code; + return ss.str(); +} + +string DoubleToString(double value, int digits = 8) { + std::stringstream ss; + ss << std::setprecision(digits) << value; + return ss.str(); +} + +string ShortToString(unsigned short symbol_code) { + std::stringstream ss; + ss << symbol_code; + return ss.str(); +} #endif diff --git a/String.extern.h b/String.extern.h index 943c7df61..b1043fd2b 100644 --- a/String.extern.h +++ b/String.extern.h @@ -23,12 +23,18 @@ // Prevents processing this includes file for the second time. #ifndef __MQL__ #pragma once + +// Includes. +#include + +#include +#include +#include + #include "Std.h" #include "Terminal.define.h" -#endif // Define external global functions. -#ifndef __MQL__ double StringToDouble(string value) { return std::stod(value); } auto StringFind(const string string_value, string match_substring, int start_pos = 0) -> int { @@ -50,11 +56,63 @@ string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol return std::to_string(number); } -string StringFormat(string format, ...); +template +struct TuplePrinter { + static void print(const std::string& fmt, std::ostream& os, const Tuple& t) { + const size_t idx = fmt.find_last_of('%'); + TuplePrinter::print(std::string(fmt, 0, idx), os, t); + os << std::get(t) << std::string(fmt, idx + 1); + } +}; + +template +struct TuplePrinter { + static void print(const std::string& fmt, std::ostream& os, const Tuple& t) { + const size_t idx = fmt.find_first_of('%'); + os << std::string(fmt, 0, idx) << std::get<0>(t) << std::string(fmt, idx + 1); + } +}; + +template +void PrintTo(std::ostream& out, Arg&& arg, Args&&... args) { + out << std::forward(arg); + using expander = int[]; + (void)expander{0, (void(out << std::forward(args)), 0)...}; +} + +template +void Print(Arg&& arg, Args&&... args) { + PrintTo(std::cout, arg, args...); +} + +template +void Alert(Arg&& arg, Args&&... args) { + PrintTo(std::cerr, arg, args...); +} + +template +std::string StringFormat(const std::string& fmt, Args&&... args) { + std::stringstream ss; + const auto t = std::make_tuple(std::forward(args)...); + TuplePrinter::print(fmt, ss, t); + return ss.str(); +} + +template +void PrintFormat(const std::string& fmt, Args&&... args) { + std::cout << StringFormat(fmt, args...) << std::endl; +} + string StringSubstr(string string_value, int start_pos, int length = -1) { return string_value.substr(start_pos, length == -1 ? (string_value.size() - start_pos) : length); } -unsigned short StringGetCharacter(string string_value, int pos); +unsigned short StringGetCharacter(string string_value, int pos) { + if (pos < 0 || pos >= string_value.size()) { + Alert("Character index out of string boundary! Position passed: ", pos, ", string passed: \"", string_value, "\""); + } + return string_value[pos]; +} + int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, unsigned int codepage = CP_ACP); #endif From e36c9c960f800b63f109eaef05ce8c42c50c0c0a Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 1 Dec 2022 18:23:17 +0100 Subject: [PATCH 048/123] WIP. Trying to run emscripten-generated code in the browser. --- Common.extern.h | 9 ++++++++- DateTime.extern.h | 5 +++-- Math.extern.h | 1 + Std.h | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Common.extern.h b/Common.extern.h index 61966cfb4..43bc7f98f 100644 --- a/Common.extern.h +++ b/Common.extern.h @@ -30,7 +30,14 @@ #include "DateTime.enum.h" #include "Terminal.define.h" -void DebugBreak() { raise(SIGTRAP); } +void DebugBreak() { +#ifdef _MSC_VER + // @see https://learn.microsoft.com/en-us/cpp/intrinsics/debugbreak?view=msvc-170 + __debugbreak(); +#else + raise(SIGTRAP); +#endif +} int _LastError = 0; diff --git a/DateTime.extern.h b/DateTime.extern.h index 0ece67d69..1ffb17098 100644 --- a/DateTime.extern.h +++ b/DateTime.extern.h @@ -29,6 +29,7 @@ // Includes. #include + #include "DateTime.enum.h" #include "String.mqh" @@ -44,7 +45,7 @@ class datetime { public: datetime() { dt = 0; } datetime(const long& _time) { dt = _time; } - datetime(const int& _time); + // datetime(const int& _time); bool operator==(const int _time) const = delete; bool operator==(const datetime& _time) const { return dt == _time; } bool operator<(const int _time) const = delete; @@ -82,7 +83,7 @@ string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES) { } template -extern datetime operator"" _D(); +datetime operator"" _D(); #define DATETIME_LITERAL(STR) _D " ## STR ## " diff --git a/Math.extern.h b/Math.extern.h index 07434b946..a19b60b13 100644 --- a/Math.extern.h +++ b/Math.extern.h @@ -24,6 +24,7 @@ #ifndef __MQL__ #pragma once +#include #include template diff --git a/Std.h b/Std.h index 2a982cb78..d85cd83ac 100644 --- a/Std.h +++ b/Std.h @@ -202,7 +202,10 @@ class _cpp_array { // E.g., size = 10, new_size = 90, reserve_size = 50 // thus: new_reserve_size = new_size + reserve_size - (new_size % reserve_size) // which is: 90 + reserve_size - (90 % reserve_size) = 90 + 50 - 40 = 100. - m_data.reserve(new_size + reserve_size - (new_size % reserve_size)); + if (reserve_size > 0) { + new_size = reserve_size - (new_size % reserve_size); + } + m_data.reserve(new_size); m_data.resize(new_size); } From 42409e33161df00389e41b60f6ce18e85f184c1f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 15 Dec 2022 18:16:04 +0100 Subject: [PATCH 049/123] WIP. Trying to make smart pointers to work in JS. --- Convert.extern.h | 4 +-- DateTime.mqh | 4 +-- DictSlot.mqh | 2 ++ DictStruct.mqh | 17 +++------- Object.extern.h | 9 ++++- Refs.struct.h | 56 ++++++++++++++++++++++++-------- Serializer/SerializerConverter.h | 16 ++++++--- Serializer/SerializerJson.h | 26 ++++++++------- String.extern.h | 2 ++ Task/Task.h | 27 ++++++++++----- Task/Task.struct.h | 16 +++++++++ Task/TaskManager.h | 25 +++++++++++--- Trade/TradeSignal.h | 9 +++++ Trade/TradeSignalManager.h | 12 +++++++ 14 files changed, 164 insertions(+), 61 deletions(-) diff --git a/Convert.extern.h b/Convert.extern.h index a2f4bd2db..a21d6599e 100644 --- a/Convert.extern.h +++ b/Convert.extern.h @@ -25,8 +25,8 @@ #pragma once // Includes. -#include #include +#include // Define external global functions. double NormalizeDouble(double value, int digits) { return std::round(value / digits) * digits; } @@ -45,7 +45,7 @@ string DoubleToString(double value, int digits = 8) { string ShortToString(unsigned short symbol_code) { std::stringstream ss; - ss << symbol_code; + ss << (char)symbol_code; return ss.str(); } #endif diff --git a/DateTime.mqh b/DateTime.mqh index 2f9e1fa30..ab7abd69a 100644 --- a/DateTime.mqh +++ b/DateTime.mqh @@ -129,8 +129,8 @@ class DateTime { } #ifdef __debug_verbose__ - string _passed = - "time now " + (string)dt_curr.GetTimestamp() + ", time last " + (string)dt_last.GetTimestamp() + " "; + string _passed = "time now " + TimeToString(dt_curr.GetTimestamp()) + ", time last " + + TimeToString(dt_last.GetTimestamp()) + " "; if (_update) { _passed += "updating time "; diff --git a/DictSlot.mqh b/DictSlot.mqh index 41a85408d..eea48969d 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,6 +40,8 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} + DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} + bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } bool HasKey() { return bool(_flags & DICT_SLOT_HAS_KEY); } diff --git a/DictStruct.mqh b/DictStruct.mqh index 72e841a0e..5c47a1a06 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -89,17 +89,6 @@ class DictStruct : public DictBase { THIS_ATTR _mode = right._mode; } - void operator=(DictStruct& right) { - Clear(); - Resize(right.GetSlotCount()); - for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - THIS_ATTR _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; - } - THIS_ATTR _DictSlots_ref._num_used = right._DictSlots_ref._num_used; - THIS_ATTR _current_id = right._current_id; - THIS_ATTR _mode = right._mode; - } - void Clear() { for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); @@ -124,7 +113,7 @@ class DictStruct : public DictBase { /** * Inserts value using hashless key. */ - bool Push(V& value) { + bool Push(const V& value) { if (!InsertInto(THIS_ATTR _DictSlots_ref, value)) return false; return true; } @@ -136,6 +125,8 @@ class DictStruct : public DictBase { /** * Inserts value using hashless key. + * + * @todo Get rid of this method. */ #ifdef __MQL__ template <> @@ -385,7 +376,7 @@ class DictStruct : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { + bool InsertInto(DictSlotsRef& dictSlotsRef, const V& value) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeList; else if (THIS_ATTR _mode != DictModeList) { diff --git a/Object.extern.h b/Object.extern.h index f8b97dbd8..0b4bd3e35 100644 --- a/Object.extern.h +++ b/Object.extern.h @@ -25,5 +25,12 @@ * Includes external declarations related to objects. */ #ifndef __MQL__ -extern void *GetPointer(void *anyobject); +template +X* GetPointer(X& value) { + return &value; +} +template +X* GetPointer(X* ptr) { + return ptr; +} #endif diff --git a/Refs.struct.h b/Refs.struct.h index c97ad4b20..3225c782a 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -31,9 +31,15 @@ #endif // Includes. +#include + #include "Refs.rc.h" #include "Std.h" +#ifdef EMSCRIPTEN +#include +#endif + class Dynamic; // Forward class declaration. template @@ -87,6 +93,10 @@ struct SimpleRef { } }; +template +using base_type = + typename std::remove_cv::type>::type>::type; + /** * Class used to hold strong reference to reference-counted object. */ @@ -97,21 +107,34 @@ struct Ref { */ X* ptr_object; +#ifdef EMSCRIPTEN + typedef X element_type; +#endif + public: /** * Constructor. */ - Ref(X* _ptr) { THIS_REF = _ptr; } + Ref(X* _ptr) { + ptr_object = nullptr; + THIS_REF = _ptr; + } /** * Constructor. */ - Ref(Ref& ref) { THIS_REF = ref.Ptr(); } + Ref(const Ref& ref) { + ptr_object = nullptr; + Set(ref.Ptr()); + } /** * Constructor. */ - Ref(WeakRef& ref) { THIS_REF = ref.Ptr(); } + Ref(WeakRef& ref) { + ptr_object = nullptr; + Set(ref.Ptr()); + } /** * Constructor. @@ -126,7 +149,11 @@ struct Ref { /** * Returns pointer to target object. */ - X* Ptr() { return ptr_object; } + X* Ptr() const { return ptr_object; } + +#ifdef EMSCRIPTEN + X* get() const { return ptr_object; } +#endif /** * Checks whether any object is referenced. @@ -208,7 +235,11 @@ struct Ref { /** * Makes a strong reference to the given object. */ - X* operator=(X* _ptr) { + X* operator=(X* _ptr) { return Set(_ptr); } + /** + * Makes a strong reference to the given object. + */ + X* Set(X* _ptr) { if (ptr_object == _ptr) { // Assigning the same object. return Ptr(); @@ -240,18 +271,12 @@ struct Ref { /** * Makes a strong reference to the given weakly-referenced object. */ - X* operator=(WeakRef& right) { - THIS_REF = right.Ptr(); - return Ptr(); - } + X* operator=(const WeakRef& right) { return Set((X*)right.Ptr()); } /** * Makes a strong reference to the strongly-referenced object. */ - X* operator=(Ref& right) { - THIS_REF = right.Ptr(); - return Ptr(); - } + X* operator=(const Ref& right) { return Set((X*)right.Ptr()); } /** * Equality operator. @@ -259,6 +284,11 @@ struct Ref { bool operator==(const Ref& r) { return ptr_object != NULL && ptr_object == r.ptr_object; } }; +template +Ref make_ref() { + return Ref(); +} + /** * Class used to hold weak reference to reference-counted object. */ diff --git a/Serializer/SerializerConverter.h b/Serializer/SerializerConverter.h index 7e9490239..571bb1353 100644 --- a/Serializer/SerializerConverter.h +++ b/Serializer/SerializerConverter.h @@ -39,6 +39,10 @@ class SerializerNode; #include "SerializerDict.h" #include "SerializerNode.h" +#ifdef __debug__ +#include "SerializerJson.h" +#endif + class SerializerConverter { public: SerializerNode* root_node; @@ -70,8 +74,9 @@ class SerializerConverter { SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); #ifdef __debug__ Print("FromObject(): serializer flags: ", serializer_flags); - Print("FromObject(): result: ", - _serializer.GetRoot() != NULL ? _serializer.GetRoot().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); + Print("FromObject(): result: ", _serializer.GetRoot() != NULL + ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) + : "NULL"); #endif return _converter; } @@ -84,8 +89,9 @@ class SerializerConverter { SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); #ifdef __debug__ Print("FromObject(): serializer flags: ", serializer_flags); - Print("FromObject(): result: ", - _serializer.GetRoot() != NULL ? _serializer.GetRoot().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); + Print("FromObject(): result: ", _serializer.GetRoot() != NULL + ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) + : "NULL"); #endif return _converter; } @@ -115,7 +121,7 @@ class SerializerConverter { SerializerConverter _converter(((C*)NULL)PTR_DEREF Parse(arg), 0); #ifdef __debug__ Print("FromString(): result: ", - _converter.Node() != NULL ? _converter.Node().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); + _converter.Node() != NULL ? _converter.Node() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); #endif return _converter; } diff --git a/Serializer/SerializerJson.h b/Serializer/SerializerJson.h index fd3ed5fed..491954708 100644 --- a/Serializer/SerializerJson.h +++ b/Serializer/SerializerJson.h @@ -195,7 +195,7 @@ class SerializerJson { #ifdef __debug__ Print("SerializerJson: Value \"" + extracted + "\" for key " + - (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif expectingValue = false; @@ -217,7 +217,8 @@ class SerializerJson { } #ifdef __debug__ - Print("SerializerJson: Entering object for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Entering object for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif node = new SerializerNode(SerializerNodeObject, current, key); @@ -237,16 +238,18 @@ class SerializerJson { } #ifdef __debug__ - Print("SerializerJson: Leaving object for key " + (current != NULL && current.GetKeyParam() != NULL - ? ("\"" + current.GetKeyParam().ToString() + "\"") - : "")); + Print("SerializerJson: Leaving object for key " + + (current != NULL && current PTR_DEREF GetKeyParam() != NULL + ? ("\"" + current PTR_DEREF GetKeyParam() PTR_DEREF ToString() + "\"") + : "")); #endif current = PTR_ATTRIB(current, GetParent()); expectingValue = false; } else if (ch == '[') { #ifdef __debug__ - Print("SerializerJson: Entering list for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Entering list for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif if (expectingKey) { @@ -264,7 +267,8 @@ class SerializerJson { key = NULL; } else if (ch == ']') { #ifdef __debug__ - Print("SerializerJson: Leaving list for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Leaving list for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif if (expectingKey || expectingValue || PTR_ATTRIB(current, GetType()) != SerializerNodeArray) { @@ -285,8 +289,8 @@ class SerializerJson { value = StringFind(extracted, ".") != -1 ? SerializerNodeParam::FromValue(StringToDouble(extracted)) : SerializerNodeParam::FromValue(StringToInteger(extracted)); #ifdef __debug__ - Print("SerializerJson: Value " + value.AsString() + " for key " + - (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Value " + value PTR_DEREF AsString() + " for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif PTR_ATTRIB(current, AddChild(new SerializerNode(PTR_ATTRIB(current, GetType()) == SerializerNodeObject @@ -306,8 +310,8 @@ class SerializerJson { value = SerializerNodeParam::FromValue(ch == 't' ? true : false); #ifdef __debug__ - Print("SerializerJson: Value " + (value.ToBool() ? "true" : "false") + " for key " + - (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print(string("SerializerJson: Value ") + (value PTR_DEREF ToBool() ? "true" : "false") + " for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif // Skipping value. diff --git a/String.extern.h b/String.extern.h index b1043fd2b..55a0f4f78 100644 --- a/String.extern.h +++ b/String.extern.h @@ -78,6 +78,8 @@ void PrintTo(std::ostream& out, Arg&& arg, Args&&... args) { out << std::forward(arg); using expander = int[]; (void)expander{0, (void(out << std::forward(args)), 0)...}; + out << "\n"; + out.flush(); } template diff --git a/Task/Task.h b/Task/Task.h index 0854b9d18..c2ca184cc 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -30,10 +30,6 @@ #pragma once #endif -// Prevents processing this includes file for the second time. -#ifndef TASK_H -#define TASK_H - // Includes. #include "../DictStruct.mqh" #include "../Terminal.define.h" @@ -54,12 +50,12 @@ class Task : public Taskable { * Class constructor. */ Task() {} - Task(TaskEntry &_entry) { Add(_entry); } + Task(const TaskEntry &_entry) { Add(_entry); } /** * Class copy constructor. */ - Task(Task &_task) { tasks = PTR_TO_REF(_task.GetTasks()); } + Task(const Task &_task) { tasks = PTR_TO_REF(_task.GetTasks()); } /** * Class deconstructor. @@ -71,7 +67,7 @@ class Task : public Taskable { /** * Adds new task. */ - void Add(TaskEntry &_entry) { tasks.Push(_entry); } + void Add(const TaskEntry &_entry) { tasks.Push(_entry); } /* Virtual methods */ @@ -214,7 +210,7 @@ class Task : public Taskable { /** * Returns tasks. */ - DictStruct *GetTasks() { return &tasks; } + const DictStruct *GetTasks() const { return &tasks; } /** * Count entry flags. @@ -317,4 +313,17 @@ class Task : public Taskable { /* Other methods */ }; -#endif // TASK_H + +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(Task) { + emscripten::class_("Task").smart_ptr>("Ref").constructor(emscripten::optional_override([]() { + return Ref(new Task()); + })) + //.function("Add", optional_override([](Task &self, Ref task) { self.Add(task.Ptr()); })) + ; +} + +#endif diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 391eebc9c..db3a202cb 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -65,6 +65,15 @@ struct TaskEntry { public: // Constructors. TaskEntry() { Init(); } + TaskEntry(const TaskEntry &_entry) + : action(_entry.action), + cond(_entry.cond), + expires(_entry.expires), + last_process(_entry.last_process), + last_success(_entry.last_success), + flags(_entry.flags) { + Init(); + } TaskEntry(const TaskActionEntry &_action, const TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } template TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { @@ -143,3 +152,10 @@ struct TaskEntry { SERIALIZER_EMPTY_STUB; }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TaskEntry) { emscripten::class_("TaskEntry").constructor(); } + +#endif diff --git a/Task/TaskManager.h b/Task/TaskManager.h index 7cd985fde..d549cc95f 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -30,10 +30,6 @@ #pragma once #endif -// Prevents processing this includes file for the second time. -#ifndef TASK_MANAGER_H -#define TASK_MANAGER_H - // Includes. #include "../DictObject.mqh" #include "../Serializer/SerializerConverter.h" @@ -95,6 +91,11 @@ class TaskManager { return Add((Task *)_task_obj); } + /** + * Clears tasks list. + */ + void Clear() { tasks.Clear(); } + /* Processing methods */ /** @@ -110,4 +111,18 @@ class TaskManager { } }; -#endif // TASK_MANAGER_H +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TaskManager) { + emscripten::class_("TaskManager") + .constructor() + .function("Add", emscripten::optional_override([](TaskManager &self, Ref task) { + Print("Adding Task"); + self.Add(task.Ptr()); + })) + // .function("Add", emscripten::select_overload(&TaskManager::Add)) + .function("Clear", &TaskManager::Clear) + .function("Process", &TaskManager::Process); +} +#endif diff --git a/Trade/TradeSignal.h b/Trade/TradeSignal.h index 7a48524f5..4a11e43de 100644 --- a/Trade/TradeSignal.h +++ b/Trade/TradeSignal.h @@ -179,3 +179,12 @@ class TradeSignal { */ string ToString() { return signal.ToString(); } }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TradeSignal) { + emscripten::class_("TradeSignal").constructor().function("ToString", &TradeSignal::ToString); +} + +#endif diff --git a/Trade/TradeSignalManager.h b/Trade/TradeSignalManager.h index 87dd5c017..b9a03fb82 100644 --- a/Trade/TradeSignalManager.h +++ b/Trade/TradeSignalManager.h @@ -181,3 +181,15 @@ class TradeSignalManager : Dynamic { .ToString(SERIALIZER_JSON_NO_WHITESPACES); } }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TradeSignalManager) { + emscripten::class_("TradeSignalManager") + .constructor() + .function("SignalAdd", &TradeSignalManager::SignalAdd) + .function("ToString", &TradeSignalManager::ToString); +} + +#endif From da13c54bc5645cb5d3a7f7153bad10c5901b045f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 21 Dec 2022 20:42:07 +0100 Subject: [PATCH 050/123] WIP. Making Account and Exchange classes to work via Emscripten. Also introduced MemoryFileSystem for accessing temporary files written by MQL/C++ code. --- Account/Account.struct.h | 2 +- Account/AccountBase.struct.h | 3 +- Array.mqh | 6 +- Bar.struct.h | 4 +- BufferStruct.mqh | 8 +- Chart.struct.static.h | 6 ++ Data.struct.h | 54 +++++++++++-- DictStruct.mqh | 6 +- File.define.h | 35 +++++++- File.extern.h | 27 ++++++- File.mqh | 33 -------- Flags.h | 5 ++ Log.mqh | 1 + Object.mqh | 5 -- Platform.extern.h | 38 +++++++++ Platform.h | 15 +++- Refs.mqh | 10 +++ Refs.struct.h | 9 +++ Std.h | 21 +++++ Storage/MemoryFileSystem.h | 149 +++++++++++++++++++++++++++++++++++ String.extern.h | 32 ++------ SymbolInfo.mqh | 4 +- SymbolInfo.struct.h | 4 +- Task/TaskManager.h | 14 +++- Terminal.enum.h | 66 ++++++++++++---- Terminal.extern.h | 51 ++++++++++++ 26 files changed, 496 insertions(+), 112 deletions(-) create mode 100644 Platform.extern.h create mode 100644 Storage/MemoryFileSystem.h diff --git a/Account/Account.struct.h b/Account/Account.struct.h index 2ae613e55..efae51d51 100644 --- a/Account/Account.struct.h +++ b/Account/Account.struct.h @@ -28,7 +28,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#include "../Serializer.enum.h" +#include "../Serializer/Serializer.enum.h" #endif // Forward class declaration. diff --git a/Account/AccountBase.struct.h b/Account/AccountBase.struct.h index ab237c6b7..85a0cbde2 100644 --- a/Account/AccountBase.struct.h +++ b/Account/AccountBase.struct.h @@ -28,7 +28,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#include "../Serializer.enum.h" +#include "../Serializer/Serializer.enum.h" #endif // Forward class declaration. @@ -36,6 +36,7 @@ class Serializer; // Includes. #include "../Serializer/Serializer.h" +#include "../Std.h" #include "../Terminal.define.h" // Struct for account entries. diff --git a/Array.mqh b/Array.mqh index 040767b6f..8b2035edf 100644 --- a/Array.mqh +++ b/Array.mqh @@ -119,7 +119,7 @@ class Array { int i; string result = ""; for (i = 0; i < ArraySize(arr); i++) { - result += StringFormat("%d:%d%s", i, arr[i], sep); + result += StringFormat("%d:%d%s", i, arr[i], C_STR(sep)); } // Return text without last separator. return StringSubstr(result, 0, StringLen(result) - StringLen(sep)); @@ -136,7 +136,7 @@ class Array { int i; string result = ""; for (i = 0; i < ArraySize(arr); i++) { - result += StringFormat("%d:%g%s", i, arr[i], sep); + result += StringFormat("%d:%g%s", i, arr[i], C_STR(sep)); } // Return text without last separator. return StringSubstr(result, 0, StringLen(result) - StringLen(sep)); @@ -404,7 +404,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { int i; string res = ""; for (i = 0; i < ArraySize(arr); i++) { - res += StringFormat("%g%s", NormalizeDouble(arr[i], digits), dlm); + res += StringFormat("%g%s", NormalizeDouble(arr[i], digits), C_STR(dlm)); } res = StringSubstr(res, 0, StringLen(res) - StringLen(dlm)); return res; diff --git a/Bar.struct.h b/Bar.struct.h index 5d0f18255..a261a8673 100644 --- a/Bar.struct.h +++ b/Bar.struct.h @@ -54,12 +54,12 @@ struct BarOHLC BarOHLC() : open(0), high(0), low(0), close(0), time(0){}; BarOHLC(double _open, double _high, double _low, double _close, datetime _time = 0) : time(_time), open(_open), high(_high), low(_low), close(_close) { - if (_time == 0) { + if (_time == (datetime)0) { _time = TimeCurrent(); } } BarOHLC(ARRAY_REF(double, _prices), datetime _time = 0) : time(_time) { - _time = _time == 0 ? TimeCurrent() : _time; + _time = _time == (datetime)0 ? TimeCurrent() : _time; int _size = ArraySize(_prices); close = _prices[0]; open = _prices[_size - 1]; diff --git a/BufferStruct.mqh b/BufferStruct.mqh index 2bc6cd93c..bda4a34d9 100644 --- a/BufferStruct.mqh +++ b/BufferStruct.mqh @@ -63,17 +63,17 @@ class BufferStruct : public DictStruct { /** * Constructor. */ - BufferStruct() : max(INT_MIN), min(INT_MAX) { SetOverflowListener(BufferStructOverflowListener, 10); } + BufferStruct() : max(INT_MIN), min(INT_MAX) { THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } BufferStruct(BufferStruct& _right) : max(INT_MIN), min(INT_MAX) { this = _right; - SetOverflowListener(BufferStructOverflowListener, 10); + THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } /** * Adds new value. */ void Add(TStruct& _value, long _dt = 0) { - _dt = _dt > 0 ? _dt : TimeCurrent(); + _dt = _dt > 0 ? _dt : (long)TimeCurrent(); if (Set(_dt, _value)) { min = _dt < min ? _dt : min; max = _dt > max ? _dt : max; @@ -87,7 +87,7 @@ class BufferStruct : public DictStruct { min = INT_MAX; max = INT_MIN; if (_dt > 0) { - for (DictStructIterator iter(Begin()); iter.IsValid(); ++iter) { + for (DictStructIterator iter(THIS_ATTR Begin()); iter.IsValid(); ++iter) { long _time = iter.Key(); if (_older && _time < _dt) { Unset(iter.Key()); diff --git a/Chart.struct.static.h b/Chart.struct.static.h index a5c97d387..cf19e5805 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -25,9 +25,15 @@ * Includes Chart's static structs. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. #include "Chart.define.h" #include "Chart.symboltf.h" +#include "Platform.extern.h" #include "Terminal.define.h" /* Defines struct for chart static methods. */ diff --git a/Data.struct.h b/Data.struct.h index 9d6fe8959..a73a602c8 100644 --- a/Data.struct.h +++ b/Data.struct.h @@ -129,8 +129,42 @@ struct DataParamEntry : public MqlParam { string_value = _string_value; } DataParamEntry(const DataParamEntry &_r) { ASSIGN_TO_THIS(MqlParam, _r); } + + DataParamEntry(bool _value) { + type = TYPE_BOOL; + integer_value = _value; + } + DataParamEntry(const datetime _value) { + type = TYPE_DATETIME; + integer_value = _value; + } + DataParamEntry(double _value) { + type = TYPE_DOUBLE; + double_value = _value; + } + DataParamEntry(int _value) { + type = TYPE_INT; + integer_value = _value; + } + DataParamEntry(const string _value) { + type = TYPE_STRING; + string_value = _value; + } + DataParamEntry(unsigned int _value) { + type = TYPE_UINT; + integer_value = _value; + } + DataParamEntry(long _value) { + type = TYPE_LONG; + integer_value = _value; + } + DataParamEntry(unsigned long _value) { + type = TYPE_ULONG; + integer_value = (long)_value; + } + // Struct operators. - void operator=(const bool _value) { + void operator=(bool _value) { type = TYPE_BOOL; integer_value = _value; } @@ -138,11 +172,11 @@ struct DataParamEntry : public MqlParam { type = TYPE_DATETIME; integer_value = _value; } - void operator=(const double _value) { + void operator=(double _value) { type = TYPE_DOUBLE; double_value = _value; } - void operator=(const int _value) { + void operator=(int _value) { type = TYPE_INT; integer_value = _value; } @@ -150,15 +184,19 @@ struct DataParamEntry : public MqlParam { type = TYPE_STRING; string_value = _value; } - void operator=(const unsigned int _value) { + void operator=(unsigned int _value) { type = TYPE_UINT; integer_value = _value; } - template - void operator=(const T _value) { - type = TYPE_INT; - integer_value = (int)_value; + void operator=(long _value) { + type = TYPE_LONG; + integer_value = _value; + } + void operator=(unsigned long _value) { + type = TYPE_ULONG; + integer_value = (long)_value; } + bool operator==(const DataParamEntry &_s) { return type == _s.type && double_value == _s.double_value && integer_value == _s.integer_value && string_value == _s.string_value; diff --git a/DictStruct.mqh b/DictStruct.mqh index 5c47a1a06..8a52642fa 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -152,12 +152,12 @@ class DictStruct : public DictBase { V operator[](K key) { DictSlot* slot; - int position; + unsigned int position; if (THIS_ATTR _mode == DictModeList) slot = THIS_ATTR GetSlot((unsigned int)key); else - slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); + slot = THIS_ATTR GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); if (slot == NULL || !slot PTR_DEREF IsUsed()) { Alert("Invalid DictStruct key \"", key, "\" (called by [] operator). Returning empty structure."); @@ -174,7 +174,7 @@ class DictStruct : public DictBase { */ V GetByKey(const K _key) { unsigned int position; - DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); + DictSlot* slot = THIS_ATTR GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); if (!slot) { static V _empty; diff --git a/File.define.h b/File.define.h index e932ab836..39b5ce3d9 100644 --- a/File.define.h +++ b/File.define.h @@ -19,13 +19,46 @@ * along with this program. If not, see . * */ - // Defines. #ifndef __MQL__ +#pragma once + // File constants to read the whole value of char, short or int type. #define CHAR_VALUE 1 #define INT_VALUE 4 #define SHORT_VALUE 2 // Used for checking file handles (see FileOpen() and FileFindFirst()). #define INVALID_HANDLE -1 + +enum ENUM_FILE_PROPERTY_INTEGER { + FILE_EXISTS, + FILE_CREATE_DATE, + FILE_MODIFY_DATE, + FILE_ACCESS_DATE, + FILE_SIZE, + FILE_POSITION, + FILE_END, + FILE_LINE_END, + FILE_IS_COMMON, + FILE_IS_TEXT, + FILE_IS_BINARY, + FILE_IS_CSV, + FILE_IS_ANSI, + FILE_IS_READABLE, + FILE_IS_WRITABLE, +}; +enum ENUM_FILE_OPEN_FLAGS { + FILE_READ = 1, + FILE_WRITE = 2, + FILE_BIN = 4, + FILE_CSV = 8, + FILE_TXT = 16, + FILE_ANSI = 32, + FILE_UNICODE = 64, + FILE_SHARE_READ = 128, + FILE_SHARE_WRITE = 256, + FILE_REWRITE = 512, + FILE_COMMON = 4096, +}; + #endif diff --git a/File.extern.h b/File.extern.h index cc1c63cf6..de79731bf 100644 --- a/File.extern.h +++ b/File.extern.h @@ -22,15 +22,36 @@ // Includes. #include "File.define.h" +#include "Storage/MemoryFileSystem.h" +#include "String.extern.h" #include "Terminal.define.h" // Define external global functions. #ifndef __MQL__ + +MemoryFileSystem _memfs; + extern bool FileIsEnding(int file_handle); + extern bool FileIsExist(const string file_name, int common_flag = 0); -extern int FileClose(int file_handle); -extern int FileOpen(string file_name, int open_flags, short delimiter = '\t', unsigned int codepage = CP_ACP); + +void FileClose(int file_handle) { _memfs.FileClose(file_handle); } + +int FileOpen(string file_name, int open_flags, short delimiter = '\t', unsigned int codepage = CP_ACP) { + return _memfs.FileOpen(file_name, open_flags, delimiter, codepage); +} + extern int FileReadInteger(int file_handle, int size = INT_VALUE); + extern string FileReadString(int file_handle, int length = -1); -extern unsigned int FileWriteString(int file_handle, const string text_string, int length = -1); + +unsigned int FileWriteString(int file_handle, const string text_string, int length = -1) { + return _memfs.FileWrite(file_handle, text_string); +} + +template +unsigned int FileWrite(int file_handle, Arg&& arg, Args&&... args) { + return _memfs.FileWrite(file_handle, arg, args...); +} + #endif diff --git a/File.mqh b/File.mqh index c6e62fb54..7c98322de 100644 --- a/File.mqh +++ b/File.mqh @@ -37,39 +37,6 @@ #include "Terminal.enum.h" #include "Terminal.extern.h" -#ifndef __MQL__ -enum ENUM_FILE_PROPERTY_INTEGER { - FILE_EXISTS, - FILE_CREATE_DATE, - FILE_MODIFY_DATE, - FILE_ACCESS_DATE, - FILE_SIZE, - FILE_POSITION, - FILE_END, - FILE_LINE_END, - FILE_IS_COMMON, - FILE_IS_TEXT, - FILE_IS_BINARY, - FILE_IS_CSV, - FILE_IS_ANSI, - FILE_IS_READABLE, - FILE_IS_WRITABLE, -}; -enum ENUM_FILE_OPEN_FLAGS { - FILE_READ = 1, - FILE_WRITE = 2, - FILE_BIN = 4, - FILE_CSV = 8, - FILE_TXT = 16, - FILE_ANSI = 32, - FILE_UNICODE = 64, - FILE_SHARE_READ = 128, - FILE_SHARE_WRITE = 256, - FILE_REWRITE = 512, - FILE_COMMON = 4096, -}; -#endif - /** * Class to provide a group of functions for working with files. */ diff --git a/Flags.h b/Flags.h index 341eca289..8807629b4 100644 --- a/Flags.h +++ b/Flags.h @@ -20,6 +20,11 @@ * */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + /** * Flags manipulation helper. */ diff --git a/Log.mqh b/Log.mqh index f542b93e7..9930bebd3 100644 --- a/Log.mqh +++ b/Log.mqh @@ -33,6 +33,7 @@ class DictStruct; #include "Collection.mqh" #include "DateTime.mqh" #include "DictStruct.mqh" +#include "File.mqh" #include "Object.mqh" // Define assert macros. diff --git a/Object.mqh b/Object.mqh index b3d471a31..542c73a68 100644 --- a/Object.mqh +++ b/Object.mqh @@ -97,11 +97,6 @@ class Object : public Dynamic { } bool IsDynamic() { return IsDynamic(obj); } - /** - * Returns text representation of the object. - */ - virtual string ToString() { return StringFormat("[Object #%04x]", GetPointer(this)); } - /** * Returns text representation of the object. */ diff --git a/Platform.extern.h b/Platform.extern.h new file mode 100644 index 000000000..87adc94ca --- /dev/null +++ b/Platform.extern.h @@ -0,0 +1,38 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "Platform.h" + +#ifndef __MQL__ + +/** + * Returns number of candles for a given symbol and time-frame. + */ +static int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { return Platform::Bars(_symbol, _tf); } + +#endif diff --git a/Platform.h b/Platform.h index c7db1f1a7..ccbada32f 100644 --- a/Platform.h +++ b/Platform.h @@ -20,6 +20,11 @@ * */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. /** @@ -180,6 +185,14 @@ class Platform { */ static bool IsNewYear() { return (time_flags & DATETIME_YEAR) != 0; } + /** + * Returns number of candles for a given symbol and time-frame. + */ + static int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; + } + /** * Binds Candle and/or Tick indicator as a source of prices or data for given indicator. * @@ -322,8 +335,6 @@ int Platform::global_tick_index = 0; DictStruct> Platform::indis; DictStruct> Platform::indis_dflt; -// void OnTimer() { Print("Timer"); Platform::OnTimer(); } - /** * Will test given indicator class with platform-default data source bindings. */ diff --git a/Refs.mqh b/Refs.mqh index 6df09cd49..4a37f4cf6 100644 --- a/Refs.mqh +++ b/Refs.mqh @@ -130,6 +130,16 @@ class Dynamic { "side."); } } + + /** + * Returns text representation of the object. + */ + virtual string ToString() { + if (ptr_ref_counter == nullptr) return ""; + + return StringFormat("%d strong ref(s) and %d weak ref(s)", ptr_ref_counter PTR_DEREF num_strong_refs, + ptr_ref_counter PTR_DEREF num_weak_refs); + } }; #endif diff --git a/Refs.struct.h b/Refs.struct.h index 3225c782a..0eef226e6 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -282,6 +282,15 @@ struct Ref { * Equality operator. */ bool operator==(const Ref& r) { return ptr_object != NULL && ptr_object == r.ptr_object; } + + /** + * Returns information about object references counter. + */ + string ToString() { + if (ptr_object == nullptr) return "Empty pointer"; + + return ptr_object PTR_DEREF ToString(); + } }; template diff --git a/Std.h b/Std.h index d85cd83ac..59afc3671 100644 --- a/Std.h +++ b/Std.h @@ -296,6 +296,13 @@ class InvalidEnumValue { }; #ifndef __MQL__ +struct _WRONG_VALUE { + template + operator T() { + return (T)-1; + } +} WRONG_VALUE; + // Converter of NULL_VALUE into expected type. e.g., "int x = NULL_VALUE" will end up with "x = 0". struct _NULL_VALUE { template @@ -304,6 +311,20 @@ struct _NULL_VALUE { } } NULL_VALUE; +/** + * Converting an enumeration value of any type to a text form. + * + * @docs + * - https://www.mql5.com/en/docs/convert/enumtostring + */ +string EnumToString(int _value) { + std::stringstream ss; + // We really don't want to mess with type reflection here (if possible at all). So we are outputting the input + // integer. + ss << _value; + return ss.str(); +} + template <> inline _NULL_VALUE::operator const std::string() const { return ""; diff --git a/Storage/MemoryFileSystem.h b/Storage/MemoryFileSystem.h new file mode 100644 index 000000000..bd84d7a68 --- /dev/null +++ b/Storage/MemoryFileSystem.h @@ -0,0 +1,149 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * In-memory file-system used e.g., to create files in C++ and access them in JS via Emscripten. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once + +// Includes. +#include + +#include "../DictStruct.mqh" +#include "../File.define.h" +#include "../String.mqh" + +class MemoryFileSystemFile : public Dynamic { + public: + // FILE_* flags from MQL. + unsigned int flags; + + // Whether file is already opened. + bool opened; + + // MemoryFileSystemFile handle index. + int handle; + + // Auto-incremented handle index. + static unsigned int last_handle; + + // String-based buffer. + string buffer; + + // Current cursor offset. + int offset; + + /** + * Constructor. + */ + MemoryFileSystemFile(string data = "") { + handle = last_handle++; + buffer = data; + } +}; + +unsigned int MemoryFileSystemFile::last_handle = 0; + +class MemoryFileSystem { + // Files by path. + DictStruct> files_by_path; + + // Files by handle. + DictStruct> files_by_handle; + + public: + MemoryFileSystem() { + int _ea_version_handle = FileOpen("EA.txt", FILE_WRITE); + FileWrite(_ea_version_handle, "Hello world!"); + FileClose(_ea_version_handle); + } + + /** + * Opens file for reading/writing and returns its handle. + */ + int FileOpen(string _path, int _flags, short _delimiter = ';', unsigned int codepage = CP_ACP) { + Ref _file; + + if (files_by_path.KeyExists("_path")) { + _file = files_by_path.GetByKey(_path); + + if (_file REF_DEREF opened) { + // MemoryFileSystemFile is already opened. + Print("Error: MemoryFileSystemFile \"" + _path + "\" is already opened!"); + DebugBreak(); + return INVALID_HANDLE; + } + + if ((_flags & FILE_WRITE) != 0) { + // Truncating file. + _file REF_DEREF buffer = ""; + } + } else { + if ((_flags & FILE_READ) != 0) { + // MemoryFileSystemFile doesn't exit. + Print("Error: MemoryFileSystemFile \"" + _path + "\" doesn't exist!"); + DebugBreak(); + return INVALID_HANDLE; + } + + _file = new MemoryFileSystemFile(); + files_by_path.Set(_path, _file); + files_by_handle.Set(_file REF_DEREF handle, _file); + } + + return _file REF_DEREF handle; + } + + /** + * Closes file by the handle given. + */ + void FileClose(int handle) { + if (!files_by_handle.KeyExists(handle)) { + Print("Error: MemoryFileSystemFile handle ", handle, " is not opened!"); + DebugBreak(); + return; + } + + files_by_handle.Unset(handle); + } + + template + unsigned int FileWrite(int file_handle, Arg&& arg, Args&&... args) { + if (!files_by_handle.KeyExists(file_handle)) { + Print("Error: MemoryFileSystemFile handle ", file_handle, " is not opened!"); + DebugBreak(); + return 0; + } + + std::stringstream str; + PrintTo(str, arg, args...); + string data = str.str(); + Ref _file = files_by_handle.GetByKey(file_handle); + _file REF_DEREF buffer += data; + return data.size(); + } +}; + +#endif diff --git a/String.extern.h b/String.extern.h index 55a0f4f78..f4ea595a4 100644 --- a/String.extern.h +++ b/String.extern.h @@ -56,22 +56,14 @@ string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol return std::to_string(number); } -template -struct TuplePrinter { - static void print(const std::string& fmt, std::ostream& os, const Tuple& t) { - const size_t idx = fmt.find_last_of('%'); - TuplePrinter::print(std::string(fmt, 0, idx), os, t); - os << std::get(t) << std::string(fmt, idx + 1); - } -}; - -template -struct TuplePrinter { - static void print(const std::string& fmt, std::ostream& os, const Tuple& t) { - const size_t idx = fmt.find_first_of('%'); - os << std::string(fmt, 0, idx) << std::get<0>(t) << std::string(fmt, idx + 1); - } -}; +template +std::string StringFormat(std::string f, Args&&... args) { + int size = snprintf(nullptr, 0, f.c_str(), args...); + std::string res; + res.resize(size); + snprintf(&res[0], size + 1, f.c_str(), args...); + return res; +} template void PrintTo(std::ostream& out, Arg&& arg, Args&&... args) { @@ -92,14 +84,6 @@ void Alert(Arg&& arg, Args&&... args) { PrintTo(std::cerr, arg, args...); } -template -std::string StringFormat(const std::string& fmt, Args&&... args) { - std::stringstream ss; - const auto t = std::make_tuple(std::forward(args)...); - TuplePrinter::print(fmt, ss, t); - return ss.str(); -} - template void PrintFormat(const std::string& fmt, Args&&... args) { std::cout << StringFormat(fmt, args...) << std::endl; diff --git a/SymbolInfo.mqh b/SymbolInfo.mqh index 50d21311e..259d6caef 100644 --- a/SymbolInfo.mqh +++ b/SymbolInfo.mqh @@ -111,7 +111,7 @@ class SymbolInfo : public Object { */ MqlTick GetTick() { if (!SymbolInfoTick(symbol, last_tick)) { - GetLogger().Error("Cannot return current prices!", __FUNCTION__); + GetLogger() PTR_DEREF Error("Cannot return current prices!", __FUNCTION__); } return last_tick; } @@ -487,7 +487,7 @@ class SymbolInfo : public Object { static int _index = 0; if (_index++ >= ArraySize(tick_data) - 1) { if (ArrayResize(tick_data, _index + 100, 1000) < 0) { - GetLogger().Error(StringFormat("Cannot resize array (size: %d)!", _index), __FUNCTION__); + GetLogger() PTR_DEREF Error(StringFormat("Cannot resize array (size: %d)!", _index), __FUNCTION__); return false; } } diff --git a/SymbolInfo.struct.h b/SymbolInfo.struct.h index ea08ee9af..ba167a187 100644 --- a/SymbolInfo.struct.h +++ b/SymbolInfo.struct.h @@ -32,10 +32,10 @@ // Includes. #include "Serializer/Serializable.h" +#include "Serializer/Serializer.h" #include "Std.h" #include "SymbolInfo.struct.static.h" #include "Tick/Tick.struct.h" -#include "Serializer/Serializer.h" // Defines struct to store symbol data. struct SymbolInfoEntry @@ -58,7 +58,7 @@ struct SymbolInfoEntry spread = (unsigned int)round((ask - bid) * pow(10, SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS))); } // Copy constructor. - SymbolInfoEntry(const SymbolInfoEntry& _sie) { this = _sie; } + SymbolInfoEntry(const SymbolInfoEntry& _sie) { THIS_REF = _sie; } // Getters string ToCSV() { return StringFormat("%g,%g,%g,%g,%d", bid, ask, last, spread, volume); } // Serializers. diff --git a/Task/TaskManager.h b/Task/TaskManager.h index d549cc95f..7f017217a 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -94,7 +94,19 @@ class TaskManager { /** * Clears tasks list. */ - void Clear() { tasks.Clear(); } + void Clear() { + Task *task0 = tasks[0].Ptr(); + + for (int i = 0; i < tasks.Size(); ++i) { + std::cout << "Task #" << i << ": " << tasks[i].ToString() << std::endl; + } + + tasks.Clear(); + + std::cout << "Tasks cleared." << std::endl; + std::cout << task0 PTR_DEREF ToString() << std::endl; + // std::cout.flush(); + } /* Processing methods */ diff --git a/Terminal.enum.h b/Terminal.enum.h index 574615a23..386caf381 100644 --- a/Terminal.enum.h +++ b/Terminal.enum.h @@ -59,26 +59,46 @@ enum ENUM_INIT_RETCODE { #ifndef __MQL__ /** - * Enumeration for the MQL program properties (integer type). + * Enumeration for the MQL5 program properties (integer type). * * @docs * - https://www.mql5.com/en/docs/constants/environment_state/mql5_programm_info */ + enum ENUM_MQL_INFO_INTEGER { - MQL_DEBUG, // Indication that the program is running in the debugging mode (bool). - MQL_DLLS_ALLOWED, // The permission to use DLL for the given running program (bool). - MQL_FORWARD, // Indication that the program is running in the forward testing process (bool). - MQL_FRAME_MODE, // Indication that the program is running in gathering optimization result frames mode (bool). - MQL_LICENSE_TYPE, // Type of license of the EX module. - MQL_MEMORY_LIMIT, // Maximum possible amount of dynamic memory for MQL5 program in MB (int). - MQL_MEMORY_USED, // Memory used by MQL5 program in MB (int). - MQL_OPTIMIZATION, // Indication that the program is running in the optimization mode (bool). - MQL_PROFILER, // Indication that the program is running in the code profiling mode (bool). - MQL_PROGRAM_TYPE, // Type of the MQL5 program (ENUM_PROGRAM_TYPE). - MQL_SIGNALS_ALLOWED, // The permission to modify the Signals for the given running program (bool). - MQL_TESTER, // Indication that the program is running in the tester (bool). - MQL_TRADE_ALLOWED, // The permission to trade for the given running program (bool). - MQL_VISUAL_MODE, // Indication that the program is running in the visual testing mode (bool). + MQL_DEBUG = 5, // Indication that the program is running in the debugging mode (bool). + MQL_DLLS_ALLOWED = 3, // The permission to use DLL for the given running program (bool). + MQL_FORWARD = 16, // Indication that the program is running in the forward testing process (bool). + MQL_FRAME_MODE = 12, // Indication that the program is running in gathering optimization result frames mode (bool). + MQL_HANDLES_USED = 17, // The current number of active object handles. These include both dynamic (created via new) + // and non-dynamic objects, global/local variables or class members. The more handles a + // program uses, the more resources it consumes. + MQL_LICENSE_TYPE = 9, // Type of license of the EX module. + MQL_MEMORY_LIMIT = 13, // Maximum possible amount of dynamic memory for MQL5 program in MB (int). + MQL_MEMORY_USED = 11, // Memory used by MQL5 program in MB (int). + MQL_OPTIMIZATION = 7, // Indication that the program is running in the optimization mode (bool). + MQL_PROFILER = 10, // Indication that the program is running in the code profiling mode (bool). + MQL_PROGRAM_TYPE = 2, // Type of the MQL5 program (ENUM_PROGRAM_TYPE). + MQL_SIGNALS_ALLOWED = 14, // The permission to modify the Signals for the given running program (bool). + MQL_TESTER = 6, // Indication that the program is running in the tester (bool). + MQL_TRADE_ALLOWED = 4, // The permission to trade for the given running program (bool). + MQL_VISUAL_MODE = 8, // Indication that the program is running in the visual testing mode (bool). + + // Additional enumerations for MQL4 compatibility: + + // MQL4: + MQL_CODEPAGE = 128 +}; + +/** + * @docs + * - https://www.mql5.com/en/docs/constants/environment_state/mql5_programm_info#enum_program_type + */ +enum ENUM_PROGRAM_TYPE { + PROGRAM_SCRIPT, // Script. + PROGRAM_EXPERT, // Expert. + PROGRAM_INDICATOR, // Indicator + PROGRAM_SERVICE, // Service. }; /** @@ -88,8 +108,9 @@ enum ENUM_MQL_INFO_INTEGER { * - https://www.mql5.com/en/docs/constants/environment_state/mql5_programm_info */ enum ENUM_MQL_INFO_STRING { - MQL_PROGRAM_NAME, // Name of the running mql5-program (string). - MQL5_PROGRAM_PATH, // Path for the given running program (string). + MQL_PROGRAM_NAME, // Name of the running mql5-program (string). + MQL5_PROGRAM_PATH, // Path for the given running program (string). + MQL_PROGRAM_PATH = MQL5_PROGRAM_PATH // Same as above. }; /** @@ -164,6 +185,17 @@ enum ENUM_TERMINAL_INFO_INTEGER { TERMINAL_X64, // Indication of the "64-bit terminal" (bool). }; +/** + * Enumeration for MQLInfoInteger(MQL_LICENSE_TYPE). + */ +enum ENUM_LICENSE_TYPE { + LICENSE_FREE, // A free unlimited version. + LICENSE_DEMO, // A trial version of a paid product from the Market. It works only in the strategy tester. + LICENSE_FULL, // A purchased licensed version allows at least 5 activations. The number of activations is specified + // by seller. Seller may increase the allowed number of activations. + LICENSE_TIME // A version with limited term liсense. +}; + /** * Enumeration for the Terminal properties (string). * diff --git a/Terminal.extern.h b/Terminal.extern.h index 65582439f..ecb073b2c 100644 --- a/Terminal.extern.h +++ b/Terminal.extern.h @@ -22,7 +22,58 @@ // Define external global functions. #ifndef __MQL__ +#pragma once + +// Includes. +#include "String.mqh" +#include "Terminal.define.h" +#include "Terminal.enum.h" + extern int GetLastError(); extern string TerminalInfoString(int property_id); extern void ResetLastError(); +string MQLInfoString(int property_id) { + switch (property_id) { + case MQL_PROGRAM_NAME: + return "EA"; + case MQL_PROGRAM_PATH: + return ""; + } + return ""; +} + +int MQLInfoInteger(int property_id) { + switch (property_id) { + case MQL_CODEPAGE: + return CP_ACP; + case MQL_PROGRAM_TYPE: + return PROGRAM_EXPERT; + case MQL_DLLS_ALLOWED: + return false; + case MQL_TRADE_ALLOWED: + return true; + case MQL_SIGNALS_ALLOWED: + return true; + case MQL_DEBUG: + return true; + case MQL_PROFILER: + return false; + case MQL_TESTER: + return true; + case MQL_OPTIMIZATION: + return true; + case MQL_VISUAL_MODE: + return false; + case MQL_FRAME_MODE: + return false; + case MQL_LICENSE_TYPE: + return LICENSE_FREE; + } + return -1; +} + +bool _StopFlag = false; + +bool IsStopped() { return _StopFlag; } + #endif From ff982e32bf1a56f887cb2252beccf96ed1835d20 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 9 Jan 2023 19:39:57 +0100 Subject: [PATCH 051/123] WIP. End up with include loop. --- Dict.mqh | 101 +++---- Draw.mqh | 36 +-- File.extern.h | 1 + File.mqh | 5 + Indicator/Indicator.define.h | 4 +- Indicator/IndicatorBase.h | 5 +- Indicator/IndicatorData.h | 6 +- Indicators/Tick/Indi_TickRandom.mqh | 1 - Math.extern.h | 2 + Matrix.mqh | 18 +- MiniMatrix.h | 2 +- Object.extern.h | 60 +++++ Orders.mqh | 1 - Platform.h | 18 ++ Serializer/SerializerCsv.h | 125 ++++----- Std.h | 6 + Storage/ValueStorage.h | 28 +- Storage/ValueStorage.history.h | 1 - Storage/ValueStorage.spread.h | 1 - String.extern.h | 26 ++ Terminal.define.h | 398 +++++++++++++++++++--------- Trade.mqh | 1 - 22 files changed, 551 insertions(+), 295 deletions(-) diff --git a/Dict.mqh b/Dict.mqh index 56f894fdc..923e63575 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -26,6 +26,7 @@ #include "Convert.basic.h" #include "DictBase.mqh" +#include "DictIteratorBase.mqh" #include "Matrix.mqh" #include "Serializer/Serializer.h" #include "Serializer/SerializerNodeIterator.h" @@ -41,12 +42,12 @@ class DictIterator : public DictIteratorBase { /** * Constructor. */ - DictIterator(DictBase& dict, unsigned int slotIdx) : DictIteratorBase(dict, slotIdx) {} + DictIterator(DictBase& dict, unsigned int slotIdx) : DictIteratorBase(dict, slotIdx) {} /** * Copy constructor. */ - DictIterator(const DictIterator& right) : DictIteratorBase(right) {} + DictIterator(const DictIterator& right) : DictIteratorBase(right) {} }; /** @@ -70,37 +71,37 @@ class Dict : public DictBase { Clear(); Resize(right.GetSlotCount()); for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; + THIS_ATTR _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; } - _DictSlots_ref._num_used = right._DictSlots_ref._num_used; - _current_id = right._current_id; - _mode = right._mode; + THIS_ATTR _DictSlots_ref._num_used = right._DictSlots_ref._num_used; + THIS_ATTR _current_id = right._current_id; + THIS_ATTR _mode = right._mode; } void operator=(const Dict& right) { Clear(); Resize(right.GetSlotCount()); for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; + THIS_ATTR _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; } - _DictSlots_ref._num_used = right._DictSlots_ref._num_used; - _current_id = right._current_id; - _mode = right._mode; + THIS_ATTR _DictSlots_ref._num_used = right._DictSlots_ref._num_used; + THIS_ATTR _current_id = right._current_id; + THIS_ATTR _mode = right._mode; } void Clear() { - for (unsigned int i = 0; i < (unsigned int)ArraySize(_DictSlots_ref.DictSlots); ++i) { - if (_DictSlots_ref.DictSlots[i].IsUsed()) _DictSlots_ref.DictSlots[i].SetFlags(0); + for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { + if (THIS_ATTR _DictSlots_ref.DictSlots[i].IsUsed()) THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); } - _DictSlots_ref._num_used = 0; + THIS_ATTR _DictSlots_ref._num_used = 0; } /** * Inserts value using hashless key. */ bool Push(V value) { - if (!InsertInto(_DictSlots_ref, value)) return false; + if (!InsertInto(THIS_ATTR _DictSlots_ref, value)) return false; return true; } @@ -113,15 +114,15 @@ class Dict : public DictBase { * Inserts or replaces value for a given key. */ bool Set(K key, V value) { - if (!InsertInto(_DictSlots_ref, key, value, true)) return false; + if (!InsertInto(THIS_ATTR _DictSlots_ref, key, value, true)) return false; return true; } V operator[](K key) { - if (_mode == DictModeList) return GetSlot((unsigned int)key).value; + if (THIS_ATTR _mode == DictModeList) return THIS_ATTR GetSlot((unsigned int)key).value; int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, key, position); + DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); if (!slot) return (V)NULL; @@ -136,7 +137,7 @@ class Dict : public DictBase { */ V GetByKey(const K _key, V _default = NULL) { unsigned int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, _key, position); + DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); if (!slot) { return _default; @@ -149,7 +150,7 @@ class Dict : public DictBase { * Returns value for a given position. */ V GetByPos(unsigned int _position) { - DictSlot* slot = GetSlotByPos(_DictSlots_ref, _position); + DictSlot* slot = GetSlotByPos(THIS_ATTR _DictSlots_ref, _position); if (!slot) { Alert("Invalid DictStruct position \"", _position, "\" (called by GetByPos()). Returning empty structure."); @@ -164,10 +165,12 @@ class Dict : public DictBase { /** * Checks whether dictionary contains given key => value pair. */ +#ifdef __MQL__ template <> +#endif bool Contains(const K key, const V value) { unsigned int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, key, position); + DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); if (!slot) return false; @@ -177,9 +180,11 @@ class Dict : public DictBase { /** * Returns index of dictionary's value or -1 if value doesn't exist. */ +#ifdef __MQL__ template <> +#endif int IndexOf(V& value) { - for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + for (DictIteratorBase i(THIS_ATTR Begin()); i.IsValid(); ++i) { if (i.Value() == value) { return (int)i.Index(); } @@ -192,7 +197,7 @@ class Dict : public DictBase { * Checks whether dictionary contains given value. */ bool Contains(const V value) { - for (DictIterator i = Begin(); i.IsValid(); ++i) { + for (DictIterator i = THIS_ATTR Begin(); i.IsValid(); ++i) { if (i.Value() == value) { return true; } @@ -232,7 +237,7 @@ class Dict : public DictBase { if ((_is_full || !_is_performant) && allow_resize) { // We have to resize the dict as it is either full or have perfomance problems due to massive number of conflicts // when inserting new values. - if (overflow_listener == NULL) { + if (THIS_ATTR overflow_listener == NULL) { // There is no overflow listener so we can freely grow up the dict. if (!GrowUp()) { // Can't resize the dict. Error happened. @@ -240,8 +245,9 @@ class Dict : public DictBase { } } else { // Overflow listener will decide if we can grow up the dict. - if (overflow_listener(_is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, - dictSlotsRef._num_used, 0)) { + if (THIS_ATTR overflow_listener( + _is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, + dictSlotsRef._num_used, 0)) { // We can freely grow up the dict. if (!GrowUp()) { // Can't resize the dict. Error happened. @@ -268,11 +274,12 @@ class Dict : public DictBase { (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { ++_num_conflicts; - if (overflow_listener != NULL) { + if (THIS_ATTR overflow_listener != NULL) { // We had to skip slot as it is already occupied. Now we are checking if // there is too many conflicts/skips and thus we can overwrite slot in // the starting position. - if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + if (THIS_ATTR overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, + _num_conflicts)) { // Looks like dict is working as buffer and we can overwrite slot in the starting position. position = _starting_position; break; @@ -309,9 +316,9 @@ class Dict : public DictBase { * Inserts hashless value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, V value) { - if (_mode == DictModeUnknown) - _mode = DictModeList; - else if (_mode != DictModeList) { + if (THIS_ATTR _mode == DictModeUnknown) + THIS_ATTR _mode = DictModeList; + else if (THIS_ATTR _mode != DictModeList) { Alert("Warning: Dict already operates as a dictionary, not a list!"); DebugBreak(); return false; @@ -322,7 +329,7 @@ class Dict : public DictBase { if (!GrowUp()) return false; } - unsigned int position = Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); + unsigned int position = THIS_ATTR Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); // Searching for empty DictSlot. while (dictSlotsRef.DictSlots[position].IsUsed()) { @@ -342,14 +349,15 @@ class Dict : public DictBase { * Expands array of DictSlots by given percentage value. */ bool GrowUp(int percent = DICT_GROW_UP_PERCENT_DEFAULT) { - return Resize(MathMax(10, (int)((float)ArraySize(_DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); + return Resize( + MathMax(10, (int)((float)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } /** * Shrinks or expands array of DictSlots. */ bool Resize(int new_size) { - if (new_size <= MathMin(_DictSlots_ref._num_used, ArraySize(_DictSlots_ref.DictSlots))) { + if (new_size <= MathMin(THIS_ATTR _DictSlots_ref._num_used, ArraySize(THIS_ATTR _DictSlots_ref.DictSlots))) { // We already use minimum number of slots possible. return true; } @@ -367,36 +375,37 @@ class Dict : public DictBase { new_DictSlots._num_used = 0; // Copies entire array of DictSlots into new array of DictSlots. Hashes will be rehashed. - for (i = 0; i < ArraySize(_DictSlots_ref.DictSlots); ++i) { - if (!_DictSlots_ref.DictSlots[i].IsUsed()) continue; + for (i = 0; i < ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { + if (!THIS_ATTR _DictSlots_ref.DictSlots[i].IsUsed()) continue; - if (_DictSlots_ref.DictSlots[i].HasKey()) { - if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].key, _DictSlots_ref.DictSlots[i].value, false)) + if (THIS_ATTR _DictSlots_ref.DictSlots[i].HasKey()) { + if (!InsertInto(new_DictSlots, THIS_ATTR _DictSlots_ref.DictSlots[i].key, + THIS_ATTR _DictSlots_ref.DictSlots[i].value, false)) return false; } else { - if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].value)) return false; + if (!InsertInto(new_DictSlots, THIS_ATTR _DictSlots_ref.DictSlots[i].value)) return false; } } // Freeing old DictSlots array. - ArrayFree(_DictSlots_ref.DictSlots); + ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots); - _DictSlots_ref = new_DictSlots; + THIS_ATTR _DictSlots_ref = new_DictSlots; return true; } public: -#ifdef __cplusplus +#ifdef __MQL__ template <> #endif SerializerNodeType Serialize(Serializer& s) { if (s.IsWriting()) { - for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + for (DictIteratorBase i(THIS_ATTR Begin()); i.IsValid(); ++i) { V value = i.Value(); - s.Pass(THIS_REF, GetMode() == DictModeDict ? i.KeyAsString() : "", value); + s.Pass(THIS_REF, THIS_ATTR GetMode() == DictModeDict ? i.KeyAsString() : "", value); } - return (GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray; + return (THIS_ATTR GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray; } else { SerializerIterator i; @@ -432,9 +441,9 @@ class Dict : public DictBase { */ template Matrix* ToMatrix() { - Matrix* result = new Matrix(Size()); + Matrix* result = new Matrix(THIS_ATTR Size()); - for (DictIterator i = Begin(); i.IsValid(); ++i) result[i.Index()] = (X)i.Value(); + for (DictIterator i = THIS_ATTR Begin(); i.IsValid(); ++i) result[i.Index()] = (X)i.Value(); return result; } diff --git a/Draw.mqh b/Draw.mqh index 5c2fcca9e..3fb403904 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -30,8 +30,10 @@ class Chart; class Draw; // Includes. -#include "Chart.mqh" #include "Data.define.h" +#include "Object.extern.h" +#include "Platform.h" +#include "Terminal.define.h" #ifndef __MQL4__ // Defines macros (for MQL4 backward compatibility). @@ -41,21 +43,6 @@ class Draw; #define SetIndexShift(_index, _value) (PlotIndexSetInteger(_index, PLOT_SHIFT, _value)) #endif -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compatibility). -bool ObjectCreate(string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { - return Draw::ObjectCreate(0, _name, _otype, _swindow, _t1, _p1); -} -bool ObjectDelete(string _name) { return Draw::ObjectDelete(_name); } -bool ObjectSet(string _name, int _prop_id, double _value) { return Draw::ObjectSet(_name, _prop_id, _value); } -int ObjectsTotal(int _type = EMPTY) { return Draw::ObjectsTotal(); } -string ObjectName(int _index) { return Draw::ObjectName(_index); } -void SetIndexLabel(int _index, string _text) { Draw::SetIndexLabel(_index, _text); } -void SetIndexStyle(int _index, int _type, int _style = EMPTY, int _width = EMPTY, color _clr = CLR_NONE) { - Draw::SetIndexStyle(_index, _type, _style, _width, _clr); -} -#endif - #define WINDOW_MAIN 0 #ifdef __MQL5__ @@ -85,7 +72,7 @@ class Draw : public Object { /** * Class constructor. */ - Draw(long _chart_id = 0) : chart_id(_chart_id != 0 ? _chart_id : ChartID()) {} + Draw(long _chart_id = 0) : chart_id(_chart_id != 0 ? _chart_id : Platform::ChartID()) {} /* Graphic object related methods */ @@ -335,3 +322,18 @@ class Draw : public Object { return true; } }; + +#ifndef __MQL4__ +// Defines global functions (for MQL4 backward compatibility). +bool ObjectCreate(string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { + return Draw::ObjectCreate(0, _name, _otype, _swindow, _t1, _p1); +} +bool ObjectDelete(string _name) { return Draw::ObjectDelete(_name); } +bool ObjectSet(string _name, int _prop_id, double _value) { return Draw::ObjectSet(_name, _prop_id, _value); } +int ObjectsTotal(int _type = EMPTY) { return Draw::ObjectsTotal(); } +string ObjectName(int _index) { return Draw::ObjectName(_index); } +void SetIndexLabel(int _index, string _text) { Draw::SetIndexLabel(_index, _text); } +void SetIndexStyle(int _index, int _type, int _style = EMPTY, int _width = EMPTY, color _clr = CLR_NONE) { + Draw::SetIndexStyle(_index, _type, _style, _width, _clr); +} +#endif diff --git a/File.extern.h b/File.extern.h index de79731bf..ca4e965b5 100644 --- a/File.extern.h +++ b/File.extern.h @@ -28,6 +28,7 @@ // Define external global functions. #ifndef __MQL__ +#pragma once MemoryFileSystem _memfs; diff --git a/File.mqh b/File.mqh index 7c98322de..fc840d1a7 100644 --- a/File.mqh +++ b/File.mqh @@ -29,6 +29,11 @@ * - Files with which file operations are conducted means cannot be outside the file sandbox. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. #include "File.define.h" #include "File.extern.h" diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index 3d1a65c24..d0e2900df 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -35,8 +35,8 @@ #define DUMMY #define ICUSTOM_DEF(SET_HANDLE, PARAMS) \ - double _res[]; \ - if (_handle == NULL || _handle == INVALID_HANDLE) { \ + ARRAY(double, _res); \ + if (_handle == 0 || _handle == INVALID_HANDLE) { \ if ((_handle = ::iCustom(_symbol, _tf, _name PARAMS)) == INVALID_HANDLE) { \ SetUserError(ERR_USER_INVALID_HANDLE); \ return EMPTY_VALUE; \ diff --git a/Indicator/IndicatorBase.h b/Indicator/IndicatorBase.h index ff1327cb2..3dede1258 100644 --- a/Indicator/IndicatorBase.h +++ b/Indicator/IndicatorBase.h @@ -34,11 +34,10 @@ #include "../Array.mqh" #include "../BufferStruct.mqh" #include "../Chart.struct.tf.h" -//#include "../ChartBase.h" -#include "../ChartMt.h" #include "../DateTime.mqh" #include "../Log.mqh" #include "../Object.mqh" +#include "../Platform.extern.h" #include "../Refs.mqh" #include "../Serializer/Serializer.h" #include "../Serializer/SerializerCsv.h" @@ -192,7 +191,7 @@ class IndicatorBase : public Object { /** * Get name of the indicator. */ - virtual string GetName() = NULL; + virtual string GetName() = 0; /** * Get full name of the indicator (with "over ..." part). diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 58776bff9..78b5bb1f1 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -31,15 +31,13 @@ // Forward class declaration. class IndicatorBase; +class IndicatorDraw; // Includes. #include "../Bar.struct.h" -#include "../DrawIndicator.mqh" #include "../Flags.h" +#include "../Storage/IValueStorage.h" #include "../Storage/ItemsHistory.h" -#include "../Storage/ValueStorage.h" -#include "../Storage/ValueStorage.indicator.h" -#include "../Storage/ValueStorage.native.h" #include "../SymbolInfo.struct.h" #include "Indicator.enum.h" #include "IndicatorBase.h" diff --git a/Indicators/Tick/Indi_TickRandom.mqh b/Indicators/Tick/Indi_TickRandom.mqh index c3b3a6253..56e8148c5 100644 --- a/Indicators/Tick/Indi_TickRandom.mqh +++ b/Indicators/Tick/Indi_TickRandom.mqh @@ -31,7 +31,6 @@ #endif // Includes. -#include "../../Chart.struct.static.h" #include "../../Indicator/IndicatorTick.h" #include "../../Indicator/IndicatorTick.provider.h" diff --git a/Math.extern.h b/Math.extern.h index a19b60b13..7965fd1f3 100644 --- a/Math.extern.h +++ b/Math.extern.h @@ -75,4 +75,6 @@ template T log10(T value) { return std::log10(value); } +int MathRand() { return std::rand() % 32768; } +int rand() { return std::rand() % 32768; } #endif diff --git a/Matrix.mqh b/Matrix.mqh index 59f3eef39..de0f7177c 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -282,7 +282,7 @@ class MatrixDimension { /** * Sets physical position of the dimension in the matrix. */ - void SetPosition(int& _position[], int _level) { + void SetPosition(ARRAY_REF(int, _position), int _level) { for (int i = 0; i < ArraySize(_position); ++i) { position[i] = i < _level ? _position[i] : -1; } @@ -472,8 +472,8 @@ class MatrixDimension { * * @todo Allow of resizing containers instead of freeing them firstly. */ - static MatrixDimension* SetDimensions(MatrixDimension* _ptr_parent_dimension, int& _dimensions[], int index, - int& _current_position[]) { + static MatrixDimension* SetDimensions(MatrixDimension* _ptr_parent_dimension, ARRAY_REF(int, _dimensions), + int index, ARRAY_REF(int, _current_position)) { if (_ptr_parent_dimension == NULL) _ptr_parent_dimension = new MatrixDimension(); if (index == 0 && _dimensions[0] == 0) { @@ -634,7 +634,7 @@ class MatrixDimension { /** * Extracts dimensions's values to the given array. Used internally. */ - void FillArray(X& array[], int& offset) { + void FillArray(ARRAY_REF(X, array), int& offset) { int i; if (type == MATRIX_DIMENSION_TYPE_CONTAINERS) { for (i = 0; i < ArraySize(containers); ++i) { @@ -647,7 +647,7 @@ class MatrixDimension { } } - void FromArray(X& _array[], int& offset) { + void FromArray(ARRAY_REF(X, _array), int& offset) { int i; switch (type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: @@ -1378,7 +1378,7 @@ class Matrix { /** * Fills array with all values from the matrix. */ - void GetRawArray(X& array[]) { + void GetRawArray(ARRAY_REF(X, array)) { ArrayResize(array, GetSize()); int offset = 0; ptr_first_dimension.FillArray(array, offset); @@ -1425,7 +1425,7 @@ class Matrix { } #endif - void FillFromArray(X& _array[]) { + void FillFromArray(ARRAY_REF(X, _array)) { if (ArraySize(_array) != GetSize()) { Print("Matrix::FillFromArray(): input array (", ArraySize(_array), " elements) must be the same size as matrix (", GetSize(), " elements)!"); @@ -1908,10 +1908,10 @@ class Matrix { return GetDimensionsTotal(_dimensions); } - static int GetDimensionsTotal(int& dimensions[]) { + static int GetDimensionsTotal(FIXED_ARRAY_REF(int, dimensions, MATRIX_DIMENSIONS)) { int size = 0; - for (int i = 0; i < ArraySize(dimensions); ++i) { + for (int i = 0; i < MATRIX_DIMENSIONS; ++i) { if (dimensions[i] != 0) { if (size == 0) { size = 1; diff --git a/MiniMatrix.h b/MiniMatrix.h index 3ceaaa5ab..14560235f 100644 --- a/MiniMatrix.h +++ b/MiniMatrix.h @@ -27,7 +27,7 @@ template class MiniMatrix2d { public: - T data[]; + ARRAY(T, data); int size_x; int size_y; diff --git a/Object.extern.h b/Object.extern.h index 0b4bd3e35..8490e9499 100644 --- a/Object.extern.h +++ b/Object.extern.h @@ -25,6 +25,9 @@ * Includes external declarations related to objects. */ #ifndef __MQL__ + +#pragma once + template X* GetPointer(X& value) { return &value; @@ -33,4 +36,61 @@ template X* GetPointer(X* ptr) { return ptr; } + +template +ENUM_POINTER_TYPE CheckPointer(X& value) { + return (&value) != nullptr ? POINTER_DYNAMIC : POINTER_INVALID; +} +template +ENUM_POINTER_TYPE CheckPointer(X* ptr) { + return ptr != nullptr ? POINTER_DYNAMIC : POINTER_INVALID; +} + +enum ENUM_OBJECT { + OBJ_VLINE = 0, // Vertical Line + OBJ_HLINE = 1, // Horizontal Line + OBJ_TREND = 2, // Trend Line + OBJ_TRENDBYANGLE = 3, // Trend Line By Angle + OBJ_CYCLES = 4, // Cycle Lines + OBJ_ARROWED_LINE = 108, // Arrowed Line + OBJ_CHANNEL = 5, // Equidistant Channel + OBJ_STDDEVCHANNEL = 6, // Standard Deviation Channel + OBJ_REGRESSION = 7, // Linear Regression Channel + OBJ_PITCHFORK = 8, // Andrews’ Pitchfork + OBJ_GANNLINE = 9, // Gann Line + OBJ_GANNFAN = 10, // Gann Fan + OBJ_GANNGRID = 11, // Gann Grid + OBJ_FIBO = 12, // Fibonacci Retracement + OBJ_FIBOTIMES = 13, // Fibonacci Time Zones + OBJ_FIBOFAN = 14, // Fibonacci Fan + OBJ_FIBOARC = 15, // Fibonacci Arcs + OBJ_FIBOCHANNEL = 16, // Fibonacci Channel + OBJ_EXPANSION = 17, // Fibonacci Expansion + OBJ_ELLIOTWAVE5 = 18, // Elliott Motive Wave + OBJ_ELLIOTWAVE3 = 19, // Elliott Correction Wave + OBJ_RECTANGLE = 20, // Rectangle + OBJ_TRIANGLE = 21, // Triangle + OBJ_ELLIPSE = 22, // Ellipse + OBJ_ARROW_THUMB_UP = 23, // Thumbs Up + OBJ_ARROW_THUMB_DOWN = 24, // Thumbs Down + OBJ_ARROW_UP = 25, // Arrow Up + OBJ_ARROW_DOWN = 26, // Arrow Down + OBJ_ARROW_STOP = 27, // Stop Sign + OBJ_ARROW_CHECK = 28, // Check Sign + OBJ_ARROW_LEFT_PRICE = 29, // Left Price Label + OBJ_ARROW_RIGHT_PRICE = 30, // Right Price Label + OBJ_ARROW_BUY = 31, // Buy Sign + OBJ_ARROW_SELL = 32, // Sell Sign + OBJ_ARROW = 100, // Arrow + OBJ_TEXT = 101, // Text + OBJ_LABEL = 102, // Label + OBJ_BUTTON = 103, // Button + OBJ_CHART = 104, // Chart + OBJ_BITMAP = 105, // Bitmap + OBJ_BITMAP_LABEL = 106, // Bitmap Label + OBJ_EDIT = 107, // Edit + OBJ_EVENT = 109, // The "Event" object corresponding to an event in the economic calendar + OBJ_RECTANGLE_LABEL = 110 // The "Rectangle label" object for creating and designing the custom graphical interface. +}; + #endif diff --git a/Orders.mqh b/Orders.mqh index 2b5ca4057..906f018a6 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -25,7 +25,6 @@ class Orders; // Includes. #include "Account/Account.h" -#include "Chart.mqh" #include "Log.mqh" #include "Math.h" #include "Order.mqh" diff --git a/Platform.h b/Platform.h index ccbada32f..f0da9db31 100644 --- a/Platform.h +++ b/Platform.h @@ -25,6 +25,19 @@ #pragma once #endif +#ifndef __MQL__ + +/** + * Extern declarations for C++. + */ + +/** + * Returns number of candles for a given symbol and time-frame. + */ +extern int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf); + +#endif + // Includes. /** @@ -193,6 +206,11 @@ class Platform { return 0; } + /** + * Returns id of the current chart. + */ + static int ChartID() { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); } + /** * Binds Candle and/or Tick indicator as a source of prices or data for given indicator. * diff --git a/Serializer/SerializerCsv.h b/Serializer/SerializerCsv.h index 85992b779..aea45d535 100644 --- a/Serializer/SerializerCsv.h +++ b/Serializer/SerializerCsv.h @@ -55,12 +55,12 @@ class SerializerCsv { SerializerConverter* _stub = (SerializerConverter*)serializer_aux_arg; if (CheckPointer(_root) == POINTER_INVALID) { - Alert("SerializerCsv: Invalid root node poiner!"); + Alert("SerializerCsv: Invalid root node pointer!"); DebugBreak(); return NULL; } - if (_stub == NULL || _stub.Node() == NULL) { + if (_stub == NULL || _stub PTR_DEREF Node() == NULL) { Alert("SerializerCsv: Cannot convert to CSV without stub object!"); DebugBreak(); return NULL; @@ -72,12 +72,13 @@ class SerializerCsv { unsigned int _num_columns, _num_rows; int x, y; - if (_stub.Node().IsArray()) { - _num_columns = _stub.Node().MaximumNumChildrenInDeepEnd(); - _num_rows = _root.NumChildren(); + if (_stub PTR_DEREF Node() PTR_DEREF IsArray()) { + _num_columns = _stub PTR_DEREF Node() PTR_DEREF MaximumNumChildrenInDeepEnd(); + _num_rows = _root PTR_DEREF NumChildren(); } else { - _num_columns = MathMax(_stub.Node().MaximumNumChildrenInDeepEnd(), _root.MaximumNumChildrenInDeepEnd()); - _num_rows = _root.NumChildren() > 0 ? 1 : 0; + _num_columns = MathMax(_stub PTR_DEREF Node() PTR_DEREF MaximumNumChildrenInDeepEnd(), + _root PTR_DEREF MaximumNumChildrenInDeepEnd()); + _num_rows = _root PTR_DEREF NumChildren() > 0 ? 1 : 0; } if (_include_titles) { @@ -100,61 +101,61 @@ class SerializerCsv { _column_types_out = &_column_types; } - _matrix_out.Resize(_num_columns, _num_rows); - _column_types_out.Resize(_num_columns, 1); + _matrix_out PTR_DEREF Resize(_num_columns, _num_rows); + _column_types_out PTR_DEREF Resize(_num_columns, 1); if (_include_titles) { _column_titles.Resize(_num_columns, 1); int _titles_current_column = 0; - SerializerCsv::ExtractColumns(_stub.Node(), &_column_titles, _column_types_out, serializer_flags, + SerializerCsv::ExtractColumns(_stub PTR_DEREF Node(), &_column_titles, _column_types_out, serializer_flags, _titles_current_column); - for (x = 0; x < _matrix_out.SizeX(); ++x) { - _matrix_out.Set(x, 0, EscapeString(_column_titles.Get(x, 0))); + for (x = 0; x < _matrix_out PTR_DEREF SizeX(); ++x) { + _matrix_out PTR_DEREF Set(x, 0, EscapeString(_column_titles.Get(x, 0))); } } #ifdef __debug__ - Print("Stub: ", _stub.Node().ToString()); - Print("Data: ", _root.ToString()); + Print("Stub: ", _stub PTR_DEREF Node() PTR_DEREF ToString()); + Print("Data: ", _root PTR_DEREF ToString()); Print("Size: ", _num_columns, " x ", _num_rows); #endif - if (!SerializerCsv::FlattenNode(_root, _stub.Node(), _matrix_out, _column_types_out, _include_key ? 1 : 0, - _include_titles ? 1 : 0, serializer_flags)) { + if (!SerializerCsv::FlattenNode(_root, _stub PTR_DEREF Node(), PTR_TO_REF(_matrix_out), _column_types_out, + _include_key ? 1 : 0, _include_titles ? 1 : 0, serializer_flags)) { Alert("SerializerCsv: Error occured during flattening!"); } string _result; - for (y = 0; y < _matrix_out.SizeY(); ++y) { - for (x = 0; x < _matrix_out.SizeX(); ++x) { - _result += _matrix_out.Get(x, y); + for (y = 0; y < _matrix_out PTR_DEREF SizeY(); ++y) { + for (x = 0; x < _matrix_out PTR_DEREF SizeX(); ++x) { + _result += _matrix_out PTR_DEREF Get(x, y); - if (x != _matrix_out.SizeX() - 1) { + if (x != _matrix_out PTR_DEREF SizeX() - 1) { _result += ","; } } - if (y != _matrix_out.SizeY() - 1) _result += "\n"; + if (y != _matrix_out PTR_DEREF SizeY() - 1) _result += "\n"; } if ((serializer_flags & SERIALIZER_FLAG_REUSE_STUB) == 0) { - _stub.Clean(); + _stub PTR_DEREF Clean(); } return _result; } static string ParamToString(SerializerNodeParam* param) { - switch (param.GetType()) { + switch (param PTR_DEREF GetType()) { case SerializerNodeParamBool: case SerializerNodeParamLong: case SerializerNodeParamDouble: - return param.AsString(false, false, false, param.GetFloatingPointPrecision()); + return param PTR_DEREF AsString(false, false, false, param PTR_DEREF GetFloatingPointPrecision()); case SerializerNodeParamString: - return EscapeString(param.AsString(false, false, false, param.GetFloatingPointPrecision())); + return EscapeString(param PTR_DEREF AsString(false, false, false, param PTR_DEREF GetFloatingPointPrecision())); default: - Print("Error: Wrong param type ", EnumToString(param.GetType()), "!"); + Print("Error: Wrong param type ", EnumToString(param PTR_DEREF GetType()), "!"); DebugBreak(); } @@ -173,12 +174,12 @@ class SerializerCsv { */ static void ExtractColumns(SerializerNode* _stub, MiniMatrix2d* _titles, MiniMatrix2d* _column_types, int _flags, int& _column) { - for (unsigned int _stub_entry_idx = 0; _stub_entry_idx < _stub.NumChildren(); ++_stub_entry_idx) { - SerializerNode* _child = _stub.GetChild(_stub_entry_idx); - if (_child.IsContainer()) { + for (unsigned int _stub_entry_idx = 0; _stub_entry_idx < _stub PTR_DEREF NumChildren(); ++_stub_entry_idx) { + SerializerNode* _child = _stub PTR_DEREF GetChild(_stub_entry_idx); + if (_child PTR_DEREF IsContainer()) { ExtractColumns(_child, _titles, _column_types, _flags, _column); - } else if (_child.HasKey()) { - _titles.Set(_column++, 0, _child.Key()); + } else if (_child PTR_DEREF HasKey()) { + _titles PTR_DEREF Set(_column++, 0, _child PTR_DEREF Key()); } } } @@ -192,31 +193,31 @@ class SerializerCsv { bool _include_key = bool(_flags & SERIALIZER_CSV_INCLUDE_KEY); - if (_stub.IsArray()) { - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { + if (_stub PTR_DEREF IsArray()) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { if (_include_key) { // Adding object's key in the first row. - SerializerNode* _child = _data.GetChild(_data_entry_idx); - string key = _child.HasKey() ? _child.Key() : ""; + SerializerNode* _child = _data PTR_DEREF GetChild(_data_entry_idx); + string key = _child PTR_DEREF HasKey() ? _child PTR_DEREF Key() : ""; _cells.Set(0, _row + _data_entry_idx, key); } - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), _stub.GetChild(0), _cells, _column_types, _column, - _row + _data_entry_idx, 0, 0, _flags)) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), _stub PTR_DEREF GetChild(0), _cells, + _column_types, _column, _row + _data_entry_idx, 0, 0, _flags)) { return false; } } - } else if (_stub.IsObject()) { + } else if (_stub PTR_DEREF IsObject()) { // Object means that there is only one row. - if (_data.IsArray()) { + if (_data PTR_DEREF IsArray()) { // Stub is an object, but data is an array (should be?). - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), _stub, _cells, _column_types, _column, _row, 0, - 0, _flags)) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), _stub, _cells, _column_types, _column, + _row, 0, 0, _flags)) { return false; } - _column += (int)_stub.GetChild(_data_entry_idx).MaximumNumChildrenInDeepEnd(); + _column += (int)_stub PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF MaximumNumChildrenInDeepEnd(); } } else { // Stub and object are both arrays. @@ -237,34 +238,34 @@ class SerializerCsv { int _level, int _flags) { unsigned int _data_entry_idx, _entry_size; - if (_stub.IsObject()) { - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { - if (_stub.NumChildren() == 0) { - Print("Stub is empty for object representation of: ", _data.ToString(false, 2)); + if (_stub PTR_DEREF IsObject()) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { + if (_stub PTR_DEREF NumChildren() == 0) { + Print("Stub is empty for object representation of: ", _data PTR_DEREF ToString(false, 2)); Print( "Note that if you're serializing a dictionary, your stub must contain a single, dummy key and maximum " "possible object representation."); - Print("Missing key \"", _data.Key(), "\" in stub."); + Print("Missing key \"", _data PTR_DEREF Key(), "\" in stub."); DebugBreak(); } - _entry_size = MathMax(_stub.GetChild(_data_entry_idx).TotalNumChildren(), - _data.GetChild(_data_entry_idx).TotalNumChildren()); + _entry_size = MathMax(_stub PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren(), + _data PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren()); - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), - _stub != NULL ? _stub.GetChild(_data_entry_idx) : NULL, _cells, _column_types, - _column, _row, _data_entry_idx, _level + 1, _flags)) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), + _stub != NULL ? _stub PTR_DEREF GetChild(_data_entry_idx) : NULL, _cells, + _column_types, _column, _row, _data_entry_idx, _level + 1, _flags)) { return false; } _column += (int)_entry_size; } - } else if (_stub.IsArray()) { - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { - _entry_size = MathMax(_stub.GetChild(_data_entry_idx).TotalNumChildren(), - _data.GetChild(_data_entry_idx).TotalNumChildren()); + } else if (_stub PTR_DEREF IsArray()) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { + _entry_size = MathMax(_stub PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren(), + _data PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren()); - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), _stub.GetChild(0), _cells, _column_types, _column, - _row, _data_entry_idx, _level + 1, _flags)) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), _stub PTR_DEREF GetChild(0), _cells, + _column_types, _column, _row, _data_entry_idx, _level + 1, _flags)) { return false; } @@ -277,14 +278,14 @@ class SerializerCsv { bool _include_titles_tree = (_flags & SERIALIZER_CSV_INCLUDE_TITLES_TREE) == SERIALIZER_CSV_INCLUDE_TITLES_TREE; if (_column_types != NULL) { - if (_data.GetValueParam() == NULL) { + if (_data PTR_DEREF GetValueParam() == NULL) { Alert("Error: Expected value here! Stub is probably initialized without proper structure."); DebugBreak(); } - _column_types.Set(_column, 0, _data.GetValueParam().GetType()); + _column_types PTR_DEREF Set(_column, 0, _data PTR_DEREF GetValueParam() PTR_DEREF GetType()); } - _cells.Set(_column, _row, ParamToString(_data.GetValueParam())); + _cells.Set(_column, _row, ParamToString(_data PTR_DEREF GetValueParam())); } return true; diff --git a/Std.h b/Std.h index 59afc3671..8337ec71d 100644 --- a/Std.h +++ b/Std.h @@ -34,6 +34,10 @@ #include #endif +#ifndef __MQL__ +#define __FUNCSIG__ __FUNCTION__ +#endif + #ifdef __MQL__ #define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE)this) = ((TYPE)VALUE) #else @@ -93,6 +97,7 @@ * ARRAY_REF(, ) */ #define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS +#define FIXED_ARRAY_REF(T, N, S) ARRAY_REF(T, N) #define CONST_ARRAY_REF(T, N) const N ARRAY_DECLARATION_BRACKETS @@ -118,6 +123,7 @@ * ARRAY_REF(, ) */ #define ARRAY_REF(T, N) _cpp_array& N +#define FIXED_ARRAY_REF(T, N, S) T(&N)[S] #define CONST_ARRAY_REF(T, N) const _cpp_array& N diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index 6f704c47a..8e7fa6e66 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -256,20 +256,6 @@ int ArrayCopy(ARRAY_REF(D, _target), ValueStorage &_source, int _dst_start = return _num_copied; } -/** - * iHigest() version working on ValueStorage. - */ -int iHighest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { - return iPeak(_price, _count, _start, IPEAK_HIGHEST); -} - -/** - * iLowest() version working on ValueStorage. - */ -int iLowest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { - return iPeak(_price, _count, _start, IPEAK_LOWEST); -} - /** * iLowest() version working on ValueStorage. */ @@ -315,4 +301,18 @@ int iPeak(ValueStorage &_price, int _count, int _start, ENUM_IPEAK _type return _price_size - _peak_idx - 1; } +/** + * iHigest() version working on ValueStorage. + */ +int iHighest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { + return iPeak(_price, _count, _start, IPEAK_HIGHEST); +} + +/** + * iLowest() version working on ValueStorage. + */ +int iLowest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { + return iPeak(_price, _count, _start, IPEAK_LOWEST); +} + #endif // VALUE_STORAGE_H diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index ed11af3c9..73d64a74f 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -31,7 +31,6 @@ #endif // Includes. -#include "../Indicator/IndicatorData.h" #include "ValueStorage.h" // Forward declarations. diff --git a/Storage/ValueStorage.spread.h b/Storage/ValueStorage.spread.h index 98e3689fc..890b168a1 100644 --- a/Storage/ValueStorage.spread.h +++ b/Storage/ValueStorage.spread.h @@ -25,7 +25,6 @@ */ // Includes. -#include "../Chart.struct.h" #include "ObjectsCache.h" #include "ValueStorage.history.h" diff --git a/String.extern.h b/String.extern.h index f4ea595a4..8c1cde2f6 100644 --- a/String.extern.h +++ b/String.extern.h @@ -101,4 +101,30 @@ unsigned short StringGetCharacter(string string_value, int pos) { int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, unsigned int codepage = CP_ACP); + +bool StringInit(string& string_var, int new_len = 0, unsigned short character = 0) { + string_var = string(new_len, (char)character); + return true; +} + +/** + * It replaces all the found substrings of a string by a set sequence of symbols. + * + * @docs + * - https://www.mql5.com/en/docs/strings/stringreplace + */ +int StringReplace(string& str, const string& find, const string& replacement) { + int num_replacements; + for (size_t pos = 0;; pos += replacement.length()) { + // Locate the substring to replace + pos = str.find(find, pos); + if (pos == string::npos) break; + // Replace by erasing and inserting + str.erase(pos, find.length()); + str.insert(pos, replacement); + ++num_replacements; + } + return num_replacements; +} + #endif diff --git a/Terminal.define.h b/Terminal.define.h index 129089236..a316eea43 100644 --- a/Terminal.define.h +++ b/Terminal.define.h @@ -38,141 +38,275 @@ #define CP_UTF8 65001 // UTF-8 code page. // Colors. -#define AliceBlue 0xFFF8F0 -#define AntiqueWhite 0xD7EBFA -#define Aqua 0xFFFF00 -#define Aquamarine 0xD4FF7F -#define Beige 0xDCF5F5 -#define Bisque 0xC4E4FF -#define Black 0x000000 -#define BlanchedAlmond 0xCDEBFF -#define Blue 0xFF0000 -#define BlueViolet 0xE22B8A -#define Brown 0x2A2AA5 -#define BurlyWood 0x87B8DE -#define CadetBlue 0xA09E5F -#define Chartreuse 0x00FF7F -#define Chocolate 0x1E69D2 -#define Coral 0x507FFF -#define CornflowerBlue 0xED9564 -#define Cornsilk 0xDCF8FF -#define Crimson 0x3C14DC -#define DarkBlue 0x8B0000 -#define DarkGoldenrod 0x0B86B8 -#define DarkGray 0xA9A9A9 -#define DarkGreen 0x006400 -#define DarkKhaki 0x6BB7BD -#define DarkOliveGreen 0x2F6B55 -#define DarkOrange 0x008CFF -#define DarkOrchid 0xCC3299 -#define DarkSalmon 0x7A96E9 -#define DarkSlateBlue 0x8B3D48 -#define DarkSlateGray 0x4F4F2F -#define DarkTurquoise 0xD1CE00 -#define DarkViolet 0xD30094 -#define DeepPink 0x9314FF -#define DeepSkyBlue 0xFFBF00 -#define DimGray 0x696969 -#define DodgerBlue 0xFF901E -#define FireBrick 0x2222B2 -#define ForestGreen 0x228B22 -#define Gainsboro 0xDCDCDC -#define Gold 0x00D7FF -#define Goldenrod 0x20A5DA -#define Gray 0x808080 -#define Green 0x008000 -#define GreenYellow 0x2FFFAD -#define Honeydew 0xF0FFF0 -#define HotPink 0xB469FF -#define IndianRed 0x5C5CCD -#define Indigo 0x82004B -#define Ivory 0xF0FFFF -#define Khaki 0x8CE6F0 -#define Lavender 0xFAE6E6 -#define LavenderBlush 0xF5F0FF -#define LawnGreen 0x00FC7C -#define LemonChiffon 0xCDFAFF -#define LightBlue 0xE6D8AD -#define LightCoral 0x8080F0 -#define LightCyan 0xFFFFE0 -#define LightGoldenrod 0xD2FAFA -#define LightGray 0xD3D3D3 -#define LightGreen 0x90EE90 -#define LightPink 0xC1B6FF -#define LightSalmon 0x7AA0FF -#define LightSeaGreen 0xAAB220 -#define LightSkyBlue 0xFACE87 -#define LightSlateGray 0x998877 -#define LightSteelBlue 0xDEC4B0 -#define LightYellow 0xE0FFFF -#define Lime 0x00FF00 -#define LimeGreen 0x32CD32 -#define Linen 0xE6F0FA -#define Magenta 0xFF00FF -#define Maroon 0x000080 -#define MediumAquamarine 0xAACD66 -#define MediumBlue 0xCD0000 -#define MediumOrchid 0xD355BA -#define MediumPurple 0xDB7093 -#define MediumSeaGreen 0x71B33C -#define MediumSlateBlue 0xEE687B -#define MediumSpringGreen 0x9AFA00 -#define MediumTurquoise 0xCCD148 -#define MediumVioletRed 0x8515C7 -#define MidnightBlue 0x701919 -#define MintCream 0xFAFFF5 -#define MistyRose 0xE1E4FF -#define Moccasin 0xB5E4FF -#define NavajoWhite 0xADDEFF -#define Navy 0x800000 -#define OldLace 0xE6F5FD -#define Olive 0x008080 -#define OliveDrab 0x238E6B -#define Orange 0x00A5FF -#define OrangeRed 0x0045FF -#define Orchid 0xD670DA -#define PaleGoldenrod 0xAAE8EE -#define PaleGreen 0x98FB98 -#define PaleTurquoise 0xEEEEAF -#define PaleVioletRed 0x9370DB -#define PapayaWhip 0xD5EFFF -#define PeachPuff 0xB9DAFF -#define Peru 0x3F85CD -#define Pink 0xCBC0FF -#define Plum 0xDDA0DD -#define PowderBlue 0xE6E0B0 -#define Purple 0x800080 -#define Red 0x0000FF -#define RosyBrown 0x8F8FBC -#define RoyalBlue 0xE16941 -#define SaddleBrown 0x13458B -#define Salmon 0x7280FA -#define SandyBrown 0x60A4F4 -#define SeaGreen 0x578B2E -#define Seashell 0xEEF5FF -#define Sienna 0x2D52A0 -#define Silver 0xC0C0C0 -#define SkyBlue 0xEBCE87 -#define SlateBlue 0xCD5A6A -#define SlateGray 0x908070 -#define Snow 0xFAFAFF -#define SpringGreen 0x7FFF00 -#define SteelBlue 0xB48246 -#define Tan 0x8CB4D2 -#define Teal 0x808000 -#define Thistle 0xD8BFD8 -#define Tomato 0x4763FF -#define Turquoise 0xD0E040 -#define Violet 0xEE82EE -#define Wheat 0xB3DEF5 -#define White 0xFFFFFF -#define WhiteSmoke 0xF5F5F5 -#define Yellow 0x00FFFF -#define YellowGreen 0x32CD9A +#define clrAliceBlue 0x00F0F8FF +#define clrAntiqueWhite 0x00FAEBD7 +#define clrAqua 0x0000FFFF +#define clrAquamarine 0x007FFFD4 +#define clrBeige 0x00F5F5DC +#define clrBisque 0x00FFE4C4 +#define clrBlack 0x00000000 +#define clrBlanchedAlmond 0x00FFEBCD +#define clrBlue 0x000000FF +#define clrBlueViolet 0x008A2BE2 +#define clrBrown 0x00A52A2A +#define clrBurlyWood 0x00DEB887 +#define clrCadetBlue 0x005F9EA0 +#define clrChartreuse 0x007FFF00 +#define clrChocolate 0x00D2691E +#define clrCoral 0x00FF7F50 +#define clrCornflowerBlue 0x006495ED +#define clrCornsilk 0x00FFF8DC +#define clrCrimson 0x00DC143C +#define clrDarkBlue 0x0000008B +#define clrDarkGoldenrod 0x00B8860B +#define clrDarkGray 0x00A9A9A9 +#define clrDarkGreen 0x00006400 +#define clrDarkKhaki 0x00BDB76B +#define clrDarkOliveGreen 0x00556B2F +#define clrDarkOrange 0x00FF8C00 +#define clrDarkOrchid 0x009932CC +#define clrDarkSalmon 0x00E9967A +#define clrDarkSeaGreen 0x008FBC8F +#define clrDarkSlateBlue 0x00483D8B +#define clrDarkSlateGray 0x002F4F4F +#define clrDarkTurquoise 0x0000CED1 +#define clrDarkViolet 0x009400D3 +#define clrDeepPink 0x00FF1493 +#define clrDeepSkyBlue 0x0000BFFF +#define clrDimGray 0x00696969 +#define clrDodgerBlue 0x001E90FF +#define clrFireBrick 0x00B22222 +#define clrForestGreen 0x00228B22 +#define clrGainsboro 0x00DCDCDC +#define clrGold 0x00FFD700 +#define clrGoldenrod 0x00DAA520 +#define clrGray 0x00808080 +#define clrGreen 0x00008000 +#define clrGreenYellow 0x00ADFF2F +#define clrHoneydew 0x00F0FFF0 +#define clrHotPink 0x00FF69B4 +#define clrIndianRed 0x00CD5C5C +#define clrIndigo 0x004B0082 +#define clrIvory 0x00FFFFF0 +#define clrKhaki 0x00F0E68C +#define clrLavender 0x00E6E6FA +#define clrLavenderBlush 0x00FFF0F5 +#define clrLawnGreen 0x007CFC00 +#define clrLemonChiffon 0x00FFFACD +#define clrLightBlue 0x00ADD8E6 +#define clrLightCoral 0x00F08080 +#define clrLightCyan 0x00E0FFFF +#define clrLightGoldenrodYellow 0x00FAFAD2 +#define clrLightGreen 0x0090EE90 +#define clrLightGrey 0x00D3D3D3 +#define clrLightPink 0x00FFB6C1 +#define clrLightSalmon 0x00FFA07A +#define clrLightSeaGreen 0x0020B2AA +#define clrLightSkyBlue 0x0087CEFA +#define clrLightSlateGray 0x00778899 +#define clrLightSteelBlue 0x00B0C4DE +#define clrLightYellow 0x00FFFFE0 +#define clrLime 0x0000FF00 +#define clrLimeGreen 0x0032CD32 +#define clrLinen 0x00FAF0E6 +#define clrMagenta 0x00FF00FF +#define clrMaroon 0x00800000 +#define clrMediumAquamarine 0x0066CDAA +#define clrMediumBlue 0x000000CD +#define clrMediumOrchid 0x00BA55D3 +#define clrMediumPurple 0x009370DB +#define clrMediumSeaGreen 0x003CB371 +#define clrMediumSlateBlue 0x007B68EE +#define clrMediumSpringGreen 0x0000FA9A +#define clrMediumTurquoise 0x0048D1CC +#define clrMediumVioletRed 0x00C71585 +#define clrMidnightBlue 0x00191970 +#define clrMintCream 0x00F5FFFA +#define clrMistyRose 0x00FFE4E1 +#define clrMoccasin 0x00FFE4B5 +#define clrNavajoWhite 0x00FFDEAD +#define clrNavy 0x00000080 +#define clrOldLace 0x00FDF5E6 +#define clrOlive 0x00808000 +#define clrOliveDrab 0x006B8E23 +#define clrOrange 0x00FFA500 +#define clrOrangeRed 0x00FF4500 +#define clrOrchid 0x00DA70D6 +#define clrPaleGoldenrod 0x00EEE8AA +#define clrPaleGreen 0x0098FB98 +#define clrPaleTurquoise 0x00AFEEEE +#define clrPaleVioletRed 0x00DB7093 +#define clrPapayaWhip 0x00FFEFD5 +#define clrPeachPuff 0x00FFDAB9 +#define clrPeru 0x00CD853F +#define clrPink 0x00FFC0CB +#define clrPlum 0x00DDA0DD +#define clrPowderBlue 0x00B0E0E6 +#define clrPurple 0x00800080 +#define clrRed 0x00FF0000 +#define clrRosyBrown 0x00BC8F8F +#define clrRoyalBlue 0x004169E1 +#define clrSaddleBrown 0x008B4513 +#define clrSalmon 0x00FA8072 +#define clrSandyBrown 0x00F4A460 +#define clrSeaGreen 0x002E8B57 +#define clrSeashell 0x00FFF5EE +#define clrSienna 0x00A0522D +#define clrSilver 0x00C0C0C0 +#define clrSkyBlue 0x0087CEEB +#define clrSlateBlue 0x006A5ACD +#define clrSlateGray 0x00708090 +#define clrSnow 0x00FFFAFA +#define clrSpringGreen 0x0000FF7F +#define clrSteelBlue 0x004682B4 +#define clrTan 0x00D2B48C +#define clrTeal 0x00008080 +#define clrThistle 0x00D8BFD8 +#define clrTomato 0x00FF6347 +#define clrTurquoise 0x0040E0D0 +#define clrViolet 0x00EE82EE +#define clrWheat 0x00F5DEB3 +#define clrWhite 0x00FFFFFF +#define clrWhiteSmoke 0x00F5F5F5 +#define clrYellow 0x00FFFF00 +#define clrYellowGreen 0x009ACD32 + +#define AliceBlue clrAliceBlue +#define AntiqueWhite clrAntiqueWhite +#define Aqua clrAqua +#define Aquamarine clrAquamarine +#define Beige clrBeige +#define Bisque clrBisque +#define Black clrBlack +#define BlanchedAlmond clrBlanchedAlmond +#define Blue clrBlue +#define BlueViolet clrBlueViolet +#define Brown clrBrown +#define BurlyWood clrBurlyWood +#define CadetBlue clrCadetBlue +#define Chartreuse clrChartreuse +#define Chocolate clrChocolate +#define Coral clrCoral +#define CornflowerBlue clrCornflowerBlue +#define Cornsilk clrCornsilk +#define Crimson clrCrimson +#define DarkBlue clrDarkBlue +#define DarkGoldenrod clrDarkGoldenrod +#define DarkGray clrDarkGray +#define DarkGreen clrDarkGreen +#define DarkKhaki clrDarkKhaki +#define DarkOliveGreen clrDarkOliveGreen +#define DarkOrange clrDarkOrange +#define DarkOrchid clrDarkOrchid +#define DarkSalmon clrDarkSalmon +#define DarkSeaGreen clrDarkSeaGreen +#define DarkSlateBlue clrDarkSlateBlue +#define DarkSlateGray clrDarkSlateGray +#define DarkTurquoise clrDarkTurquoise +#define DarkViolet clrDarkViolet +#define DeepPink clrDeepPink +#define DeepSkyBlue clrDeepSkyBlue +#define DimGray clrDimGray +#define DodgerBlue clrDodgerBlue +#define FireBrick clrFireBrick +#define ForestGreen clrForestGreen +#define Gainsboro clrGainsboro +#define Gold clrGold +#define Goldenrod clrGoldenrod +#define Gray clrGray +#define Green clrGreen +#define GreenYellow clrGreenYellow +#define Honeydew clrHoneydew +#define HotPink clrHotPink +#define IndianRed clrIndianRed +#define Indigo clrIndigo +#define Ivory clrIvory +#define Khaki clrKhaki +#define Lavender clrLavender +#define LavenderBlush clrLavenderBlush +#define LawnGreen clrLawnGreen +#define LemonChiffon clrLemonChiffon +#define LightBlue clrLightBlue +#define LightCoral clrLightCoral +#define LightCyan clrLightCyan +#define LightGoldenrod clrLightGoldenrod +#define LightGray clrLightGray +#define LightGreen clrLightGreen +#define LightPink clrLightPink +#define LightSalmon clrLightSalmon +#define LightSeaGreen clrLightSeaGreen +#define LightSkyBlue clrLightSkyBlue +#define LightSlateGray clrLightSlateGray +#define LightSteelBlue clrLightSteelBlue +#define LightYellow clrLightYellow +#define Lime clrLime +#define LimeGreen clrLimeGreen +#define Linen clrLinen +#define Magenta clrMagenta +#define Maroon clrMaroon +#define MediumAquamarine clrMediumAquamarine +#define MediumBlue clrMediumBlue +#define MediumOrchid clrMediumOrchid +#define MediumPurple clrMediumPurple +#define MediumSeaGreen clrMediumSeaGreen +#define MediumSlateBlue clrMediumSlateBlue +#define MediumSpringGreen clrMediumSpringGreen +#define MediumTurquoise clrMediumTurquoise +#define MediumVioletRed clrMediumVioletRed +#define MidnightBlue clrMidnightBlue +#define MintCream clrMintCream +#define MistyRose clrMistyRose +#define Moccasin clrMoccasin +#define NavajoWhite clrNavajoWhite +#define Navy clrNavy +#define OldLace clrOldLace +#define Olive clrOlive +#define OliveDrab clrOliveDrab +#define Orange clrOrange +#define OrangeRed clrOrangeRed +#define Orchid clrOrchid +#define PaleGoldenrod clrPaleGoldenrod +#define PaleGreen clrPaleGreen +#define PaleTurquoise clrPaleTurquoise +#define PaleVioletRed clrPaleVioletRed +#define PapayaWhip clrPapayaWhip +#define PeachPuff clrPeachPuff +#define Peru clrPeru +#define Pink clrPink +#define Plum clrPlum +#define PowderBlue clrPowderBlue +#define Purple clrPurple +#define Red clrRed +#define RosyBrown clrRosyBrown +#define RoyalBlue clrRoyalBlue +#define SaddleBrown clrSaddleBrown +#define Salmon clrSalmon +#define SandyBrown clrSandyBrown +#define SeaGreen clrSeaGreen +#define Seashell clrSeashell +#define Sienna clrSienna +#define Silver clrSilver +#define SkyBlue clrSkyBlue +#define SlateBlue clrSlateBlue +#define SlateGray clrSlateGray +#define Snow clrSnow +#define SpringGreen clrSpringGreen +#define SteelBlue clrSteelBlue +#define Tan clrTan +#define Teal clrTeal +#define Thistle clrThistle +#define Tomato clrTomato +#define Turquoise clrTurquoise +#define Violet clrViolet +#define Wheat clrWheat +#define White clrWhite +#define WhiteSmoke clrWhiteSmoke +#define Yellow clrYellow +#define YellowGreen clrYellowGreen + #ifndef __MQL__ #define clrNONE -1 #define CLR_NONE -1 -#define DarkSeaGreen 0x8BBC8F #endif // Custom user errors. diff --git a/Trade.mqh b/Trade.mqh index f6eea3136..eb74a6564 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -31,7 +31,6 @@ class Trade; // Includes. #include "Account/AccountMt.h" -#include "Chart.mqh" #include "Convert.mqh" #include "DictStruct.mqh" #include "Indicator/IndicatorData.h" From 36993ce915e3b9a3bc458a2f233a22c5c0a93926 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 12 Jan 2023 20:08:20 +0100 Subject: [PATCH 052/123] WIP. Fixing Emscripten compilation errors. --- Chart.struct.tf.h | 4 +-- Draw.mqh | 2 +- DrawIndicator.mqh | 8 +++--- Indicator/Indicator.define.h | 3 ++ Indicator/Indicator.enum.h | 2 +- Indicator/Indicator.struct.h | 8 +++--- Indicator/IndicatorData.h | 31 +++++++++++---------- Indicator/IndicatorData.struct.cache.h | 4 +-- Indicator/IndicatorData.struct.h | 4 ++- Indicator/IndicatorData.struct.serialize.h | 8 +++--- Indicator/IndicatorData.struct.signal.h | 21 ++++++++++---- Order.struct.h | 7 +++-- Platform.extern.h | 22 +++++++++++---- Platform.h | 32 ++++++++++++++++++++++ Std.h | 2 +- 15 files changed, 110 insertions(+), 48 deletions(-) diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 1f1a2f89c..81f26a1c3 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -28,7 +28,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#include "Platform.h" +#include "Platform.extern.h" #endif // Forward declarations. @@ -280,7 +280,7 @@ struct ChartTf { * @param * _tf ENUM_TIMEFRAMES Specify timeframe enum. */ - static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { return ::PeriodSeconds(_tf); } + static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { return ChartTf::TfToSeconds(_tf); } /** * Returns text representation of the timeframe constant. diff --git a/Draw.mqh b/Draw.mqh index 3fb403904..5cea3f3ee 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -32,7 +32,7 @@ class Draw; // Includes. #include "Data.define.h" #include "Object.extern.h" -#include "Platform.h" +//#include "Platform.h" #include "Terminal.define.h" #ifndef __MQL4__ diff --git a/DrawIndicator.mqh b/DrawIndicator.mqh index 36269393e..d1ec770be 100644 --- a/DrawIndicator.mqh +++ b/DrawIndicator.mqh @@ -128,11 +128,11 @@ class DrawIndicator { } else { DrawPoint* last_point = last_points.GetByKey(_name); - draw.TLine(_name + "_" + IntegerToString(_time), last_point.value, _value, last_point.time, _time, color_line, - false, _window); + draw PTR_DEREF TLine(_name + "_" + IntegerToString(_time), last_point PTR_DEREF value, _value, + last_point PTR_DEREF time, _time, color_line, false, _window); - last_point.time = _time; - last_point.value = _value; + last_point PTR_DEREF time = _time; + last_point PTR_DEREF value = _value; } } }; diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index d0e2900df..b16a7b853 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -30,6 +30,9 @@ #pragma once #endif +// Includes. +#include "../Platform.extern.h" + // Defines macros. #define COMMA , #define DUMMY diff --git a/Indicator/Indicator.enum.h b/Indicator/Indicator.enum.h index 646788714..660658722 100644 --- a/Indicator/Indicator.enum.h +++ b/Indicator/Indicator.enum.h @@ -178,7 +178,7 @@ enum ENUM_SIGNAL_LINE { FINAL_SIGNAL_LINE_ENTRY, }; -#ifdef __MQL4__ +#ifndef __MQL5__ /** * The volume type is used in calculations. * diff --git a/Indicator/Indicator.struct.h b/Indicator/Indicator.struct.h index 90d45fea2..a05d0bb5f 100644 --- a/Indicator/Indicator.struct.h +++ b/Indicator/Indicator.struct.h @@ -85,19 +85,19 @@ struct IndicatorParams { DataParamEntry _param = input_params[_index]; switch (_param.type) { case TYPE_BOOL: - return (T)param.integer_value; + return (T)_param.integer_value; case TYPE_INT: case TYPE_LONG: case TYPE_UINT: case TYPE_ULONG: - return param.integer_value; + return _param.integer_value; case TYPE_DOUBLE: case TYPE_FLOAT: - return (T)param.double_value; + return (T)_param.double_value; case TYPE_CHAR: case TYPE_STRING: case TYPE_UCHAR: - return (T)param.string_value; + return (T)_param.string_value; default: SetUserError(ERR_INVALID_PARAMETER); break; diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 78b5bb1f1..981a52b82 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -31,10 +31,11 @@ // Forward class declaration. class IndicatorBase; -class IndicatorDraw; +class DrawIndicator; // Includes. #include "../Bar.struct.h" +#include "../Chart.struct.tf.h" #include "../Flags.h" #include "../Storage/IValueStorage.h" #include "../Storage/ItemsHistory.h" @@ -70,7 +71,7 @@ class IndicatorData : public IndicatorBase { IndicatorCalculateCache cache; IndicatorDataParams idparams; // Indicator data params. IndicatorState istate; - Ref indi_src; // Indicator used as data source. + Ref indi_src; // Indicator used as data source. protected: /* Protected methods */ @@ -87,7 +88,7 @@ class IndicatorData : public IndicatorBase { case IDATA_ICUSTOM: break; case IDATA_INDICATOR: - if (indi_src.IsSet() == NULL) { + if (indi_src.IsSet()) { // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); // SetDataSource(_indi_price, true, PRICE_OPEN); } @@ -120,9 +121,11 @@ class IndicatorData : public IndicatorBase { * Deinitialize drawing. */ void DeinitDraw() { + /* @todo: To refactor. if (draw) { delete draw; } + */ } public: @@ -225,7 +228,7 @@ class IndicatorData : public IndicatorBase { } return GetName() + "#" + IntegerToString(GetId()) + "-" + _mode + "[" + IntegerToString(_max_modes) + "]" + - (HasDataSource() ? (" (over " + GetDataSource(false).GetFullName() + ")") : ""); + (HasDataSource() ? (" (over " + GetDataSource(false) PTR_DEREF GetFullName() + ")") : ""); } /** @@ -391,13 +394,13 @@ class IndicatorData : public IndicatorBase { */ template double GetMax(int start_bar = 0, int count = WHOLE_ARRAY) { - double max = NULL; + double max = -DBL_MAX; int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); for (int shift = start_bar; shift <= last_bar; ++shift) { double value = GetEntry(shift).GetMax(_max_modes); - if (max == NULL || value > max) { + if (max == -DBL_MAX || value > max) { max = value; } } @@ -410,13 +413,13 @@ class IndicatorData : public IndicatorBase { */ template double GetMin(int start_bar, int count = WHOLE_ARRAY) { - double min = NULL; + double min = DBL_MAX; int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); for (int shift = start_bar; shift <= last_bar; ++shift) { double value = GetEntry(shift).GetMin(_max_modes); - if (min == NULL || value < min) { + if (min == DBL_MAX || value < min) { min = value; } } @@ -450,7 +453,7 @@ class IndicatorData : public IndicatorBase { */ template double GetMed(int start_bar, int count = WHOLE_ARRAY) { - double array[]; + ARRAY(double, array); int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); int num_bars = last_bar - start_bar + 1; @@ -513,7 +516,7 @@ class IndicatorData : public IndicatorBase { * Returns true of successful copy. * Returns false on invalid values. */ - bool CopyEntries(IndicatorDataEntry& _data[], int _count, int _start_shift = 0) { + bool CopyEntries(ARRAY_REF(IndicatorDataEntry, _data), int _count, int _start_shift = 0) { bool _is_valid = true; if (ArraySize(_data) < _count) { _is_valid &= ArrayResize(_data, _count) > 0; @@ -534,7 +537,7 @@ class IndicatorData : public IndicatorBase { * Returns false on invalid values. */ template - bool CopyValues(T& _data[], int _count, int _start_shift = 0, int _mode = 0) { + bool CopyValues(ARRAY_REF(T, _data), int _count, int _start_shift = 0, int _mode = 0) { bool _is_valid = true; if (ArraySize(_data) < _count) { _count = ArrayResize(_data, _count); @@ -1184,7 +1187,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's struct value via index. */ - virtual IndicatorDataEntry GetEntry(int _rel_shift = 0) = NULL; + virtual IndicatorDataEntry GetEntry(int _rel_shift = 0) = 0; /** * Returns the indicator's struct value via timestamp. @@ -1209,7 +1212,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's entry value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) = NULL; + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) = 0; /** * Returns the shift of the maximum value over a specific number of periods depending on type. @@ -1278,7 +1281,7 @@ class IndicatorData : public IndicatorBase { * * When indicator values are not valid, returns empty signals. */ - virtual IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) = NULL; + virtual IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) = 0; /** * Returns spread for the bar. diff --git a/Indicator/IndicatorData.struct.cache.h b/Indicator/IndicatorData.struct.cache.h index c6ee5e1dc..b3c7c4f0e 100644 --- a/Indicator/IndicatorData.struct.cache.h +++ b/Indicator/IndicatorData.struct.cache.h @@ -221,7 +221,7 @@ class IndicatorCalculateCache : public Dynamic { */ void Resize(int _buffers_size) { for (int i = 0; i < ArraySize(buffers); ++i) { - buffers[i].Resize(_buffers_size, 65535); + buffers[i] PTR_DEREF Resize(_buffers_size, 65535); } } @@ -230,7 +230,7 @@ class IndicatorCalculateCache : public Dynamic { */ template D GetValue(int _buffer_index, int _shift) { - return GetBuffer(_buffer_index).Fetch(_shift).Get(); + return GetBuffer(_buffer_index) PTR_DEREF Fetch(_shift).Get(); } /** diff --git a/Indicator/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h index 3e49d5902..7d399c0c1 100644 --- a/Indicator/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -188,7 +188,7 @@ struct IndicatorDataEntry { // Constructors. IndicatorDataEntry(int _size = 1) : flags(INDI_ENTRY_FLAG_NONE), timestamp(0) { Resize(_size); } - IndicatorDataEntry(IndicatorDataEntry &_entry) { THIS_REF = _entry; } + IndicatorDataEntry(const IndicatorDataEntry &_entry) { THIS_REF = _entry; } int GetSize() { return ArraySize(values); } // Operator overloading methods. template @@ -211,7 +211,9 @@ struct IndicatorDataEntry { T operator[](I _index) { return values[(int)_index].Get(); } +#ifdef __MQL__ template <> +#endif double operator[](int _index) { if (_index >= ArraySize(values)) { return 0; diff --git a/Indicator/IndicatorData.struct.serialize.h b/Indicator/IndicatorData.struct.serialize.h index c6b97399e..d2d8067dd 100644 --- a/Indicator/IndicatorData.struct.serialize.h +++ b/Indicator/IndicatorData.struct.serialize.h @@ -42,11 +42,11 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { switch (values[i].GetDataType()) { case TYPE_DOUBLE: - _s.Pass(THIS_REF, (string)i, values[i].value.vdbl, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vdbl, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); break; case TYPE_FLOAT: - _s.Pass(THIS_REF, (string)i, values[i].value.vflt, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vflt, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); break; case TYPE_INT: @@ -58,7 +58,7 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); } } else { - _s.Pass(THIS_REF, (string)i, values[i].value.vint, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vint, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } break; @@ -74,7 +74,7 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { */ SetUserError(ERR_INVALID_PARAMETER); } else { - _s.Pass(THIS_REF, (string)i, values[i].value.vlong, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vlong, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } break; diff --git a/Indicator/IndicatorData.struct.signal.h b/Indicator/IndicatorData.struct.signal.h index f27094803..0c141f95b 100644 --- a/Indicator/IndicatorData.struct.signal.h +++ b/Indicator/IndicatorData.struct.signal.h @@ -79,11 +79,22 @@ struct IndicatorSignal { } } SetSignal(INDICATOR_SIGNAL_CROSSOVER, _is_cross); + // INDICATOR_SIGNAL_DIVERGENCE - int _shift0 = ChartStatic::iBarShift(_symbol, _tf, _data[0].timestamp); - int _shift1 = ChartStatic::iBarShift(_symbol, _tf, _data[_size - 1].timestamp); - double _price_w0 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift0); - double _price_w1 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift1); + // + // @fixit Should use pointer to IndicatorBase as a source of prices. + // int _shift0 = ChartStatic::iBarShift(_symbol, _tf, _data[0].timestamp); + // int _shift1 = ChartStatic::iBarShift(_symbol, _tf, _data[_size - 1].timestamp); + // double _price_w0 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift0); + // double _price_w1 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift1); + Alert(__FUNCSIG__, " Should use pointer to IndicatorBase as a source of prices!"); + DebugBreak(); + + int _shift0 = 0; + int _shift1 = 1; + double _price_w0 = 0; + double _price_w1 = 0; + SetSignal(INDICATOR_SIGNAL_DIVERGENCE, ((_price_w0 - _price_w1 > 0) && (_data[0][_m1] - _data[_size - 1][_m1]) < 0) || ((_price_w0 - _price_w1) < 0 && (_data[0][_m1] - _data[_size - 1][_m1]) > 0)); @@ -142,7 +153,7 @@ struct IndicatorSignal { int _size = sizeof(int) * 8; for (int i = 0; i < _size; i++) { int _value = CheckSignals(1 << i) ? 1 : 0; - _s.Pass(this, (string)(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + _s.Pass(THIS_REF, IntegerToString(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } return SerializerNodeObject; } diff --git a/Order.struct.h b/Order.struct.h index fff61929c..93f02f4f3 100644 --- a/Order.struct.h +++ b/Order.struct.h @@ -139,7 +139,8 @@ struct OrderParams { // s.Pass(THIS_REF, "cond_args", cond_args); return SerializerNodeObject; } - } cond_close[]; + }; + ARRAY(OrderCloseCond, cond_close); bool dummy; // Whether order is dummy (fake) or not (real). color color_arrow; // Color of the opening arrow on the chart. unsigned short refresh_freq; // How often to refresh order values (in secs). @@ -201,7 +202,7 @@ struct OrderParams { SetUserError(ERR_INVALID_PARAMETER); } void SetConditionClose(ENUM_ORDER_CONDITION _cond, int _index = 0) { - DataParamEntry _args[]; + ARRAY(DataParamEntry, _args); SetConditionClose(_cond, _args, _index); } void SetConditionClose(ENUM_ORDER_CONDITION _cond, ARRAY_REF(DataParamEntry, _args), int _index = 0) { @@ -290,7 +291,7 @@ struct OrderData { volume_curr(0), volume_init(0) {} // Copy constructor. - OrderData(OrderData &_odata) { this = _odata; } + OrderData(OrderData &_odata) { THIS_REF = _odata; } // Getters. template T Get(ENUM_ORDER_PROPERTY_CUSTOM _prop_name) { diff --git a/Platform.extern.h b/Platform.extern.h index 87adc94ca..0c2ea98d6 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -23,16 +23,26 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#endif - -// Includes. -#include "Platform.h" -#ifndef __MQL__ +template +double iCustom(string symbol, int timeframe, string name, Args... args) { + Alert(__FUNCSIG__, " it not implemented!"); + return 0; +} /** * Returns number of candles for a given symbol and time-frame. */ -static int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { return Platform::Bars(_symbol, _tf); } +extern int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf); + +/** + * Returns the number of calculated data for the specified indicator. + */ +extern int BarsCalculated(int indicator_handle); + +/** + * Gets data of a specified buffer of a certain indicator in the necessary quantity. + */ +extern int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)); #endif diff --git a/Platform.h b/Platform.h index f0da9db31..f8d3a0a44 100644 --- a/Platform.h +++ b/Platform.h @@ -44,6 +44,7 @@ extern int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf); * Current platform's static methods. */ +#include "DrawIndicator.mqh" #include "Flags.h" #include "Indicator/IndicatorData.h" #include "Indicator/tests/classes/IndicatorTfDummy.h" @@ -206,6 +207,14 @@ class Platform { return 0; } + /** + * Returns the number of calculated data for the specified indicator. + */ + static int BarsCalculated(int indicator_handle) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; + } + /** * Returns id of the current chart. */ @@ -353,6 +362,29 @@ int Platform::global_tick_index = 0; DictStruct> Platform::indis; DictStruct> Platform::indis_dflt; +#ifndef __MQL__ +// Following methods must be there are they're externed in Platform.extern.h +// and there's no better place for them! + +/** + * Returns number of candles for a given symbol and time-frame. + */ +int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { return Platform::Bars(_symbol, _tf); } + +/** + * Returns the number of calculated data for the specified indicator. + */ +int BarsCalculated(int indicator_handle) { return Platform::BarsCalculated(indicator_handle); } + +/** + * Gets data of a specified buffer of a certain indicator in the necessary quantity. + */ +int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); +} + +#endif + /** * Will test given indicator class with platform-default data source bindings. */ diff --git a/Std.h b/Std.h index 8337ec71d..a7670198f 100644 --- a/Std.h +++ b/Std.h @@ -238,7 +238,7 @@ class color { unsigned int value; public: - color(unsigned int _color) { value = _color; } + color(unsigned int _color = 0) { value = _color; } color& operator=(unsigned int _color) { value = _color; return *this; From efa69daba8e2b380993b2d5f603f7f9c3920195f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Sat, 14 Jan 2023 13:47:56 +0100 Subject: [PATCH 053/123] WIP. Fixing Emscripten compilation errors. --- Deal.enum.h | 4 ++++ Order.mqh | 15 ++++++++------- Platform.extern.h | 21 +++++++++++++++++++++ Platform.h | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/Deal.enum.h b/Deal.enum.h index ceef21a7f..41c3ca747 100644 --- a/Deal.enum.h +++ b/Deal.enum.h @@ -26,6 +26,10 @@ */ #ifndef __MQL__ + +// Allows the preprocessor to include a header file when it is needed. +#pragma once + enum ENUM_DEAL_TYPE { DEAL_TYPE_BUY, DEAL_TYPE_SELL, diff --git a/Order.mqh b/Order.mqh index b0092bee5..b7508eace 100644 --- a/Order.mqh +++ b/Order.mqh @@ -305,9 +305,10 @@ class Order : public SymbolInfo { int _num = oparams.Get(ORDER_PARAM_COND_CLOSE_NUM); for (int _ci = 0; _ci < _num; _ci++) { ENUM_ORDER_CONDITION _cond = oparams.Get(ORDER_PARAM_COND_CLOSE, _ci); - DataParamEntry _cond_args[1]; - _cond_args[0] = oparams.Get(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _ci); - _result |= _result || Order::CheckCondition(_cond, _cond_args); + ARRAY(DataParamEntry, _cond_args); + DataParamEntry _item0 = oparams.Get(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _ci); + ArrayPush(_cond_args, _item0); + _result |= Order::CheckCondition(_cond, _cond_args); } } return _result; @@ -470,7 +471,7 @@ class Order : public SymbolInfo { #endif } datetime GetOpenTime() { - if (odata.Get(ORDER_PROP_TIME_OPENED) == 0) { + if (odata.Get(ORDER_PROP_TIME_OPENED) == (datetime)0) { OrderSelect(); odata.Set(ORDER_PROP_TIME_OPENED, Order::OrderOpenTime()); } @@ -503,7 +504,7 @@ class Order : public SymbolInfo { return (datetime)_result; #endif } - datetime GetCloseTime() { return IsClosed() ? odata.Get(ORDER_PROP_TIME_CLOSED) : 0; } + datetime GetCloseTime() { return IsClosed() ? odata.Get(ORDER_PROP_TIME_CLOSED) : (datetime)0; } /** * Returns comment of the currently selected order/position. @@ -695,7 +696,7 @@ class Order : public SymbolInfo { case ORDER_TP: return OrderTakeProfit(); } - return NULL; + return 0; } /** @@ -1003,7 +1004,7 @@ class Order : public SymbolInfo { * * @see: https://docs.mql4.com/trading/orderdelete */ - static bool OrderDelete(unsigned long _ticket, color _color = NULL) { + static bool OrderDelete(unsigned long _ticket, color _color = color()) { #ifdef __MQL4__ return ::OrderDelete((int)_ticket, _color); #else diff --git a/Platform.extern.h b/Platform.extern.h index 0c2ea98d6..81cd3a12a 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -24,6 +24,9 @@ // Allows the preprocessor to include a header file when it is needed. #pragma once +// Includes. +#include "Deal.enum.h" + template double iCustom(string symbol, int timeframe, string name, Args... args) { Alert(__FUNCSIG__, " it not implemented!"); @@ -45,4 +48,22 @@ extern int BarsCalculated(int indicator_handle); */ extern int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)); +extern unsigned long PositionGetTicket(int _index); + +extern long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id); + +extern double PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE property_id); + +extern string PositionGetString(ENUM_POSITION_PROPERTY_STRING property_id); + +extern int HistoryDealsTotal(); + +extern unsigned long HistoryDealGetTicket(int index); + +extern long HistoryDealGetInteger(unsigned long ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id); + +extern double HistoryDealGetDouble(unsigned long ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id); + +extern string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRING property_id); + #endif diff --git a/Platform.h b/Platform.h index f8d3a0a44..16e026f55 100644 --- a/Platform.h +++ b/Platform.h @@ -23,9 +23,9 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#endif -#ifndef __MQL__ +// Includes. +#include "Deal.enum.h" /** * Extern declarations for C++. @@ -383,6 +383,48 @@ int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, A Print("Not yet implemented: ", __FUNCTION__, " returns 0."); } +unsigned long PositionGetTicket(int _index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); } + +long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +string PositionGetString(ENUM_POSITION_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return ""; +} + +int HistoryDealsTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +unsigned long HistoryDealGetTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +long HistoryDealGetInteger(unsigned long ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double HistoryDealGetDouble(unsigned long ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return 0; +} + #endif /** From db0b8a0a3d74f4687764929dbb022277f2c04757 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 19 Jan 2023 20:06:25 +0100 Subject: [PATCH 054/123] WIP. Making code C++/Emscripten-compatible. --- Account/AccountMt.h | 3 +- Chart.struct.static.h | 4 +- Indicator/Indicator.define.h | 3 - Indicator/IndicatorData.h | 70 +++++------ Order.enum.h | 3 +- Order.mqh | 20 ++-- Order.struct.h | 1 + OrderQuery.h | 24 ++-- Orders.mqh | 33 ++--- Platform.extern.h | 69 +++++++++++ Platform.h | 148 +++++++++++++++++++++++ Refs.struct.h | 9 +- Serializer/SerializerConverter.h | 2 +- Std.h | 12 +- Storage/ValueStorage.indicator.h | 6 +- String.extern.h | 12 ++ Trade.mqh | 182 ++++++++++++++-------------- Trade.struct.h | 200 ++++++++++++++++--------------- 18 files changed, 525 insertions(+), 276 deletions(-) diff --git a/Account/AccountMt.h b/Account/AccountMt.h index 9e1713692..2ecb09dac 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -37,6 +37,7 @@ class AccountMt; #include "../Orders.mqh" #include "../Serializer/Serializer.h" #include "../SymbolInfo.mqh" +#include "../Task/TaskCondition.enum.h" #include "../Trade.struct.h" #include "Account.define.h" #include "Account.enum.h" @@ -283,7 +284,7 @@ class AccountMt { return ::AccountFreeMarginMode(); #else // @todo: Not implemented yet. - return NULL; + return NULL_VALUE; #endif } static double GetAccountFreeMarginMode() { return AccountMt::AccountFreeMarginMode(); } diff --git a/Chart.struct.static.h b/Chart.struct.static.h index cf19e5805..6d02bb9d4 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -75,7 +75,7 @@ struct ChartStatic { } return _bar_shift; #else // __MQL5__ - if (_time < 0) return (-1); + if (_time == (datetime)0) return (-1); ARRAY(datetime, arr); datetime _time0; // ENUM_TIMEFRAMES _tf = MQL4::TFMigrate(_tf); @@ -337,7 +337,7 @@ struct ChartStatic { // ENUM_TIMEFRAMES _tf = MQL4::TFMigrate(_tf); // @todo: Improves performance by caching values. - datetime _time = (_shift >= 0 && ::CopyTime(_symbol, _tf, _shift, 1, _arr) > 0) ? _arr[0] : 0; + datetime _time = (_shift >= 0 && ::CopyTime(_symbol, _tf, _shift, 1, _arr) > 0) ? _arr[0] : (datetime)0; if (_LastError != ERR_NO_ERROR) { Print("Error: ", _LastError, " while doing CopyTime() in ChartStatic::GetBarTime(", _symbol, ", ", diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index b16a7b853..d0e2900df 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -30,9 +30,6 @@ #pragma once #endif -// Includes. -#include "../Platform.extern.h" - // Defines macros. #define COMMA , #define DUMMY diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 981a52b82..d6ab968d3 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -30,7 +30,7 @@ #endif // Forward class declaration. -class IndicatorBase; +class IndicatorData; class DrawIndicator; // Includes. @@ -48,6 +48,8 @@ class DrawIndicator; #include "IndicatorData.struct.serialize.h" #include "IndicatorData.struct.signal.h" +extern IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData* _indi, int _mode); + /** * Implements class to store indicator data. */ @@ -71,7 +73,7 @@ class IndicatorData : public IndicatorBase { IndicatorCalculateCache cache; IndicatorDataParams idparams; // Indicator data params. IndicatorState istate; - Ref indi_src; // Indicator used as data source. + Ref indi_src; // Indicator used as data source. protected: /* Protected methods */ @@ -134,7 +136,7 @@ class IndicatorData : public IndicatorBase { /** * Class constructor. */ - IndicatorData(const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + IndicatorData(const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) : do_draw(false), idparams(_idparams), indi_src(_indi_src) { Init(); } @@ -576,7 +578,7 @@ class IndicatorData : public IndicatorBase { } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) { int _source_id = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)); - Print("Setting data source by id is now obsolete. Please use SetDataSource(IndicatorBase*) method for ", + Print("Setting data source by id is now obsolete. Please use SetDataSource(IndicatorData*) method for ", GetName(), " (data source id ", _source_id, ")."); DebugBreak(); @@ -608,7 +610,7 @@ class IndicatorData : public IndicatorBase { } if (_validate) { - ValidateDataSource(&this, _result); + ValidateDataSource(THIS_PTR, _result); } return _result; @@ -776,7 +778,7 @@ class IndicatorData : public IndicatorBase { // If _indi or any of the _indi's data source points to this indicator then this would create circular dependency. for (_curr = _indi; _curr != nullptr && _iterations_left != 0; - _curr = _curr.GetDataSource(false), --_iterations_left) { + _curr = _curr PTR_DEREF GetDataSource(false), --_iterations_left) { if (_curr == THIS_PTR) { // Circular dependency found. Print("Error: Circular dependency found when trying to attach " + _indi PTR_DEREF GetFullName() + " into " + @@ -788,15 +790,15 @@ class IndicatorData : public IndicatorBase { if (indi_src.IsSet()) { if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT) && - !bool(_indi.GetFlags() | INDI_FLAG_INDEXABLE_BY_SHIFT)) { - Print(GetFullName(), ": Cannot set data source to ", _indi.GetFullName(), + !bool(_indi PTR_DEREF GetFlags() | INDI_FLAG_INDEXABLE_BY_SHIFT)) { + Print(GetFullName(), ": Cannot set data source to ", _indi PTR_DEREF GetFullName(), ", because source indicator isn't indexable by shift!"); DebugBreak(); return; } if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP) && - !bool(_indi.GetFlags() | INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { - Print(GetFullName(), ": Cannot set data source to ", _indi.GetFullName(), + !bool(_indi PTR_DEREF GetFlags() | INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { + Print(GetFullName(), ": Cannot set data source to ", _indi PTR_DEREF GetFullName(), ", because source indicator isn't indexable by timestamp!"); DebugBreak(); return; @@ -804,14 +806,14 @@ class IndicatorData : public IndicatorBase { } if (indi_src.IsSet() && indi_src.Ptr() != _indi) { - indi_src.Ptr().RemoveListener(THIS_PTR); + indi_src REF_DEREF RemoveListener(THIS_PTR); } indi_src = _indi; if (_indi != NULL) { - indi_src.Ptr().AddListener(THIS_PTR); + indi_src REF_DEREF AddListener(THIS_PTR); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID), -1); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE), _input_mode); - indi_src.Ptr().OnBecomeDataSourceFor(THIS_PTR); + indi_src REF_DEREF OnBecomeDataSourceFor(THIS_PTR); } } @@ -870,14 +872,14 @@ class IndicatorData : public IndicatorBase { last_tick_index = _global_tick_index; // Checking and potentially initializing new data source. - if (HasDataSource(true) != NULL) { + if (HasDataSource(true)) { // Ticking data source if not yet ticked. - GetDataSource().Tick(_global_tick_index); + GetDataSource() PTR_DEREF Tick(_global_tick_index); } // Also ticking all used indicators if they've not yet ticked. for (DictStructIterator> iter = indicators.Begin(); iter.IsValid(); ++iter) { - iter.Value().Ptr().Tick(_global_tick_index); + iter.Value() REF_DEREF Tick(_global_tick_index); } // Overridable OnTick() method. @@ -925,27 +927,27 @@ class IndicatorData : public IndicatorBase { return; } - if (!_target.IsDataSourceModeSelectable()) { + if (!_target PTR_DEREF IsDataSourceModeSelectable()) { // We don't validate source mode as it will use all modes. return; } - if (_source.GetModeCount() > 1 && - _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { + if (_source PTR_DEREF GetModeCount() > 1 && + _target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { // Mode must be selected if source indicator has more that one mode. Alert("Warning! ", GetName(), " must select source indicator's mode via SetDataSourceMode(int). Defaulting to mode 0."); - _target.idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); + _target PTR_DEREF idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); DebugBreak(); - } else if (_source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == 1 && - _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { - _target.idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); - } else if (_target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) < 0 || - _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) > - _source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) { - Alert("Error! ", _target.GetName(), + } else if (_source PTR_DEREF Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == 1 && + _target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { + _target PTR_DEREF idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); + } else if (_target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) < 0 || + _target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) > + _source PTR_DEREF Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) { + Alert("Error! ", _target PTR_DEREF GetName(), " must select valid source indicator's mode via SetDataSourceMode(int) between 0 and ", - _source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)), "."); + _source PTR_DEREF Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)), "."); DebugBreak(); } } @@ -1329,7 +1331,7 @@ class IndicatorData : public IndicatorBase { default: Print("Error: Invalid applied price " + EnumToString(_ap) + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " - "IndicatorBase::HasSpecificAppliedPriceValueStorage()!"); + "IndicatorData::HasSpecificAppliedPriceValueStorage()!"); DebugBreak(); return false; } @@ -1372,7 +1374,7 @@ class IndicatorData : public IndicatorBase { default: Print("Error: Invalid applied price " + EnumToString(_ap) + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " - "IndicatorBase::GetSpecificAppliedPriceValueStorage()!"); + "IndicatorData::GetSpecificAppliedPriceValueStorage()!"); DebugBreak(); return NULL; } @@ -1736,7 +1738,7 @@ class IndicatorData : public IndicatorBase { } if (!value_storages[_mode].IsSet()) { - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + value_storages[_mode] = InstantiateIndicatorBufferValueStorageDouble(THIS_PTR, _mode); } return value_storages[_mode].Ptr(); } @@ -1754,7 +1756,7 @@ class IndicatorData : public IndicatorBase { void EmitEntry(IndicatorDataEntry& entry) { for (int i = 0; i < ArraySize(listeners); ++i) { if (listeners[i].ObjectExists()) { - listeners[i].Ptr().OnDataSourceEntry(entry); + listeners[i] REF_DEREF OnDataSourceEntry(entry); } } } @@ -1891,7 +1893,7 @@ class IndicatorData : public IndicatorBase { /** * BarsCalculated()-compatible method to be used on Indicator instance. */ -int BarsCalculated(IndicatorData* _indi) { return _indi.GetBarsCalculated(); } +int BarsCalculated(IndicatorData* _indi) { return _indi PTR_DEREF GetBarsCalculated(); } /** * CopyBuffer() method to be used on Indicator instance with ValueStorage buffer. @@ -1909,7 +1911,7 @@ int CopyBuffer(IndicatorData* _indi, int _mode, int _start, int _count, ValueSto } for (int i = _start; i < _count; ++i) { - IndicatorDataEntry _entry = _indi.GetEntry(i); + IndicatorDataEntry _entry = _indi PTR_DEREF GetEntry(i); if (!_entry.IsValid()) { break; diff --git a/Order.enum.h b/Order.enum.h index c6489a73d..c466d638a 100644 --- a/Order.enum.h +++ b/Order.enum.h @@ -243,7 +243,8 @@ enum ENUM_ORDER_TYPE { // price. ORDER_TYPE_SELL_STOP_LIMIT, // Upon reaching the order price, a pending Sell Limit order is placed at the StopLimit // price. - ORDER_TYPE_CLOSE_BY // Order to close a position by an opposite one. + ORDER_TYPE_CLOSE_BY, // Order to close a position by an opposite one. + ORDER_TYPE_UNSET // A NULL value. }; #endif diff --git a/Order.mqh b/Order.mqh index b7508eace..7808c34ca 100644 --- a/Order.mqh +++ b/Order.mqh @@ -1081,9 +1081,9 @@ class Order : public SymbolInfo { if (IsClosed()) { Refresh(); } else { - GetLogger().Warning(StringFormat("Failed to modify order (#%d/p:%g/sl:%g/tp:%g/code:%d).", - odata.Get(ORDER_PROP_TICKET), _price, _sl, _tp, _last_error), - __FUNCTION_LINE__, ToCSV()); + GetLogger() PTR_DEREF Warning(StringFormat("Failed to modify order (#%d/p:%g/sl:%g/tp:%g/code:%d).", + odata.Get(ORDER_PROP_TICKET), _price, _sl, _tp, _last_error), + __FUNCTION_LINE__, ToCSV()); Refresh(ORDER_SL); Refresh(ORDER_TP); // TODO: Refresh(ORDER_PRI) @@ -1693,7 +1693,7 @@ class Order : public SymbolInfo { if (!_result || _last_error > ERR_NO_ERROR) { if (_last_error > ERR_NO_ERROR && _last_error != 4014) { // @fixme: In MT4 (why 4014?). - GetLogger().Warning(StringFormat("Update failed! Error: %d", _last_error), __FUNCTION_LINE__); + GetLogger() PTR_DEREF Warning(StringFormat("Update failed! Error: %d", _last_error), __FUNCTION_LINE__); } odata.ProcessLastError(); ResetLastError(); @@ -1984,7 +1984,7 @@ class Order : public SymbolInfo { * Return text representation of the order. */ static string OrderTypeToString(ENUM_ORDER_TYPE _cmd, bool _lc = false) { - _cmd = _cmd != NULL ? _cmd : OrderType(); + _cmd = _cmd != ORDER_TYPE_UNSET ? _cmd : OrderType(); string _res = StringSubstr(EnumToString(_cmd), 11); StringReplace(_res, "_", " "); if (_lc) { @@ -2059,8 +2059,8 @@ class Order : public SymbolInfo { /** * Get color of the order based on its type. */ - static color GetOrderColor(ENUM_ORDER_TYPE _cmd = (ENUM_ORDER_TYPE)-1, color cbuy = Blue, color csell = Red) { - if (_cmd == NULL) _cmd = (ENUM_ORDER_TYPE)OrderType(); + static color GetOrderColor(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, color cbuy = Blue, color csell = Red) { + if (_cmd == ORDER_TYPE_UNSET) _cmd = (ENUM_ORDER_TYPE)OrderType(); return OrderData::GetTypeValue(_cmd) > 0 ? cbuy : csell; } @@ -2308,7 +2308,7 @@ class Order : public SymbolInfo { _out = OrderGetString(property_id); return true; #else - return OrderGetParam(property_id, selected_ticket_type, ORDER_SELECT_DATA_TYPE_STRING, _out) != (string)NULL_VALUE; + return OrderGetParam(property_id, selected_ticket_type, ORDER_SELECT_DATA_TYPE_STRING, _out) != NULL_STRING; #endif } @@ -2333,7 +2333,7 @@ class Order : public SymbolInfo { static long OrderGetValue(int property_id, ENUM_ORDER_SELECT_TYPE type, long &_out) { switch (type) { case ORDER_SELECT_TYPE_NONE: - return NULL; + return 0; case ORDER_SELECT_TYPE_ACTIVE: _out = ::OrderGetInteger((ENUM_ORDER_PROPERTY_INTEGER)property_id); break; @@ -2371,7 +2371,7 @@ class Order : public SymbolInfo { static double OrderGetValue(int property_id, ENUM_ORDER_SELECT_TYPE type, double &_out) { switch (type) { case ORDER_SELECT_TYPE_NONE: - return NULL; + return 0; case ORDER_SELECT_TYPE_ACTIVE: _out = ::OrderGetDouble((ENUM_ORDER_PROPERTY_DOUBLE)property_id); break; diff --git a/Order.struct.h b/Order.struct.h index 93f02f4f3..897f28394 100644 --- a/Order.struct.h +++ b/Order.struct.h @@ -33,6 +33,7 @@ // Includes. #include "Data.struct.h" #include "Order.enum.h" +#include "Platform.extern.h" #include "Serializer/Serializer.h" #include "SymbolInfo.struct.static.h" #include "Terminal.mqh" diff --git a/OrderQuery.h b/OrderQuery.h index aede72e81..a3a9c9e4b 100644 --- a/OrderQuery.h +++ b/OrderQuery.h @@ -62,8 +62,8 @@ class OrderQuery : public Dynamic { template T CalcSumByProp(E _prop) { T _sum = 0; - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { - _sum += iter.Value().Ptr().Get(_prop); + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { + _sum += iter.Value() REF_DEREF Get(_prop); } return _sum; } @@ -77,10 +77,10 @@ class OrderQuery : public Dynamic { template T CalcSumByPropWithCond(E _prop, ECT _prop_cond_type, ECV _prop_cond_value) { T _sum = 0; - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { Order *_order = iter.Value().Ptr(); - if (_order.Get(_prop_cond_type) == _prop_cond_value) { - _sum += _order.Get(_prop); + if (_order PTR_DEREF Get(_prop_cond_type) == _prop_cond_value) { + _sum += _order PTR_DEREF Get(_prop); } } return _sum; @@ -96,13 +96,13 @@ class OrderQuery : public Dynamic { template Ref FindByPropViaOp(E _prop, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP) _op) { Ref _order_ref_found; - if (orders.Size() == 0) { + if (orders PTR_DEREF Size() == 0) { return _order_ref_found; } - _order_ref_found = orders.Begin().Value(); - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { + _order_ref_found = orders PTR_DEREF Begin().Value(); + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { Ref _order_ref = iter.Value(); - if (Compare(_order_ref.Ptr().Get(_prop), _op, _order_ref_found.Ptr().Get(_prop))) { + if (Compare(_order_ref REF_DEREF Get(_prop), _op, _order_ref_found REF_DEREF Get(_prop))) { _order_ref_found = _order_ref; } } @@ -119,12 +119,12 @@ class OrderQuery : public Dynamic { template Ref FindByValueViaOp(E _prop, T _value, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP) _op) { Ref _order_ref_found; - if (orders.Size() == 0) { + if (orders PTR_DEREF Size() == 0) { return _order_ref_found; } - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { Ref _order_ref = iter.Value(); - if (Compare(_order_ref.Ptr().Get(_prop), _op, _value)) { + if (Compare(_order_ref REF_DEREF Get(_prop), _op, _value)) { _order_ref_found = _order_ref; break; } diff --git a/Orders.mqh b/Orders.mqh index 906f018a6..e5ca4df9f 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -25,6 +25,7 @@ class Orders; // Includes. #include "Account/Account.h" +#include "Chart.struct.static.h" #include "Log.mqh" #include "Math.h" #include "Order.mqh" @@ -78,7 +79,7 @@ class Orders { // Enum variables. ENUM_ORDERS_POOL pool; // Struct variables. - Order *orders[]; + ARRAY(Order *, orders); // Class variables. Ref logger; // Market *market; @@ -107,7 +108,7 @@ class Orders { orders[_size] = new Order(_req); return true; } else { - Logger().Error("Cannot allocate the memory.", __FUNCTION__); + Logger() PTR_DEREF Error("Cannot allocate the memory.", __FUNCTION__); return false; } } @@ -119,7 +120,7 @@ class Orders { */ Order *SelectOrder(unsigned long _ticket) { for (unsigned int _pos = ArraySize(orders); _pos >= 0; _pos--) { - if (orders[_pos].Get(ORDER_PROP_TICKET) == _ticket) { + if (orders[_pos] PTR_DEREF Get(ORDER_PROP_TICKET) == _ticket) { return orders[_pos]; } } @@ -139,7 +140,7 @@ class Orders { ArrayResize(orders, _size + 1, 100); return orders[_size] = new Order(_ticket); } - Logger().Error(StringFormat("Cannot select order (ticket=#%d)!", _ticket), __FUNCTION__); + Logger() PTR_DEREF Error(StringFormat("Cannot select order (ticket=#%d)!", _ticket), __FUNCTION__); return NULL; } @@ -148,10 +149,10 @@ class Orders { /** * Calculate number of lots for open positions. */ - static double GetOpenLots(string _symbol = NULL, long magic_number = 0, int magic_range = 0) { + static double GetOpenLots(string _symbol = NULL_STRING, long magic_number = 0, int magic_range = 0) { double total_lots = 0; // @todo: Convert to MQL5. - _symbol = _symbol != NULL ? _symbol : _Symbol; + _symbol = _symbol != NULL_STRING ? _symbol : _Symbol; for (int i = 0; i < OrdersTotal(); i++) { if (Order::TryOrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break; if (Order::OrderSymbol() == _symbol) { @@ -173,7 +174,7 @@ class Orders { * Returns sum of all stop loss or profit take points * from all opened orders for the given symbol. */ - static double TotalSLTP(ENUM_ORDER_TYPE _cmd = NULL, bool sl = true) { + static double TotalSLTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, bool sl = true) { double total_buy_sl = 0, total_buy_tp = 0; double total_sell_sl = 0, total_sell_tp = 0; // @todo: Convert to MQL5. @@ -219,7 +220,7 @@ class Orders { /** * Get sum of total stop loss values of opened orders. */ - double TotalSL(ENUM_ORDER_TYPE _cmd = NULL) { return TotalSLTP(_cmd, true); } + double TotalSL(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return TotalSLTP(_cmd, true); } /** * Get sum of total take profit values of opened orders. @@ -227,7 +228,7 @@ class Orders { * @return * Returns total take profit points. */ - double TotalTP(ENUM_ORDER_TYPE _cmd = NULL) { return TotalSLTP(_cmd, false); } + double TotalTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return TotalSLTP(_cmd, false); } /** * Get ratio of total stop loss points. @@ -235,7 +236,7 @@ class Orders { * @return * Returns ratio between 0 and 1. */ - double RatioSL(ENUM_ORDER_TYPE _cmd = NULL) { + double RatioSL(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return 1.0 / fmax(TotalSL(_cmd) + TotalTP(_cmd), 0.01) * TotalSL(_cmd); } @@ -245,7 +246,7 @@ class Orders { * @return * Returns ratio between 0 and 1. */ - double RatioTP(ENUM_ORDER_TYPE _cmd = NULL) { + double RatioTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return 1.0 / fmax(TotalSL(_cmd) + TotalTP(_cmd), 0.01) * TotalTP(_cmd); } @@ -255,13 +256,13 @@ class Orders { * @return * Returns sum of all lots from all opened orders. */ - double TotalLots(ENUM_ORDER_TYPE _cmd = NULL) { + double TotalLots(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { double buy_lots = 0, sell_lots = 0; // @todo: Convert to MQL5. for (int i = 0; i < OrdersTotal(); i++) { if (!Order::OrderSelect(i, SELECT_BY_POS)) { - Logger().Error(StringFormat("OrderSelect (%d) returned the error", i), __FUNCTION__, - Terminal::GetErrorText(GetLastError())); + Logger() PTR_DEREF Error(StringFormat("OrderSelect (%d) returned the error", i), __FUNCTION__, + Terminal::GetErrorText(GetLastError())); break; } if (Order::OrderSymbol() == _Symbol) { @@ -299,7 +300,7 @@ class Orders { } else if (_sell_lots > 0 && _sell_lots > _buy_lots) { return ORDER_TYPE_SELL; } else { - return NULL; + return ORDER_TYPE_UNSET; } } @@ -533,7 +534,7 @@ class Orders { */ static unsigned int GetOrdersByType(ENUM_ORDER_TYPE _cmd, string _symbol = NULL) { unsigned int _counter = 0; - _symbol = _symbol != NULL ? _symbol : _Symbol; + _symbol = _symbol != NULL_STRING ? _symbol : _Symbol; for (int i = 0; i < OrdersTotal(); i++) { if (Order::TryOrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break; if (Order::OrderSymbol() == _symbol) { diff --git a/Platform.extern.h b/Platform.extern.h index 81cd3a12a..41742d45e 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -26,6 +26,12 @@ // Includes. #include "Deal.enum.h" +#include "Order.define.h" + +// Forward declarations. +class MqlTradeRequest; +class MqlTradeResult; +class MqlTradeCheckResult; template double iCustom(string symbol, int timeframe, string name, Args... args) { @@ -48,6 +54,15 @@ extern int BarsCalculated(int indicator_handle); */ extern int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)); +extern int CopyOpen(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); +extern int CopyHigh(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); +extern int CopyLow(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); +extern int CopyClose(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); + extern unsigned long PositionGetTicket(int _index); extern long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id); @@ -66,4 +81,58 @@ extern double HistoryDealGetDouble(unsigned long ticket_number, ENUM_DEAL_PROPER extern string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRING property_id); +extern bool OrderSelect(int index); + +extern bool PositionSelectByTicket(int index); + +extern bool HistoryOrderSelect(int index); + +extern bool OrderSend(const MqlTradeRequest& request, MqlTradeResult& result); + +extern bool OrderCheck(const MqlTradeRequest& request, MqlTradeCheckResult& result); + +extern unsigned long OrderGetTicket(int index); + +extern unsigned long HistoryOrderGetTicket(int index); + +extern bool HistorySelectByPosition(long position_id); + +extern bool HistoryDealSelect(unsigned long ticket); + +extern long OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id); + +extern long HistoryOrderGetInteger(unsigned long ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id); + +extern double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property_id); + +extern double HistoryOrderGetDouble(unsigned long ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id); + +string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id); + +string HistoryOrderGetString(unsigned long ticket_number, ENUM_ORDER_PROPERTY_STRING property_id); + +extern int PositionsTotal(); + +extern bool HistorySelect(datetime from_date, datetime to_date); + +extern int HistoryOrdersTotal(); + +extern int OrdersTotal(); + +extern int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(long, arr)); + +extern int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(long, arr)); + +extern int ChartID(); + +extern bool OrderCalcMargin(ENUM_ORDER_TYPE _action, string _symbol, double _volume, double _price, double& _margin); + +double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id); + +long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); + +string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); + #endif diff --git a/Platform.h b/Platform.h index 16e026f55..8b2f666f9 100644 --- a/Platform.h +++ b/Platform.h @@ -26,6 +26,7 @@ // Includes. #include "Deal.enum.h" +#include "Order.struct.h" /** * Extern declarations for C++. @@ -425,6 +426,153 @@ string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRI return 0; } +bool OrderSelect(int index, int select, int pool = MODE_TRADES) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool PositionSelectByTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool HistoryOrderSelect(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool OrderSend(const MqlTradeRequest &request, MqlTradeResult &result) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool OrderCheck(const MqlTradeRequest &request, MqlTradeCheckResult &result) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +unsigned long OrderGetTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +unsigned long HistoryOrderGetTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +bool HistorySelectByPosition(long position_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool HistoryDealSelect(unsigned long ticket) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +long OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +long HistoryOrderGetInteger(unsigned long ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double HistoryOrderGetDouble(unsigned long ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return 0; +} + +string HistoryOrderGetString(unsigned long ticket_number, ENUM_ORDER_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return 0; +} + +int PositionsTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +bool HistorySelect(datetime from_date, datetime to_date) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return 0; +} + +int HistoryOrdersTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int OrdersTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyOpen(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyHigh(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyLow(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyClose(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(long, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(long, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int ChartID() { return Platform::ChartID(); } + +bool OrderCalcMargin(ENUM_ORDER_TYPE _action, string _symbol, double _volume, double _price, double &_margin) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return false; +} + +long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return false; +} + +string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return false; +} + #endif /** diff --git a/Refs.struct.h b/Refs.struct.h index 0eef226e6..da94bf8a1 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -317,12 +317,17 @@ struct WeakRef { /** * Constructor. */ - WeakRef(WeakRef& ref) { this = ref.Ptr(); } + WeakRef(const WeakRef& ref) { THIS_REF = ref.Ptr(); } /** * Constructor. */ - WeakRef(Ref& ref) { this = ref.Ptr(); } + WeakRef(WeakRef& ref) { THIS_REF = ref.Ptr(); } + + /** + * Constructor. + */ + WeakRef(Ref& ref) { THIS_REF = ref.Ptr(); } /** * Destructor. diff --git a/Serializer/SerializerConverter.h b/Serializer/SerializerConverter.h index 571bb1353..350cf0763 100644 --- a/Serializer/SerializerConverter.h +++ b/Serializer/SerializerConverter.h @@ -51,7 +51,7 @@ class SerializerConverter { SerializerConverter(SerializerNode* _root = NULL, int serializer_flags = 0) : root_node(_root), _serializer_flags(serializer_flags) {} - SerializerConverter(SerializerConverter& right) { + SerializerConverter(const SerializerConverter& right) { root_node = right.root_node; _serializer_flags = right._serializer_flags; } diff --git a/Std.h b/Std.h index a7670198f..aaa06888f 100644 --- a/Std.h +++ b/Std.h @@ -309,12 +309,16 @@ struct _WRONG_VALUE { } } WRONG_VALUE; +const char* _empty_string_c = ""; +const string _empty_string = ""; + // Converter of NULL_VALUE into expected type. e.g., "int x = NULL_VALUE" will end up with "x = 0". struct _NULL_VALUE { template - explicit operator T() const { + operator T() const { return (T)0; } + } NULL_VALUE; /** @@ -332,11 +336,13 @@ string EnumToString(int _value) { } template <> -inline _NULL_VALUE::operator const std::string() const { - return ""; +_NULL_VALUE::operator string() const { + return _empty_string; } +#define NULL_STRING "" #else #define NULL_VALUE NULL +#define NULL_STRING NULL #endif #ifndef __MQL__ diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 88887f356..4406fe397 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -48,7 +48,7 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { /** * Constructor. */ - IndicatorBufferValueStorage(IndicatorBase *_indi_candle, int _mode = 0, bool _is_series = false) + IndicatorBufferValueStorage(IndicatorData* _indi_candle, int _mode = 0, bool _is_series = false) : mode(_mode), HistoryValueStorage(_indi_candle) {} /** @@ -56,3 +56,7 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { */ C Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_rel_shift)); } }; + +IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData* _indi, int _mode) { + return new IndicatorBufferValueStorage(_indi, _mode); +} diff --git a/String.extern.h b/String.extern.h index 8c1cde2f6..26a4a9b74 100644 --- a/String.extern.h +++ b/String.extern.h @@ -27,6 +27,8 @@ // Includes. #include +#include +#include #include #include #include @@ -127,4 +129,14 @@ int StringReplace(string& str, const string& find, const string& replacement) { return num_replacements; } +string StringToLower(string str) { + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return ::tolower(c); }); + return str; +} + +string StringToUpper(string str) { + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return ::toupper(c); }); + return str; +} + #endif diff --git a/Trade.mqh b/Trade.mqh index eb74a6564..d6d98228d 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -46,7 +46,7 @@ class Trade; class Trade : public Taskable { public: AccountMt account; - Ref indi_candle; + Ref indi_candle; DictStruct> orders_active; DictStruct> orders_history; DictStruct> orders_pending; @@ -65,11 +65,11 @@ class Trade : public Taskable { /** * Class constructor. */ - Trade(IndicatorBase *_indi_candle) : indi_candle(_indi_candle), order_last(NULL) { + Trade(IndicatorData *_indi_candle) : indi_candle(_indi_candle), order_last(NULL) { SetName(); OrdersLoadByMagic(tparams.magic_no); }; - Trade(TradeParams &_tparams, IndicatorBase *_indi_candle) + Trade(TradeParams &_tparams, IndicatorData *_indi_candle) : indi_candle(_indi_candle), tparams(_tparams), order_last(NULL) { SetName(); OrdersLoadByMagic(tparams.magic_no); @@ -92,17 +92,19 @@ class Trade : public Taskable { /** * Class deconstructor. */ - void ~Trade() {} + ~Trade() {} /* Getters simple */ /** * Gets an account parameter value of double type. */ + /* template T Get(ENUM_ACCOUNT_INFO_DOUBLE _param) { return account.Get(_param); } + */ /** * Gets a trade state value. @@ -327,16 +329,16 @@ class Trade : public Taskable { bool _result = false; Ref _order = order_last; - if (_order.IsSet() && _order.Ptr().Get(ORDER_TYPE) == _cmd && - _order.Ptr().Get(ORDER_TIME_SETUP) > GetSource() PTR_DEREF GetBarTime()) { + if (_order.IsSet() && _order REF_DEREF Get(ORDER_TYPE) == _cmd && + _order REF_DEREF Get(ORDER_TIME_SETUP) > GetSource() PTR_DEREF GetBarTime()) { _result |= true; } if (!_result) { for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().Get(ORDER_TYPE) == _cmd) { - long _time_opened = _order.Ptr().Get(ORDER_TIME_SETUP); + if (_order REF_DEREF Get(ORDER_TYPE) == _cmd) { + long _time_opened = _order REF_DEREF Get(ORDER_TIME_SETUP); _result |= _shift > 0 && _time_opened < GetSource() PTR_DEREF GetBarTime(_shift - 1); _result |= _time_opened >= GetSource() PTR_DEREF GetBarTime(_shift); if (_result) { @@ -357,7 +359,7 @@ class Trade : public Taskable { OrderData _odata; double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); - if (_order.IsSet() && _order.Ptr().IsOpen()) { + if (_order.IsSet() && _order REF_DEREF IsOpen()) { if (_odata.Get(ORDER_TYPE) == _cmd) { switch (_cmd) { case ORDER_TYPE_BUY: @@ -373,7 +375,7 @@ class Trade : public Taskable { if (!_result) { for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid() && !_result; ++iter) { _order = iter.Value(); - if (_order.IsSet() && _order.Ptr().IsOpen()) { + if (_order.IsSet() && _order REF_DEREF IsOpen()) { if (_odata.Get(ORDER_TYPE) == _cmd) { switch (_cmd) { case ORDER_TYPE_BUY: @@ -531,8 +533,8 @@ class Trade : public Taskable { * * @see: https://www.mql5.com/en/code/8568 */ - double GetMaxLotSize(double _sl, ENUM_ORDER_TYPE _cmd = NULL) { - _cmd = _cmd == NULL ? Order::OrderType() : _cmd; + double GetMaxLotSize(double _sl, ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { + _cmd = _cmd == ORDER_TYPE_UNSET ? Order::OrderType() : _cmd; double risk_amount = account.GetTotalBalance() / 100 * tparams.risk_margin; double _ticks = fabs(_sl - GetSource() PTR_DEREF GetOpenOffer(_cmd)) / GetSource() PTR_DEREF GetSymbolProps().GetTickSize(); @@ -540,7 +542,7 @@ class Trade : public Taskable { lot_size1 *= GetSource() PTR_DEREF GetSymbolProps().GetVolumeMin(); return NormalizeLots(lot_size1); } - double GetMaxLotSize(unsigned int _pips, ENUM_ORDER_TYPE _cmd = NULL) { + double GetMaxLotSize(unsigned int _pips, ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return GetMaxLotSize(CalcOrderSLTP(_pips, _cmd, ORDER_TYPE_SL)); } @@ -653,8 +655,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. */ bool OrderAdd(Order *_order) { bool _result = false; - unsigned int _last_error = _order.Get(ORDER_PROP_LAST_ERROR); - logger.Link(_order.GetLogger()); + unsigned int _last_error = _order PTR_DEREF Get(ORDER_PROP_LAST_ERROR); + logger.Link(_order PTR_DEREF GetLogger()); Ref _ref_order = _order; switch (_last_error) { case 69539: @@ -663,7 +665,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. tstats.Add(TRADE_STAT_ORDERS_ERRORS); // Pass-through. case ERR_NO_ERROR: // 0 - orders_active.Set(_order.Get(ORDER_PROP_TICKET), _ref_order); + orders_active.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _ref_order); order_last = _order; tstates.AddState(TRADE_STATE_ORDERS_ACTIVE); tstats.Add(TRADE_STAT_ORDERS_OPENED); @@ -695,10 +697,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * Moves active order to history. */ bool OrderMoveToHistory(Order *_order) { - _order.Refresh(true); - orders_active.Unset(_order.Get(ORDER_PROP_TICKET)); + _order PTR_DEREF Refresh(true); + orders_active.Unset(_order PTR_DEREF Get(ORDER_PROP_TICKET)); Ref _ref_order = _order; - bool result = orders_history.Set(_order.Get(ORDER_PROP_TICKET), _ref_order); + bool result = orders_history.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _ref_order); /* @todo if (strategy != NULL) { strategy.OnOrderClose(_order); @@ -724,8 +726,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool _result = true; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { Ref _order = iter.Value(); - if (_order.IsSet() && _order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh(_force); + if (_order.IsSet() && _order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh(_force); } else if (_order.IsSet()) { _result &= OrderMoveToHistory(_order.Ptr()); if (_first_close) { @@ -744,9 +746,9 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool _result = true; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { Ref _order = iter.Value(); - if (_order.IsSet() && _order.Ptr().IsOpen(true)) { - if (_force || _order.Ptr().ShouldRefresh()) { - _order.Ptr().Refresh(_prop); + if (_order.IsSet() && _order REF_DEREF IsOpen(true)) { + if (_force || _order REF_DEREF ShouldRefresh()) { + _order REF_DEREF Refresh(_prop); } } else if (_order.IsSet()) { _result &= OrderMoveToHistory(_order.Ptr()); @@ -758,7 +760,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Sends a trade request. */ - bool RequestSend(MqlTradeRequest &_request, OrderParams &_oparams) { + bool RequestSend(const MqlTradeRequest &_request, OrderParams &_oparams) { bool _result = false; switch (_request.action) { case TRADE_ACTION_CLOSE_BY: @@ -783,11 +785,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. Order *_order = new Order(_request, _oparams); _result = OrderAdd(_order); if (_result) { - OnOrderOpen(_order); + OnOrderOpen(PTR_TO_REF(_order)); } return _result; } - bool RequestSend(MqlTradeRequest &_request) { + bool RequestSend(const MqlTradeRequest &_request) { OrderParams _oparams; return RequestSend(_request, _oparams); } @@ -798,11 +800,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool OrderLoad(Order *_order) { bool _result = false; Ref _order_ref = _order; - if (_order.IsOpen()) { + if (_order PTR_DEREF IsOpen()) { // @todo: _order.IsPending()? - _result &= orders_active.Set(_order.Get(ORDER_PROP_TICKET), _order_ref); + _result &= orders_active.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); } else { - _result &= orders_history.Set(_order.Get(ORDER_PROP_TICKET), _order_ref); + _result &= orders_history.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); } return _result && GetLastError() == ERR_NO_ERROR; } @@ -857,13 +859,13 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - if (_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + if (_order REF_DEREF OrderClose(_reason, _comment)) { _closed++; OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + logger.AddLastError(__FUNCTION_LINE__, _order REF_DEREF Get(ORDER_PROP_LAST_ERROR)); return -1; } } else { @@ -887,16 +889,16 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh(); - if (_order.Ptr().GetRequest().type == _cmd) { - if (_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh(); + if (_order REF_DEREF GetRequest().type == _cmd) { + if (_order REF_DEREF OrderClose(_reason, _comment)) { _closed++; OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { logger.Error("Error while closing order!", __FUNCTION_LINE__, - StringFormat("Code: %d", _order.Ptr().Get(ORDER_PROP_LAST_ERROR))); + StringFormat("Code: %d", _order REF_DEREF Get(ORDER_PROP_LAST_ERROR))); return -1; } order_last = _order; @@ -925,15 +927,15 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh((E)_prop); - if (Math::Compare(_order.Ptr().Get((E)_prop), _value, _op)) { - if (_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh((E)_prop); + if (Math::Compare(_order REF_DEREF Get((E)_prop), _value, _op)) { + if (_order REF_DEREF OrderClose(_reason, _comment)) { _closed++; OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + logger.AddLastError(__FUNCTION_LINE__, _order REF_DEREF Get(ORDER_PROP_LAST_ERROR)); return -1; } } @@ -961,17 +963,17 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh(); - if (Math::Compare(_order.Ptr().Get((E)_prop1), _value1, _op) && - Math::Compare(_order.Ptr().Get((E)_prop2), _value2, _op)) { - if (!_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh(); + if (Math::Compare(_order REF_DEREF Get((E)_prop1), _value1, _op) && + Math::Compare(_order REF_DEREF Get((E)_prop2), _value2, _op)) { + if (!_order REF_DEREF OrderClose(_reason, _comment)) { #ifndef __MQL4__ // @fixme: GH-571. - logger.Info(__FUNCTION_LINE__, _order.Ptr().ToString()); + logger.Info(__FUNCTION_LINE__, _order REF_DEREF ToString()); #endif // @fixme: GH-570. - // logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + // logger.AddLastError(__FUNCTION_LINE__, _order REF_DEREF Get(ORDER_PROP_LAST_ERROR)); logger.Warning("Issue with closing the order!", __FUNCTION_LINE__); ResetLastError(); return -1; @@ -1024,11 +1026,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Calculates the best SL/TP value for the order given the limits. */ - float CalcBestSLTP(float _value, // Suggested value. - float _max_pips, // Maximal amount of pips. - ENUM_ORDER_TYPE_VALUE _mode, // Type of value (stop loss or take profit). - ENUM_ORDER_TYPE _cmd = NULL, // Order type (e.g. buy or sell). - float _lot_size = 0 // Lot size of the order. + float CalcBestSLTP(float _value, // Suggested value. + float _max_pips, // Maximal amount of pips. + ENUM_ORDER_TYPE_VALUE _mode, // Type of value (stop loss or take profit). + ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, // Order type (e.g. buy or sell). + float _lot_size = 0 // Lot size of the order. ) { float _max_value1 = _max_pips > 0 ? CalcOrderSLTP(_max_pips, _cmd, _mode) : 0; float _max_value2 = tparams.risk_margin > 0 ? GetMaxSLTP(_cmd, _lot_size, _mode) : 0; @@ -1049,8 +1051,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. ENUM_ORDER_TYPE_VALUE _mode // Type of value (stop loss or take profit). ) { double _pip_size = SymbolInfoStatic::GetPipSize(GetSource() PTR_DEREF GetSymbol()); - double _price = _cmd == NULL ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); - _cmd = _cmd == NULL ? Order::OrderType() : _cmd; + double _price = _cmd == ORDER_TYPE_UNSET ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); + _cmd = _cmd == ORDER_TYPE_UNSET ? Order::OrderType() : _cmd; return _value > 0 ? float(_price + _value * _pip_size * Order::OrderDirection(_cmd, _mode)) : 0; } float CalcOrderSL(float _value, ENUM_ORDER_TYPE _cmd) { return CalcOrderSLTP(_value, _cmd, ORDER_TYPE_SL); } @@ -1068,14 +1070,14 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * @return * Returns maximum stop loss price value for the given symbol. */ - float GetMaxSLTP(ENUM_ORDER_TYPE _cmd = NULL, float _lot_size = 0, ENUM_ORDER_TYPE_VALUE _mode = ORDER_TYPE_SL, - float _risk_margin = 1.0) { - double _price = _cmd == NULL ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); + float GetMaxSLTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, float _lot_size = 0, + ENUM_ORDER_TYPE_VALUE _mode = ORDER_TYPE_SL, float _risk_margin = 1.0) { + double _price = _cmd == ORDER_TYPE_UNSET ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); // For the new orders, use the available margin for calculation, otherwise use the account balance. float _margin = Convert::MoneyToValue( - (_cmd == NULL ? account.GetMarginAvail() : account.GetTotalBalance()) / 100 * _risk_margin, _lot_size, - GetSource() PTR_DEREF GetSymbol()); - _cmd = _cmd == NULL ? Order::OrderType() : _cmd; + (_cmd == ORDER_TYPE_UNSET ? account.GetMarginAvail() : account.GetTotalBalance()) / 100 * _risk_margin, + _lot_size, GetSource() PTR_DEREF GetSymbol()); + _cmd = _cmd == ORDER_TYPE_UNSET ? Order::OrderType() : _cmd; // @fixme // _lot_size = _lot_size <= 0 ? fmax(Order::OrderLots(), GetSource() PTR_DEREF GetVolumeMin()) : _lot_size; return (float)_price + @@ -1084,10 +1086,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // + Convert::MoneyToValue(account.GetMarginAvail() / 100 * _risk_margin, _lot_size) + _margin * Order::OrderDirection(_cmd, _mode); } - float GetMaxSL(ENUM_ORDER_TYPE _cmd = NULL, float _lot_size = 0, float _risk_margin = 1.0) { + float GetMaxSL(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, float _lot_size = 0, float _risk_margin = 1.0) { return GetMaxSLTP(_cmd, _lot_size, ORDER_TYPE_SL, _risk_margin); } - float GetMaxTP(ENUM_ORDER_TYPE _cmd = NULL, float _lot_size = 0, float _risk_margin = 1.0) { + float GetMaxTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, float _lot_size = 0, float _risk_margin = 1.0) { return GetMaxSLTP(_cmd, _lot_size, ORDER_TYPE_TP, _risk_margin); } @@ -1207,7 +1209,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * * @todo: Improve number of increases for bull/bear variables. */ - double GetTrend(int method, ENUM_TIMEFRAMES _tf = NULL, bool simple = false) { + double GetTrend(int method, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, bool simple = false) { static datetime _last_trend_check = 0; static double _last_trend = 0; string symbol = GetSource() PTR_DEREF GetSymbol(); @@ -1354,7 +1356,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * @return * Returns Buy operation for bullish, Sell for bearish, otherwise NULL for neutral market trend. */ - ENUM_ORDER_TYPE GetTrendOp(int method, ENUM_TIMEFRAMES _tf = NULL, bool simple = false) { + ENUM_ORDER_TYPE GetTrendOp(int method, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, bool simple = false) { double _curr_trend = GetTrend(method, _tf, simple); return _curr_trend == 0 ? (ENUM_ORDER_TYPE)(ORDER_TYPE_BUY + ORDER_TYPE_SELL) : (_curr_trend > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL); @@ -1494,7 +1496,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. default: logger.Error(StringFormat("Invalid order type: %s!", EnumToString(_cmd), __FUNCTION__)); } - return NULL; + return 0; } double NormalizeSL(double _value, ENUM_ORDER_TYPE _cmd) { @@ -1851,7 +1853,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // case TRADE_ORDER_CONDS_IN_TREND: // case TRADE_ORDER_CONDS_IN_TREND_NOT: default: - GetLogger().Error(StringFormat("Invalid Trade condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error(StringFormat("Invalid Trade condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); SetUserError(ERR_INVALID_PARAMETER); break; } @@ -1903,21 +1905,17 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDER_CLOSE_MOST_LOSS: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - _result = _oquery_ref.Ptr() - .FindByPropViaOp(ORDER_PROP_PROFIT, - STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_LT)) - .Ptr() - .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); + _result = _oquery_ref REF_DEREF FindByPropViaOp( + ORDER_PROP_PROFIT, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_LT)) + REF_DEREF OrderClose(ORDER_REASON_CLOSED_BY_ACTION); RefreshActiveOrders(true, true); } break; case TRADE_ACTION_ORDER_CLOSE_MOST_PROFIT: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - _result = _oquery_ref.Ptr() - .FindByPropViaOp(ORDER_PROP_PROFIT, - STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_GT)) - .Ptr() - .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); + _result = _oquery_ref REF_DEREF FindByPropViaOp( + ORDER_PROP_PROFIT, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_GT)) + REF_DEREF OrderClose(ORDER_REASON_CLOSED_BY_ACTION); RefreshActiveOrders(true, true); } break; @@ -1957,22 +1955,24 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDERS_CLOSE_SIDE_IN_LOSS: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - ENUM_ORDER_TYPE _order_types1[] = {ORDER_TYPE_BUY, ORDER_TYPE_SELL}; - ENUM_ORDER_TYPE _order_type_profitable = - _oquery_ref.Ptr() - .FindPropBySum( - _order_types1, ORDER_PROP_PROFIT, ORDER_TYPE); + ARRAY(ENUM_ORDER_TYPE, _order_types1); + ArrayPush(_order_types1, ORDER_TYPE_BUY); + ArrayPush(_order_types1, ORDER_TYPE_SELL); + ENUM_ORDER_TYPE _order_type_profitable = _oquery_ref REF_DEREF + FindPropBySum( + _order_types1, ORDER_PROP_PROFIT, ORDER_TYPE); _result = OrdersCloseViaCmd(Order::NegateOrderType(_order_type_profitable), ORDER_REASON_CLOSED_BY_ACTION) >= 0; } break; case TRADE_ACTION_ORDERS_CLOSE_SIDE_IN_PROFIT: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - ENUM_ORDER_TYPE _order_types2[] = {ORDER_TYPE_BUY, ORDER_TYPE_SELL}; - ENUM_ORDER_TYPE _order_type_profitable2 = - _oquery_ref.Ptr() - .FindPropBySum( - _order_types2, ORDER_PROP_PROFIT, ORDER_TYPE); + ARRAY(ENUM_ORDER_TYPE, _order_types2); + ArrayPush(_order_types2, ORDER_TYPE_BUY); + ArrayPush(_order_types2, ORDER_TYPE_SELL); + ENUM_ORDER_TYPE _order_type_profitable2 = _oquery_ref REF_DEREF + FindPropBySum( + _order_types2, ORDER_PROP_PROFIT, ORDER_TYPE); _result = OrdersCloseViaCmd(_order_type_profitable2, ORDER_REASON_CLOSED_BY_ACTION) >= 0; } break; @@ -1986,7 +1986,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case TRADE_ACTION_STATE_ADD: tstates.AddState(_entry.GetArg(0).ToValue()); default: - GetLogger().Error(StringFormat("Invalid Trade action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error(StringFormat("Invalid Trade action: %d!", _entry.GetId(), __FUNCTION_LINE__)); SetUserError(ERR_INVALID_PARAMETER); break; } @@ -2036,7 +2036,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Binds IndicatorCandle-based class. */ - void SetSource(IndicatorBase *_indi_candle) { indi_candle = _indi_candle; } + void SetSource(IndicatorData *_indi_candle) { indi_candle = _indi_candle; } /** * Returns pointer to Log class. diff --git a/Trade.struct.h b/Trade.struct.h index 18b5aaa4c..beaf37140 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -37,6 +37,96 @@ struct TradeStats; #include "DateTime.mqh" #include "Trade.enum.h" +/* Structure for trade statistics. */ +struct TradeStats { + DateTime dt[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; + unsigned int order_stats[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; + // Struct constructors. + TradeStats() { ResetStats(); } + TradeStats(const TradeStats &r) { THIS_REF = r; } + // Check statistics for new periods + void Check() {} + /* Getters */ + // Get order stats for the given type and period. + unsigned int GetOrderStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, bool _reset = true) { +#ifdef __debug_verbose__ + Print("GetOrderStats: type ", EnumToString(_type), ", period ", EnumToString(_period), ", reset = ", _reset); +#endif + if (_reset && _period > TRADE_STAT_ALL) { + unsigned int _periods_started = dt[(int)_type][(int)_period].GetStartedPeriods(true, false); +#ifdef __debug_verbose__ + Print("GetOrderStats: _periods_started = ", _periods_started); +#endif + if (_periods_started >= DATETIME_HOUR) { + ResetStats(_type, _period, _periods_started); + } + } + return order_stats[(int)_type][(int)_period]; + } + /* Setters */ + // Add value for the given type and period. + void Add(ENUM_TRADE_STAT_TYPE _type, int _value = 1) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + order_stats[(int)_type][(int)p] += _value; + } + } + /* Reset stats for the given periods. */ + void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, unsigned int _periods) { + if ((_periods & DATETIME_HOUR) != 0) { + ResetStats(TRADE_STAT_PER_HOUR); + } + if ((_periods & DATETIME_DAY) != 0) { + ResetStats(TRADE_STAT_PER_DAY); + } + if ((_periods & DATETIME_WEEK) != 0) { + ResetStats(TRADE_STAT_PER_WEEK); + } + if ((_periods & DATETIME_MONTH) != 0) { + ResetStats(TRADE_STAT_PER_MONTH); + } + if ((_periods & DATETIME_YEAR) != 0) { + ResetStats(TRADE_STAT_PER_YEAR); + } + } + /* Reset stats for the given type and period. */ + void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period) { + order_stats[(int)_type][(int)_period] = 0; + } + /* Reset stats for the given period. */ + void ResetStats(ENUM_TRADE_STAT_PERIOD _period) { + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { + order_stats[t][(int)_period] = 0; +#ifdef __debug_verbose__ + Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(_period)); +#endif + dt[t][(int)_period].GetStartedPeriods(true, true); + } + } + /* Reset stats for the given type. */ + void ResetStats(ENUM_TRADE_STAT_TYPE _type) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + order_stats[(int)_type][p] = 0; +#ifdef __debug_vebose__ + Print("Resetting trade counter for type ", EnumToString(_type), " and period ", EnumToString(p)); +#endif + dt[(int)_type][p].GetStartedPeriods(true, true); + } + } + /* Reset all stats. */ + void ResetStats() { + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + order_stats[t][p] = 0; +#ifdef __debug_verbose__ + Print("Resetting trade counter for type ", EnumToString((ENUM_TRADE_STAT_TYPE)t), " and period ", + EnumToString((ENUM_TRADE_STAT_PERIOD)p)); +#endif + dt[t][p].GetStartedPeriods(true, true); + } + } + } +}; + /* Structure for trade parameters. */ struct TradeParams { float lot_size; // Default lot size. @@ -59,7 +149,7 @@ struct TradeParams { } TradeParams(unsigned long _magic_no, ENUM_LOG_LEVEL _ll = V_INFO) : bars_min(100), lot_size(0), order_comment(""), log_level(_ll), magic_no(_magic_no) {} - TradeParams(TradeParams &_tparams) { this = _tparams; } + TradeParams(const TradeParams &_tparams) { THIS_REF = _tparams; } // Deconstructor. ~TradeParams() {} // Getters. @@ -106,10 +196,10 @@ struct TradeParams { return limits_stats[(int)_type][(int)_period] > 0 && _value >= limits_stats[(int)_type][(int)_period]; } bool IsLimitGe(TradeStats &_stats) { - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - unsigned int _stat_value = _stats.GetOrderStats(t, p); - if (_stat_value > 0 && IsLimitGe(t, p, _stat_value)) { + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; ++t) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; ++p) { + unsigned int _stat_value = _stats.GetOrderStats((ENUM_TRADE_STAT_TYPE)t, (ENUM_TRADE_STAT_PERIOD)p); + if (_stat_value > 0 && IsLimitGe((ENUM_TRADE_STAT_TYPE)t, (ENUM_TRADE_STAT_PERIOD)p, _stat_value)) { return true; } } @@ -168,16 +258,16 @@ struct TradeParams { } void SetLimits(ENUM_TRADE_STAT_TYPE _type, unsigned int _value = 0) { // Set new trading limits for the given type. - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - limits_stats[(int)_type][(int)p] = _value; + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + limits_stats[(int)_type][p] = _value; } } void SetLimits(unsigned int _value = 0) { // Set new trading limits for all types and periods. // Zero value is for no limits. - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - limits_stats[(int)t][(int)p] = _value; + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + limits_stats[t][p] = _value; } } } @@ -195,94 +285,6 @@ struct TradeParams { } } trade_params_defaults; -/* Structure for trade statistics. */ -struct TradeStats { - DateTime dt[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; - unsigned int order_stats[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; - // Struct constructors. - TradeStats() { ResetStats(); } - // Check statistics for new periods - void Check() {} - /* Getters */ - // Get order stats for the given type and period. - unsigned int GetOrderStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, bool _reset = true) { -#ifdef __debug_verbose__ - Print("GetOrderStats: type ", EnumToString(_type), ", period ", EnumToString(_period), ", reset = ", _reset); -#endif - if (_reset && _period > TRADE_STAT_ALL) { - unsigned int _periods_started = dt[(int)_type][(int)_period].GetStartedPeriods(true, false); -#ifdef __debug_verbose__ - Print("GetOrderStats: _periods_started = ", _periods_started); -#endif - if (_periods_started >= DATETIME_HOUR) { - ResetStats(_type, _period, _periods_started); - } - } - return order_stats[(int)_type][(int)_period]; - } - /* Setters */ - // Add value for the given type and period. - void Add(ENUM_TRADE_STAT_TYPE _type, int _value = 1) { - for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - order_stats[(int)_type][(int)p] += _value; - } - } - /* Reset stats for the given periods. */ - void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, unsigned int _periods) { - if ((_periods & DATETIME_HOUR) != 0) { - ResetStats(TRADE_STAT_PER_HOUR); - } - if ((_periods & DATETIME_DAY) != 0) { - ResetStats(TRADE_STAT_PER_DAY); - } - if ((_periods & DATETIME_WEEK) != 0) { - ResetStats(TRADE_STAT_PER_WEEK); - } - if ((_periods & DATETIME_MONTH) != 0) { - ResetStats(TRADE_STAT_PER_MONTH); - } - if ((_periods & DATETIME_YEAR) != 0) { - ResetStats(TRADE_STAT_PER_YEAR); - } - } - /* Reset stats for the given type and period. */ - void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period) { - order_stats[(int)_type][(int)_period] = 0; - } - /* Reset stats for the given period. */ - void ResetStats(ENUM_TRADE_STAT_PERIOD _period) { - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - order_stats[(int)t][(int)_period] = 0; -#ifdef __debug_verbose__ - Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(_period)); -#endif - dt[(int)t][(int)_period].GetStartedPeriods(true, true); - } - } - /* Reset stats for the given type. */ - void ResetStats(ENUM_TRADE_STAT_TYPE _type) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - order_stats[(int)_type][(int)p] = 0; -#ifdef __debug_vebose__ - Print("Resetting trade counter for type ", EnumToString(_type), " and period ", EnumToString(p)); -#endif - dt[(int)_type][(int)p].GetStartedPeriods(true, true); - } - } - /* Reset all stats. */ - void ResetStats() { - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - order_stats[(int)t][(int)p] = 0; -#ifdef __debug_verbose__ - Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(p)); -#endif - dt[(int)t][(int)p].GetStartedPeriods(true, true); - } - } - } -}; - /* Structure for trade states. */ struct TradeStates { protected: @@ -352,7 +354,7 @@ struct TradeStates { int _size = sizeof(int) * 8; for (int i = 0; i < _size; i++) { int _value = CheckState(1 << i) ? 1 : 0; - _s.Pass(THIS_REF, (string)(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC); + _s.Pass(THIS_REF, IntegerToString(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC); } return SerializerNodeObject; } From f4c5d18c0a06f220c650be149d1db2a264b9542e Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 20 Jan 2023 15:00:34 +0100 Subject: [PATCH 055/123] WIP. Code is now compiling for a FX31337-wasm's tests/js/TestRunner.js --- Account/AccountMt.h | 9 +- Array.extern.h | 4 +- Array.mqh | 6 +- Bar.struct.h | 4 +- BufferStruct.mqh | 6 +- Chart.struct.static.h | 2 + Chart.struct.tf.h | 69 +++++- Collection.mqh | 11 +- Convert.basic.h | 28 +++ Dict.mqh | 8 +- DictBase.mqh | 20 +- DictStruct.mqh | 15 -- Indicator/Indicator.enum.h | 8 +- Indicator/Indicator.struct.h | 2 +- Indicator/IndicatorData.h | 48 ++-- Indicator/IndicatorData.struct.cache.h | 6 +- Indicator/IndicatorData.struct.h | 20 +- Indicator/IndicatorData.struct.signal.h | 4 +- Log.mqh | 9 +- Math.extern.h | 2 +- Matrix.mqh | 292 ++++++++++++------------ Order.mqh | 236 +++++++++++-------- Order.struct.h | 45 ++-- Orders.mqh | 6 + Platform.extern.h | 14 +- Platform.h | 5 + Refs.struct.h | 34 +-- Serializer/SerializerCsv.h | 5 +- Std.h | 6 + Storage/ItemsHistory.h | 2 +- Storage/ValueStorage.accessor.h | 4 +- Storage/ValueStorage.h | 2 - String.extern.h | 12 +- SymbolInfo.mqh | 11 +- Task/TaskManager.h | 2 + Task/TaskObject.h | 2 +- Terminal.mqh | 81 ++++--- Tick/Tick.struct.h | 4 +- Trade.mqh | 55 +++-- Trade.struct.h | 22 +- 40 files changed, 648 insertions(+), 473 deletions(-) diff --git a/Account/AccountMt.h b/Account/AccountMt.h index 2ecb09dac..fc9d2fee1 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -470,7 +470,7 @@ class AccountMt { */ bool IsFreeMargin(ENUM_ORDER_TYPE _cmd, double size_of_lot, string _symbol = NULL) { bool _res = true; - double margin = AccountFreeMarginCheck(_symbol, _cmd, size_of_lot); + // double margin = AccountFreeMarginCheck(_symbol, _cmd, size_of_lot); if (GetLastError() == 134 /* NOT_ENOUGH_MONEY */) _res = false; return (_res); } @@ -618,9 +618,10 @@ class AccountMt { return StringFormat( "Type: %s, Server/Company/Name: %s/%s/%s, Currency: %s, Balance: %g, Credit: %g, Equity: %g, Profit: %g, " "Margin Used/Free/Avail: %g(%.1f%%)/%g/%g, Orders limit: %g: Leverage: 1:%d, StopOut Level: %d (Mode: %d)", - GetType(), GetServerName(), GetCompanyName(), GetAccountName(), GetCurrency(), GetBalance(), GetCredit(), - GetEquity(), GetProfit(), GetMarginUsed(), GetMarginUsedInPct(), GetMarginFree(), GetMarginAvail(), - GetLimitOrders(), GetLeverage(), GetStopoutLevel(), GetStopoutMode()); + C_STR(GetType()), C_STR(GetServerName()), C_STR(GetCompanyName()), C_STR(GetAccountName()), + C_STR(GetCurrency()), GetBalance(), GetCredit(), GetEquity(), GetProfit(), GetMarginUsed(), + GetMarginUsedInPct(), GetMarginFree(), GetMarginAvail(), GetLimitOrders(), GetLeverage(), GetStopoutLevel(), + GetStopoutMode()); } /** diff --git a/Array.extern.h b/Array.extern.h index f95f26d3c..821a5c751 100644 --- a/Array.extern.h +++ b/Array.extern.h @@ -34,7 +34,9 @@ int ArraySize(const ARRAY_REF(T, _array)) { } template -constexpr int ArraySize(const T REF(_array)[size]); +constexpr int ArraySize(const T REF(_array)[size]) { + return size; +} template int ArrayResize(ARRAY_REF(T, _array), int _new_size, int _reserve_size = 0) { diff --git a/Array.mqh b/Array.mqh index 8b2035edf..c0417d65a 100644 --- a/Array.mqh +++ b/Array.mqh @@ -760,7 +760,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { template static void ArrayStore(ARRAY_REF(X, array), int index, X value, int reserve_size = 0) { if (index >= ArraySize(array)) { - ArrayResize(array, MathMax(index + 1, ArraySize(array)), reserve_size); + ::ArrayResize(array, MathMax(index + 1, ArraySize(array)), reserve_size); } else if (index < 0) { Print("Index cannot be negative! " + IntegerToString(index) + " passed."); DebugBreak(); @@ -772,11 +772,11 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { template void ArrayPush(ARRAY_REF(X, array), X value) { - ArrayResize(Array::ArraySize(array) + 1); + ::ArrayResize(array, Array::ArraySize(array) + 1); array[ArraySize(array) - 1] = value; } template void ArrayPushObject(ARRAY_REF(X, array), X& value) { - ArrayResize(array, Array::ArraySize(array) + 1); + ::ArrayResize(array, Array::ArraySize(array) + 1); array[Array::ArraySize(array) - 1] = value; } diff --git a/Bar.struct.h b/Bar.struct.h index a261a8673..bc0016259 100644 --- a/Bar.struct.h +++ b/Bar.struct.h @@ -51,7 +51,7 @@ struct BarOHLC datetime time; double open, high, low, close; // Struct constructor. - BarOHLC() : open(0), high(0), low(0), close(0), time(0){}; + BarOHLC() : time(0), open(0), high(0), low(0), close(0){}; BarOHLC(double _open, double _high, double _low, double _close, datetime _time = 0) : time(_time), open(_open), high(_high), low(_low), close(_close) { if (_time == (datetime)0) { @@ -259,5 +259,5 @@ struct BarEntry { s.PassStruct(THIS_REF, "ohlc", ohlc, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } - string ToCSV() { return StringFormat("%s", ohlc.ToCSV()); } + string ToCSV() { return StringFormat("%s", C_STR(ohlc.ToCSV())); } }; diff --git a/BufferStruct.mqh b/BufferStruct.mqh index bda4a34d9..216a9f15a 100644 --- a/BufferStruct.mqh +++ b/BufferStruct.mqh @@ -63,8 +63,8 @@ class BufferStruct : public DictStruct { /** * Constructor. */ - BufferStruct() : max(INT_MIN), min(INT_MAX) { THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } - BufferStruct(BufferStruct& _right) : max(INT_MIN), min(INT_MAX) { + BufferStruct() : min(INT_MAX), max(INT_MIN) { THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } + BufferStruct(BufferStruct& _right) : min(INT_MAX), max(INT_MIN) { this = _right; THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } @@ -74,7 +74,7 @@ class BufferStruct : public DictStruct { */ void Add(TStruct& _value, long _dt = 0) { _dt = _dt > 0 ? _dt : (long)TimeCurrent(); - if (Set(_dt, _value)) { + if (THIS_ATTR Set(_dt, _value)) { min = _dt < min ? _dt : min; max = _dt > max ? _dt : max; } diff --git a/Chart.struct.static.h b/Chart.struct.static.h index 6d02bb9d4..befc9946b 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -293,6 +293,8 @@ struct ChartStatic { ChartStatic::iClose(_symbol, _tf, _shift) + ChartStatic::iClose(_symbol, _tf, _shift)) / 4; break; + default: + break; // FINAL_APPLIED_PRICE_ENTRY. } return _result; } diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 81f26a1c3..c9644babf 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -49,7 +49,7 @@ struct ChartTf { public: // Constructors. ChartTf(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : tf(_tf), tfi(ChartTf::TfToIndex(_tf)){}; - ChartTf(ENUM_TIMEFRAMES_INDEX _tfi) : tfi(_tfi), tf(ChartTf::IndexToTf(_tfi)){}; + ChartTf(ENUM_TIMEFRAMES_INDEX _tfi) : tf(ChartTf::IndexToTf(_tfi)), tfi(_tfi){}; ChartTf(const ChartTf& _ctf) : tf(_ctf.tf), tfi(_ctf.tfi){}; // Struct operators. @@ -186,6 +186,65 @@ struct ChartTf { return PERIOD_CURRENT; } + /** + * Convert timeframe period to seconds. + * + * @param + * _tf ENUM_TIMEFRAMES Specify timeframe enum. + */ + static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { + switch (_tf) { + case PERIOD_CURRENT: + return TfToSeconds(Period()); + case PERIOD_M1: // 1 minute. + return 60; + case PERIOD_M2: // 2 minutes (non-standard). + return 60 * 2; + case PERIOD_M3: // 3 minutes (non-standard). + return 60 * 3; + case PERIOD_M4: // 4 minutes (non-standard). + return 60 * 4; + case PERIOD_M5: // 5 minutes. + return 60 * 5; + case PERIOD_M6: // 6 minutes (non-standard). + return 60 * 6; + case PERIOD_M10: // 10 minutes (non-standard). + return 60 * 10; + case PERIOD_M12: // 12 minutes (non-standard). + return 60 * 12; + case PERIOD_M15: // 15 minutes. + return 60 * 15; + case PERIOD_M20: // 20 minutes (non-standard). + return 60 * 20; + case PERIOD_M30: // 30 minutes. + return 60 * 30; + case PERIOD_H1: // 1 hour. + return 60 * 60; + case PERIOD_H2: // 2 hours (non-standard). + return 60 * 60 * 2; + case PERIOD_H3: // 3 hours (non-standard). + return 60 * 60 * 3; + case PERIOD_H4: // 4 hours. + return 60 * 60 * 4; + case PERIOD_H6: // 6 hours (non-standard). + return 60 * 60 * 6; + case PERIOD_H8: // 8 hours (non-standard). + return 60 * 60 * 8; + case PERIOD_H12: // 12 hours (non-standard). + return 60 * 60 * 12; + case PERIOD_D1: // Daily. + return 60 * 60 * 24; + case PERIOD_W1: // Weekly. + return 60 * 60 * 24 * 7; + case PERIOD_MN1: // Monthly. + return 60 * 60 * 24 * 30; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return 0; + } + /** * Convert period to proper chart timeframe value. * @@ -274,14 +333,6 @@ struct ChartTf { */ static double TfToMinutes(const ENUM_TIMEFRAMES _tf) { return ChartTf::TfToSeconds(_tf) / 60; } - /** - * Convert timeframe period to seconds. - * - * @param - * _tf ENUM_TIMEFRAMES Specify timeframe enum. - */ - static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { return ChartTf::TfToSeconds(_tf); } - /** * Returns text representation of the timeframe constant. * diff --git a/Collection.mqh b/Collection.mqh index d43fa1b70..875d550c3 100644 --- a/Collection.mqh +++ b/Collection.mqh @@ -30,7 +30,7 @@ /** * Class to deal with collection of objects. */ -template +template class Collection { protected: // Variables. @@ -45,8 +45,7 @@ class Collection { Collection() {} Collection(string _name) : name(_name) {} Collection(void *_obj) { Add(_obj); } - ~Collection() { - } + ~Collection() {} /* Setters */ @@ -99,7 +98,7 @@ class Collection { /** * Returns pointer to the current object. */ - X* GetCurrentItem() { return data[index].Ptr() != NULL ? data[index].Ptr() : NULL; } + X *GetCurrentItem() { return data[index].Ptr() != NULL ? data[index].Ptr() : NULL; } /** * Returns ID of the current object. @@ -160,7 +159,7 @@ class Collection { X *_object = GetSize() > 0 ? data[0].Ptr() : NULL; for (i = 0; i < ArraySize(data); i++) { double _weight = data[i].Ptr().GetWeight(); - if (_weight < _object.GetWeight()) { + if (_weight < _object PTR_DEREF GetWeight()) { _object = data[i].Ptr(); } } @@ -175,7 +174,7 @@ class Collection { X *_object = GetSize() > 0 ? data[0].Ptr() : NULL; for (i = 0; i < ArraySize(data); i++) { double _weight = data[i].Ptr().GetWeight(); - if (_weight > _object.GetWeight()) { + if (_weight > _object PTR_DEREF GetWeight()) { _object = data[i].Ptr(); } } diff --git a/Convert.basic.h b/Convert.basic.h index 3725a9e13..f4bd8f6df 100644 --- a/Convert.basic.h +++ b/Convert.basic.h @@ -104,6 +104,13 @@ class ConvertBasic { #endif } + template + static X StringTo(string _value) { + X _out; + StringToType(_value, _out); + return _out; + } + static void BoolToType(bool _value, bool& _out) { _out = _value; } static void BoolToType(bool _value, char& _out) { _out = (char)_value; } static void BoolToType(bool _value, unsigned char& _out) { _out = (unsigned char)_value; } @@ -119,6 +126,13 @@ class ConvertBasic { static void BoolToType(bool _value, color& _out) { _out = 0; } static void BoolToType(bool _value, datetime& _out) {} + template + static X BoolTo(bool _value) { + X _out; + BoolToType(_value, _out); + return _out; + } + static void LongToType(long _value, bool& _out) { _out = (bool)_value; } static void LongToType(long _value, char& _out) { _out = (char)_value; } static void LongToType(long _value, unsigned char& _out) { _out = (unsigned char)_value; } @@ -134,6 +148,13 @@ class ConvertBasic { static void LongToType(long _value, color& _out) { _out = 0; } static void LongToType(long _value, datetime& _out) {} + template + static X LongTo(long _value) { + X _out; + LongToType(_value, _out); + return _out; + } + static void DoubleToType(double _value, bool& _out) { _out = (bool)_value; } static void DoubleToType(double _value, char& _out) { _out = (char)_value; } static void DoubleToType(double _value, unsigned char& _out) { _out = (unsigned char)_value; } @@ -148,4 +169,11 @@ class ConvertBasic { static void DoubleToType(double _value, string& _out) { _out = _value ? "1" : "0"; } static void DoubleToType(double _value, color& _out) { _out = 0; } static void DoubleToType(double _value, datetime& _out) {} + + template + static X DoubleTo(double _value) { + X _out; + DoubleToType(_value, _out); + return _out; + } }; diff --git a/Dict.mqh b/Dict.mqh index 923e63575..e18268cd5 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -126,7 +126,7 @@ class Dict : public DictBase { if (!slot) return (V)NULL; - return slot.value; + return slot PTR_DEREF value; } /** @@ -143,7 +143,7 @@ class Dict : public DictBase { return _default; } - return slot.value; + return slot PTR_DEREF value; } /** @@ -159,7 +159,7 @@ class Dict : public DictBase { return _empty; } - return slot.value; + return slot PTR_DEREF value; } /** @@ -174,7 +174,7 @@ class Dict : public DictBase { if (!slot) return false; - return slot.value == value; + return slot PTR_DEREF value == value; } /** diff --git a/DictBase.mqh b/DictBase.mqh index 5490d8c4e..413894115 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -186,7 +186,15 @@ class DictBase { if (GetMode() == DictModeList) { // In list mode value index is the slot index. - position = (int)key; +#ifndef __MQL__ + if constexpr (std::is_same::value) { +#endif + position = (int)key; +#ifndef __MQL__ + } else { + RUNTIME_ERROR("List mode for a dict could only work if Dict's key type is an integer!"); + } +#endif } else { position = Hash(key) % ArraySize(_DictSlots_ref.DictSlots); } @@ -203,7 +211,15 @@ class DictBase { if (_DictSlots_ref.DictSlots[position].IsUsed()) { if (GetMode() == DictModeList) { - _should_be_removed = position == (unsigned int)key; +#ifndef __MQL__ + if constexpr (std::is_same::value) { +#endif + _should_be_removed = position == (unsigned int)key; +#ifndef __MQL__ + } else { + RUNTIME_ERROR("List mode for a dict could only work if Dict's key type is an integer!"); + } +#endif } else { _should_be_removed = _DictSlots_ref.DictSlots[position].HasKey() && _DictSlots_ref.DictSlots[position].key == key; diff --git a/DictStruct.mqh b/DictStruct.mqh index 8a52642fa..6ff0063fb 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -123,21 +123,6 @@ class DictStruct : public DictBase { */ bool operator+=(V& value) { return Push(value); } -/** - * Inserts value using hashless key. - * - * @todo Get rid of this method. - */ -#ifdef __MQL__ - template <> -#endif - bool Push(Dynamic* value) { - V ptr = value; - - if (!InsertInto(THIS_ATTR _DictSlots_ref, ptr)) return false; - return true; - } - /** * Inserts or replaces value for a given key. */ diff --git a/Indicator/Indicator.enum.h b/Indicator/Indicator.enum.h index 660658722..d5fd94008 100644 --- a/Indicator/Indicator.enum.h +++ b/Indicator/Indicator.enum.h @@ -193,10 +193,10 @@ enum ENUM_APPLIED_VOLUME { VOLUME_TICK = 0, VOLUME_REAL = 1 }; // Indicator flags. enum ENUM_INDI_FLAGS { - INDI_FLAG_INDEXABLE_BY_SHIFT, // Indicator supports indexation by shift. - INDI_FLAG_INDEXABLE_BY_TIMESTAMP, // Indicator supports indexation by shift. - INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT, // Source indicator must be indexable by shift. - INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP // Source indicator must be indexable by timestamp. + INDI_FLAG_INDEXABLE_BY_SHIFT = 1 << 0, // Indicator supports indexation by shift. + INDI_FLAG_INDEXABLE_BY_TIMESTAMP = 1 << 1, // Indicator supports indexation by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT = 1 << 2, // Source indicator must be indexable by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP = 1 << 3 // Source indicator must be indexable by timestamp. }; // Flags indicating which data sources are required to be provided in order indicator to work. diff --git a/Indicator/Indicator.struct.h b/Indicator/Indicator.struct.h index a05d0bb5f..d3fe759a3 100644 --- a/Indicator/Indicator.struct.h +++ b/Indicator/Indicator.struct.h @@ -48,13 +48,13 @@ struct ChartParams; /* Structure for indicator parameters. */ struct IndicatorParams { public: // @todo: Change it to protected. + string custom_indi_name; // Name of the indicator passed to iCustom() method. string name; // Name of the indicator. int shift; // Shift (relative to the current bar, 0 - default). unsigned int max_params; // Max supported input params. ENUM_INDICATOR_TYPE itype; // Indicator type (e.g. INDI_RSI). color indi_color; // Indicator color. ARRAY(DataParamEntry, input_params); // Indicator input params. - string custom_indi_name; // Name of the indicator passed to iCustom() method. string symbol; // Symbol used by indicator. public: /* Special methods */ diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index d6ab968d3..2d706bda3 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -95,6 +95,8 @@ class IndicatorData : public IndicatorBase { // SetDataSource(_indi_price, true, PRICE_OPEN); } break; + default: + break; } // By default, indicator is indexable only by shift and data source must be also indexable by shift. flags = INDI_FLAG_INDEXABLE_BY_SHIFT | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT; @@ -159,7 +161,7 @@ class IndicatorData : public IndicatorBase { * Access indicator entry data using [] operator via shift. */ IndicatorDataEntry operator[](int _rel_shift) { - if (!bool(flags | INDI_FLAG_INDEXABLE_BY_SHIFT)) { + if (!bool(flags & INDI_FLAG_INDEXABLE_BY_SHIFT)) { Print(GetFullName(), " is not indexable by shift!"); DebugBreak(); IndicatorDataEntry _default; @@ -227,6 +229,9 @@ class IndicatorData : public IndicatorBase { case IDATA_INDICATOR: _mode = "On-I"; break; + default: + _mode = "Unkw"; + break; } return GetName() + "#" + IntegerToString(GetId()) + "-" + _mode + "[" + IntegerToString(_max_modes) + "]" + @@ -256,7 +261,6 @@ class IndicatorData : public IndicatorBase { return _price; } datetime _bar_time = GetBarTime(_shift); - float _value = 0; BarOHLC _ohlc(_values, _bar_time); _price = _ohlc.GetAppliedPrice(_ap); } @@ -741,7 +745,7 @@ class IndicatorData : public IndicatorBase { */ void AddListener(IndicatorData* _indi) { WeakRef _ref = _indi; - ArrayPushObject(listeners, _ref); + ArrayPush(listeners, _ref); } /** @@ -789,15 +793,15 @@ class IndicatorData : public IndicatorBase { } if (indi_src.IsSet()) { - if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT) && - !bool(_indi PTR_DEREF GetFlags() | INDI_FLAG_INDEXABLE_BY_SHIFT)) { + if (bool(flags & INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT) && + !bool(_indi PTR_DEREF GetFlags() & INDI_FLAG_INDEXABLE_BY_SHIFT)) { Print(GetFullName(), ": Cannot set data source to ", _indi PTR_DEREF GetFullName(), ", because source indicator isn't indexable by shift!"); DebugBreak(); return; } - if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP) && - !bool(_indi PTR_DEREF GetFlags() | INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { + if (bool(flags & INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP) && + !bool(_indi PTR_DEREF GetFlags() & INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { Print(GetFullName(), ": Cannot set data source to ", _indi PTR_DEREF GetFullName(), ", because source indicator isn't indexable by timestamp!"); DebugBreak(); @@ -1004,7 +1008,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's value in plain format. */ - virtual string ToString(int _index = 0) { + string EntryToString(int _index = 0) { IndicatorDataEntry _entry = GetEntry(_index); int _serializer_flags = SERIALIZER_FLAG_SKIP_HIDDEN | SERIALIZER_FLAG_INCLUDE_DEFAULT | SERIALIZER_FLAG_INCLUDE_DYNAMIC | SERIALIZER_FLAG_INCLUDE_FEATURE; @@ -1044,10 +1048,6 @@ class IndicatorData : public IndicatorBase { } switch (GetAppliedPrice()) { - case PRICE_ASK: - return INDI_VS_TYPE_PRICE_ASK; - case PRICE_BID: - return INDI_VS_TYPE_PRICE_BID; case PRICE_OPEN: return INDI_VS_TYPE_PRICE_OPEN; case PRICE_HIGH: @@ -1062,6 +1062,12 @@ class IndicatorData : public IndicatorBase { return INDI_VS_TYPE_PRICE_TYPICAL; case PRICE_WEIGHTED: return INDI_VS_TYPE_PRICE_WEIGHTED; + default: + if ((int)GetAppliedPrice() == (int)PRICE_ASK) { + return INDI_VS_TYPE_PRICE_ASK; + } else if ((int)GetAppliedPrice() == (int)PRICE_BID) { + return INDI_VS_TYPE_PRICE_BID; + } } Print("Error: ", GetFullName(), " has not supported applied price set: ", EnumToString(GetAppliedPrice()), "!"); @@ -1310,10 +1316,6 @@ class IndicatorData : public IndicatorBase { } switch (_ap) { - case PRICE_ASK: - return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); - case PRICE_BID: - return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); case PRICE_OPEN: return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); case PRICE_HIGH: @@ -1329,6 +1331,11 @@ class IndicatorData : public IndicatorBase { case PRICE_WEIGHTED: return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_WEIGHTED); default: + if ((int)GetAppliedPrice() == (int)PRICE_ASK) { + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); + } else if ((int)GetAppliedPrice() == (int)PRICE_BID) { + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); + } Print("Error: Invalid applied price " + EnumToString(_ap) + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " "IndicatorData::HasSpecificAppliedPriceValueStorage()!"); @@ -1353,10 +1360,6 @@ class IndicatorData : public IndicatorBase { } switch (_ap) { - case PRICE_ASK: - return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); - case PRICE_BID: - return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); case PRICE_OPEN: return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); case PRICE_HIGH: @@ -1372,6 +1375,11 @@ class IndicatorData : public IndicatorBase { case PRICE_WEIGHTED: return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_WEIGHTED); default: + if ((int)GetAppliedPrice() == (int)PRICE_ASK) { + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); + } else if ((int)GetAppliedPrice() == (int)PRICE_BID) { + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); + } Print("Error: Invalid applied price " + EnumToString(_ap) + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " "IndicatorData::GetSpecificAppliedPriceValueStorage()!"); diff --git a/Indicator/IndicatorData.struct.cache.h b/Indicator/IndicatorData.struct.cache.h index b3c7c4f0e..492b305a9 100644 --- a/Indicator/IndicatorData.struct.cache.h +++ b/Indicator/IndicatorData.struct.cache.h @@ -176,8 +176,10 @@ class IndicatorCalculateCache : public Dynamic { return price_low_buffer; case PRICE_CLOSE: return price_close_buffer; + default: + RUNTIME_ERROR("Applied price not supported!"); } - return NULL; + return nullptr; } /** @@ -241,7 +243,7 @@ class IndicatorCalculateCache : public Dynamic { template D GetTailValue(int _buffer_index, int _shift) { ValueStorage *_buff = GetBuffer(_buffer_index); - int _index = _buff.IsSeries() ? _shift : (ArraySize(_buff) - _shift - 1); + int _index = _buff PTR_DEREF IsSeries() ? _shift : (ArraySize(_buff) - _shift - 1); return _buff[_index].Get(); } diff --git a/Indicator/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h index 7d399c0c1..dd4e29493 100644 --- a/Indicator/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -187,7 +187,7 @@ struct IndicatorDataEntry { ARRAY(IndicatorDataEntryValue, values); // Constructors. - IndicatorDataEntry(int _size = 1) : flags(INDI_ENTRY_FLAG_NONE), timestamp(0) { Resize(_size); } + IndicatorDataEntry(int _size = 1) : timestamp(0), flags(INDI_ENTRY_FLAG_NONE) { Resize(_size); } IndicatorDataEntry(const IndicatorDataEntry &_entry) { THIS_REF = _entry; } int GetSize() { return ArraySize(values); } // Operator overloading methods. @@ -327,7 +327,7 @@ struct IndicatorDataEntry { int GetYear() { return DateTimeStatic::Year(timestamp); } long GetTime() { return timestamp; }; ENUM_DATATYPE GetDataType(int _mode) { return values[_mode].GetDataType(); } - ushort GetDataTypeFlags(ENUM_DATATYPE _dt) { + unsigned short GetDataTypeFlags(ENUM_DATATYPE _dt) { switch (_dt) { case TYPE_BOOL: case TYPE_CHAR: @@ -402,21 +402,21 @@ struct IndicatorDataEntry { /* Structure for indicator data parameters. */ struct IndicatorDataParams { public: - // @todo: Move to protected. - bool is_draw; // Draw active. - color indi_color; // Indicator color. protected: /* Struct protected variables */ - bool is_fed; // Whether calc_start_bar is already calculated. int data_src_mode; // Mode used as input from data source. int draw_window; // Drawing window. - int src_id; // Id of the indicator to be used as data source. - int src_mode; // Mode of source indicator - unsigned int max_buffers; // Max buffers to store. - unsigned int max_modes; // Max supported indicator modes (values per entry). ENUM_DATATYPE dtype; // Type of basic data to store values (DTYPE_DOUBLE, DTYPE_INT). + unsigned int max_modes; // Max supported indicator modes (values per entry). + unsigned int max_buffers; // Max buffers to store. ENUM_IDATA_SOURCE_TYPE idstype; // Indicator's data source type (e.g. IDATA_BUILTIN, IDATA_ICUSTOM). ENUM_IDATA_VALUE_RANGE idvrange; // Indicator's range value data type. + color indi_color; // Indicator color. + // @todo: Move to protected. + bool is_draw; // Draw active. + bool is_fed; // Whether calc_start_bar is already calculated. + int src_id; // Id of the indicator to be used as data source. + int src_mode; // Mode of source indicator public: /* Struct enumerations */ enum ENUM_IDATA_PARAM { diff --git a/Indicator/IndicatorData.struct.signal.h b/Indicator/IndicatorData.struct.signal.h index 0c141f95b..0ea5024a6 100644 --- a/Indicator/IndicatorData.struct.signal.h +++ b/Indicator/IndicatorData.struct.signal.h @@ -90,8 +90,8 @@ struct IndicatorSignal { Alert(__FUNCSIG__, " Should use pointer to IndicatorBase as a source of prices!"); DebugBreak(); - int _shift0 = 0; - int _shift1 = 1; + // int _shift0 = 0; + // int _shift1 = 1; double _price_w0 = 0; double _price_w1 = 0; diff --git a/Log.mqh b/Log.mqh index 9930bebd3..0a4bff34a 100644 --- a/Log.mqh +++ b/Log.mqh @@ -60,12 +60,12 @@ class Log : public Object { ENUM_LOG_LEVEL log_level; string msg; }; - DictStruct> logs; - string filename; - ARRAY(log_entry, data); int last_entry; datetime last_flush; ENUM_LOG_LEVEL log_level; + string filename; + ARRAY(log_entry, data); + DictStruct> logs; public: /** @@ -145,7 +145,7 @@ class Log : public Object { * Adds a log entry. */ bool Add(string msg, string prefix, string suffix, ENUM_LOG_LEVEL entry_log_level = V_INFO) { - return Add(prefix, msg, suffix, entry_log_level); + return Add(entry_log_level, msg, prefix, suffix); } bool Add(ARRAY_REF(double, arr), string prefix, string suffix, ENUM_LOG_LEVEL entry_log_level = V_INFO) { return Add(prefix, Array::ArrToString(arr), suffix, entry_log_level); @@ -315,7 +315,6 @@ class Log : public Object { bool DeleteByTimestamp(datetime timestamp) { int size = ArraySize(data); if (size > 0) { - int offset = 0; for (int i = 0; i < size; i++) { if (data[i].timestamp == timestamp) { Erase(data, i); diff --git a/Math.extern.h b/Math.extern.h index 7965fd1f3..d63691eb4 100644 --- a/Math.extern.h +++ b/Math.extern.h @@ -76,5 +76,5 @@ T log10(T value) { return std::log10(value); } int MathRand() { return std::rand() % 32768; } -int rand() { return std::rand() % 32768; } +// int rand() { return std::rand() % 32768; } #endif diff --git a/Matrix.mqh b/Matrix.mqh index de0f7177c..5fdbc3e0f 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -137,30 +137,31 @@ struct MatrixDimensionAccessor { /** * Constructor. */ - MatrixDimensionAccessor(Matrix* _ptr_matrix = NULL, MatrixDimension* _ptr_dimension = NULL, int _index = 0) + MatrixDimensionAccessor(Matrix* _ptr_matrix = nullptr, MatrixDimension* _ptr_dimension = nullptr, + int _index = 0) : ptr_matrix(_ptr_matrix), ptr_dimension(_ptr_dimension), index(_index) {} /** * Index operator. Returns container or value accessor. */ MatrixDimensionAccessor operator[](int _index) { - return MatrixDimensionAccessor(ptr_matrix, ptr_dimension.containers[index], _index); + return MatrixDimensionAccessor(ptr_matrix, ptr_dimension PTR_DEREF containers[index], _index); } /** * Returns target dimension type. */ - ENUM_MATRIX_DIMENSION_TYPE Type() const { return ptr_dimension.type; } + ENUM_MATRIX_DIMENSION_TYPE Type() const { return ptr_dimension PTR_DEREF type; } #define MATRIX_ACCESSOR_OPERATOR(OP) \ void operator OP(X _value) { \ - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { \ - Print("Error: Trying to use matrix", ptr_matrix.Repr(), \ + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { \ + Print("Error: Trying to use matrix", ptr_matrix PTR_DEREF Repr(), \ "'s value operator " #OP " in a dimension which doesn't contain values!"); \ return; \ } \ \ - ptr_dimension.values[index] OP _value; \ + ptr_dimension PTR_DEREF values[index] OP _value; \ } MATRIX_ACCESSOR_OPERATOR(+=) @@ -172,24 +173,26 @@ struct MatrixDimensionAccessor { * Assignment operator. Sets value for this dimensions. */ void operator=(X _value) { - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { - Print("Error: Trying to set matrix", ptr_matrix.Repr(), "'s value in a dimension which doesn't contain values!"); + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { + Print("Error: Trying to set matrix", ptr_matrix PTR_DEREF Repr(), + "'s value in a dimension which doesn't contain values!"); return; } - ptr_dimension.values[index] = _value; + ptr_dimension PTR_DEREF values[index] = _value; } /** * Returns value pointed by this accessor. */ X Val() { - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { - Print("Error: Trying to get value from matrix", ptr_matrix.Repr(), "'s dimension which doesn't contain values!"); + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { + Print("Error: Trying to get value from matrix", ptr_matrix PTR_DEREF Repr(), + "'s dimension which doesn't contain values!"); return (X)EMPTY_VALUE; } - return ptr_dimension.values[index]; + return ptr_dimension PTR_DEREF values[index]; } /** @@ -197,16 +200,17 @@ struct MatrixDimensionAccessor { * dimension length. */ X ValOrZero() { - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { - Print("Error: Trying to get value from matrix", ptr_matrix.Repr(), "'s dimension which doesn't contain values!"); + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { + Print("Error: Trying to get value from matrix", ptr_matrix PTR_DEREF Repr(), + "'s dimension which doesn't contain values!"); return (X)EMPTY_VALUE; } - int _num_values = ArraySize(ptr_dimension.values); + int _num_values = ArraySize(ptr_dimension PTR_DEREF values); if (_num_values == 0 || index >= _num_values) return (X)0; - return ptr_dimension.values[index]; + return ptr_dimension PTR_DEREF values[index]; } }; @@ -219,13 +223,13 @@ class MatrixDimension { ENUM_MATRIX_DIMENSION_TYPE type; // Values array if type is "Values". - X values[]; + ARRAY(X, values); // Physical position of the dimension in the matrix. int position[MATRIX_DIMENSIONS - 1]; // Containers array if type is "Containers" - MatrixDimension* containers[]; + ARRAY(MatrixDimension, containers); /** * Constructor. @@ -249,13 +253,13 @@ class MatrixDimension { int i; if (type == MATRIX_DIMENSION_TYPE_CONTAINERS) { - ArrayResize(_clone.containers, ArraySize(containers)); + ArrayResize(_clone PTR_DEREF containers, ArraySize(containers)); for (i = 0; i < ArraySize(containers); ++i) { - _clone.containers[i] = containers[i].Clone(); + _clone PTR_DEREF containers[i] = containers[i].Clone(); } } else { - ArrayCopy(_clone.values, values); + ArrayCopy(_clone PTR_DEREF values, values); } return _clone; @@ -462,6 +466,9 @@ class MatrixDimension { ArrayFill(values, _last_size, _num_items - _last_size, (X)0); } break; + + default: + RUNTIME_ERROR("We shouldn't be here!"); } type = _type; @@ -478,21 +485,21 @@ class MatrixDimension { if (index == 0 && _dimensions[0] == 0) { // Matrix without any dimensions. - _ptr_parent_dimension.type = MATRIX_DIMENSION_TYPE_VALUES; + _ptr_parent_dimension PTR_DEREF type = MATRIX_DIMENSION_TYPE_VALUES; } - _ptr_parent_dimension.SetPosition(_current_position, index); + _ptr_parent_dimension PTR_DEREF SetPosition(_current_position, index); int i; if (_dimensions[index + 1] == 0) { - _ptr_parent_dimension.Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_VALUES); + _ptr_parent_dimension PTR_DEREF Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_VALUES); } else { - _ptr_parent_dimension.Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_CONTAINERS); + _ptr_parent_dimension PTR_DEREF Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_CONTAINERS); for (i = 0; i < _dimensions[index]; ++i) { - _ptr_parent_dimension.containers[i] = - SetDimensions(_ptr_parent_dimension.containers[i], _dimensions, index + 1, _current_position); + _ptr_parent_dimension PTR_DEREF containers[i] = + SetDimensions(_ptr_parent_dimension PTR_DEREF containers[i], _dimensions, index + 1, _current_position); ++_current_position[index]; } @@ -505,7 +512,6 @@ class MatrixDimension { * Executes operation on a single value. */ X OpSingle(ENUM_MATRIX_OPERATION _op, X _src = (X)0, X _arg1 = (X)0, X _arg2 = (X)0, X _arg3 = (X)0) { - int _pos = 0; switch (_op) { case MATRIX_OPERATION_ABS: return MathAbs(_src); @@ -668,20 +674,19 @@ class MatrixDimension { */ void Op(MatrixDimension* _r, ENUM_MATRIX_OPERATION _op, X _arg1 = (X)0, int _only_value_index = -1) { int i; - bool r_is_single = ArraySize(_r.values) == 1; - if (_r.type == MATRIX_DIMENSION_TYPE_VALUES && ArraySize(_r.values) == 1) { + if (_r PTR_DEREF type == MATRIX_DIMENSION_TYPE_VALUES && ArraySize(_r PTR_DEREF values) == 1) { // There is only one value in the right container, we will use that value for all operations. _only_value_index = 0; } switch (type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: - switch (_r.type) { + switch (_r PTR_DEREF type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: // Both dimensions have containers. for (i = 0; i < ArraySize(containers); ++i) { - containers[i].Op(_r.containers[ArraySize(_r.containers) == 1 ? 0 : i], _op, _arg1); + containers[i].Op(_r PTR_DEREF containers[ArraySize(_r PTR_DEREF containers) == 1 ? 0 : i], _op, _arg1); } break; case MATRIX_DIMENSION_TYPE_VALUES: @@ -695,21 +700,22 @@ class MatrixDimension { } break; case MATRIX_DIMENSION_TYPE_VALUES: - switch (_r.type) { + switch (_r PTR_DEREF type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: // Right dimension have containers. - if (ArraySize(_r.containers) != 1) { + if (ArraySize(_r PTR_DEREF containers) != 1) { Alert("Right container must have exactly one element!"); return; } - Op(_r.containers[0], _op, _arg1); + Op(_r PTR_DEREF containers[0], _op, _arg1); break; case MATRIX_DIMENSION_TYPE_VALUES: // Left and right dimensions have values or we use single right value. for (i = 0; i < ArraySize(values); ++i) { - values[i] = OpSingle(_op, values[i], _r.values[_only_value_index != -1 ? _only_value_index : i]); + values[i] = + OpSingle(_op, values[i], _r PTR_DEREF values[_only_value_index != -1 ? _only_value_index : i]); } break; @@ -763,7 +769,7 @@ class Matrix { return; } - Initialize(_right.ptr_first_dimension.Clone()); + Initialize(_right.ptr_first_dimension PTR_DEREF Clone()); } /** @@ -778,7 +784,7 @@ class Matrix { * Matrix initializer. */ void Initialize(MatrixDimension* _dimension) { - if (ptr_first_dimension != NULL) delete ptr_first_dimension; + if (ptr_first_dimension != nullptr) delete ptr_first_dimension; ptr_first_dimension = _dimension; // Calculating dimensions. @@ -791,11 +797,11 @@ class Matrix { for (i = 0; i < MATRIX_DIMENSIONS; ++i) { if (_dimension == NULL) break; - if (_dimension.type == MATRIX_DIMENSION_TYPE_CONTAINERS) { - dimensions[i] = ArraySize(_dimension.containers); - _dimension = _dimension.containers[0]; - } else if (_dimension.type == MATRIX_DIMENSION_TYPE_VALUES) { - dimensions[i++] = ArraySize(_dimension.values); + if (_dimension PTR_DEREF type == MATRIX_DIMENSION_TYPE_CONTAINERS) { + dimensions[i] = ArraySize(_dimension PTR_DEREF containers); + _dimension = _dimension PTR_DEREF containers[0]; + } else if (_dimension PTR_DEREF type == MATRIX_DIMENSION_TYPE_VALUES) { + dimensions[i++] = ArraySize(_dimension PTR_DEREF values); break; } else { Print("Internal error: unknown dimension type!"); @@ -824,14 +830,14 @@ class Matrix { /** * Assignment operator. */ - void operator=(const Matrix& _right) { Initialize(_right.ptr_first_dimension.Clone()); } + void operator=(const Matrix& _right) { Initialize(_right.ptr_first_dimension PTR_DEREF Clone()); } /** * Assignment operator. Initializes matrix using given dimension. */ Matrix(MatrixDimensionAccessor& accessor) { if (accessor.Type() == MATRIX_DIMENSION_TYPE_CONTAINERS) { - Initialize(accessor.ptr_dimension.containers[accessor.index].Clone()); + Initialize(accessor.ptr_dimension PTR_DEREF containers[accessor.index].Clone()); } else if (accessor.Type() == MATRIX_DIMENSION_TYPE_VALUES) { SetShape(1); this[0] = accessor.Val(); @@ -847,7 +853,7 @@ class Matrix { * Destructor. */ ~Matrix() { - if (ptr_first_dimension != NULL) { + if (ptr_first_dimension != nullptr) { delete ptr_first_dimension; } } @@ -925,7 +931,7 @@ class Matrix { return; } - int initial_container_size = ptr_first_dimension.DuplicateDimension(_level, _num); + int initial_container_size = ptr_first_dimension PTR_DEREF DuplicateDimension(_level, _num); dimensions[_level] += _num * initial_container_size; RecalculateSize(); } @@ -1068,7 +1074,7 @@ class Matrix { */ void Abs() { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_ABS); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_ABS); } } @@ -1077,7 +1083,7 @@ class Matrix { */ void Add(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_ADD, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_ADD, value); } } @@ -1091,7 +1097,7 @@ class Matrix { */ void Sub(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_SUBTRACT, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_SUBTRACT, value); } } @@ -1105,7 +1111,7 @@ class Matrix { */ void Mul(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_MULTIPLY, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_MULTIPLY, value); } } @@ -1119,7 +1125,7 @@ class Matrix { */ void Div(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_DIVIDE, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_DIVIDE, value); } } @@ -1128,7 +1134,7 @@ class Matrix { */ void Fill(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL, value); } } @@ -1137,7 +1143,7 @@ class Matrix { */ void FillRandom(int _seed = -1) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_RANDOM, _seed); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_RANDOM, _seed); } } @@ -1146,7 +1152,7 @@ class Matrix { */ void FillRandom(X _start, X _end, int _seed = -1) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_RANDOM_RANGE, _start, _end, _seed); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_RANDOM_RANGE, _start, _end, _seed); } } @@ -1155,7 +1161,7 @@ class Matrix { */ void FillPosAdd() { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_POS_ADD); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_POS_ADD); } } @@ -1164,7 +1170,7 @@ class Matrix { */ void FillPosMul() { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_POS_MUL); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_POS_MUL); } } @@ -1175,7 +1181,7 @@ class Matrix { X _out1 = 0, _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); } return _out1; } @@ -1187,7 +1193,7 @@ class Matrix { X _out1 = MaxOf((X)0), _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_MIN, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_MIN, 0, 0, 0, _out1, _out2, _out3); } return _out1; } @@ -1199,7 +1205,7 @@ class Matrix { X _out1 = MinOf((X)0), _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_MAX, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_MAX, 0, 0, 0, _out1, _out2, _out3); } return _out1; } @@ -1211,7 +1217,7 @@ class Matrix { X _out1 = 0, _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); return GetSize() > 0 ? _out1 / GetSize() : 0; } return MinOf((X)0); @@ -1219,7 +1225,7 @@ class Matrix { void Power(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_POWER, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_POWER, value); } } @@ -1228,7 +1234,7 @@ class Matrix { */ X Med() { if (ptr_first_dimension) { - X array[]; + ARRAY(X, array); GetRawArray(array); ArraySort(array); @@ -1293,8 +1299,8 @@ class Matrix { Matrix* operator+(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); } return result; @@ -1305,7 +1311,7 @@ class Matrix { */ void operator+=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); } } @@ -1315,8 +1321,8 @@ class Matrix { Matrix* operator-(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); } return result; @@ -1327,7 +1333,7 @@ class Matrix { */ void operator-=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); } } @@ -1337,8 +1343,8 @@ class Matrix { Matrix* operator*(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); } return result; @@ -1349,7 +1355,7 @@ class Matrix { */ void operator*=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); } } @@ -1359,8 +1365,8 @@ class Matrix { Matrix* operator/(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); } return result; @@ -1371,7 +1377,7 @@ class Matrix { */ void operator/=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); } } @@ -1381,21 +1387,21 @@ class Matrix { void GetRawArray(ARRAY_REF(X, array)) { ArrayResize(array, GetSize()); int offset = 0; - ptr_first_dimension.FillArray(array, offset); + ptr_first_dimension PTR_DEREF FillArray(array, offset); } /** * Flattens matrix. */ Matrix* Flatten() { - X values[]; + ARRAY(X, values); GetRawArray(values); Matrix* result = new Matrix(ArraySize(values)); for (int i = 0; i < ArraySize(values); ++i) { - result[i] = values[i]; + PTR_TO_REF(result)[i] = values[i]; } return result; @@ -1432,7 +1438,7 @@ class Matrix { } int offset = 0; - ptr_first_dimension.FromArray(_array, offset); + ptr_first_dimension PTR_DEREF FromArray(_array, offset); } /** @@ -1489,15 +1495,15 @@ class Matrix { Print("Mean(): Unsupported absolute difference operator: ", EnumToString(_abs_diff_op), "!"); } - if (!ShapeCompatible(&this, _prediction)) { - Print("MeanAbsolute(): Shape ", Repr(), " is not compatible with prediction shape ", _prediction.Repr(), "!"); - return NULL; + if (!ShapeCompatible(THIS_PTR, _prediction)) { + Print("MeanAbsolute(): Shape ", Repr(), " is not compatible with prediction shape ", _prediction PTR_DEREF Repr(), + "!"); + return nullptr; } - if (_weights != NULL && _weights.GetDimensions() > this PTR_DEREF GetDimensions()) { - Print("MeanAbsolute(): Shape ", Repr(), ": Weights must be a tensor level <= ", this PTR_DEREF GetDimensions(), - "!"); - return NULL; + if (_weights != nullptr && _weights PTR_DEREF GetDimensions() > this PTR_DEREF GetDimensions()) { + Print("MeanAbsolute(): Shape ", Repr(), ": Weights must be a tensor level <= ", THIS_ATTR GetDimensions(), "!"); + return nullptr; } Matrix*_matrix, *_pooled; @@ -1506,27 +1512,31 @@ class Matrix { _matrix = Clone(); // Calculating absolute difference between copied tensor and given prediction. - _matrix.ptr_first_dimension.Op(_prediction.ptr_first_dimension, _abs_diff_op); + _matrix PTR_DEREF ptr_first_dimension PTR_DEREF Op(_prediction PTR_DEREF ptr_first_dimension, _abs_diff_op); switch (_abs_diff_op) { case MATRIX_OPERATION_ABS_DIFF_SQUARE: case MATRIX_OPERATION_ABS_DIFF_SQUARE_LOG: // Reducing values of the last dimension of the matrix. - _pooled = _matrix.GetPooled(_reduction, MATRIX_PADDING_SAME, dimensions[1] == 0 ? dimensions[0] : 1, - dimensions[2] == 0 ? dimensions[1] : 1, dimensions[3] == 0 ? dimensions[2] : 1, - dimensions[4] == 0 ? dimensions[3] : 1, dimensions[5] == 0 ? dimensions[4] : 1); + _pooled = + _matrix PTR_DEREF GetPooled(_reduction, MATRIX_PADDING_SAME, dimensions[1] == 0 ? dimensions[0] : 1, + dimensions[2] == 0 ? dimensions[1] : 1, dimensions[3] == 0 ? dimensions[2] : 1, + dimensions[4] == 0 ? dimensions[3] : 1, dimensions[5] == 0 ? dimensions[4] : 1); // Physically reducing last dimension of the matrix. - _pooled.ReduceSimple(); + _pooled PTR_DEREF ReduceSimple(); delete _matrix; _matrix = _pooled; break; + default: + RUNTIME_ERROR("Difference operation not supported!") } - if (_weights != NULL) { + if (_weights != nullptr) { // Multiplying copied tensor by given weights. Note that weights tensor could be of lower level than original // tensor. - _matrix.ptr_first_dimension.Op(_weights.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + _matrix PTR_DEREF ptr_first_dimension PTR_DEREF Op(_weights PTR_DEREF ptr_first_dimension, + MATRIX_OPERATION_MULTIPLY); } return _matrix; @@ -1536,17 +1546,17 @@ class Matrix { * Reduces single or all dimensions containing only a single value. */ void ReduceSimple(bool _only_last_dimension = true, ENUM_MATRIX_OPERATION _reduce_op = MATRIX_OPERATION_SUM) { - if (ptr_first_dimension != NULL) { - ptr_first_dimension.ReduceSimple(_only_last_dimension ? GetDimensions() - 1 : 0, _reduce_op); + if (ptr_first_dimension != nullptr) { + ptr_first_dimension PTR_DEREF ReduceSimple(_only_last_dimension ? GetDimensions() - 1 : 0, _reduce_op); } } void Reduce(int _level = 0, ENUM_MATRIX_OPERATION _reduce_op = MATRIX_OPERATION_SUM) { - if (ptr_first_dimension == NULL) { + if (ptr_first_dimension == nullptr) { return; } - ptr_first_dimension.Reduce(_level, _reduce_op); + ptr_first_dimension PTR_DEREF Reduce(_level, _reduce_op); for (int i = _level + 1; i < MATRIX_DIMENSIONS; ++i) { dimensions[i] = 0; @@ -1559,11 +1569,12 @@ class Matrix { * Computes the Poisson loss */ Matrix* Poisson(Matrix* _prediction) { - if (ptr_first_dimension == NULL) { - return NULL; + if (ptr_first_dimension == nullptr) { + return nullptr; } Matrix* _clone = Clone(); - _clone.ptr_first_dimension.Op(_prediction.ptr_first_dimension, MATRIX_OPERATION_POISSON); + _clone PTR_DEREF ptr_first_dimension PTR_DEREF Op(_prediction PTR_DEREF ptr_first_dimension, + MATRIX_OPERATION_POISSON); return _clone; } @@ -1577,7 +1588,7 @@ class Matrix { Matrix* VectorReduce(Matrix* _product, ENUM_MATRIX_VECTOR_REDUCE _reduce, int _dimension = 0) { if (_dimension == -1) _dimension = GetDimensions() - 1; - if (!ShapeCompatibleLossely(&this, _product)) { + if (!ShapeCompatibleLossely(THIS_PTR, _product)) { // Alert("VectorReduce(): Incompatible shapes: ", Repr(), " and ", _product.Repr(), "!"); // return NULL; } @@ -1603,7 +1614,6 @@ class Matrix { Matrix* _ptr_result = new Matrix(_out_dims[0], _out_dims[1], _out_dims[2], _out_dims[3], _out_dims[4]); - int _curr_dimension = 0; bool _stop = false; while (!_stop) { @@ -1621,7 +1631,8 @@ class Matrix { // Taking one group at a time. for (int b = 0; b < dimensions[_dimension]; ++b) { X _value_a = GetValue(_index[0], _index[1], _index[2], _index[3], _index[4]); - X _value_b = _product.GetValueLossely(GetDimensions(), _index[0], _index[1], _index[2], _index[3], _index[4]); + X _value_b = + _product PTR_DEREF GetValueLossely(GetDimensions(), _index[0], _index[1], _index[2], _index[3], _index[4]); switch (_reduce) { case MATRIX_VECTOR_REDUCE_COSINE_SIMILARITY: @@ -1659,7 +1670,7 @@ class Matrix { break; } - _ptr_result.SetValue(_res, _out_index[0], _out_index[1], _out_index[2], _out_index[3], _out_index[4]); + _ptr_result PTR_DEREF SetValue(_res, _out_index[0], _out_index[1], _out_index[2], _out_index[3], _out_index[4]); if (_dimension == 0) ++_index[1]; @@ -1731,19 +1742,19 @@ class Matrix { switch (_reduction) { case MATRIX_OPERATION_SUM: - result = _diff.Sum(); + result = _diff PTR_DEREF Sum(); break; case MATRIX_OPERATION_MIN: - result = _diff.Min(); + result = _diff PTR_DEREF Min(); break; case MATRIX_OPERATION_MAX: - result = _diff.Max(); + result = _diff PTR_DEREF Max(); break; case MATRIX_OPERATION_AVG: - result = _diff.Avg(); + result = _diff PTR_DEREF Avg(); break; case MATRIX_OPERATION_MED: - result = _diff.Med(); + result = _diff PTR_DEREF Med(); break; default: Print("MeanAbsolute(): Unsupported reduction type: ", EnumToString(_reduction), "!"); @@ -1781,7 +1792,7 @@ class Matrix { */ Matrix* Relu() { Matrix* result = Clone(); - result.Relu_(); + result PTR_DEREF Relu_(); return result; } @@ -1792,7 +1803,7 @@ class Matrix { X _out1 = 0, _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_RELU, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_RELU, 0, 0, 0, _out1, _out2, _out3); } } @@ -1801,7 +1812,7 @@ class Matrix { */ Matrix* Clone() const { Matrix* _cloned = new Matrix(dimensions[0], dimensions[1], dimensions[2], dimensions[3], dimensions[4]); - _cloned.ptr_first_dimension.CopyFrom(ptr_first_dimension); + _cloned PTR_DEREF ptr_first_dimension PTR_DEREF CopyFrom(ptr_first_dimension); return _cloned; } @@ -1813,15 +1824,15 @@ class Matrix { void Set(X value, const int _1d, const int _2d = -1, const int _3d = -1, const int _4d = -1, const int _5d = -1) { if (_2d == -1) { - this[_1d] = value; + THIS_REF[_1d] = value; } else if (_3d == -1) { - this[_1d][_2d] = value; + THIS_REF[_1d][_2d] = value; } else if (_4d == -1) { - this[_1d][_2d][_3d] = value; + THIS_REF[_1d][_2d][_3d] = value; } else if (_5d == -1) { - this[_1d][_2d][_3d][_4d] = value; + THIS_REF[_1d][_2d][_3d][_4d] = value; } else { - this[_1d][_2d][_3d][_4d][_5d] = value; + THIS_REF[_1d][_2d][_3d][_4d][_5d] = value; } } @@ -1831,25 +1842,25 @@ class Matrix { if (dimensions[0] < _in_channels) { Alert("Insufficient number of channels in the input. First dimensions should have ", _in_channels, " arrays, got ", dimensions[0]); - return NULL; + return nullptr; } Matrix* clone = Clone(); - clone.DuplicateDimension(1, _out_channels - 1); + clone PTR_DEREF DuplicateDimension(1, _out_channels - 1); if (_weights != NULL) { - Matrix* weight_flattened = _weights.Flatten(); + Matrix* weight_flattened = _weights PTR_DEREF Flatten(); for (int _in_channel_idx = 0; _in_channel_idx < _in_channels; ++_in_channel_idx) { - clone.ptr_first_dimension.containers[_in_channel_idx].Op(weight_flattened.ptr_first_dimension, - MATRIX_OPERATION_MULTIPLY); + clone PTR_DEREF ptr_first_dimension PTR_DEREF containers[_in_channel_idx].Op( + weight_flattened PTR_DEREF ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); } delete weight_flattened; } - Matrix* pooled = - clone.GetPooled(MATRIX_OPERATION_SUM, MATRIX_PADDING_VALID, 1, 2, _krn_1d, _krn_2d, 0, // Kernel size. - 1, 2, _stride_1d, _stride_2d); + Matrix* pooled = clone PTR_DEREF GetPooled(MATRIX_OPERATION_SUM, MATRIX_PADDING_VALID, 1, 2, _krn_1d, _krn_2d, + 0, // Kernel size. + 1, 2, _stride_1d, _stride_2d); delete clone; return pooled; @@ -1966,7 +1977,7 @@ class Matrix { ChunkOp(_op, _padding, _pool_1d, _pool_2d, _pool_3d, _pool_4d, _pool_5d, _stride_1d, _stride_2d, _stride_3d, _stride_4d, _stride_5d, _chunk_1d, _chunk_2d, _chunk_3d, _chunk_4d, _chunk_5d); - _result.Set(result, _chunk_1d, _chunk_2d, _chunk_3d, _chunk_4d, _chunk_5d); + _result PTR_DEREF Set(result, _chunk_1d, _chunk_2d, _chunk_3d, _chunk_4d, _chunk_5d); } } } @@ -2016,7 +2027,7 @@ class Matrix { _accessor_d1 = this[d1]; if (_accessor_d1.Type() == MATRIX_DIMENSION_TYPE_VALUES) { - _MATRIX_AGGR(ptr_first_dimension.values[d1]); + _MATRIX_AGGR(ptr_first_dimension PTR_DEREF values[d1]); continue; } @@ -2113,16 +2124,16 @@ class Matrix { /** * Checks whether both matrices have the same dimensions' length. */ - static bool ShapeCompatible(Matrix* _a, Matrix* _b) { return _a.Repr() == _b.Repr(); } + static bool ShapeCompatible(Matrix* _a, Matrix* _b) { return _a PTR_DEREF Repr() == _b PTR_DEREF Repr(); } /** * Checks whether right matrix have less or equal dimensions' length.. */ static bool ShapeCompatibleLossely(Matrix* _a, Matrix* _b) { - if (_b.GetDimensions() > _a.GetDimensions()) return false; + if (_b PTR_DEREF GetDimensions() > _a PTR_DEREF GetDimensions()) return false; - for (int i = 0; i < _b.GetDimensions(); ++i) { - if (_b.dimensions[i] != 1 && _b.dimensions[i] > _a.dimensions[i]) return false; + for (int i = 0; i < _b PTR_DEREF GetDimensions(); ++i) { + if (_b PTR_DEREF dimensions[i] != 1 && _b PTR_DEREF dimensions[i] > _a PTR_DEREF dimensions[i]) return false; } return true; @@ -2131,20 +2142,17 @@ class Matrix { static Matrix* CreateFromString(string text) { Matrix* _ptr_matrix = new Matrix(); - _ptr_matrix.FromString(text); + _ptr_matrix PTR_DEREF FromString(text); return _ptr_matrix; } void FromString(string text) { - MatrixDimension*_dimensions[], *_root_dimension = NULL; - int _dimensions_length[MATRIX_DIMENSIONS] = {0, 0, 0, 0, 0}; + ARRAY(MatrixDimension*, _dimensions); + MatrixDimension* _root_dimension = nullptr; int i, _number_start_pos; - bool _had_values; X _number; bool _expecting_value_or_child = true; - bool _expecting_comma = false; - bool _expecting_end = false; for (i = 0; i < StringLen(text); ++i) { unsigned short _char = StringGetCharacter(text, i), c; @@ -2156,8 +2164,6 @@ class Matrix { return; } - _had_values = false; - if (ArraySize(_dimensions) != 0) { _dimensions[ArraySize(_dimensions) - 1].type = MATRIX_DIMENSION_TYPE_CONTAINERS; } @@ -2174,13 +2180,11 @@ class Matrix { } _expecting_value_or_child = true; - _expecting_end = true; break; case ']': ArrayResize(_dimensions, ArraySize(_dimensions) - 1, MATRIX_DIMENSIONS); _expecting_value_or_child = true; - _expecting_comma = false; break; case '0': @@ -2209,15 +2213,11 @@ class Matrix { i -= 2; _dimensions[ArraySize(_dimensions) - 1].type = MATRIX_DIMENSION_TYPE_VALUES; _dimensions[ArraySize(_dimensions) - 1].AddValue(_number); - _expecting_end = true; _expecting_value_or_child = true; - _expecting_comma = false; break; case ',': _expecting_value_or_child = true; - _expecting_comma = false; - _expecting_end = false; break; case ' ': case '\t': @@ -2241,7 +2241,7 @@ class Matrix { * */ string ToString(bool _whitespaces = false, int _precision = 3) { - return ptr_first_dimension.ToString(_whitespaces, _precision); + return ptr_first_dimension PTR_DEREF ToString(_whitespaces, _precision); } /** diff --git a/Order.mqh b/Order.mqh index 7808c34ca..7ecefc664 100644 --- a/Order.mqh +++ b/Order.mqh @@ -695,6 +695,8 @@ class Order : public SymbolInfo { return OrderStopLoss(); case ORDER_TP: return OrderTakeProfit(); + default: + break; } return 0; } @@ -1158,17 +1160,17 @@ class Order : public SymbolInfo { * Returns number of the ticket assigned to the order by the trade server * or -1 if it fails. */ - static long OrderSend(string _symbol, // Symbol. - int _cmd, // Operation. - double _volume, // Volume. - double _price, // Price. - unsigned long _deviation, // Deviation. - double _stoploss, // Stop loss. - double _takeprofit, // Take profit. - string _comment = NULL, // Comment. - unsigned long _magic = 0, // Magic number. - datetime _expiration = 0, // Pending order expiration. - color _arrow_color = clrNONE // Color. + static long OrderSend(string _symbol, // Symbol. + int _cmd, // Operation. + double _volume, // Volume. + double _price, // Price. + unsigned long _deviation, // Deviation. + double _stoploss, // Stop loss. + double _takeprofit, // Take profit. + string _comment = NULL_STRING, // Comment. + unsigned long _magic = 0, // Magic number. + datetime _expiration = 0, // Pending order expiration. + color _arrow_color = clrNONE // Color. ) { #ifdef __MQL4__ #ifdef __debug__ @@ -1300,7 +1302,7 @@ class Order : public SymbolInfo { // - https://www.mql5.com/en/docs/constants/errorswarnings/enum_trade_return_codes // - https://www.mql5.com/en/docs/constants/structures/mqltradecheckresult #ifdef __debug__ - PrintFormat("%s: Error %d: %s", __FUNCTION_LINE__, _result_check.retcode, _result_check.comment); + PrintFormat("%s: Error %d: %s", C_STR(__FUNCTION_LINE__), _result_check.retcode, C_STR(_result_check.comment)); #endif _result.retcode = _result_check.retcode; return false; @@ -1564,7 +1566,7 @@ class Order : public SymbolInfo { } else { #ifdef __debug__ PrintFormat("%s: Possible values for 'select' parameters are: SELECT_BY_POS or SELECT_BY_HISTORY.", - __FUNCTION_LINE__); + C_STR(__FUNCTION_LINE__)); #endif } _result = selected_ticket_type != ORDER_SELECT_TYPE_NONE; @@ -1742,8 +1744,6 @@ class Order : public SymbolInfo { * Update specific double value of the current order. */ bool RefreshDummy(ENUM_ORDER_PROPERTY_DOUBLE _prop_id) { - bool _result = false; - double _value = WRONG_VALUE; ResetLastError(); switch (_prop_id) { case ORDER_PRICE_CURRENT: @@ -1781,6 +1781,8 @@ class Order : public SymbolInfo { OrderCloseDummy(); } break; + default: + break; } break; case ORDER_PRICE_OPEN: @@ -1795,6 +1797,8 @@ class Order : public SymbolInfo { case ORDER_TP: odata.Set(_prop_id, orequest.tp); break; + default: + break; } return true; @@ -1805,12 +1809,13 @@ class Order : public SymbolInfo { */ bool RefreshDummy(ENUM_ORDER_PROPERTY_INTEGER _prop_id) { bool _result = false; - long _value = WRONG_VALUE; ResetLastError(); switch (_prop_id) { case ORDER_MAGIC: odata.Set(_prop_id, orequest.magic); break; + default: + break; } return _result && GetLastError() == ERR_NO_ERROR; @@ -1827,6 +1832,8 @@ class Order : public SymbolInfo { case ORDER_SYMBOL: odata.Set(_prop_id, orequest.symbol); break; + default: + break; } return true; @@ -1870,7 +1877,7 @@ class Order : public SymbolInfo { } else { int _last_error = GetLastError(); ologger.Error("Error refreshing order property!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); } return _result && GetLastError() == ERR_NO_ERROR; } @@ -1896,9 +1903,6 @@ class Order : public SymbolInfo { _result = Order::OrderGetInteger(ORDER_POSITION_BY_ID, _value); break; #endif - case (ENUM_ORDER_PROPERTY_INTEGER)ORDER_REASON: - _result = Order::OrderGetInteger((ENUM_ORDER_PROPERTY_INTEGER)ORDER_REASON, _value); - break; case ORDER_STATE: _result = Order::OrderGetInteger(ORDER_STATE, _value); break; @@ -1927,6 +1931,10 @@ class Order : public SymbolInfo { _result = Order::OrderGetInteger(ORDER_TYPE_TIME, _value); break; default: + if ((int)_prop_id == (int)ORDER_REASON) { + _result = Order::OrderGetInteger((ENUM_ORDER_PROPERTY_INTEGER)ORDER_REASON, _value); + break; + } return false; } if (_result) { @@ -1934,7 +1942,7 @@ class Order : public SymbolInfo { } else { int _last_error = GetLastError(); ologger.Error("Error updating order property!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); } return _result && GetLastError() == ERR_NO_ERROR; } @@ -1949,15 +1957,16 @@ class Order : public SymbolInfo { case ORDER_COMMENT: _value = Order::OrderGetString(ORDER_COMMENT); break; -#ifdef ORDER_EXTERNAL_ID - case (ENUM_ORDER_PROPERTY_STRING)ORDER_EXTERNAL_ID: - _value = Order::OrderGetString(ORDER_EXTERNAL_ID); - break; -#endif case ORDER_SYMBOL: _value = Order::OrderGetString(ORDER_SYMBOL); break; default: +#ifdef ORDER_EXTERNAL_ID + if ((int)_prop_id == (int)ORDER_EXTERNAL_ID) { + _value = Order::OrderGetString(ORDER_EXTERNAL_ID); + break; + } +#endif _result = false; break; } @@ -1966,7 +1975,7 @@ class Order : public SymbolInfo { } else { int _last_error = GetLastError(); ologger.Error("Error updating order property!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); } return true; } @@ -2019,6 +2028,8 @@ class Order : public SymbolInfo { return ORDER_TYPE_SELL; case ORDER_TYPE_SELL: return ORDER_TYPE_BUY; + default: + break; } return WRONG_VALUE; } @@ -2450,9 +2461,11 @@ class Order : public SymbolInfo { template static X OrderGetParam(int _prop_id, ENUM_ORDER_SELECT_TYPE _type, ENUM_ORDER_SELECT_DATA_TYPE _data_type, X &_out) { #ifndef __MQL4__ + long _long; + string _string; switch (selected_ticket_type) { case ORDER_SELECT_TYPE_NONE: - return NULL; + return NULL_VALUE; case ORDER_SELECT_TYPE_ACTIVE: case ORDER_SELECT_TYPE_HISTORY: @@ -2465,13 +2478,13 @@ class Order : public SymbolInfo { case ORDER_TIME_SETUP: return OrderGetValue(DEAL_TIME, _type, _out); case ORDER_TYPE: - switch ((int)OrderGetValue(DEAL_TYPE, _type, _out)) { + switch (OrderGetValue(DEAL_TYPE, _type, _long)) { case DEAL_TYPE_BUY: - return (X)ORDER_TYPE_BUY; + return ConvertBasic::LongTo(ORDER_TYPE_BUY); case DEAL_TYPE_SELL: - return (X)ORDER_TYPE_SELL; + return ConvertBasic::LongTo(ORDER_TYPE_SELL); default: - return NULL; + return NULL_VALUE; } break; case ORDER_STATE: @@ -2480,43 +2493,44 @@ class Order : public SymbolInfo { case ORDER_TIME_EXPIRATION: case ORDER_TIME_DONE: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TIME_SETUP_MSC: return OrderGetValue(DEAL_TIME_MSC, _type, _out); case ORDER_TIME_DONE_MSC: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TYPE_FILLING: case ORDER_TYPE_TIME: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_MAGIC: return OrderGetValue(DEAL_MAGIC, _type, _out); - case ORDER_REASON: - switch ((int)OrderGetValue(DEAL_REASON, _type, _out)) { - case DEAL_REASON_CLIENT: - return (X)ORDER_REASON_CLIENT; - case DEAL_REASON_MOBILE: - return (X)ORDER_REASON_MOBILE; - case DEAL_REASON_WEB: - return (X)ORDER_REASON_WEB; - case DEAL_REASON_EXPERT: - return (X)ORDER_REASON_EXPERT; - case DEAL_REASON_SL: - return (X)ORDER_REASON_SL; - case DEAL_REASON_TP: - return (X)ORDER_REASON_TP; - case DEAL_REASON_SO: - return (X)ORDER_REASON_SO; - default: - return NULL; - } - break; case ORDER_POSITION_ID: return OrderGetValue(DEAL_POSITION_ID, _type, _out); case ORDER_POSITION_BY_ID: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; + default: + if ((int)_prop_id == (int)ORDER_REASON) { + switch (OrderGetValue(DEAL_REASON, _type, _long)) { + case DEAL_REASON_CLIENT: + return ConvertBasic::LongTo(ORDER_REASON_CLIENT); + case DEAL_REASON_MOBILE: + return ConvertBasic::LongTo(ORDER_REASON_MOBILE); + case DEAL_REASON_WEB: + return ConvertBasic::LongTo(ORDER_REASON_WEB); + case DEAL_REASON_EXPERT: + return ConvertBasic::LongTo(ORDER_REASON_EXPERT); + case DEAL_REASON_SL: + return ConvertBasic::LongTo(ORDER_REASON_SL); + case DEAL_REASON_TP: + return ConvertBasic::LongTo(ORDER_REASON_TP); + case DEAL_REASON_SO: + return ConvertBasic::LongTo(ORDER_REASON_SO); + default: + return NULL_VALUE; + } + } } break; case ORDER_SELECT_DATA_TYPE_DOUBLE: @@ -2525,26 +2539,31 @@ class Order : public SymbolInfo { return OrderGetValue(DEAL_VOLUME, _type, _out); case ORDER_VOLUME_CURRENT: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_PRICE_OPEN: return OrderGetValue(DEAL_PRICE, _type, _out); case ORDER_SL: case ORDER_TP: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_PRICE_CURRENT: return OrderGetValue(DEAL_PRICE, _type, _out); case ORDER_PRICE_STOPLIMIT: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; } break; case ORDER_SELECT_DATA_TYPE_STRING: switch (_prop_id) { case ORDER_SYMBOL: case ORDER_COMMENT: - case ORDER_EXTERNAL_ID: - return NULL; + return NULL_VALUE; + default: +#ifdef ORDER_EXTERNAL_ID + if ((int)_prop_id == (int)ORDER_EXTERNAL_ID) { + return NULL_VALUE; + } +#endif } break; } @@ -2557,13 +2576,13 @@ class Order : public SymbolInfo { case ORDER_TIME_SETUP: return OrderGetValue(POSITION_TIME, _type, _out); case ORDER_TYPE: - switch ((int)OrderGetValue(POSITION_TYPE, _type, _out)) { + switch (OrderGetValue(POSITION_TYPE, _type, _long)) { case POSITION_TYPE_BUY: - return (X)ORDER_TYPE_BUY; + return ConvertBasic::LongTo(ORDER_TYPE_BUY); case POSITION_TYPE_SELL: - return (X)ORDER_TYPE_SELL; + return ConvertBasic::LongTo(ORDER_TYPE_SELL); default: - return NULL; + return NULL_VALUE; } break; case ORDER_STATE: @@ -2572,37 +2591,38 @@ class Order : public SymbolInfo { case ORDER_TIME_EXPIRATION: case ORDER_TIME_DONE: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TIME_SETUP_MSC: return OrderGetValue(POSITION_TIME_MSC, _type, _out); case ORDER_TIME_DONE_MSC: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TYPE_FILLING: case ORDER_TYPE_TIME: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_MAGIC: return OrderGetValue(POSITION_MAGIC, _type, _out); - case ORDER_REASON: - switch ((int)OrderGetValue(POSITION_REASON, _type, _out)) { - case POSITION_REASON_CLIENT: - return (X)ORDER_REASON_CLIENT; - case POSITION_REASON_MOBILE: - return (X)ORDER_REASON_MOBILE; - case POSITION_REASON_WEB: - return (X)ORDER_REASON_WEB; - case POSITION_REASON_EXPERT: - return (X)ORDER_REASON_EXPERT; - default: - return NULL; - } - break; case ORDER_POSITION_ID: return OrderGetValue(POSITION_IDENTIFIER, _type, _out); case ORDER_POSITION_BY_ID: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; + default: + if ((int)_prop_id == (int)ORDER_REASON) { + switch (OrderGetValue(POSITION_REASON, _type, _long)) { + case POSITION_REASON_CLIENT: + return ConvertBasic::LongTo(ORDER_REASON_CLIENT); + case POSITION_REASON_MOBILE: + return ConvertBasic::LongTo(ORDER_REASON_MOBILE); + case POSITION_REASON_WEB: + return ConvertBasic::LongTo(ORDER_REASON_WEB); + case POSITION_REASON_EXPERT: + return ConvertBasic::LongTo(ORDER_REASON_EXPERT); + default: + return NULL_VALUE; + } + } } break; case ORDER_SELECT_DATA_TYPE_DOUBLE: @@ -2612,7 +2632,7 @@ class Order : public SymbolInfo { case ORDER_VOLUME_CURRENT: // @fixme SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_PRICE_OPEN: return OrderGetValue(POSITION_PRICE_OPEN, _type, _out); case ORDER_SL: @@ -2624,7 +2644,7 @@ class Order : public SymbolInfo { case ORDER_PRICE_STOPLIMIT: // @fixme SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; } break; case ORDER_SELECT_DATA_TYPE_STRING: @@ -2633,15 +2653,19 @@ class Order : public SymbolInfo { return OrderGetValue(POSITION_SYMBOL, _type, _out); case ORDER_COMMENT: return OrderGetValue(POSITION_COMMENT, _type, _out); - case ORDER_EXTERNAL_ID: - return OrderGetValue(POSITION_EXTERNAL_ID, _type, _out); + default: +#ifdef ORDER_EXTERNAL_ID + if ((int)_prop_id == (int)ORDER_EXTERNAL_ID) { + return OrderGetValue(POSITION_EXTERNAL_ID, _type, _out); + } +#endif } break; } break; } - return NULL; + return NULL_VALUE; #else return OrderGetValue(_prop_id, _type, _out); #endif @@ -2680,7 +2704,7 @@ class Order : public SymbolInfo { * Returns true when the condition is met. */ bool CheckCondition(ENUM_ORDER_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { - float _profit = (float)Get(ORDER_PROP_PROFIT_PIPS); + // float _profit = (float)Get(ORDER_PROP_PROFIT_PIPS); switch (_cond) { case ORDER_COND_IN_LOSS: return Get(ORDER_PROP_PROFIT_PIPS) < (ArraySize(_args) > 0 ? -DataParamEntry::ToDouble(_args[0]) : 0); @@ -2699,6 +2723,8 @@ class Order : public SymbolInfo { return TimeCurrent() - odata.Get(ORDER_TIME_SETUP) > _arg_value; case ORDER_COND_LIFETIME_LT_ARG: return TimeCurrent() - odata.Get(ORDER_TIME_SETUP) < _arg_value; + default: + return false; } } case ORDER_COND_PROP_EQ_ARG: @@ -2719,6 +2745,8 @@ class Order : public SymbolInfo { return odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_prop_id) > _args[1].double_value; case ORDER_COND_PROP_LT_ARG: return odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_prop_id) < _args[1].double_value; + default: + return false; } case TYPE_INT: case TYPE_LONG: @@ -2732,6 +2760,8 @@ class Order : public SymbolInfo { return odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_prop_id) > _args[1].integer_value; case ORDER_COND_PROP_LT_ARG: return odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_prop_id) < _args[1].integer_value; + default: + return false; } case TYPE_STRING: Refresh((ENUM_ORDER_PROPERTY_STRING)_prop_id); @@ -2743,12 +2773,17 @@ class Order : public SymbolInfo { return odata.Get((ENUM_ORDER_PROPERTY_STRING)_prop_id) > _args[1].string_value; case ORDER_COND_PROP_LT_ARG: return odata.Get((ENUM_ORDER_PROPERTY_STRING)_prop_id) < _args[1].string_value; + default: + return false; } + default: + return false; } } } default: - ologger.Error(StringFormat("Invalid order condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + ologger.Error( + StringFormat("Invalid order condition: %s at %s!", C_STR(EnumToString(_cond)), C_STR(__FUNCTION_LINE__))); } SetUserError(ERR_INVALID_PARAMETER); return false; @@ -2771,12 +2806,12 @@ class Order : public SymbolInfo { bool ExecuteAction(ENUM_ORDER_ACTION _action, ARRAY_REF(DataParamEntry, _args)) { switch (_action) { case ORDER_ACTION_CLOSE: - switch (oparams.dummy) { - case false: - return OrderClose(ORDER_REASON_CLOSED_BY_ACTION); - case true: - return OrderCloseDummy(ORDER_REASON_CLOSED_BY_ACTION); + if (oparams.dummy) { + return OrderCloseDummy(ORDER_REASON_CLOSED_BY_ACTION); + } else { + return OrderClose(ORDER_REASON_CLOSED_BY_ACTION); } + break; case ORDER_ACTION_OPEN: return !oparams.dummy ? OrderSend() >= 0 : OrderSendDummy() >= 0; case ORDER_ACTION_COND_CLOSE_ADD: @@ -2792,7 +2827,8 @@ class Order : public SymbolInfo { oparams.AddConditionClose((ENUM_ORDER_CONDITION)_args[0].integer_value, _sargs); } default: - ologger.Error(StringFormat("Invalid order action: %s!", EnumToString(_action), __FUNCTION_LINE__)); + ologger.Error( + StringFormat("Invalid order action: %s at %s!", C_STR(EnumToString(_action)), C_STR(__FUNCTION_LINE__))); return false; } } @@ -2821,21 +2857,21 @@ class Order : public SymbolInfo { switch (_type) { case TYPE_DOUBLE: for (i = 0; i < Array::ArraySize(_props); i++) { - _output += StringFormat("%g%s", odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_props[i]), _dlm); + _output += StringFormat("%g%s", odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_props[i]), C_STR(_dlm)); } break; case TYPE_LONG: for (i = 0; i < Array::ArraySize(_props); i++) { - _output += StringFormat("%d%s", odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_props[i]), _dlm); + _output += StringFormat("%d%s", odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_props[i]), C_STR(_dlm)); } break; case TYPE_STRING: for (i = 0; i < Array::ArraySize(_props); i++) { - _output += StringFormat("%d%s", odata.Get((ENUM_ORDER_PROPERTY_STRING)_props[i]), _dlm); + _output += StringFormat("%s%s", C_STR(odata.Get((ENUM_ORDER_PROPERTY_STRING)_props[i])), C_STR(_dlm)); } break; default: - ologger.Error(StringFormat("%s: Unsupported type: %s!", __FUNCTION_LINE__, EnumToString(_type))); + ologger.Error(StringFormat("%s: Unsupported type: %s!", C_STR(__FUNCTION_LINE__), C_STR(EnumToString(_type)))); } return ""; } diff --git a/Order.struct.h b/Order.struct.h index 897f28394..cab1a5739 100644 --- a/Order.struct.h +++ b/Order.struct.h @@ -154,7 +154,7 @@ struct OrderParams { T Get(ENUM_ORDER_PARAM _param, int _index1 = 0, int _index2 = 0) { switch (_param) { case ORDER_PARAM_COLOR_ARROW: - return (T)color_arrow; + return (T)(unsigned int)color_arrow; case ORDER_PARAM_COND_CLOSE: return (T)cond_close[_index1].cond; case ORDER_PARAM_COND_CLOSE_ARG_VALUE: @@ -167,6 +167,9 @@ struct OrderParams { return (T)refresh_freq; case ORDER_PARAM_UPDATE_FREQ: return (T)update_freq; + default: + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; } SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; @@ -182,7 +185,7 @@ struct OrderParams { void Set(ENUM_ORDER_PARAM _param, T _value, int _index1 = 0, int _index2 = 0) { switch (_param) { case ORDER_PARAM_COLOR_ARROW: - color_arrow = (color)_value; + color_arrow = (color)(unsigned int)_value; return; case ORDER_PARAM_COND_CLOSE: SetConditionClose((ENUM_ORDER_CONDITION)_value, _index1); @@ -199,6 +202,8 @@ struct OrderParams { case ORDER_PARAM_UPDATE_FREQ: update_freq = (unsigned short)_value; return; + default: + SetUserError(ERR_INVALID_PARAMETER); } SetUserError(ERR_INVALID_PARAMETER); } @@ -232,12 +237,7 @@ struct OrderData { unsigned long position_by_id; // Position By ID. unsigned long ticket; // Ticket number. ENUM_ORDER_STATE state; // State. - datetime time_closed; // Closed time. - datetime time_done; // Execution/cancellation time. - datetime time_expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type). - datetime time_setup; // Setup time. - datetime time_last_refresh; // Last refresh of order values. - datetime time_last_update; // Last update of order stops. + string comment; // Comment. double commission; // Commission. double profit; // Profit. double total_profit; // Total profit (profit minus fees). @@ -246,22 +246,27 @@ struct OrderData { double price_current; // Current price. double price_stoplimit; // The limit order price for the StopLimit order. double swap; // Order cumulative swap. + datetime time_closed; // Closed time. + datetime time_done; // Execution/cancellation time. + long time_done_msc; // The time of execution/cancellation time (in msc). + datetime time_expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type). + datetime time_last_refresh; // Last refresh of order values. + datetime time_last_update; // Last update of order stops. + datetime time_setup; // Setup time. + long time_setup_msc; // The time of placing the order (in msc). double total_fees; // Total fees. double sl; // Current Stop loss level of the order. double tp; // Current Take Profit level of the order. - long time_setup_msc; // The time of placing the order (in msc). - long time_done_msc; // The time of execution/cancellation time (in msc). ENUM_ORDER_TYPE type; // Type. ENUM_ORDER_TYPE_FILLING type_filling; // Filling type. ENUM_ORDER_TYPE_TIME type_time; // Lifetime (the order validity period). ENUM_ORDER_REASON reason; // Reason or source for placing an order. ENUM_ORDER_REASON_CLOSE reason_close; // Reason or source for closing an order. unsigned int last_error; // Last error code. - double volume_curr; // Current volume. - double volume_init; // Initial volume. - string comment; // Comment. string ext_id; // External trading system identifier. string symbol; // Symbol of the order. + double volume_curr; // Current volume. + double volume_init; // Initial volume. public: OrderData() : magic(0), @@ -296,7 +301,6 @@ struct OrderData { // Getters. template T Get(ENUM_ORDER_PROPERTY_CUSTOM _prop_name) { - double _tick_value = SymbolInfoStatic::GetTickValue(symbol); switch (_prop_name) { case ORDER_PROP_COMMISSION: return (T)commission; @@ -330,6 +334,9 @@ struct OrderData { return (T)time_done; case ORDER_PROP_TOTAL_FEES: return (T)total_fees; + default: + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; } SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; @@ -366,13 +373,13 @@ struct OrderData { case ORDER_STATE: return (T)state; case ORDER_TIME_EXPIRATION: - return (T)time_expiration; + return (T)(long)time_expiration; case ORDER_TIME_DONE: - return (T)time_done; + return (T)(long)time_done; case ORDER_TIME_DONE_MSC: return (T)time_done_msc; case ORDER_TIME_SETUP: - return (T)time_setup; + return (T)(long)time_setup; case ORDER_TIME_SETUP_MSC: return (T)time_setup_msc; case ORDER_TYPE_FILLING: @@ -500,7 +507,7 @@ struct OrderData { profit = (double)_value; return; case ORDER_PROP_REASON_CLOSE: - reason_close = (ENUM_ORDER_REASON_CLOSE)_value; + reason_close = (ENUM_ORDER_REASON_CLOSE)(long)_value; return; case ORDER_PROP_TICKET: ticket = (unsigned long)_value; @@ -520,6 +527,8 @@ struct OrderData { case ORDER_PROP_TOTAL_FEES: total_fees = (double)_value; return; + default: + SetUserError(ERR_INVALID_PARAMETER); } SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Orders.mqh b/Orders.mqh index e5ca4df9f..aa0add09b 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -204,6 +204,9 @@ class Orders { // PrintFormat("%s:%d%d: OP_SELL: TP=%g, SL=%g, total: %g/%g", __FUNCTION__, i, OrdersTotal(), order_tp, // order_sl, total_sell_sl, total_sell_tp); break; + default: + RUNTIME_ERROR("Not supported order type!"); + return 0; } } } @@ -273,6 +276,9 @@ class Orders { case ORDER_TYPE_SELL: sell_lots += Order::OrderLots(); break; + default: + RUNTIME_ERROR("Not supported order type!"); + return 0; } } } diff --git a/Platform.extern.h b/Platform.extern.h index 41742d45e..943ec3bcd 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -29,9 +29,9 @@ #include "Order.define.h" // Forward declarations. -class MqlTradeRequest; -class MqlTradeResult; -class MqlTradeCheckResult; +struct MqlTradeRequest; +struct MqlTradeResult; +struct MqlTradeCheckResult; template double iCustom(string symbol, int timeframe, string name, Args... args) { @@ -129,10 +129,12 @@ extern int ChartID(); extern bool OrderCalcMargin(ENUM_ORDER_TYPE _action, string _symbol, double _volume, double _price, double& _margin); -double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id); +extern double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id); -long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); +extern long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); -string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); +extern string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); + +extern string Symbol(); #endif diff --git a/Platform.h b/Platform.h index 8b2f666f9..7a520a5b5 100644 --- a/Platform.h +++ b/Platform.h @@ -573,6 +573,11 @@ string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id) { return false; } +string Symbol() { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return false; +} + #endif /** diff --git a/Refs.struct.h b/Refs.struct.h index da94bf8a1..9827f7b1a 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -115,26 +115,17 @@ struct Ref { /** * Constructor. */ - Ref(X* _ptr) { - ptr_object = nullptr; - THIS_REF = _ptr; - } + Ref(X* _ptr) : ptr_object(nullptr) { THIS_REF = _ptr; } /** * Constructor. */ - Ref(const Ref& ref) { - ptr_object = nullptr; - Set(ref.Ptr()); - } + Ref(const Ref& ref) : ptr_object(nullptr) { Set(ref.Ptr()); } /** * Constructor. */ - Ref(WeakRef& ref) { - ptr_object = nullptr; - Set(ref.Ptr()); - } + Ref(WeakRef& ref) : ptr_object(nullptr) { Set(ref.Ptr()); } /** * Constructor. @@ -312,31 +303,26 @@ struct WeakRef { /** * Constructor. */ - WeakRef(X* _ptr = NULL) { this = _ptr; } - - /** - * Constructor. - */ - WeakRef(const WeakRef& ref) { THIS_REF = ref.Ptr(); } + WeakRef(X* _ptr = NULL) : ptr_ref_counter(nullptr) { THIS_REF = _ptr; } /** * Constructor. */ - WeakRef(WeakRef& ref) { THIS_REF = ref.Ptr(); } + WeakRef(const WeakRef& ref) : ptr_ref_counter(nullptr) { THIS_REF = ref.Ptr(); } /** * Constructor. */ - WeakRef(Ref& ref) { THIS_REF = ref.Ptr(); } + WeakRef(Ref& ref) : ptr_ref_counter(nullptr) { THIS_REF = ref.Ptr(); } /** * Destructor. */ ~WeakRef() { Unset(); } - bool ObjectExists() { return ptr_ref_counter != NULL && !PTR_ATTRIB(ptr_ref_counter, deleted); } + bool ObjectExists() const { return ptr_ref_counter != NULL && !PTR_ATTRIB(ptr_ref_counter, deleted); } - X* Ptr() { return ObjectExists() ? (X*)(PTR_ATTRIB(ptr_ref_counter, ptr_object)) : NULL; } + X* Ptr() const { return ObjectExists() ? (X*)(PTR_ATTRIB(ptr_ref_counter, ptr_object)) : NULL; } /** * Makes a weak reference to the given object. @@ -374,7 +360,7 @@ struct WeakRef { * Makes a weak reference to the given weakly-referenced object. */ X* operator=(WeakRef& right) { - this = right.Ptr(); + THIS_REF = right.Ptr(); return Ptr(); } @@ -382,7 +368,7 @@ struct WeakRef { * Makes a weak reference to the strongly-referenced object. */ X* operator=(Ref& right) { - this = right.Ptr(); + THIS_REF = right.Ptr(); return Ptr(); } diff --git a/Serializer/SerializerCsv.h b/Serializer/SerializerCsv.h index aea45d535..47d6f2c03 100644 --- a/Serializer/SerializerCsv.h +++ b/Serializer/SerializerCsv.h @@ -274,8 +274,9 @@ class SerializerCsv { } else { // A property. - bool _include_titles = bool(_flags & SERIALIZER_CSV_INCLUDE_TITLES); - bool _include_titles_tree = (_flags & SERIALIZER_CSV_INCLUDE_TITLES_TREE) == SERIALIZER_CSV_INCLUDE_TITLES_TREE; + // bool _include_titles = bool(_flags & SERIALIZER_CSV_INCLUDE_TITLES); + // bool _include_titles_tree = (_flags & SERIALIZER_CSV_INCLUDE_TITLES_TREE) == + // SERIALIZER_CSV_INCLUDE_TITLES_TREE; if (_column_types != NULL) { if (_data PTR_DEREF GetValueParam() == NULL) { diff --git a/Std.h b/Std.h index aaa06888f..d214d3bf2 100644 --- a/Std.h +++ b/Std.h @@ -174,6 +174,8 @@ class _cpp_array { std::vector& str() { return m_data; } + void push(const T& value) { m_data.push_back(value); } + void operator=(const _cpp_array& r) { m_data = r.m_data; m_isSeries = r.m_isSeries; @@ -354,3 +356,7 @@ _NULL_VALUE::operator string() const { extern ENUM_TIMEFRAMES Period(); #endif + +#define RUNTIME_ERROR(MSG) \ + Print(MSG); \ + DebugBreak(); diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index d1edaed1e..178dca0a8 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -196,7 +196,7 @@ class ItemsHistory { _from_time_ms = _item.GetTimeMs() + _item.GetLengthMs() + 1; } - long _current_time_ms = TimeCurrent() * 1000; + // long _current_time_ms = TimeCurrent() * 1000; if (_from_time_ms > (long)TimeCurrent() * 1000) { // There won't be items in the future. diff --git a/Storage/ValueStorage.accessor.h b/Storage/ValueStorage.accessor.h index 8d0a95112..d4fc60aee 100644 --- a/Storage/ValueStorage.accessor.h +++ b/Storage/ValueStorage.accessor.h @@ -70,12 +70,12 @@ class ValueStorageAccessor { /** * Fetches value from the storage. */ - const C Get() const { return storage.Fetch(index); } + const C Get() const { return storage PTR_DEREF Fetch(index); } /** * Stores value in the storage. */ - void Set(C value) { storage.Store(index, value); } + void Set(C value) { storage PTR_DEREF Store(index, value); } #define VALUE_STORAGE_ACCESSOR_OP(TYPE, OP) \ TYPE operator OP(const ValueStorageAccessor& _accessor) const { return Get() OP _accessor.Get(); } \ diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index 8e7fa6e66..b550627b0 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -228,8 +228,6 @@ int ArrayCopy(ARRAY_REF(D, _target), ValueStorage &_source, int _dst_start = } } - int _pre_fill = _dst_start; - count = MathMin(count, ArraySize(_source) - _src_start); int _dst_required_size = _dst_start + count; diff --git a/String.extern.h b/String.extern.h index 26a4a9b74..4064372b9 100644 --- a/String.extern.h +++ b/String.extern.h @@ -33,6 +33,7 @@ #include #include +#include "Math.extern.h" #include "Std.h" #include "Terminal.define.h" @@ -102,7 +103,14 @@ unsigned short StringGetCharacter(string string_value, int pos) { } int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, - unsigned int codepage = CP_ACP); + unsigned int codepage = CP_ACP) { + if (count == -1) count = text_string.size(); + + for (int i = start; i < MathMin(start + count, (int)text_string.size()); ++i) + array.push((unsigned char)text_string[i]); + + return array.size(); +} bool StringInit(string& string_var, int new_len = 0, unsigned short character = 0) { string_var = string(new_len, (char)character); @@ -116,7 +124,7 @@ bool StringInit(string& string_var, int new_len = 0, unsigned short character = * - https://www.mql5.com/en/docs/strings/stringreplace */ int StringReplace(string& str, const string& find, const string& replacement) { - int num_replacements; + int num_replacements = 0; for (size_t pos = 0;; pos += replacement.length()) { // Locate the substring to replace pos = str.find(find, pos); diff --git a/SymbolInfo.mqh b/SymbolInfo.mqh index 259d6caef..534646a66 100644 --- a/SymbolInfo.mqh +++ b/SymbolInfo.mqh @@ -518,10 +518,11 @@ class SymbolInfo : public Object { "Tick size: %g (%g pts), Tick value: %g (%g/%g), " + "Digits: %d, Spread: %d pts, Trade stops level: %d, " + "Trade contract size: %g, Min lot: %g, Max lot: %g, Lot step: %g, " + "Freeze level: %d, Swap (long/short/mode): %g/%g/%d, Margin initial (maintenance): %g (%g)", - GetSymbol(), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), GetPointSize(), GetPipSize(), - GetTickSize(), GetTradeTickSize(), GetTickValue(), GetTickValueProfit(), GetTickValueLoss(), GetDigits(), - GetSpread(), GetTradeStopsLevel(), GetTradeContractSize(), GetVolumeMin(), GetVolumeMax(), GetVolumeStep(), - GetFreezeLevel(), GetSwapLong(), GetSwapShort(), GetSwapMode(), GetMarginInit(), GetMarginMaintenance()); + C_STR(GetSymbol()), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), GetPointSize(), + GetPipSize(), GetTickSize(), GetTradeTickSize(), GetTickValue(), GetTickValueProfit(), GetTickValueLoss(), + GetDigits(), GetSpread(), GetTradeStopsLevel(), GetTradeContractSize(), GetVolumeMin(), GetVolumeMax(), + GetVolumeStep(), GetFreezeLevel(), GetSwapLong(), GetSwapShort(), GetSwapMode(), GetMarginInit(), + GetMarginMaintenance()); } /** @@ -531,7 +532,7 @@ class SymbolInfo : public Object { return !_header ? StringFormat(string("%s,%g,%g,%d,%g,%g,%g,") + "%g,%g,%g,%g,%g," + "%d,%d,%d," + "%g,%g,%g,%g," + "%d,%g,%g,%d,%g,%g", - GetSymbol(), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), + C_STR(GetSymbol()), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), GetPointSize(), GetPipSize(), GetTickSize(), GetTradeTickSize(), GetTickValue(), GetTickValueProfit(), GetTickValueLoss(), GetDigits(), GetSpread(), GetTradeStopsLevel(), GetTradeContractSize(), GetVolumeMin(), GetVolumeMax(), GetVolumeStep(), GetFreezeLevel(), diff --git a/Task/TaskManager.h b/Task/TaskManager.h index 7f017217a..d9a7fc0e7 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -131,6 +131,8 @@ EMSCRIPTEN_BINDINGS(TaskManager) { .constructor() .function("Add", emscripten::optional_override([](TaskManager &self, Ref task) { Print("Adding Task"); + Print(StringToUpper("Testing StringToUpper")); + Print(StringToLower("Testing StringToLower")); self.Add(task.Ptr()); })) // .function("Add", emscripten::select_overload(&TaskManager::Add)) diff --git a/Task/TaskObject.h b/Task/TaskObject.h index a26876edf..3258b38a5 100644 --- a/Task/TaskObject.h +++ b/Task/TaskObject.h @@ -54,7 +54,7 @@ class TaskObject : public Task { /** * Class constructor with task entry as argument. */ - TaskObject(TaskEntry &_tentry, TA *_obja = NULL, TC *_objc = NULL) : obja(_obja), objc(_objc), Task(_tentry) {} + TaskObject(TaskEntry &_tentry, TA *_obja = nullptr, TC *_objc = nullptr) : Task(_tentry), obja(_obja), objc(_objc) {} /** * Class deconstructor. diff --git a/Terminal.mqh b/Terminal.mqh index 77aa28d13..6c5116679 100644 --- a/Terminal.mqh +++ b/Terminal.mqh @@ -43,8 +43,8 @@ class Terminal; #include "Refs.mqh" #include "String.mqh" #include "Terminal.define.h" -#include "Terminal.extern.h" #include "Terminal.enum.h" +#include "Terminal.extern.h" #include "Terminal.struct.h" #ifdef __MQL5__ @@ -876,13 +876,13 @@ class Terminal : public Object { * Returns true when the condition is met. */ bool CheckCondition(ENUM_TERMINAL_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { - long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; - long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; + // long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; + // long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; switch (_cond) { case TERMINAL_COND_IS_CONNECTED: return !IsConnected(); default: - Print(StringFormat("Invalid terminal condition: %s!", EnumToString(_cond), __FUNCTION__)); + Print("Invalid terminal condition: ", EnumToString(_cond), " at ", __FUNCTION__, "!"); return false; } } @@ -910,14 +910,14 @@ class Terminal : public Object { * Returns true when the condition is met. */ bool ExecuteAction(ENUM_TERMINAL_ACTION _action, ARRAY_REF(MqlParam, _args)) { - long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; - long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; - long _arg3l = ArraySize(_args) > 2 ? DataParamEntry::ToInteger(_args[2]) : WRONG_VALUE; + // long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; + // long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; + // long _arg3l = ArraySize(_args) > 2 ? DataParamEntry::ToInteger(_args[2]) : WRONG_VALUE; switch (_action) { case TERMINAL_ACTION_CRASH: delete THIS_PTR; default: - Print(StringFormat("Invalid terminal action: %s!", EnumToString(_action), __FUNCTION__)); + Print("Invalid terminal action: ", EnumToString(_action), " at ", __FUNCTION__, "!"); return false; } } @@ -931,40 +931,39 @@ class Terminal : public Object { /** * Returns textual representation of the Terminal class. */ - string ToString(string _sep = "; ") { + string ToString() override { + string _sep = "; "; return StringFormat("Allow DLL: %s", IsDllsAllowed() ? "Yes" : "No") + _sep + - StringFormat("Allow Libraries: %s", IsLibrariesAllowed() ? "Yes" : "No") + _sep + - StringFormat("CPUs: %d", GetCpuCores()) + _sep + - // StringFormat("Community account: %s", (string)HasCommunityAccount()) + _sep + - // StringFormat("Community balance: %.2f", GetCommunityBalance()) + _sep + - // StringFormat("Community connection: %s", (string)IsCommunityConnected()) + _sep + - StringFormat("Disk space: %d", GetDiskSpace()) + _sep + - StringFormat("Enabled FTP: %s", IsFtpEnabled() ? "Yes" : "No") + _sep + - StringFormat("Enabled e-mail: %s", IsEmailEnabled() ? "Yes" : "No") + _sep + - // StringFormat("Enabled notifications: %s", (string)IsNotificationsEnabled()) + _sep + - StringFormat("IsOptimization: %s", IsOptimization() ? "Yes" : "No") + _sep + - StringFormat("IsRealtime: %s", IsRealtime() ? "Yes" : "No") + _sep + - StringFormat("IsTesting: %s", IsTesting() ? "Yes" : "No") + _sep + - StringFormat("IsVisual: %s", IsVisualMode() ? "Yes" : "No") + _sep + - // StringFormat("MQ ID: %s", (string)HasMetaQuotesId()) + _sep + - StringFormat("Memory (free): %d", GetFreeMemory()) + _sep + - StringFormat("Memory (physical): %d", GetPhysicalMemory()) + _sep + - StringFormat("Memory (total): %d", GetTotalMemory()) + _sep + - StringFormat("Memory (used): %d", GetUsedMemory()) + _sep + - StringFormat("Path (Common): %s", GetCommonPath()) + _sep + StringFormat("Path (Data): %s", GetDataPath()) + - _sep + StringFormat("Path (Expert): %s", GetExpertPath()) + _sep + - StringFormat("Path (Terminal): %s", GetTerminalPath()) + _sep + - StringFormat("Program name: %s", WindowExpertName()) + _sep + - StringFormat("Screen DPI: %d", GetScreenDpi()) + _sep + StringFormat("Terminal build: %d", GetBuild()) + - _sep + StringFormat("Terminal code page: %d", IntegerToString(GetCodePage())) + _sep + - StringFormat("Terminal company: %s", GetCompany()) + _sep + - StringFormat("Terminal connected: %s", IsConnected() ? "Yes" : "No") + _sep + - StringFormat("Terminal language: %s", GetLanguage()) + _sep + StringFormat("Terminal name: %s", GetName()) + - _sep + StringFormat("Termnal max bars: %d", GetMaxBars()) + _sep + - StringFormat("Trade allowed: %s", IsTradeAllowed() ? "Yes" : "No") + _sep + - StringFormat("Trade context busy: %s", IsTradeContextBusy() ? "Yes" : "No") + _sep + - StringFormat("Trade perm: %s", CheckPermissionToTrade() ? "Yes" : "No") + _sep + - StringFormat("Trade ping (last): %d", GetPingLast()); + StringFormat("Allow Libraries: %s", IsLibrariesAllowed() ? "Yes" : "No") + _sep + + StringFormat("CPUs: %d", GetCpuCores()) + _sep + + // StringFormat("Community account: %s", (string)HasCommunityAccount()) + _sep + + // StringFormat("Community balance: %.2f", GetCommunityBalance()) + _sep + + // StringFormat("Community connection: %s", (string)IsCommunityConnected()) + _sep + + StringFormat("Disk space: %d", GetDiskSpace()) + _sep + + StringFormat("Enabled FTP: %s", IsFtpEnabled() ? "Yes" : "No") + _sep + + StringFormat("Enabled e-mail: %s", IsEmailEnabled() ? "Yes" : "No") + _sep + + // StringFormat("Enabled notifications: %s", (string)IsNotificationsEnabled()) + _sep + + StringFormat("IsOptimization: %s", IsOptimization() ? "Yes" : "No") + _sep + + StringFormat("IsRealtime: %s", IsRealtime() ? "Yes" : "No") + _sep + + StringFormat("IsTesting: %s", IsTesting() ? "Yes" : "No") + _sep + + StringFormat("IsVisual: %s", IsVisualMode() ? "Yes" : "No") + _sep + + // StringFormat("MQ ID: %s", (string)HasMetaQuotesId()) + _sep + + StringFormat("Memory (free): %d", GetFreeMemory()) + _sep + + StringFormat("Memory (physical): %d", GetPhysicalMemory()) + _sep + + StringFormat("Memory (total): %d", GetTotalMemory()) + _sep + + StringFormat("Memory (used): %d", GetUsedMemory()) + _sep + "Path (Common): " + GetCommonPath() + _sep + + "Path (Data): " + GetDataPath() + _sep + "Path (Expert): " + GetExpertPath() + _sep + + "Path (Terminal): ", + GetTerminalPath() + _sep + "Program name: ", + WindowExpertName() + _sep + StringFormat("Screen DPI: %d", GetScreenDpi()) + _sep + + StringFormat("Terminal build: %d", GetBuild()) + _sep + + "Terminal code page: " + IntegerToString(GetCodePage()) + _sep + "Terminal company: " + GetCompany() + + _sep + "Terminal connected: " + (IsConnected() ? "Yes" : "No") + _sep + + "Terminal language: " + GetLanguage() + _sep + "Terminal name: " + GetName() + _sep + + StringFormat("Termnal max bars: %d", GetMaxBars()) + _sep + + "Trade allowed: " + (IsTradeAllowed() ? "Yes" : "No") + _sep + + "Trade context busy: " + (IsTradeContextBusy() ? "Yes" : "No") + _sep + "Trade perm: %s" + + (CheckPermissionToTrade() ? "Yes" : "No") + _sep + StringFormat("Trade ping (last): %d", GetPingLast()); } }; diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index b600e930d..9b0622bf2 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -69,8 +69,8 @@ template struct TickTAB : TickAB { long time_ms; // Time of the last prices update. // Struct constructors. - TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : time_ms(_time_ms), TickAB(_ask, _bid) {} - TickTAB(MqlTick &_tick) : time_ms(_tick.time_msc), TickAB(_tick) {} + TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : TickAB(_ask, _bid), time_ms(_time_ms) {} + TickTAB(MqlTick &_tick) : TickAB(_tick), time_ms(_tick.time_msc) {} /** * Method used by ItemsHistory. diff --git a/Trade.mqh b/Trade.mqh index d6d98228d..2f5b81303 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -241,7 +241,8 @@ class Trade : public Taskable { * Sets default name of trade instance. */ void SetName() { - name = StringFormat("%s@%s", GetSource() PTR_DEREF GetSymbol(), ChartTf::TfToString(GetSource() PTR_DEREF GetTf())); + name = StringFormat("%s@%s", C_STR(GetSource() PTR_DEREF GetSymbol()), + C_STR(ChartTf::TfToString(GetSource() PTR_DEREF GetTf()))); } /** @@ -269,6 +270,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result = _open < _low; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } return _result; @@ -291,6 +295,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result = GetSource() PTR_DEREF GetOpenOffer(_cmd) < _pp; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } return _result; @@ -368,6 +375,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result |= _odata.Get(ORDER_PRICE_OPEN) >= _price_curr; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } } @@ -384,6 +394,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result |= _odata.Get(ORDER_PRICE_OPEN) >= _price_curr; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } } else if (_order.IsSet()) { @@ -401,7 +414,7 @@ class Trade : public Taskable { bool _result = false; Ref _order = order_last; OrderData _odata; - double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); + // double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); if (_order.IsSet()) { _result = _odata.Get(ORDER_TYPE) != _cmd; @@ -661,7 +674,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. switch (_last_error) { case 69539: logger.Error("Error while opening an order!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); tstats.Add(TRADE_STAT_ORDERS_ERRORS); // Pass-through. case ERR_NO_ERROR: // 0 @@ -684,7 +697,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; default: logger.Error("Cannot add order!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); tstats.Add(TRADE_STAT_ORDERS_ERRORS); _result = false; break; @@ -854,7 +867,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * On error, returns -1. */ int OrdersCloseAll(ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_ALL, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { @@ -884,7 +897,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. */ int OrdersCloseViaCmd(ENUM_ORDER_TYPE _cmd, ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { @@ -922,7 +935,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. template int OrdersCloseViaProp(E _prop, T _value, ENUM_MATH_CONDITION _op, ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { @@ -958,7 +971,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. template int OrdersCloseViaProp2(E _prop1, T _value1, E _prop2, T _value2, ENUM_MATH_CONDITION _op, ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { @@ -1109,7 +1122,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return NormalizeSLTP(_value1 < _value2 ? _value1 : _value2, _cmd, _mode); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; case ORDER_TYPE_SELL_LIMIT: @@ -1120,11 +1133,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return NormalizeSLTP(_value1 > _value2 ? _value1 : _value2, _cmd, _mode); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; default: - logger.Error(StringFormat("Invalid order type: %s!", EnumToString(_cmd), __FUNCTION__)); + logger.Error(StringFormat("Invalid order type: %s at %s!", C_STR(EnumToString(_cmd)), C_STR(__FUNCTION__))); } return EMPTY_VALUE; } @@ -1475,7 +1488,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return fmax(_value, GetSource() PTR_DEREF GetBid() + GetTradeDistanceInValue()); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; // Selling is done at the Bid price. @@ -1490,11 +1503,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return fmin(_value, GetSource() PTR_DEREF GetAsk() - GetTradeDistanceInValue()); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; default: - logger.Error(StringFormat("Invalid order type: %s!", EnumToString(_cmd), __FUNCTION__)); + logger.Error(StringFormat("Invalid order type: %s at %s!", C_STR(EnumToString(_cmd)), C_STR(__FUNCTION__))); } return 0; } @@ -1578,7 +1591,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } #ifdef __debug__ if (!_is_valid) { - PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", __FUNCTION__, EnumToString(_cmd), _value, _price); + PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", __FUNCTION__, C_STR(EnumToString(_cmd)), _value, + _price); } #endif if (_is_valid && _value_prev > 0 && _locked) { @@ -1609,7 +1623,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. double ask = GetSource() PTR_DEREF GetAsk(); double bid = GetSource() PTR_DEREF GetBid(); double openprice = GetSource() PTR_DEREF GetOpenOffer(_cmd); - double closeprice = GetSource() PTR_DEREF GetCloseOffer(_cmd); + // double closeprice = GetSource() PTR_DEREF GetCloseOffer(_cmd); // The minimum distance of SYMBOL_TRADE_STOPS_LEVEL taken into account. double distance = GetTradeDistanceInValue(); // bool result; @@ -1698,7 +1712,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } #ifdef __debug__ if (!_is_valid) { - PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", __FUNCTION__, EnumToString(_cmd), _value, _price); + PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", C_STR(__FUNCTION__), C_STR(EnumToString(_cmd)), + _value, _price); } #endif if (_is_valid && _value_prev > 0 && _locked) { @@ -1853,7 +1868,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // case TRADE_ORDER_CONDS_IN_TREND: // case TRADE_ORDER_CONDS_IN_TREND_NOT: default: - GetLogger() PTR_DEREF Error(StringFormat("Invalid Trade condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error( + StringFormat("Invalid Trade condition: %d at %s!", _entry.GetId(), C_STR(__FUNCTION_LINE__))); SetUserError(ERR_INVALID_PARAMETER); break; } @@ -1986,7 +2002,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case TRADE_ACTION_STATE_ADD: tstates.AddState(_entry.GetArg(0).ToValue()); default: - GetLogger() PTR_DEREF Error(StringFormat("Invalid Trade action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + GetLogger() + PTR_DEREF Error(StringFormat("Invalid Trade action: %d at %s!", _entry.GetId(), C_STR(__FUNCTION_LINE__))); SetUserError(ERR_INVALID_PARAMETER); break; } diff --git a/Trade.struct.h b/Trade.struct.h index beaf37140..56919c02a 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -129,13 +129,13 @@ struct TradeStats { /* Structure for trade parameters. */ struct TradeParams { - float lot_size; // Default lot size. - float risk_margin; // Maximum account margin to risk (in %). - string order_comment; // Order comment. + unsigned short bars_min; // Minimum bars to trade. + string order_comment; // Order comment. + float lot_size; // Default lot size. + unsigned long magic_no; // Unique magic number used for the trading. + float risk_margin; // Maximum account margin to risk (in %). unsigned int limits_stats[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; unsigned int slippage; // Value of the maximum price slippage in points. - unsigned long magic_no; // Unique magic number used for the trading. - unsigned short bars_min; // Minimum bars to trade. ENUM_LOG_LEVEL log_level; // Log verbosity level. // Constructors. TradeParams(float _lot_size = 0, float _risk_margin = 1.0, unsigned int _slippage = 50) @@ -148,7 +148,7 @@ struct TradeParams { SetLimits(0); } TradeParams(unsigned long _magic_no, ENUM_LOG_LEVEL _ll = V_INFO) - : bars_min(100), lot_size(0), order_comment(""), log_level(_ll), magic_no(_magic_no) {} + : bars_min(100), order_comment(""), lot_size(0), magic_no(_magic_no), log_level(_ll) {} TradeParams(const TradeParams &_tparams) { THIS_REF = _tparams; } // Deconstructor. ~TradeParams() {} @@ -163,11 +163,13 @@ struct TradeParams { case TRADE_PARAM_MAGIC_NO: return (T)magic_no; case TRADE_PARAM_ORDER_COMMENT: - return (T)order_comment; + return ConvertBasic::StringTo(order_comment); case TRADE_PARAM_RISK_MARGIN: return (T)risk_margin; case TRADE_PARAM_SLIPPAGE: return (T)slippage; + default: + break; } SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; @@ -220,7 +222,7 @@ struct TradeParams { magic_no = (unsigned long)_value; return; case TRADE_PARAM_ORDER_COMMENT: - order_comment = (string)_value; + order_comment = SerializerConversions::ValueToString(_value); return; case TRADE_PARAM_RISK_MARGIN: risk_margin = (float)_value; @@ -228,6 +230,8 @@ struct TradeParams { case TRADE_PARAM_SLIPPAGE: slippage = (unsigned int)_value; return; + default: + break; } SetUserError(ERR_INVALID_PARAMETER); } @@ -328,6 +332,8 @@ struct TradeStates { return "Terminal offline"; case TRADE_STATE_TRADE_TERMINAL_SHUTDOWN: return "Terminal is shutting down"; + default: + break; } return "Unknown!"; } From c09b514e9afa31a5c11d5d0f81d2637da595ac71 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 26 Jan 2023 17:00:20 +0100 Subject: [PATCH 056/123] IndicatorsTest now compiles in MT5. Need to check other tests. --- Candle.struct.h | 5 +- DateTime.static.h | 17 ++-- DictSlot.mqh | 2 +- DictStruct.mqh | 4 +- Indicator/Indicator.h | 12 +-- Indicator/IndicatorData.h | 13 ++- Indicator/IndicatorData.struct.h | 2 + Indicators/Indi_Demo.mqh | 2 +- Indicators/Indi_Momentum.mqh | 4 +- Indicators/Indi_PriceFeeder.mqh | 2 +- Indicators/Indi_StdDev.mqh | 3 +- Log.mqh | 3 +- Platform.h | 5 +- PlatformTime.h | 19 ++-- Refs.struct.h | 13 +-- Storage/ValueStorage.indicator.h | 4 +- Task/Task.h | 4 +- Terminal.define.h | 4 + Terminal.mqh | 58 ++++++------- Tick/Tick.struct.h | 1 + tests/IndicatorsTest.mq5 | 144 +++++++++++++++---------------- 21 files changed, 166 insertions(+), 155 deletions(-) diff --git a/Candle.struct.h b/Candle.struct.h index 75acc6b09..6b2f502e3 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -236,7 +236,7 @@ struct CandleOCTOHLC : CandleOHLC { // Number of ticks which formed the candle. Also known as volume. int volume; - // Struct constructors. + // Struct constructor. CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, int _start_time = -1, int _length = 0, long _open_timestamp_ms = -1, long _close_timestamp_ms = -1, int _volume = 0) : CandleOHLC(_open, _high, _low, _close), @@ -251,6 +251,9 @@ struct CandleOCTOHLC : CandleOHLC { } } + // Struct constructor. + CandleOCTOHLC(const CandleOCTOHLC &r) { THIS_REF = r; } + /** * Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price. */ diff --git a/DateTime.static.h b/DateTime.static.h index 1b5950128..c2ca188d8 100644 --- a/DateTime.static.h +++ b/DateTime.static.h @@ -31,7 +31,6 @@ #endif // Includes. -#include "DateTime.static.h" #include "PlatformTime.h" /* @@ -43,7 +42,7 @@ struct DateTimeStatic { */ static int Day(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::TimeDay(dt); @@ -59,7 +58,7 @@ struct DateTimeStatic { */ static int DayOfWeek(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::DayOfWeek(); @@ -75,7 +74,7 @@ struct DateTimeStatic { */ static int DayOfYear(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::DayOfYear(); @@ -91,7 +90,7 @@ struct DateTimeStatic { */ static int Hour(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::Hour(); @@ -116,7 +115,7 @@ struct DateTimeStatic { */ static int Minute(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::Minute(); @@ -132,7 +131,7 @@ struct DateTimeStatic { */ static int Month(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::Month(); @@ -148,7 +147,7 @@ struct DateTimeStatic { */ static int Seconds(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::Seconds(); @@ -194,7 +193,7 @@ struct DateTimeStatic { */ static int Year(datetime dt = 0) { if (dt == (datetime)0) { - dt = PlatformTime::CurrentTimestamp(); + dt = (datetime)PlatformTime::CurrentTimestamp(); } #ifdef __MQL4__ return ::Year(); diff --git a/DictSlot.mqh b/DictSlot.mqh index eea48969d..07b42fbf2 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,7 +40,7 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} - DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} + DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key) { value = r.value; } bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } diff --git a/DictStruct.mqh b/DictStruct.mqh index 6ff0063fb..229a9567c 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -113,7 +113,7 @@ class DictStruct : public DictBase { /** * Inserts value using hashless key. */ - bool Push(const V& value) { + bool Push(V& value) { if (!InsertInto(THIS_ATTR _DictSlots_ref, value)) return false; return true; } @@ -361,7 +361,7 @@ class DictStruct : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const V& value) { + bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeList; else if (THIS_ATTR _mode != DictModeList) { diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 9bab3b18f..8d625a583 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -27,12 +27,6 @@ // Forward class declaration. struct IndicatorParams; -#include "Indicator.define.h" -#include "Indicator.enum.h" -#include "Indicator.struct.h" -#include "Indicator.struct.serialize.h" -#include "IndicatorData.h" - // Includes. #include "../Array.mqh" #include "../BufferStruct.mqh" @@ -48,6 +42,12 @@ struct IndicatorParams; #include "../Storage/ValueStorage.h" #include "../Storage/ValueStorage.indicator.h" #include "../Storage/ValueStorage.native.h" +#include "../Task/TaskCondition.enum.h" +#include "Indicator.define.h" +#include "Indicator.enum.h" +#include "Indicator.struct.h" +#include "Indicator.struct.serialize.h" +#include "IndicatorData.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compatibility). diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 2d706bda3..0707e4fe8 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -32,6 +32,11 @@ // Forward class declaration. class IndicatorData; class DrawIndicator; +class IValueStorage; + +struct ExternInstantiateIndicatorBufferValueStorageDouble { + static IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData*, int); +}; // Includes. #include "../Bar.struct.h" @@ -48,8 +53,6 @@ class DrawIndicator; #include "IndicatorData.struct.serialize.h" #include "IndicatorData.struct.signal.h" -extern IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData* _indi, int _mode); - /** * Implements class to store indicator data. */ @@ -745,7 +748,7 @@ class IndicatorData : public IndicatorBase { */ void AddListener(IndicatorData* _indi) { WeakRef _ref = _indi; - ArrayPush(listeners, _ref); + ArrayPushObject(listeners, _ref); } /** @@ -1746,7 +1749,9 @@ class IndicatorData : public IndicatorBase { } if (!value_storages[_mode].IsSet()) { - value_storages[_mode] = InstantiateIndicatorBufferValueStorageDouble(THIS_PTR, _mode); + value_storages[_mode] = + ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble(THIS_PTR, + _mode); } return value_storages[_mode].Ptr(); } diff --git a/Indicator/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h index dd4e29493..549c44219 100644 --- a/Indicator/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -530,6 +530,8 @@ struct IndicatorDataParams { indi_color = _clr; draw_window = _window; } + bool IsDrawing() { return is_draw; } + void SetIndicatorColor(color _clr) { indi_color = _clr; } }; diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index d4bf22c37..07afa9a28 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -81,7 +81,7 @@ class Indi_Demo : public Indicator { */ virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = Indi_Demo::iDemo(THIS_PTR, ToRelShift(_abs_shift)); - if (idparams.is_draw) { + if (idparams.IsDrawing()) { draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(ToRelShift(_abs_shift)), _value); } return _value; diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 122c15e37..679f96c45 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -150,7 +150,7 @@ class Indi_Momentum : public Indicator { // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), iparams.shift + ToRelShift(_abs_shift)); - if (idparams.is_draw) { + if (idparams.IsDrawing()) { draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); } break; @@ -164,7 +164,7 @@ class Indi_Momentum : public Indicator { // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), iparams.shift + ToRelShift(_abs_shift)); - if (idparams.is_draw) { + if (idparams.IsDrawing()) { draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); } break; diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index cbe8b7213..4b93f08ea 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -103,7 +103,7 @@ class Indi_PriceFeeder : public Indicator { void OnTick(int _global_tick_index) override { Indicator::OnTick(_global_tick_index); - if (idparams.is_draw) { + if (idparams.IsDrawing()) { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); IndicatorDataEntry _entry = GetEntry(0); for (int i = 0; i < _max_modes; ++i) { diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 3154b4e51..7de50a928 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -199,7 +199,8 @@ class Indi_StdDev : public Indicator { Indi_PriceFeeder *_indi_price_feeder; if (!ObjectsCache::TryGet(_key, _indi_price_feeder)) { IndiPriceFeederParams _params(); - _indi_price_feeder = ObjectsCache::Set(_key, new Indi_PriceFeeder(_params)); + IndicatorData *_indi_pf = new Indi_PriceFeeder(_params); + _indi_price_feeder = ObjectsCache::Set(_key, _indi_pf); } // Filling reused price feeder. diff --git a/Log.mqh b/Log.mqh index 0a4bff34a..b83ca09e0 100644 --- a/Log.mqh +++ b/Log.mqh @@ -188,7 +188,8 @@ class Log : public Object { void Link(Log *_log) { PTR_ATTRIB(_log, SetLevel(log_level)); // Sets the same level as this instance. // @todo: Make sure we're not linking the same instance twice. - logs.Push(_log); + Ref _ref_log = _log; + logs.Push(_ref_log); } /** diff --git a/Platform.h b/Platform.h index 7a520a5b5..90f8440cf 100644 --- a/Platform.h +++ b/Platform.h @@ -219,7 +219,10 @@ class Platform { /** * Returns id of the current chart. */ - static int ChartID() { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); } + static int ChartID() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; + } /** * Binds Candle and/or Tick indicator as a source of prices or data for given indicator. diff --git a/PlatformTime.h b/PlatformTime.h index 8e62646f5..89cb39527 100644 --- a/PlatformTime.h +++ b/PlatformTime.h @@ -23,7 +23,6 @@ // Includes. #include "DateTime.enum.h" #include "DateTime.mqh" -#include "DateTime.struct.h" /** * @file @@ -35,7 +34,9 @@ // Includes. #include #include + #include "DateTime.struct.h" +#endif class PlatformTime { static MqlDateTime current_time; @@ -49,19 +50,19 @@ class PlatformTime { void static Tick() { #ifdef __MQL__ - static _last_time_ms = 0; + static long _last_timestamp_ms = 0; - current_time_s = ::TimeCurrent(¤t_time); + current_timestamp_s = ::TimeCurrent(current_time); - current_time_ms = (long)GetTickCount(); + current_timestamp_ms = (long)GetTickCount(); - if (_last_time_ms != 0 && current_time_ms < _last_time_ms) { + if (_last_timestamp_ms != 0 && current_timestamp_ms < _last_timestamp_ms) { // Overflow occured (49.7 days passed). // More info: https://docs.mql4.com/common/gettickcount - current_time_ms += _last_time_ms; + current_timestamp_ms += _last_timestamp_ms; } - _last_time_ms = current_time_ms; + _last_timestamp_ms = current_timestamp_ms; #else using namespace std::chrono; current_timestamp_s = (long)duration_cast(system_clock::now().time_since_epoch()).count(); @@ -82,8 +83,6 @@ class PlatformTime { } }; -MqlDateTime PlatformTime::current_time{0, 0, 0, 0, 0, 0, 0, 0}; +MqlDateTime PlatformTime::current_time = {0, 0, 0, 0, 0, 0, 0, 0}; long PlatformTime::current_timestamp_s = 0; long PlatformTime::current_timestamp_ms = 0; - -#endif diff --git a/Refs.struct.h b/Refs.struct.h index 9827f7b1a..210f58f11 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -30,9 +30,6 @@ #pragma once #endif -// Includes. -#include - #include "Refs.rc.h" #include "Std.h" @@ -93,10 +90,6 @@ struct SimpleRef { } }; -template -using base_type = - typename std::remove_cv::type>::type>::type; - /** * Class used to hold strong reference to reference-counted object. */ @@ -284,9 +277,9 @@ struct Ref { } }; -template -Ref make_ref() { - return Ref(); +template +Ref MakeRef(X* _ptr) { + return Ref(_ptr); } /** diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 4406fe397..254767c7c 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -34,6 +34,7 @@ class IndicatorData; // Includes. +#include "../Indicator/IndicatorData.h" #include "ValueStorage.history.h" /** @@ -57,6 +58,7 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { C Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_rel_shift)); } }; -IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData* _indi, int _mode) { +IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble( + IndicatorData* _indi, int _mode) { return new IndicatorBufferValueStorage(_indi, _mode); } diff --git a/Task/Task.h b/Task/Task.h index c2ca184cc..266a60284 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -50,7 +50,7 @@ class Task : public Taskable { * Class constructor. */ Task() {} - Task(const TaskEntry &_entry) { Add(_entry); } + Task(TaskEntry &_entry) { Add(_entry); } /** * Class copy constructor. @@ -67,7 +67,7 @@ class Task : public Taskable { /** * Adds new task. */ - void Add(const TaskEntry &_entry) { tasks.Push(_entry); } + void Add(TaskEntry &_entry) { tasks.Push(_entry); } /* Virtual methods */ diff --git a/Terminal.define.h b/Terminal.define.h index a316eea43..fd66662aa 100644 --- a/Terminal.define.h +++ b/Terminal.define.h @@ -37,6 +37,8 @@ #define CP_UTF7 65000 // UTF-7 code page. #define CP_UTF8 65001 // UTF-8 code page. +#ifndef __MQL__ + // Colors. #define clrAliceBlue 0x00F0F8FF #define clrAntiqueWhite 0x00FAEBD7 @@ -304,6 +306,8 @@ #define Yellow clrYellow #define YellowGreen clrYellowGreen +#endif + #ifndef __MQL__ #define clrNONE -1 #define CLR_NONE -1 diff --git a/Terminal.mqh b/Terminal.mqh index 6c5116679..3fe1a77b0 100644 --- a/Terminal.mqh +++ b/Terminal.mqh @@ -934,36 +934,34 @@ class Terminal : public Object { string ToString() override { string _sep = "; "; return StringFormat("Allow DLL: %s", IsDllsAllowed() ? "Yes" : "No") + _sep + - StringFormat("Allow Libraries: %s", IsLibrariesAllowed() ? "Yes" : "No") + _sep + - StringFormat("CPUs: %d", GetCpuCores()) + _sep + - // StringFormat("Community account: %s", (string)HasCommunityAccount()) + _sep + - // StringFormat("Community balance: %.2f", GetCommunityBalance()) + _sep + - // StringFormat("Community connection: %s", (string)IsCommunityConnected()) + _sep + - StringFormat("Disk space: %d", GetDiskSpace()) + _sep + - StringFormat("Enabled FTP: %s", IsFtpEnabled() ? "Yes" : "No") + _sep + - StringFormat("Enabled e-mail: %s", IsEmailEnabled() ? "Yes" : "No") + _sep + - // StringFormat("Enabled notifications: %s", (string)IsNotificationsEnabled()) + _sep + - StringFormat("IsOptimization: %s", IsOptimization() ? "Yes" : "No") + _sep + - StringFormat("IsRealtime: %s", IsRealtime() ? "Yes" : "No") + _sep + - StringFormat("IsTesting: %s", IsTesting() ? "Yes" : "No") + _sep + - StringFormat("IsVisual: %s", IsVisualMode() ? "Yes" : "No") + _sep + - // StringFormat("MQ ID: %s", (string)HasMetaQuotesId()) + _sep + - StringFormat("Memory (free): %d", GetFreeMemory()) + _sep + - StringFormat("Memory (physical): %d", GetPhysicalMemory()) + _sep + - StringFormat("Memory (total): %d", GetTotalMemory()) + _sep + - StringFormat("Memory (used): %d", GetUsedMemory()) + _sep + "Path (Common): " + GetCommonPath() + _sep + - "Path (Data): " + GetDataPath() + _sep + "Path (Expert): " + GetExpertPath() + _sep + - "Path (Terminal): ", - GetTerminalPath() + _sep + "Program name: ", - WindowExpertName() + _sep + StringFormat("Screen DPI: %d", GetScreenDpi()) + _sep + - StringFormat("Terminal build: %d", GetBuild()) + _sep + - "Terminal code page: " + IntegerToString(GetCodePage()) + _sep + "Terminal company: " + GetCompany() + - _sep + "Terminal connected: " + (IsConnected() ? "Yes" : "No") + _sep + - "Terminal language: " + GetLanguage() + _sep + "Terminal name: " + GetName() + _sep + - StringFormat("Termnal max bars: %d", GetMaxBars()) + _sep + - "Trade allowed: " + (IsTradeAllowed() ? "Yes" : "No") + _sep + - "Trade context busy: " + (IsTradeContextBusy() ? "Yes" : "No") + _sep + "Trade perm: %s" + - (CheckPermissionToTrade() ? "Yes" : "No") + _sep + StringFormat("Trade ping (last): %d", GetPingLast()); + StringFormat("Allow Libraries: %s", IsLibrariesAllowed() ? "Yes" : "No") + _sep + + StringFormat("CPUs: %d", GetCpuCores()) + _sep + + // StringFormat("Community account: %s", (string)HasCommunityAccount()) + _sep + + // StringFormat("Community balance: %.2f", GetCommunityBalance()) + _sep + + // StringFormat("Community connection: %s", (string)IsCommunityConnected()) + _sep + + StringFormat("Disk space: %d", GetDiskSpace()) + _sep + + StringFormat("Enabled FTP: %s", IsFtpEnabled() ? "Yes" : "No") + _sep + + StringFormat("Enabled e-mail: %s", IsEmailEnabled() ? "Yes" : "No") + _sep + + // StringFormat("Enabled notifications: %s", (string)IsNotificationsEnabled()) + _sep + + StringFormat("IsOptimization: %s", IsOptimization() ? "Yes" : "No") + _sep + + StringFormat("IsRealtime: %s", IsRealtime() ? "Yes" : "No") + _sep + + StringFormat("IsTesting: %s", IsTesting() ? "Yes" : "No") + _sep + + StringFormat("IsVisual: %s", IsVisualMode() ? "Yes" : "No") + _sep + + // StringFormat("MQ ID: %s", (string)HasMetaQuotesId()) + _sep + + StringFormat("Memory (free): %d", GetFreeMemory()) + _sep + + StringFormat("Memory (physical): %d", GetPhysicalMemory()) + _sep + + StringFormat("Memory (total): %d", GetTotalMemory()) + _sep + + StringFormat("Memory (used): %d", GetUsedMemory()) + _sep + "Path (Common): " + GetCommonPath() + _sep + + "Path (Data): " + GetDataPath() + _sep + "Path (Expert): " + GetExpertPath() + _sep + + "Path (Terminal): " + GetTerminalPath() + _sep + "Program name: " + WindowExpertName() + _sep + + StringFormat("Screen DPI: %d", GetScreenDpi()) + _sep + StringFormat("Terminal build: %d", GetBuild()) + + _sep + "Terminal code page: " + IntegerToString(GetCodePage()) + _sep + "Terminal company: " + GetCompany() + + _sep + "Terminal connected: " + (IsConnected() ? "Yes" : "No") + _sep + + "Terminal language: " + GetLanguage() + _sep + "Terminal name: " + GetName() + _sep + + StringFormat("Termnal max bars: %d", GetMaxBars()) + _sep + + "Trade allowed: " + (IsTradeAllowed() ? "Yes" : "No") + _sep + + "Trade context busy: " + (IsTradeContextBusy() ? "Yes" : "No") + _sep + "Trade perm: %s" + + (CheckPermissionToTrade() ? "Yes" : "No") + _sep + StringFormat("Trade ping (last): %d", GetPingLast()); } }; diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 9b0622bf2..71f08dcf8 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -71,6 +71,7 @@ struct TickTAB : TickAB { // Struct constructors. TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : TickAB(_ask, _bid), time_ms(_time_ms) {} TickTAB(MqlTick &_tick) : TickAB(_tick), time_ms(_tick.time_msc) {} + TickTAB(const TickTAB &r) { THIS_REF = r; } /** * Method used by ItemsHistory. diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 1b96d9b5c..b1fc5c575 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -164,29 +164,29 @@ bool InitIndicators() { /* Standard indicators */ // AC. - indis.Push(new Indi_AC()); + indis.Push(Ref(new Indi_AC())); // AD. - indis.Push(new Indi_AD()); + indis.Push(Ref(new Indi_AD())); // ADX. IndiADXParams adx_params(14); - indis.Push(new Indi_ADX(adx_params)); + indis.Push(Ref(new Indi_ADX(adx_params))); // Alligator. IndiAlligatorParams alli_params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - indis.Push(new Indi_Alligator(alli_params)); + indis.Push(Ref(new Indi_Alligator(alli_params))); // Awesome Oscillator (AO). - indis.Push(new Indi_AO()); + indis.Push(Ref(new Indi_AO())); // Accumulation Swing Index (ASI). IndiASIParams _asi_params; - indis.Push(new Indi_ASI(_asi_params)); + indis.Push(Ref(new Indi_ASI(_asi_params))); // Average True Range (ATR). IndiATRParams atr_params(14); - indis.Push(new Indi_ATR(atr_params)); + indis.Push(Ref(new Indi_ATR(atr_params))); // Bollinger Bands - Built-in. IndiBandsParams bands_params(20, 2, 0, PRICE_OPEN); @@ -201,50 +201,50 @@ bool InitIndicators() { // Bears Power. IndiBearsPowerParams bears_params(13, PRICE_CLOSE); - indis.Push(new Indi_BearsPower(bears_params)); + indis.Push(Ref(new Indi_BearsPower(bears_params))); // Bulls Power. IndiBullsPowerParams bulls_params(13, PRICE_CLOSE); - indis.Push(new Indi_BullsPower(bulls_params)); + indis.Push(Ref(new Indi_BullsPower(bulls_params))); // Market Facilitation Index (BWMFI). IndiBWIndiMFIParams _bwmfi_params(1); - indis.Push(new Indi_BWMFI(_bwmfi_params)); + indis.Push(Ref(new Indi_BWMFI(_bwmfi_params))); // Commodity Channel Index (CCI). IndiCCIParams cci_params(14, PRICE_OPEN); - indis.Push(new Indi_CCI(cci_params)); + indis.Push(Ref(new Indi_CCI(cci_params))); // DeMarker. IndiDeMarkerParams dm_params(14); - indis.Push(new Indi_DeMarker(dm_params)); + indis.Push(Ref(new Indi_DeMarker(dm_params))); // Envelopes. IndiEnvelopesParams env_params(13, 0, MODE_SMA, PRICE_OPEN, 2); - indis.Push(new Indi_Envelopes(env_params)); + indis.Push(Ref(new Indi_Envelopes(env_params))); // Force Index. IndiForceParams force_params(13, MODE_SMA, PRICE_CLOSE); - indis.Push(new Indi_Force(force_params)); + indis.Push(Ref(new Indi_Force(force_params))); // Fractals. - indis.Push(new Indi_Fractals()); + indis.Push(Ref(new Indi_Fractals())); // Fractal Adaptive Moving Average (FRAMA). IndiFrAIndiMAParams frama_params(); - indis.Push(new Indi_FrAMA(frama_params)); + indis.Push(Ref(new Indi_FrAMA(frama_params))); // Gator Oscillator. IndiGatorParams gator_params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - indis.Push(new Indi_Gator(gator_params)); + indis.Push(Ref(new Indi_Gator(gator_params))); // Heiken Ashi. IndiHeikenAshiParams _ha_params(); - indis.Push(new Indi_HeikenAshi(_ha_params)); + indis.Push(Ref(new Indi_HeikenAshi(_ha_params))); // Ichimoku Kinko Hyo. IndiIchimokuParams ichi_params(9, 26, 52); - indis.Push(new Indi_Ichimoku(ichi_params)); + indis.Push(Ref(new Indi_Ichimoku(ichi_params))); // Moving Average. IndiMAParams ma_params(13, 0, MODE_SMA, PRICE_OPEN); @@ -263,23 +263,23 @@ bool InitIndicators() { // Money Flow Index (MFI). IndiMFIParams mfi_params(14); - indis.Push(new Indi_MFI(mfi_params)); + indis.Push(Ref(new Indi_MFI(mfi_params))); // Momentum (MOM). IndiMomentumParams mom_params(); - indis.Push(new Indi_Momentum(mom_params)); + indis.Push(Ref(new Indi_Momentum(mom_params))); // On Balance Volume (OBV). - indis.Push(new Indi_OBV()); + indis.Push(Ref(new Indi_OBV())); // OsMA. IndiOsMAParams osma_params(12, 26, 9, PRICE_CLOSE); - indis.Push(new Indi_OsMA(osma_params)); + indis.Push(Ref(new Indi_OsMA(osma_params))); // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); Ref indi_rsi = new Indi_RSI(rsi_params); - indis.Push(indi_rsi.Ptr()); + indis.Push(Ref(indi_rsi.Ptr())); // Bollinger Bands over RSI. IndiBandsParams indi_bands_over_rsi_params(20, 2, 0, PRICE_OPEN); @@ -302,11 +302,11 @@ bool InitIndicators() { // Relative Vigor Index (RVI). IndiRVIParams rvi_params(14); - indis.Push(new Indi_RVI(rvi_params)); + indis.Push(Ref(new Indi_RVI(rvi_params))); // Parabolic SAR. IndiSARParams sar_params(0.02, 0.2); - indis.Push(new Indi_SAR(sar_params)); + indis.Push(Ref(new Indi_SAR(sar_params))); // Standard Deviation (StdDev). Ref indi_price_for_stdev = new Indi_Price(PriceIndiParams()); @@ -314,24 +314,24 @@ bool InitIndicators() { // stddev_on_price_params.SetDraw(clrBlue, 1); // @fixme Ref indi_stddev_on_price = new Indi_StdDev(stddev_on_price_params, IDATA_BUILTIN, indi_price_for_stdev.Ptr()); - indis.Push(indi_stddev_on_price.Ptr()); + indis.Push(Ref(indi_stddev_on_price.Ptr())); // Stochastic Oscillator. IndiStochParams stoch_params(5, 3, 3, MODE_SMMA, STO_LOWHIGH); - indis.Push(new Indi_Stochastic(stoch_params)); + indis.Push(Ref(new Indi_Stochastic(stoch_params))); // Williams' Percent Range (WPR). IndiWPRParams wpr_params(14); - indis.Push(new Indi_WPR(wpr_params)); + indis.Push(Ref(new Indi_WPR(wpr_params))); // ZigZag. IndiZigZagParams zz_params(12, 5, 3); - indis.Push(new Indi_ZigZag(zz_params)); + indis.Push(Ref(new Indi_ZigZag(zz_params))); /* Special indicators */ // Demo/Dummy Indicator. - indis.Push(new Indi_Demo()); + indis.Push(Ref(new Indi_Demo())); // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); @@ -339,7 +339,7 @@ bool InitIndicators() { IndiBandsParams bands_on_price_params(); // bands_on_price_params.SetDraw(clrCadetBlue); // @fixme Ref indi_bands_on_price = new Indi_Bands(bands_on_price_params, IDATA_BUILTIN, indi_price_4_bands.Ptr()); - indis.Push(indi_bands_on_price.Ptr()); + indis.Push(Ref(indi_bands_on_price.Ptr())); // Standard Deviation (StdDev) over MA(SMA). // NOTE: If you set ma_shift parameter for MA, then StdDev will no longer @@ -352,7 +352,7 @@ bool InitIndicators() { Ref indi_stddev_on_ma_sma = new Indi_StdDev(stddev_params_on_ma_sma, IDATA_BUILTIN, indi_ma_sma_for_stddev.Ptr()); - indis.Push(indi_stddev_on_ma_sma.Ptr()); + indis.Push(Ref(indi_stddev_on_ma_sma.Ptr())); // Standard Deviation (StdDev) in SMA mode over Price. PriceIndiParams price_params_for_stddev_sma(); @@ -361,7 +361,7 @@ bool InitIndicators() { // stddev_sma_on_price_params.SetDraw(true, 1); // @fixme Ref indi_stddev_on_sma = new Indi_StdDev(stddev_sma_on_price_params, IDATA_BUILTIN, indi_price_for_stddev_sma.Ptr()); - indis.Push(indi_stddev_on_sma.Ptr()); + indis.Push(Ref(indi_stddev_on_sma.Ptr())); // Moving Average (MA) over Price indicator. PriceIndiParams price_params_4_ma(); @@ -370,7 +370,7 @@ bool InitIndicators() { // ma_on_price_params.SetDraw(clrYellowGreen); // @fixme ma_on_price_params.SetIndicatorType(INDI_MA_ON_PRICE); Ref indi_ma_on_price = new Indi_MA(ma_on_price_params, IDATA_BUILTIN, indi_price_4_ma.Ptr()); - indis.Push(indi_ma_on_price.Ptr()); + indis.Push(Ref(indi_ma_on_price.Ptr())); // Commodity Channel Index (CCI) over Price indicator. PriceIndiParams price_params_4_cci(); @@ -378,7 +378,7 @@ bool InitIndicators() { IndiCCIParams cci_on_price_params(); // cci_on_price_params.SetDraw(clrYellowGreen, 1); // @fixme Ref indi_cci_on_price = new Indi_CCI(cci_on_price_params, IDATA_BUILTIN, indi_price_4_cci.Ptr()); - indis.Push(indi_cci_on_price.Ptr()); + indis.Push(Ref(indi_cci_on_price.Ptr())); // Envelopes over Price indicator. PriceIndiParams price_params_4_envelopes(); @@ -387,7 +387,7 @@ bool InitIndicators() { // env_on_price_params.SetDraw(clrBrown); // @fixme Ref indi_envelopes_on_price = new Indi_Envelopes(env_on_price_params, IDATA_BUILTIN, indi_price_4_envelopes.Ptr()); - indis.Push(indi_envelopes_on_price.Ptr()); + indis.Push(Ref(indi_envelopes_on_price.Ptr())); // DEMA over Price indicator. PriceIndiParams price_params_4_dema(); @@ -404,7 +404,7 @@ bool InitIndicators() { // mom_on_price_params.SetDraw(clrDarkCyan); // @fixme Ref indi_momentum_on_price = new Indi_Momentum(mom_on_price_params, IDATA_BUILTIN, indi_price_4_momentum.Ptr()); - indis.Push(indi_momentum_on_price.Ptr()); + indis.Push(Ref(indi_momentum_on_price.Ptr())); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); @@ -412,13 +412,13 @@ bool InitIndicators() { IndiRSIParams rsi_on_price_params(); // rsi_on_price_params.SetDraw(clrBisque, 1); // @fixme Ref indi_rsi_on_price = new Indi_RSI(rsi_on_price_params, IDATA_BUILTIN, indi_price_4_rsi.Ptr()); - indis.Push(indi_rsi_on_price.Ptr()); + indis.Push(Ref(indi_rsi_on_price.Ptr())); // Drawer (socket-based) indicator over RSI over Price. IndiDrawerParams drawer_params(14, PRICE_OPEN); // drawer_params.SetDraw(clrBisque, 0); // @fixme Ref indi_drawer_on_rsi = new Indi_Drawer(drawer_params, IDATA_BUILTIN, indi_rsi_on_price.Ptr()); - indis.Push(indi_drawer_on_rsi.Ptr()); + indis.Push(Ref(indi_drawer_on_rsi.Ptr())); // Applied Price over OHCL indicator. IndiAppliedPriceParams applied_price_params(); @@ -426,11 +426,11 @@ bool InitIndicators() { IndiOHLCParams applied_price_ohlc_params(PRICE_TYPICAL); Ref indi_applied_price_on_price = new Indi_AppliedPrice(applied_price_params, IDATA_INDICATOR, new Indi_OHLC(applied_price_ohlc_params)); - indis.Push(indi_applied_price_on_price.Ptr()); + indis.Push(Ref(indi_applied_price_on_price.Ptr())); // ADXW. IndiADXWParams adxw_params(14); - indis.Push(new Indi_ADXW(adxw_params)); + indis.Push(Ref(new Indi_ADXW(adxw_params))); // AMA. IndiAMAParams ama_params(); @@ -438,126 +438,126 @@ bool InitIndicators() { // However, in that case we need to specifiy applied price (excluding ASK and BID). Indi_AMA* _indi_ama = new Indi_AMA(ama_params, IDATA_INDICATOR); _indi_ama.SetAppliedPrice(PRICE_OPEN); - indis.Push(_indi_ama); + indis.Push(Ref(_indi_ama)); // Original AMA. IndiAMAParams ama_params_orig(); ama_params_orig.SetName("Original AMA to compare"); - indis.Push(new Indi_AMA(ama_params_orig)); + indis.Push(Ref(new Indi_AMA(ama_params_orig))); // Chaikin Oscillator. IndiCHOParams cho_params(); - indis.Push(new Indi_CHO(cho_params)); + indis.Push(Ref(new Indi_CHO(cho_params))); // Chaikin Volatility. IndiCHVParams chv_params(); - indis.Push(new Indi_CHV(chv_params)); + indis.Push(Ref(new Indi_CHV(chv_params))); // Color Bars. IndiColorBarsParams color_bars_params(); - indis.Push(new Indi_ColorBars(color_bars_params)); + indis.Push(Ref(new Indi_ColorBars(color_bars_params))); // Color Candles Daily. IndiColorCandlesDailyParams color_candles_daily_params(); - indis.Push(new Indi_ColorCandlesDaily(color_candles_daily_params)); + indis.Push(Ref(new Indi_ColorCandlesDaily(color_candles_daily_params))); // Color Line. IndiColorLineParams color_line_params(); - indis.Push(new Indi_ColorLine(color_line_params)); + indis.Push(Ref(new Indi_ColorLine(color_line_params))); // Detrended Price Oscillator. IndiDetrendedPriceParams detrended_params(); - indis.Push(new Indi_DetrendedPrice(detrended_params)); + indis.Push(Ref(new Indi_DetrendedPrice(detrended_params))); // Mass Index. IndiMassIndexParams mass_index_params(); - indis.Push(new Indi_MassIndex(mass_index_params)); + indis.Push(Ref(new Indi_MassIndex(mass_index_params))); // OHLC. IndiOHLCParams ohlc_params(); - indis.Push(new Indi_OHLC(ohlc_params)); + indis.Push(Ref(new Indi_OHLC(ohlc_params))); // Price Channel. IndiPriceChannelParams price_channel_params(); - indis.Push(new Indi_PriceChannel(price_channel_params)); + indis.Push(Ref(new Indi_PriceChannel(price_channel_params))); // Price Volume Trend. IndiPriceVolumeTrendParams price_volume_trend_params(); - indis.Push(new Indi_PriceVolumeTrend(price_volume_trend_params)); + indis.Push(Ref(new Indi_PriceVolumeTrend(price_volume_trend_params))); // Bill Williams' Zone Trade. IndiBWZTParams bwzt_params(); - indis.Push(new Indi_BWZT(bwzt_params)); + indis.Push(Ref(new Indi_BWZT(bwzt_params))); // Rate of Change. IndiRateOfChangeParams rate_of_change_params(); - indis.Push(new Indi_RateOfChange(rate_of_change_params)); + indis.Push(Ref(new Indi_RateOfChange(rate_of_change_params))); // Triple Exponential Moving Average. IndiTEMAParams tema_params(); - indis.Push(new Indi_TEMA(tema_params)); + indis.Push(Ref(new Indi_TEMA(tema_params))); // Triple Exponential Average. IndiTRIXParams trix_params(); - indis.Push(new Indi_TRIX(trix_params)); + indis.Push(Ref(new Indi_TRIX(trix_params))); // Ultimate Oscillator. IndiUltimateOscillatorParams ultimate_oscillator_params(); - indis.Push(new Indi_UltimateOscillator(ultimate_oscillator_params)); + indis.Push(Ref(new Indi_UltimateOscillator(ultimate_oscillator_params))); // VIDYA. IndiVIDYAParams vidya_params(); - indis.Push(new Indi_VIDYA(vidya_params)); + indis.Push(Ref(new Indi_VIDYA(vidya_params))); // Volumes. IndiVolumesParams volumes_params(); - indis.Push(new Indi_Volumes(volumes_params)); + indis.Push(Ref(new Indi_Volumes(volumes_params))); // Volume Rate of Change. IndiVROCParams vol_rate_of_change_params(); - indis.Push(new Indi_VROC(vol_rate_of_change_params)); + indis.Push(Ref(new Indi_VROC(vol_rate_of_change_params))); // Larry Williams' Accumulation/Distribution. IndiWilliamsADParams williams_ad_params(); - indis.Push(new Indi_WilliamsAD(williams_ad_params)); + indis.Push(Ref(new Indi_WilliamsAD(williams_ad_params))); // ZigZag Color. IndiZigZagColorParams zigzag_color_params(); - indis.Push(new Indi_ZigZagColor(zigzag_color_params)); + indis.Push(Ref(new Indi_ZigZagColor(zigzag_color_params))); // Custom Moving Average. IndiCustomMovingAverageParams cma_params(); - indis.Push(new Indi_CustomMovingAverage(cma_params)); + indis.Push(Ref(new Indi_CustomMovingAverage(cma_params))); // Math (specialized indicator). IndiMathParams math_params(MATH_OP_SUB, BAND_UPPER, BAND_LOWER, 0, 0); // math_params.SetDraw(clrBlue); // @fixme math_params.SetName("Bands(UP - LO)"); Ref indi_math_1 = new Indi_Math(math_params, IDATA_INDICATOR, indi_bands.Ptr()); - indis.Push(indi_math_1.Ptr()); + indis.Push(Ref(indi_math_1.Ptr())); // Math (specialized indicator) via custom math method. IndiMathParams math_custom_params(MathCustomOp, BAND_UPPER, BAND_LOWER, 0, 0); // math_custom_params.SetDraw(clrBeige); // @fixme math_custom_params.SetName("Bands(Custom math fn)"); Ref indi_math_2 = new Indi_Math(math_custom_params, IDATA_INDICATOR, indi_bands.Ptr()); - indis.Push(indi_math_2.Ptr()); + indis.Push(Ref(indi_math_2.Ptr())); // RS (Math-based) indicator. IndiRSParams rs_params(); - indis.Push(new Indi_RS(rs_params)); + indis.Push(Ref(new Indi_RS(rs_params))); // Pattern Detector. IndiPatternParams pattern_params(); - indis.Push(new Indi_Pattern(pattern_params)); + indis.Push(Ref(new Indi_Pattern(pattern_params))); // Pivot. IndiPivotParams pivot_params(); - indis.Push(new Indi_Pivot(pivot_params)); + indis.Push(Ref(new Indi_Pivot(pivot_params))); // Candle Pattern Detector. CandleParams candle_params(); - indis.Push(new Indi_Candle(candle_params)); + indis.Push(Ref(new Indi_Candle(candle_params))); // Push white-listed indicators here. // whitelisted_indis.Push(_indi_test); @@ -592,7 +592,7 @@ bool PrintIndicators(string _prefix = "") { continue; } if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString(0)); + PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString()); } } return GetLastError() == ERR_NO_ERROR; From 88108ce6edc52215612c3e0995163cf64d799d3d Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Sat, 28 Jan 2023 00:04:09 +0100 Subject: [PATCH 057/123] WIP. Fixing MT5 tests. --- Database.mqh | 28 +++++++++++++++++++++------- DictSlot.mqh | 4 ++++ Draw.mqh | 3 ++- Market.struct.h | 1 + Matrix.mqh | 2 +- Order.enum.h | 2 ++ Order.mqh | 10 +++++----- PlatformTime.h | 1 - Task/TaskManager.h | 6 +++++- tests/EATest.mq5 | 1 + tests/OrderTest.mq5 | 2 +- tests/RefsTest.mq5 | 33 +++++++++++++++++---------------- tests/TerminalTest.mq5 | 4 ++-- 13 files changed, 62 insertions(+), 35 deletions(-) diff --git a/Database.mqh b/Database.mqh index 078949f49..2a4bcc82b 100644 --- a/Database.mqh +++ b/Database.mqh @@ -74,6 +74,21 @@ struct DatabaseTableColumnEntry { // State methods. bool IsKey() { return bool(flags & DATABASE_COLUMN_FLAG_IS_KEY); } bool IsNull() { return bool(flags & DATABASE_COLUMN_FLAG_IS_NULL); } + + DatabaseTableColumnEntry() {} + DatabaseTableColumnEntry(const string _name, const ENUM_DATATYPE _type, unsigned short _flags = 0, + unsigned short _char_size = 0) { + name = _name; + type = _type; + flags = _flags; + char_size = _char_size; + } + DatabaseTableColumnEntry(const DatabaseTableColumnEntry &r) { + name = r.name; + type = r.type; + flags = r.flags; + char_size = r.char_size; + } }; struct DatabaseTableSchema { DictStruct columns; @@ -84,6 +99,7 @@ struct DatabaseTableSchema { columns.Push(_columns[i]); } } + DatabaseTableSchema(const DatabaseTableSchema &r) { columns = r.columns; } // Methods. bool AddColumn(DatabaseTableColumnEntry &column) { return columns.Push(column); } }; @@ -98,13 +114,11 @@ struct DbSymbolInfoEntry : public SymbolInfoEntry { } // Methods. void DefineSchema() { - DatabaseTableColumnEntry _columns[] = { - {"bid", TYPE_DOUBLE}, {"ask", TYPE_DOUBLE}, {"last", TYPE_DOUBLE}, - {"spread", TYPE_DOUBLE}, {"volume", TYPE_INT}, - }; - for (int i = 0; i < ArraySize(_columns); i++) { - schema.columns.Push(_columns[i]); - } + schema.columns.Push(DatabaseTableColumnEntry("bid", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("ask", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("last", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("spread", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("volume", TYPE_INT)); } }; #endif diff --git a/DictSlot.mqh b/DictSlot.mqh index 07b42fbf2..3752244c9 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,7 +40,11 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} +#ifdef __MQL__ + DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} +#else DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key) { value = r.value; } +#endif bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } diff --git a/Draw.mqh b/Draw.mqh index 5cea3f3ee..0e637d088 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -33,6 +33,7 @@ class Draw; #include "Data.define.h" #include "Object.extern.h" //#include "Platform.h" +#include "Object.mqh" #include "Terminal.define.h" #ifndef __MQL4__ @@ -72,7 +73,7 @@ class Draw : public Object { /** * Class constructor. */ - Draw(long _chart_id = 0) : chart_id(_chart_id != 0 ? _chart_id : Platform::ChartID()) {} + Draw(long _chart_id = 0) : chart_id(_chart_id != 0 ? _chart_id : ::ChartID()) {} /* Graphic object related methods */ diff --git a/Market.struct.h b/Market.struct.h index 1283ce193..f7233b5ec 100644 --- a/Market.struct.h +++ b/Market.struct.h @@ -29,6 +29,7 @@ class Serializer; // Includes. +#include "DateTime.entry.h" #include "DateTime.struct.h" #include "Serializer/SerializerNode.enum.h" #include "Std.h" diff --git a/Matrix.mqh b/Matrix.mqh index 5fdbc3e0f..cb030c1fe 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -229,7 +229,7 @@ class MatrixDimension { int position[MATRIX_DIMENSIONS - 1]; // Containers array if type is "Containers" - ARRAY(MatrixDimension, containers); + ARRAY(MatrixDimension*, containers); /** * Constructor. diff --git a/Order.enum.h b/Order.enum.h index c466d638a..d9e9f3a20 100644 --- a/Order.enum.h +++ b/Order.enum.h @@ -246,6 +246,8 @@ enum ENUM_ORDER_TYPE { ORDER_TYPE_CLOSE_BY, // Order to close a position by an opposite one. ORDER_TYPE_UNSET // A NULL value. }; +#else +#define ORDER_TYPE_UNSET NULL #endif /* Positions */ diff --git a/Order.mqh b/Order.mqh index 7ecefc664..fed44822a 100644 --- a/Order.mqh +++ b/Order.mqh @@ -307,7 +307,7 @@ class Order : public SymbolInfo { ENUM_ORDER_CONDITION _cond = oparams.Get(ORDER_PARAM_COND_CLOSE, _ci); ARRAY(DataParamEntry, _cond_args); DataParamEntry _item0 = oparams.Get(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _ci); - ArrayPush(_cond_args, _item0); + ArrayPushObject(_cond_args, _item0); _result |= Order::CheckCondition(_cond, _cond_args); } } @@ -2478,7 +2478,7 @@ class Order : public SymbolInfo { case ORDER_TIME_SETUP: return OrderGetValue(DEAL_TIME, _type, _out); case ORDER_TYPE: - switch (OrderGetValue(DEAL_TYPE, _type, _long)) { + switch ((int)OrderGetValue(DEAL_TYPE, _type, _long)) { case DEAL_TYPE_BUY: return ConvertBasic::LongTo(ORDER_TYPE_BUY); case DEAL_TYPE_SELL: @@ -2512,7 +2512,7 @@ class Order : public SymbolInfo { return NULL_VALUE; default: if ((int)_prop_id == (int)ORDER_REASON) { - switch (OrderGetValue(DEAL_REASON, _type, _long)) { + switch ((int)OrderGetValue(DEAL_REASON, _type, _long)) { case DEAL_REASON_CLIENT: return ConvertBasic::LongTo(ORDER_REASON_CLIENT); case DEAL_REASON_MOBILE: @@ -2576,7 +2576,7 @@ class Order : public SymbolInfo { case ORDER_TIME_SETUP: return OrderGetValue(POSITION_TIME, _type, _out); case ORDER_TYPE: - switch (OrderGetValue(POSITION_TYPE, _type, _long)) { + switch ((int)OrderGetValue(POSITION_TYPE, _type, _long)) { case POSITION_TYPE_BUY: return ConvertBasic::LongTo(ORDER_TYPE_BUY); case POSITION_TYPE_SELL: @@ -2610,7 +2610,7 @@ class Order : public SymbolInfo { return NULL_VALUE; default: if ((int)_prop_id == (int)ORDER_REASON) { - switch (OrderGetValue(POSITION_REASON, _type, _long)) { + switch ((int)OrderGetValue(POSITION_REASON, _type, _long)) { case POSITION_REASON_CLIENT: return ConvertBasic::LongTo(ORDER_REASON_CLIENT); case POSITION_REASON_MOBILE: diff --git a/PlatformTime.h b/PlatformTime.h index 89cb39527..6b54aeffb 100644 --- a/PlatformTime.h +++ b/PlatformTime.h @@ -22,7 +22,6 @@ // Includes. #include "DateTime.enum.h" -#include "DateTime.mqh" /** * @file diff --git a/Task/TaskManager.h b/Task/TaskManager.h index d9a7fc0e7..8fa594a38 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -97,15 +97,19 @@ class TaskManager { void Clear() { Task *task0 = tasks[0].Ptr(); - for (int i = 0; i < tasks.Size(); ++i) { +#ifndef __MQL__ + for (unsigned int i = 0; i < tasks.Size(); ++i) { std::cout << "Task #" << i << ": " << tasks[i].ToString() << std::endl; } +#endif tasks.Clear(); +#ifndef __MQL__ std::cout << "Tasks cleared." << std::endl; std::cout << task0 PTR_DEREF ToString() << std::endl; // std::cout.flush(); +#endif } /* Processing methods */ diff --git a/tests/EATest.mq5 b/tests/EATest.mq5 index 96eb8238f..5f97929b5 100644 --- a/tests/EATest.mq5 +++ b/tests/EATest.mq5 @@ -28,6 +28,7 @@ struct DataParamEntry; // Includes. +#include "../Account/Account.struct.h" #include "../EA.mqh" #include "../Test.mqh" diff --git a/tests/OrderTest.mq5 b/tests/OrderTest.mq5 index 343adc249..7a0fc2dae 100644 --- a/tests/OrderTest.mq5 +++ b/tests/OrderTest.mq5 @@ -113,7 +113,7 @@ bool OpenOrder(int _index, int _order_no) { OrderParams _oparams; if (_request.type == ORDER_TYPE_SELL) { ARRAY(DataParamEntry, _cond_args); - DataParamEntry _param1 = ORDER_TYPE_TIME; + DataParamEntry _param1 = (int)ORDER_TYPE_TIME; DataParamEntry _param2 = PeriodSeconds() * (MAX_ORDERS + _index); ArrayPushObject(_cond_args, _param1); ArrayPushObject(_cond_args, _param2); diff --git a/tests/RefsTest.mq5 b/tests/RefsTest.mq5 index c3a38c88b..8f0b0cf9e 100644 --- a/tests/RefsTest.mq5 +++ b/tests/RefsTest.mq5 @@ -39,6 +39,7 @@ class DynamicClass : public Dynamic { int number; DynamicClass(int _number, DynamicClass* _parent = NULL) : number(_number), parent(_parent) {} + DynamicClass(const DynamicClass& r) { THIS_REF = r; } }; /** @@ -57,7 +58,6 @@ class BadDynamicClass : public Dynamic { */ int OnInit() { // Weak references only. - WeakRef dyn1 = new DynamicClass(1); assertTrueOrFail(dyn1.ObjectExists(), "Object should exist"); @@ -137,25 +137,26 @@ int OnInit() { // Dictionary of weak references. DictStruct> refs2; + /* - Ref dyn9_1 = new DynamicClass(1); - Ref dyn9_2 = new DynamicClass(2); - Ref dyn9_3 = new DynamicClass(3); - - WeakRef dyn9_1_weak_ref = dyn9_1; - WeakRef dyn9_2_weak_ref = dyn9_2; - WeakRef dyn9_3_weak_ref = dyn9_3; + Ref dyn9_1 = new DynamicClass(1); + Ref dyn9_2 = new DynamicClass(2); + Ref dyn9_3 = new DynamicClass(3); - refs2.Set("1", dyn9_1_weak_ref); - refs2.Set("2", dyn9_2_weak_ref); - refs2.Set("3", dyn9_3_weak_ref); + WeakRef dyn9_1_weak_ref = dyn9_1; + WeakRef dyn9_2_weak_ref = dyn9_2; + WeakRef dyn9_3_weak_ref = dyn9_3; - // Should make refs2["2"] to have no existing object. - dyn9_2 = NULL; + refs2.Set("1", dyn9_1_weak_ref); + refs2.Set("2", dyn9_2_weak_ref); + refs2.Set("3", dyn9_3_weak_ref); - assertTrueOrFail(refs2.GetByKey("1").ObjectExists(), "Object should exists"); - assertTrueOrFail(!refs2.GetByKey("2").ObjectExists(), "Object should not exists as it has no more strong references"); - assertTrueOrFail(refs2.GetByKey("3").ObjectExists(), "Object should exists"); + // Should make refs2["2"] to have no existing object. + dyn9_2 = NULL; + assertTrueOrFail(refs2.GetByKey("1").ObjectExists(), "Object should exists"); + assertTrueOrFail(!refs2.GetByKey("2").ObjectExists(), "Object should not exists as it has no more strong + references"); assertTrueOrFail(refs2.GetByKey("3").ObjectExists(), "Object should exists"); + */ return INIT_SUCCEEDED; } diff --git a/tests/TerminalTest.mq5 b/tests/TerminalTest.mq5 index 3c9fe2441..6373e7413 100644 --- a/tests/TerminalTest.mq5 +++ b/tests/TerminalTest.mq5 @@ -37,7 +37,7 @@ Terminal *terminal; */ int OnInit() { terminal = new Terminal(); - Print("TERMINAL (OnInit):\n\t\t\t", terminal.ToString("\n\t\t\t")); + Print("TERMINAL (OnInit):\n\t\t\t", terminal.ToString()); assertTrueOrFail(terminal.IsDllsAllowed(), "DLLs not allowed!"); assertTrueOrFail(terminal.IsExpertEnabled(), "Expert Advisors not allowed!"); assertTrueOrFail(terminal.IsLibrariesAllowed(), "Libraries not allowed!"); @@ -73,6 +73,6 @@ int OnInit() { * Implements OnDeinit(). */ void OnDeinit(const int reason) { - Print("TERMINAL (OnDeinit):\n\t\t\t", terminal.ToString("\n\t\t\t")); + Print("TERMINAL (OnDeinit):\n\t\t\t", terminal.ToString()); Object::Delete(terminal); } From 17cd38a13f3c5500cadff3ea86a6e1904eb2972f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 2 Feb 2023 16:16:16 +0100 Subject: [PATCH 058/123] Fixed C++ and MQL5 errors for tests in /tests folder. --- 3D/Chart3DCandles.h | 1 + 3D/Mesh.h | 5 +++++ 3D/Vertex.h | 17 ++++++++++++----- Account/Account.struct.h | 15 +++++++++++++++ BufferFXT.mqh | 14 ++++++++++++++ BufferStruct.mqh | 2 +- Chart.struct.h | 1 + Database.mqh | 1 + DateTime.entry.h | 1 + Indicators/Indi_RSI.mqh | 5 +++++ Strategy.mqh | 9 +++++---- Strategy.struct.h | 9 +++++++++ tests/DatabaseTest.mq5 | 14 +++++++------- 13 files changed, 77 insertions(+), 17 deletions(-) diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index 9f1cc40b9..ea421b0e5 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -25,6 +25,7 @@ * 3D chart candles renderer. */ +#include "../Chart.define.h" #include "Chart3DType.h" #include "Cube.h" #include "Device.h" diff --git a/3D/Mesh.h b/3D/Mesh.h index 0ee82c0dc..719b33aff 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -45,8 +45,13 @@ struct PointEntry { T point; long key; + // Default constructor. PointEntry() {} + // Copy constructor. + PointEntry(const PointEntry& r) : point(r.point), key(r.key) {} + + // Constructor. PointEntry(const T& _point) { point = _point; key = MakeKey(_point.Position.x, _point.Position.y, _point.Position.z); diff --git a/3D/Vertex.h b/3D/Vertex.h index 8466fa312..f9b84851e 100644 --- a/3D/Vertex.h +++ b/3D/Vertex.h @@ -8,11 +8,18 @@ struct Vertex { DXVector3 Normal; DXColor Color; - Vertex() { - Color.r = 1.0f; - Color.g = 1.0f; - Color.b = 1.0f; - Color.a = 1.0f; + // Default constructor. + Vertex(float r = 1, float g = 1, float b = 1, float a = 1) { + Color.r = r; + Color.g = g; + Color.b = b; + Color.a = a; + } + + Vertex(const Vertex &r) { + Position = r.Position; + Normal = r.Normal; + Color = r.Color; } static const ShaderVertexLayout Layout[3]; diff --git a/Account/Account.struct.h b/Account/Account.struct.h index efae51d51..4d90c2a94 100644 --- a/Account/Account.struct.h +++ b/Account/Account.struct.h @@ -48,6 +48,21 @@ struct AccountEntry { double margin_used; double margin_free; double margin_avail; + + // Default constructor. + AccountEntry() {} + + // Constructor. + AccountEntry(const AccountEntry& r) + : dtime(r.dtime), + balance(r.balance), + credit(r.credit), + equity(r.equity), + profit(r.profit), + margin_used(r.margin_used), + margin_free(r.margin_free), + margin_avail(r.margin_avail) {} + // Serializers. void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} SerializerNodeType Serialize(Serializer& _s) { diff --git a/BufferFXT.mqh b/BufferFXT.mqh index 61a372f85..a60dc0c02 100644 --- a/BufferFXT.mqh +++ b/BufferFXT.mqh @@ -73,6 +73,20 @@ struct BufferFXTEntry { int flag; // Flag to launch an expert (0 - bar will be modified, but the expert will not be launched). public: + // Default constructor + BufferFXTEntry() {} + + // Copy constructor + BufferFXTEntry(const BufferFXTEntry &r) + : otm(r.otm), + open(r.open), + high(r.high), + low(r.low), + close(r.close), + volume(r.volume), + ctm(r.ctm), + flag(r.flag) {} + bool operator==(const BufferFXTEntry &_s) { // @fixme return false; diff --git a/BufferStruct.mqh b/BufferStruct.mqh index 216a9f15a..a43c06074 100644 --- a/BufferStruct.mqh +++ b/BufferStruct.mqh @@ -64,7 +64,7 @@ class BufferStruct : public DictStruct { * Constructor. */ BufferStruct() : min(INT_MAX), max(INT_MIN) { THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } - BufferStruct(BufferStruct& _right) : min(INT_MAX), max(INT_MIN) { + BufferStruct(const BufferStruct& _right) : min(INT_MAX), max(INT_MIN) { this = _right; THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } diff --git a/Chart.struct.h b/Chart.struct.h index a4100f935..e0c04a219 100644 --- a/Chart.struct.h +++ b/Chart.struct.h @@ -51,6 +51,7 @@ struct ChartEntry { // Constructors. ChartEntry() {} ChartEntry(const BarEntry& _bar) { SetBar(_bar); } + ChartEntry(const ChartEntry& _r) { SetBar(_r.bar); } // Getters. BarEntry GetBar() { return bar; } string ToCSV() { return StringFormat("%s", bar.ToCSV()); } diff --git a/Database.mqh b/Database.mqh index 2a4bcc82b..80571651c 100644 --- a/Database.mqh +++ b/Database.mqh @@ -109,6 +109,7 @@ struct DbSymbolInfoEntry : public SymbolInfoEntry { DatabaseTableSchema schema; // Constructors. DbSymbolInfoEntry() { DefineSchema(); } + DbSymbolInfoEntry(const DbSymbolInfoEntry &r) { schema = r.schema; } DbSymbolInfoEntry(const MqlTick &_tick, const string _symbol = NULL) : SymbolInfoEntry(_tick, _symbol) { DefineSchema(); } diff --git a/DateTime.entry.h b/DateTime.entry.h index c99d8d27f..539ec5a45 100644 --- a/DateTime.entry.h +++ b/DateTime.entry.h @@ -33,6 +33,7 @@ // Includes. #include "DateTime.static.h" #include "PlatformTime.h" +#include "Std.h" struct DateTimeEntry : MqlDateTime { int week_of_year; diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 3b401778e..5aacd6181 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -79,6 +79,11 @@ struct IndiRSIParams : IndicatorParams { struct RSIGainLossData { double avg_gain; double avg_loss; + // Default constructor. + RSIGainLossData() {} + + // Copy constructor. + RSIGainLossData(const RSIGainLossData &r) : avg_gain(r.avg_gain), avg_loss(r.avg_loss) {} }; /** diff --git a/Strategy.mqh b/Strategy.mqh index d52f5168a..961808aa7 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -259,7 +259,7 @@ class Strategy : public Taskable { * Gets strategy entry. */ StgEntry GetEntry() { - StgEntry _entry = {}; + StgEntry _entry; for (ENUM_STRATEGY_STATS_PERIOD _p = EA_STATS_DAILY; _p < FINAL_ENUM_STRATEGY_STATS_PERIOD; _p++) { _entry.SetStats(stats_period[(int)_p], _p); } @@ -988,9 +988,10 @@ class Strategy : public Taskable { if (METHOD(_method, 1)) _result |= _result || !IsTrend(_cmd); // 2 if (METHOD(_method, 2)) _result |= _result || !trade REF_DEREF IsPivot(_cmd); // 4 if (METHOD(_method, 3)) - _result |= _result || Open[_shift] > High[_shift + 1] || Open[_shift] < Low[_shift + 1]; // 8 - if (METHOD(_method, 4)) _result |= _result || trade REF_DEREF IsPeak(_cmd); // 16 - if (METHOD(_method, 5)) _result |= _result || trade REF_DEREF HasOrderBetter(_cmd); // 32 + _result |= _result || iOpen(Symbol(), PERIOD_CURRENT, _shift) > iHigh(Symbol(), PERIOD_CURRENT, _shift + 1) || + iOpen(Symbol(), PERIOD_CURRENT, _shift) < iLow(Symbol(), PERIOD_CURRENT, _shift + 1); // 8 + if (METHOD(_method, 4)) _result |= _result || trade REF_DEREF IsPeak(_cmd); // 16 + if (METHOD(_method, 5)) _result |= _result || trade REF_DEREF HasOrderBetter(_cmd); // 32 /* if (METHOD(_method, 6)) _result |= diff --git a/Strategy.struct.h b/Strategy.struct.h index 5c4eef27f..19dce3bcd 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -436,6 +436,15 @@ struct StgStatsPeriod { struct StgEntry { unsigned short signals; StgStatsPeriod stats_period[FINAL_ENUM_STRATEGY_STATS_PERIOD]; + // Default constructor. + StgEntry() {} + + // Copy constructor. + StgEntry(const StgEntry &r) : signals(r.signals) { + for (int i = 0; i < FINAL_ENUM_STRATEGY_STATS_PERIOD; ++i) { + stats_period[i] = r.stats_period[i]; + } + } string ToCSV() { return StringFormat("%s,%s,%s,%s", stats_period[(int)EA_STATS_DAILY].ToCSV(), stats_period[(int)EA_STATS_WEEKLY].ToCSV(), stats_period[(int)EA_STATS_MONTHLY].ToCSV(), diff --git a/tests/DatabaseTest.mq5 b/tests/DatabaseTest.mq5 index c37b969c9..2cbc81ddf 100644 --- a/tests/DatabaseTest.mq5 +++ b/tests/DatabaseTest.mq5 @@ -45,13 +45,13 @@ int OnInit() { db = new Database(":memory:", DATABASE_OPEN_MEMORY); // Create Table1 table. - DatabaseTableColumnEntry columns[] = { - {"SYMBOL", TYPE_CHAR, DATABASE_COLUMN_FLAG_NONE, 6}, - {"BID", TYPE_DOUBLE}, - {"ASK", TYPE_DOUBLE}, - {"VOLUME", TYPE_INT, DATABASE_COLUMN_FLAG_IS_NULL}, - {"COMMENT", TYPE_STRING, DATABASE_COLUMN_FLAG_IS_NULL}, - }; + ARRAY(DatabaseTableColumnEntry, columns); + ArrayPushObject(columns, DatabaseTableColumnEntry("SYMBOL", TYPE_CHAR, DATABASE_COLUMN_FLAG_NONE, 6)); + ArrayPushObject(columns, DatabaseTableColumnEntry("BID", TYPE_DOUBLE)); + ArrayPushObject(columns, DatabaseTableColumnEntry("ASK", TYPE_DOUBLE)); + ArrayPushObject(columns, DatabaseTableColumnEntry("VOLUME", TYPE_INT, DATABASE_COLUMN_FLAG_IS_NULL)); + ArrayPushObject(columns, DatabaseTableColumnEntry("COMMENT", TYPE_STRING, DATABASE_COLUMN_FLAG_IS_NULL)); + DatabaseTableSchema schema = columns; assertTrueOrFail(db.CreateTable("Table1", schema), "Cannot create table! Error: " + (string)_LastError); DatabasePrint(db.GetHandle(), "PRAGMA TABLE_INFO(Table1);", 0); From a30a47652bc735652e9e74342c865ec84cdb1375 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 7 Feb 2023 17:51:32 +0100 Subject: [PATCH 059/123] WIP. Trying to make tests to run on MT4. --- Chart.struct.tf.h | 2 +- Indicator/Indicator.h | 6 +- Indicator/IndicatorData.h | 8 +- Indicator/tests/classes/Indicators.h | 19 +- Indicators/Indi_Demo.mqh | 2 +- Indicators/Indi_Momentum.mqh | 6 +- Indicators/Indi_PriceFeeder.mqh | 2 +- Refs.struct.h | 6 +- Storage/ValueStorage.indicator.h | 5 - SummaryReport.mqh | 507 ++++++++++++++------------- tests/IndicatorsTest.mq5 | 206 +++++------ 11 files changed, 390 insertions(+), 379 deletions(-) diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index c9644babf..f392ef0d5 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -195,7 +195,7 @@ struct ChartTf { static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { switch (_tf) { case PERIOD_CURRENT: - return TfToSeconds(Period()); + return PeriodSeconds(_tf); case PERIOD_M1: // 1 minute. return 60; case PERIOD_M2: // 2 minutes (non-standard). diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 8d625a583..8dc615bd7 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -207,9 +207,9 @@ class Indicator : public IndicatorData { * Sets whether indicator's buffers should be drawn on the chart. */ void SetDraw(bool _value, color _color = clrAquamarine, int _window = 0) { - draw.SetEnabled(_value); - draw.SetColorLine(_color); - draw.SetWindow(_window); + // draw.SetEnabled(_value); + // draw.SetColorLine(_color); + // draw.SetWindow(_window); } /* Converters */ diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 0707e4fe8..a08cdeae4 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -44,6 +44,7 @@ struct ExternInstantiateIndicatorBufferValueStorageDouble { #include "../Flags.h" #include "../Storage/IValueStorage.h" #include "../Storage/ItemsHistory.h" +#include "../Storage/ValueStorage.indicator.h" #include "../SymbolInfo.struct.h" #include "Indicator.enum.h" #include "IndicatorBase.h" @@ -72,7 +73,7 @@ class IndicatorData : public IndicatorBase { ARRAY(WeakRef, listeners); // List of indicators that listens for events from this one. BufferStruct idata; DictStruct> indicators; // Indicators list keyed by id. - DrawIndicator* draw; + // DrawIndicator* draw; IndicatorCalculateCache cache; IndicatorDataParams idparams; // Indicator data params. IndicatorState istate; @@ -1939,4 +1940,9 @@ int CopyBuffer(IndicatorData* _indi, int _mode, int _start, int _count, ValueSto return _num_copied; } +IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble( + IndicatorData* _indi, int _mode) { + return new IndicatorBufferValueStorage(_indi, _mode); +} + #endif // INDICATOR_DATA_H diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h index d71902dd5..aac05a9ee 100644 --- a/Indicator/tests/classes/Indicators.h +++ b/Indicator/tests/classes/Indicators.h @@ -37,24 +37,27 @@ * Helper class to store all indicators and call OnTick() on them. */ class Indicators { - Ref _indis[]; + DictStruct> _indis; public: void Add(IndicatorBase* _indi) { Ref _ref = _indi; - ArrayPushObject(_indis, _ref); + _indis.Push(_ref); } - void Remove(IndicatorData* _indi) { - Ref _ref = _indi; - Util::ArrayRemoveFirst(_indis, _ref); - } + void Add(Ref& _indi) { Add(_indi.Ptr()); } + + IndicatorData* Get(int index) { return _indis[index].Ptr(); } + + IndicatorData* operator[](int index) { return Get(index); } + + int Size() { return _indis.Size(); } /** * Executes OnTick() on every added indicator. */ void Tick(int _global_tick_index) { - for (int i = 0; i < ArraySize(_indis); ++i) { + for (unsigned int i = 0; i < _indis.Size(); ++i) { _indis[i].Ptr().OnTick(_global_tick_index); } } @@ -64,7 +67,7 @@ class Indicators { */ string ToString(int _shift = 0) { string _result; - for (int i = 0; i < ArraySize(_indis); ++i) { + for (unsigned int i = 0; i < _indis.Size(); ++i) { IndicatorDataEntry _entry = _indis[i].Ptr().GetEntry(_shift); _result += _indis[i].Ptr().GetFullName() + " = " + _entry.ToString() + "\n"; } diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index 07afa9a28..ca34c5186 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -82,7 +82,7 @@ class Indi_Demo : public Indicator { virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = Indi_Demo::iDemo(THIS_PTR, ToRelShift(_abs_shift)); if (idparams.IsDrawing()) { - draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(ToRelShift(_abs_shift)), _value); + // draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(ToRelShift(_abs_shift)), _value); } return _value; } diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 679f96c45..159f38f41 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -151,7 +151,8 @@ class Indi_Momentum : public Indicator { _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), iparams.shift + ToRelShift(_abs_shift)); if (idparams.IsDrawing()) { - draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); + // draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, + // 1); } break; case IDATA_ICUSTOM: @@ -165,7 +166,8 @@ class Indi_Momentum : public Indicator { _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), iparams.shift + ToRelShift(_abs_shift)); if (idparams.IsDrawing()) { - draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); + // draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, + // 1); } break; } diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index 4b93f08ea..be3fbd9d4 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -107,7 +107,7 @@ class Indi_PriceFeeder : public Indicator { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); IndicatorDataEntry _entry = GetEntry(0); for (int i = 0; i < _max_modes; ++i) { - draw.DrawLineTo(GetName() + "_" + IntegerToString(i), GetBarTime(0), _entry.values[i].GetDbl()); + // draw.DrawLineTo(GetName() + "_" + IntegerToString(i), GetBarTime(0), _entry.values[i].GetDbl()); } } } diff --git a/Refs.struct.h b/Refs.struct.h index 210f58f11..3de03deba 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -277,9 +277,9 @@ struct Ref { } }; -template -Ref MakeRef(X* _ptr) { - return Ref(_ptr); +template +Ref MakeRef(T* _ptr) { + return Ref(_ptr); } /** diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 254767c7c..58d4db243 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -57,8 +57,3 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { */ C Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_rel_shift)); } }; - -IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble( - IndicatorData* _indi, int _mode) { - return new IndicatorBufferValueStorage(_indi, _mode); -} diff --git a/SummaryReport.mqh b/SummaryReport.mqh index 964a52b98..11ef0fb46 100644 --- a/SummaryReport.mqh +++ b/SummaryReport.mqh @@ -22,6 +22,7 @@ #include "Account/AccountMt.h" #include "Convert.mqh" +#include "Indicator/IndicatorData.h" #include "Order.struct.h" #include "Terminal.mqh" #include "Trade.mqh" @@ -30,291 +31,291 @@ * Class to provide a summary report. */ class SummaryReport { - protected: - // Variables. - double init_deposit; - double summary_profit; - double gross_profit; - double gross_loss; - double max_profit; - double min_profit; - double con_profit1; - double con_profit2; - double con_loss1; - double con_loss2; - double max_loss; - double max_dd; - double max_dd_pct; - double rel_dd_pct; - double rel_dd; - double expected_payoff; - double profit_factor; - double abs_dd; - int summary_trades; - int profit_trades; - int loss_trades; - int short_trades; - int long_trades; - int win_short_trades; - int win_long_trades; - int con_profit_trades1; - int con_profit_trades2; - int con_loss_trades1; - int con_loss_trades2; - int avg_con_wins; - int avg_con_losses; + protected: + // Variables. + double init_deposit; + double summary_profit; + double gross_profit; + double gross_loss; + double max_profit; + double min_profit; + double con_profit1; + double con_profit2; + double con_loss1; + double con_loss2; + double max_loss; + double max_dd; + double max_dd_pct; + double rel_dd_pct; + double rel_dd; + double expected_payoff; + double profit_factor; + double abs_dd; + int summary_trades; + int profit_trades; + int loss_trades; + int short_trades; + int long_trades; + int win_short_trades; + int win_long_trades; + int con_profit_trades1; + int con_profit_trades2; + int con_loss_trades1; + int con_loss_trades2; + int avg_con_wins; + int avg_con_losses; - double init_balance; + double init_balance; - public: - /** - * Default constructor. - */ + public: + /** + * Default constructor. + */ SummaryReport() { InitVars(AccountMt::AccountBalance()); } - /** - * Constructor to initialize starting balance. - */ + /** + * Constructor to initialize starting balance. + */ SummaryReport(double deposit) { InitVars(deposit); } - /** - * Constructor to initialize starting balance. - */ - void InitVars(double deposit = 0) { - init_deposit = deposit; - max_loss = deposit; - summary_profit = 0.0; - gross_profit = 0.0; - gross_loss = 0.0; - max_profit = 0.0; - min_profit = 0.0; - con_profit1 = 0.0; - con_profit2 = 0.0; - con_loss1 = 0.0; - con_loss2 = 0.0; - max_dd = 0.0; - max_dd_pct = 0.0; - rel_dd_pct = 0.0; - rel_dd = 0.0; - expected_payoff = 0.0; - profit_factor = 0.0; - abs_dd = 0.0; - summary_trades = 0; - profit_trades = 0; - loss_trades = 0; - short_trades = 0; - long_trades = 0; - win_short_trades = 0; - win_long_trades = 0; - con_profit_trades1 = 0; - con_profit_trades2 = 0; - con_loss_trades1 = 0; - con_loss_trades2 = 0; - avg_con_wins = 0; - avg_con_losses = 0; - } + /** + * Constructor to initialize starting balance. + */ + void InitVars(double deposit = 0) { + init_deposit = deposit; + max_loss = deposit; + summary_profit = 0.0; + gross_profit = 0.0; + gross_loss = 0.0; + max_profit = 0.0; + min_profit = 0.0; + con_profit1 = 0.0; + con_profit2 = 0.0; + con_loss1 = 0.0; + con_loss2 = 0.0; + max_dd = 0.0; + max_dd_pct = 0.0; + rel_dd_pct = 0.0; + rel_dd = 0.0; + expected_payoff = 0.0; + profit_factor = 0.0; + abs_dd = 0.0; + summary_trades = 0; + profit_trades = 0; + loss_trades = 0; + short_trades = 0; + long_trades = 0; + win_short_trades = 0; + win_long_trades = 0; + con_profit_trades1 = 0; + con_profit_trades2 = 0; + con_loss_trades1 = 0; + con_loss_trades2 = 0; + avg_con_wins = 0; + avg_con_losses = 0; + } - /** - * Get initial deposit. - */ - double GetInitDeposit() { - static double deposit = 0; - if (deposit > 0) { - return deposit; + /** + * Get initial deposit. + */ + double GetInitDeposit() { + static double deposit = 0; + if (deposit > 0) { + return deposit; } else if (!Terminal::IsRealtime() && init_deposit > 0) { - deposit = init_deposit; - } else { - deposit = AccountMt::CalcInitDeposit(); - } - return (deposit); + deposit = init_deposit; + } else { + deposit = AccountMt::CalcInitDeposit(); } + return (deposit); + } - /** - * Calculates summary details. - */ - void CalculateSummary() { - int sequence = 0, profitseqs = 0, loss_seqs = 0; - double sequential = 0.0, prev_profit = EMPTY_VALUE, dd_pct, drawdown; - double max_peak = init_deposit, min_peak = init_deposit, balance = init_deposit; - int trades_total = TradeHistoryStatic::HistoryOrdersTotal(); - double profit; + /** + * Calculates summary details. + */ + void CalculateSummary() { + int sequence = 0, profitseqs = 0, loss_seqs = 0; + double sequential = 0.0, prev_profit = EMPTY_VALUE, dd_pct, drawdown; + double max_peak = init_deposit, min_peak = init_deposit, balance = init_deposit; + int trades_total = TradeHistoryStatic::HistoryOrdersTotal(); + double profit; - // Initialize summaries. - InitVars(init_deposit); + // Initialize summaries. + InitVars(init_deposit); - for (int i = 0; i < trades_total; i++) { - if (!Order::TryOrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) { - continue; - } - int type = Order::OrderType(); - // Initial balance not considered. - if (i == 0 && type == ACC_OP_BALANCE) continue; - // Calculate profit. - profit = OrderStatic::Profit() + OrderStatic::Commission() + Order::OrderSwap(); - balance += profit; - // Drawdown check. - if (max_peak < balance) { - drawdown = max_peak-min_peak; - if (max_peak != 0.0) { - dd_pct = drawdown / max_peak * 100.0; - if (rel_dd_pct < dd_pct) { - rel_dd_pct = dd_pct; - rel_dd = drawdown; - } - } - if (max_dd < drawdown) { - max_dd = drawdown; - max_dd_pct = max_peak != 0.0 ? max_dd / max_peak * 100.0 : 100.0; + for (int i = 0; i < trades_total; i++) { + if (!Order::TryOrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) { + continue; + } + int type = Order::OrderType(); + // Initial balance not considered. + if (i == 0 && type == ACC_OP_BALANCE) continue; + // Calculate profit. + profit = OrderStatic::Profit() + OrderStatic::Commission() + Order::OrderSwap(); + balance += profit; + // Drawdown check. + if (max_peak < balance) { + drawdown = max_peak - min_peak; + if (max_peak != 0.0) { + dd_pct = drawdown / max_peak * 100.0; + if (rel_dd_pct < dd_pct) { + rel_dd_pct = dd_pct; + rel_dd = drawdown; } - max_peak = balance; - min_peak = balance; } - if (min_peak > balance) min_peak = balance; - if (max_loss > balance) max_loss = balance; - // Market orders only. - if (type != ORDER_TYPE_BUY && type != ORDER_TYPE_SELL) continue; - // Calculate profit in points. - // profit = (OrderClosePrice() - OrderOpenPrice()) / MarketInfo(OrderSymbol(), MODE_POINT); - summary_profit += profit; - summary_trades++; - if (type == ORDER_TYPE_BUY) { - long_trades++; - } else if (type == ORDER_TYPE_SELL) { - short_trades++; + if (max_dd < drawdown) { + max_dd = drawdown; + max_dd_pct = max_peak != 0.0 ? max_dd / max_peak * 100.0 : 100.0; } - if (profit < 0) { - // Loss trades. - loss_trades++; - gross_loss += profit; - if (min_profit > profit) min_profit = profit; - // Fortune changed. - if (prev_profit != EMPTY_VALUE && prev_profit >= 0) { + max_peak = balance; + min_peak = balance; + } + if (min_peak > balance) min_peak = balance; + if (max_loss > balance) max_loss = balance; + // Market orders only. + if (type != ORDER_TYPE_BUY && type != ORDER_TYPE_SELL) continue; + // Calculate profit in points. + // profit = (OrderClosePrice() - OrderOpenPrice()) / MarketInfo(OrderSymbol(), MODE_POINT); + summary_profit += profit; + summary_trades++; + if (type == ORDER_TYPE_BUY) { + long_trades++; + } else if (type == ORDER_TYPE_SELL) { + short_trades++; + } + if (profit < 0) { + // Loss trades. + loss_trades++; + gross_loss += profit; + if (min_profit > profit) min_profit = profit; + // Fortune changed. + if (prev_profit != EMPTY_VALUE && prev_profit >= 0) { if (con_profit_trades1 < sequence || (con_profit_trades1 == sequence && con_profit2 < sequential)) { - con_profit_trades1 = sequence; - con_profit1 = sequential; - } - if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { - con_profit2 = sequential; - con_profit_trades2 = sequence; - } - profitseqs++; - avg_con_wins += sequence; - sequence = 0; - sequential = 0.0; + con_profit_trades1 = sequence; + con_profit1 = sequential; } - } else { - // Profit trades (profit >= 0). - profit_trades++; - if (type == ORDER_TYPE_BUY) win_long_trades++; - if (type == ORDER_TYPE_SELL) win_short_trades++; - gross_profit += profit; - if (max_profit < profit) max_profit = profit; - // Fortune changed. - if (prev_profit != EMPTY_VALUE && prev_profit < 0) { - if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { - con_loss_trades1 = sequence; - con_loss1 = sequential; - } - if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { - con_loss2 = sequential; - con_loss_trades2 = sequence; - } - loss_seqs++; - avg_con_losses += sequence; - sequence = 0; - sequential = 0.0; + if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { + con_profit2 = sequential; + con_profit_trades2 = sequence; } + profitseqs++; + avg_con_wins += sequence; + sequence = 0; + sequential = 0.0; } - sequence++; - sequential += profit; - prev_profit = profit; - } - // Final drawdown check. - drawdown = max_peak - min_peak; - if (max_peak != 0.0) { - dd_pct = drawdown / max_peak * 100.0; - if (rel_dd_pct < dd_pct) { - rel_dd_pct = dd_pct; - rel_dd = drawdown; - } - } - if (max_dd < drawdown) { - max_dd = drawdown; - max_dd_pct = max_peak != 0 ? max_dd / max_peak * 100.0 : 100.0; - } - // Consider last trade. - if (prev_profit != EMPTY_VALUE) { - profit = prev_profit; - if (profit < 0) { - if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { + } else { + // Profit trades (profit >= 0). + profit_trades++; + if (type == ORDER_TYPE_BUY) win_long_trades++; + if (type == ORDER_TYPE_SELL) win_short_trades++; + gross_profit += profit; + if (max_profit < profit) max_profit = profit; + // Fortune changed. + if (prev_profit != EMPTY_VALUE && prev_profit < 0) { + if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { con_loss_trades1 = sequence; con_loss1 = sequential; } - if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { + if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { con_loss2 = sequential; con_loss_trades2 = sequence; } loss_seqs++; avg_con_losses += sequence; + sequence = 0; + sequential = 0.0; + } + } + sequence++; + sequential += profit; + prev_profit = profit; + } + // Final drawdown check. + drawdown = max_peak - min_peak; + if (max_peak != 0.0) { + dd_pct = drawdown / max_peak * 100.0; + if (rel_dd_pct < dd_pct) { + rel_dd_pct = dd_pct; + rel_dd = drawdown; + } + } + if (max_dd < drawdown) { + max_dd = drawdown; + max_dd_pct = max_peak != 0 ? max_dd / max_peak * 100.0 : 100.0; + } + // Consider last trade. + if (prev_profit != EMPTY_VALUE) { + profit = prev_profit; + if (profit < 0) { + if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { + con_loss_trades1 = sequence; + con_loss1 = sequential; + } + if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { + con_loss2 = sequential; + con_loss_trades2 = sequence; + } + loss_seqs++; + avg_con_losses += sequence; } else { if (con_profit_trades1 < sequence || (con_profit_trades1 == sequence && con_profit2 < sequential)) { - con_profit_trades1 = sequence; - con_profit1 = sequential; - } + con_profit_trades1 = sequence; + con_profit1 = sequential; + } if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { - con_profit2 = sequential; - con_profit_trades2 = sequence; - } - profitseqs++; - avg_con_wins += sequence; + con_profit2 = sequential; + con_profit_trades2 = sequence; } + profitseqs++; + avg_con_wins += sequence; } - // Collecting done. - double dnum, profitkoef = 0.0, losskoef = 0.0, avg_profit = 0.0, avgloss = 0.0; - // Average consecutive wins and losses. - dnum = avg_con_wins; - avg_con_wins = profitseqs > 0 ? (int) (dnum / profitseqs + 0.5) : 0; - dnum = avg_con_losses; - avg_con_losses = loss_seqs > 0 ? (int) (dnum / loss_seqs + 0.5) : 0; - // Absolute values. - if (gross_loss < 0.0) gross_loss *=- 1.0; - if (min_profit < 0.0) min_profit *=- 1.0; - if (con_loss1 < 0.0) con_loss1 *=- 1.0; - if (con_loss2 < 0.0) con_loss2 *=- 1.0; - profit_factor = gross_loss > 0.0 ? gross_profit / gross_loss : 0.0; - // Expected payoff. - avg_profit = profit_trades > 0 ? gross_profit / profit_trades : 0; - avgloss = loss_trades > 0 ? gross_loss / loss_trades : 0; - if (summary_trades > 0) { - profitkoef = 1.0 * profit_trades / summary_trades; - losskoef = 1.0 * loss_trades / summary_trades; - expected_payoff = profitkoef * avg_profit - losskoef * avgloss; - } - // Absolute drawdown. - abs_dd = init_deposit - max_loss; } + // Collecting done. + double dnum, profitkoef = 0.0, losskoef = 0.0, avg_profit = 0.0, avgloss = 0.0; + // Average consecutive wins and losses. + dnum = avg_con_wins; + avg_con_wins = profitseqs > 0 ? (int)(dnum / profitseqs + 0.5) : 0; + dnum = avg_con_losses; + avg_con_losses = loss_seqs > 0 ? (int)(dnum / loss_seqs + 0.5) : 0; + // Absolute values. + if (gross_loss < 0.0) gross_loss *= -1.0; + if (min_profit < 0.0) min_profit *= -1.0; + if (con_loss1 < 0.0) con_loss1 *= -1.0; + if (con_loss2 < 0.0) con_loss2 *= -1.0; + profit_factor = gross_loss > 0.0 ? gross_profit / gross_loss : 0.0; + // Expected payoff. + avg_profit = profit_trades > 0 ? gross_profit / profit_trades : 0; + avgloss = loss_trades > 0 ? gross_loss / loss_trades : 0; + if (summary_trades > 0) { + profitkoef = 1.0 * profit_trades / summary_trades; + losskoef = 1.0 * loss_trades / summary_trades; + expected_payoff = profitkoef * avg_profit - losskoef * avgloss; + } + // Absolute drawdown. + abs_dd = init_deposit - max_loss; + } - /** - * Return summary report. - */ - string GetReport(string sep = "\n", string _currency = "") { - string output = ""; - _currency = _currency != "" ? _currency : AccountInfoString(ACCOUNT_CURRENCY); - output += StringFormat("Currency pair symbol: %s", _Symbol) + sep; - output += StringFormat("Initial deposit: %.2f %s", GetInitDeposit(), _currency) + sep; - output += StringFormat("Total net profit: %.2f %s", summary_profit, _currency) + sep; - output += StringFormat("Gross profit: %.2f %s", gross_profit, _currency) + sep; - output += StringFormat("Gross loss: %.2f %s", gross_loss, _currency) + sep; - output += StringFormat("Absolute drawdown: %.2f %s", abs_dd, _currency) + sep; + /** + * Return summary report. + */ + string GetReport(string sep = "\n", string _currency = "") { + string output = ""; + _currency = _currency != "" ? _currency : AccountInfoString(ACCOUNT_CURRENCY); + output += StringFormat("Currency pair symbol: %s", _Symbol) + sep; + output += StringFormat("Initial deposit: %.2f %s", GetInitDeposit(), _currency) + sep; + output += StringFormat("Total net profit: %.2f %s", summary_profit, _currency) + sep; + output += StringFormat("Gross profit: %.2f %s", gross_profit, _currency) + sep; + output += StringFormat("Gross loss: %.2f %s", gross_loss, _currency) + sep; + output += StringFormat("Absolute drawdown: %.2f %s", abs_dd, _currency) + sep; output += StringFormat("Maximal drawdown: %.1f %s (%.1f%%)", max_dd, _currency, max_dd_pct) + sep; output += StringFormat("Relative drawdown: (%.1f%%) %.1f %s", rel_dd_pct, rel_dd, _currency) + sep; - output += StringFormat("Profit factor: %.2f", profit_factor) + sep; - output += StringFormat("Expected payoff: %.2f", expected_payoff) + sep; - output += StringFormat("Trades total %d", summary_trades) + sep; + output += StringFormat("Profit factor: %.2f", profit_factor) + sep; + output += StringFormat("Expected payoff: %.2f", expected_payoff) + sep; + output += StringFormat("Trades total %d", summary_trades) + sep; output += StringFormat("Short positions (won %%): %d (%.1f%%)", short_trades, short_trades ? 100.0 * win_short_trades / short_trades : 0) + sep; @@ -327,22 +328,22 @@ class SummaryReport { output += StringFormat("Loss trades (%% of total): %d (%.1f%%)", loss_trades, loss_trades ? 100.0 * loss_trades / summary_trades : 0) + sep; - output += StringFormat("Largest profit trade: %.2f", max_profit) + sep; - output += StringFormat("Largest loss trade: %.2f", -min_profit) + sep; + output += StringFormat("Largest profit trade: %.2f", max_profit) + sep; + output += StringFormat("Largest loss trade: %.2f", -min_profit) + sep; output += StringFormat("Average profit trade: %.2f", profit_trades ? gross_profit / profit_trades : 0) + sep; output += StringFormat("Average loss trade: %.2f", loss_trades ? -gross_loss / loss_trades : 0) + sep; - output += StringFormat("Average consecutive wins: %.2f", avg_con_wins) + sep; - output += StringFormat("Average consecutive losses: %.2f", avg_con_losses) + sep; + output += StringFormat("Average consecutive wins: %.2f", avg_con_wins) + sep; + output += StringFormat("Average consecutive losses: %.2f", avg_con_losses) + sep; output += StringFormat("Maximum consecutive wins (profit in money): %d (%.2f)", con_profit_trades1, con_profit1) + sep; - output += StringFormat("Maximum consecutive losses (loss in money): %d (%.2f)", con_loss_trades1, -con_loss1) + sep; + output += StringFormat("Maximum consecutive losses (loss in money): %d (%.2f)", con_loss_trades1, -con_loss1) + sep; output += StringFormat("Maximal consecutive profit (count of wins): %.2f (%d)", con_profit2, con_profit_trades2) + sep; - output += StringFormat("Maximal consecutive loss (count of losses): %.2f (%d)", con_loss2, con_loss_trades2) + sep; - return output; - } + output += StringFormat("Maximal consecutive loss (count of losses): %.2f (%d)", con_loss2, con_loss_trades2) + sep; + return output; + } }; diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index b1fc5c575..b306ed976 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -38,6 +38,7 @@ struct DataParamEntry; #include "../DictObject.mqh" #include "../Indicator/Indicator.h" #include "../Indicator/tests/classes/IndicatorTfDummy.h" +#include "../Indicator/tests/classes/Indicators.h" #include "../Indicators/Bitwise/indicators.h" #include "../Indicators/Tick/Indi_TickMt.mqh" #include "../Indicators/indicators.h" @@ -51,9 +52,9 @@ struct DataParamEntry; enum ENUM_CUSTOM_INDICATORS { INDI_SPECIAL_MATH_CUSTOM = FINAL_INDICATOR_TYPE_ENTRY + 1 }; // Global variables. -DictStruct> indis; -DictStruct> whitelisted_indis; -DictStruct> tested; +Indicators indis; +DictStruct whitelisted_indis; +DictStruct tested; double test_values[] = {1.245, 1.248, 1.254, 1.264, 1.268, 1.261, 1.256, 1.250, 1.242, 1.240, 1.235, 1.240, 1.234, 1.245, 1.265, 1.274, 1.285, 1.295, 1.300, 1.312, 1.315, 1.320, 1.325, 1.335, 1.342, 1.348, 1.352, 1.357, 1.359, 1.422, 1.430, 1.435}; @@ -74,8 +75,8 @@ int OnInit() { Print("Connecting candle and tick indicators to all indicators..."); // Connecting all indicators to default candle indicator (which is connected to default tick indicator). - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - Platform::AddWithDefaultBindings(iter.Value().Ptr(), _Symbol, PERIOD_CURRENT); + for (int i = 0; i < indis.Size(); ++i) { + Platform::AddWithDefaultBindings(indis[i], _Symbol, PERIOD_CURRENT); } // Check for any errors. @@ -106,19 +107,20 @@ void OnTick() { return; } - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + for (int i = 0; i < indis.Size(); ++i) { + IndicatorData* _indi = indis[i]; + if (whitelisted_indis.Size() == 0) { - if (tested.Contains(iter.Value())) { + if (tested.Contains(_indi)) { // Indicator is already tested, skipping. continue; } } else { - if (!whitelisted_indis.Contains(iter.Value())) { + if (!whitelisted_indis.Contains(_indi)) { continue; } } - IndicatorData* _indi = iter.Value().Ptr(); IndicatorDataEntry _entry(_indi PTR_DEREF GetEntry()); // if (_indi.GetType() != INDI_AMA) @@ -128,7 +130,7 @@ void OnTick() { if (_entry.IsValid()) { PrintFormat("%s: bar %d: %s", _indi PTR_DEREF GetFullName(), _candles PTR_DEREF GetBars(), _indi PTR_DEREF ToString()); - tested.Push(iter.Value()); // Mark as tested. + tested.Push(_indi); // Mark as tested. } } } @@ -140,9 +142,11 @@ void OnTick() { */ void OnDeinit(const int reason) { int num_not_tested = 0; - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - if (!tested.Contains(iter.Value())) { - PrintFormat("%s: Indicator not tested: %s", __FUNCTION__, iter.Value().Ptr().GetFullName()); + for (int i = 0; i < indis.Size(); ++i) { + IndicatorData* _indi = indis[i]; + + if (!tested.Contains(_indi)) { + PrintFormat("%s: Indicator not tested: %s", __FUNCTION__, _indi.GetFullName()); ++num_not_tested; } } @@ -159,127 +163,127 @@ bool InitIndicators() { // Price indicator. Ref indi_price = new Indi_Price(PriceIndiParams()); - // indis.Push(indi_price); // @fixme: Make it work with the test? + // indis.Add(indi_price); // @fixme: Make it work with the test? /* Standard indicators */ // AC. - indis.Push(Ref(new Indi_AC())); + indis.Add(new Indi_AC()); // AD. - indis.Push(Ref(new Indi_AD())); + indis.Add(new Indi_AD()); // ADX. IndiADXParams adx_params(14); - indis.Push(Ref(new Indi_ADX(adx_params))); + indis.Add(new Indi_ADX(adx_params)); // Alligator. IndiAlligatorParams alli_params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - indis.Push(Ref(new Indi_Alligator(alli_params))); + indis.Add(new Indi_Alligator(alli_params)); // Awesome Oscillator (AO). - indis.Push(Ref(new Indi_AO())); + indis.Add(new Indi_AO()); // Accumulation Swing Index (ASI). IndiASIParams _asi_params; - indis.Push(Ref(new Indi_ASI(_asi_params))); + indis.Add(new Indi_ASI(_asi_params)); // Average True Range (ATR). IndiATRParams atr_params(14); - indis.Push(Ref(new Indi_ATR(atr_params))); + indis.Add(new Indi_ATR(atr_params)); // Bollinger Bands - Built-in. IndiBandsParams bands_params(20, 2, 0, PRICE_OPEN); Ref indi_bands = new Indi_Bands(bands_params); - indis.Push(indi_bands); - // whitelisted_indis.Push(indi_bands); + indis.Add(indi_bands); + // whitelisted_indis.Add(indi_bands); // Bollinger Bands - OnCalculate. Ref indi_bands_oncalculate = new Indi_Bands(bands_params, IDATA_ONCALCULATE); - indis.Push(indi_bands_oncalculate); - // whitelisted_indis.Push(indi_bands_oncalculate); + indis.Add(indi_bands_oncalculate); + // whitelisted_indis.Add(indi_bands_oncalculate); // Bears Power. IndiBearsPowerParams bears_params(13, PRICE_CLOSE); - indis.Push(Ref(new Indi_BearsPower(bears_params))); + indis.Add(new Indi_BearsPower(bears_params)); // Bulls Power. IndiBullsPowerParams bulls_params(13, PRICE_CLOSE); - indis.Push(Ref(new Indi_BullsPower(bulls_params))); + indis.Add(new Indi_BullsPower(bulls_params)); // Market Facilitation Index (BWMFI). IndiBWIndiMFIParams _bwmfi_params(1); - indis.Push(Ref(new Indi_BWMFI(_bwmfi_params))); + indis.Add(new Indi_BWMFI(_bwmfi_params)); // Commodity Channel Index (CCI). IndiCCIParams cci_params(14, PRICE_OPEN); - indis.Push(Ref(new Indi_CCI(cci_params))); + indis.Add(new Indi_CCI(cci_params)); // DeMarker. IndiDeMarkerParams dm_params(14); - indis.Push(Ref(new Indi_DeMarker(dm_params))); + indis.Add(new Indi_DeMarker(dm_params)); // Envelopes. IndiEnvelopesParams env_params(13, 0, MODE_SMA, PRICE_OPEN, 2); - indis.Push(Ref(new Indi_Envelopes(env_params))); + indis.Add(new Indi_Envelopes(env_params)); // Force Index. IndiForceParams force_params(13, MODE_SMA, PRICE_CLOSE); - indis.Push(Ref(new Indi_Force(force_params))); + indis.Add(new Indi_Force(force_params)); // Fractals. - indis.Push(Ref(new Indi_Fractals())); + indis.Add(new Indi_Fractals()); // Fractal Adaptive Moving Average (FRAMA). IndiFrAIndiMAParams frama_params(); - indis.Push(Ref(new Indi_FrAMA(frama_params))); + indis.Add(new Indi_FrAMA(frama_params)); // Gator Oscillator. IndiGatorParams gator_params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - indis.Push(Ref(new Indi_Gator(gator_params))); + indis.Add(new Indi_Gator(gator_params)); // Heiken Ashi. IndiHeikenAshiParams _ha_params(); - indis.Push(Ref(new Indi_HeikenAshi(_ha_params))); + indis.Add(new Indi_HeikenAshi(_ha_params)); // Ichimoku Kinko Hyo. IndiIchimokuParams ichi_params(9, 26, 52); - indis.Push(Ref(new Indi_Ichimoku(ichi_params))); + indis.Add(new Indi_Ichimoku(ichi_params)); // Moving Average. IndiMAParams ma_params(13, 0, MODE_SMA, PRICE_OPEN); Ref indi_ma = new Indi_MA(ma_params); - indis.Push(indi_ma); + indis.Add(indi_ma); // DEMA. IndiDEMAParams dema_params(13, 2, PRICE_OPEN); Ref indi_dema = new Indi_DEMA(dema_params, INDI_DEMA_DEFAULT_IDSTYPE, indi_price.Ptr()); - // indis.Push(indi_dema); // @fixme + // indis.Add(indi_dema); // @fixme // MACD. IndiMACDParams macd_params(12, 26, 9, PRICE_CLOSE); Ref macd = new Indi_MACD(macd_params); - indis.Push(macd); + indis.Add(macd); // Money Flow Index (MFI). IndiMFIParams mfi_params(14); - indis.Push(Ref(new Indi_MFI(mfi_params))); + indis.Add(new Indi_MFI(mfi_params)); // Momentum (MOM). IndiMomentumParams mom_params(); - indis.Push(Ref(new Indi_Momentum(mom_params))); + indis.Add(new Indi_Momentum(mom_params)); // On Balance Volume (OBV). - indis.Push(Ref(new Indi_OBV())); + indis.Add(new Indi_OBV()); // OsMA. IndiOsMAParams osma_params(12, 26, 9, PRICE_CLOSE); - indis.Push(Ref(new Indi_OsMA(osma_params))); + indis.Add(new Indi_OsMA(osma_params)); // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); Ref indi_rsi = new Indi_RSI(rsi_params); - indis.Push(Ref(indi_rsi.Ptr())); + indis.Add(indi_rsi.Ptr()); // Bollinger Bands over RSI. IndiBandsParams indi_bands_over_rsi_params(20, 2, 0, PRICE_OPEN); @@ -287,26 +291,26 @@ bool InitIndicators() { // Using RSI's mode 0 as applied price. indi_bands_over_rsi REF_DEREF SetDataSourceAppliedPrice(INDI_VS_TYPE_INDEX_0); indi_bands_over_rsi REF_DEREF SetDataSource(indi_rsi.Ptr()); - indis.Push(indi_bands_over_rsi); + indis.Add(indi_bands_over_rsi); // Standard Deviation (StdDev). IndiStdDevParams stddev_params(13, 10, MODE_SMA, PRICE_OPEN); Ref indi_stddev = new Indi_StdDev(stddev_params); - indis.Push(indi_stddev); + indis.Add(indi_stddev); // Relative Strength Index (RSI) over Standard Deviation (StdDev). IndiRSIParams indi_rsi_over_stddev_params(); Ref indi_rsi_over_stddev = new Indi_RSI(indi_rsi_over_stddev_params); indi_rsi_over_stddev.Ptr().SetDataSource(indi_stddev.Ptr()); - indis.Push(indi_rsi_over_stddev); + indis.Add(indi_rsi_over_stddev); // Relative Vigor Index (RVI). IndiRVIParams rvi_params(14); - indis.Push(Ref(new Indi_RVI(rvi_params))); + indis.Add(new Indi_RVI(rvi_params)); // Parabolic SAR. IndiSARParams sar_params(0.02, 0.2); - indis.Push(Ref(new Indi_SAR(sar_params))); + indis.Add(new Indi_SAR(sar_params)); // Standard Deviation (StdDev). Ref indi_price_for_stdev = new Indi_Price(PriceIndiParams()); @@ -314,24 +318,24 @@ bool InitIndicators() { // stddev_on_price_params.SetDraw(clrBlue, 1); // @fixme Ref indi_stddev_on_price = new Indi_StdDev(stddev_on_price_params, IDATA_BUILTIN, indi_price_for_stdev.Ptr()); - indis.Push(Ref(indi_stddev_on_price.Ptr())); + indis.Add(indi_stddev_on_price.Ptr()); // Stochastic Oscillator. IndiStochParams stoch_params(5, 3, 3, MODE_SMMA, STO_LOWHIGH); - indis.Push(Ref(new Indi_Stochastic(stoch_params))); + indis.Add(new Indi_Stochastic(stoch_params)); // Williams' Percent Range (WPR). IndiWPRParams wpr_params(14); - indis.Push(Ref(new Indi_WPR(wpr_params))); + indis.Add(new Indi_WPR(wpr_params)); // ZigZag. IndiZigZagParams zz_params(12, 5, 3); - indis.Push(Ref(new Indi_ZigZag(zz_params))); + indis.Add(new Indi_ZigZag(zz_params)); /* Special indicators */ // Demo/Dummy Indicator. - indis.Push(Ref(new Indi_Demo())); + indis.Add(new Indi_Demo()); // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); @@ -339,7 +343,7 @@ bool InitIndicators() { IndiBandsParams bands_on_price_params(); // bands_on_price_params.SetDraw(clrCadetBlue); // @fixme Ref indi_bands_on_price = new Indi_Bands(bands_on_price_params, IDATA_BUILTIN, indi_price_4_bands.Ptr()); - indis.Push(Ref(indi_bands_on_price.Ptr())); + indis.Add(indi_bands_on_price.Ptr()); // Standard Deviation (StdDev) over MA(SMA). // NOTE: If you set ma_shift parameter for MA, then StdDev will no longer @@ -352,7 +356,7 @@ bool InitIndicators() { Ref indi_stddev_on_ma_sma = new Indi_StdDev(stddev_params_on_ma_sma, IDATA_BUILTIN, indi_ma_sma_for_stddev.Ptr()); - indis.Push(Ref(indi_stddev_on_ma_sma.Ptr())); + indis.Add(indi_stddev_on_ma_sma.Ptr()); // Standard Deviation (StdDev) in SMA mode over Price. PriceIndiParams price_params_for_stddev_sma(); @@ -361,7 +365,7 @@ bool InitIndicators() { // stddev_sma_on_price_params.SetDraw(true, 1); // @fixme Ref indi_stddev_on_sma = new Indi_StdDev(stddev_sma_on_price_params, IDATA_BUILTIN, indi_price_for_stddev_sma.Ptr()); - indis.Push(Ref(indi_stddev_on_sma.Ptr())); + indis.Add(indi_stddev_on_sma.Ptr()); // Moving Average (MA) over Price indicator. PriceIndiParams price_params_4_ma(); @@ -370,7 +374,7 @@ bool InitIndicators() { // ma_on_price_params.SetDraw(clrYellowGreen); // @fixme ma_on_price_params.SetIndicatorType(INDI_MA_ON_PRICE); Ref indi_ma_on_price = new Indi_MA(ma_on_price_params, IDATA_BUILTIN, indi_price_4_ma.Ptr()); - indis.Push(Ref(indi_ma_on_price.Ptr())); + indis.Add(indi_ma_on_price.Ptr()); // Commodity Channel Index (CCI) over Price indicator. PriceIndiParams price_params_4_cci(); @@ -378,7 +382,7 @@ bool InitIndicators() { IndiCCIParams cci_on_price_params(); // cci_on_price_params.SetDraw(clrYellowGreen, 1); // @fixme Ref indi_cci_on_price = new Indi_CCI(cci_on_price_params, IDATA_BUILTIN, indi_price_4_cci.Ptr()); - indis.Push(Ref(indi_cci_on_price.Ptr())); + indis.Add(indi_cci_on_price.Ptr()); // Envelopes over Price indicator. PriceIndiParams price_params_4_envelopes(); @@ -387,7 +391,7 @@ bool InitIndicators() { // env_on_price_params.SetDraw(clrBrown); // @fixme Ref indi_envelopes_on_price = new Indi_Envelopes(env_on_price_params, IDATA_BUILTIN, indi_price_4_envelopes.Ptr()); - indis.Push(Ref(indi_envelopes_on_price.Ptr())); + indis.Add(indi_envelopes_on_price.Ptr()); // DEMA over Price indicator. PriceIndiParams price_params_4_dema(); @@ -396,7 +400,7 @@ bool InitIndicators() { // dema_on_price_params.SetDraw(clrRed); // @fixme Ref indi_dema_on_price = new Indi_DEMA(dema_on_price_params, INDI_DEMA_DEFAULT_IDSTYPE, indi_price_4_dema.Ptr()); - // indis.Push(indi_dema_on_price.Ptr()); // @fixme + // indis.Add(indi_dema_on_price.Ptr()); // @fixme // Momentum over Price indicator. Ref indi_price_4_momentum = new Indi_Price(); @@ -404,7 +408,7 @@ bool InitIndicators() { // mom_on_price_params.SetDraw(clrDarkCyan); // @fixme Ref indi_momentum_on_price = new Indi_Momentum(mom_on_price_params, IDATA_BUILTIN, indi_price_4_momentum.Ptr()); - indis.Push(Ref(indi_momentum_on_price.Ptr())); + indis.Add(indi_momentum_on_price.Ptr()); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); @@ -412,13 +416,13 @@ bool InitIndicators() { IndiRSIParams rsi_on_price_params(); // rsi_on_price_params.SetDraw(clrBisque, 1); // @fixme Ref indi_rsi_on_price = new Indi_RSI(rsi_on_price_params, IDATA_BUILTIN, indi_price_4_rsi.Ptr()); - indis.Push(Ref(indi_rsi_on_price.Ptr())); + indis.Add(indi_rsi_on_price.Ptr()); // Drawer (socket-based) indicator over RSI over Price. IndiDrawerParams drawer_params(14, PRICE_OPEN); // drawer_params.SetDraw(clrBisque, 0); // @fixme Ref indi_drawer_on_rsi = new Indi_Drawer(drawer_params, IDATA_BUILTIN, indi_rsi_on_price.Ptr()); - indis.Push(Ref(indi_drawer_on_rsi.Ptr())); + indis.Add(indi_drawer_on_rsi.Ptr()); // Applied Price over OHCL indicator. IndiAppliedPriceParams applied_price_params(); @@ -426,11 +430,11 @@ bool InitIndicators() { IndiOHLCParams applied_price_ohlc_params(PRICE_TYPICAL); Ref indi_applied_price_on_price = new Indi_AppliedPrice(applied_price_params, IDATA_INDICATOR, new Indi_OHLC(applied_price_ohlc_params)); - indis.Push(Ref(indi_applied_price_on_price.Ptr())); + indis.Add(indi_applied_price_on_price.Ptr()); // ADXW. IndiADXWParams adxw_params(14); - indis.Push(Ref(new Indi_ADXW(adxw_params))); + indis.Add(new Indi_ADXW(adxw_params)); // AMA. IndiAMAParams ama_params(); @@ -438,129 +442,129 @@ bool InitIndicators() { // However, in that case we need to specifiy applied price (excluding ASK and BID). Indi_AMA* _indi_ama = new Indi_AMA(ama_params, IDATA_INDICATOR); _indi_ama.SetAppliedPrice(PRICE_OPEN); - indis.Push(Ref(_indi_ama)); + indis.Add(_indi_ama); // Original AMA. IndiAMAParams ama_params_orig(); ama_params_orig.SetName("Original AMA to compare"); - indis.Push(Ref(new Indi_AMA(ama_params_orig))); + indis.Add(new Indi_AMA(ama_params_orig)); // Chaikin Oscillator. IndiCHOParams cho_params(); - indis.Push(Ref(new Indi_CHO(cho_params))); + indis.Add(new Indi_CHO(cho_params)); // Chaikin Volatility. IndiCHVParams chv_params(); - indis.Push(Ref(new Indi_CHV(chv_params))); + indis.Add(new Indi_CHV(chv_params)); // Color Bars. IndiColorBarsParams color_bars_params(); - indis.Push(Ref(new Indi_ColorBars(color_bars_params))); + indis.Add(new Indi_ColorBars(color_bars_params)); // Color Candles Daily. IndiColorCandlesDailyParams color_candles_daily_params(); - indis.Push(Ref(new Indi_ColorCandlesDaily(color_candles_daily_params))); + indis.Add(new Indi_ColorCandlesDaily(color_candles_daily_params)); // Color Line. IndiColorLineParams color_line_params(); - indis.Push(Ref(new Indi_ColorLine(color_line_params))); + indis.Add(new Indi_ColorLine(color_line_params)); // Detrended Price Oscillator. IndiDetrendedPriceParams detrended_params(); - indis.Push(Ref(new Indi_DetrendedPrice(detrended_params))); + indis.Add(new Indi_DetrendedPrice(detrended_params)); // Mass Index. IndiMassIndexParams mass_index_params(); - indis.Push(Ref(new Indi_MassIndex(mass_index_params))); + indis.Add(new Indi_MassIndex(mass_index_params)); // OHLC. IndiOHLCParams ohlc_params(); - indis.Push(Ref(new Indi_OHLC(ohlc_params))); + indis.Add(new Indi_OHLC(ohlc_params)); // Price Channel. IndiPriceChannelParams price_channel_params(); - indis.Push(Ref(new Indi_PriceChannel(price_channel_params))); + indis.Add(new Indi_PriceChannel(price_channel_params)); // Price Volume Trend. IndiPriceVolumeTrendParams price_volume_trend_params(); - indis.Push(Ref(new Indi_PriceVolumeTrend(price_volume_trend_params))); + indis.Add(new Indi_PriceVolumeTrend(price_volume_trend_params)); // Bill Williams' Zone Trade. IndiBWZTParams bwzt_params(); - indis.Push(Ref(new Indi_BWZT(bwzt_params))); + indis.Add(new Indi_BWZT(bwzt_params)); // Rate of Change. IndiRateOfChangeParams rate_of_change_params(); - indis.Push(Ref(new Indi_RateOfChange(rate_of_change_params))); + indis.Add(new Indi_RateOfChange(rate_of_change_params)); // Triple Exponential Moving Average. IndiTEMAParams tema_params(); - indis.Push(Ref(new Indi_TEMA(tema_params))); + indis.Add(new Indi_TEMA(tema_params)); // Triple Exponential Average. IndiTRIXParams trix_params(); - indis.Push(Ref(new Indi_TRIX(trix_params))); + indis.Add(new Indi_TRIX(trix_params)); // Ultimate Oscillator. IndiUltimateOscillatorParams ultimate_oscillator_params(); - indis.Push(Ref(new Indi_UltimateOscillator(ultimate_oscillator_params))); + indis.Add(new Indi_UltimateOscillator(ultimate_oscillator_params)); // VIDYA. IndiVIDYAParams vidya_params(); - indis.Push(Ref(new Indi_VIDYA(vidya_params))); + indis.Add(new Indi_VIDYA(vidya_params)); // Volumes. IndiVolumesParams volumes_params(); - indis.Push(Ref(new Indi_Volumes(volumes_params))); + indis.Add(new Indi_Volumes(volumes_params)); // Volume Rate of Change. IndiVROCParams vol_rate_of_change_params(); - indis.Push(Ref(new Indi_VROC(vol_rate_of_change_params))); + indis.Add(new Indi_VROC(vol_rate_of_change_params)); // Larry Williams' Accumulation/Distribution. IndiWilliamsADParams williams_ad_params(); - indis.Push(Ref(new Indi_WilliamsAD(williams_ad_params))); + indis.Add(new Indi_WilliamsAD(williams_ad_params)); // ZigZag Color. IndiZigZagColorParams zigzag_color_params(); - indis.Push(Ref(new Indi_ZigZagColor(zigzag_color_params))); + indis.Add(new Indi_ZigZagColor(zigzag_color_params)); // Custom Moving Average. IndiCustomMovingAverageParams cma_params(); - indis.Push(Ref(new Indi_CustomMovingAverage(cma_params))); + indis.Add(new Indi_CustomMovingAverage(cma_params)); // Math (specialized indicator). IndiMathParams math_params(MATH_OP_SUB, BAND_UPPER, BAND_LOWER, 0, 0); // math_params.SetDraw(clrBlue); // @fixme math_params.SetName("Bands(UP - LO)"); Ref indi_math_1 = new Indi_Math(math_params, IDATA_INDICATOR, indi_bands.Ptr()); - indis.Push(Ref(indi_math_1.Ptr())); + indis.Add(indi_math_1.Ptr()); // Math (specialized indicator) via custom math method. IndiMathParams math_custom_params(MathCustomOp, BAND_UPPER, BAND_LOWER, 0, 0); // math_custom_params.SetDraw(clrBeige); // @fixme math_custom_params.SetName("Bands(Custom math fn)"); Ref indi_math_2 = new Indi_Math(math_custom_params, IDATA_INDICATOR, indi_bands.Ptr()); - indis.Push(Ref(indi_math_2.Ptr())); + indis.Add(indi_math_2.Ptr()); // RS (Math-based) indicator. IndiRSParams rs_params(); - indis.Push(Ref(new Indi_RS(rs_params))); + indis.Add(new Indi_RS(rs_params)); // Pattern Detector. IndiPatternParams pattern_params(); - indis.Push(Ref(new Indi_Pattern(pattern_params))); + indis.Add(new Indi_Pattern(pattern_params)); // Pivot. IndiPivotParams pivot_params(); - indis.Push(Ref(new Indi_Pivot(pivot_params))); + indis.Add(new Indi_Pivot(pivot_params)); // Candle Pattern Detector. CandleParams candle_params(); - indis.Push(Ref(new Indi_Candle(candle_params))); + indis.Add(new Indi_Candle(candle_params)); // Push white-listed indicators here. - // whitelisted_indis.Push(_indi_test); + // whitelisted_indis.Add(_indi_test); return GetLastError() == ERR_NO_ERROR; } @@ -571,13 +575,13 @@ double MathCustomOp(double a, double b) { return 1.11 + (b - a) * 2.0; } * Print indicators. */ bool PrintIndicators(string _prefix = "") { - for (DictIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - if (whitelisted_indis.Size() != 0 && !whitelisted_indis.Contains(iter.Value())) { + for (int i = 0; i < indis.Size(); ++i) { + IndicatorData* _indi = indis[i]; + + if (whitelisted_indis.Size() != 0 && !whitelisted_indis.Contains(_indi)) { continue; } - IndicatorData* _indi = iter.Value().Ptr(); - if (_indi.GetModeCount() == 0) { // Indicator has no modes. PrintFormat("Skipping %s as it has no modes.", _indi.GetFullName()); From 720ec62b113ffce187fbad7d54c789190f85f6be Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 8 Feb 2023 16:42:03 +0100 Subject: [PATCH 060/123] WIP. Should fix tests in MT4 and MT5. --- DictSlot.mqh | 8 +++---- Indicator/tests/classes/Indicators.h | 4 ++-- Refs.struct.h | 16 ++++++++++++++ Tick/Tick.struct.h | 14 +++++++++++++ Tick/TickManager.h | 1 + tests/IndicatorsTest.mq5 | 4 ++-- tests/RefsTest.mq5 | 31 ++++++++++++++-------------- 7 files changed, 54 insertions(+), 24 deletions(-) diff --git a/DictSlot.mqh b/DictSlot.mqh index 3752244c9..1b28cea9e 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,11 +40,11 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} -#ifdef __MQL__ - DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} -#else + //#ifdef __MQL__ + // DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} + //#else DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key) { value = r.value; } -#endif + //#endif bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h index aac05a9ee..871d059a3 100644 --- a/Indicator/tests/classes/Indicators.h +++ b/Indicator/tests/classes/Indicators.h @@ -40,7 +40,7 @@ class Indicators { DictStruct> _indis; public: - void Add(IndicatorBase* _indi) { + void Add(IndicatorData* _indi) { Ref _ref = _indi; _indis.Push(_ref); } @@ -51,7 +51,7 @@ class Indicators { IndicatorData* operator[](int index) { return Get(index); } - int Size() { return _indis.Size(); } + int Size() { return (int)_indis.Size(); } /** * Executes OnTick() on every added indicator. diff --git a/Refs.struct.h b/Refs.struct.h index 3de03deba..ddda68a3b 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -357,6 +357,14 @@ struct WeakRef { return Ptr(); } + /** + * Makes a weak reference to the given weakly-referenced object. + */ + X* operator=(const WeakRef& right) { + THIS_REF = right.Ptr(); + return Ptr(); + } + /** * Makes a weak reference to the strongly-referenced object. */ @@ -365,6 +373,14 @@ struct WeakRef { return Ptr(); } + /** + * Makes a weak reference to the strongly-referenced object. + */ + X* operator=(const Ref& right) { + THIS_REF = right.Ptr(); + return Ptr(); + } + /** * Equality operator. */ diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 71f08dcf8..bda8880d5 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -47,6 +47,20 @@ struct MqlTick { long time_msc; // Time of a price last update in milliseconds. unsigned int flags; // Tick flags. unsigned long volume; // Volume for the current last price. + // Default constructor. + MqlTick() {} + + // Copy constructor. + MqlTick(){const MqlTick & r} { + time = r.time; + ask = r.ask; + bid = r.bid; + last = r.last; + volume_real = r.volume_real; + time_msc = r.time_msc; + flags = r.flags; + volume = r.volume; + } }; #endif diff --git a/Tick/TickManager.h b/Tick/TickManager.h index 76f2f0e1d..d34239ac3 100644 --- a/Tick/TickManager.h +++ b/Tick/TickManager.h @@ -27,6 +27,7 @@ // Includes. #include "../BufferStruct.mqh" +#include "Tick.struct.h" #include "TickManager.h" //#include "TickManager.struct.h" diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index b306ed976..c113d8892 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -53,8 +53,8 @@ enum ENUM_CUSTOM_INDICATORS { INDI_SPECIAL_MATH_CUSTOM = FINAL_INDICATOR_TYPE_EN // Global variables. Indicators indis; -DictStruct whitelisted_indis; -DictStruct tested; +Dict whitelisted_indis; +Dict tested; double test_values[] = {1.245, 1.248, 1.254, 1.264, 1.268, 1.261, 1.256, 1.250, 1.242, 1.240, 1.235, 1.240, 1.234, 1.245, 1.265, 1.274, 1.285, 1.295, 1.300, 1.312, 1.315, 1.320, 1.325, 1.335, 1.342, 1.348, 1.352, 1.357, 1.359, 1.422, 1.430, 1.435}; diff --git a/tests/RefsTest.mq5 b/tests/RefsTest.mq5 index 8f0b0cf9e..943a22378 100644 --- a/tests/RefsTest.mq5 +++ b/tests/RefsTest.mq5 @@ -137,26 +137,25 @@ int OnInit() { // Dictionary of weak references. DictStruct> refs2; - /* - Ref dyn9_1 = new DynamicClass(1); - Ref dyn9_2 = new DynamicClass(2); - Ref dyn9_3 = new DynamicClass(3); + Ref dyn9_1 = new DynamicClass(1); + Ref dyn9_2 = new DynamicClass(2); + Ref dyn9_3 = new DynamicClass(3); - WeakRef dyn9_1_weak_ref = dyn9_1; - WeakRef dyn9_2_weak_ref = dyn9_2; - WeakRef dyn9_3_weak_ref = dyn9_3; + WeakRef dyn9_1_weak_ref = dyn9_1; + WeakRef dyn9_2_weak_ref = dyn9_2; + WeakRef dyn9_3_weak_ref = dyn9_3; - refs2.Set("1", dyn9_1_weak_ref); - refs2.Set("2", dyn9_2_weak_ref); - refs2.Set("3", dyn9_3_weak_ref); + refs2.Set("1", dyn9_1_weak_ref); + refs2.Set("2", dyn9_2_weak_ref); + refs2.Set("3", dyn9_3_weak_ref); - // Should make refs2["2"] to have no existing object. - dyn9_2 = NULL; + // Should make refs2["2"] to have no existing object. + dyn9_2 = NULL; + + assertTrueOrFail(refs2.GetByKey("1").ObjectExists(), "Object should exists"); + assertTrueOrFail(!refs2.GetByKey("2").ObjectExists(), "Object should not exists as it has no more strong references"); + assertTrueOrFail(refs2.GetByKey("3").ObjectExists(), "Object should exists"); - assertTrueOrFail(refs2.GetByKey("1").ObjectExists(), "Object should exists"); - assertTrueOrFail(!refs2.GetByKey("2").ObjectExists(), "Object should not exists as it has no more strong - references"); assertTrueOrFail(refs2.GetByKey("3").ObjectExists(), "Object should exists"); - */ return INIT_SUCCEEDED; } From 032e8e7bcd2445093d72dcbcdc32ef2768b883ed Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 9 Feb 2023 18:23:28 +0100 Subject: [PATCH 061/123] WIP. Should fix errors in MT4, MT5 & C++ for TaskRunner. --- .github/workflows/compile-cpp.yml | 2 ++ Chart.struct.tf.h | 7 ++++++- Indicator/IndicatorData.h | 5 ++++- Storage/ValueStorage.history.h | 2 +- Storage/ValueStorage.indicator.h | 9 +++++++-- Tick/Tick.struct.h | 2 +- 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.github/workflows/compile-cpp.yml b/.github/workflows/compile-cpp.yml index 9a2d220e4..b68563cfe 100644 --- a/.github/workflows/compile-cpp.yml +++ b/.github/workflows/compile-cpp.yml @@ -43,6 +43,8 @@ jobs: with: compiler: gcc-latest - name: Compile ${{ matrix.file }} via emcc + if: always() run: emcc "${{ matrix.file }}" - name: Compile ${{ matrix.file }} via g++ + if: always() run: g++ -c "${{ matrix.file }}" diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index f392ef0d5..8eb01b41c 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -195,7 +195,12 @@ struct ChartTf { static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { switch (_tf) { case PERIOD_CURRENT: - return PeriodSeconds(_tf); +#ifdef __MQL__ + return ::PeriodSeconds(_tf); +#else + RUNTIME_ERROR("PeriodSeconds(PERIOD_CURRENT) is not implemented! Returning 0."); + return 0; +#endif case PERIOD_M1: // 1 minute. return 60; case PERIOD_M2: // 2 minutes (non-standard). diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index a08cdeae4..97fe40b4a 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -44,7 +44,6 @@ struct ExternInstantiateIndicatorBufferValueStorageDouble { #include "../Flags.h" #include "../Storage/IValueStorage.h" #include "../Storage/ItemsHistory.h" -#include "../Storage/ValueStorage.indicator.h" #include "../SymbolInfo.struct.h" #include "Indicator.enum.h" #include "IndicatorBase.h" @@ -1940,6 +1939,10 @@ int CopyBuffer(IndicatorData* _indi, int _mode, int _start, int _count, ValueSto return _num_copied; } +// clang-format off +#include "../Storage/ValueStorage.indicator.h" +// clang-format on + IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble( IndicatorData* _indi, int _mode) { return new IndicatorBufferValueStorage(_indi, _mode); diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index 73d64a74f..c78b69880 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -65,7 +65,7 @@ class HistoryValueStorage : public ValueStorage { /** * Initializes storage with given value. */ - virtual void Initialize(C _value) { + virtual void Initialize(C _value) override { Print("HistoryValueStorage does not implement Initialize()!"); DebugBreak(); } diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 58d4db243..06c125d80 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -32,6 +32,8 @@ // Forward declarations. class IndicatorData; +template +class HistoryValueStorage; // Includes. #include "../Indicator/IndicatorData.h" @@ -50,10 +52,13 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { * Constructor. */ IndicatorBufferValueStorage(IndicatorData* _indi_candle, int _mode = 0, bool _is_series = false) - : mode(_mode), HistoryValueStorage(_indi_candle) {} + : HistoryValueStorage(_indi_candle), mode(_mode) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - C Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_rel_shift)); } + C Fetch(int _rel_shift) override { + IndicatorData* _indi = THIS_ATTR indi_candle.Ptr(); + return _indi PTR_DEREF GetValue(mode, THIS_ATTR RealShift(_rel_shift)); + } }; diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index bda8880d5..fb27ecbfa 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -51,7 +51,7 @@ struct MqlTick { MqlTick() {} // Copy constructor. - MqlTick(){const MqlTick & r} { + MqlTick(const MqlTick &r) { time = r.time; ask = r.ask; bid = r.bid; From 11b6ce5a2184ff47f0c52ef10fc3f77f5b6ff157 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 16 Feb 2023 17:56:48 +0100 Subject: [PATCH 062/123] Added missing includes. --- Task/TaskAction.h | 1 + Task/TaskCondition.h | 1 + Task/TaskGetter.h | 1 + 3 files changed, 3 insertions(+) diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 56d053b99..5f48a66b7 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -35,6 +35,7 @@ #define TASK_ACTION_H // Includes. +#include "../DateTime.mqh" #include "../Std.h" #include "../Terminal.define.h" #include "TaskAction.enum.h" diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 4ccbdbf04..962c088bb 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -35,6 +35,7 @@ #define TASK_CONDITION_H // Includes. +#include "../DateTime.mqh" #include "../Std.h" #include "../Terminal.define.h" #include "TaskCondition.enum.h" diff --git a/Task/TaskGetter.h b/Task/TaskGetter.h index a7cddb16c..346add6f5 100644 --- a/Task/TaskGetter.h +++ b/Task/TaskGetter.h @@ -36,6 +36,7 @@ // Includes. //#include "TaskGetter.enum.h" +#include "../DateTime.mqh" #include "../Terminal.define.h" #include "TaskGetter.struct.h" #include "TaskGetterBase.h" From f78b9fd3dcf0ef559d9569e5c5c36925ded12ca4 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 16 Feb 2023 18:36:02 +0100 Subject: [PATCH 063/123] Addes required flags for emcc and gcc. --- .github/workflows/compile-cpp.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile-cpp.yml b/.github/workflows/compile-cpp.yml index b68563cfe..1aecc1521 100644 --- a/.github/workflows/compile-cpp.yml +++ b/.github/workflows/compile-cpp.yml @@ -44,7 +44,10 @@ jobs: compiler: gcc-latest - name: Compile ${{ matrix.file }} via emcc if: always() - run: emcc "${{ matrix.file }}" + run: > + emcc -s WASM=1 -s ENVIRONMENT=node -s EXIT_RUNTIME=0 -s NO_EXIT_RUNTIME=1 -s ASSERTIONS=1 -Wall -s + MODULARIZE=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 --bind -s EXPORTED_FUNCTIONS="[]" -g -std=c++17 + "${{ matrix.file }}" - name: Compile ${{ matrix.file }} via g++ if: always() - run: g++ -c "${{ matrix.file }}" + run: g++ -g -std=c++17 -c "${{ matrix.file }}" From a13a079532bbb0bf13797936be469660bd814bf9 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 17 Feb 2023 13:50:27 +0100 Subject: [PATCH 064/123] Made tests to continue even if one of them fails. --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 516d1a9b4..8f24b535e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -86,6 +86,7 @@ jobs: MtVersion: 4.0.0.1349 TestExpert: ${{ matrix.test }} RunOnError: show_logs 200 + if: always() timeout-minutes: 10 Scripts-MQL4: @@ -121,6 +122,7 @@ jobs: uses: fx31337/mql-tester-action@master with: Script: ${{ matrix.test }} + if: always() timeout-minutes: 10 Scripts-MQL4-Ignore: @@ -146,6 +148,7 @@ jobs: with: Script: ${{ matrix.test }} RunOnFail: "exit 0" + if: always() timeout-minutes: 10 Trade-Tests-MQL4: @@ -167,4 +170,5 @@ jobs: uses: fx31337/mql-tester-action@master with: Script: ${{ matrix.test }} + if: always() timeout-minutes: 10 From 2a5f72cb9bbf9f4aabc3983d72980c2d76ae82f7 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 17 Feb 2023 14:48:49 +0100 Subject: [PATCH 065/123] Added ToString() override to Indicator class, so IndicatorsTest will print the results. --- Indicator/Indicator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 8dc615bd7..20aa42c85 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -532,7 +532,7 @@ class Indicator : public IndicatorData { /** * Returns stored data in human-readable format. */ - // virtual bool ToString() = NULL; // @fixme? + string ToString() override { return EntryToString(); } /** * Whether we can and have to select mode when specifying data source. From a36e13553160d48e8fb9fedfa680c6fb085bc6f5 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 17 Feb 2023 19:37:14 +0100 Subject: [PATCH 066/123] WIP. Making FX's Indicator.cpp's to compile. --- Draw.mqh | 53 +++++++++------- DrawIndicator.mqh | 5 +- Platform.extern.h | 29 +++++++++ Platform.h | 70 +++++++++++++++++++++ Storage/ValueStorage.indicator.h | 1 - Terminal.enum.h | 105 +++++++++++++++++++++++++++++++ 6 files changed, 237 insertions(+), 26 deletions(-) diff --git a/Draw.mqh b/Draw.mqh index 0e637d088..c6c200af3 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -32,9 +32,11 @@ class Draw; // Includes. #include "Data.define.h" #include "Object.extern.h" -//#include "Platform.h" #include "Object.mqh" +#include "Platform.extern.h" #include "Terminal.define.h" +#include "Terminal.enum.h" +#include "Terminal.extern.h" #ifndef __MQL4__ // Defines macros (for MQL4 backward compatibility). @@ -46,7 +48,7 @@ class Draw; #define WINDOW_MAIN 0 -#ifdef __MQL5__ +#ifndef __MQL4__ #define OBJPROP_TIME1 ((ENUM_OBJECT_PROPERTY_INTEGER)0) #define OBJPROP_PRICE1 1 #define OBJPROP_TIME2 2 @@ -157,24 +159,6 @@ class Draw : public Object { return ::ObjectSet(name, prop_id, prop_value); #else // __MQL5__ switch (prop_id) { - // Datetime value to set/get first coordinate time part. - case OBJPROP_TIME1: - return ObjectSetInteger(chart_id, name, OBJPROP_TIME, (long)prop_value); - // Datetime value to set/get second coordinate time part. - case OBJPROP_TIME2: - return ObjectSetInteger(chart_id, name, OBJPROP_TIME, 1, (long)prop_value); - // Datetime value to set/get third coordinate time part. - case OBJPROP_TIME3: - return ObjectSetInteger(chart_id, name, OBJPROP_TIME, 2, (long)prop_value); - // Double value to set/get first coordinate price part. - case OBJPROP_PRICE1: - return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, (double)prop_value); - // Double value to set/get second coordinate price part. - case OBJPROP_PRICE2: - return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, 1, prop_value); - // Double value to set/get third coordinate price part. - case OBJPROP_PRICE3: - return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, 2, prop_value); case OBJPROP_ANGLE: // Double value to set/get angle object property in degrees. case OBJPROP_DEVIATION: // Double value to set/get deviation property for Standard deviation objects. case OBJPROP_SCALE: // Double value to set/get scale object property. @@ -203,6 +187,29 @@ class Draw : public Object { default: break; } + + // MQL4 enum values. + switch (prop_id) { + // Datetime value to set/get first coordinate time part. + case OBJPROP_TIME1: + return ObjectSetInteger(chart_id, name, OBJPROP_TIME, (long)prop_value); + // Datetime value to set/get second coordinate time part. + case OBJPROP_TIME2: + return ObjectSetInteger(chart_id, name, OBJPROP_TIME, 1, (long)prop_value); + // Datetime value to set/get third coordinate time part. + case OBJPROP_TIME3: + return ObjectSetInteger(chart_id, name, OBJPROP_TIME, 2, (long)prop_value); + // Double value to set/get first coordinate price part. + case OBJPROP_PRICE1: + return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, (double)prop_value); + // Double value to set/get second coordinate price part. + case OBJPROP_PRICE2: + return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, 1, prop_value); + // Double value to set/get third coordinate price part. + case OBJPROP_PRICE3: + return ObjectSetDouble(chart_id, name, OBJPROP_PRICE, 2, prop_value); + } + return (false); #endif } @@ -261,7 +268,7 @@ class Draw : public Object { * Draw a vertical line. */ bool DrawVLine(string oname, datetime tm) { - bool result = Draw::ObjectCreate(NULL, oname, OBJ_VLINE, 0, tm, 0); + bool result = Draw::ObjectCreate(NULL_VALUE, oname, OBJ_VLINE, 0, tm, 0); if (!result) PrintFormat("%(): Can't create vertical line! code #", __FUNCTION__, GetLastError()); return (result); } @@ -270,7 +277,7 @@ class Draw : public Object { * Draw a horizontal line. */ bool DrawHLine(string oname, double value) { - bool result = Draw::ObjectCreate(NULL, oname, OBJ_HLINE, 0, 0, value); + bool result = Draw::ObjectCreate(NULL_VALUE, oname, OBJ_HLINE, 0, 0, value); if (!result) PrintFormat("%(): Can't create horizontal line! code #", __FUNCTION__, GetLastError()); return (result); } @@ -279,7 +286,7 @@ class Draw : public Object { * Delete a vertical line. */ bool DeleteVertLine(string oname) { - bool result = Draw::ObjectDelete(NULL, oname); + bool result = Draw::ObjectDelete(NULL_VALUE, oname); if (!result) PrintFormat("%(): Can't delete vertical line! code #", __FUNCTION__, GetLastError()); return (result); } diff --git a/DrawIndicator.mqh b/DrawIndicator.mqh index d1ec770be..02fbc3ec0 100644 --- a/DrawIndicator.mqh +++ b/DrawIndicator.mqh @@ -48,7 +48,7 @@ class DrawPoint { } // Special methods. DrawPoint(const DrawPoint& r) : time(r.time), value(r.value) {} - DrawPoint(datetime _time = NULL, double _value = 0) : time(_time), value(_value) {} + DrawPoint(datetime _time = 0, double _value = 0) : time(_time), value(_value) {} }; class DrawIndicator { @@ -124,7 +124,8 @@ class DrawIndicator { } if (!last_points.KeyExists(_name)) { - last_points.Set(_name, DrawPoint(_time, _value)); + DrawPoint _point(_time, _value); + last_points.Set(_name, _point); } else { DrawPoint* last_point = last_points.GetByKey(_name); diff --git a/Platform.extern.h b/Platform.extern.h index 943ec3bcd..8f6e8e7cf 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -27,6 +27,7 @@ // Includes. #include "Deal.enum.h" #include "Order.define.h" +#include "Terminal.enum.h" // Forward declarations. struct MqlTradeRequest; @@ -137,4 +138,32 @@ extern string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); extern string Symbol(); +extern string ObjectName(long _chart_id, int _pos, int _sub_window = -1, int _type = -1); + +extern int ObjectsTotal(long chart_id, int type = EMPTY, int window = -1); + +extern bool PlotIndexSetString(int plot_index, int prop_id, string prop_value); + +extern bool PlotIndexSetInteger(int plot_index, int prop_id, int prop_value); + +extern bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, long prop_value); + +extern bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, + long prop_value); + +extern bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value); + +extern bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, + double prop_value); + +extern bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1); +extern bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, + datetime _t2, double _p2); + +extern bool ObjectMove(long chart_id, string name, int point_index, datetime time, double price); + +extern bool ObjectDelete(long chart_id, string name); + +extern int ObjectFind(long chart_id, string name); + #endif diff --git a/Platform.h b/Platform.h index 90f8440cf..a2408db20 100644 --- a/Platform.h +++ b/Platform.h @@ -581,6 +581,76 @@ string Symbol() { return false; } +string ObjectName(long _chart_id, int _pos, int _sub_window = -1, int _type = -1) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return ""; +} + +int ObjectsTotal(long chart_id, int type = EMPTY, int window = -1) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +bool PlotIndexSetString(int plot_index, int prop_id, string prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool PlotIndexSetInteger(int plot_index, int prop_id, int prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, long prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, + long prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, + double prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, datetime _t2, + double _p2) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectMove(long chart_id, string name, int point_index, datetime time, double price) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectDelete(long chart_id, string name) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +int GetLastError() { return _LastError; } + +int ObjectFind(long chart_id, string name) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + #endif /** diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 06c125d80..54c249bf6 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -36,7 +36,6 @@ template class HistoryValueStorage; // Includes. -#include "../Indicator/IndicatorData.h" #include "ValueStorage.history.h" /** diff --git a/Terminal.enum.h b/Terminal.enum.h index 386caf381..5e56a0fe6 100644 --- a/Terminal.enum.h +++ b/Terminal.enum.h @@ -230,4 +230,109 @@ enum ENUM_UNINIT_REASON { REASON_INITFAILED = 8, REASON_CLOSE = 9, }; + +enum ENUM_DRAW_TYPE { + DRAW_NONE, + DRAW_LINE, + DRAW_SECTION, + DRAW_HISTOGRAM, + DRAW_HISTOGRAM2, + DRAW_ARROW, + DRAW_ZIGZAG, + DRAW_FILLING, + DRAW_BARS, + DRAW_CANDLES, + DRAW_COLOR_LINE, + DRAW_COLOR_SECTION, + DRAW_COLOR_HISTOGRAM, + DRAW_COLOR_HISTOGRAM2, + DRAW_COLOR_ARROW, + DRAW_COLOR_ZIGZAG, + DRAW_COLOR_BARS, + DRAW_COLOR_CANDLES +}; + +enum ENUM_PLOT_PROPERTY_INTEGER { + PLOT_ARROW, + PLOT_ARROW_SHIFT, + PLOT_DRAW_BEGIN, + PLOT_DRAW_TYPE, + PLOT_SHOW_DATA, + PLOT_SHIFT, + PLOT_LINE_STYLE, + PLOT_LINE_WIDTH, + PLOT_COLOR_INDEXES, + PLOT_LINE_COLOR +}; + +enum ENUM_PLOT_PROPERTY_DOUBLE { PLOT_EMPTY_VALUE }; + +enum ENUM_PLOT_PROPERTY_STRING { PLOT_LABEL }; + +enum ENUM_LINE_STYLE { STYLE_SOLID, STYLE_DASH, STYLE_DOT, STYLE_DASHDOT, STYLE_DASHDOTDOT }; + +enum ENUM_OBJECT_PROPERTY_INTEGER { + OBJPROP_COLOR, + OBJPROP_STYLE, + OBJPROP_WIDTH, + OBJPROP_BACK, + OBJPROP_ZORDER, + OBJPROP_FILL, + OBJPROP_HIDDEN, + OBJPROP_SELECTED, + OBJPROP_READONLY, + OBJPROP_TYPE, + OBJPROP_TIME, + OBJPROP_SELECTABLE, + OBJPROP_CREATETIME, + OBJPROP_LEVELS, + OBJPROP_LEVELCOLOR, + OBJPROP_LEVELSTYLE, + OBJPROP_LEVELWIDTH, + OBJPROP_ALIGN, + OBJPROP_FONTSIZE, + OBJPROP_RAY_LEFT, + OBJPROP_RAY_RIGHT, + OBJPROP_RAY, + OBJPROP_ELLIPSE, + OBJPROP_ARROWCODE, + OBJPROP_TIMEFRAMES, + OBJPROP_ANCHOR, + OBJPROP_XDISTANCE, + OBJPROP_YDISTANCE, + OBJPROP_DIRECTION, + OBJPROP_DEGREE, + OBJPROP_DRAWLINES, + OBJPROP_STATE, + OBJPROP_CHART_ID, + OBJPROP_XSIZE, + OBJPROP_YSIZE, + OBJPROP_XOFFSET, + OBJPROP_YOFFSET, + OBJPROP_PERIOD, + OBJPROP_DATE_SCALE, + OBJPROP_PRICE_SCALE, + OBJPROP_CHART_SCALE, + OBJPROP_BGCOLOR, + OBJPROP_CORNER, + OBJPROP_BORDER_TYPE, + OBJPROP_BORDER_COLOR +}; + +enum ENUM_OBJECT_PROPERTY_DOUBLE { OBJPROP_PRICE, OBJPROP_LEVELVALUE, OBJPROP_SCALE, OBJPROP_ANGLE, OBJPROP_DEVIATION }; + +enum ENUM_OBJECT_PROPERTY_STRING { + OBJPROP_NAME, + OBJPROP_TEXT, + OBJPROP_TOOLTIP, + OBJPROP_LEVELTEXT, + OBJPROP_FONT, + OBJPROP_BMPFILE, + OBJPROP_SYMBOL +}; + +enum ENUM_BORDER_TYPE { BORDER_FLAT, BORDER_RAISED, BORDER_SUNKEN }; + +enum ENUM_ALIGN_MODE { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT }; + #endif From ba94fa8e3c01604b1a751810126477b9e52d2b6b Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 21 Feb 2023 13:56:18 +0000 Subject: [PATCH 067/123] Sets job max-parallel to 4 as per API limits --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8f24b535e..e1c8d083f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -73,6 +73,7 @@ jobs: - SummaryReportTest - TickerTest - TradeTest + max-parallel: 4 steps: - uses: actions/download-artifact@v2 with: @@ -114,6 +115,7 @@ jobs: - TerminalTest - TimerTest - ValueStorageTest + max-parallel: 4 steps: - uses: actions/download-artifact@v2 with: From ccade1953784755550d182b1fd32b92556720a2d Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 23 Feb 2023 20:48:16 +0100 Subject: [PATCH 068/123] WIP. Using Indi_TickProvider to provide tick for Candle indicator and finally, for RSI or other one. --- Buffer/BufferTick.h | 8 +- Candle.struct.h | 53 ++++---- DictObject.mqh | 2 +- Indicator/Indicator.h | 65 +++++----- Indicator/IndicatorCandle.h | 40 +++--- Indicator/IndicatorCandle.provider.h | 4 +- Indicator/IndicatorData.h | 6 +- Indicator/IndicatorTf.h | 13 +- Indicator/IndicatorTf.provider.h | 4 +- Indicator/IndicatorTick.h | 28 ++-- Indicator/IndicatorTick.provider.h | 2 +- Indicator/tests/classes/IndicatorTfDummy.h | 2 +- Indicators/Indi_BWMFI.mqh | 12 +- Indicators/Indi_Envelopes.mqh | 6 +- Indicators/Indi_Fractals.mqh | 4 +- Indicators/Indi_Gator.mqh | 4 +- Indicators/Indi_Ichimoku.mqh | 13 +- Indicators/Tick/Indi_TickProvider.h | 142 +++++++++++++++++++++ Indicators/Tick/Indi_TickRandom.mqh | 4 +- Std.h | 13 ++ Storage/ObjectsCache.h | 2 +- Storage/ValueStorage.history.h | 8 ++ Storage/ValueStorage.indicator.h | 23 +++- Storage/ValueStorage.price_median.h | 4 +- Storage/ValueStorage.price_typical.h | 4 +- Storage/ValueStorage.price_weighted.h | 4 +- Storage/ValueStorage.spread.h | 4 +- Storage/ValueStorage.tick_volume.h | 4 +- Storage/ValueStorage.time.h | 4 +- Storage/ValueStorage.volume.h | 4 +- Tick/Tick.struct.h | 30 +++++ 31 files changed, 377 insertions(+), 139 deletions(-) create mode 100644 Indicators/Tick/Indi_TickProvider.h diff --git a/Buffer/BufferTick.h b/Buffer/BufferTick.h index 3aa8da911..f271905a1 100644 --- a/Buffer/BufferTick.h +++ b/Buffer/BufferTick.h @@ -30,6 +30,10 @@ #include "../Storage/IValueStorage.h" #include "../Tick/Tick.struct.h" +// Forward declarations. +template +class BufferTick; + // TV = Type of price stored by BufferTick. RV = Type of property to be retrieved from BufferTick. template class BufferTickValueStorage : ValueStorage { @@ -71,7 +75,7 @@ class BufferTickValueStorage : ValueStorage { /** * Returns number of values available to fetch (size of the values buffer). */ - int Size() override { return (int)buffer_tick.Size(); } + int Size() override { return (int)THIS_ATTR buffer_tick.Size(); } }; /** @@ -109,7 +113,7 @@ class BufferTick : public BufferStruct> { _vs_spread = NULL; _vs_volume = NULL; _vs_tick_volume = NULL; - SetOverflowListener(BufferStructOverflowListener, 10); + THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } public: diff --git a/Candle.struct.h b/Candle.struct.h index 6b2f502e3..1e0123a21 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -239,7 +239,7 @@ struct CandleOCTOHLC : CandleOHLC { // Struct constructor. CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, int _start_time = -1, int _length = 0, long _open_timestamp_ms = -1, long _close_timestamp_ms = -1, int _volume = 0) - : CandleOHLC(_open, _high, _low, _close), + : CandleOHLC(_open, _high, _low, _close), is_complete(true), start_time(_start_time), length(_length), @@ -254,6 +254,11 @@ struct CandleOCTOHLC : CandleOHLC { // Struct constructor. CandleOCTOHLC(const CandleOCTOHLC &r) { THIS_REF = r; } + // Virtual destructor. Required because of Emscripted warning, despite structure has no virtual methods: + // warning: destructor called on non-final 'CandleOCTOHLC' that has virtual functions but non-virtual + // destructor [-Wdelete-non-abstract-non-virtual-dtor] + virtual ~CandleOCTOHLC() {} + /** * Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price. */ @@ -264,7 +269,7 @@ struct CandleOCTOHLC : CandleOHLC { open_timestamp_ms = _timestamp_ms; close_timestamp_ms = _timestamp_ms; volume = _price != 0 ? 1 : 0; - open = high = low = close = _price; + THIS_ATTR open = THIS_ATTR high = THIS_ATTR low = THIS_ATTR close = _price; } /** @@ -280,19 +285,19 @@ struct CandleOCTOHLC : CandleOHLC { if (_is_init || _timestamp_ms < open_timestamp_ms) { open_timestamp_ms = _timestamp_ms; - open = _price; + THIS_ATTR open = _price; } if (_is_init || _timestamp_ms > close_timestamp_ms) { close_timestamp_ms = _timestamp_ms; - close = _price; + THIS_ATTR close = _price; } if (_is_init) { - high = _price; - low = _price; + THIS_ATTR high = _price; + THIS_ATTR low = _price; } else { - high = MathMax(high, _price); - low = MathMin(low, _price); + THIS_ATTR high = MathMax(THIS_ATTR high, _price); + THIS_ATTR low = MathMin(THIS_ATTR low, _price); } // Increasing candle's volume. ++volume; @@ -337,8 +342,8 @@ struct CandleOCTOHLC : CandleOHLC { * Returns text representation of candle. */ string ToString() { - return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", open, high, low, close, - is_complete ? "Complete" : "Incomplete", + return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", THIS_ATTR open, THIS_ATTR high, THIS_ATTR low, + THIS_ATTR close, is_complete ? "Complete" : "Incomplete", TimeToString(open_timestamp_ms, TIME_DATE | TIME_MINUTES | TIME_SECONDS), TimeToString(close_timestamp_ms, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); } @@ -352,18 +357,20 @@ struct CandleTOHLC : CandleOHLC { datetime time; // Struct constructors. CandleTOHLC(datetime _time = 0, T _open = 0, T _high = 0, T _low = 0, T _close = 0) - : time(_time), CandleOHLC(_open, _high, _low, _close) {} + : time(_time), CandleOHLC(_open, _high, _low, _close) {} // Getters. datetime GetTime() { return time; } // Serializers. SerializerNodeType Serialize(Serializer &s); // Converters. - string ToCSV() { return StringFormat("%d,%g,%g,%g,%g", time, open, high, low, close); } + string ToCSV() { + return StringFormat("%d,%g,%g,%g,%g", time, THIS_ATTR open, THIS_ATTR high, THIS_ATTR low, THIS_ATTR close); + } }; /* Method to serialize CandleEntry structure. */ template -SerializerNodeType CandleOHLC::Serialize(Serializer &s) { +SerializerNodeType CandleOHLC::Serialize(Serializer &s) { // s.Pass(THIS_REF, "time", TimeToString(time)); s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); @@ -374,25 +381,25 @@ SerializerNodeType CandleOHLC::Serialize(Serializer &s) { /* Method to serialize CandleEntry structure. */ template -SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { +SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { s.Pass(THIS_REF, "time", time); - s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "open", THIS_ATTR open, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "high", THIS_ATTR high, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "low", THIS_ATTR low, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close", THIS_ATTR close, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } /* Method to serialize CandleEntry structure. */ template -SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { +SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { s.Pass(THIS_REF, "is_complete", is_complete, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "open_timestamp_ms", open_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "close_timestamp_ms", close_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "open", THIS_ATTR open, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "high", THIS_ATTR high, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "low", THIS_ATTR low, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close", THIS_ATTR close, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "volume", volume, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } diff --git a/DictObject.mqh b/DictObject.mqh index c02437267..a19078a79 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -153,7 +153,7 @@ class DictObject : public DictBase { */ V* GetByKey(const K _key) { unsigned int position; - DictSlot* slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, _key, position); + DictSlot* slot = THIS_ATTR GetSlotByKey(this PTR_DEREF _DictSlots_ref, _key, position); if (!slot) return NULL; diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 20aa42c85..6f84b10e8 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -49,17 +49,6 @@ struct IndicatorParams; #include "Indicator.struct.serialize.h" #include "IndicatorData.h" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compatibility). -bool IndicatorBuffers(int _count) { return Indicator::SetIndicatorBuffers(_count); } -int IndicatorCounted(int _value = 0) { - static int prev_calculated = 0; - // https://docs.mql4.com/customind/indicatorcounted - prev_calculated = _value > 0 ? _value : prev_calculated; - return prev_calculated; -} -#endif - #ifdef __MQL5__ // Defines global functions (for MQL5 forward compatibility). template (GetModeCount()); + IndicatorDataEntry _entry = GetEntry(shift); + double value = _entry.GetMax(GetModeCount()); if (value > max) { max = value; max_idx = shift; @@ -183,7 +173,8 @@ class Indicator : public IndicatorData { int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); for (int shift = start_bar; shift <= last_bar; ++shift) { - double value = GetEntry(shift).GetMin(GetModeCount()); + IndicatorDataEntry _entry = GetEntry(shift); + double value = _entry.GetMin(GetModeCount()); if (value < min) { min = value; min_idx = shift; @@ -226,7 +217,7 @@ class Indicator : public IndicatorData { /* Buffer methods */ - virtual string CacheKey() { return GetFullName(); } + string CacheKey() override { return GetFullName(); } /** * Initializes a cached proxy between i*OnArray() methods and OnCalculate() @@ -358,9 +349,8 @@ class Indicator : public IndicatorData { * * When indicator values are not valid, returns empty signals. */ - IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) { - bool _is_valid = true; - IndicatorDataEntry _data[]; + IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) override { + ARRAY(IndicatorDataEntry, _data); if (!CopyEntries(_data, _count, _shift)) { // Some copied data is invalid, so returns empty signals. IndicatorSignal _signals(0); @@ -381,7 +371,7 @@ class Indicator : public IndicatorData { /** * Get more descriptive name of the indicator. */ - string GetDescriptiveName() { + string GetDescriptiveName() override { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); string name = iparams.name + " ("; @@ -393,8 +383,10 @@ class Indicator : public IndicatorData { name += "custom, "; break; case IDATA_INDICATOR: - name += "over " + GetDataSource().GetDescriptiveName() + ", "; + name += "over " + GetDataSource() PTR_DEREF GetDescriptiveName() + ", "; break; + default: + name += "unknown "; } name += IntegerToString(_max_modes) + (_max_modes == 1 ? " mode" : " modes"); @@ -407,14 +399,14 @@ class Indicator : public IndicatorData { /** * Sets name of the indicator. */ - void SetName(string _name) { iparams.SetName(_name); } + void SetName(string _name) override { iparams.SetName(_name); } /** * Sets indicator's handle. * * Note: Not supported in MT4. */ - void SetHandle(int _handle) { + void SetHandle(int _handle) override { istate.handle = _handle; istate.is_changed = true; } @@ -436,7 +428,7 @@ class Indicator : public IndicatorData { * @return * Returns true when the condition is met. */ - bool CheckCondition(ENUM_INDICATOR_CONDITION _cond, DataParamEntry& _args[]) { + bool CheckCondition(ENUM_INDICATOR_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { switch (_cond) { case INDI_COND_ENTRY_IS_MAX: // @todo: Add arguments, check if the entry value is max. @@ -461,7 +453,8 @@ class Indicator : public IndicatorData { // Indicator entry value is lesser than median. return false; default: - GetLogger().Error(StringFormat("Invalid indicator condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error( + StringFormat("Invalid indicator condition: %s at %s!", EnumToString(_cond), __FUNCTION_LINE__)); return false; } } @@ -480,18 +473,19 @@ class Indicator : public IndicatorData { * @return * Returns true when the action has been executed successfully. */ - virtual bool ExecuteAction(ENUM_INDICATOR_ACTION _action, DataParamEntry& _args[]) { + virtual bool ExecuteAction(ENUM_INDICATOR_ACTION _action, ARRAY_REF(DataParamEntry, _args)) { bool _result = true; long _arg1 = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; switch (_action) { case INDI_ACTION_CLEAR_CACHE: - _arg1 = _arg1 > 0 ? _arg1 : TimeCurrent(); + _arg1 = _arg1 != 0 ? _arg1 : (long)TimeCurrent(); Print("Action not yet implemented!"); DebugBreak(); // idata.Clear(_arg1); return true; default: - GetLogger().Error(StringFormat("Invalid Indicator action: %s!", EnumToString(_action), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error(StringFormat("Invalid Indicator action: %s at %s!", C_STR(EnumToString(_action)), + C_STR(__FUNCTION_LINE__))); return false; } return _result; @@ -537,7 +531,7 @@ class Indicator : public IndicatorData { /** * Whether we can and have to select mode when specifying data source. */ - virtual bool IsDataSourceModeSelectable() { return true; } + virtual bool IsDataSourceModeSelectable() override { return true; } /** * Checks if indicator entry is valid. @@ -652,7 +646,7 @@ class Indicator : public IndicatorData { DebugBreak(); } } - GetEntryAlter(_entry, _rel_shift); + THIS_ATTR GetEntryAlter(_entry, _rel_shift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { idata.Add(_entry, _bar_time); @@ -675,7 +669,7 @@ class Indicator : public IndicatorData { * This method allows user to modify the struct entry before it's added to cache. * This method is called on GetEntry() right after values are set. */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) { + void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) override { ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE)); _entry.AddFlags(_entry.GetDataTypeFlags(_dtype)); }; @@ -702,10 +696,21 @@ class Indicator : public IndicatorData { /** * Update indicator. */ - virtual bool Update() { + virtual bool Update() override { // @todo return false; }; }; +#ifndef __MQL4__ +// Defines global functions (for MQL4 backward compatibility). +bool IndicatorBuffers(int _count) { return Indicator::SetIndicatorBuffers(_count); } +int IndicatorCounted(int _value = 0) { + static int prev_calculated = 0; + // https://docs.mql4.com/customind/indicatorcounted + prev_calculated = _value > 0 ? _value : prev_calculated; + return prev_calculated; +} +#endif + #endif diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index d11686168..0f6c70ea6 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -84,8 +84,8 @@ class IndicatorCandle : public Indicator { */ void Init() { // Along with indexing by shift, we can also index via timestamp! - flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_INDI_CANDLE_MODE_ENTRY); + THIS_ATTR flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; + THIS_ATTR Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), (int)FINAL_INDI_CANDLE_MODE_ENTRY); } public: @@ -96,11 +96,11 @@ class IndicatorCandle : public Indicator { */ IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(INDI_CANDLE_HISTORY_SIZE) { + : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(INDI_CANDLE_HISTORY_SIZE) { Init(); } IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name), history(INDI_CANDLE_HISTORY_SIZE) { + : Indicator(_itype, _shift, _name), history(INDI_CANDLE_HISTORY_SIZE) { Init(); } @@ -154,13 +154,13 @@ class IndicatorCandle : public Indicator { int GetBars() override { // Will return number of bars prepended and appended to the history, // even if those bars were cleaned up because of history's candle limit. - return (int)history.GetPeakSize() - iparams.shift; + return (int)history.GetPeakSize() - THIS_ATTR iparams.shift; } /** * Returns current tick index (incremented every OnTick()). */ - int GetTickIndex() override { return GetTick() PTR_DEREF GetTickIndex(); } + int GetTickIndex() override { return THIS_ATTR GetTick() PTR_DEREF GetTickIndex(); } /** * Check if there is a new bar to parse. @@ -182,7 +182,7 @@ class IndicatorCandle : public Indicator { /** * Removes candle from the buffer. Used mainly for testing purposes. */ - void InvalidateCandle(int _abs_shift) { + void InvalidateCandle(int _abs_shift) override { if (_abs_shift != GetBarIndex()) { Print( "IndicatorCandle::InvalidateCandle() currently supports specyfing " @@ -198,7 +198,7 @@ class IndicatorCandle : public Indicator { /** * Returns time of the bar for a given shift. */ - virtual datetime GetBarTime(int _rel_shift = 0) { return history.GetItemTimeByShift(_rel_shift); } + datetime GetBarTime(int _rel_shift = 0) override { return history.GetItemTimeByShift(_rel_shift); } /** * Traverses source indicators' hierarchy and tries to find OHLC-featured @@ -216,7 +216,7 @@ class IndicatorCandle : public Indicator { BarOHLC _bar; CandleOCTOHLC _candle; - if (history.TryGetItemByShift(ToAbsShift(_rel_shift), _candle)) { + if (history.TryGetItemByShift(THIS_ATTR ToAbsShift(_rel_shift), _candle)) { _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.start_time); } @@ -262,7 +262,7 @@ class IndicatorCandle : public Indicator { */ IndicatorDataEntry GetEntry(int _shift = 0) override { ResetLastError(); - int _ishift = _shift + iparams.GetShift(); + int _ishift = _shift + THIS_ATTR iparams.GetShift(); CandleOCTOHLC _candle = history.GetItemByShift(_ishift); return CandleToEntry(_candle.GetTime(), _candle); } @@ -271,35 +271,35 @@ class IndicatorCandle : public Indicator { * Returns value storage for a given mode. */ IValueStorage* GetValueStorage(int _mode = 0) override { - if (_mode >= ArraySize(value_storages)) { - ArrayResize(value_storages, _mode + 1); + if (_mode >= ArraySize(THIS_ATTR value_storages)) { + ArrayResize(THIS_ATTR value_storages, _mode + 1); } - if (!value_storages[_mode].IsSet()) { + if (!THIS_ATTR value_storages[_mode].IsSet()) { // Buffer not yet created. switch (_mode) { case INDI_CANDLE_MODE_PRICE_OPEN: case INDI_CANDLE_MODE_PRICE_HIGH: case INDI_CANDLE_MODE_PRICE_LOW: case INDI_CANDLE_MODE_PRICE_CLOSE: - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + THIS_ATTR value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); break; case INDI_CANDLE_MODE_SPREAD: case INDI_CANDLE_MODE_TICK_VOLUME: case INDI_CANDLE_MODE_VOLUME: - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + THIS_ATTR value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); break; case INDI_CANDLE_MODE_TIME: - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + THIS_ATTR value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); break; case INDI_CANDLE_MODE_PRICE_MEDIAN: - value_storages[_mode] = new PriceMedianValueStorage(THIS_PTR); + THIS_ATTR value_storages[_mode] = new PriceMedianValueStorage(THIS_PTR); break; case INDI_CANDLE_MODE_PRICE_TYPICAL: - value_storages[_mode] = new PriceTypicalValueStorage(THIS_PTR); + THIS_ATTR value_storages[_mode] = new PriceTypicalValueStorage(THIS_PTR); break; case INDI_CANDLE_MODE_PRICE_WEIGHTED: - value_storages[_mode] = new PriceWeightedValueStorage(THIS_PTR); + THIS_ATTR value_storages[_mode] = new PriceWeightedValueStorage(THIS_PTR); break; default: Print("ERROR: Unsupported value storage mode ", _mode); @@ -307,7 +307,7 @@ class IndicatorCandle : public Indicator { } } - return value_storages[_mode].Ptr(); + return THIS_ATTR value_storages[_mode].Ptr(); } /** diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index b6737c945..ccecbd14e 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -47,8 +47,8 @@ class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider, ItemsHistoryItemProvider>>* _history, - long _time_ms, float _ask, float _bid) { + void OnTick(ItemsHistory, ItemsHistoryItemProvider>>* _history, long _time_ms, + float _ask, float _bid) { // Should be overrided. } diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 97fe40b4a..86bb1a443 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1216,7 +1216,7 @@ class IndicatorData : public IndicatorBase { * This method allows user to modify the struct entry before it's added to cache. * This method is called on GetEntry() right after values are set. */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry) {} + virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) {} // virtual ENUM_IDATA_VALUE_RANGE GetIDataValueRange() = NULL; @@ -1948,4 +1948,8 @@ IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIn return new IndicatorBufferValueStorage(_indi, _mode); } +#ifndef __MQL__ +int GetBarsFromStart(IndicatorData* _indi) { return _indi PTR_DEREF GetBars(); } +#endif + #endif // INDICATOR_DATA_H diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 577b21068..69f319706 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -50,7 +50,8 @@ class IndicatorTf : public IndicatorCandle(iparams.GetSecsPerCandle(), THIS_PTR)); + THIS_ATTR history.SetItemProvider( + new ItemsHistoryTfCandleProvider(THIS_ATTR iparams.GetSecsPerCandle(), THIS_PTR)); } public: @@ -60,7 +61,7 @@ class IndicatorTf : public IndicatorCandle { /** * Called when new tick was emitted from IndicatorTick-based source. */ - virtual void OnTick(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _time_ms, - float _ask, float _bid) { + void OnTick(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _time_ms, float _ask, + float _bid) { ++tick_index; // Print("IndicatorTf's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index a9a602440..29c298696 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -65,12 +65,12 @@ class IndicatorTick : public Indicator { */ void Init() { // We can't index by shift. - flags &= ~INDI_FLAG_INDEXABLE_BY_SHIFT; + THIS_ATTR flags &= ~INDI_FLAG_INDEXABLE_BY_SHIFT; // We can only index via timestamp. - flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; + THIS_ATTR flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; // Ask and Bid price. - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); + THIS_ATTR Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), (int)2); history.SetItemProvider(new ItemsHistoryTickProvider(THIS_PTR)); } @@ -82,17 +82,17 @@ class IndicatorTick : public Indicator { * Class constructor. */ IndicatorTick(string _symbol, const TS& _itparams, const IndicatorDataParams& _idparams, - IndicatorBase* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_itparams, _idparams, _indi_src, _indi_mode) { + IndicatorData* _indi_src = NULL, int _indi_mode = 0) + : Indicator(_itparams, _idparams, _indi_src, _indi_mode) { itparams = _itparams; if (_indi_src != NULL) { - SetDataSource(_indi_src, _indi_mode); + THIS_ATTR SetDataSource(_indi_src, _indi_mode); } symbol = _symbol; Init(); } IndicatorTick(string _symbol, ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name) { + : Indicator(_itype, _shift, _name) { symbol = _symbol; Init(); } @@ -115,12 +115,18 @@ class IndicatorTick : public Indicator { /** * Gets ask price for a given date and time. Return current ask price if _dt wasn't passed or is 0. */ - virtual double GetAsk(int _shift = 0) { return GetEntryValue(INDI_TICK_MODE_PRICE_ASK, _shift).Get(); } + double GetAsk(int _shift = 0) override { + IndicatorDataEntryValue _entry = GetEntryValue(INDI_TICK_MODE_PRICE_ASK, _shift); + return _entry.Get(); + } /** * Gets bid price for a given date and time. Return current bid price if _dt wasn't passed or is 0. */ - virtual double GetBid(int _shift = 0) { return GetEntryValue(INDI_TICK_MODE_PRICE_BID, _shift).Get(); } + double GetBid(int _shift = 0) override { + IndicatorDataEntryValue _entry = GetEntryValue(INDI_TICK_MODE_PRICE_BID, _shift); + return _entry.Get(); + } /** * Returns value storage of given kind. @@ -150,7 +156,7 @@ class IndicatorTick : public Indicator { /** * Checks whether indicator support given value storage type. */ - virtual bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { + bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { switch (_type) { case INDI_VS_TYPE_PRICE_ASK: case INDI_VS_TYPE_PRICE_BID: @@ -158,6 +164,8 @@ class IndicatorTick : public Indicator { case INDI_VS_TYPE_VOLUME: case INDI_VS_TYPE_TICK_VOLUME: return true; + default: + break; } return Indicator::HasSpecificValueStorage(_type); diff --git a/Indicator/IndicatorTick.provider.h b/Indicator/IndicatorTick.provider.h index 16659088a..660b6f0ab 100644 --- a/Indicator/IndicatorTick.provider.h +++ b/Indicator/IndicatorTick.provider.h @@ -33,7 +33,7 @@ #include "../Storage/ItemsHistory.h" /** - * Regenerates candles and updates exising candles from new ticks. Subclasses by IndicatorTf, IndicatorRenko. + * Regenerates candles and updates existing candles from new ticks. Derived by IndicatorTf, IndicatorRenko. */ template class ItemsHistoryTickProvider : public ItemsHistoryItemProvider> { diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 4e75818ed..458b4dfcc 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -45,7 +45,7 @@ class IndicatorTfDummy : public IndicatorTf { public: IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} IndicatorTfDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTf(_tf) {} - IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi = 0) : IndicatorTf(_tfi) {} + IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi = (ENUM_TIMEFRAMES_INDEX)0) : IndicatorTf(_tfi) {} string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index d9df71a79..aa18f3b17 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -138,14 +138,14 @@ class Indi_BWMFI : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ - Print(GetVolume(_shift), ", ", GetVolume(_shift + 1), " | ", GetValue(BWMFI_BUFFER, _shift), " > ", - GetValue(BWMFI_BUFFER, _shift + 1)); + Print(GetVolume(_rel_shift), ", ", GetVolume(_rel_shift + 1), " | ", GetValue(BWMFI_BUFFER, _rel_shift), + " > ", GetValue(BWMFI_BUFFER, _rel_shift + 1)); // @see: https://en.wikipedia.org/wiki/Market_facilitation_index - bool _vol_up = GetVolume(_shift) > GetVolume(_shift + 1); - bool _val_up = GetValue(BWMFI_BUFFER, _shift) > GetValue(BWMFI_BUFFER, _shift + 1); + bool _vol_up = GetVolume(_rel_shift) > GetVolume(_rel_shift + 1); + bool _val_up = GetValue(BWMFI_BUFFER, _rel_shift) > GetValue(BWMFI_BUFFER, _rel_shift + 1); double _histcolor = EMPTY_VALUE; switch (_vol_up) { case true: diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 7fc7ffd19..e5b813c06 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -237,11 +237,11 @@ class Indi_Envelopes : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ // The LINE_MAIN only exists in MQL4 for Envelopes. - _entry.values[LINE_MAIN] = GetValue((ENUM_LO_UP_LINE)LINE_MAIN, _shift); + _entry.values[LINE_MAIN] = GetValue((ENUM_LO_UP_LINE)LINE_MAIN, _rel_shift); #endif } diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index 6e920d173..6f93e25f1 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -124,8 +124,8 @@ class Indi_Fractals : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ // In MT4 line identifiers starts from 1, so populating also at 0. _entry.values[0] = _entry.values[LINE_UPPER]; diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index cbec2fac4..712fc8108 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -200,8 +200,8 @@ class Indi_Gator : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ // @todo: Can we calculate upper and lower histogram color in MT4? // @see: https://docs.mql4.com/indicators/igator diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index 42878ac52..32c546990 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -164,16 +164,17 @@ class Indi_Ichimoku : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); + int _abs_shift = ToAbsShift(_rel_shift); #ifdef __MQL4__ // In MQL4 value of LINE_TENKANSEN is 1 (not 0 as in MQL5), // so we are duplicating it. - _entry.values[0] = GetEntryValue(LINE_TENKANSEN, _shift); + _entry.values[0] = GetEntryValue(LINE_TENKANSEN, _abs_shift); #endif - _entry.values[LINE_SENKOUSPANA] = GetEntryValue(LINE_SENKOUSPANA, _shift + GetKijunSen()); - _entry.values[LINE_SENKOUSPANB] = GetEntryValue(LINE_SENKOUSPANB, _shift + GetKijunSen()); - _entry.values[LINE_CHIKOUSPAN] = GetEntryValue(LINE_CHIKOUSPAN, _shift + GetKijunSen()); + _entry.values[LINE_SENKOUSPANA] = GetEntryValue(LINE_SENKOUSPANA, _abs_shift + GetKijunSen()); + _entry.values[LINE_SENKOUSPANB] = GetEntryValue(LINE_SENKOUSPANB, _abs_shift + GetKijunSen()); + _entry.values[LINE_CHIKOUSPAN] = GetEntryValue(LINE_CHIKOUSPAN, _abs_shift + GetKijunSen()); } /** diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h new file mode 100644 index 000000000..2cfc24437 --- /dev/null +++ b/Indicators/Tick/Indi_TickProvider.h @@ -0,0 +1,142 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Tick-based indicator which you may feed with data. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../../Indicator/IndicatorTick.h" +#include "../../Indicator/IndicatorTick.provider.h" + +// Structs. +// Params for MT patform's tick-based indicator. +struct Indi_TickProviderParams : IndicatorParams { + Indi_TickProviderParams() : IndicatorParams(INDI_TICK_RANDOM) {} +}; + +// MT platform's tick-based indicator. +class Indi_TickProvider : public IndicatorTick> { + private: + int current_index; + ARRAY(TickTAB, buffer); + + public: + Indi_TickProvider(Indi_TickProviderParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTick(_p.symbol, _p, + IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_TickProvider(string _symbol = NULL_STRING, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0, string _name = "") + : IndicatorTick(_symbol, Indi_TickProviderParams(), + IndicatorDataParams(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), _indi_src) { + Init(); + } + + /** + * Initializes the class. + */ + void Init() { current_index = 0; } + + string GetName() override { return "Indi_TickProvider"; } + + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + unsigned int GetSuitableDataSourceTypes() override { return INDI_SUITABLE_DS_TYPE_EXPECT_NONE; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } + + /** + * Returns the indicator's struct entry for the given shift. + */ + IndicatorDataEntry GetEntry(int _index = 0) override { + IndicatorDataEntry _default; + return _default; + } + + /** + * Fetches historic ticks for a given time range. + */ + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) override { + // No history. + return false; + } + + /** + * Feeds ticks buffer with given array of new ticks. + */ + void Feed(ARRAY_REF(TickTAB, _ticks)) { + for (int i = 0; i < ArraySize(_ticks); ++i) { + ArrayPush(buffer, _ticks[i]); + } + } + + int BufferSize() { return ArraySize(buffer); } + + void OnTick(int _global_tick_index) override { + if (current_index >= ArraySize(buffer)) { + // No more ticks. + return; + } + + TickTAB _tick = buffer[current_index++]; + + IndicatorDataEntry _entry(TickToEntry(_tick.GetTimestamp(), _tick)); + EmitEntry(_entry); + // Appending tick into the history. + AppendEntry(_entry); + } +}; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(Indi_TickProviderBase) { + emscripten::class_>>( + "IndiTickProviderBase"); +} + +EMSCRIPTEN_BINDINGS(Indi_TickProvider) { + emscripten::class_< + Indi_TickProvider, + emscripten::base>>>( + "Indi_TickProvider") + //.smart_ptr>("Ref") + .constructor<>() + .function("BufferSize", &Indi_TickProvider::BufferSize) + .function("Feed", &Indi_TickProvider::Feed); +} + +#endif diff --git a/Indicators/Tick/Indi_TickRandom.mqh b/Indicators/Tick/Indi_TickRandom.mqh index 56e8148c5..5f131e6dd 100644 --- a/Indicators/Tick/Indi_TickRandom.mqh +++ b/Indicators/Tick/Indi_TickRandom.mqh @@ -93,8 +93,8 @@ class Indi_TickRandom : public IndicatorTick _tick(, _bid); - IndicatorDataEntry _entry(TickToEntry(_time, _tick)); + TickAB _tick(_ask, _bid); + IndicatorDataEntry _entry(TickToEntry(TimeCurrent(), _tick)); EmitEntry(_entry); // Appending tick into the history. AppendEntry(_entry); diff --git a/Std.h b/Std.h index d214d3bf2..190ad3af6 100644 --- a/Std.h +++ b/Std.h @@ -230,6 +230,19 @@ class _cpp_array { void setIsSeries(bool _isSeries) { m_isSeries = _isSeries; } }; +#ifdef EMSCRIPTEN +#include + +#define REGISTER_ARRAY_OF(N, T, D) \ + EMSCRIPTEN_BINDINGS(N) { \ + emscripten::class_<_cpp_array>(D) \ + .constructor() \ + .function("Push", &_cpp_array::push) \ + .function("Size", &_cpp_array::size); \ + } + +#endif + template class _cpp_array; #endif diff --git a/Storage/ObjectsCache.h b/Storage/ObjectsCache.h index 0ca816fba..bb6cf6fac 100644 --- a/Storage/ObjectsCache.h +++ b/Storage/ObjectsCache.h @@ -42,7 +42,7 @@ class DictStructDestructable : public DictStruct { * Destructor. */ ~DictStructDestructable() { - for (DictStructIterator iter = Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator iter = THIS_ATTR Begin(); iter.IsValid(); ++iter) { delete iter.Value(); } } diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index c78b69880..722bf422e 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -38,6 +38,10 @@ class IndicatorData; template class ValueStorage; +#ifndef __MQL__ +extern int GetBarsFromStart(IndicatorData* _indi); +#endif + /** * Storage for direct access to indicator's buffer for a given mode. */ @@ -90,7 +94,11 @@ class HistoryValueStorage : public ValueStorage { if (!indi_candle.ObjectExists()) { return 0; } +#ifdef __MQL__ return indi_candle REF_DEREF GetBars(); +#else + return GetBarsFromStart(indi_candle.Ptr()); +#endif } /** diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 54c249bf6..e01ecdc42 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -31,7 +31,6 @@ #endif // Forward declarations. -class IndicatorData; template class HistoryValueStorage; @@ -53,11 +52,27 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { IndicatorBufferValueStorage(IndicatorData* _indi_candle, int _mode = 0, bool _is_series = false) : HistoryValueStorage(_indi_candle), mode(_mode) {} - /** - * Fetches value from a given shift. Takes into consideration as-series flag. - */ +/** + * Fetches value from a given shift. Takes into consideration as-series flag. + */ +#ifdef __MQL__ C Fetch(int _rel_shift) override { IndicatorData* _indi = THIS_ATTR indi_candle.Ptr(); return _indi PTR_DEREF GetValue(mode, THIS_ATTR RealShift(_rel_shift)); } +#else + C Fetch(int _rel_shift) override; +#endif }; + +// clang-format off +#include "../Indicator/IndicatorData.h" +// clang-format on + +#ifndef __MQL__ +template +C IndicatorBufferValueStorage::Fetch(int _rel_shift) { + IndicatorData* _indi = THIS_ATTR indi_candle.Ptr(); + return _indi PTR_DEREF GetValue(mode, THIS_ATTR RealShift(_rel_shift)); +} +#endif \ No newline at end of file diff --git a/Storage/ValueStorage.price_median.h b/Storage/ValueStorage.price_median.h index 3752af417..890ffee3e 100644 --- a/Storage/ValueStorage.price_median.h +++ b/Storage/ValueStorage.price_median.h @@ -39,12 +39,12 @@ class PriceMedianValueStorage : public HistoryValueStorage { /** * Constructor. */ - PriceMedianValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + PriceMedianValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - PriceMedianValueStorage(PriceMedianValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + PriceMedianValueStorage(PriceMedianValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.price_typical.h b/Storage/ValueStorage.price_typical.h index 4bf51f786..fe99eb869 100644 --- a/Storage/ValueStorage.price_typical.h +++ b/Storage/ValueStorage.price_typical.h @@ -36,12 +36,12 @@ class PriceTypicalValueStorage : public HistoryValueStorage { /** * Constructor. */ - PriceTypicalValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + PriceTypicalValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - PriceTypicalValueStorage(PriceTypicalValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + PriceTypicalValueStorage(PriceTypicalValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.price_weighted.h b/Storage/ValueStorage.price_weighted.h index 17818583e..91029acc4 100644 --- a/Storage/ValueStorage.price_weighted.h +++ b/Storage/ValueStorage.price_weighted.h @@ -36,12 +36,12 @@ class PriceWeightedValueStorage : public HistoryValueStorage { /** * Constructor. */ - PriceWeightedValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + PriceWeightedValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - PriceWeightedValueStorage(PriceWeightedValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + PriceWeightedValueStorage(PriceWeightedValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.spread.h b/Storage/ValueStorage.spread.h index 890b168a1..17510321e 100644 --- a/Storage/ValueStorage.spread.h +++ b/Storage/ValueStorage.spread.h @@ -36,12 +36,12 @@ class SpreadValueStorage : public HistoryValueStorage { /** * Constructor. */ - SpreadValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + SpreadValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - SpreadValueStorage(SpreadValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + SpreadValueStorage(SpreadValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.tick_volume.h b/Storage/ValueStorage.tick_volume.h index cc6dd5ec6..f2f6d699b 100644 --- a/Storage/ValueStorage.tick_volume.h +++ b/Storage/ValueStorage.tick_volume.h @@ -36,12 +36,12 @@ class TickVolumeValueStorage : public HistoryValueStorage { /** * Constructor. */ - TickVolumeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + TickVolumeValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - TickVolumeValueStorage(TickVolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + TickVolumeValueStorage(TickVolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.time.h b/Storage/ValueStorage.time.h index 67461a958..c2bdf2bf1 100644 --- a/Storage/ValueStorage.time.h +++ b/Storage/ValueStorage.time.h @@ -37,12 +37,12 @@ class TimeValueStorage : public HistoryValueStorage { /** * Constructor. */ - TimeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + TimeValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - TimeValueStorage(TimeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + TimeValueStorage(TimeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.volume.h b/Storage/ValueStorage.volume.h index 68d5320ba..17072e40e 100644 --- a/Storage/ValueStorage.volume.h +++ b/Storage/ValueStorage.volume.h @@ -36,12 +36,12 @@ class VolumeValueStorage : public HistoryValueStorage { /** * Constructor. */ - VolumeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + VolumeValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - VolumeValueStorage(VolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + VolumeValueStorage(VolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index fb27ecbfa..2a4b5df7f 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -76,6 +76,8 @@ struct TickAB { TickAB(MqlTick &_tick) : ask((T)_tick.ask), bid((T)_tick.bid) {} }; +struct DoubleTickAB : TickAB {}; + /** * Structure for storing ask and bid prices of the symbol. */ @@ -92,6 +94,11 @@ struct TickTAB : TickAB { */ long GetTimeMs() { return time_ms; } + /** + * Returns time as timestamp (in seconds). + */ + long GetTimestamp() { return time_ms; } + /** * Method used by ItemsHistory. */ @@ -100,3 +107,26 @@ struct TickTAB : TickAB { return 0; } }; + +struct DoubleTickTAB : TickTAB {}; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TickAB) { + emscripten::value_object>("TickAB") + .field("ask", &TickAB::ask) + .field("bid", &TickAB::bid); +} + +EMSCRIPTEN_BINDINGS(TickTAB) { + // emscripten::value_object, emscripten::base>>("TickTABDouble") + emscripten::value_object>("TickTAB") + .field("ask", &TickAB::ask) + .field("bid", &TickAB::bid) + .field("time_ms", &TickTAB::time_ms); +} + +REGISTER_ARRAY_OF(ArrayTickTABDouble, TickTAB, "TickTABArray"); + +#endif From 16ebdc4ef4c3db51969b980fbe92fc76c60f3726 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 24 Feb 2023 15:10:08 +0100 Subject: [PATCH 069/123] Fixing MQL4 errors. --- Candle.struct.h | 14 ++++++++++++++ Storage/ValueStorage.indicator.h | 2 +- Tick/Tick.struct.h | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Candle.struct.h b/Candle.struct.h index 1e0123a21..360e5d1da 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -257,7 +257,9 @@ struct CandleOCTOHLC : CandleOHLC { // Virtual destructor. Required because of Emscripted warning, despite structure has no virtual methods: // warning: destructor called on non-final 'CandleOCTOHLC' that has virtual functions but non-virtual // destructor [-Wdelete-non-abstract-non-virtual-dtor] +#ifndef __MQL__ virtual ~CandleOCTOHLC() {} +#endif /** * Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price. @@ -370,7 +372,11 @@ struct CandleTOHLC : CandleOHLC { /* Method to serialize CandleEntry structure. */ template +#ifdef __MQL__ +SerializerNodeType CandleOHLC::Serialize(Serializer &s) { +#else SerializerNodeType CandleOHLC::Serialize(Serializer &s) { +#endif // s.Pass(THIS_REF, "time", TimeToString(time)); s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); @@ -381,7 +387,11 @@ SerializerNodeType CandleOHLC::Serialize(Serializer &s) { /* Method to serialize CandleEntry structure. */ template +#ifdef __MQL__ +SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { +#else SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { +#endif s.Pass(THIS_REF, "time", time); s.Pass(THIS_REF, "open", THIS_ATTR open, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "high", THIS_ATTR high, SERIALIZER_FIELD_FLAG_DYNAMIC); @@ -392,7 +402,11 @@ SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { /* Method to serialize CandleEntry structure. */ template +#ifdef __MQL__ +SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { +#else SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { +#endif s.Pass(THIS_REF, "is_complete", is_complete, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "open_timestamp_ms", open_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "close_timestamp_ms", close_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index e01ecdc42..eb52f8b21 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -75,4 +75,4 @@ C IndicatorBufferValueStorage::Fetch(int _rel_shift) { IndicatorData* _indi = THIS_ATTR indi_candle.Ptr(); return _indi PTR_DEREF GetValue(mode, THIS_ATTR RealShift(_rel_shift)); } -#endif \ No newline at end of file +#endif diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 2a4b5df7f..4493d31ce 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -31,6 +31,7 @@ // Includes. #include "../DateTime.extern.h" +#include "../Std.h" #ifndef __MQL__ /** From 65b8f294cf927570686bcd925d19ad7e537d12e4 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Sat, 25 Feb 2023 04:51:25 +0100 Subject: [PATCH 070/123] WIP. Fixing MT4 errors. --- Indicator/Indicator.define.h | 52 ++++++++++++++--------------- Indicator/IndicatorData.h | 11 +++--- Indicator/IndicatorData.struct.h | 4 ++- Indicators/Indi_AC.mqh | 21 +++++++----- Indicators/Indi_RSI.mqh | 36 -------------------- Indicators/Tick/Indi_TickProvider.h | 2 +- Indicators/Tick/Indi_TickRandom.mqh | 2 +- Object.enum.h | 3 ++ Object.extern.h | 3 ++ Platform.extern.h | 3 ++ Platform.h | 16 +++++---- Socket.mqh | 4 +-- Storage/Objects.h | 8 ++--- SymbolInfo.struct.static.h | 5 ++- 14 files changed, 77 insertions(+), 93 deletions(-) diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index d0e2900df..26d7142ea 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -100,32 +100,32 @@ #define EMPTY_VALUE DBL_MAX #endif -#define INDICATOR_BUILTIN_CALL_AND_RETURN(NATIVE_METHOD_CALL, MODE, SHIFT) \ - int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; \ - double _res[]; \ - ResetLastError(); \ - if (_handle == NULL || _handle == INVALID_HANDLE) { \ - if ((_handle = NATIVE_METHOD_CALL) == INVALID_HANDLE) { \ - SetUserError(ERR_USER_INVALID_HANDLE); \ - return EMPTY_VALUE; \ - } else if (Object::IsValid(_obj)) { \ - _obj.SetHandle(_handle); \ - } \ - } \ - if (Terminal::IsVisualMode()) { \ - /* To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), */ \ - /* we check the number of calculated data only in visual mode. */ \ - int _bars_calc = BarsCalculated(_handle); \ - if (GetLastError() > 0) { \ - return EMPTY_VALUE; \ - } else if (_bars_calc <= 2) { \ - SetUserError(ERR_USER_INVALID_BUFF_NUM); \ - return EMPTY_VALUE; \ - } \ - } \ - if (CopyBuffer(_handle, MODE, SHIFT, 1, _res) < 0) { \ - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; \ - } \ +#define INDICATOR_BUILTIN_CALL_AND_RETURN(NATIVE_METHOD_CALL, MODE, SHIFT) \ + int _handle = Object::IsValid(_obj) ? _obj PTR_DEREF Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : 0; \ + ARRAY(double, _res); \ + ResetLastError(); \ + if (_handle == 0 || _handle == INVALID_HANDLE) { \ + if ((_handle = NATIVE_METHOD_CALL) == INVALID_HANDLE) { \ + SetUserError(ERR_USER_INVALID_HANDLE); \ + return EMPTY_VALUE; \ + } else if (Object::IsValid(_obj)) { \ + _obj.SetHandle(_handle); \ + } \ + } \ + if (Terminal::IsVisualMode()) { \ + /* To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), */ \ + /* we check the number of calculated data only in visual mode. */ \ + int _bars_calc = BarsCalculated(_handle); \ + if (GetLastError() > 0) { \ + return EMPTY_VALUE; \ + } else if (_bars_calc <= 2) { \ + SetUserError(ERR_USER_INVALID_BUFF_NUM); \ + return EMPTY_VALUE; \ + } \ + } \ + if (CopyBuffer(_handle, MODE, SHIFT, 1, _res) < 0) { \ + return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; \ + } \ return _res[0]; #define INDI_REQUIRE_BARS_OR_RETURN(_indi, _period, _ret) \ diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 86bb1a443..ad1e5dc55 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1351,8 +1351,7 @@ class IndicatorData : public IndicatorBase { * Returns value storage to be used for given applied price or applied price overriden by target indicator via * SetDataSourceAppliedPrice(). */ - virtual ValueStorage* GetSpecificAppliedPriceValueStorage(ENUM_APPLIED_PRICE _ap, - IndicatorData* _target = nullptr) { + ValueStorage* GetSpecificAppliedPriceValueStorage(ENUM_APPLIED_PRICE _ap, IndicatorData* _target = nullptr) { if (_target != nullptr) { if (_target PTR_DEREF GetDataSourceAppliedType() != INDI_VS_TYPE_NONE) { // User wants to use custom value storage type as applied price, so we forcefully override AP given as the @@ -1448,15 +1447,13 @@ class IndicatorData : public IndicatorBase { /** * Fetches historic ticks for a given time range. */ - virtual bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { - return false; - } + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { return false; } /** * Fetches historic ticks for a given start time and minimum number of tick to retrieve. */ - virtual bool FetchHistoryByStartTimeAndCount(long _from_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _min_count, - ARRAY_REF(TickTAB, _out_ticks)) { + bool FetchHistoryByStartTimeAndCount(long _from_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _min_count, + ARRAY_REF(TickTAB, _out_ticks)) { // Print("FetchHistoryByStartTimeAndCount:"); // Print("- Requested _from_ms = ", _from_ms, ", _dir = ", EnumToString(_dir), ", _min_count = ", _min_count); diff --git a/Indicator/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h index 549c44219..66f137cf1 100644 --- a/Indicator/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -30,6 +30,7 @@ #define STRUCT_ENUM_INDICATOR_STATE_PROP STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) // Includes. +#include "../Serializer/SerializerConversions.h" #include "../Serializer/SerializerNode.enum.h" #include "IndicatorData.enum.h" @@ -389,7 +390,8 @@ struct IndicatorDataEntry { int _asize = ArraySize(values); string _result = ""; for (int i = 0; i < _asize; i++) { - _result += StringFormat("%s%s", (string)values[i].Get(), i < _asize ? "," : ""); + _result += + StringFormat("%s%s", C_STR(SerializerConversions::ValueToString(values[i].Get())), i < _asize ? "," : ""); } return _result; } diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index d51e1e7b2..ce3b3fb78 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -20,18 +20,15 @@ * */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. #include "../BufferStruct.mqh" #include "../Indicator/Indicator.h" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compability). -double iAC(string _symbol, int _tf, int _shift) { - ResetLastError(); - return Indi_AC::iAC(_symbol, (ENUM_TIMEFRAMES)_tf, _shift); -} -#endif - // Structs. struct IndiACParams : IndicatorParams { // Struct constructor. @@ -139,3 +136,11 @@ class Indi_AC : public Indicator { return _ptr; } }; + +#ifndef __MQL4__ +// Defines global functions (for MQL4 backward compability). +double iAC(string _symbol, int _tf, int _shift) { + ResetLastError(); + return Indi_AC::iAC(_symbol, (ENUM_TIMEFRAMES)_tf, _shift); +} +#endif diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 5aacd6181..2c4b409be 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -23,12 +23,6 @@ // Includes. #include "../DictStruct.mqh" #include "../Indicator/Indicator.h" -#include "Indi_Bands.mqh" -#include "Indi_CCI.mqh" -#include "Indi_Envelopes.mqh" -#include "Indi_MA.mqh" -#include "Indi_Momentum.mqh" -#include "Indi_StdDev.mqh" #include "Price/Indi_Price.mqh" #ifndef __MQL4__ @@ -336,34 +330,4 @@ class Indi_RSI : public Indicator { } return _value; } - - /** - * Provides built-in indicators whose can be used as data source. - */ - virtual IndicatorData *FetchDataSource(ENUM_INDICATOR_TYPE _id) { - if (_id == INDI_BANDS) { - IndiBandsParams bands_params; - return new Indi_Bands(bands_params); - } else if (_id == INDI_CCI) { - IndiCCIParams cci_params; - return new Indi_CCI(cci_params); - } else if (_id == INDI_ENVELOPES) { - IndiEnvelopesParams env_params; - return new Indi_Envelopes(env_params); - } else if (_id == INDI_MOMENTUM) { - IndiMomentumParams mom_params; - return new Indi_Momentum(mom_params); - } else if (_id == INDI_MA) { - IndiMAParams ma_params; - return new Indi_MA(ma_params); - } else if (_id == INDI_RSI) { - IndiRSIParams _rsi_params; - return new Indi_RSI(_rsi_params); - } else if (_id == INDI_STDDEV) { - IndiStdDevParams stddev_params; - return new Indi_StdDev(stddev_params); - } - - return IndicatorData::FetchDataSource(_id); - } }; diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h index 2cfc24437..389c6b2b1 100644 --- a/Indicators/Tick/Indi_TickProvider.h +++ b/Indicators/Tick/Indi_TickProvider.h @@ -89,7 +89,7 @@ class Indi_TickProvider : public IndicatorTick, _out_ticks)) override { + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { // No history. return false; } diff --git a/Indicators/Tick/Indi_TickRandom.mqh b/Indicators/Tick/Indi_TickRandom.mqh index 5f131e6dd..9d5763bf8 100644 --- a/Indicators/Tick/Indi_TickRandom.mqh +++ b/Indicators/Tick/Indi_TickRandom.mqh @@ -85,7 +85,7 @@ class Indi_TickRandom : public IndicatorTick, _out_ticks)) { + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { // No history. return false; } diff --git a/Object.enum.h b/Object.enum.h index 68d22f513..04d83c42b 100644 --- a/Object.enum.h +++ b/Object.enum.h @@ -26,6 +26,9 @@ */ #ifndef __MQLBUILD__ + +#pragma once + // Used for checking the type of the object pointer. // @docs // - https://docs.mql4.com/constants/namedconstants/enum_pointer_type diff --git a/Object.extern.h b/Object.extern.h index 8490e9499..68f44de50 100644 --- a/Object.extern.h +++ b/Object.extern.h @@ -28,6 +28,9 @@ #pragma once +// Includes. +#include "Object.enum.h" + template X* GetPointer(X& value) { return &value; diff --git a/Platform.extern.h b/Platform.extern.h index 8f6e8e7cf..fabde3d0b 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -25,7 +25,10 @@ #pragma once // Includes. +#include "Account/Account.enum.h" +#include "Data.define.h" #include "Deal.enum.h" +#include "Object.extern.h" #include "Order.define.h" #include "Terminal.enum.h" diff --git a/Platform.h b/Platform.h index a2408db20..349817853 100644 --- a/Platform.h +++ b/Platform.h @@ -359,7 +359,7 @@ class Platform { }; bool Platform::initialized = false; -DateTime Platform::time = 0; +DateTime Platform::time = (datetime)0; unsigned int Platform::time_flags = 0; bool Platform::time_clear_flags = true; int Platform::global_tick_index = 0; @@ -385,9 +385,13 @@ int BarsCalculated(int indicator_handle) { return Platform::BarsCalculated(indic */ int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; } -unsigned long PositionGetTicket(int _index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); } +unsigned long PositionGetTicket(int _index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); @@ -573,20 +577,20 @@ long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id) { string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); - return false; + return ""; } string Symbol() { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); - return false; + return ""; } -string ObjectName(long _chart_id, int _pos, int _sub_window = -1, int _type = -1) { +string ObjectName(long _chart_id, int _pos, int _sub_window, int _type) { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); return ""; } -int ObjectsTotal(long chart_id, int type = EMPTY, int window = -1) { +int ObjectsTotal(long chart_id, int type, int window) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } diff --git a/Socket.mqh b/Socket.mqh index be44e54f6..e1023634d 100644 --- a/Socket.mqh +++ b/Socket.mqh @@ -121,7 +121,7 @@ class Socket { return true; #else return false; -#endif; +#endif } /** @@ -184,7 +184,7 @@ class Socket { } #else return false; -#endif; +#endif } /** diff --git a/Storage/Objects.h b/Storage/Objects.h index 3be674f54..3af152e0f 100644 --- a/Storage/Objects.h +++ b/Storage/Objects.h @@ -49,12 +49,12 @@ class Objects { * Tries to retrieve pointer to object for a given key. Returns true if object did exist. */ static bool TryGet(CONST_REF_TO(string) key, C*& out_ptr) { - int position; - if (!GetObjects().KeyExists(key, position)) { + unsigned int position; + if (!GetObjects() PTR_DEREF KeyExists(key, position)) { out_ptr = NULL; return false; } else { - out_ptr = GetObjects().GetByPos(position).Ptr(); + out_ptr = GetObjects() PTR_DEREF GetByPos(position).Ptr(); return true; } } @@ -64,7 +64,7 @@ class Objects { */ static C* Set(CONST_REF_TO(string) key, C* ptr) { Ref _ref(ptr); - GetObjects().Set(key, _ref); + GetObjects() PTR_DEREF Set(key, _ref); return ptr; } }; diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index 72bb18844..5100e7f70 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -27,7 +27,10 @@ #include "MQL5.mqh" #include "Order.enum.h" +#include "Platform.extern.h" #include "Std.h" +#include "SymbolInfo.enum.h" +#include "SymbolInfo.extern.h" #include "Tick/Tick.struct.h" /** @@ -38,7 +41,7 @@ struct SymbolInfoStatic { /** * Get the current symbol pair from the current chart. */ - static string GetCurrentSymbol() { return _Symbol; } + static string GetCurrentSymbol() { return ::Symbol(); } /** * Updates and gets the latest tick prices. From 478b640130a922d1a0bca056a8eb14b2c7a4f75e Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 1 Mar 2023 19:10:02 +0100 Subject: [PATCH 071/123] WIP. Testing RSI over IndicatorTfDummy over Indi_TickProvider. Now we need to implement missing extern functions. --- Array.extern.h | 5 +++ Indicator/IndicatorData.h | 26 +++++++++++--- Indicator/tests/classes/Indicators.h | 8 +++-- Indicators/Indi_Drawer.mqh | 4 +-- Indicators/Indi_PriceFeeder.mqh | 6 ++-- Indicators/Indi_RSI.mqh | 54 ++++++++++++++++------------ Indicators/Price/Indi_Price.mqh | 24 ++++++------- Indicators/Tick/Indi_TickMt.mqh | 6 ++-- Indicators/Tick/Indi_TickProvider.h | 6 ++-- Indicators/Tick/Indi_TickRandom.mqh | 4 ++- Platform.h | 41 ++++++++++++++++++--- SymbolInfo.extern.h | 8 ++++- 12 files changed, 135 insertions(+), 57 deletions(-) diff --git a/Array.extern.h b/Array.extern.h index 821a5c751..675b26ca1 100644 --- a/Array.extern.h +++ b/Array.extern.h @@ -50,6 +50,11 @@ bool ArraySetAsSeries(ARRAY_REF(T, _array), bool _flag) { return true; } +template +bool ArrayGetAsSeries(ARRAY_REF(T, _array)) { + return _array.getIsSeries(); +} + template int ArrayMaximum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index ad1e5dc55..cb784124f 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -67,6 +67,7 @@ class IndicatorData : public IndicatorBase { int last_tick_index; // Index of the last tick. long first_tick_time_ms; // Time of the first ask/bid tick. void* mydata; + bool last_tick_result; // Result of the last Tick() invocation. ENUM_INDI_VS_TYPE retarget_ap_av; // Value storage type to be used as applied price/volume. ARRAY(Ref, value_storages); ARRAY(WeakRef, listeners); // List of indicators that listens for events from this one. @@ -865,10 +866,10 @@ class IndicatorData : public IndicatorBase { HasSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME); } - void Tick(int _global_tick_index) { + bool Tick(int _global_tick_index) { if (last_tick_index == _global_tick_index) { // We've already ticked. - return; + return last_tick_result; } if (_global_tick_index == 0) { @@ -884,13 +885,24 @@ class IndicatorData : public IndicatorBase { GetDataSource() PTR_DEREF Tick(_global_tick_index); } + last_tick_result = false; + // Also ticking all used indicators if they've not yet ticked. for (DictStructIterator> iter = indicators.Begin(); iter.IsValid(); ++iter) { - iter.Value() REF_DEREF Tick(_global_tick_index); + // If any of the attached indicators ticks then we signal that the tick happened, even if this indicator doesn't + // tick. It is because e.g., RSI could use Candle indicator and Candle could use Tick indicator. Ticking RSI + // doesn't signal tick in RSI, nor Candle, but only Tick indicator and only if new tick occured in the Tick + // indicator. In other words: Only Tick indicator returns true in its OnTick(). Also, in OnTick() it sends a tick + // into Candle indicator which aggregates ticks. RSI doesn't have OnTick() and we can't know if there is new RSI + // value. The only way to know that is to Tick all indicators in hierarchy and if one of them returns true in + // OnTick() then we know that we have new value for RSI. + last_tick_result |= iter.Value() REF_DEREF Tick(_global_tick_index); } // Overridable OnTick() method. - OnTick(_global_tick_index); + last_tick_result |= OnTick(_global_tick_index); + + return last_tick_result; } /** @@ -1835,7 +1847,11 @@ class IndicatorData : public IndicatorBase { /** * Called when new tick is retrieved from attached data source. */ - virtual void OnTick(int _global_tick_index) {} + virtual bool OnTick(int _global_tick_index) { + // We really don't know if new tick have happened. Let's just return false and let the Platform's Tick() method tick + // the Tick indicator in order to know if new tick was signalled. + return false; + } /** * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h index 871d059a3..f5676139d 100644 --- a/Indicator/tests/classes/Indicators.h +++ b/Indicator/tests/classes/Indicators.h @@ -53,12 +53,14 @@ class Indicators { int Size() { return (int)_indis.Size(); } + void Clear() { _indis.Clear(); } + /** * Executes OnTick() on every added indicator. */ void Tick(int _global_tick_index) { for (unsigned int i = 0; i < _indis.Size(); ++i) { - _indis[i].Ptr().OnTick(_global_tick_index); + _indis[i].Ptr() PTR_DEREF OnTick(_global_tick_index); } } @@ -68,8 +70,8 @@ class Indicators { string ToString(int _shift = 0) { string _result; for (unsigned int i = 0; i < _indis.Size(); ++i) { - IndicatorDataEntry _entry = _indis[i].Ptr().GetEntry(_shift); - _result += _indis[i].Ptr().GetFullName() + " = " + _entry.ToString() + "\n"; + IndicatorDataEntry _entry = _indis[i].Ptr() PTR_DEREF GetEntry(_shift); + _result += _indis[i].Ptr() PTR_DEREF GetFullName() + " = " + _entry.ToString() + "\n"; } return _result; } diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index d12dc6368..830284920 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -114,8 +114,8 @@ class Indi_Drawer : public Indicator { /** * Called when new tick is retrieved from attached data source. */ - void OnTick(int _global_tick_index) override { - Indicator::OnTick(_global_tick_index); + bool OnTick(int _global_tick_index) override { + return Indicator::OnTick(_global_tick_index); /* @fixme TaskActionEntry action(INDI_ACTION_SET_VALUE); diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index be3fbd9d4..78cc64f16 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -100,8 +100,8 @@ class Indi_PriceFeeder : public Indicator { /** * Called when new tick is retrieved from attached data source. */ - void OnTick(int _global_tick_index) override { - Indicator::OnTick(_global_tick_index); + bool OnTick(int _global_tick_index) override { + bool _result = Indicator::OnTick(_global_tick_index); if (idparams.IsDrawing()) { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); @@ -110,5 +110,7 @@ class Indi_PriceFeeder : public Indicator { // draw.DrawLineTo(GetName() + "_" + IntegerToString(i), GetBarTime(0), _entry.values[i].GetDbl()); } } + + return _result; } }; diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 2c4b409be..aa1a4a5f1 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -25,18 +25,6 @@ #include "../Indicator/Indicator.h" #include "Price/Indi_Price.mqh" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compability). -double iRSI(string _symbol, int _tf, int _period, int _ap, int _shift) { - ResetLastError(); - return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); -} -double iRSIOnArray(double &_arr[], int _total, int _period, int _abs_shift) { - ResetLastError(); - return Indi_RSI::iRSIOnArray(_arr, _total, _period, _abs_shift); -} -#endif - // Structs. struct IndiRSIParams : IndicatorParams { protected: @@ -45,14 +33,14 @@ struct IndiRSIParams : IndicatorParams { public: IndiRSIParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : applied_price(_ap), IndicatorParams(INDI_RSI) { + : IndicatorParams(INDI_RSI), applied_price(_ap) { shift = _shift; SetCustomIndicatorName("Examples\\RSI"); SetPeriod(_period); }; IndiRSIParams(IndiRSIParams &_params) { THIS_REF = _params; }; // Getters. - ENUM_APPLIED_PRICE GetAppliedPrice() override { return applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return applied_price; } int GetPeriod() { return period; } // Setters. void SetPeriod(int _period) { period = _period; } @@ -126,8 +114,13 @@ class Indi_RSI : public Indicator { ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iRSI(_symbol, _tf, _period, _applied_price, _shift); -#else // __MQL5__ +#elif __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iRSI(_symbol, _tf, _period, _applied_price), 0, _shift); +#else + RUNTIME_ERROR( + "In C++ Indi_RSI::iRSI() method couldn't be used directly. Please use an On-Indicator mode and attach " + "indicator via Platform::Add/AddWithDefaultBindings()."); + return DBL_MAX; #endif } @@ -140,13 +133,14 @@ class Indi_RSI : public Indicator { ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, Indi_RSI *_obj = NULL) { int i; - double indi_values[]; + ARRAY(double, indi_values); ArrayResize(indi_values, _period); double result; for (i = _shift; i < (int)_shift + (int)_period; i++) { - indi_values[_shift + _period - (i - _shift) - 1] = _indi[i][_obj.GetParams().indi_mode]; + indi_values[_shift + _period - (i - _shift) - 1] = + _indi PTR_DEREF GetSpecificAppliedPriceValueStorage(_applied_price) PTR_DEREF Fetch(i); } result = iRSIOnArray(indi_values, 0, _period - 1, 0); @@ -159,7 +153,7 @@ class Indi_RSI : public Indicator { * * @see https://school.stockcharts.com/doku.php?id=technical_indicators:relative_strength_index_rsi * - * Reson behind iRSI with SSMA and not just iRSIOnArray() (from above website): + * Reason behind iRSI with SMMA and not just iRSIOnArray() (from above website): * * "Taking the prior value plus the current value is a smoothing technique * similar to that used in calculating an exponential moving average. This @@ -182,7 +176,7 @@ class Indi_RSI : public Indicator { } int i; - double indi_values[]; + ARRAY(double, indi_values); ArrayResize(indi_values, _period); double result; @@ -238,7 +232,7 @@ class Indi_RSI : public Indicator { new_data.avg_gain = (last_data.avg_gain * (_period - 1) + curr_gain) / _period; new_data.avg_loss = (last_data.avg_loss * (_period - 1) + curr_loss) / _period; - _target.aux_data.Set(_bar_time_curr, new_data); + _target PTR_DEREF aux_data.Set(_bar_time_curr, new_data); if (new_data.avg_loss == 0.0) { // @fixme Why 0 loss? @@ -255,7 +249,7 @@ class Indi_RSI : public Indicator { /** * Calculates RSI on the array of values. */ - static double iRSIOnArray(double &array[], int total, int period, int shift) { + static double iRSIOnArray(ARRAY_REF(double, array), int total, int period, int shift) { #ifdef __MQL4__ return ::iRSIOnArray(array, total, period, shift); #else @@ -308,9 +302,9 @@ class Indi_RSI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override { double _value = EMPTY_VALUE; - double _res[]; + ARRAY(double, _res); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_RSI::iRSI(GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), @@ -327,7 +321,21 @@ class Indi_RSI : public Indicator { _value = Indi_RSI::iRSIOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), ToRelShift(_abs_shift)); break; + default: + RUNTIME_ERROR("Invalid indicator IDATA_* type!"); } return _value; } }; + +#ifndef __MQL4__ +// Defines global functions (for MQL4 backward compability). +double iRSI(string _symbol, int _tf, int _period, int _ap, int _shift) { + ResetLastError(); + return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); +} +double iRSIOnArray(ARRAY_REF(double, _arr), int _total, int _period, int _abs_shift) { + ResetLastError(); + return Indi_RSI::iRSIOnArray(_arr, _total, _period, _abs_shift); +} +#endif diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index 64d4791a9..91dd3811a 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -30,12 +30,12 @@ struct PriceIndiParams : IndicatorParams { ENUM_APPLIED_PRICE ap; // Struct constructor. - PriceIndiParams(ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) : ap(_ap), IndicatorParams(INDI_PRICE) { + PriceIndiParams(ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) : IndicatorParams(INDI_PRICE), ap(_ap) { SetShift(_shift); }; - PriceIndiParams(PriceIndiParams &_params) { THIS_REF = _params; }; + PriceIndiParams(PriceIndiParams &_params) : IndicatorParams() { THIS_REF = _params; }; // Getters. - ENUM_APPLIED_PRICE GetAppliedPrice() override { return ap; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return ap; } // Setters. void SetAppliedPrice(ENUM_APPLIED_PRICE _ap) { ap = _ap; } }; @@ -60,7 +60,7 @@ class Indi_Price : public Indicator { /** * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. */ - virtual unsigned int GetSuitableDataSourceTypes() { + unsigned int GetSuitableDataSourceTypes() override { // We can work only with Candle-based indicator attached. return INDI_SUITABLE_DS_TYPE_CANDLE; } @@ -111,21 +111,21 @@ class Indi_Price : public Indicator { case INDI_VS_TYPE_PRICE_ASK: // Tick. case INDI_VS_TYPE_PRICE_BID: // Tick. return GetPlatformPrices(GetSymbol(), iparams.GetAppliedPrice(), GetTf(), iparams.GetShift()) - .GetValueStorage(0); + PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_OPEN: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_OPEN, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_OPEN, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_HIGH: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_HIGH, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_HIGH, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_LOW: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_LOW, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_LOW, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_CLOSE: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_CLOSE, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_CLOSE, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_MEDIAN: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_MEDIAN, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_MEDIAN, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_TYPICAL: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_TYPICAL, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_TYPICAL, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_WEIGHTED: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_WEIGHTED, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_WEIGHTED, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); default: // Trying in parent class. return Indicator::GetSpecificValueStorage(_type); diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 39d588861..b87bdf585 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -154,7 +154,7 @@ class Indi_TickMt : public IndicatorTick= ArraySize(buffer)) { // No more ticks. - return; + return false; } TickTAB _tick = buffer[current_index++]; @@ -117,6 +117,8 @@ class Indi_TickProvider : public IndicatorTick _tick(_ask, _bid); @@ -98,5 +98,7 @@ class Indi_TickRandom : public IndicatorTick> indis_dflt; + // Result of the last tick. + static bool last_tick_result; + public: /** * Initializes platform. @@ -113,12 +116,14 @@ class Platform { DictStructIterator> _iter; + last_tick_result = false; + for (_iter = indis.Begin(); _iter.IsValid(); ++_iter) { - _iter.Value() REF_DEREF Tick(global_tick_index); + last_tick_result |= _iter.Value() REF_DEREF Tick(global_tick_index); } for (_iter = indis_dflt.Begin(); _iter.IsValid(); ++_iter) { - _iter.Value() REF_DEREF Tick(global_tick_index); + last_tick_result |= _iter.Value() REF_DEREF Tick(global_tick_index); } // Will check for new time periods in consecutive Platform::UpdateTime(). @@ -128,6 +133,11 @@ class Platform { ++global_tick_index; } + /** + * Checks whether we had a tick inside previous Tick() invocation. + */ + static bool HadTick() { return last_tick_result; } + /** * Returns dictionary of added indicators (keyed by unique id). */ @@ -359,6 +369,7 @@ class Platform { }; bool Platform::initialized = false; +bool Platform::last_tick_result = false; DateTime Platform::time = (datetime)0; unsigned int Platform::time_flags = 0; bool Platform::time_clear_flags = true; @@ -650,11 +661,33 @@ bool ObjectDelete(long chart_id, string name) { int GetLastError() { return _LastError; } +void ResetLastError() { _LastError = 0; } + int ObjectFind(long chart_id, string name) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } +bool TimeToStruct(datetime dt, MqlDateTime &dt_struct) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +SymbolGetter::operator string() { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return ""; +} + +ENUM_TIMEFRAMES Period() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return (ENUM_TIMEFRAMES)0; +} + +datetime StructToTime(MqlDateTime &dt_struct) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty datetime (0)."); + return (datetime)0; +} + #endif /** diff --git a/SymbolInfo.extern.h b/SymbolInfo.extern.h index 60b085d5b..f31450b70 100644 --- a/SymbolInfo.extern.h +++ b/SymbolInfo.extern.h @@ -27,11 +27,17 @@ // Define external global functions. #ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once + extern long SymbolInfoInteger(string name, ENUM_SYMBOL_INFO_INTEGER prop_id); extern bool SymbolInfoMarginRate(string name, ENUM_ORDER_TYPE order_type, double &initial_margin_rate, double &maintenance_margin_rate); extern bool SymbolInfoTick(string symbol, MqlTick &tick); // Define external global variables. -extern string _Symbol; +class SymbolGetter { + public: + operator string(); +} _Symbol; #endif From 30d6f7fbbd68eb4dab41cd9855adafd582fa8a8c Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 2 Mar 2023 19:04:26 +0100 Subject: [PATCH 072/123] WIP. Testing RSI over IndicatorTfDummy over Indi_TickProvider. RSI returns values. It's good! --- DateTime.extern.h | 15 +- DictBase.mqh | 1 + Indicator/Indicator.h | 1 + Indicator/IndicatorCandle.h | 2 +- Indicator/IndicatorTf.h | 24 +-- Indicator/IndicatorTf.struct.h | 22 ++- Indicator/tests/classes/IndicatorTfDummy.h | 17 +- Indicators/Tick/Indi_TickProvider.h | 5 +- Platform.define.h | 30 +++ Platform.extern.h | 58 +++--- Platform.h | 219 ++++++++++++++++----- PlatformTime.h | 22 +-- Serializer/SerializerConverter.h | 8 +- Serializer/SerializerCsv.h | 2 +- Std.h | 2 + Tick/Tick.struct.h | 26 +-- 16 files changed, 301 insertions(+), 153 deletions(-) create mode 100644 Platform.define.h diff --git a/DateTime.extern.h b/DateTime.extern.h index 1ffb17098..2f3bd3526 100644 --- a/DateTime.extern.h +++ b/DateTime.extern.h @@ -44,7 +44,7 @@ class datetime { public: datetime() { dt = 0; } - datetime(const long& _time) { dt = _time; } + datetime(const int64& _time) { dt = _time; } // datetime(const int& _time); bool operator==(const int _time) const = delete; bool operator==(const datetime& _time) const { return dt == _time; } @@ -52,7 +52,7 @@ class datetime { bool operator>(const int _time) const = delete; bool operator<(const datetime& _time) const { return dt < _time; } bool operator>(const datetime& _time) const { return dt > _time; } - operator long() const { return dt; } + operator int64() const { return dt; } }; extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, @@ -71,16 +71,7 @@ extern datetime TimeGMT(MqlDateTime& dt_struct); extern datetime TimeTradeServer(); extern datetime TimeTradeServer(MqlDateTime& dt_struct); extern datetime StringToTime(const string& value); -string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES) { - /* - auto now = std::chrono::time_point(); - auto in_time_t = std::chrono::system_clock::to_time_t(now); - */ - std::stringstream ss; - ss << __FUNCTION__ << " is not yet implemented!"; - // ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X"); - return ss.str(); -} +extern string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES); template datetime operator"" _D(); diff --git a/DictBase.mqh b/DictBase.mqh index 413894115..2d99174c2 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -61,6 +61,7 @@ class DictBase { _current_id = 0; _mode = DictModeUnknown; _flags = 0; + overflow_listener = nullptr; } /** diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 6f84b10e8..1083523a8 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -116,6 +116,7 @@ class Indicator : public IndicatorData { : IndicatorData(IndicatorDataParams::GetInstance()) { iparams.SetIndicatorType(_itype); iparams.SetShift(_shift); + SetName(_name); Init(); } diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 0f6c70ea6..d9fe084a2 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -94,7 +94,7 @@ class IndicatorCandle : public Indicator { /** * Class constructor. */ - IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, + IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(INDI_CANDLE_HISTORY_SIZE) { Init(); diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 69f319706..9f0aea621 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -59,34 +59,20 @@ class IndicatorTf : public IndicatorCandle { public: - IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} - IndicatorTfDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTf(_tf) {} - IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi = (ENUM_TIMEFRAMES_INDEX)0) : IndicatorTf(_tfi) {} + /* + @todo - string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } + IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} + */ + + IndicatorTfDummy(ENUM_TIMEFRAMES _tf) : IndicatorTf(IndicatorTfDummyParams(_tf), IndicatorDataParams()) {} + IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi) + : IndicatorTf(IndicatorTfDummyParams(ChartTf::IndexToTf(_tfi)), IndicatorDataParams()) {} + + string GetName() override { return "IndicatorTfDummy(" + iparams.tf.GetString() + ")"; } void OnDataSourceEntry(IndicatorDataEntry& entry) override { // When overriding OnDataSourceEntry() we have to remember to call parent diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h index 4f1f531b2..84fdf5439 100644 --- a/Indicators/Tick/Indi_TickProvider.h +++ b/Indicators/Tick/Indi_TickProvider.h @@ -64,7 +64,10 @@ class Indi_TickProvider : public IndicatorTick. + * + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Defines. +#define PLATFORM_WRONG_SYMBOL "" +#define PLATFORM_WRONG_TIMEFRAME ((ENUM_TIMEFRAMES)INT_MAX) diff --git a/Platform.extern.h b/Platform.extern.h index fabde3d0b..11edea715 100644 --- a/Platform.extern.h +++ b/Platform.extern.h @@ -67,9 +67,9 @@ extern int CopyLow(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, extern int CopyClose(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, close_array)); -extern unsigned long PositionGetTicket(int _index); +extern unsigned int64 PositionGetTicket(int _index); -extern long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id); +extern int64 PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id); extern double PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE property_id); @@ -77,13 +77,13 @@ extern string PositionGetString(ENUM_POSITION_PROPERTY_STRING property_id); extern int HistoryDealsTotal(); -extern unsigned long HistoryDealGetTicket(int index); +extern unsigned int64 HistoryDealGetTicket(int index); -extern long HistoryDealGetInteger(unsigned long ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id); +extern int64 HistoryDealGetInteger(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id); -extern double HistoryDealGetDouble(unsigned long ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id); +extern double HistoryDealGetDouble(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id); -extern string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRING property_id); +extern string HistoryDealGetString(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_STRING property_id); extern bool OrderSelect(int index); @@ -95,25 +95,25 @@ extern bool OrderSend(const MqlTradeRequest& request, MqlTradeResult& result); extern bool OrderCheck(const MqlTradeRequest& request, MqlTradeCheckResult& result); -extern unsigned long OrderGetTicket(int index); +extern unsigned int64 OrderGetTicket(int index); -extern unsigned long HistoryOrderGetTicket(int index); +extern unsigned int64 HistoryOrderGetTicket(int index); -extern bool HistorySelectByPosition(long position_id); +extern bool HistorySelectByPosition(int64 position_id); -extern bool HistoryDealSelect(unsigned long ticket); +extern bool HistoryDealSelect(unsigned int64 ticket); -extern long OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id); +extern int64 OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id); -extern long HistoryOrderGetInteger(unsigned long ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id); +extern int64 HistoryOrderGetInteger(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id); extern double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property_id); -extern double HistoryOrderGetDouble(unsigned long ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id); +extern double HistoryOrderGetDouble(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id); string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id); -string HistoryOrderGetString(unsigned long ticket_number, ENUM_ORDER_PROPERTY_STRING property_id); +string HistoryOrderGetString(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_STRING property_id); extern int PositionsTotal(); @@ -124,10 +124,10 @@ extern int HistoryOrdersTotal(); extern int OrdersTotal(); extern int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, - ARRAY_REF(long, arr)); + ARRAY_REF(int64, arr)); extern int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, - ARRAY_REF(long, arr)); + ARRAY_REF(int64, arr)); extern int ChartID(); @@ -135,38 +135,38 @@ extern bool OrderCalcMargin(ENUM_ORDER_TYPE _action, string _symbol, double _vol extern double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id); -extern long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); +extern int64 AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); extern string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); extern string Symbol(); -extern string ObjectName(long _chart_id, int _pos, int _sub_window = -1, int _type = -1); +extern string ObjectName(int64 _chart_id, int _pos, int _sub_window = -1, int _type = -1); -extern int ObjectsTotal(long chart_id, int type = EMPTY, int window = -1); +extern int ObjectsTotal(int64 chart_id, int type = EMPTY, int window = -1); extern bool PlotIndexSetString(int plot_index, int prop_id, string prop_value); extern bool PlotIndexSetInteger(int plot_index, int prop_id, int prop_value); -extern bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, long prop_value); +extern bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int64 prop_value); -extern bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, - long prop_value); +extern bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, + int64 prop_value); -extern bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value); +extern bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value); -extern bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, +extern bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, double prop_value); -extern bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1); -extern bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, +extern bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1); +extern bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, datetime _t2, double _p2); -extern bool ObjectMove(long chart_id, string name, int point_index, datetime time, double price); +extern bool ObjectMove(int64 chart_id, string name, int point_index, datetime time, double price); -extern bool ObjectDelete(long chart_id, string name); +extern bool ObjectDelete(int64 chart_id, string name); -extern int ObjectFind(long chart_id, string name); +extern int ObjectFind(int64 chart_id, string name); #endif diff --git a/Platform.h b/Platform.h index 703278ab1..9e4af58c7 100644 --- a/Platform.h +++ b/Platform.h @@ -27,6 +27,7 @@ // Includes. #include "Deal.enum.h" #include "Order.struct.h" +#include "Platform.define.h" /** * Extern declarations for C++. @@ -85,6 +86,12 @@ class Platform { // Result of the last tick. static bool last_tick_result; + // Symbol of the currently ticking indicator. + static string symbol; + + // Timeframe of the currently ticking indicator. + static ENUM_TIMEFRAMES period; + public: /** * Initializes platform. @@ -96,9 +103,6 @@ class Platform { } initialized = true; - - // Starting from current timestamp. - time.Update(); } /** @@ -110,6 +114,10 @@ class Platform { * Performs tick on every added indicator. */ static void Tick() { + // @todo Should update time for each ticking indicator and only when it signal a tick. + PlatformTime::Tick(); + time.Update(); + // Checking starting periods and updating time to current one. time_flags = time.GetStartedPeriods(); time.Update(); @@ -119,13 +127,37 @@ class Platform { last_tick_result = false; for (_iter = indis.Begin(); _iter.IsValid(); ++_iter) { + // Updating current symbol and timeframe to the ones used by ticking indicator and its parents. + symbol = _iter.Value() REF_DEREF GetSymbol(); + period = _iter.Value() REF_DEREF GetTf(); + +#ifdef __debug__ + PrintFormat("Tick #%d for %s for symbol %s and period %s", global_tick_index, + C_STR(_iter.Value() REF_DEREF GetFullName()), C_STR(symbol), C_STR(ChartTf::TfToString(period))); +#endif + last_tick_result |= _iter.Value() REF_DEREF Tick(global_tick_index); } for (_iter = indis_dflt.Begin(); _iter.IsValid(); ++_iter) { + // Updating current symbol and timeframe to the ones used by ticking indicator and its parents. + symbol = (_iter.Value() REF_DEREF GetTick(false) != nullptr) ? _iter.Value() REF_DEREF GetSymbol() + : PLATFORM_WRONG_SYMBOL; + period = (_iter.Value() REF_DEREF GetCandle(false) != nullptr) ? _iter.Value() REF_DEREF GetTf() + : PLATFORM_WRONG_TIMEFRAME; + +#ifdef __debug__ + PrintFormat("Tick #%d for %s for symbol %s and period %s", global_tick_index, + C_STR(_iter.Value() REF_DEREF GetFullName()), C_STR(symbol), C_STR(ChartTf::TfToString(period))); +#endif + last_tick_result |= _iter.Value() REF_DEREF Tick(global_tick_index); } + // Clearing symbol and period in order to signal retrieving symbol/period outside the ticking indicator. + symbol = PLATFORM_WRONG_SYMBOL; + period = PLATFORM_WRONG_TIMEFRAME; + // Will check for new time periods in consecutive Platform::UpdateTime(). time_clear_flags = true; @@ -280,13 +312,13 @@ class Platform { /** * Returns default Candle-compatible indicator for current platform for given symbol and TF. */ - static IndicatorData *FetchDefaultCandleIndicator(string _symbol = "", ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - if (_symbol == "") { - _symbol = _Symbol; + static IndicatorData *FetchDefaultCandleIndicator(string _symbol, ENUM_TIMEFRAMES _tf) { + if (_symbol == PLATFORM_WRONG_SYMBOL) { + RUNTIME_ERROR("Cannot fetch default candle indicator for unknown symbol!"); } - if (_tf == PERIOD_CURRENT) { - _tf = (ENUM_TIMEFRAMES)Period(); + if (_tf == PERIOD_CURRENT || _tf == PLATFORM_WRONG_TIMEFRAME) { + RUNTIME_ERROR("Cannot fetch default candle indicator for unknown period/timeframe!"); } // Candle is per symbol and TF. Single Candle indicator can't handle multiple TFs. @@ -311,9 +343,9 @@ class Platform { /** * Returns default Tick-compatible indicator for current platform for given symbol. */ - static IndicatorData *FetchDefaultTickIndicator(string _symbol = "") { - if (_symbol == "") { - _symbol = _Symbol; + static IndicatorData *FetchDefaultTickIndicator(string _symbol) { + if (_symbol == PLATFORM_WRONG_SYMBOL) { + RUNTIME_ERROR("Cannot fetch default tick indicator for unknown symbol!"); } string _key = Util::MakeKey("PlatformIndicatorTick", _symbol); @@ -366,6 +398,39 @@ class Platform { } return _result; } + + /** + * Returns symbol of the currently ticking indicator. + **/ + static string GetSymbol() { + if (symbol == PLATFORM_WRONG_SYMBOL) { + RUNTIME_ERROR("Retrieving symbol outside the OnTick() of the currently ticking indicator is prohibited!"); + } + return symbol; + } + + /** + * Returns timeframe of the currently ticking indicator. + **/ + static ENUM_TIMEFRAMES GetPeriod() { + if (period == PLATFORM_WRONG_TIMEFRAME) { + RUNTIME_ERROR( + "Retrieving period/timeframe outside the OnTick() of the currently ticking indicator is prohibited!"); + } + + return period; + } + + private: + /** + * Sets symbol of the currently ticking indicator. + **/ + static void SetSymbol(string _symbol) { symbol = _symbol; } + + /** + * Sets timeframe of the currently ticking indicator. + **/ + static void SetPeriod(ENUM_TIMEFRAMES _period) { period = _period; } }; bool Platform::initialized = false; @@ -374,6 +439,8 @@ DateTime Platform::time = (datetime)0; unsigned int Platform::time_flags = 0; bool Platform::time_clear_flags = true; int Platform::global_tick_index = 0; +string Platform::symbol = PLATFORM_WRONG_SYMBOL; +ENUM_TIMEFRAMES Platform::period = PLATFORM_WRONG_TIMEFRAME; DictStruct> Platform::indis; DictStruct> Platform::indis_dflt; @@ -399,12 +466,12 @@ int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, A return 0; } -unsigned long PositionGetTicket(int _index) { +unsigned int64 PositionGetTicket(int _index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -long PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id) { +int64 PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } @@ -424,22 +491,22 @@ int HistoryDealsTotal() { return 0; } -unsigned long HistoryDealGetTicket(int index) { +unsigned int64 HistoryDealGetTicket(int index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -long HistoryDealGetInteger(unsigned long ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id) { +int64 HistoryDealGetInteger(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -double HistoryDealGetDouble(unsigned long ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id) { +double HistoryDealGetDouble(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -string HistoryDealGetString(unsigned long ticket_number, ENUM_DEAL_PROPERTY_STRING property_id) { +string HistoryDealGetString(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_STRING property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); return 0; } @@ -469,32 +536,32 @@ bool OrderCheck(const MqlTradeRequest &request, MqlTradeCheckResult &result) { return false; } -unsigned long OrderGetTicket(int index) { +unsigned int64 OrderGetTicket(int index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -unsigned long HistoryOrderGetTicket(int index) { +unsigned int64 HistoryOrderGetTicket(int index) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -bool HistorySelectByPosition(long position_id) { +bool HistorySelectByPosition(int64 position_id) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool HistoryDealSelect(unsigned long ticket) { +bool HistoryDealSelect(unsigned int64 ticket) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -long OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id) { +int64 OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -long HistoryOrderGetInteger(unsigned long ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id) { +int64 HistoryOrderGetInteger(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } @@ -504,7 +571,7 @@ double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property_id) { return 0; } -double HistoryOrderGetDouble(unsigned long ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id) { +double HistoryOrderGetDouble(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } @@ -514,7 +581,7 @@ string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id) { return 0; } -string HistoryOrderGetString(unsigned long ticket_number, ENUM_ORDER_PROPERTY_STRING property_id) { +string HistoryOrderGetString(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_STRING property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); return 0; } @@ -559,12 +626,12 @@ int CopyClose(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int return 0; } -int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(long, arr)) { +int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(int64, arr)) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(long, arr)) { +int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(int64, arr)) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } @@ -581,7 +648,7 @@ double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id) { return false; } -long AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id) { +int64 AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return false; } @@ -596,12 +663,12 @@ string Symbol() { return ""; } -string ObjectName(long _chart_id, int _pos, int _sub_window, int _type) { +string ObjectName(int64 _chart_id, int _pos, int _sub_window, int _type) { Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); return ""; } -int ObjectsTotal(long chart_id, int type, int window) { +int ObjectsTotal(int64 chart_id, int type, int window) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } @@ -616,45 +683,45 @@ bool PlotIndexSetInteger(int plot_index, int prop_id, int prop_value) { return false; } -bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, long prop_value) { +bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int64 prop_value) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectSetInteger(long chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, - long prop_value) { +bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, + int64 prop_value) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value) { +bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectSetDouble(long chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, +bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, double prop_value) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { +bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectCreate(long _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, datetime _t2, +bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, datetime _t2, double _p2) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectMove(long chart_id, string name, int point_index, datetime time, double price) { +bool ObjectMove(int64 chart_id, string name, int point_index, datetime time, double price) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } -bool ObjectDelete(long chart_id, string name) { +bool ObjectDelete(int64 chart_id, string name) { Print("Not yet implemented: ", __FUNCTION__, " returns false."); return false; } @@ -663,29 +730,77 @@ int GetLastError() { return _LastError; } void ResetLastError() { _LastError = 0; } -int ObjectFind(long chart_id, string name) { +int ObjectFind(int64 chart_id, string name) { Print("Not yet implemented: ", __FUNCTION__, " returns 0."); return 0; } -bool TimeToStruct(datetime dt, MqlDateTime &dt_struct) { - Print("Not yet implemented: ", __FUNCTION__, " returns false."); - return false; -} +string TimeToString(datetime value, int mode) { + static std::stringstream ss; + ss.clear(); + ss.str(""); -SymbolGetter::operator string() { - Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); - return ""; + std::time_t time = value; + std::tm *ptm = std::localtime(&time); + char date[16], minutes[16], seconds[16]; + std::strftime(date, 32, "%Y.%m.%d", ptm); + std::strftime(minutes, 32, "%H:%M", ptm); + std::strftime(seconds, 32, "%S", ptm); + + if (mode | TIME_DATE) ss << date; + + if (mode | TIME_MINUTES) { + if (mode | TIME_DATE) { + ss << " "; + } + ss << minutes; + } + + if (mode | TIME_SECONDS) { + if (mode | TIME_DATE && !(mode | TIME_MINUTES)) { + ss << " "; + } else if (mode | TIME_MINUTES) { + ss << ":"; + } + ss << seconds; + } + + return ss.str(); } -ENUM_TIMEFRAMES Period() { - Print("Not yet implemented: ", __FUNCTION__, " returns 0."); - return (ENUM_TIMEFRAMES)0; +bool TimeToStruct(datetime dt, MqlDateTime &dt_struct) { + time_t now = (time_t)dt; + + tm *ltm = localtime(&now); + + dt_struct.day = ltm->tm_mday; + dt_struct.day_of_week = ltm->tm_wday; + dt_struct.day_of_year = ltm->tm_yday; + dt_struct.hour = ltm->tm_hour; + dt_struct.min = ltm->tm_min; + dt_struct.mon = ltm->tm_mon; + dt_struct.sec = ltm->tm_sec; + dt_struct.year = ltm->tm_year; + + return true; } +SymbolGetter::operator string() { return Platform::GetSymbol(); } + +ENUM_TIMEFRAMES Period() { return Platform::GetPeriod(); } + datetime StructToTime(MqlDateTime &dt_struct) { - Print("Not yet implemented: ", __FUNCTION__, " returns empty datetime (0)."); - return (datetime)0; + tm ltm; + ltm.tm_mday = dt_struct.day; + ltm.tm_wday = dt_struct.day_of_week; + ltm.tm_yday = dt_struct.day_of_year; + ltm.tm_hour = dt_struct.hour; + ltm.tm_min = dt_struct.min; + ltm.tm_mon = dt_struct.mon; + ltm.tm_sec = dt_struct.sec; + ltm.tm_year = dt_struct.year; + + return mktime(<m); } #endif diff --git a/PlatformTime.h b/PlatformTime.h index 6b54aeffb..b67cc43dc 100644 --- a/PlatformTime.h +++ b/PlatformTime.h @@ -39,21 +39,21 @@ class PlatformTime { static MqlDateTime current_time; - static long current_timestamp_s; - static long current_timestamp_ms; + static int64 current_timestamp_s; + static int64 current_timestamp_ms; public: - static long CurrentTimestamp() { return current_timestamp_s; } - static long CurrentTimestampMs() { return current_timestamp_ms; } + static int64 CurrentTimestamp() { return current_timestamp_s; } + static int64 CurrentTimestampMs() { return current_timestamp_ms; } static MqlDateTime CurrentTime() { return current_time; } void static Tick() { #ifdef __MQL__ - static long _last_timestamp_ms = 0; + static int64 _last_timestamp_ms = 0; current_timestamp_s = ::TimeCurrent(current_time); - current_timestamp_ms = (long)GetTickCount(); + current_timestamp_ms = (int64)GetTickCount(); if (_last_timestamp_ms != 0 && current_timestamp_ms < _last_timestamp_ms) { // Overflow occured (49.7 days passed). @@ -64,11 +64,11 @@ class PlatformTime { _last_timestamp_ms = current_timestamp_ms; #else using namespace std::chrono; - current_timestamp_s = (long)duration_cast(system_clock::now().time_since_epoch()).count(); - current_timestamp_ms = (long)duration_cast(system_clock::now().time_since_epoch()).count(); + current_timestamp_s = (int64)duration_cast(system_clock::now().time_since_epoch()).count(); + current_timestamp_ms = (int64)duration_cast(system_clock::now().time_since_epoch()).count(); using namespace std::chrono; - std::time_t t = std::time(0); + std::time_t t = current_timestamp_s; std::tm* now = std::localtime(&t); current_time.day = now->tm_mday; current_time.day_of_week = now->tm_wday; @@ -83,5 +83,5 @@ class PlatformTime { }; MqlDateTime PlatformTime::current_time = {0, 0, 0, 0, 0, 0, 0, 0}; -long PlatformTime::current_timestamp_s = 0; -long PlatformTime::current_timestamp_ms = 0; +int64 PlatformTime::current_timestamp_s = 0; +int64 PlatformTime::current_timestamp_ms = 0; diff --git a/Serializer/SerializerConverter.h b/Serializer/SerializerConverter.h index 350cf0763..8774f5f95 100644 --- a/Serializer/SerializerConverter.h +++ b/Serializer/SerializerConverter.h @@ -39,7 +39,7 @@ class SerializerNode; #include "SerializerDict.h" #include "SerializerNode.h" -#ifdef __debug__ +#ifdef __debug_verbose__ #include "SerializerJson.h" #endif @@ -72,7 +72,7 @@ class SerializerConverter { _serializer.FreeRootNodeOwnership(); _serializer.PassObject(_value, "", _value, SERIALIZER_FIELD_FLAG_VISIBLE); SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); -#ifdef __debug__ +#ifdef __debug_verbose__ Print("FromObject(): serializer flags: ", serializer_flags); Print("FromObject(): result: ", _serializer.GetRoot() != NULL ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) @@ -87,7 +87,7 @@ class SerializerConverter { _serializer.FreeRootNodeOwnership(); _serializer.PassObject(_value, "", _value, SERIALIZER_FIELD_FLAG_VISIBLE); SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); -#ifdef __debug__ +#ifdef __debug_verbose__ Print("FromObject(): serializer flags: ", serializer_flags); Print("FromObject(): result: ", _serializer.GetRoot() != NULL ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) @@ -119,7 +119,7 @@ class SerializerConverter { template static SerializerConverter FromString(string arg) { SerializerConverter _converter(((C*)NULL)PTR_DEREF Parse(arg), 0); -#ifdef __debug__ +#ifdef __debug_verbose__ Print("FromString(): result: ", _converter.Node() != NULL ? _converter.Node() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); #endif diff --git a/Serializer/SerializerCsv.h b/Serializer/SerializerCsv.h index 47d6f2c03..3390865ba 100644 --- a/Serializer/SerializerCsv.h +++ b/Serializer/SerializerCsv.h @@ -114,7 +114,7 @@ class SerializerCsv { } } -#ifdef __debug__ +#ifdef __debug_verbose__ Print("Stub: ", _stub PTR_DEREF Node() PTR_DEREF ToString()); Print("Data: ", _root PTR_DEREF ToString()); Print("Size: ", _num_columns, " x ", _num_rows); diff --git a/Std.h b/Std.h index 190ad3af6..13ffe0869 100644 --- a/Std.h +++ b/Std.h @@ -56,6 +56,7 @@ #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE* NAME = PTR #define nullptr NULL #define REF_DEREF .Ptr(). +#define int64 long #else #define THIS_ATTR this-> #define THIS_PTR (this) @@ -66,6 +67,7 @@ #define PTR_TO_REF(PTR) (*PTR) #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE& NAME = PTR #define REF_DEREF .Ptr()-> +#define int64 long long #endif // References. diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 4493d31ce..708f4fc3c 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -40,14 +40,14 @@ * https://www.mql5.com/en/docs/constants/structures/mqltick */ struct MqlTick { - datetime time; // Time of the last prices update. - double ask; // Current Ask price. - double bid; // Current Bid price. - double last; // Price of the last deal (last). - double volume_real; // Volume for the current last price with greater accuracy. - long time_msc; // Time of a price last update in milliseconds. - unsigned int flags; // Tick flags. - unsigned long volume; // Volume for the current last price. + datetime time; // Time of the last prices update. + double ask; // Current Ask price. + double bid; // Current Bid price. + double last; // Price of the last deal (last). + double volume_real; // Volume for the current last price with greater accuracy. + int64 time_msc; // Time of a price last update in milliseconds. + unsigned int flags; // Tick flags. + unsigned int64 volume; // Volume for the current last price. // Default constructor. MqlTick() {} @@ -84,26 +84,26 @@ struct DoubleTickAB : TickAB {}; */ template struct TickTAB : TickAB { - long time_ms; // Time of the last prices update. + int64 time_ms; // Time of the last prices update. // Struct constructors. - TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : TickAB(_ask, _bid), time_ms(_time_ms) {} + TickTAB(int64 _time_ms = 0, T _ask = 0, T _bid = 0) : TickAB(_ask, _bid), time_ms(_time_ms) {} TickTAB(MqlTick &_tick) : TickAB(_tick), time_ms(_tick.time_msc) {} TickTAB(const TickTAB &r) { THIS_REF = r; } /** * Method used by ItemsHistory. */ - long GetTimeMs() { return time_ms; } + int64 GetTimeMs() { return time_ms; } /** * Returns time as timestamp (in seconds). */ - long GetTimestamp() { return time_ms; } + int64 GetTimestamp() { return time_ms / 1000; } /** * Method used by ItemsHistory. */ - long GetLengthMs() { + int64 GetLengthMs() { // Ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. return 0; } From db3442db6185812fb7aab554227b92fce20aeb78 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 8 Mar 2023 17:20:36 +0100 Subject: [PATCH 073/123] Fixes recent syntax errors for C++. --- Chart.struct.static.h | 6 +++--- Indicator/IndicatorTf.h | 5 ++++- Orders.mqh | 4 ++-- Platform.h | 14 +++++++------- Std.h | 13 +++++++------ SymbolInfo.extern.h | 2 +- Tick/Tick.struct.h | 4 ++-- 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Chart.struct.static.h b/Chart.struct.static.h index befc9946b..2758c2d02 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -151,7 +151,7 @@ struct ChartStatic { if (_start < 0) return (-1); _count = (_count <= 0 ? ChartStatic::iBars(_symbol_tf.Symbol(), _symbol_tf.Tf()) : _count); ARRAY(double, arr_d); - ARRAY(long, arr_l); + ARRAY(int64, arr_l); ARRAY(datetime, arr_dt); ArraySetAsSeries(arr_d, true); switch (_type) { @@ -208,7 +208,7 @@ struct ChartStatic { if (_start < 0) return (-1); _count = (_count <= 0 ? iBars(_symbol, _tf) : _count); ARRAY(double, arr_d); - ARRAY(long, arr_l); + ARRAY(int64, arr_l); ARRAY(datetime, arr_dt); ArraySetAsSeries(arr_d, true); switch (_type) { @@ -314,7 +314,7 @@ struct ChartStatic { } return _volume; #else // __MQL5__ - ARRAY(long, _arr); + ARRAY(int64, _arr); ArraySetAsSeries(_arr, true); return (_shift >= 0 && CopyTickVolume(_symbol, _tf, _shift, 1, _arr) > 0) ? _arr[0] : 0; #endif diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 9f0aea621..c4195c68b 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -72,7 +72,10 @@ class IndicatorTf : public IndicatorCandle>(_icparams, _idparams) { + Init(); + } /** * Gets indicator's time-frame. diff --git a/Orders.mqh b/Orders.mqh index aa0add09b..89b821555 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -184,7 +184,7 @@ class Orders { // Terminal::GetErrorText(GetLastError())); break; } - if (Order::OrderSymbol() == _Symbol) { + if (Order::OrderSymbol() == (string)_Symbol) { double order_tp = Order::OrderTakeProfit(); double order_sl = Order::OrderStopLoss(); switch (Order::OrderType()) { @@ -268,7 +268,7 @@ class Orders { Terminal::GetErrorText(GetLastError())); break; } - if (Order::OrderSymbol() == _Symbol) { + if (Order::OrderSymbol() == (string)_Symbol) { switch (Order::OrderType()) { case ORDER_TYPE_BUY: buy_lots += Order::OrderLots(); diff --git a/Platform.h b/Platform.h index 9e4af58c7..f216c5d6b 100644 --- a/Platform.h +++ b/Platform.h @@ -747,19 +747,19 @@ string TimeToString(datetime value, int mode) { std::strftime(minutes, 32, "%H:%M", ptm); std::strftime(seconds, 32, "%S", ptm); - if (mode | TIME_DATE) ss << date; + if (mode & TIME_DATE) ss << date; - if (mode | TIME_MINUTES) { - if (mode | TIME_DATE) { + if (mode & TIME_MINUTES) { + if (mode & TIME_DATE) { ss << " "; } ss << minutes; } - if (mode | TIME_SECONDS) { - if (mode | TIME_DATE && !(mode | TIME_MINUTES)) { + if (mode & TIME_SECONDS) { + if (mode & TIME_DATE && !(mode & TIME_MINUTES)) { ss << " "; - } else if (mode | TIME_MINUTES) { + } else if (mode & TIME_MINUTES) { ss << ":"; } ss << seconds; @@ -785,7 +785,7 @@ bool TimeToStruct(datetime dt, MqlDateTime &dt_struct) { return true; } -SymbolGetter::operator string() { return Platform::GetSymbol(); } +SymbolGetter::operator string() const { return Platform::GetSymbol(); } ENUM_TIMEFRAMES Period() { return Platform::GetPeriod(); } diff --git a/Std.h b/Std.h index 13ffe0869..2d4848e6b 100644 --- a/Std.h +++ b/Std.h @@ -235,12 +235,13 @@ class _cpp_array { #ifdef EMSCRIPTEN #include -#define REGISTER_ARRAY_OF(N, T, D) \ - EMSCRIPTEN_BINDINGS(N) { \ - emscripten::class_<_cpp_array>(D) \ - .constructor() \ - .function("Push", &_cpp_array::push) \ - .function("Size", &_cpp_array::size); \ +#define REGISTER_ARRAY_OF(N, T, D) \ + EMSCRIPTEN_BINDINGS(N) { \ + emscripten::register_vector(D "CppVector"); \ + emscripten::class_<_cpp_array>(D) \ + .constructor() \ + .function("Push", &_cpp_array::push) \ + .function("Size", &_cpp_array::size); \ } #endif diff --git a/SymbolInfo.extern.h b/SymbolInfo.extern.h index f31450b70..0fe18dec6 100644 --- a/SymbolInfo.extern.h +++ b/SymbolInfo.extern.h @@ -38,6 +38,6 @@ extern bool SymbolInfoTick(string symbol, MqlTick &tick); // Define external global variables. class SymbolGetter { public: - operator string(); + operator string() const; } _Symbol; #endif diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 708f4fc3c..66f59a9c9 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -123,8 +123,8 @@ EMSCRIPTEN_BINDINGS(TickAB) { EMSCRIPTEN_BINDINGS(TickTAB) { // emscripten::value_object, emscripten::base>>("TickTABDouble") emscripten::value_object>("TickTAB") - .field("ask", &TickAB::ask) - .field("bid", &TickAB::bid) + .field("ask", &TickTAB::ask) + .field("bid", &TickTAB::bid) .field("time_ms", &TickTAB::time_ms); } From 93a46bbdcca161bc8d2c0a293c47c1f870ab1813 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 7 Apr 2023 19:50:12 +0200 Subject: [PATCH 074/123] Little changes for array #defines. --- Std.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Std.h b/Std.h index 2d4848e6b..8f5ca61de 100644 --- a/Std.h +++ b/Std.h @@ -98,6 +98,7 @@ * @usage * ARRAY_REF(, ) */ +#define ARRAY_TYPE(T) T[] #define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS #define FIXED_ARRAY_REF(T, N, S) ARRAY_REF(T, N) @@ -124,7 +125,8 @@ * @usage * ARRAY_REF(, ) */ -#define ARRAY_REF(T, N) _cpp_array& N +#define ARRAY_TYPE(T) _cpp_array +#define ARRAY_REF(T, N) ARRAY_TYPE(T)& N #define FIXED_ARRAY_REF(T, N, S) T(&N)[S] #define CONST_ARRAY_REF(T, N) const _cpp_array& N From 42de20c59740d02242c11a6690b06cdd62f0fe3c Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 20 Apr 2023 19:08:08 +0200 Subject: [PATCH 075/123] WIP. Making a Tester class and exporting IndicatorTfDummy and RSI indicator to be used in JS. --- Chart.enum.h | 30 ++++++++++++++++++++++ Indicator/IndicatorBase.h | 10 ++++++++ Indicator/IndicatorData.h | 15 +++++++++++ Indicator/tests/classes/IndicatorTfDummy.h | 30 ++++++++++++++++++++++ Indicators/Tick/Indi_TickProvider.h | 17 ++++++++---- Platform.h | 1 - Refs.struct.h | 7 +++++ 7 files changed, 104 insertions(+), 6 deletions(-) diff --git a/Chart.enum.h b/Chart.enum.h index 3a5463f87..e523c9dfa 100644 --- a/Chart.enum.h +++ b/Chart.enum.h @@ -126,6 +126,36 @@ enum ENUM_TIMEFRAMES { PERIOD_MN1 = 43200 // 1 month. }; +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(ENUM_TIMEFRAMES) { + emscripten::enum_("timeframes") + .value("CURRENT", PERIOD_CURRENT) + .value("M1", PERIOD_M1) + .value("M2", PERIOD_M2) + .value("M3", PERIOD_M3) + .value("M3", PERIOD_M3) + .value("M5", PERIOD_M5) + .value("M6", PERIOD_M6) + .value("M10", PERIOD_M10) + .value("M12", PERIOD_M12) + .value("M15", PERIOD_M15) + .value("M20", PERIOD_M20) + .value("M30", PERIOD_M30) + .value("H1", PERIOD_H1) + .value("H3", PERIOD_H3) + .value("H4", PERIOD_H4) + .value("H6", PERIOD_H6) + .value("H8", PERIOD_H8) + .value("H12", PERIOD_H12) + .value("D1", PERIOD_D1) + .value("W1", PERIOD_W1) + .value("MN1", PERIOD_MN1); +} +#endif + #endif // Define type of periods. diff --git a/Indicator/IndicatorBase.h b/Indicator/IndicatorBase.h index 3dede1258..fdbdb6b17 100644 --- a/Indicator/IndicatorBase.h +++ b/Indicator/IndicatorBase.h @@ -356,3 +356,13 @@ class IndicatorBase : public Object { #endif } }; + +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(IndicatorBase) { + emscripten::class_("IndicatorBase").smart_ptr>("Ref"); +} + +#endif diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index cb784124f..2d13e115a 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1965,4 +1965,19 @@ IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIn int GetBarsFromStart(IndicatorData* _indi) { return _indi PTR_DEREF GetBars(); } #endif +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(IndicatorData) { + emscripten::class_>("IndicatorData") + .smart_ptr>("Ref") + .function("SetSource", emscripten::optional_override([](IndicatorData& self, IndicatorData* base) { + self.SetDataSource(base); + }), + emscripten::allow_raw_pointer>()); +} + +#endif + #endif // INDICATOR_DATA_H diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 340a15b9b..171137d95 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -68,3 +68,33 @@ class IndicatorTfDummy : public IndicatorTf { #endif } }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyParams) { emscripten::value_object("indicators.TfParams"); } + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyBaseBaseBase) { + emscripten::class_, emscripten::base>( + "IndicatorTfDummyBaseBaseBase"); +} + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyBaseBase) { + emscripten::class_>, + emscripten::base>>("IndicatorTfDummyBaseBase"); +} + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyBase) { + emscripten::class_< + IndicatorTf, + emscripten::base>>>( + "IndicatorTfDummyBase"); +} + +EMSCRIPTEN_BINDINGS(IndicatorTfDummy) { + emscripten::class_>>("indicators.Tf") + .smart_ptr>("Ref") + .constructor(); +} + +#endif diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h index 84fdf5439..290433783 100644 --- a/Indicators/Tick/Indi_TickProvider.h +++ b/Indicators/Tick/Indi_TickProvider.h @@ -128,18 +128,25 @@ class Indi_TickProvider : public IndicatorTick +EMSCRIPTEN_BINDINGS(Indi_TickProviderBaseBase) { + emscripten::class_, emscripten::base>("IndiTickProviderBaseBase") + .smart_ptr>>("Ref>"); +} + EMSCRIPTEN_BINDINGS(Indi_TickProviderBase) { - emscripten::class_>>( - "IndiTickProviderBase"); + emscripten::class_>, + emscripten::base>>("IndiTickProviderBas e") + .smart_ptr>>>( + "Ref>"); } EMSCRIPTEN_BINDINGS(Indi_TickProvider) { emscripten::class_< Indi_TickProvider, emscripten::base>>>( - "Indi_TickProvider") - //.smart_ptr>("Ref") - .constructor<>() + "indicators.TickProvider") + .smart_ptr>("Ref") + .constructor(emscripten::optional_override([]() { return Ref(new Indi_TickProvider()); })) .function("BufferSize", &Indi_TickProvider::BufferSize) .function("Feed", &Indi_TickProvider::Feed); } diff --git a/Platform.h b/Platform.h index f216c5d6b..3800f0159 100644 --- a/Platform.h +++ b/Platform.h @@ -120,7 +120,6 @@ class Platform { // Checking starting periods and updating time to current one. time_flags = time.GetStartedPeriods(); - time.Update(); DictStructIterator> _iter; diff --git a/Refs.struct.h b/Refs.struct.h index ddda68a3b..b80fa30e7 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -130,6 +130,13 @@ struct Ref { */ ~Ref() { Unset(); } +#ifndef __MQL__ + template + operator Ref() { + return Ref(ptr_object); + } +#endif + /** * Returns pointer to target object. */ From 3bc9a57e22ef2c83e718d6e43b73169e545c5de0 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 28 Apr 2023 22:18:50 +0200 Subject: [PATCH 076/123] src/IndicatorTest.cpp --- Chart.enum.h | 11 +++++++ Indicator/IndicatorData.h | 24 ++++++++++++--- Indicator/tests/classes/IndicatorTfDummy.h | 11 +++++-- Indicators/Indi_RSI.mqh | 34 ++++++++++++++++++++-- Indicators/Tick/Indi_TickProvider.h | 27 +++++++++++++++++ Refs.struct.h | 8 +++-- Tick/Tick.struct.h | 8 +++++ 7 files changed, 112 insertions(+), 11 deletions(-) diff --git a/Chart.enum.h b/Chart.enum.h index e523c9dfa..1b61aeace 100644 --- a/Chart.enum.h +++ b/Chart.enum.h @@ -154,6 +154,17 @@ EMSCRIPTEN_BINDINGS(ENUM_TIMEFRAMES) { .value("W1", PERIOD_W1) .value("MN1", PERIOD_MN1); } + +EMSCRIPTEN_BINDINGS(ENUM_APPLIED_PRICE) { + emscripten::enum_("ap") + .value("open", PRICE_OPEN) + .value("high", PRICE_HIGH) + .value("low", PRICE_LOW) + .value("median", PRICE_MEDIAN) + .value("typical", PRICE_TYPICAL) + .value("weighted", PRICE_WEIGHTED); +} + #endif #endif diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 2d13e115a..7d1941353 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -83,6 +83,11 @@ class IndicatorData : public IndicatorBase { /* Protected methods */ bool Init() { +#ifdef __cplusplus + // In C++ we default to On-Indicator mode as there are no built-in ones. + idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR); +#endif + ArrayResize(value_storages, GetModeCount()); if (indi_src.IsSet()) { // SetDataSource(_indi_src, _indi_mode); @@ -868,6 +873,9 @@ class IndicatorData : public IndicatorBase { bool Tick(int _global_tick_index) { if (last_tick_index == _global_tick_index) { +#ifdef __debug_indicator__ + Print("We've already ticked tick index #", _global_tick_index, ". Skipping Tick() for ", GetFullName()); +#endif // We've already ticked. return last_tick_result; } @@ -879,13 +887,15 @@ class IndicatorData : public IndicatorBase { last_tick_index = _global_tick_index; + last_tick_result = false; + // Checking and potentially initializing new data source. if (HasDataSource(true)) { // Ticking data source if not yet ticked. - GetDataSource() PTR_DEREF Tick(_global_tick_index); - } - last_tick_result = false; + // If data source returns true, that means it ticked and there could be more ticks in the future. + last_tick_result |= GetDataSource() PTR_DEREF Tick(_global_tick_index); + } // Also ticking all used indicators if they've not yet ticked. for (DictStructIterator> iter = indicators.Begin(); iter.IsValid(); ++iter) { @@ -896,7 +906,13 @@ class IndicatorData : public IndicatorBase { // into Candle indicator which aggregates ticks. RSI doesn't have OnTick() and we can't know if there is new RSI // value. The only way to know that is to Tick all indicators in hierarchy and if one of them returns true in // OnTick() then we know that we have new value for RSI. - last_tick_result |= iter.Value() REF_DEREF Tick(_global_tick_index); + bool _tick_result = iter.Value() REF_DEREF Tick(_global_tick_index); + +#ifdef __debug_indicator__ + Print(iter.Value() REF_DEREF GetFullName(), "'s Tick() result: ", _tick_result ? "true" : "false"); +#endif + + last_tick_result |= _tick_result; } // Overridable OnTick() method. diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 171137d95..591c3f089 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -50,9 +50,16 @@ class IndicatorTfDummy : public IndicatorTf { IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} */ - IndicatorTfDummy(ENUM_TIMEFRAMES _tf) : IndicatorTf(IndicatorTfDummyParams(_tf), IndicatorDataParams()) {} + IndicatorTfDummy(ENUM_TIMEFRAMES _tf) : IndicatorTf(IndicatorTfDummyParams(_tf), IndicatorDataParams()) { Init(); } IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi) - : IndicatorTf(IndicatorTfDummyParams(ChartTf::IndexToTf(_tfi)), IndicatorDataParams()) {} + : IndicatorTf(IndicatorTfDummyParams(ChartTf::IndexToTf(_tfi)), IndicatorDataParams()) { + Init(); + } + + void Init() { + // Explicitly specifying built-in mode as in C++ default mode is On-Indicator. + idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_BUILTIN); + } string GetName() override { return "IndicatorTfDummy(" + iparams.tf.GetString() + ")"; } diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index aa1a4a5f1..78c121d8d 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -27,11 +27,9 @@ // Structs. struct IndiRSIParams : IndicatorParams { - protected: int period; ENUM_APPLIED_PRICE applied_price; - public: IndiRSIParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) : IndicatorParams(INDI_RSI), applied_price(_ap) { shift = _shift; @@ -303,6 +301,10 @@ class Indi_RSI : public Indicator { * (before mode and shift). */ IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override { +#ifdef __debug_indicator__ + Print("Indi_RSI::GetEntryValue(mode = ", _mode, ", abs_shift = ", _abs_shift, ")"); +#endif + double _value = EMPTY_VALUE; ARRAY(double, _res); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { @@ -339,3 +341,31 @@ double iRSIOnArray(ARRAY_REF(double, _arr), int _total, int _period, int _abs_sh return Indi_RSI::iRSIOnArray(_arr, _total, _period, _abs_shift); } #endif + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(Indi_RSI_Params) { + emscripten::value_object("indicators.RSIParams") + .field("period", &IndiRSIParams::period) + .field("appliedPrice", &IndiRSIParams::applied_price) + // Inherited fields: + .field("shift", &IndiRSIParams::shift); +} + +EMSCRIPTEN_BINDINGS(Indi_RSIBase) { + emscripten::class_, emscripten::base>("Indi_RSIBase"); +} + +EMSCRIPTEN_BINDINGS(Indi_RSI) { + emscripten::class_>>("indicators.RSI") + .smart_ptr>("Ref") + .constructor(&make_ref) + .constructor(&make_ref) + .constructor(&make_ref, + emscripten::allow_raw_pointer>()) + .constructor(&make_ref, + emscripten::allow_raw_pointer>()); +} + +#endif diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h index 290433783..28e9b9f93 100644 --- a/Indicators/Tick/Indi_TickProvider.h +++ b/Indicators/Tick/Indi_TickProvider.h @@ -67,6 +67,8 @@ class Indi_TickProvider : public IndicatorTick(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_BUILTIN); } string GetName() override { return "Indi_TickProvider"; } @@ -85,6 +87,10 @@ class Indi_TickProvider : public IndicatorTick, _out_ticks)) { +#ifdef __debug_indicator__ + Print("Indi_TickProvider::FetchHistoryByTimeRange(from_ms = ", _from_ms, ", to_ms = ", _to_ms, ")"); +#endif // No history. return false; } @@ -109,12 +118,23 @@ class Indi_TickProvider : public IndicatorTick= ArraySize(buffer)) { +#ifdef __debug_indicator__ + Print("Indi_TickProvider: Tick Index #", _global_tick_index, " is beyond buffer size ", ArraySize(buffer), + ", so acknowledging that there are no more ticks."); +#endif // No more ticks. return false; } TickTAB _tick = buffer[current_index++]; +#ifdef __debug_indicator__ + Print("Indi_TickProvider: OHLC: ", _tick.ToString()); +#endif IndicatorDataEntry _entry(TickToEntry(_tick.GetTimestamp(), _tick)); EmitEntry(_entry); @@ -128,6 +148,11 @@ class Indi_TickProvider : public IndicatorTick +EMSCRIPTEN_BINDINGS(Indi_TickProviderParams) { + emscripten::value_object("indicators.TickProviderParams") + .field("symbol", &Indi_TickProviderParams::symbol); +} + EMSCRIPTEN_BINDINGS(Indi_TickProviderBaseBase) { emscripten::class_, emscripten::base>("IndiTickProviderBaseBase") .smart_ptr>>("Ref>"); @@ -147,6 +172,8 @@ EMSCRIPTEN_BINDINGS(Indi_TickProvider) { "indicators.TickProvider") .smart_ptr>("Ref") .constructor(emscripten::optional_override([]() { return Ref(new Indi_TickProvider()); })) + .constructor(emscripten::optional_override( + [](Indi_TickProviderParams &_p) { return Ref(new Indi_TickProvider(_p)); })) .function("BufferSize", &Indi_TickProvider::BufferSize) .function("Feed", &Indi_TickProvider::Feed); } diff --git a/Refs.struct.h b/Refs.struct.h index b80fa30e7..92e667791 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -284,10 +284,12 @@ struct Ref { } }; -template -Ref MakeRef(T* _ptr) { - return Ref(_ptr); +#ifdef __cplusplus +template +Ref make_ref(Types&&... Args) { + return new T(std::forward(Args)...); } +#endif /** * Class used to hold weak reference to reference-counted object. diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 66f59a9c9..c2edbceca 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -107,6 +107,14 @@ struct TickTAB : TickAB { // Ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. return 0; } + + /** + * Return string representation of tick's OHLC. + */ + string ToString() { + return IntegerToString(time_ms) + ": Ask " + DoubleToString(THIS_ATTR ask) + + ", Bid: " + DoubleToString(THIS_ATTR bid); + } }; struct DoubleTickTAB : TickTAB {}; From 7f16aa1b81906c4cada0fe866ced2e332bb7890d Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 7 Apr 2023 19:50:12 +0200 Subject: [PATCH 077/123] Little changes for array #defines. --- Std.h | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/Std.h b/Std.h index 76ed66e47..8f5ca61de 100644 --- a/Std.h +++ b/Std.h @@ -34,6 +34,10 @@ #include #endif +#ifndef __MQL__ +#define __FUNCSIG__ __FUNCTION__ +#endif + #ifdef __MQL__ #define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE)this) = ((TYPE)VALUE) #else @@ -52,6 +56,7 @@ #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE* NAME = PTR #define nullptr NULL #define REF_DEREF .Ptr(). +#define int64 long #else #define THIS_ATTR this-> #define THIS_PTR (this) @@ -62,6 +67,7 @@ #define PTR_TO_REF(PTR) (*PTR) #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE& NAME = PTR #define REF_DEREF .Ptr()-> +#define int64 long long #endif // References. @@ -92,7 +98,9 @@ * @usage * ARRAY_REF(, ) */ +#define ARRAY_TYPE(T) T[] #define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS +#define FIXED_ARRAY_REF(T, N, S) ARRAY_REF(T, N) #define CONST_ARRAY_REF(T, N) const N ARRAY_DECLARATION_BRACKETS @@ -117,7 +125,9 @@ * @usage * ARRAY_REF(, ) */ -#define ARRAY_REF(T, N) _cpp_array& N +#define ARRAY_TYPE(T) _cpp_array +#define ARRAY_REF(T, N) ARRAY_TYPE(T)& N +#define FIXED_ARRAY_REF(T, N, S) T(&N)[S] #define CONST_ARRAY_REF(T, N) const _cpp_array& N @@ -166,6 +176,10 @@ class _cpp_array { m_isSeries = r.m_isSeries; } + std::vector& str() { return m_data; } + + void push(const T& value) { m_data.push_back(value); } + void operator=(const _cpp_array& r) { m_data = r.m_data; m_isSeries = r.m_isSeries; @@ -196,6 +210,17 @@ class _cpp_array { */ int size() const { return (int)m_data.size(); } + void resize(int new_size, int reserve_size = 0) { + // E.g., size = 10, new_size = 90, reserve_size = 50 + // thus: new_reserve_size = new_size + reserve_size - (new_size % reserve_size) + // which is: 90 + reserve_size - (90 % reserve_size) = 90 + 50 - 40 = 100. + if (reserve_size > 0) { + new_size = reserve_size - (new_size % reserve_size); + } + m_data.reserve(new_size); + m_data.resize(new_size); + } + /** * Checks whether */ @@ -209,6 +234,20 @@ class _cpp_array { void setIsSeries(bool _isSeries) { m_isSeries = _isSeries; } }; +#ifdef EMSCRIPTEN +#include + +#define REGISTER_ARRAY_OF(N, T, D) \ + EMSCRIPTEN_BINDINGS(N) { \ + emscripten::register_vector(D "CppVector"); \ + emscripten::class_<_cpp_array>(D) \ + .constructor() \ + .function("Push", &_cpp_array::push) \ + .function("Size", &_cpp_array::size); \ + } + +#endif + template class _cpp_array; #endif @@ -219,7 +258,7 @@ class color { unsigned int value; public: - color(unsigned int _color) { value = _color; } + color(unsigned int _color = 0) { value = _color; } color& operator=(unsigned int _color) { value = _color; return *this; @@ -283,20 +322,47 @@ class InvalidEnumValue { }; #ifndef __MQL__ +struct _WRONG_VALUE { + template + operator T() { + return (T)-1; + } +} WRONG_VALUE; + +const char* _empty_string_c = ""; +const string _empty_string = ""; + // Converter of NULL_VALUE into expected type. e.g., "int x = NULL_VALUE" will end up with "x = 0". struct _NULL_VALUE { template - explicit operator T() const { + operator T() const { return (T)0; } + } NULL_VALUE; +/** + * Converting an enumeration value of any type to a text form. + * + * @docs + * - https://www.mql5.com/en/docs/convert/enumtostring + */ +string EnumToString(int _value) { + std::stringstream ss; + // We really don't want to mess with type reflection here (if possible at all). So we are outputting the input + // integer. + ss << _value; + return ss.str(); +} + template <> -inline _NULL_VALUE::operator const std::string() const { - return ""; +_NULL_VALUE::operator string() const { + return _empty_string; } +#define NULL_STRING "" #else #define NULL_VALUE NULL +#define NULL_STRING NULL #endif #ifndef __MQL__ @@ -308,3 +374,7 @@ inline _NULL_VALUE::operator const std::string() const { extern ENUM_TIMEFRAMES Period(); #endif + +#define RUNTIME_ERROR(MSG) \ + Print(MSG); \ + DebugBreak(); From 050cee419f4c1ea1a37b702d9bf10ae8eeb25296 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 24 May 2023 19:17:59 +0200 Subject: [PATCH 078/123] Empty commit to run tests. From 2d7e33940c9319f07f356251afa10bb70eabbdf6 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 24 May 2023 19:26:42 +0200 Subject: [PATCH 079/123] Fixes Indi_RSI #elif error. Also, added PERIOD_TF_IRREGULAR enum value for ENUM_TIMEFRAME, so IndicatorTfParams could be initialized as non-tf-based indicator type. --- Chart.enum.h | 3 +++ Indicator/IndicatorRenko.h | 4 ++-- Indicators/Indi_RSI.mqh | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Chart.enum.h b/Chart.enum.h index 1b61aeace..da71f9581 100644 --- a/Chart.enum.h +++ b/Chart.enum.h @@ -169,6 +169,9 @@ EMSCRIPTEN_BINDINGS(ENUM_APPLIED_PRICE) { #endif +// Non-TF based period. Used e.g., by Renko indicator. +#define PERIOD_TF_IRREGULAR ((ENUM_TIMEFRAMES)-1) + // Define type of periods. // @see: https://docs.mql4.com/constants/chartconstants/enum_timeframes #define TFS 21 diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index df4a403da..cea1ff7a0 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -55,11 +55,11 @@ enum ENUM_INDI_RENKO_CANDLE_TYPE { struct RenkoParams : IndicatorTfParams { int pips_limit; - RenkoParams(int _pips_limit = 10, int _shift = 0) : IndicatorTfParams("Renko") { + RenkoParams(int _pips_limit = 10, int _shift = 0) : IndicatorTfParams("Renko", PERIOD_TF_IRREGULAR) { pips_limit = _pips_limit; shift = _shift; }; - RenkoParams(RenkoParams &_params) : IndicatorTfParams("Renko") { THIS_REF = _params; }; + RenkoParams(RenkoParams &_params) : IndicatorTfParams("Renko", PERIOD_TF_IRREGULAR) { THIS_REF = _params; }; // Getters. unsigned int GetSecsPerCandle() { diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 78c121d8d..2b2825a90 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -112,13 +112,15 @@ class Indi_RSI : public Indicator { ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iRSI(_symbol, _tf, _period, _applied_price, _shift); -#elif __MQL5__ +#else +#ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iRSI(_symbol, _tf, _period, _applied_price), 0, _shift); #else RUNTIME_ERROR( "In C++ Indi_RSI::iRSI() method couldn't be used directly. Please use an On-Indicator mode and attach " "indicator via Platform::Add/AddWithDefaultBindings()."); return DBL_MAX; +#endif #endif } From 930cda41307f322211f032252be0f875eb504e7c Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 24 May 2023 19:31:44 +0200 Subject: [PATCH 080/123] Fixes tests using Platform::FetchDefaultCandleIndicator() as method now requires both, symbol and time-frame to be passed. --- Indicator/tests/IndicatorCandle.test.mq5 | 2 +- Indicator/tests/IndicatorRenko.test.mq5 | 2 +- Indicator/tests/IndicatorTf.test.mq5 | 6 +++--- PlatformTime.h | 2 ++ tests/3DTest.mq5 | 2 +- tests/BufferFXTTest.mq5 | 2 +- tests/DrawIndicatorTest.mq5 | 2 +- tests/OrderTest.mq5 | 2 +- 8 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Indicator/tests/IndicatorCandle.test.mq5 b/Indicator/tests/IndicatorCandle.test.mq5 index 79ba7453a..c2bbf072f 100644 --- a/Indicator/tests/IndicatorCandle.test.mq5 +++ b/Indicator/tests/IndicatorCandle.test.mq5 @@ -36,7 +36,7 @@ Ref indi_candle; */ int OnInit() { Platform::Init(); - Platform::Add(indi_candle = Platform::FetchDefaultCandleIndicator()); + Platform::Add(indi_candle = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1)); return _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; } diff --git a/Indicator/tests/IndicatorRenko.test.mq5 b/Indicator/tests/IndicatorRenko.test.mq5 index 483749ff6..80ff7d3b5 100644 --- a/Indicator/tests/IndicatorRenko.test.mq5 +++ b/Indicator/tests/IndicatorRenko.test.mq5 @@ -47,7 +47,7 @@ Ref indi_renko; int OnInit() { Platform::Init(); // Platform ticks. - indi_tick = Platform::FetchDefaultTickIndicator(); + indi_tick = Platform::FetchDefaultTickIndicator("EURUSD"); // Renko with 10 pips limit. Platform::Add(indi_renko = new IndicatorRenko(1)); diff --git a/Indicator/tests/IndicatorTf.test.mq5 b/Indicator/tests/IndicatorTf.test.mq5 index 139e1275f..f4db42ced 100644 --- a/Indicator/tests/IndicatorTf.test.mq5 +++ b/Indicator/tests/IndicatorTf.test.mq5 @@ -55,13 +55,13 @@ Ref indi_ama_custom; int OnInit() { Platform::Init(); // Platform ticks. - indi_tick = Platform::FetchDefaultTickIndicator(); + indi_tick = Platform::FetchDefaultTickIndicator("EURUSD"); // 1-second candles. // indicators.Add(indi_tf = new IndicatorTfDummy(1)); // 1:1 candles from platform using current timeframe. - indi_tf_real = Platform::FetchDefaultCandleIndicator(); + indi_tf_real = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); // 1-second candles. // indicators.Add(indi_ama = new Indi_AMA()); @@ -70,7 +70,7 @@ int OnInit() { _ama_params.applied_price = PRICE_OPEN; // AMA on platform candles. - Platform::Add(indi_ama_orig_sim = new Indi_AMA(_ama_params)); + Platform::AddWithDefaultBindings(indi_ama_orig_sim = new Indi_AMA(_ama_params), "EURUSD", PERIOD_M1); // Original built-in AMA indicator on platform OHLCs. Platform::Add(indi_ama_orig = new Indi_AMA(_ama_params, IDATA_BUILTIN)); diff --git a/PlatformTime.h b/PlatformTime.h index b67cc43dc..5cad5dd3c 100644 --- a/PlatformTime.h +++ b/PlatformTime.h @@ -37,6 +37,8 @@ #include "DateTime.struct.h" #endif +#include "Std.h" + class PlatformTime { static MqlDateTime current_time; static int64 current_timestamp_s; diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 35b329fd5..16e64e77f 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -66,7 +66,7 @@ int OnInit() { _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); _mesh.Ptr().SetShaderPS(_shader_p.Ptr()); - Ref _chart = new Chart3D(Platform::FetchDefaultCandleIndicator(), CHART3D_TYPE_CANDLES); + Ref _chart = new Chart3D(Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1), CHART3D_TYPE_CANDLES); unsigned int _rand_color = rand() * 1256; diff --git a/tests/BufferFXTTest.mq5 b/tests/BufferFXTTest.mq5 index ea1f59814..120f60725 100644 --- a/tests/BufferFXTTest.mq5 +++ b/tests/BufferFXTTest.mq5 @@ -36,7 +36,7 @@ BufferFXT *ticks; */ int OnInit() { Platform::Init(); - ticks = new BufferFXT(Platform::FetchDefaultCandleIndicator()); + ticks = new BufferFXT(Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1)); // Test 1. // @todo return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED); diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index 7863ca883..070545a33 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -47,7 +47,7 @@ int bar_processed; */ int OnInit() { Platform::Init(); - candles = Platform::FetchDefaultCandleIndicator(); + candles = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); bool _result = true; // Initialize indicators. _result &= InitIndicators(); diff --git a/tests/OrderTest.mq5 b/tests/OrderTest.mq5 index 7a0fc2dae..65b5beddf 100644 --- a/tests/OrderTest.mq5 +++ b/tests/OrderTest.mq5 @@ -48,7 +48,7 @@ Order *orders_dummy[MAX_ORDERS]; */ int OnInit() { Platform::Init(); - _candles = Platform::FetchDefaultCandleIndicator(); + _candles = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); bool _result = true; bar_processed = 0; assertTrueOrFail(GetLastError() == ERR_NO_ERROR, StringFormat("Error: %d!", GetLastError())); From df4bb442a5228af2b25d6fb4124e305731db13a3 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 1 Jun 2023 18:34:18 +0200 Subject: [PATCH 081/123] Tiny internal changes. Part of testing emcc API. --- Platform.h | 13 +++++++++---- Std.h | 5 ++++- String.extern.h | 39 +++++++++++++++++++++++++++++++++++++-- tests/IndicatorsTest.mq5 | 4 ++-- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/Platform.h b/Platform.h index 3800f0159..811bd6223 100644 --- a/Platform.h +++ b/Platform.h @@ -126,7 +126,8 @@ class Platform { last_tick_result = false; for (_iter = indis.Begin(); _iter.IsValid(); ++_iter) { - // Updating current symbol and timeframe to the ones used by ticking indicator and its parents. + // Print("Ticking ", _iter.Value() REF_DEREF GetFullName()); + // Updating current symbol and timeframe to the ones used by ticking indicator and its parents. symbol = _iter.Value() REF_DEREF GetSymbol(); period = _iter.Value() REF_DEREF GetTf(); @@ -313,11 +314,15 @@ class Platform { */ static IndicatorData *FetchDefaultCandleIndicator(string _symbol, ENUM_TIMEFRAMES _tf) { if (_symbol == PLATFORM_WRONG_SYMBOL) { - RUNTIME_ERROR("Cannot fetch default candle indicator for unknown symbol!"); + Print("Cannot fetch default candle indicator for unknown symbol \"", _symbol, "\" (passed TF value ", (int)_tf, + ")!"); + DebugBreak(); } if (_tf == PERIOD_CURRENT || _tf == PLATFORM_WRONG_TIMEFRAME) { - RUNTIME_ERROR("Cannot fetch default candle indicator for unknown period/timeframe!"); + Print("Cannot fetch default candle indicator for unknown period/timeframe (passed symbol \"", _symbol, + "\", TF value ", (int)_tf, ")!"); + DebugBreak(); } // Candle is per symbol and TF. Single Candle indicator can't handle multiple TFs. @@ -344,7 +349,7 @@ class Platform { */ static IndicatorData *FetchDefaultTickIndicator(string _symbol) { if (_symbol == PLATFORM_WRONG_SYMBOL) { - RUNTIME_ERROR("Cannot fetch default tick indicator for unknown symbol!"); + RUNTIME_ERROR("Cannot fetch default tick indicator for unknown symbol for indicator ", GetFullName(), "!"); } string _key = Util::MakeKey("PlatformIndicatorTick", _symbol); diff --git a/Std.h b/Std.h index 8f5ca61de..ecaa13dc3 100644 --- a/Std.h +++ b/Std.h @@ -26,6 +26,9 @@ #include "Math.define.h" #endif +// Includes. +#include "Data.enum.h" + // Data types. #ifdef __cplusplus #include @@ -126,7 +129,7 @@ * ARRAY_REF(, ) */ #define ARRAY_TYPE(T) _cpp_array -#define ARRAY_REF(T, N) ARRAY_TYPE(T)& N +#define ARRAY_REF(T, N) ARRAY_TYPE(T) & N #define FIXED_ARRAY_REF(T, N, S) T(&N)[S] #define CONST_ARRAY_REF(T, N) const _cpp_array& N diff --git a/String.extern.h b/String.extern.h index 4064372b9..487cde055 100644 --- a/String.extern.h +++ b/String.extern.h @@ -55,7 +55,7 @@ int StringSplit(const string& string_value, const unsigned short separator, ARRA return result.size(); } long StringToInteger(string value) { return std::stol(value); } -string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol = ' ') { +string IntegerToString(int64 number, int str_len = 0, unsigned short fill_symbol = ' ') { return std::to_string(number); } @@ -73,7 +73,7 @@ void PrintTo(std::ostream& out, Arg&& arg, Args&&... args) { out << std::forward(arg); using expander = int[]; (void)expander{0, (void(out << std::forward(args)), 0)...}; - out << "\n"; + out << std::endl; out.flush(); } @@ -147,4 +147,39 @@ string StringToUpper(string str) { return str; } +string EnumToString(ENUM_DATATYPE _value) { + switch (_value) { + case TYPE_BOOL: + return "TYPE_BOOL"; + case TYPE_CHAR: + return "TYPE_CHAR"; + case TYPE_COLOR: + return "TYPE_COLOR"; + case TYPE_DATETIME: + return "TYPE_DATETIME"; + case TYPE_DOUBLE: + return "TYPE_DOUBLE"; + case TYPE_FLOAT: + return "TYPE_FLOAT"; + case TYPE_INT: + return "TYPE_INT"; + case TYPE_LONG: + return "TYPE_LONG"; + case TYPE_SHORT: + return "TYPE_SHORT"; + case TYPE_STRING: + return "TYPE_STRING"; + case TYPE_UCHAR: + return "TYPE_UCHAR"; + case TYPE_UINT: + return "TYPE_UINT"; + case TYPE_ULONG: + return "TYPE_ULONG"; + case TYPE_USHORT: + return "TYPE_USHORT"; + } + + return ""; +} + #endif diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index c113d8892..d412f4b93 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -76,7 +76,7 @@ int OnInit() { Print("Connecting candle and tick indicators to all indicators..."); // Connecting all indicators to default candle indicator (which is connected to default tick indicator). for (int i = 0; i < indis.Size(); ++i) { - Platform::AddWithDefaultBindings(indis[i], _Symbol, PERIOD_CURRENT); + Platform::AddWithDefaultBindings(indis[i], _Symbol, PERIOD_M1); } // Check for any errors. @@ -96,7 +96,7 @@ int OnInit() { */ void OnTick() { Platform::Tick(); - IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); + IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_M1); if (_candles PTR_DEREF IsNewBar()) { if (_candles PTR_DEREF GetBarIndex() > 550) { From b3a7f4a9d807e9583bcb715192dd988d121668e5 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 5 Jun 2023 14:11:46 +0200 Subject: [PATCH 082/123] Fixes warning "too many arguments for function-like macro 'RUNTIME_ERROR'" --- Platform.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Platform.h b/Platform.h index 811bd6223..f1805daa5 100644 --- a/Platform.h +++ b/Platform.h @@ -349,7 +349,8 @@ class Platform { */ static IndicatorData *FetchDefaultTickIndicator(string _symbol) { if (_symbol == PLATFORM_WRONG_SYMBOL) { - RUNTIME_ERROR("Cannot fetch default tick indicator for unknown symbol for indicator ", GetFullName(), "!"); + Alert("Cannot fetch default tick indicator for unknown symbol!"); + DebugBreak(); } string _key = Util::MakeKey("PlatformIndicatorTick", _symbol); From 69220b5e56485850f04538fe0babb30bd29cbcc1 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 8 Jun 2023 16:42:57 +0200 Subject: [PATCH 083/123] Should fix problem with MA expecting additional bar, despite it has all required bars to generate averages. --- Indicators/Indi_Envelopes.mqh | 7 +++++-- Indicators/Indi_MA.mqh | 3 ++- Indicators/Indi_Momentum.mqh | 4 ---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index e5b813c06..2eac502d7 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -150,8 +150,6 @@ class Indi_Envelopes : public Indicator { int _mode, // (MT4 _mode): 0 - MODE_MAIN, 1 - MODE_UPPER, 2 - MODE_LOWER; (MT5 // _mode): 0 - UPPER_LINE, 1 - LOWER_LINE int _shift = 0) { - INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, _shift + _ma_shift + _ma_period); - return iEnvelopesOnArray(_source.GetSpecificAppliedPriceValueStorage(_ap, _target), 0, _ma_period, _ma_method, _ma_shift, _deviation, _mode, _shift, _target PTR_DEREF GetCache()); } @@ -173,6 +171,11 @@ class Indi_Envelopes : public Indicator { static double iEnvelopesOnArray(ValueStorage *_price, int _total, int _ma_period, ENUM_MA_METHOD _ma_method, int _ma_shift, double _deviation, int _mode, int _shift, IndicatorCalculateCache *_cache = NULL) { + // We need 1 bar more because MA methods assumes we have historic bars. + if (_price PTR_DEREF Size() < _shift + _ma_shift + _ma_period + 1) { + return DBL_MIN; + } + double _indi_value_buffer[]; double _result; diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 2f1a7ec69..2fe09b214 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -134,7 +134,8 @@ class Indi_MA : public Indicator { unsigned int ma_period, unsigned int ma_shift, ENUM_MA_METHOD ma_method, // (MT4/MT5): MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA ENUM_APPLIED_PRICE _ap, int shift = 0) { - INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, int(ma_period + ma_shift + shift)); + // We need 1 bar more because MA methods assumes we have historic bars. + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, int(ma_period + ma_shift + shift + 1)); ValueStorage *_data = (ValueStorage *)_source.GetSpecificAppliedPriceValueStorage(_ap, _target); return iMAOnArray(_data, 0, ma_period, ma_shift, ma_method, shift, _target PTR_DEREF GetCache()); } diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 159f38f41..4b7602ee7 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -109,13 +109,9 @@ class Indi_Momentum : public Indicator { double _indi_value_buffer[]; IndicatorDataEntry _entry(_indi.GetModeCount()); - _period += 1; - ArrayResize(_indi_value_buffer, _period); for (int i = 0; i < (int)_period; i++) { - // Print(": Getting data from ", _indi PTR_DEREF GetFullName(), " from shift ", i); - // Getting value from single, selected buffer. _indi_value_buffer[i] = _indi[i].GetValue(_mode); } From 03bcdf30388347850f1e552e2f99fc80bd7d14b9 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 8 Jun 2023 21:28:50 +0200 Subject: [PATCH 084/123] Little changes required by emcc support. --- Chart.struct.tf.h | 8 ++++++++ Indicator/Indicator.enum.h | 9 +++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 8eb01b41c..ddcfc17fc 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -186,6 +186,14 @@ struct ChartTf { return PERIOD_CURRENT; } + /** + * Convert timeframe period to miliseconds. + * + * @param + * _tf ENUM_TIMEFRAMES Specify timeframe enum. + */ + static int64 TfToMs(const ENUM_TIMEFRAMES _tf) { return (int64)TfToSeconds(_tf) * 1000; } + /** * Convert timeframe period to seconds. * diff --git a/Indicator/Indicator.enum.h b/Indicator/Indicator.enum.h index d5fd94008..f67244456 100644 --- a/Indicator/Indicator.enum.h +++ b/Indicator/Indicator.enum.h @@ -193,10 +193,11 @@ enum ENUM_APPLIED_VOLUME { VOLUME_TICK = 0, VOLUME_REAL = 1 }; // Indicator flags. enum ENUM_INDI_FLAGS { - INDI_FLAG_INDEXABLE_BY_SHIFT = 1 << 0, // Indicator supports indexation by shift. - INDI_FLAG_INDEXABLE_BY_TIMESTAMP = 1 << 1, // Indicator supports indexation by shift. - INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT = 1 << 2, // Source indicator must be indexable by shift. - INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP = 1 << 3 // Source indicator must be indexable by timestamp. + INDI_FLAG_INDEXABLE_BY_SHIFT = 1 << 0, // Indicator supports indexation by shift. + INDI_FLAG_INDEXABLE_BY_TIMESTAMP = 1 << 1, // Indicator supports indexation by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT = 1 << 2, // Source indicator must be indexable by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP = 1 << 3, // Source indicator must be indexable by timestamp. + INDI_FLAG_LOOSE_TF_CANDLE_INDICATOR = 1 << 4 // It is a non TF-based indicator, e.g., Renko. }; // Flags indicating which data sources are required to be provided in order indicator to work. From d53d07aa1745ab5efba7d7a7d7766600476b83f8 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 15 Jun 2023 15:28:06 +0200 Subject: [PATCH 085/123] Should fix problems with DrawIndicatorTest as Platform::AddWithDefaultBindings() must take symbol and time-frame (we use fixed pair of symbol and time-frame, so code will work in c++). --- Platform.h | 3 +-- tests/DrawIndicatorTest.mq5 | 16 +++++++++------- tests/IndicatorsTest.mq5 | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Platform.h b/Platform.h index f1805daa5..c02abac4b 100644 --- a/Platform.h +++ b/Platform.h @@ -186,8 +186,7 @@ class Platform { /** * Adds indicator to be processed by platform and tries to initialize its data source(s). */ - static void AddWithDefaultBindings(IndicatorData *_indi, CONST_REF_TO(string) _symbol = "", - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + static void AddWithDefaultBindings(IndicatorData *_indi, CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { Add(_indi); BindDefaultDataSource(_indi, _symbol, _tf); } diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index 070545a33..5081ff6f4 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -24,8 +24,8 @@ * Test functionality of DrawIndicator class. */ -#define __debug__ -#define __debug_verbose__ +//#define __debug__ +//#define __debug_verbose__ // Includes. #include "../DictStruct.mqh" @@ -73,7 +73,9 @@ void OnTick() { _indi.OnTick(Platform::GetGlobalTickIndex()); IndicatorDataEntry _entry = _indi.GetEntry(); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)) && _entry.IsValid()) { +#ifdef __debug__ PrintFormat("%s: bar %d: %s", _indi.GetName(), bar_processed, _indi.ToString()); +#endif } } } @@ -92,28 +94,28 @@ bool InitIndicators() { // Bollinger Bands. IndiBandsParams bands_params(20, 2, 0, PRICE_MEDIAN); - Platform::AddWithDefaultBindings(new Indi_Bands(bands_params)); + Platform::AddWithDefaultBindings(new Indi_Bands(bands_params), "EURUSD", PERIOD_M1); // Moving Average. IndiMAParams ma_params(13, 10, MODE_SMA, PRICE_OPEN); - Platform::AddWithDefaultBindings(new Indi_MA(ma_params)); + Platform::AddWithDefaultBindings(new Indi_MA(ma_params), "EURUSD", PERIOD_M1); // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); - Platform::AddWithDefaultBindings(new Indi_RSI(rsi_params)); + Platform::AddWithDefaultBindings(new Indi_RSI(rsi_params), "EURUSD", PERIOD_M1); /* Special indicators */ // Demo/Dummy Indicator. IndiDemoParams demo_params; - Platform::AddWithDefaultBindings(new Indi_Demo(demo_params)); + Platform::AddWithDefaultBindings(new Indi_Demo(demo_params), "EURUSD", PERIOD_M1); #ifndef __MQL4__ // @fixme: Make it work for MT4. // Current Price (used by custom indicators) . PriceIndiParams price_params(); // price_params.SetDraw(clrGreenYellow); - Platform::AddWithDefaultBindings(new Indi_Price(price_params)); + Platform::AddWithDefaultBindings(new Indi_Price(price_params), "EURUSD", PERIOD_M1); #endif /* @fixme: Array out of range. diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index d412f4b93..c06263758 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -76,7 +76,7 @@ int OnInit() { Print("Connecting candle and tick indicators to all indicators..."); // Connecting all indicators to default candle indicator (which is connected to default tick indicator). for (int i = 0; i < indis.Size(); ++i) { - Platform::AddWithDefaultBindings(indis[i], _Symbol, PERIOD_M1); + Platform::AddWithDefaultBindings(indis[i], "EURUSD", PERIOD_M1); } // Check for any errors. From b246c9db3e46416c796f188e05cb98340bf39b98 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 15 Jun 2023 18:13:54 +0200 Subject: [PATCH 086/123] Fixing CompileTest --- 3D/Cube.h | 4 ++-- 3D/Device.h | 29 +++++++++++++++++------------ 3D/Devices/MTDX/MTDXDevice.h | 14 +++++--------- 3D/Mesh.h | 4 ++-- Platform.h | 2 +- tests/3DTest.mq5 | 4 ++-- 6 files changed, 29 insertions(+), 28 deletions(-) diff --git a/3D/Cube.h b/3D/Cube.h index 0bc9038ff..5ed20a8b9 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -77,8 +77,8 @@ class Cube : public Mesh { * Initializes graphics device-related things. */ virtual void Initialize(Device* _device) { - SetShaderVS(_device.VertexShader(ShaderCubeSourceVS, T::Layout)); - SetShaderPS(_device.PixelShader(ShaderCubeSourcePS)); + SetShaderVS(_device.CreateVertexShader(ShaderCubeSourceVS, T::Layout)); + SetShaderPS(_device.CreatePixelShader(ShaderCubeSourcePS)); } #endif }; diff --git a/3D/Device.h b/3D/Device.h index d7b64f94f..5124a22ac 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -138,20 +138,25 @@ class Device : public Dynamic { /** * Creates vertex shader to be used by current graphics device. */ - virtual Shader* VertexShader(string _source_code, const ShaderVertexLayout& _layout[], - string _entry_point = "main") = NULL; + virtual Shader* CreateVertexShader(string _source_code, const ShaderVertexLayout& _layout[], + string _entry_point = "main") = NULL; /** * Creates pixel shader to be used by current graphics device. */ - virtual Shader* PixelShader(string _source_code, string _entry_point = "main") = NULL; + virtual Shader* CreatePixelShader(string _source_code, string _entry_point = "main") = 0; + + /** + * Creates vertex buffer to be used by current graphics device. + */ + virtual VertexBuffer* CreateVertexBuffer() = 0; /** * Creates vertex buffer to be used by current graphics device. */ template - VertexBuffer* VertexBuffer(T& data[]) { - VertexBuffer* _buff = VertexBuffer(); + VertexBuffer* CreateVertexBuffer(T& data[]) { + VertexBuffer* _buff = CreateVertexBuffer(); // Unfortunately we can't make this method virtual. if (dynamic_cast(_buff) != NULL) { // MT5's DirectX. @@ -165,15 +170,10 @@ class Device : public Dynamic { return _buff; } - /** - * Creates vertex buffer to be used by current graphics device. - */ - virtual VertexBuffer* VertexBuffer() = NULL; - /** * Creates index buffer to be used by current graphics device. */ - virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) = NULL; + virtual IndexBuffer* CreateIndexBuffer(unsigned int& _indices[]) = 0; /** * Renders vertex buffer with optional point indices. @@ -183,7 +183,7 @@ class Device : public Dynamic { /** * Renders vertex buffer with optional point indices. */ - virtual void RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; + virtual void RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = 0; /** * Renders given mesh. @@ -233,6 +233,11 @@ class Device : public Dynamic { int Height() { return frontend.Ptr().Height(); } void SetCameraOrtho3D(float _pos_x = 0.0f, float _pos_y = 0.0f, float _pos_z = 0.0f) { + if (Width() <= 0 || Height() <= 0) { + Print("Cannot set 2D camera as width or height of the viewport is zero!"); + DebugBreak(); + return; + } DXMatrixOrthoLH(mtx_projection, 1.0f * _pos_z, 1.0f / Width() * Height() * _pos_z, -10000, 10000); } diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 7bb1c93b8..166a924ed 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -93,15 +93,11 @@ class MTDXDevice : public Device { } } - /** - * Creates index buffer to be used by current graphics device. - */ - IndexBuffer* IndexBuffer() { return NULL; } - /** * Creates vertex shader to be used by current graphics device. */ - virtual Shader* VertexShader(string _source_code, const ShaderVertexLayout& _layout[], string _entry_point = "main") { + Shader* CreateVertexShader(string _source_code, const ShaderVertexLayout& _layout[], + string _entry_point = "main") override { MTDXShader* _shader = new MTDXShader(&this); _shader.Create(SHADER_TYPE_VS, _source_code, _entry_point); _shader.SetDataLayout(_layout); @@ -111,7 +107,7 @@ class MTDXDevice : public Device { /** * Creates pixel shader to be used by current graphics device. */ - virtual Shader* PixelShader(string _source_code, string _entry_point = "main") { + Shader* CreatePixelShader(string _source_code, string _entry_point = "main") override { MTDXShader* _shader = new MTDXShader(&this); _shader.Create(SHADER_TYPE_PS, _source_code, _entry_point); return _shader; @@ -120,12 +116,12 @@ class MTDXDevice : public Device { /** * Creates vertex buffer to be used by current graphics device. */ - VertexBuffer* VertexBuffer() { return new MTDXVertexBuffer(&this); } + VertexBuffer* CreateVertexBuffer() override { return new MTDXVertexBuffer(&this); } /** * Creates index buffer to be used by current graphics device. */ - virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) { + IndexBuffer* CreateIndexBuffer(unsigned int& _indices[]) override { IndexBuffer* _buffer = new MTDXIndexBuffer(&this); _buffer.Fill(_indices); return _buffer; diff --git a/3D/Mesh.h b/3D/Mesh.h index 719b33aff..d77c6ede8 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -254,8 +254,8 @@ class Mesh : public Dynamic { Print("Indices: ", _s_indices); #endif - vbuff = _vbuff = _device.VertexBuffer(_vertices); - ibuff = _ibuff = _device.IndexBuffer(_indices); + vbuff = _vbuff = _device.CreateVertexBuffer(_vertices); + ibuff = _ibuff = _device.CreateIndexBuffer(_indices); return true; } }; diff --git a/Platform.h b/Platform.h index c02abac4b..0431390d4 100644 --- a/Platform.h +++ b/Platform.h @@ -817,7 +817,7 @@ datetime StructToTime(MqlDateTime &dt_struct) { \ int OnInit() { \ Platform::Init(); \ - Platform::AddWithDefaultBindings(indi.Ptr()); \ + Platform::AddWithDefaultBindings(indi.Ptr(), "EURUSD", PERIOD_M1); \ bool _result = true; \ assertTrueOrFail(indi REF_DEREF IsValid(), "Error on IsValid!"); \ return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); \ diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 16e64e77f..9ac4d2872 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -59,8 +59,8 @@ int OnInit() { gfx.Start(new MT5Frontend()); - Ref _shader_v = gfx.VertexShader(ShaderSourceVS, Vertex::Layout); - Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + Ref _shader_v = gfx.CreateVertexShader(ShaderSourceVS, Vertex::Layout); + Ref _shader_p = gfx.CreatePixelShader(ShaderSourcePS); Ref> _mesh = new Cube(1.0f, 1.0f, 1.0f); _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); From 78d86348f7e5fcf757708aebd9a1e5f59934504b Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 15 Jun 2023 19:32:44 +0200 Subject: [PATCH 087/123] Fixes problem with not preserving TF passed to Candle indicators. --- Indicator/IndicatorTf.h | 5 +---- Platform.h | 23 +++++++++++++++++++---- tests/TradeTest.mq5 | 9 ++++----- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index c4195c68b..00f2ec094 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -39,9 +39,6 @@ template class IndicatorTf : public IndicatorCandle> { protected: - // Time-frame used to create candles. - ENUM_TIMEFRAMES tf; - /* Protected methods */ /** @@ -80,7 +77,7 @@ class IndicatorTf : public IndicatorCandle _ref = _indi; + + DictStructIterator> _iter; + for (_iter = indis_dflt.Begin(); _iter.IsValid(); ++_iter) { + if (_iter.Value() == _ref) { + Alert("Warning: ", _indi PTR_DEREF GetFullName(), + " was already added as default candle/tick indicator and shouldn't be added by Platform:Add() as default " + "indicators are also ticked when calling Platform::Tick()."); + DebugBreak(); + } + } + indis.Set(_indi PTR_DEREF GetId(), _ref); } @@ -333,11 +344,15 @@ class Platform { // Adding indicator to list of default indicators in order to tick it on every Tick() call. Ref _ref = _indi_candle; indis_dflt.Set(_indi_candle PTR_DEREF GetId(), _ref); - } - if (!_indi_candle PTR_DEREF HasDataSource()) { - // Missing tick indicator. - _indi_candle PTR_DEREF InjectDataSource(FetchDefaultTickIndicator(_symbol)); + if (!_indi_candle PTR_DEREF HasDataSource()) { + // Missing tick indicator. + _indi_candle PTR_DEREF InjectDataSource(FetchDefaultTickIndicator(_symbol)); + } +#ifdef __debug__ + Print("Added default candle indicator for symbol ", _symbol, " and time-frame ", _tf, ". Now it has symbol ", + _indi_candle PTR_DEREF GetSymbol(), " and time-frame ", EnumToString(_indi_candle PTR_DEREF GetTf())); +#endif } return _indi_candle; diff --git a/tests/TradeTest.mq5 b/tests/TradeTest.mq5 index 55ff0c3a4..cc828bdd7 100644 --- a/tests/TradeTest.mq5 +++ b/tests/TradeTest.mq5 @@ -46,10 +46,9 @@ bool _finish_test = false; */ int OnInit() { Platform::Init(); - _chart_m1 = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_M1); - _chart_m5 = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_M5); - Platform::Add(_chart_m1.Ptr()); - Platform::Add(_chart_m5.Ptr()); + _chart_m1 = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); + _chart_m5 = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M5); + return INIT_SUCCEEDED; } @@ -83,7 +82,7 @@ int Test() { // Test market. assertTrueOrFail(trade1 PTR_DEREF IsTradeAllowed(), "Trade not allowed!"); assertTrueOrFail(trade1 PTR_DEREF GetSource() PTR_DEREF GetTf() == PERIOD_M1, - StringFormat("Fail on GetTf() => [%s]!", trade1 PTR_DEREF GetSource() PTR_DEREF GetTf())); + StringFormat("Fail on GetTf() => [%d]!", trade1 PTR_DEREF GetSource() PTR_DEREF GetTf())); assertTrueOrFail(trade1 PTR_DEREF GetSource() PTR_DEREF GetOpen() > 0, "Fail on GetOpen()!"); assertTrueOrFail(trade1 PTR_DEREF GetSource() PTR_DEREF GetSymbol() == _Symbol, "Fail on GetSymbol()!"); // assertTrueOrFail(trade1.IsTradeAllowed(), "Fail on IsTradeAllowed()!"); // @fixme From 94d2da46e83dd7bad64be2b94c4f907c44e01808 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 16 Jun 2023 14:36:16 +0200 Subject: [PATCH 088/123] Fixes ZigZag and ZigZagColor value validation. --- Indicators/Indi_ZigZag.mqh | 4 +++- Indicators/Indi_ZigZagColor.mqh | 8 +++++--- Platform.h | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index fcb56a4d2..3242fd352 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -404,7 +404,9 @@ class Indi_ZigZag : public Indicator { /** * Checks if indicator entry values are valid. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return !_entry.HasValue(EMPTY_VALUE); } + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return _entry.values[0].Get() != DBL_MAX && _entry.values[0].Get() != EMPTY_VALUE; + } /* Getters */ diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index d0fcc7925..187bf02f3 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -61,13 +61,13 @@ class Indi_ZigZagColor : public Indicator { IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) : Indicator( _p, IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), - _indi_src){}; + _indi_src) {} Indi_ZigZagColor(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) : Indicator( IndiZigZagColorParams(), IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), - _indi_src){}; + _indi_src) {} /** * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. */ @@ -321,7 +321,9 @@ class Indi_ZigZagColor : public Indicator { /** * Checks if indicator entry values are valid. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return _entry.values[0].Get() != EMPTY_VALUE; } + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return _entry.values[0].Get() != DBL_MAX && _entry.values[0].Get() != EMPTY_VALUE; + } /* Getters */ diff --git a/Platform.h b/Platform.h index 041d239fd..b5f5a3828 100644 --- a/Platform.h +++ b/Platform.h @@ -844,7 +844,7 @@ datetime StructToTime(MqlDateTime &dt_struct) { IndicatorDataEntry _entry = indi REF_DEREF GetEntry(); \ bool _is_ready = indi REF_DEREF Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)); \ bool _is_valid = _entry.IsValid(); \ - Print(indi REF_DEREF ToString(), _is_ready ? "" : " (Not yet ready)"); \ + Print(indi REF_DEREF ToString(), _is_ready ? " (Ready)" : " (Not yet ready)"); \ if (_is_ready && !_is_valid) { \ Print(indi REF_DEREF ToString(), " (Invalid entry!)"); \ assertTrueOrExit(_entry.IsValid(), "Invalid entry!"); \ From 294eeff7c930886cfc65adec77ef3bf6f474daee Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 24 Jun 2023 00:13:32 +0100 Subject: [PATCH 089/123] ADXW: Renames variables to avoid global conflicts --- Indicators/Indi_ADXW.mqh | 73 ++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 4b3876059..3a9c657a4 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -156,32 +156,31 @@ class Indi_ADXW : public Indicator { /** * OnCalculate() method for ADXW indicator. */ - static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &ExtADXWBuffer, - ValueStorage &ExtPDIBuffer, ValueStorage &ExtNDIBuffer, - ValueStorage &ExtPDSBuffer, ValueStorage &ExtNDSBuffer, - ValueStorage &ExtPDBuffer, ValueStorage &ExtNDBuffer, - ValueStorage &ExtTRBuffer, ValueStorage &ExtATRBuffer, - ValueStorage &ExtDXBuffer, int ExtADXWPeriod) { + static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &_adxw_buff, + ValueStorage &_pdi_buff, ValueStorage &_ndi_buff, + ValueStorage &_pds_buff, ValueStorage &_nds_buff, + ValueStorage &_pdb_buff, ValueStorage &_nd_buff, ValueStorage &_tr_buff, + ValueStorage &_atr_buff, ValueStorage &_dx_buff, int _adxw_period) { int i; // Checking for bars count. - if (rates_total < ExtADXWPeriod) return (0); + if (rates_total < _adxw_period) return (0); // Detect start position. int start; if (prev_calculated > 1) start = prev_calculated - 1; else { start = 1; - for (i = 0; i < ExtADXWPeriod; i++) { - ExtADXWBuffer[i] = 0; - ExtPDIBuffer[i] = 0; - ExtNDIBuffer[i] = 0; - ExtPDSBuffer[i] = 0; - ExtNDSBuffer[i] = 0; - ExtPDBuffer[i] = 0; - ExtNDBuffer[i] = 0; - ExtTRBuffer[i] = 0; - ExtATRBuffer[i] = 0; - ExtDXBuffer[i] = 0; + for (i = 0; i < _adxw_period; i++) { + _adxw_buff[i] = 0; + _pdi_buff[i] = 0; + _ndi_buff[i] = 0; + _pds_buff[i] = 0; + _nds_buff[i] = 0; + _pdb_buff[i] = 0; + _nd_buff[i] = 0; + _tr_buff[i] = 0; + _atr_buff[i] = 0; + _dx_buff[i] = 0; } } for (i = start; i < rates_total && !IsStopped(); i++) { @@ -205,40 +204,40 @@ class Indi_ADXW : public Indicator { else tmp_neg = 0.0; } - ExtPDBuffer[i] = tmp_pos; - ExtNDBuffer[i] = tmp_neg; + _pdb_buff[i] = tmp_pos; + _nd_buff[i] = tmp_neg; // Define TR. double tr = MathMax(MathMax(MathAbs(high_price - low_price), MathAbs(high_price - prev_close)), MathAbs(low_price - prev_close)); // Write down TR to TR buffer. - ExtTRBuffer[i] = tr; + _tr_buff[i] = tr; // Fill smoothed positive and negative buffers and TR buffer. - if (i < ExtADXWPeriod) { - ExtATRBuffer[i] = 0.0; - ExtPDIBuffer[i] = 0.0; - ExtNDIBuffer[i] = 0.0; + if (i < _adxw_period) { + _atr_buff[i] = 0.0; + _pdi_buff[i] = 0.0; + _ndi_buff[i] = 0.0; } else { - ExtATRBuffer[i] = SmoothedMA(i, ExtADXWPeriod, ExtATRBuffer[i - 1].Get(), ExtTRBuffer); - ExtPDSBuffer[i] = SmoothedMA(i, ExtADXWPeriod, ExtPDSBuffer[i - 1].Get(), ExtPDBuffer); - ExtNDSBuffer[i] = SmoothedMA(i, ExtADXWPeriod, ExtNDSBuffer[i - 1].Get(), ExtNDBuffer); + _atr_buff[i] = SmoothedMA(i, _adxw_period, _atr_buff[i - 1].Get(), _tr_buff); + _pds_buff[i] = SmoothedMA(i, _adxw_period, _pds_buff[i - 1].Get(), _pdb_buff); + _nds_buff[i] = SmoothedMA(i, _adxw_period, _nds_buff[i - 1].Get(), _nd_buff); } // Calculate PDI and NDI buffers. - if (ExtATRBuffer[i] != 0.0) { - ExtPDIBuffer[i] = 100.0 * ExtPDSBuffer[i].Get() / ExtATRBuffer[i].Get(); - ExtNDIBuffer[i] = 100.0 * ExtNDSBuffer[i].Get() / ExtATRBuffer[i].Get(); + if (_atr_buff[i] != 0.0) { + _pdi_buff[i] = 100.0 * _pds_buff[i].Get() / _atr_buff[i].Get(); + _ndi_buff[i] = 100.0 * _nds_buff[i].Get() / _atr_buff[i].Get(); } else { - ExtPDIBuffer[i] = 0.0; - ExtNDIBuffer[i] = 0.0; + _pdi_buff[i] = 0.0; + _ndi_buff[i] = 0.0; } // Calculate DX buffer. - double dTmp = ExtPDIBuffer[i] + ExtNDIBuffer[i]; + double dTmp = _pdi_buff[i] + _ndi_buff[i]; if (dTmp != 0.0) - dTmp = 100.0 * MathAbs((ExtPDIBuffer[i] - ExtNDIBuffer[i]) / dTmp); + dTmp = 100.0 * MathAbs((_pdi_buff[i] - _ndi_buff[i]) / dTmp); else dTmp = 0.0; - ExtDXBuffer[i] = dTmp; + _dx_buff[i] = dTmp; // Fill ADXW buffer as smoothed DX buffer. - ExtADXWBuffer[i] = SmoothedMA(i, ExtADXWPeriod, ExtADXWBuffer[i - 1].Get(), ExtDXBuffer); + _adxw_buff[i] = SmoothedMA(i, _adxw_period, _adxw_buff[i - 1].Get(), _dx_buff); } // OnCalculate done. Return new prev_calculated. return (rates_total); From 4c26b6c855f5327a16a091785e240c04bf47d2c3 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 24 Jun 2023 00:19:04 +0100 Subject: [PATCH 090/123] Indi_ADXW: Fixes logic for SetCustomIndicatorName() --- Indicators/Indi_ADXW.mqh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 3a9c657a4..8506f24f1 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -39,7 +39,7 @@ struct IndiADXWParams : IndiADXParams { 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 == "") { + if (custom_indi_name == "" || custom_indi_name == "Examples\\ADX") { SetCustomIndicatorName("Examples\\ADXW"); } }; From db83ebb459f1d7e99928c374b1f65a7f33aac1ab Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 24 Jun 2023 00:13:32 +0100 Subject: [PATCH 091/123] ADXW: Renames variables to avoid global conflicts --- Indicators/Indi_ADXW.mqh | 73 ++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 2263d11cc..e0d3deec5 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -158,33 +158,32 @@ class Indi_ADXW : public Indicator { /** * OnCalculate() method for ADXW indicator. */ - static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &ExtADXWBuffer, - ValueStorage &ExtPDIBuffer, ValueStorage &ExtNDIBuffer, - ValueStorage &ExtPDSBuffer, ValueStorage &ExtNDSBuffer, - ValueStorage &ExtPDBuffer, ValueStorage &ExtNDBuffer, - ValueStorage &ExtTRBuffer, ValueStorage &ExtATRBuffer, - ValueStorage &ExtDXBuffer, int ExtADXWPeriod) { + static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &_adxw_buff, + ValueStorage &_pdi_buff, ValueStorage &_ndi_buff, + ValueStorage &_pds_buff, ValueStorage &_nds_buff, + ValueStorage &_pdb_buff, ValueStorage &_nd_buff, ValueStorage &_tr_buff, + ValueStorage &_atr_buff, ValueStorage &_dx_buff, int _adxw_period) { int i; // Checking for bars count. - if (rates_total < ExtADXWPeriod) return (0); + if (rates_total < _adxw_period) return (0); // Detect start position. int start; if (prev_calculated > 1) start = prev_calculated - 1; else { start = 1; - for (i = 0; i < ExtADXWPeriod; i++) { - ExtADXWBuffer[i] = 0; - ExtPDIBuffer[i] = 0; - ExtNDIBuffer[i] = 0; - ExtPDSBuffer[i] = 0; - ExtNDSBuffer[i] = 0; - ExtPDBuffer[i] = 0; - ExtNDBuffer[i] = 0; - ExtTRBuffer[i] = 0; - ExtATRBuffer[i] = 0; - ExtDXBuffer[i] = 0; + for (i = 0; i < _adxw_period; i++) { + _adxw_buff[i] = 0; + _pdi_buff[i] = 0; + _ndi_buff[i] = 0; + _pds_buff[i] = 0; + _nds_buff[i] = 0; + _pdb_buff[i] = 0; + _nd_buff[i] = 0; + _tr_buff[i] = 0; + _atr_buff[i] = 0; + _dx_buff[i] = 0; } } for (i = start; i < rates_total && !IsStopped(); i++) { @@ -208,40 +207,40 @@ class Indi_ADXW : public Indicator { else tmp_neg = 0.0; } - ExtPDBuffer[i] = tmp_pos; - ExtNDBuffer[i] = tmp_neg; + _pdb_buff[i] = tmp_pos; + _nd_buff[i] = tmp_neg; // Define TR. double tr = MathMax(MathMax(MathAbs(high_price - low_price), MathAbs(high_price - prev_close)), MathAbs(low_price - prev_close)); // Write down TR to TR buffer. - ExtTRBuffer[i] = tr; + _tr_buff[i] = tr; // Fill smoothed positive and negative buffers and TR buffer. - if (i < ExtADXWPeriod) { - ExtATRBuffer[i] = 0.0; - ExtPDIBuffer[i] = 0.0; - ExtNDIBuffer[i] = 0.0; + if (i < _adxw_period) { + _atr_buff[i] = 0.0; + _pdi_buff[i] = 0.0; + _ndi_buff[i] = 0.0; } else { - ExtATRBuffer[i] = SmoothedMA(i, ExtADXWPeriod, ExtATRBuffer[i - 1].Get(), ExtTRBuffer); - ExtPDSBuffer[i] = SmoothedMA(i, ExtADXWPeriod, ExtPDSBuffer[i - 1].Get(), ExtPDBuffer); - ExtNDSBuffer[i] = SmoothedMA(i, ExtADXWPeriod, ExtNDSBuffer[i - 1].Get(), ExtNDBuffer); + _atr_buff[i] = SmoothedMA(i, _adxw_period, _atr_buff[i - 1].Get(), _tr_buff); + _pds_buff[i] = SmoothedMA(i, _adxw_period, _pds_buff[i - 1].Get(), _pdb_buff); + _nds_buff[i] = SmoothedMA(i, _adxw_period, _nds_buff[i - 1].Get(), _nd_buff); } // Calculate PDI and NDI buffers. - if (ExtATRBuffer[i] != 0.0) { - ExtPDIBuffer[i] = 100.0 * ExtPDSBuffer[i].Get() / ExtATRBuffer[i].Get(); - ExtNDIBuffer[i] = 100.0 * ExtNDSBuffer[i].Get() / ExtATRBuffer[i].Get(); + if (_atr_buff[i] != 0.0) { + _pdi_buff[i] = 100.0 * _pds_buff[i].Get() / _atr_buff[i].Get(); + _ndi_buff[i] = 100.0 * _nds_buff[i].Get() / _atr_buff[i].Get(); } else { - ExtPDIBuffer[i] = 0.0; - ExtNDIBuffer[i] = 0.0; + _pdi_buff[i] = 0.0; + _ndi_buff[i] = 0.0; } // Calculate DX buffer. - double dTmp = ExtPDIBuffer[i] + ExtNDIBuffer[i]; + double dTmp = _pdi_buff[i] + _ndi_buff[i]; if (dTmp != 0.0) - dTmp = 100.0 * MathAbs((ExtPDIBuffer[i] - ExtNDIBuffer[i]) / dTmp); + dTmp = 100.0 * MathAbs((_pdi_buff[i] - _ndi_buff[i]) / dTmp); else dTmp = 0.0; - ExtDXBuffer[i] = dTmp; + _dx_buff[i] = dTmp; // Fill ADXW buffer as smoothed DX buffer. - ExtADXWBuffer[i] = SmoothedMA(i, ExtADXWPeriod, ExtADXWBuffer[i - 1].Get(), ExtDXBuffer); + _adxw_buff[i] = SmoothedMA(i, _adxw_period, _adxw_buff[i - 1].Get(), _dx_buff); } // OnCalculate done. Return new prev_calculated. return (rates_total); From c48da70532b14a395937c81b3c110d93b4615582 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 24 Jun 2023 00:19:04 +0100 Subject: [PATCH 092/123] Indi_ADXW: Fixes logic for SetCustomIndicatorName() --- Indicators/Indi_ADXW.mqh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index e0d3deec5..0d1613344 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -39,7 +39,7 @@ struct IndiADXWParams : IndiADXParams { 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 == "") { + if (custom_indi_name == "" || custom_indi_name == "Examples\\ADX") { SetCustomIndicatorName("Examples\\ADXW"); } }; From 1b5830f8012c177c70df5f874a42728805e3d7c7 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 24 Jun 2023 14:30:01 +0100 Subject: [PATCH 093/123] Indicators: Renames some variables to avoid global variable conflict --- Indicators/Indi_AMA.mqh | 22 +++++++------- Indicators/Indi_FractalAdaptiveMA.mqh | 6 ++-- Indicators/Indi_MA.mqh | 44 +++++++++++++-------------- Indicators/Indi_TEMA.mqh | 4 +-- Indicators/Indi_VIDYA.mqh | 4 +-- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index 76daa7318..a50e2fff6 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -145,7 +145,7 @@ class Indi_AMA : public Indicator { /** * OnInit() method for AMA indicator. */ - static void CalculateInit(int InpPeriodAMA, int InpFastPeriodEMA, int InpSlowPeriodEMA, int InpShiftAMA, + static void CalculateInit(int InpPeriodAMA, int _period_fast_ema, int _period_slow_ema, int _ishift_ama, double &ExtFastSC, double &ExtSlowSC, int &ExtPeriodAMA, int &ExtSlowPeriodEMA, int &ExtFastPeriodEMA) { // Check for input values. @@ -156,20 +156,20 @@ class Indi_AMA : public Indicator { InpPeriodAMA, ExtPeriodAMA); } else ExtPeriodAMA = InpPeriodAMA; - if (InpSlowPeriodEMA <= 0) { + if (_period_slow_ema <= 0) { ExtSlowPeriodEMA = 30; PrintFormat( - "Input parameter InpSlowPeriodEMA has incorrect value (%d). Indicator will use value %d for calculations.", - InpSlowPeriodEMA, ExtSlowPeriodEMA); + "Input parameter _period_slow_ema has incorrect value (%d). Indicator will use value %d for calculations.", + _period_slow_ema, ExtSlowPeriodEMA); } else - ExtSlowPeriodEMA = InpSlowPeriodEMA; - if (InpFastPeriodEMA <= 0) { + ExtSlowPeriodEMA = _period_slow_ema; + if (_period_fast_ema <= 0) { ExtFastPeriodEMA = 2; PrintFormat( - "Input parameter InpFastPeriodEMA has incorrect value (%d). Indicator will use value %d for calculations.", - InpFastPeriodEMA, ExtFastPeriodEMA); + "Input parameter _period_fast_ema has incorrect value (%d). Indicator will use value %d for calculations.", + _period_fast_ema, ExtFastPeriodEMA); } else - ExtFastPeriodEMA = InpFastPeriodEMA; + ExtFastPeriodEMA = _period_fast_ema; // Calculate ExtFastSC & ExtSlowSC. ExtFastSC = 2.0 / (ExtFastPeriodEMA + 1.0); @@ -180,14 +180,14 @@ class Indi_AMA : public Indicator { * OnCalculate() method for AMA indicator. */ static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &ExtAMABuffer, int InpPeriodAMA, - int InpFastPeriodEMA, int InpSlowPeriodEMA, int InpShiftAMA) { + int _period_fast_ema, int _period_slow_ema, int _ishift_ama) { double ExtFastSC; double ExtSlowSC; int ExtPeriodAMA; int ExtSlowPeriodEMA; int ExtFastPeriodEMA; - CalculateInit(InpPeriodAMA, InpFastPeriodEMA, InpSlowPeriodEMA, InpShiftAMA, ExtFastSC, ExtSlowSC, ExtPeriodAMA, + CalculateInit(InpPeriodAMA, _period_fast_ema, _period_slow_ema, _ishift_ama, ExtFastSC, ExtSlowSC, ExtPeriodAMA, ExtSlowPeriodEMA, ExtFastPeriodEMA); int i; // Check for rates count. diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index 5ddbed457..d7d783a08 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -144,7 +144,7 @@ class Indi_FrAMA : public Indicator { } static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &FrAmaBuffer, int InpPeriodFrAMA, - int InpShift, ENUM_APPLIED_PRICE InpAppliedPrice) { + int _ishift, ENUM_APPLIED_PRICE _applied_price) { if (rates_total < 2 * InpPeriodFrAMA) return (0); int start, i; @@ -152,7 +152,7 @@ class Indi_FrAMA : public Indicator { if (prev_calculated == 0) { start = 2 * InpPeriodFrAMA - 1; for (i = 0; i <= start; i++) - FrAmaBuffer[i] = AppliedPriceValueStorage::GetApplied(open, high, low, close, i, InpAppliedPrice); + FrAmaBuffer[i] = AppliedPriceValueStorage::GetApplied(open, high, low, close, i, _applied_price); } else start = prev_calculated - 1; @@ -170,7 +170,7 @@ class Indi_FrAMA : public Indicator { 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 = AppliedPriceValueStorage::GetApplied(open, high, low, close, i, InpAppliedPrice); + double _iprice = AppliedPriceValueStorage::GetApplied(open, high, low, close, i, _applied_price); FrAmaBuffer[i] = alfa * _iprice + (1 - alfa) * FrAmaBuffer[i - 1].Get(); } diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 2f1a7ec69..6a796a9b0 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -267,23 +267,23 @@ class Indi_MA : public Indicator { * Calculates Simple Moving Average (SMA). The same as in "Example Moving Average" indicator. */ static void CalculateSimpleMA(int rates_total, int prev_calculated, int begin, ValueStorage &price, - ValueStorage &ExtLineBuffer, int _ma_period) { + ValueStorage &_line_buff, int _ma_period) { int i, start; // First calculation or number of bars was changed. if (prev_calculated == 0) { start = _ma_period + begin; // Set empty value for first start bars. - for (i = 0; i < start - 1; i++) ExtLineBuffer[i] = 0.0; + for (i = 0; i < start - 1; i++) _line_buff[i] = 0.0; // Calculate first visible value. double first_value = 0; for (i = begin; i < start; i++) first_value += price[i].Get(); first_value /= _ma_period; - ExtLineBuffer[start - 1] = first_value; + _line_buff[start - 1] = first_value; } else start = prev_calculated - 1; // Main loop. for (i = start; i < rates_total && !IsStopped(); i++) { - ExtLineBuffer[i] = ExtLineBuffer[i - 1] + (price[i] - price[i - _ma_period]) / _ma_period; + _line_buff[i] = _line_buff[i - 1] + (price[i] - price[i - _ma_period]) / _ma_period; } } @@ -291,21 +291,21 @@ class Indi_MA : public Indicator { * Calculates Exponential Moving Average (EMA). The same as in "Example Moving Average" indicator. */ static void CalculateEMA(int rates_total, int prev_calculated, int begin, ValueStorage &price, - ValueStorage &ExtLineBuffer, int _ma_period) { + ValueStorage &_line_buff, int _ma_period) { int i, limit; double SmoothFactor = 2.0 / (1.0 + _ma_period); // First calculation or number of bars was changed. if (prev_calculated == 0) { limit = _ma_period + begin; - ExtLineBuffer[begin] = price[begin]; + _line_buff[begin] = price[begin]; for (i = begin + 1; i < limit; i++) { - ExtLineBuffer[i] = price[i] * SmoothFactor + ExtLineBuffer[i - 1] * (1.0 - SmoothFactor); + _line_buff[i] = price[i] * SmoothFactor + _line_buff[i - 1] * (1.0 - SmoothFactor); } } else limit = prev_calculated - 1; // Main loop. for (i = limit; i < rates_total && !IsStopped(); i++) { - ExtLineBuffer[i] = price[i] * SmoothFactor + ExtLineBuffer[i - 1] * (1.0 - SmoothFactor); + _line_buff[i] = price[i] * SmoothFactor + _line_buff[i - 1] * (1.0 - SmoothFactor); } } @@ -313,7 +313,7 @@ class Indi_MA : public Indicator { * Calculates Linearly Weighted Moving Average (LWMA). The same as in "Example Moving Average" indicator. */ static void CalculateLWMA(int rates_total, int prev_calculated, int begin, ValueStorage &price, - ValueStorage &ExtLineBuffer, int _ma_period) { + ValueStorage &_line_buff, int _ma_period) { int i, limit; static int weightsum; double sum; @@ -322,7 +322,7 @@ class Indi_MA : public Indicator { weightsum = 0; limit = _ma_period + begin; // Set empty value for first limit bars. - for (i = 0; i < limit; i++) ExtLineBuffer[i] = 0.0; + for (i = 0; i < limit; i++) _line_buff[i] = 0.0; // Calculate first visible value. double firstValue = 0; for (i = begin; i < limit; i++) { @@ -331,14 +331,14 @@ class Indi_MA : public Indicator { firstValue += k * price[i].Get(); } firstValue /= (double)weightsum; - ExtLineBuffer[limit - 1] = firstValue; + _line_buff[limit - 1] = firstValue; } else limit = prev_calculated - 1; // Main loop. for (i = limit; i < rates_total && !IsStopped(); i++) { sum = 0; for (int j = 0; j < _ma_period; j++) sum += (_ma_period - j) * price[i - j].Get(); - ExtLineBuffer[i] = sum / weightsum; + _line_buff[i] = sum / weightsum; } //--- } @@ -347,23 +347,23 @@ class Indi_MA : public Indicator { * Calculates Smoothed Moving Average (SMMA). The same as in "Example Moving Average" indicator. */ static void CalculateSmoothedMA(int rates_total, int prev_calculated, int begin, ValueStorage &price, - ValueStorage &ExtLineBuffer, int _ma_period) { + ValueStorage &_line_buff, int _ma_period) { int i, limit; // First calculation or number of bars was changed. if (prev_calculated == 0) { limit = _ma_period + begin; // Set empty value for first limit bars. - for (i = 0; i < limit - 1; i++) ExtLineBuffer[i] = 0.0; + for (i = 0; i < limit - 1; i++) _line_buff[i] = 0.0; // Calculate first visible value. double firstValue = 0; for (i = begin; i < limit; i++) firstValue += price[i].Get(); firstValue /= _ma_period; - ExtLineBuffer[limit - 1] = firstValue; + _line_buff[limit - 1] = firstValue; } else limit = prev_calculated - 1; // Main loop. for (i = limit; i < rates_total && !IsStopped(); i++) - ExtLineBuffer[i] = (ExtLineBuffer[i - 1] * (_ma_period - 1) + price[i].Get()) / _ma_period; + _line_buff[i] = (_line_buff[i - 1] * (_ma_period - 1) + price[i].Get()) / _ma_period; //--- } @@ -582,7 +582,7 @@ class Indi_MA : public Indicator { * Calculates Moving Average. The same as in "Example Moving Average" indicator. */ static int Calculate(const int rates_total, const int prev_calculated, const int begin, ValueStorage &price, - ValueStorage &ExtLineBuffer, int _ma_method, int _ma_period) { + ValueStorage &_line_buff, int _ma_method, int _ma_period) { // Check for bars count. if (rates_total < _ma_period - 1 + begin) { // Not enough bars for calculation. @@ -590,22 +590,22 @@ class Indi_MA : public Indicator { } if (prev_calculated == 0) { // First calculation or number of bars was changed. - ArrayInitialize(ExtLineBuffer, (double)0); + ArrayInitialize(_line_buff, (double)0); } // Calculation. switch (_ma_method) { case MODE_EMA: - CalculateEMA(rates_total, prev_calculated, begin, price, ExtLineBuffer, _ma_period); + CalculateEMA(rates_total, prev_calculated, begin, price, _line_buff, _ma_period); break; case MODE_LWMA: - CalculateLWMA(rates_total, prev_calculated, begin, price, ExtLineBuffer, _ma_period); + CalculateLWMA(rates_total, prev_calculated, begin, price, _line_buff, _ma_period); break; case MODE_SMMA: - CalculateSmoothedMA(rates_total, prev_calculated, begin, price, ExtLineBuffer, _ma_period); + CalculateSmoothedMA(rates_total, prev_calculated, begin, price, _line_buff, _ma_period); break; case MODE_SMA: - CalculateSimpleMA(rates_total, prev_calculated, begin, price, ExtLineBuffer, _ma_period); + CalculateSimpleMA(rates_total, prev_calculated, begin, price, _line_buff, _ma_period); break; } // Return value of prev_calculated for next call. diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index cd380ea24..8c1be3f40 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -127,11 +127,11 @@ class Indi_TEMA : public Indicator { /** * OnCalculate() method for TEMA indicator. * - * Note that InpShift is used for drawing only and thus is unused. + * Note that _ishift is used for drawing only and thus is unused. */ static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &TemaBuffer, ValueStorage &Ema, ValueStorage &EmaOfEma, ValueStorage &EmaOfEmaOfEma, - int InpPeriodEMA, int InpShift) { + int InpPeriodEMA, int _ishift) { if (rates_total < 3 * InpPeriodEMA - 3) return (0); //--- int start; diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index 8e13b4c27..aff6a87f1 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -132,10 +132,10 @@ class Indi_VIDYA : public Indicator { /** * OnCalculate() method for VIDyA indicator. * - * Note that InpShift is used for drawing only and thus is unused. + * Note that _ishift is used for drawing only and thus is unused. */ static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &VIDYA_Buffer, int InpPeriodCMO, - int InpPeriodEMA, int InpShift) { + int InpPeriodEMA, int _ishift) { double ExtF = 2.0 / (1.0 + InpPeriodEMA); if (rates_total < InpPeriodEMA + InpPeriodCMO - 1) return (0); From 7b292b7c0c85e59331956ee6e83181f4df956a24 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 10 Sep 2023 15:00:57 +0100 Subject: [PATCH 094/123] Improves Fibonacci calculation for Pivot --- Bar.struct.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Bar.struct.h b/Bar.struct.h index 5d0f18255..2d07403a6 100644 --- a/Bar.struct.h +++ b/Bar.struct.h @@ -101,14 +101,16 @@ struct BarOHLC break; case PP_FIBONACCI: _pp = GetPivot(); - _r1 = (double)(_pp + 0.382 * _range); - _r2 = (double)(_pp + 0.618 * _range); - _r3 = _pp + _range; - _r4 = _r1 + _range; // ? - _s1 = (double)(_pp - 0.382 * _range); - _s2 = (double)(_pp - 0.618 * _range); - _s3 = _pp - _range; - _s4 = _s1 - _range; // ? + _r1 = (double)(_pp + 0.236 * _range); + _r2 = (double)(_pp + 0.382 * _range); + _r3 = (double)(_pp + 0.500 * _range); + _r4 = (double)(_pp + 0.618 * _range); + // _r5 = (double)(_pp + 0.786 * _range); + _s1 = (double)(_pp - 0.236 * _range); + _s2 = (double)(_pp - 0.382 * _range); + _s3 = (double)(_pp - 0.500 * _range); + _s4 = (double)(_pp - 0.618 * _range); + // _s5 = (double)(_pp - 0.786 * _range); break; case PP_FLOOR: // Most basic and popular type of pivots used in Forex trading technical analysis. From bbf828473fb882dbb810198984d3fa6ea8509b30 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 18 Mar 2024 19:28:42 +0100 Subject: [PATCH 095/123] ACQUIRE_BUFFERn / RELEASE_BUFFERn functionality required for EA31337/EA31337-indicators-stats#1 --- Std.h | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/Std.h b/Std.h index a680db7d2..f46504330 100644 --- a/Std.h +++ b/Std.h @@ -298,3 +298,157 @@ inline _NULL_VALUE::operator const std::string() const { #else #define NULL_VALUE NULL #endif + +/** + * Standarization of specifying ArraySetAsSeries for OnCalculate(). + * Automatically determines required ArraySetAsSeries for buffers on start and + * end of given code block that uses given buffers. + */ + +#define SET_BUFFER_AS_SERIES_FOR_TARGET(A) ArraySetAsSeries(A, false); + +#ifdef __MQL4__ +#define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, true); +#else +#define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, false); +#endif + +// Ensures that we do RELEASE_BUFFERx after ACQUIRE_BUFFERx. +struct AsSeriesReleaseEnsurer { + bool released; + int num_buffs; + AsSeriesReleaseEnsurer(int _num_buffs) : released(false), num_buffs(_num_buffs) {} + void done(int _num_buffs) { + if (_num_buffs != num_buffs) { + Alert("You have acquired ", num_buffs, " buffers via ACQUIRE_BUFFER", num_buffs, + "(), but now trying to release with mismatched RELEASE_BUFFER", _num_buffs, "()!"); + DebugBreak(); + } + + if (released) { + Alert("You have used RELEASE_BUFFER", num_buffs, "() again which is not required!"); + DebugBreak(); + } + + released = true; + } + ~AsSeriesReleaseEnsurer() { + if (!released) { + Alert("You have used ACQUIRE_BUFFER", num_buffs, "() but didn't release buffer(s) via RELEASE_BUFFER", num_buffs, + "() before returning from the scope!"); + DebugBreak(); + } + } +}; + +#define SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(NUM_BUFFS) \ + AsSeriesReleaseEnsurer _as_series_release_ensurer(NUM_BUFFS); +#define SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(NUM_BUFFS) _as_series_release_ensurer.done(NUM_BUFFS); + +// Acquiring buffer is preparing it to be used as in MQL5. +#define ACQUIRE_BUFFER1(A) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(1); +#define ACQUIRE_BUFFER2(A, B) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(2); +#define ACQUIRE_BUFFER3(A, B, C) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(3); +#define ACQUIRE_BUFFER4(A, B, C, D) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(4); +#define ACQUIRE_BUFFER5(A, B, C, D, E) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(5); +#define ACQUIRE_BUFFER6(A, B, C, D, E, F) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(6); +#define ACQUIRE_BUFFER7(A, B, C, D, E, F, G) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(G); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(7); +#define ACQUIRE_BUFFER8(A, B, C, D, E, F, G, H) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(G); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(H); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(8); + +// Releasing buffer is setting its AsSeries as the default in the host language. +#define RELEASE_BUFFER1(A) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(1); +#define RELEASE_BUFFER2(A, B) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(2); +#define RELEASE_BUFFER3(A, B, C) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(3); +#define RELEASE_BUFFER4(A, B, C, D) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(4); +#define RELEASE_BUFFER5(A, B, C, D, E) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(5); +#define RELEASE_BUFFER6(A, B, C, D, E, F) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); \ + SET_BUFFER_AS_SERIES_FOR_HOST(F); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(6); +#define RELEASE_BUFFER7(A, B, C, D, E, F, G) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); \ + SET_BUFFER_AS_SERIES_FOR_HOST(F); \ + SET_BUFFER_AS_SERIES_FOR_HOST(G); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(7); +#define RELEASE_BUFFER8(A, B, C, D, E, F, G, H) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); \ + SET_BUFFER_AS_SERIES_FOR_HOST(F); \ + SET_BUFFER_AS_SERIES_FOR_HOST(G); \ + SET_BUFFER_AS_SERIES_FOR_HOST(H); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(8); From 20a08a785353e183de99145f46d973538fdac24d Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 22 Mar 2024 20:21:07 +0100 Subject: [PATCH 096/123] Refs EA31337/EA31337-indicators-stats#2. Closed to finish Indi_AccountStats indicator. --- Account/Account.h | 1 + Account/AccountBase.h | 40 ++++ Account/AccountMt.h | 15 +- Indicator.enum.h | 25 ++- Indicator/IndicatorCandle.h | 28 ++- Indicator/IndicatorTick.h | 2 +- Indicator/tests/classes/IndicatorTfDummy.h | 12 +- Indicator/tests/classes/IndicatorTickDummy.h | 16 +- IndicatorData.mqh | 10 +- Indicators/Account/Indi_AccountStats.mqh | 207 ++++++++++++++++++ .../Account/tests/Indi_AccountStats.test.mq4 | 27 +++ .../Account/tests/Indi_AccountStats.test.mq5 | 61 ++++++ Indicators/Indi_AMA.mqh | 8 - Indicators/Tick/Indi_TickMt.mqh | 6 +- Storage/IValueStorage.h | 5 + Storage/ValueStorage.h | 9 + Storage/ValueStorage.native.h | 19 +- 17 files changed, 444 insertions(+), 47 deletions(-) create mode 100644 Indicators/Account/Indi_AccountStats.mqh create mode 100644 Indicators/Account/tests/Indi_AccountStats.test.mq4 create mode 100644 Indicators/Account/tests/Indi_AccountStats.test.mq5 diff --git a/Account/Account.h b/Account/Account.h index 5e50510d5..a42e5822c 100644 --- a/Account/Account.h +++ b/Account/Account.h @@ -56,4 +56,5 @@ class Account : public AccountBase { */ ~Account() {} }; + #endif // ACCOUNT_H diff --git a/Account/AccountBase.h b/Account/AccountBase.h index 9d3ae7253..187649570 100644 --- a/Account/AccountBase.h +++ b/Account/AccountBase.h @@ -56,6 +56,46 @@ class AccountBase : public Dynamic { * Class deconstructor. */ ~AccountBase() {} + + /** + * Returns balance value of the current account. + */ + virtual datetime GetDateTime() { return TimeCurrent(); }; + + /** + * Returns balance value of the current account. + */ + virtual float GetBalance() = 0; + + /** + * Returns credit value of the current account. + */ + virtual float GetCredit() = 0; + + /** + * Returns profit value of the current account. + */ + virtual float GetProfit() = 0; + + /** + * Returns equity value of the current account. + */ + virtual float GetEquity() = 0; + + /** + * Returns margin value of the current account. + */ + virtual float GetMarginUsed() = 0; + + /** + * Returns free margin value of the current account. + */ + virtual float GetMarginFree() = 0; + + /** + * Get account available margin. + */ + virtual float GetMarginAvail() = 0; }; #endif // ACCOUNTBASE_H diff --git a/Account/AccountMt.h b/Account/AccountMt.h index c03c300f9..66f053591 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -42,12 +42,13 @@ class AccountMt; #include "Account.define.h" #include "Account.enum.h" #include "Account.extern.h" +#include "Account.h" #include "Account.struct.h" /** * Class to provide functions that return parameters of the current account. */ -class AccountMt { +class AccountMt : public AccountBase { protected: // Struct variables. BufferStruct entries; @@ -136,7 +137,7 @@ class AccountMt { * Returns balance value of the current account. */ static double AccountBalance() { return AccountInfoDouble(ACCOUNT_BALANCE); } - float GetBalance() { + float GetBalance() override { // @todo: Adds caching. // return UpdateStats(ACC_BALANCE, AccountBalance()); return (float)AccountMt::AccountBalance(); @@ -146,7 +147,7 @@ class AccountMt { * Returns credit value of the current account. */ static double AccountCredit() { return AccountInfoDouble(ACCOUNT_CREDIT); } - float GetCredit() { + float GetCredit() override { // @todo: Adds caching. // return UpdateStats(ACC_CREDIT, AccountCredit()); return (float)AccountMt::AccountCredit(); @@ -156,7 +157,7 @@ class AccountMt { * Returns profit value of the current account. */ static double AccountProfit() { return AccountInfoDouble(ACCOUNT_PROFIT); } - float GetProfit() { + float GetProfit() override { // @todo: Adds caching. // return UpdateStats(ACC_PROFIT, AccountProfit()); return (float)AccountMt::AccountProfit(); @@ -166,7 +167,7 @@ class AccountMt { * Returns equity value of the current account. */ static double AccountEquity() { return AccountInfoDouble(ACCOUNT_EQUITY); } - float GetEquity() { + float GetEquity() override { // @todo: Adds caching. // return UpdateStats(ACC_EQUITY, AccountEquity()); return (float)AccountMt::AccountEquity(); @@ -198,7 +199,7 @@ class AccountMt { * Returns free margin value of the current account. */ static double AccountFreeMargin() { return AccountInfoDouble(ACCOUNT_MARGIN_FREE); } - float GetMarginFree() { + float GetMarginFree() override { // @todo: Adds caching. // return UpdateStats(ACC_MARGIN_FREE, AccountFreeMargin()); return (float)AccountMt::AccountFreeMargin(); @@ -267,7 +268,7 @@ class AccountMt { * Get account available margin. */ static double AccountAvailMargin() { return fmin(AccountFreeMargin(), AccountTotalBalance()); } - float GetMarginAvail() { return (float)AccountAvailMargin(); } + float GetMarginAvail() override { return (float)AccountAvailMargin(); } /** * Returns the calculation mode of free margin allowed to open orders on the current account. diff --git a/Indicator.enum.h b/Indicator.enum.h index b2b07a3a4..c20b4e8b6 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -44,6 +44,7 @@ enum ENUM_INDICATOR_ACTION { enum ENUM_INDICATOR_TYPE { INDI_NONE = 0, // (None) INDI_AC, // Accelerator Oscillator + INDI_ACCOUNT_STATS, // Account Stats INDI_AD, // Accumulation/Distribution INDI_ADX, // Average Directional Index INDI_ADXW, // ADX by Welles Wilder @@ -237,9 +238,24 @@ enum ENUM_INDI_VS_TYPE { 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 + INDI_VS_TYPE_INDEX_LAST = INDI_VS_TYPE_INDEX_9, + + // Account Stats. + INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME, + INDI_VS_TYPE_ACCOUNT_STATS_BALANCE, + INDI_VS_TYPE_ACCOUNT_STATS_CREDIT, + INDI_VS_TYPE_ACCOUNT_STATS_EQUITY, + INDI_VS_TYPE_ACCOUNT_STATS_PROFIT, + INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED, + INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE, + INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL, + INDI_VS_TYPE_ACCOUNT_STATS_INDEX_FIRST = INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME, + INDI_VS_TYPE_ACCOUNT_STATS_INDEX_LAST = INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL, }; +#define INDI_VS_TYPE_ACCOUNT_STATS_BUFFERS_COUNT \ + (INDI_VS_TYPE_ACCOUNT_STATS_INDEX_LAST - INDI_VS_TYPE_ACCOUNT_STATS_INDEX_FIRST + 1) + // Indicator flags. enum ENUM_INDI_FLAGS { INDI_FLAG_INDEXABLE_BY_SHIFT, // Indicator supports indexation by shift. @@ -269,4 +285,11 @@ enum ENUM_INDI_DS_MODE_KIND { 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. }; + +// Type of entry +enum ENUM_INDI_EMITTED_ENTRY_TYPE { + INDI_EMITTED_ENTRY_TYPE_PARENT, // Undetermined type of entry from direct parent indicator. + INDI_EMITTED_ENTRY_TYPE_TICK, + INDI_EMITTED_ENTRY_TYPE_CANDLE, +}; //+------------------------------------------------------------------+ diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 8221afe82..da34844ca 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -32,6 +32,7 @@ // Includes. #include "../Buffer/BufferCandle.h" #include "../Candle.struct.h" +#include "../Indicator.enum.h" #include "../Indicator.mqh" #include "../Storage/ValueStorage.price_median.h" #include "../Storage/ValueStorage.price_typical.h" @@ -310,7 +311,7 @@ class IndicatorCandle : public Indicator { void EmitHistory() override { for (DictStructIterator> iter(icdata.Begin()); iter.IsValid(); ++iter) { IndicatorDataEntry _entry = CandleToEntry(iter.Key(), iter.Value()); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_CANDLE); } } @@ -342,7 +343,7 @@ class IndicatorCandle : public Indicator { /** * Adds tick's price to the matching candle and updates its OHLC values. */ - void UpdateCandle(long _tick_timestamp, double _price) { + CandleOCTOHLC UpdateCandle(long _tick_timestamp, double _price) { long _candle_timestamp = CalcCandleTimestamp(_tick_timestamp); #ifdef __debug_verbose__ @@ -368,6 +369,8 @@ class IndicatorCandle : public Indicator { } icdata.Add(_candle, _candle_timestamp); + + return _candle; } /** @@ -380,12 +383,25 @@ class IndicatorCandle : public Indicator { /** * Called when data source emits new entry (historic or future one). */ - void OnDataSourceEntry(IndicatorDataEntry& entry) override { - // Updating candle from bid price. - UpdateCandle(entry.timestamp, entry[1]); + void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + Indicator::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } + + long _candle_timestamp = CalcCandleTimestamp(entry.timestamp); // Updating tick & bar indices. - counter.OnTick(CalcCandleTimestamp(entry.timestamp)); + counter.OnTick(_candle_timestamp); + + // Updating candle from bid price. + CandleOCTOHLC _candle = UpdateCandle(entry.timestamp, entry[1]); + + // Emitting candle for children. + IndicatorDataEntry _candle_entry = CandleToEntry(_candle_timestamp, _candle); + EmitEntry(_candle_entry, INDI_EMITTED_ENTRY_TYPE_CANDLE); }; /** diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 5438923cb..cf01dfe83 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -164,7 +164,7 @@ class IndicatorTick : public Indicator { void EmitHistory() override { for (DictStructIterator> iter(itdata.Begin()); iter.IsValid(); ++iter) { IndicatorDataEntry _entry = TickToEntry(iter.Key(), iter.Value()); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); } } diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 019b800d8..f49a8161d 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -48,11 +48,13 @@ class IndicatorTfDummy : public IndicatorTf { string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } - void OnDataSourceEntry(IndicatorDataEntry& entry) override { - // When overriding OnDataSourceEntry() we have to remember to call parent - // method, because IndicatorCandle also need to invoke it in order to - // create/update matching candle. - IndicatorTf::OnDataSourceEntry(entry); + void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + IndicatorTf::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } #ifdef __debug_indicator__ Print(GetFullName(), " got new tick at ", entry.timestamp, diff --git a/Indicator/tests/classes/IndicatorTickDummy.h b/Indicator/tests/classes/IndicatorTickDummy.h index dfd59e9a3..3e6bab0ab 100644 --- a/Indicator/tests/classes/IndicatorTickDummy.h +++ b/Indicator/tests/classes/IndicatorTickDummy.h @@ -59,13 +59,13 @@ class IndicatorTickDummy : public IndicatorTick _t7(4.2f, 4.21f); TickAB _t8(4.8f, 4.81f); - EmitEntry(TickToEntry(1000, _t1)); - EmitEntry(TickToEntry(1500, _t2)); - EmitEntry(TickToEntry(2000, _t3)); - EmitEntry(TickToEntry(3000, _t4)); - EmitEntry(TickToEntry(4000, _t5)); - EmitEntry(TickToEntry(4100, _t6)); - EmitEntry(TickToEntry(4200, _t7)); - EmitEntry(TickToEntry(4800, _t8)); + EmitEntry(TickToEntry(1000, _t1), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(1500, _t2), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(2000, _t3), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(3000, _t4), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4000, _t5), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4100, _t6), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4200, _t7), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4800, _t8), INDI_EMITTED_ENTRY_TYPE_TICK); }; }; diff --git a/IndicatorData.mqh b/IndicatorData.mqh index 46225b8d3..bc0c498b1 100644 --- a/IndicatorData.mqh +++ b/IndicatorData.mqh @@ -1616,10 +1616,10 @@ class IndicatorData : public IndicatorBase { /** * Sends entry to listening indicators. */ - void EmitEntry(IndicatorDataEntry& entry) { + void EmitEntry(IndicatorDataEntry& entry, ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) { for (int i = 0; i < ArraySize(listeners); ++i) { if (listeners[i].ObjectExists()) { - listeners[i].Ptr().OnDataSourceEntry(entry); + listeners[i].Ptr().OnDataSourceEntry(entry, type); } } } @@ -1683,7 +1683,11 @@ class IndicatorData : public IndicatorBase { /** * Called when data source emits new entry (historic or future one). */ - virtual void OnDataSourceEntry(IndicatorDataEntry& entry){}; + virtual void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) { + // Sending entry to all chilren listeners (from highest parent to lowest child). + EmitEntry(entry, type); + }; virtual void OnTick() {} diff --git a/Indicators/Account/Indi_AccountStats.mqh b/Indicators/Account/Indi_AccountStats.mqh new file mode 100644 index 000000000..da45fef7d --- /dev/null +++ b/Indicators/Account/Indi_AccountStats.mqh @@ -0,0 +1,207 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Includes. +#include "../../Account/AccountBase.h" +#include "../../BufferStruct.mqh" +#include "../../Indicator.mqh" +#include "../../Platform.h" +#include "../../Storage/Objects.h" + +// Structs. +struct Indi_AccountStats_Params : IndicatorParams { + // Applied price. + ENUM_APPLIED_PRICE ap; + + // Account to use. + Ref account; + + // Struct constructor. + Indi_AccountStats_Params(AccountBase *_account = nullptr, int _shift = 0) + : IndicatorParams(INDI_ACCOUNT_STATS), account(_account) { + SetShift(_shift); + }; + Indi_AccountStats_Params(Indi_AccountStats_Params &_params) { THIS_REF = _params; }; + + // Getters. + AccountBase *GetAccount() { return account.Ptr(); } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return ap; } + + // Setters. + void SetAccount(AccountBase *_account) { account = _account; } + void SetAppliedPrice(ENUM_APPLIED_PRICE _ap) { ap = _ap; } +}; + +/** + * Price Indicator. + */ +class Indi_AccountStats : public Indicator { + Ref> buffer_date_time; + Ref> buffer_balance; + Ref> buffer_credit; + Ref> buffer_equity; + Ref> buffer_profit; + Ref> buffer_margin_used; + Ref> buffer_margin_free; + Ref> buffer_margin_avail; + + public: + /** + * Class constructor. + */ + Indi_AccountStats(Indi_AccountStats_Params &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : Indicator(_p, + IndicatorDataParams::GetInstance(INDI_VS_TYPE_ACCOUNT_STATS_BUFFERS_COUNT, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + InitAccountStats(); + }; + Indi_AccountStats(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(Indi_AccountStats_Params(), + IndicatorDataParams::GetInstance(INDI_VS_TYPE_ACCOUNT_STATS_BUFFERS_COUNT, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + InitAccountStats(); + }; + void InitAccountStats() { + buffer_date_time = new NativeValueStorage(); + buffer_balance = new NativeValueStorage(); + buffer_credit = new NativeValueStorage(); + buffer_equity = new NativeValueStorage(); + buffer_profit = new NativeValueStorage(); + buffer_margin_used = new NativeValueStorage(); + buffer_margin_free = new NativeValueStorage(); + buffer_margin_avail = new NativeValueStorage(); + } + + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + virtual unsigned int GetSuitableDataSourceTypes() { + // We require that candle indicator is attached. + 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; } + + /** + * Checks whether indicator has a valid value for a given shift. + */ + virtual bool HasValidEntry(int _shift = 0) { return GetBarTime(_shift) != 0; } + + /** + * Returns the indicator's value. + */ + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + + // Converting mode into value storage type. + ENUM_INDI_VS_TYPE _vs_type = (ENUM_INDI_VS_TYPE)(INDI_VS_TYPE_ACCOUNT_STATS_INDEX_FIRST + _mode); + + // Retrieving data from specific value storage. + switch (_vs_type) { + case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: + return ((ValueStorage *)GetSpecificValueStorage(_vs_type))PTR_DEREF FetchSeries(_ishift); + case INDI_VS_TYPE_ACCOUNT_STATS_BALANCE: + case INDI_VS_TYPE_ACCOUNT_STATS_CREDIT: + case INDI_VS_TYPE_ACCOUNT_STATS_EQUITY: + case INDI_VS_TYPE_ACCOUNT_STATS_PROFIT: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL: + return ((ValueStorage *)GetSpecificValueStorage(_vs_type))PTR_DEREF FetchSeries(_ishift); + default: + Alert("Error: Indi_AccountStats: Invalid mode passed to GetEntryValue()!"); + DebugBreak(); + return EMPTY_VALUE; + } + } + + /** + * Returns value storage of given kind. + */ + IValueStorage *GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + // Returning Price indicator which provides applied price in the only buffer #0. + switch (_type) { + case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: + return buffer_date_time.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_BALANCE: + return buffer_balance.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_CREDIT: + return buffer_credit.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_EQUITY: + return buffer_equity.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_PROFIT: + return buffer_profit.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED: + return buffer_margin_used.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE: + return buffer_margin_free.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL: + return buffer_margin_avail.Ptr(); + default: + // Trying in parent class. + return Indicator::GetSpecificValueStorage(_type); + } + } + + /** + * Checks whether indicator support given value storage type. + */ + bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + switch (_type) { + case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: + case INDI_VS_TYPE_ACCOUNT_STATS_BALANCE: + case INDI_VS_TYPE_ACCOUNT_STATS_CREDIT: + case INDI_VS_TYPE_ACCOUNT_STATS_EQUITY: + case INDI_VS_TYPE_ACCOUNT_STATS_PROFIT: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL: + return true; + default: + // Trying in parent class. + return Indicator::HasSpecificValueStorage(_type); + } + } + + /** + * Called when data source emits new entry (historic or future one). + */ + virtual void OnDataSourceEntry(IndicatorDataEntry &entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) { + Indicator::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_CANDLE) { + return; + } + + // Adding new account stats entry. + + Print("New candle: ", entry.ToString()); + } +}; diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq4 b/Indicators/Account/tests/Indi_AccountStats.test.mq4 new file mode 100644 index 000000000..8356c50b5 --- /dev/null +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq4 @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| 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 + * Test functionality of Indi_AC indicator class. + */ + +#include "Indi_AC.test.mq5" diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq5 b/Indicators/Account/tests/Indi_AccountStats.test.mq5 new file mode 100644 index 000000000..c81e0da79 --- /dev/null +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq5 @@ -0,0 +1,61 @@ +//+------------------------------------------------------------------+ +//| 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. +#include "../../../Account/AccountMt.h" +#include "../../../Platform.h" +#include "../../../Test.mqh" +#include "../Indi_AccountStats.mqh" + +/** + * @file + * Test functionality of Indi_AccountStats indicator class. + */ + +Ref indi_account_mt; + +int OnInit() { + Ref account_mt = new AccountMt(); + Indi_AccountStats_Params indi_params(account_mt.Ptr()); + indi_account_mt = new Indi_AccountStats(indi_params); + + Platform::Init(); + + Platform::AddWithDefaultBindings(indi_account_mt.Ptr()); + + bool _result = true; + assertTrueOrFail(indi_account_mt 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_account_mt REF_DEREF GetEntry(); + bool _is_ready = indi_account_mt REF_DEREF Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)); + bool _is_valid = _entry.IsValid(); + Print(indi_account_mt REF_DEREF ToString(), _is_ready ? "" : " (Not yet ready)"); + if (_is_ready && !_is_valid) { + Print(indi_account_mt REF_DEREF ToString(), " (Invalid entry!)"); + assertTrueOrExit(_entry.IsValid(), "Invalid entry!"); + } + } +} \ No newline at end of file diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index ec615c8ac..4fde34ef7 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -256,14 +256,6 @@ class Indi_AMA : public Indicator { return _value; } - /** - * Called when data source emits new entry (historic or future one). - */ - void OnDataSourceEntry(IndicatorDataEntry &entry) override { - // Just to be able to make a breakpoint here. - int x = 4; - }; - /** * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on * some data source. diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 726004fff..b60ee2d04 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -159,7 +159,7 @@ class Indi_TickMt : public IndicatorTick { _tmp_ticks[i].ask, ", ", _tmp_ticks[i].bid); #endif - EmitEntry(TickToEntry(_tmp_ticks[i].time, _tick)); + EmitEntry(TickToEntry(_tmp_ticks[i].time, _tick), INDI_EMITTED_ENTRY_TYPE_TICK); if (_num_yet_to_copy <= 0) { break; @@ -205,7 +205,7 @@ class Indi_TickMt : public IndicatorTick { // DebugBreak(); // Just emitting zeroes in case of error. TickAB _tick(0, 0); - EmitEntry(TickToEntry(TimeCurrent(), _tick)); + EmitEntry(TickToEntry(TimeCurrent(), _tick), INDI_EMITTED_ENTRY_TYPE_TICK); return; } @@ -224,6 +224,6 @@ class Indi_TickMt : public IndicatorTick { TickAB _tick(_ask, _bid); IndicatorDataEntry _entry(TickToEntry(_time, _tick)); StoreEntry(_entry); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); } }; diff --git a/Storage/IValueStorage.h b/Storage/IValueStorage.h index 290c2552d..6f4897bf6 100644 --- a/Storage/IValueStorage.h +++ b/Storage/IValueStorage.h @@ -72,6 +72,11 @@ class IValueStorage : public Dynamic { DebugBreak(); return false; } + + /** + * Returns real array index for this given shift. + **/ + virtual int GetRealIndex(int _shift) { return IsSeries() ? (Size() - 1 - _shift) : _shift; } }; /** diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index 6c7979ba0..865b2d651 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -181,6 +181,15 @@ class ValueStorage : public IValueStorage { DebugBreak(); } + /** + * Inserts new value at the end of the buffer. If buffer works as As-Series, + * then new value will act as the one at index 0. + */ + virtual void Append(C _value) { + Alert(__FUNCSIG__, " does not implement Append()!"); + DebugBreak(); + } + /** * Sets buffer drawing attributes. Currently does nothing. */ diff --git a/Storage/ValueStorage.native.h b/Storage/ValueStorage.native.h index 46ca12565..0c6180881 100644 --- a/Storage/ValueStorage.native.h +++ b/Storage/ValueStorage.native.h @@ -60,19 +60,28 @@ class NativeValueStorage : public ValueStorage { * Fetches value from a given shift. Takes into consideration as-series flag. */ C Fetch(int _shift) override { - if (_shift < 0 || _shift >= ArraySize(_values)) { + if (_shift < 0 || _shift >= Size()) { return (C)EMPTY_VALUE; - // Print("Invalid buffer data index: ", _shift, ". Buffer size: ", ArraySize(_values)); - // DebugBreak(); } - return _values[_shift]; + int _index = GetRealIndex(_shift); + + return _values[_index]; } /** * Stores value at a given shift. Takes into consideration as-series flag. */ - void Store(int _shift, C _value) override { Array::ArrayStore(_values, _shift, _value, 4096); } + void Store(int _shift, C _value) override { + if (_shift < 0 || _shift >= Size()) { + Alert("Error: NativeValueStorage: Invalid buffer data index: ", _shift, ". Buffer size: ", Size()); + DebugBreak(); + } + + int _index = GetRealIndex(_shift); + + Array::ArrayStore(_values, _index, _value, 4096); + } /** * Returns number of values available to fetch (size of the values buffer). From 4e763ae798519f18c02e1983dbdcd2647e05c49e Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 27 Mar 2024 15:13:43 +0100 Subject: [PATCH 097/123] WIP. Refs EA31337/EA31337-indicators-stats#2. Indi_AccountStats closer to be finished. Awaiting to fix MT5 compiler bug. --- IndicatorData.mqh | 48 ++++++++++--------- Indicators/Account/Indi_AccountStats.mqh | 26 ++++++++-- .../Account/tests/Indi_AccountStats.test.mq5 | 2 +- Storage/ValueStorage.native.h | 9 ++++ 4 files changed, 58 insertions(+), 27 deletions(-) diff --git a/IndicatorData.mqh b/IndicatorData.mqh index bc0c498b1..990c2e1f3 100644 --- a/IndicatorData.mqh +++ b/IndicatorData.mqh @@ -68,7 +68,7 @@ class IndicatorData : public IndicatorBase { case IDATA_ICUSTOM: break; case IDATA_INDICATOR: - if (indi_src.IsSet() == NULL) { + if (indi_src.IsSet()) { // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); // SetDataSource(_indi_price, true, PRICE_OPEN); } @@ -109,7 +109,7 @@ class IndicatorData : public IndicatorBase { /** * Class constructor. */ - IndicatorData(const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + IndicatorData(const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = nullptr, int _indi_mode = 0) : do_draw(false), idparams(_idparams), indi_src(_indi_src) { Init(); } @@ -572,9 +572,9 @@ class IndicatorData : public IndicatorBase { * Returns currently selected data source doing validation. */ IndicatorData* GetDataSource(bool _validate = true) { - IndicatorData* _result = NULL; + IndicatorData* _result = nullptr; - if (GetDataSourceRaw() != NULL) { + if (GetDataSourceRaw() != nullptr) { _result = GetDataSourceRaw(); } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) { int _source_id = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)); @@ -603,7 +603,7 @@ class IndicatorData : public IndicatorBase { // Requesting potential data source. _result = OnDataSourceRequest(); - if (_result != NULL) { + if (_result != nullptr) { // Initializing with new data source. SetDataSource(_result); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR); @@ -621,7 +621,7 @@ class IndicatorData : public IndicatorBase { * Returns given data source type. Used by i*OnIndicator methods if indicator's Calculate() uses other indicators. */ IndicatorData* GetDataSource(ENUM_INDICATOR_TYPE _type) { - IndicatorData* _result = NULL; + IndicatorData* _result = nullptr; if (indicators.KeyExists((int)_type)) { _result = indicators[(int)_type].Ptr(); } else { @@ -697,11 +697,15 @@ class IndicatorData : public IndicatorBase { } if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_INDICATOR && - GetDataSourceRaw() == NULL && _try_initialize) { + GetDataSourceRaw() == nullptr && _try_initialize) { SetDataSource(OnDataSourceRequest()); } - return GetDataSourceRaw() != NULL; + IndicatorData* _ptr = GetDataSourceRaw(); + + bool _result = _ptr != nullptr; + + return _result; } /** @@ -802,7 +806,7 @@ class IndicatorData : public IndicatorBase { indi_src.Ptr().RemoveListener(THIS_PTR); } indi_src = _indi; - if (_indi != NULL) { + if (_indi != nullptr) { 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); @@ -862,7 +866,7 @@ class IndicatorData : public IndicatorBase { last_tick_time = _current_time; // Checking and potentially initializing new data source. - if (HasDataSource(true) != NULL) { + if (HasDataSource(true)) { // Ticking data source if not yet ticked. GetDataSource().Tick(); } @@ -905,13 +909,13 @@ class IndicatorData : public IndicatorBase { * Loads and validates built-in indicators whose can be used as data source. */ void ValidateDataSource(IndicatorData* _target, IndicatorData* _source) { - if (_target == NULL) { + if (_target == nullptr) { Alert("Internal Error! _target is NULL in ", __FUNCTION_LINE__, "."); DebugBreak(); return; } - if (_source == NULL) { + if (_source == nullptr) { Alert("Error! You have to select source indicator's via SetDataSource()."); DebugBreak(); return; @@ -1129,7 +1133,7 @@ class IndicatorData : public IndicatorBase { _originator PTR_DEREF GetFullName(), "!"); DebugBreak(); } - return NULL; + return nullptr; } } @@ -1146,7 +1150,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's struct value via index. */ - virtual IndicatorDataEntry GetEntry(long _index = 0) = NULL; + virtual IndicatorDataEntry GetEntry(long _index = 0) = 0; /** * Returns the indicator's struct value via timestamp. @@ -1171,7 +1175,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's entry value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) = NULL; + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) = 0; /** * Returns the shift of the maximum value over a specific number of periods depending on type. @@ -1238,7 +1242,7 @@ class IndicatorData : public IndicatorBase { * * When indicator values are not valid, returns empty signals. */ - virtual IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) = NULL; + virtual IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) = 0; /** * Returns spread for the bar. @@ -1331,7 +1335,7 @@ class IndicatorData : public IndicatorBase { ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " "IndicatorBase::GetSpecificAppliedPriceValueStorage()!"); DebugBreak(); - return NULL; + return nullptr; } } @@ -1374,7 +1378,7 @@ class IndicatorData : public IndicatorBase { "Volume) in the hierarchy!"); DebugBreak(); } - return NULL; + return nullptr; } /** @@ -1390,7 +1394,7 @@ class IndicatorData : public IndicatorBase { virtual IValueStorage* GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { Print("Error: ", GetFullName(), " indicator has no storage type ", EnumToString(_type), "!"); DebugBreak(); - return NULL; + return nullptr; } /** @@ -1632,7 +1636,7 @@ class IndicatorData : public IndicatorBase { /** * Provides built-in indicators whose can be used as data source. */ - virtual IndicatorData* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } + virtual IndicatorData* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return nullptr; } /** * Checks whether indicator support given value storage type. @@ -1700,7 +1704,7 @@ class IndicatorData : public IndicatorBase { " without explicitly selecting an indicator, ", GetFullName(), " must override OnDataSourceRequest() method and return new instance of data source to be used by default."); DebugBreak(); - return NULL; + return nullptr; } /** @@ -1708,7 +1712,7 @@ class IndicatorData : public IndicatorBase { */ virtual IndicatorData* DataSourceRequestReturnDefault(int _applied_price) { DebugBreak(); - return NULL; + return nullptr; } /** diff --git a/Indicators/Account/Indi_AccountStats.mqh b/Indicators/Account/Indi_AccountStats.mqh index da45fef7d..975064d96 100644 --- a/Indicators/Account/Indi_AccountStats.mqh +++ b/Indicators/Account/Indi_AccountStats.mqh @@ -145,7 +145,6 @@ class Indi_AccountStats : public Indicator { * Returns value storage of given kind. */ IValueStorage *GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { - // Returning Price indicator which provides applied price in the only buffer #0. switch (_type) { case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: return buffer_date_time.Ptr(); @@ -200,8 +199,27 @@ class Indi_AccountStats : public Indicator { return; } - // Adding new account stats entry. - - Print("New candle: ", entry.ToString()); + // New candle means that account stats for current index 0 will be that we + // will now extract and store in the buffers. + + // Extracting current account stats. + datetime stats_date_time = iparams.GetAccount() PTR_DEREF GetDateTime(); + float stats_balance = iparams.GetAccount() PTR_DEREF GetBalance(); + float stats_credit = iparams.GetAccount() PTR_DEREF GetCredit(); + float stats_profit = iparams.GetAccount() PTR_DEREF GetProfit(); + float stats_equity = iparams.GetAccount() PTR_DEREF GetEquity(); + float stats_margin_used = iparams.GetAccount() PTR_DEREF GetMarginUsed(); + float stats_margin_free = iparams.GetAccount() PTR_DEREF GetMarginFree(); + float stats_margin_avail = iparams.GetAccount() PTR_DEREF GetMarginAvail(); + + // Appending account stats into buffers. + buffer_date_time REF_DEREF Append(stats_date_time); + buffer_balance REF_DEREF Append(stats_balance); + buffer_credit REF_DEREF Append(stats_credit); + buffer_profit REF_DEREF Append(stats_profit); + buffer_equity REF_DEREF Append(stats_equity); + buffer_margin_used REF_DEREF Append(stats_margin_used); + buffer_margin_free REF_DEREF Append(stats_margin_free); + buffer_margin_avail REF_DEREF Append(stats_margin_avail); } }; diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq5 b/Indicators/Account/tests/Indi_AccountStats.test.mq5 index c81e0da79..9f72f4356 100644 --- a/Indicators/Account/tests/Indi_AccountStats.test.mq5 +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq5 @@ -48,7 +48,7 @@ int OnInit() { void OnTick() { Platform::Tick(); - if (Platform::IsNewHour()) { + if (Platform::IsNewMinute()) { IndicatorDataEntry _entry = indi_account_mt REF_DEREF GetEntry(); bool _is_ready = indi_account_mt REF_DEREF Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)); bool _is_valid = _entry.IsValid(); diff --git a/Storage/ValueStorage.native.h b/Storage/ValueStorage.native.h index 0c6180881..7fb8219fc 100644 --- a/Storage/ValueStorage.native.h +++ b/Storage/ValueStorage.native.h @@ -83,6 +83,15 @@ class NativeValueStorage : public ValueStorage { Array::ArrayStore(_values, _index, _value, 4096); } + /** + * Inserts new value at the end of the buffer. If buffer works as As-Series, + * then new value will act as the one at index 0. + */ + void Append(C _value) override { + Resize(Size() + 1, 4096); + Store(Size() - 1, _value); + } + /** * Returns number of values available to fetch (size of the values buffer). */ From d6a3f579c325db308c287a907838c38c1bde4475 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 12 Apr 2024 19:06:42 +0200 Subject: [PATCH 098/123] Refs #738. WIP. OpenCL wrapper class and OpenCL integration for Matrix class (not yet complete). --- Matrix.mqh | 101 ++++++++- OpenCL.h | 523 +++++++++++++++++++++++++++++++++++++++++++ tests/OpenCLTest.mq5 | 55 +++++ 3 files changed, 677 insertions(+), 2 deletions(-) create mode 100644 OpenCL.h create mode 100644 tests/OpenCLTest.mq5 diff --git a/Matrix.mqh b/Matrix.mqh index 59f3eef39..a2f38ce7a 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -24,6 +24,8 @@ #ifndef MATRIX_MQH #define MATRIX_MQH +#define MATRIX_USE_OPENCL + #ifdef USE_MQL_MATH_STAT #ifdef __MQL5__ #include @@ -31,6 +33,7 @@ #endif #include "Math.h" +#include "OpenCL.h" #define MATRIX_DIMENSIONS 6 #define MATRIX_VALUES_ARRAY_INCREMENT 500 @@ -719,6 +722,40 @@ class MatrixDimension { } }; +enum ENUM_MATRIX_FLAGS { MATRIX_FLAGS_NONE, MATRIX_FLAGS_USE_OPENCL }; + +/** + * Buffer used for CL operations. + */ +template +struct MatrixOpenCLBuffer : Dynamic { + // Flattened matrix data. + ARRAY(X, data); + + // Current version of the data. + long version; + + // CL buffer. + Ref buffer; + + public: + /** + * Constructor. + */ + MatrixBuffer() { version = 0; } + + /** + * Prepares buffer to be used by CL. Copies flattened data from the given matrix into buffer. + */ + void FillData(const Matrix& src) { + src.GetRawArray(data); + + if (!buffer.IsSet()) { + buffer = OpenCL::Alloc(ArraySize(data), true); + } + } +}; + /** * Matrix class. */ @@ -728,6 +765,11 @@ class Matrix { // First/root dimension. MatrixDimension* ptr_first_dimension; + // Map of data size -> CL buffer to be used e.g., by CL-based MatMul method. + DictStruct> _cl_buffers_in_0; + DictStruct> _cl_buffers_in_1; + DictStruct> _cl_buffers_out; + // Array with declaration of items per matrix's dimension. int dimensions[MATRIX_DIMENSIONS]; @@ -737,10 +779,18 @@ class Matrix { // Number of matrix dimensions. int num_dimensions; + // Flags. + int flags; + /** * Constructor. */ - Matrix(string _data) { FromString(_data); } + Matrix(string _data) { + FromString(_data); +#ifdef MATRIX_USE_OPENCL + InitializeOpenCL(); +#endif + } /** * Constructor. @@ -748,12 +798,20 @@ class Matrix { Matrix(const int num_1d = 0, const int num_2d = 0, const int num_3d = 0, const int num_4d = 0, const int num_5d = 0) { ptr_first_dimension = NULL; SetShape(num_1d, num_2d, num_3d, num_4d, num_5d); +#ifdef MATRIX_USE_OPENCL + InitializeOpenCL(); +#endif } /** * Constructor. */ - Matrix(MatrixDimension* _dimension) : ptr_first_dimension(NULL) { Initialize(_dimension); } + Matrix(MatrixDimension* _dimension) : ptr_first_dimension(NULL) { + Initialize(_dimension); +#ifdef MATRIX_USE_OPENCL + InitializeOpenCL(); +#endif + } /** * Copy constructor. @@ -764,6 +822,9 @@ class Matrix { } Initialize(_right.ptr_first_dimension.Clone()); +#ifdef MATRIX_USE_OPENCL + InitializeOpenCL(); +#endif } /** @@ -773,7 +834,23 @@ class Matrix { private: Matrix(const Matrix* _right) {} +#ifdef MATRIX_USE_OPENCL + + /** + * + */ + void InitializeOpenCL() {} + +#endif + public: + /** + * Returns/allocs and returns buffer of the given size to be used in CL operations as first input parameter. + * + * Buffer will be read only. + */ + MatrixOpenCLBuffer* GetCLBufferInArg0(int size) { if (_) } + /** * Matrix initializer. */ @@ -1247,6 +1324,11 @@ class Matrix { } static void MatMul(Matrix& source, Matrix& target, Matrix& output) { +#ifdef MATRIX_USE_OPENCL + MatMulCL(source, target, output); + return; +#endif + if (source.GetSize() != target.GetRange(1)) { Alert("Inconsistent size of matrices!"); } @@ -1264,6 +1346,21 @@ class Matrix { } } + /** + * Performs matrix multiplication via OpenCL. Note that MATRIX_USE_OPENCL must be defined in order matrix to use this + * method. + */ + static void MatMulCL(Matrix& source, Matrix& target, Matrix& output) { + if (source.GetSize() != target.GetRange(1)) { + Alert("Inconsistent size of matrices!"); + } + + int num_outputs = target.GetRange(0); + int num_inputs = target.GetRange(1); + + output.SetShape(num_outputs); + } + /** * Performs matrix multiplication. */ diff --git a/OpenCL.h b/OpenCL.h new file mode 100644 index 000000000..156c4ff65 --- /dev/null +++ b/OpenCL.h @@ -0,0 +1,523 @@ +#ifndef __MQL__ +#pragma once +#endif + +#include "DictStruct.mqh" + +// Defines. +#define OPENCL_PROGRAM_MAX_ARGS 8 + +// Forward declarations; +class OpenCLProgram; + +/** + * Memory buffer. + */ +class OpenCLBuffer : public Dynamic { + // Handle to memory buffer. + int buffer_handle; + + // Allocated buffer size. + int buffer_size; + + // Whether buffer is global or local to the kernel otherwise. + bool is_global; + + // Buffer version. Should be incremented after each change. + long version; + + public: + /** + * Constructor. + */ + OpenCLBuffer(int _size, bool _is_global, unsigned int _flags = CL_MEM_READ_WRITE); + + /** + * Writes/uploads data into buffer if needed. + */ + void Write(const ARRAY_REF(double, _arr), int _arr_version = -1) { + if (ArraySize(_arr) > buffer_size) { + Alert("Array passed is too large for the allocated buffer. Tries to pass ", ArraySize(_arr), + " elements into buffer of size ", buffer_size, "."); + DebugBreak(); + return; + } + + // Do we need to reupload data into GPU? + if (_arr_version != -1 && _arr_version <= version) { + // Buffer has already up-to-date data. + return; + } + + CLBufferWrite(buffer_handle, _arr); + + version = (_arr_version != -1) ? _arr_version : (version + 1); + } + + /** + * Reads data from buffer. + */ + void Read(ARRAY_REF(double, _arr)) { + if (!ArrayIsDynamic(_arr) && ArraySize(_arr) < buffer_size) { + Alert("Array passed is too small to be the target. Buffer has size ", buffer_size, + " and you tried to read it into buffer of size ", ArraySize(_arr), "."); + DebugBreak(); + return; + } + CLBufferRead(buffer_handle, _arr); + } + + /** + * Whether buffer is global or local to the kernel otherwise. + */ + bool IsGlobal() { return is_global; } + + /** + * Returns data version. + */ + long GetVersion() { return version; } + + /** + * Returns handle to buffer. + */ + int GetHandle() { return buffer_handle; } + + /** + * Destructor. + */ + ~OpenCLBuffer() { + if (buffer_handle != INVALID_HANDLE) { + CLBufferFree(buffer_handle); + } + } +}; + +/** + * Single program (code) + kernel (function name) to be invoked. + */ +class OpenCLProgram : public Dynamic { + // Handle to program. + int program_handle; + + // Handle to kernel. + int kernel_handle; + + // Buffer handles previously passed as arguments. Used to check if buffer needs to be reuploaded. + int arg_handles[OPENCL_PROGRAM_MAX_ARGS]; + + // Version of argument data. Used to check if buffer needs to be reuploaded. + long arg_versions[OPENCL_PROGRAM_MAX_ARGS]; + + public: + /** + * Constructor. + */ + OpenCLProgram() : program_handle(INVALID_HANDLE), kernel_handle(INVALID_HANDLE) { + for (int i = 0; i < OPENCL_PROGRAM_MAX_ARGS; ++i) { + arg_handles[i] = INVALID_HANDLE; + arg_versions[i] = -1; + } + } + + /** + * Destructor. + */ + ~OpenCLProgram() { + if (kernel_handle != INVALID_HANDLE) { + CLKernelFree(kernel_handle); + } + + if (program_handle != INVALID_HANDLE) { + CLProgramFree(program_handle); + } + } + + /** + * Passes argument to the kernel. Will not set kernel argument if not needed. + * + * Note that buffer reuploading is to be done via OpenCLBuffer::Write() in + * which you can pass version of your data, so no reupload will take place if + * your version isn't greater that the one already set in the buffer. + */ + void SetArg(int _index, OpenCLBuffer* _buffer) { + if (_buffer PTR_DEREF GetHandle() == arg_handles[_index] && + _buffer PTR_DEREF GetVersion() >= arg_versions[_index]) { + // Already uploaded recent version. + return; + } + + if (_buffer PTR_DEREF IsGlobal()) { + CLSetKernelArgMem(kernel_handle, _index, _buffer PTR_DEREF GetHandle()); + } else { + CLSetKernelArgMemLocal(kernel_handle, _index, _buffer PTR_DEREF GetHandle()); + } + + // Buffer will occupy argument slot. + arg_handles[_index] = _buffer PTR_DEREF GetHandle(); + + // Storing buffer version in the argument slot. + arg_versions[_index] = _buffer PTR_DEREF GetVersion(); + } + + /** + * Executes a single kernel. + */ + bool Run() { + if (!CLExecute(kernel_handle)) { + Alert("OpenCL error occured when tried to run kernel: ", GetLastError(), "!"); + return false; + } + + return true; + } + + /** + * Executes a single kernel. Allows passing arugments to kernel. + */ + template + bool Run(A a) { + SetArg(0, a); + return Run(); + } + + /** + * Executes a single kernel. Allows passing arugments to kernel. + */ + template + bool Run(A a, B b) { + SetArg(0, a); + SetArg(1, b); + return Run(); + } + + /** + * Executes a single kernel. Allows passing arugments to kernel. + */ + template + bool Run(A a, B b, C c) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + return Run(); + } + + /** + * Executes a single kernel. Allows passing arugments to kernel. + */ + template + bool Run(A a, B b, C c, D d) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + SetArg(3, d); + return Run(); + } + + /** + * Executes a single kernel. Allows passing arugments to kernel. + */ + template + bool Run(A a, B b, C c, D d, E e) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + SetArg(3, d); + SetArg(4, e); + return Run(); + } + + /** + * Executes a single kernel. Allows passing arugments to kernel. + */ + template + bool Run(A a, B b, C c, D d, E e, F f) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + SetArg(3, d); + SetArg(4, e); + SetArg(5, f); + return Run(); + } + + /** + * Executes a single kernel. Allows passing arugments to kernel. + */ + template + bool Run(A a, B b, C c, D d, E e, F f, G g) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + SetArg(3, d); + SetArg(4, e); + SetArg(5, f); + SetArg(6, g); + return Run(); + } + + /** + * Executes a single kernel. Allows passing arugments to kernel. + */ + template + bool Run(A a, B b, C c, D d, E e, F f, G g, H h) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + SetArg(3, d); + SetArg(4, e); + SetArg(5, f); + SetArg(6, g); + SetArg(7, h); + return Run(); + } + + /** + * Executes multiple kernels where work is subdivided among kernels. + */ + bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size) { + if (!CLExecute(kernel_handle)) { + Alert("OpenCL error occured when tried to run kernel: ", GetLastError(), "!"); + return false; + } + + return true; + } + + /** + * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. + */ + template + bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a) { + SetArg(0, a); + return RunMany(_dimension, _work_offset, _work_size); + } + + /** + * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. + */ + template + bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b) { + SetArg(0, a); + SetArg(1, b); + return RunMany(_dimension, _work_offset, _work_size); + } + + /** + * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. + */ + template + bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, + C c) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + return RunMany(_dimension, _work_offset, _work_size); + } + + /** + * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. + */ + template + bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, C c, + D d) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + SetArg(3, d); + return RunMany(_dimension, _work_offset, _work_size); + } + + /** + * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. + */ + template + bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, C c, + D d, E e) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + SetArg(3, d); + SetArg(4, e); + return RunMany(_dimension, _work_offset, _work_size); + } + + /** + * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. + */ + template + bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, C c, + D d, E e, F f) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + SetArg(3, d); + SetArg(4, e); + SetArg(5, f); + return RunMany(_dimension, _work_offset, _work_size); + } + + /** + * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. + */ + template + bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, C c, + D d, E e, F f, G g) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + SetArg(3, d); + SetArg(4, e); + SetArg(5, f); + SetArg(6, g); + return RunMany(_dimension, _work_offset, _work_size); + } + + /** + * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. + */ + template + bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, C c, + D d, E e, F f, G g, H h) { + SetArg(0, a); + SetArg(1, b); + SetArg(2, c); + SetArg(3, d); + SetArg(4, e); + SetArg(5, f); + SetArg(6, g); + SetArg(7, h); + return RunMany(_dimension, _work_offset, _work_size); + } + + /** + * Returns handle to OpenCL program. + */ + int GetProgramHandle() { return program_handle; } + + /** + * Sets handle to OpenCL program. + */ + void SetProgramHandle(int _handle) { + if (program_handle != -1) { + Alert("Cannot change program handle!"); + DebugBreak(); + return; + } + program_handle = _handle; + } + + /** + * Returns handle to OpenCL kernel. + */ + int GetKernelHandle() { return kernel_handle; } + + /** + * Sets handle to OpenCL kernel. + */ + void SetKernelHandle(int _handle) { + if (kernel_handle != -1) { + Alert("Cannot change kernel handle!"); + DebugBreak(); + return; + } + kernel_handle = _handle; + } +}; + +/** + * Wrapper for OpenCL. + */ +class OpenCL { + // OpenCL handles. + static int context_handle; + + // OpenCL global memory handles. + static int cl_mem_0, cl_mem_1, cl_mem_2; + + DictStruct> programs; + + public: + /** + * Initializes CL contexts. Called automatically by OpenCLLifetimeManager. + */ + static void Initialize() { + context_handle = CLContextCreate(); + if (context_handle == INVALID_HANDLE) { + Alert("Could not create OpenCL context. Error code: ", GetLastError(), "."); + DebugBreak(); + return; + } + } + + /** + * Frees CL contexts. Called automatically by OpenCLLifetimeManager. + */ + static void Deinitialize() { CLContextFree(context_handle); } + + /** + * Allocates memory to be later passed to OpenCLProgram. + */ + static OpenCLBuffer* Alloc(int _size, bool _is_global = true) { return new OpenCLBuffer(_size, _is_global); } + + /** + * Compiles given program and returns its id or -1 in case of error. + */ + static OpenCLProgram* Compile(string _source, string _fn_name) { + OpenCLProgram* _program = new OpenCLProgram(); + + // Log of CLProgramCreate(). + string _compilation_log; + + _program PTR_DEREF SetProgramHandle(CLProgramCreate(context_handle, _source, _compilation_log)); + + if (_program PTR_DEREF GetProgramHandle() == INVALID_HANDLE) { + Alert("Could not create OpenCL program. Error code: ", GetLastError(), ". Compilation log: ", _compilation_log, + "."); + DebugBreak(); + return nullptr; + } + + _program PTR_DEREF SetKernelHandle(CLKernelCreate(_program PTR_DEREF GetProgramHandle(), _fn_name)); + + if (_program PTR_DEREF GetKernelHandle() == INVALID_HANDLE) { + Alert("Could not create OpenCL kernel. Error code: ", GetLastError(), "."); + DebugBreak(); + return nullptr; + } + + return _program; + } + + /** + * Returns handle to OpenCL context. + */ + static int GetContextHandle() { return context_handle; } +}; + +static int OpenCL::context_handle; + +/** + * Manages initialization and deinitialization of static variables for OpenCL class. + */ +class OpenCLLifetimeManager { + public: + OpenCLLifetimeManager() { OpenCL::Initialize(); } + + ~OpenCLLifetimeManager() { OpenCL::Deinitialize(); } +}; + +OpenCLLifetimeManager __opencl_lifetime_manager; + +/** + * OpenCLBuffer constructor. + */ +OpenCLBuffer::OpenCLBuffer(int _size, bool _is_global, unsigned int _flags) { + buffer_handle = CLBufferCreate(OpenCL::GetContextHandle(), _size * sizeof(double), _flags); + if (buffer_handle == INVALID_HANDLE) { + Alert("Could not create OpenCL buffer. Error code: ", GetLastError(), "."); + DebugBreak(); + } + buffer_size = _size; + is_global = _is_global; + version = 0; +} diff --git a/tests/OpenCLTest.mq5 b/tests/OpenCLTest.mq5 new file mode 100644 index 000000000..8f13e2a30 --- /dev/null +++ b/tests/OpenCLTest.mq5 @@ -0,0 +1,55 @@ +//+------------------------------------------------------------------+ +//| 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 + * Test functionality of Ticker class. + */ + +// Includes. +#include "../Matrix.mqh" +#include "../OpenCL.h" + +/** + * Implements initialization function. + */ +int OnInit() { + Ref program = + OpenCL::Compile("#pragma OPENCL EXTENSION cl_khr_fp64 : enable" NL + "__kernel void test(__global double *data) {" NL " data[0] = 5;" NL "}" NL, + + "test"); + + double result[] = {0}; + + Ref buffer = OpenCL::Alloc(1 /* 1 double */); + + if (!program REF_DEREF Run(buffer.Ptr())) { + Alert("Error running program!"); + } + + buffer REF_DEREF Read(result); + + Print("Output: ", result[0]); + + ExpertRemove(); + return (INIT_SUCCEEDED); +} From 2f2fce7b44abe6001cef897ea0aa09fe5691c663 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 19 Apr 2024 21:01:01 +0200 Subject: [PATCH 099/123] Refs #738. WIP. OpenCL integration for Matrix class needs rework as previous implementation we based on was buggy. --- Array.mqh | 2 +- Indicator.struct.h | 2 +- Matrix.mqh | 274 +++++++++++++++++++++++++++++++++++++++---- OpenCL.h | 101 +++++++++------- tests/OpenCLTest.mq5 | 12 ++ 5 files changed, 328 insertions(+), 63 deletions(-) diff --git a/Array.mqh b/Array.mqh index 65d8c529a..7ee00dbd2 100644 --- a/Array.mqh +++ b/Array.mqh @@ -772,7 +772,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { template void ArrayPush(ARRAY_REF(X, array), X value) { - ArrayResize(ArraySize(array) + 1); + ArrayResize(array, ArraySize(array) + 1); array[ArraySize(array) - 1] = value; } template diff --git a/Indicator.struct.h b/Indicator.struct.h index 1819695f3..78a128274 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -120,7 +120,7 @@ struct IndicatorParams { } void SetMaxParams(int _value) { max_params = _value; - ArrayResize(input_params, max_params); + ArrayResize(input_params, (int)max_params); } void SetName(string _name) { name = _name; }; void SetShift(int _shift) { shift = _shift; } diff --git a/Matrix.mqh b/Matrix.mqh index a2f38ce7a..00cbea7af 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -160,6 +160,7 @@ struct MatrixDimensionAccessor { if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { \ Print("Error: Trying to use matrix", ptr_matrix.Repr(), \ "'s value operator " #OP " in a dimension which doesn't contain values!"); \ + DebugBreak(); \ return; \ } \ \ @@ -177,6 +178,7 @@ struct MatrixDimensionAccessor { void operator=(X _value) { if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { Print("Error: Trying to set matrix", ptr_matrix.Repr(), "'s value in a dimension which doesn't contain values!"); + DebugBreak(); return; } @@ -189,6 +191,7 @@ struct MatrixDimensionAccessor { X Val() { if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { Print("Error: Trying to get value from matrix", ptr_matrix.Repr(), "'s dimension which doesn't contain values!"); + DebugBreak(); return (X)EMPTY_VALUE; } @@ -202,6 +205,7 @@ struct MatrixDimensionAccessor { X ValOrZero() { if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { Print("Error: Trying to get value from matrix", ptr_matrix.Repr(), "'s dimension which doesn't contain values!"); + DebugBreak(); return (X)EMPTY_VALUE; } @@ -728,7 +732,7 @@ enum ENUM_MATRIX_FLAGS { MATRIX_FLAGS_NONE, MATRIX_FLAGS_USE_OPENCL }; * Buffer used for CL operations. */ template -struct MatrixOpenCLBuffer : Dynamic { +class MatrixOpenCLBuffer : public Dynamic { // Flattened matrix data. ARRAY(X, data); @@ -742,18 +746,24 @@ struct MatrixOpenCLBuffer : Dynamic { /** * Constructor. */ - MatrixBuffer() { version = 0; } + MatrixOpenCLBuffer(int _size) { + version = 0; + buffer = OpenCL::Alloc(_size); + ArrayResize(data, _size); + } /** * Prepares buffer to be used by CL. Copies flattened data from the given matrix into buffer. */ void FillData(const Matrix& src) { src.GetRawArray(data); - - if (!buffer.IsSet()) { - buffer = OpenCL::Alloc(ArraySize(data), true); - } + buffer REF_DEREF Write(data, version); } + + /** + * Returns pointer to the CL buffer. + */ + OpenCLBuffer* GetBuffer() { return buffer.Ptr(); } }; /** @@ -766,9 +776,9 @@ class Matrix { MatrixDimension* ptr_first_dimension; // Map of data size -> CL buffer to be used e.g., by CL-based MatMul method. - DictStruct> _cl_buffers_in_0; - DictStruct> _cl_buffers_in_1; - DictStruct> _cl_buffers_out; + static DictStruct>> cl_buffers_in_0; + static DictStruct>> cl_buffers_in_1; + static DictStruct>> cl_buffers_out; // Array with declaration of items per matrix's dimension. int dimensions[MATRIX_DIMENSIONS]; @@ -782,6 +792,16 @@ class Matrix { // Flags. int flags; + // Unique id of the matrix. + int uuid; + + // Static counter, so each matrix will have its own uuid. + static int uuid_counter; + + // OpenCL program. + static Ref cl_program_matmul; + static Ref cl_program_matmul_single; + /** * Constructor. */ @@ -790,6 +810,7 @@ class Matrix { #ifdef MATRIX_USE_OPENCL InitializeOpenCL(); #endif + uuid = uuid_counter++; } /** @@ -801,6 +822,7 @@ class Matrix { #ifdef MATRIX_USE_OPENCL InitializeOpenCL(); #endif + uuid = uuid_counter++; } /** @@ -811,6 +833,7 @@ class Matrix { #ifdef MATRIX_USE_OPENCL InitializeOpenCL(); #endif + uuid = uuid_counter++; } /** @@ -825,6 +848,9 @@ class Matrix { #ifdef MATRIX_USE_OPENCL InitializeOpenCL(); #endif + + // We mark new matrix as unique one, even though we clone another matrix. + uuid = uuid_counter++; } /** @@ -839,17 +865,83 @@ class Matrix { /** * */ - void InitializeOpenCL() {} + void InitializeOpenCL() { + if (cl_program_matmul.IsSet()) { + // Already initialized. + return; + } + + cl_program_matmul = OpenCL::Compile( + "#pragma OPENCL EXTENSION cl_khr_fp64 : enable" NL "__kernel void matmul(" NL " const int Mdim," NL + " const int Ndim," NL " const int Pdim," NL " __global double* A," NL " __global double* B," NL + " __global double* C," NL " __local double* Bwrk" NL ")" NL "{" NL " int k, j;" NL + " int i = get_global_id(0);" NL " int iloc = get_local_id(0);" NL + " int nloc = get_local_size(0);" NL " double Awrk[1000];" NL " double tmp;" NL "" NL + " for (k = 0; k < Pdim; k++)" NL " Awrk[k] = A[i * Ndim + k];" NL "" NL + " for (j = 0; j < Mdim; j++)" NL " {" NL " for (k = iloc; k < Pdim; k = k + nloc)" NL + " Bwrk[k] = B[k * Pdim + j];" NL "" NL " barrier(CLK_LOCAL_MEM_FENCE);" NL "" NL + " tmp = 0.0f;" NL "" NL " for (k = 0; k < Pdim; k++)" NL + " tmp += Awrk[k] * Bwrk[k];" NL " C[i * Ndim + j] += tmp;" NL " }" NL "}" NL, + "matmul"); + + cl_program_matmul_single = OpenCL::Compile( + "#pragma OPENCL EXTENSION cl_khr_fp64 : enable" NL "__kernel void matmul(" NL "const int Mdim," NL + "const int Ndim," NL "const int Pdim," NL "__global float *A," NL "__global float *B," NL "__global float *C" NL + ")" NL "{" NL "int i, j, k;" NL "for (i=0; i* GetCLBufferInArg0(int _size) { + Ref> _buffer; + + _buffer = cl_buffers_in_0.GetByKey(_size, _buffer); + + if (!_buffer.IsSet()) { + _buffer = new MatrixOpenCLBuffer(_size); + cl_buffers_in_0.Set(_size, _buffer); + } + + return _buffer.Ptr(); + } + + /** + * Returns/allocs and returns buffer of the given size to be used in CL operations as second input parameter. + */ + static MatrixOpenCLBuffer* GetCLBufferInArg1(int _size) { + Ref> _buffer; + + _buffer = cl_buffers_in_1.GetByKey(_size, _buffer); + + if (!_buffer.IsSet()) { + _buffer = new MatrixOpenCLBuffer(_size); + cl_buffers_in_1.Set(_size, _buffer); + } + + return _buffer.Ptr(); + } + + /** + * Returns/allocs and returns buffer of the given size to be used in CL operations as output parameter. + */ + static MatrixOpenCLBuffer* GetCLBufferOutArg(int _size) { + Ref> _buffer; + + _buffer = cl_buffers_out.GetByKey(_size, _buffer); + + if (!_buffer.IsSet()) { + _buffer = new MatrixOpenCLBuffer(_size); + cl_buffers_out.Set(_size, _buffer); + } + + return _buffer.Ptr(); + } /** * Matrix initializer. @@ -876,6 +968,7 @@ class Matrix { break; } else { Print("Internal error: unknown dimension type!"); + DebugBreak(); } } @@ -986,7 +1079,7 @@ class Matrix { /** * Returns total number of values the matrix contain of. */ - int GetSize() { return size; } + int GetSize() const { return size; } /** * Returns number of matrix dimensions. @@ -1325,7 +1418,8 @@ class Matrix { static void MatMul(Matrix& source, Matrix& target, Matrix& output) { #ifdef MATRIX_USE_OPENCL - MatMulCL(source, target, output); + // MatMulCL(source, target, output); + MatMulCLSingle(source, target, output); return; #endif @@ -1350,15 +1444,116 @@ class Matrix { * Performs matrix multiplication via OpenCL. Note that MATRIX_USE_OPENCL must be defined in order matrix to use this * method. */ - static void MatMulCL(Matrix& source, Matrix& target, Matrix& output) { - if (source.GetSize() != target.GetRange(1)) { + static void MatMulCL(Matrix& _source, Matrix& _target, Matrix& _output) { + if (_source.GetSize() != _target.GetRange(1)) { Alert("Inconsistent size of matrices!"); } - int num_outputs = target.GetRange(0); - int num_inputs = target.GetRange(1); + unsigned int _m_dim = _source.GetRange(0); + unsigned int _n_dim = _source.GetRange(1); + unsigned int _p_dim = _target.GetRange(1); - output.SetShape(num_outputs); + OpenCLBuffer* _in_1 = GetCLBufferInArg0(_source.GetSize()) PTR_DEREF GetBuffer(); + OpenCLBuffer* _in_2 = GetCLBufferInArg1(_target.GetSize()) PTR_DEREF GetBuffer(); + OpenCLBuffer* _out = GetCLBufferOutArg(_source.GetRange(0)) PTR_DEREF GetBuffer(); + + double _in_1_data[]; + double _in_2_data[]; + double _out_data[]; + + _source.GetRawArray(_in_1_data); + _target.GetRawArray(_in_2_data); + + cl_program_matmul REF_DEREF SetArg(0, _m_dim); + cl_program_matmul REF_DEREF SetArg(1, _n_dim); + cl_program_matmul REF_DEREF SetArg(2, _p_dim); + cl_program_matmul REF_DEREF SetArg(3, _in_1); + cl_program_matmul REF_DEREF SetArg(4, _in_2); + cl_program_matmul REF_DEREF SetArg(5, _out); + cl_program_matmul REF_DEREF SetArgLocalMem(6, _p_dim * sizeof(X)); + ARRAY(unsigned int, _global_work_offset); + ARRAY(unsigned int, _global_work_size); + ARRAY(unsigned int, _local_work_size); + ArrayPush(_global_work_offset, 0U); + ArrayPush(_global_work_size, _n_dim); + ArrayPush(_global_work_size, _m_dim); + ArrayPush(_local_work_size, _m_dim); + + if (!cl_program_matmul REF_DEREF RunMany(2, _global_work_offset, _global_work_size, _local_work_size)) { + Alert("Errpr: Could not run Matrix::MatMulCL() over OpenCL!"); + DebugBreak(); + } + + _out PTR_DEREF Read(_out_data); + + // _output.SetShape(num_outputs); + } + + /** + * Performs matrix multiplication via OpenCL. Note that MATRIX_USE_OPENCL must be defined in order matrix to use this + * method. + */ + static void MatMulCLSingle(Matrix& _source, Matrix& _target, Matrix& _output) { + if (_source.GetRange(1) != _target.GetRange(0)) { + Alert("Inconsistent size of matrices!"); + } + + unsigned int _m_dim = _source.GetRange(0); + unsigned int _n_dim = _source.GetRange(1); + unsigned int _p_dim = _target.GetRange(1); + + OpenCLBuffer* _in_1 = GetCLBufferInArg0(_n_dim * _p_dim) PTR_DEREF GetBuffer(); + OpenCLBuffer* _in_2 = GetCLBufferInArg1(_p_dim * _m_dim) PTR_DEREF GetBuffer(); + OpenCLBuffer* _out = GetCLBufferOutArg(_m_dim * _p_dim) PTR_DEREF GetBuffer(); + + double _in_1_data[]; + double _in_2_data[]; + double _out_data[]; + + ArrayResize(_out_data, _out PTR_DEREF GetSizeItems()); + + _source.GetRawArray(_in_1_data); + _target.GetRawArray(_in_2_data); + + MatMulCL_CPU(_m_dim, _n_dim, _p_dim, _in_1_data, _in_2_data, _out_data); + + cl_program_matmul REF_DEREF SetArg(0, _n_dim); + cl_program_matmul REF_DEREF SetArg(1, _m_dim); + cl_program_matmul REF_DEREF SetArg(2, _p_dim); + cl_program_matmul REF_DEREF SetArg(3, _in_1); + cl_program_matmul REF_DEREF SetArg(4, _in_2); + cl_program_matmul REF_DEREF SetArg(5, _out); + + if (!cl_program_matmul_single REF_DEREF Run()) { + Alert("Errpr: Could not run Matrix::MatMulCL() over OpenCL!"); + DebugBreak(); + } + + _out PTR_DEREF Read(_out_data); + + // _output.SetShape(num_outputs); + } + + static void MatMulCL_CPU(int Mdim, int Ndim, int Pdim, double& A[], double& B[], double& C[]) { + /* + for (int i = 0; i < Mdim; ++i) { + for (int j = 0; j < Pdim; ++j) { + C[i * Pdim + j] = 0.0; + for (int k = 0; k < Ndim; ++k) { + C[i * Pdim + j] += A[i * Ndim + k] * B[k * Pdim + j]; + } + } + } + */ + + int i, j, k; + for (i = 0; i < Ndim; i++) { + for (j = 0; j < Mdim; j++) { + for (k = 0; k < Pdim; k++) { // C(i,j) = sum(over k) A(i,k) * B(k,j) + C[i * Pdim + j] += A[i * Ndim + k] * B[k * Pdim + j]; + } + } + } } /** @@ -1370,6 +1565,15 @@ class Matrix { return output; } + /** + * Performs matrix multiplication. + */ + Matrix* MatMul(Matrix* target) { + Matrix* output = new Matrix(); + MatMul(this, target, output); + return output; + } + /** * Performs matrix multiplication. */ @@ -1475,7 +1679,7 @@ class Matrix { /** * Fills array with all values from the matrix. */ - void GetRawArray(X& array[]) { + void GetRawArray(X& array[]) const { ArrayResize(array, GetSize()); int offset = 0; ptr_first_dimension.FillArray(array, offset); @@ -2359,4 +2563,32 @@ class Matrix { } }; +#ifdef __MQL__ +template +static int Matrix::uuid_counter = 0; +template +static Ref Matrix::cl_program_matmul; +template +static Ref Matrix::cl_program_matmul_single; +template +static DictStruct>> Matrix::cl_buffers_in_0; +template +static DictStruct>> Matrix::cl_buffers_in_1; +template +static DictStruct>> Matrix::cl_buffers_out; +#else +template +static int Matrix::uuid_counter = 0; +template +static Ref Matrix::cl_program_matmul; +template +static Ref Matrix::cl_program_matmul_single; +template +static DictStruct>> Matrix::cl_buffers_in_0; +template +static DictStruct>> Matrix::cl_buffers_in_1; +template +static DictStruct>> Matrix::cl_buffers_out; +#endif + #endif diff --git a/OpenCL.h b/OpenCL.h index 156c4ff65..ffeb1314f 100644 --- a/OpenCL.h +++ b/OpenCL.h @@ -20,9 +20,6 @@ class OpenCLBuffer : public Dynamic { // Allocated buffer size. int buffer_size; - // Whether buffer is global or local to the kernel otherwise. - bool is_global; - // Buffer version. Should be incremented after each change. long version; @@ -30,12 +27,12 @@ class OpenCLBuffer : public Dynamic { /** * Constructor. */ - OpenCLBuffer(int _size, bool _is_global, unsigned int _flags = CL_MEM_READ_WRITE); + OpenCLBuffer(int _size, unsigned int _flags = CL_MEM_READ_WRITE); /** * Writes/uploads data into buffer if needed. */ - void Write(const ARRAY_REF(double, _arr), int _arr_version = -1) { + void Write(const ARRAY_REF(double, _arr), long _arr_version = -1) { if (ArraySize(_arr) > buffer_size) { Alert("Array passed is too large for the allocated buffer. Tries to pass ", ArraySize(_arr), " elements into buffer of size ", buffer_size, "."); @@ -68,9 +65,14 @@ class OpenCLBuffer : public Dynamic { } /** - * Whether buffer is global or local to the kernel otherwise. + * Returns buffer size in bytes. */ - bool IsGlobal() { return is_global; } + int GetSizeBytes() { return buffer_size * sizeof(double); } + + /** + * Returns buffer size in items. + */ + int GetSizeItems() { return buffer_size; } /** * Returns data version. @@ -132,6 +134,20 @@ class OpenCLProgram : public Dynamic { } } + /** + * Passes local memory size argument to the kernel. + */ + void SetArgLocalMem(int _index, unsigned long _mem_size) { CLSetKernelArgMemLocal(kernel_handle, _index, _mem_size); } + + /** + * Passes argument to the kernel. Will not set kernel argument if not needed. + * + * Note that buffer reuploading is to be done via OpenCLBuffer::Write() in + * which you can pass version of your data, so no reupload will take place if + * your version isn't greater that the one already set in the buffer. + */ + void SetArg(int _index, double value) { CLSetKernelArg(kernel_handle, _index, value); } + /** * Passes argument to the kernel. Will not set kernel argument if not needed. * @@ -146,11 +162,7 @@ class OpenCLProgram : public Dynamic { return; } - if (_buffer PTR_DEREF IsGlobal()) { - CLSetKernelArgMem(kernel_handle, _index, _buffer PTR_DEREF GetHandle()); - } else { - CLSetKernelArgMemLocal(kernel_handle, _index, _buffer PTR_DEREF GetHandle()); - } + CLSetKernelArgMem(kernel_handle, _index, _buffer PTR_DEREF GetHandle()); // Buffer will occupy argument slot. arg_handles[_index] = _buffer PTR_DEREF GetHandle(); @@ -274,8 +286,9 @@ class OpenCLProgram : public Dynamic { /** * Executes multiple kernels where work is subdivided among kernels. */ - bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size) { - if (!CLExecute(kernel_handle)) { + bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), + const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size)) { + if (!CLExecute(kernel_handle, _dimension, _global_work_offset, _global_work_size, _local_work_size)) { Alert("OpenCL error occured when tried to run kernel: ", GetLastError(), "!"); return false; } @@ -287,81 +300,89 @@ class OpenCLProgram : public Dynamic { * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. */ template - bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a) { + bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), + const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a) { SetArg(0, a); - return RunMany(_dimension, _work_offset, _work_size); + return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); } /** * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. */ template - bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b) { + bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), + const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, + B b) { SetArg(0, a); SetArg(1, b); - return RunMany(_dimension, _work_offset, _work_size); + return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); } /** * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. */ template - bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, - C c) { + bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), + const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, + B b, C c) { SetArg(0, a); SetArg(1, b); SetArg(2, c); - return RunMany(_dimension, _work_offset, _work_size); + return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); } /** * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. */ template - bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, C c, - D d) { + bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), + const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, + B b, C c, D d) { SetArg(0, a); SetArg(1, b); SetArg(2, c); SetArg(3, d); - return RunMany(_dimension, _work_offset, _work_size); + return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); } /** * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. */ template - bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, C c, - D d, E e) { + bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), + const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, + B b, C c, D d, E e) { SetArg(0, a); SetArg(1, b); SetArg(2, c); SetArg(3, d); SetArg(4, e); - return RunMany(_dimension, _work_offset, _work_size); + return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); } /** * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. */ template - bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, C c, - D d, E e, F f) { + bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), + const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, + B b, C c, D d, E e, F f) { SetArg(0, a); SetArg(1, b); SetArg(2, c); SetArg(3, d); SetArg(4, e); SetArg(5, f); - return RunMany(_dimension, _work_offset, _work_size); + return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); } /** * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. */ template - bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, C c, - D d, E e, F f, G g) { + bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), + const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, + B b, C c, D d, E e, F f, G g) { SetArg(0, a); SetArg(1, b); SetArg(2, c); @@ -369,15 +390,16 @@ class OpenCLProgram : public Dynamic { SetArg(4, e); SetArg(5, f); SetArg(6, g); - return RunMany(_dimension, _work_offset, _work_size); + return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); } /** * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. */ template - bool RunMany(unsigned int _dimension, const unsigned int& _work_offset, const unsigned int& _work_size, A a, B b, C c, - D d, E e, F f, G g, H h) { + bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), + const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, + B b, C c, D d, E e, F f, G g, H h) { SetArg(0, a); SetArg(1, b); SetArg(2, c); @@ -386,7 +408,7 @@ class OpenCLProgram : public Dynamic { SetArg(5, f); SetArg(6, g); SetArg(7, h); - return RunMany(_dimension, _work_offset, _work_size); + return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); } /** @@ -431,7 +453,7 @@ class OpenCL { // OpenCL handles. static int context_handle; - // OpenCL global memory handles. + // OpenCL memory handles. static int cl_mem_0, cl_mem_1, cl_mem_2; DictStruct> programs; @@ -457,7 +479,7 @@ class OpenCL { /** * Allocates memory to be later passed to OpenCLProgram. */ - static OpenCLBuffer* Alloc(int _size, bool _is_global = true) { return new OpenCLBuffer(_size, _is_global); } + static OpenCLBuffer* Alloc(int _size) { return new OpenCLBuffer(_size); } /** * Compiles given program and returns its id or -1 in case of error. @@ -511,13 +533,12 @@ OpenCLLifetimeManager __opencl_lifetime_manager; /** * OpenCLBuffer constructor. */ -OpenCLBuffer::OpenCLBuffer(int _size, bool _is_global, unsigned int _flags) { +OpenCLBuffer::OpenCLBuffer(int _size, unsigned int _flags) { buffer_handle = CLBufferCreate(OpenCL::GetContextHandle(), _size * sizeof(double), _flags); if (buffer_handle == INVALID_HANDLE) { Alert("Could not create OpenCL buffer. Error code: ", GetLastError(), "."); DebugBreak(); } buffer_size = _size; - is_global = _is_global; version = 0; } diff --git a/tests/OpenCLTest.mq5 b/tests/OpenCLTest.mq5 index 8f13e2a30..800eb08ed 100644 --- a/tests/OpenCLTest.mq5 +++ b/tests/OpenCLTest.mq5 @@ -50,6 +50,18 @@ int OnInit() { Print("Output: ", result[0]); + Matrix *in1, *in2, *out; + in1 = Matrix::CreateFromString("[[1,2,3], [4,5,6]]"); // 2 x 3 + Print("in1 shape: ", in1 PTR_DEREF GetRange(0), " x ", in1 PTR_DEREF GetRange(1)); + in2 = Matrix::CreateFromString("[[7,8,9,10], [11,12,13,14], [15,16,17,18]]"); // 3 x 4 + Print("in2 shape: ", in2 PTR_DEREF GetRange(0), " x ", in2 PTR_DEREF GetRange(1)); + out = in1 PTR_DEREF MatMul(in2); + Print("out shape: ", out PTR_DEREF GetRange(0), " x ", out PTR_DEREF GetRange(1)); + + delete in1; + delete in2; + delete out; + ExpertRemove(); return (INIT_SUCCEEDED); } From b612dac1c4b9c57c3a57132ad035b1938d8e103b Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 24 Apr 2024 19:20:02 +0200 Subject: [PATCH 100/123] Refs #738. WIP. Partially working Matrix multiplication via OpenCL. Now we need some improvements and Matrix::Deflatten(). --- Matrix.matmul.cl | 115 +++++++++++++++++++++++++++++++++++++++++ Matrix.matmul.naive.cl | 23 +++++++++ Matrix.matmul.test.cl | 19 +++++++ Matrix.mqh | 97 +++++++++++++++++----------------- OpenCL.h | 4 +- tests/OpenCLTest.mq5 | 2 +- 6 files changed, 210 insertions(+), 50 deletions(-) create mode 100644 Matrix.matmul.cl create mode 100644 Matrix.matmul.naive.cl create mode 100644 Matrix.matmul.test.cl diff --git a/Matrix.matmul.cl b/Matrix.matmul.cl new file mode 100644 index 000000000..df718efcc --- /dev/null +++ b/Matrix.matmul.cl @@ -0,0 +1,115 @@ +#define WIDTH 1 +#define TSM 128 // The tile-size in dimension M +#define TSN 128 // The tile-size in dimension N +#define TSK 16 // The tile-size in dimension K +#define WPTM 8 // The work-per-thread in dimension M +#define WPTN 8 // The work-per-thread in dimension N +#define RTSM (TSM/WPTM) // The reduced tile-size in dimension M +#define RTSN (TSN/WPTN) // The reduced tile-size in dimension N +#define LPTA ((TSK*TSM)/(RTSM*RTSN)) // Loads-per-thread for A +#define LPTB ((TSK*TSN)/(RTSM*RTSN)) // Loads-per-thread for B +__kernel void matmul(const int M, const int N, const int K, + const __global double* A, + const __global double* B, + __global float* C) { + + // Thread identifiers + const int tidm = get_local_id(0); // Local row ID (max: TSM/WPTM) + const int tidn = get_local_id(1); // Local col ID (max: TSN/WPTN) + const int offsetM = TSM*get_group_id(0); // Work-group offset + const int offsetN = TSN*get_group_id(1); // Work-group offset + + // Local memory to fit a tile of A and B + __local float Asub[TSK][TSM]; + __local float Bsub[TSK][TSN]; + + // Allocate register space + float Areg; + float Breg[WPTN]; + float acc[WPTM][WPTN]; + + // Initialise the accumulation registers + for (int wm=0; wm(_size); + _buffer = new MatrixOpenCLBuffer(_size, CL_MEM_READ_ONLY); cl_buffers_in_0.Set(_size, _buffer); } @@ -920,7 +913,7 @@ class Matrix { _buffer = cl_buffers_in_1.GetByKey(_size, _buffer); if (!_buffer.IsSet()) { - _buffer = new MatrixOpenCLBuffer(_size); + _buffer = new MatrixOpenCLBuffer(_size, CL_MEM_READ_ONLY); cl_buffers_in_1.Set(_size, _buffer); } @@ -936,7 +929,7 @@ class Matrix { _buffer = cl_buffers_out.GetByKey(_size, _buffer); if (!_buffer.IsSet()) { - _buffer = new MatrixOpenCLBuffer(_size); + _buffer = new MatrixOpenCLBuffer(_size, CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR); cl_buffers_out.Set(_size, _buffer); } @@ -1419,7 +1412,7 @@ class Matrix { static void MatMul(Matrix& source, Matrix& target, Matrix& output) { #ifdef MATRIX_USE_OPENCL // MatMulCL(source, target, output); - MatMulCLSingle(source, target, output); + MatMulCL(source, target, output); return; #endif @@ -1445,48 +1438,56 @@ class Matrix { * method. */ static void MatMulCL(Matrix& _source, Matrix& _target, Matrix& _output) { - if (_source.GetSize() != _target.GetRange(1)) { + if (_source.GetRange(1) != _target.GetRange(0)) { Alert("Inconsistent size of matrices!"); } - unsigned int _m_dim = _source.GetRange(0); - unsigned int _n_dim = _source.GetRange(1); - unsigned int _p_dim = _target.GetRange(1); + unsigned int _rows_a = _source.GetRange(0); + unsigned int _cols_a = _source.GetRange(1); + unsigned int _cols_b = _target.GetRange(1); - OpenCLBuffer* _in_1 = GetCLBufferInArg0(_source.GetSize()) PTR_DEREF GetBuffer(); - OpenCLBuffer* _in_2 = GetCLBufferInArg1(_target.GetSize()) PTR_DEREF GetBuffer(); - OpenCLBuffer* _out = GetCLBufferOutArg(_source.GetRange(0)) PTR_DEREF GetBuffer(); + OpenCLBuffer* _in_1 = GetCLBufferInArg0(_rows_a * _cols_a) PTR_DEREF GetBuffer(); + OpenCLBuffer* _in_2 = GetCLBufferInArg1(_cols_a * _cols_b) PTR_DEREF GetBuffer(); + OpenCLBuffer* _out = GetCLBufferOutArg(_rows_a * _cols_b) PTR_DEREF GetBuffer(); double _in_1_data[]; double _in_2_data[]; double _out_data[]; + // ArrayResize(_out_data, _out PTR_DEREF GetSizeItems()); + _source.GetRawArray(_in_1_data); _target.GetRawArray(_in_2_data); - cl_program_matmul REF_DEREF SetArg(0, _m_dim); - cl_program_matmul REF_DEREF SetArg(1, _n_dim); - cl_program_matmul REF_DEREF SetArg(2, _p_dim); - cl_program_matmul REF_DEREF SetArg(3, _in_1); - cl_program_matmul REF_DEREF SetArg(4, _in_2); - cl_program_matmul REF_DEREF SetArg(5, _out); - cl_program_matmul REF_DEREF SetArgLocalMem(6, _p_dim * sizeof(X)); + _in_1 PTR_DEREF Write(_in_1_data); + _in_2 PTR_DEREF Write(_in_2_data); + + cl_program_matmul REF_DEREF SetArg(0, _in_1); + cl_program_matmul REF_DEREF SetArg(1, _in_2); + cl_program_matmul REF_DEREF SetArg(2, _out); + cl_program_matmul REF_DEREF SetArg(3, (int)_rows_a); + cl_program_matmul REF_DEREF SetArg(4, (int)_cols_a); + cl_program_matmul REF_DEREF SetArg(5, (int)_cols_b); + ARRAY(unsigned int, _global_work_offset); ARRAY(unsigned int, _global_work_size); ARRAY(unsigned int, _local_work_size); + ArrayPush(_global_work_offset, 0U); - ArrayPush(_global_work_size, _n_dim); - ArrayPush(_global_work_size, _m_dim); - ArrayPush(_local_work_size, _m_dim); + ArrayPush(_global_work_offset, 0U); + ArrayPush(_global_work_size, (unsigned int)_rows_a); + ArrayPush(_global_work_size, (unsigned int)_cols_b); + ArrayPush(_local_work_size, 1U); + ArrayPush(_local_work_size, 1U); if (!cl_program_matmul REF_DEREF RunMany(2, _global_work_offset, _global_work_size, _local_work_size)) { - Alert("Errpr: Could not run Matrix::MatMulCL() over OpenCL!"); + Alert("Error: Could not run Matrix::MatMulCL() over OpenCL!"); DebugBreak(); } _out PTR_DEREF Read(_out_data); - // _output.SetShape(num_outputs); + _output.SetShape(_rows_a, _cols_b); } /** @@ -1498,13 +1499,13 @@ class Matrix { Alert("Inconsistent size of matrices!"); } - unsigned int _m_dim = _source.GetRange(0); - unsigned int _n_dim = _source.GetRange(1); - unsigned int _p_dim = _target.GetRange(1); + unsigned int _cols_a = _source.GetRange(0); + unsigned int _rows_a = _source.GetRange(1); + unsigned int _cols_b = _target.GetRange(1); - OpenCLBuffer* _in_1 = GetCLBufferInArg0(_n_dim * _p_dim) PTR_DEREF GetBuffer(); - OpenCLBuffer* _in_2 = GetCLBufferInArg1(_p_dim * _m_dim) PTR_DEREF GetBuffer(); - OpenCLBuffer* _out = GetCLBufferOutArg(_m_dim * _p_dim) PTR_DEREF GetBuffer(); + OpenCLBuffer* _in_1 = GetCLBufferInArg0(_rows_a * _cols_b) PTR_DEREF GetBuffer(); + OpenCLBuffer* _in_2 = GetCLBufferInArg1(_cols_b * _cols_a) PTR_DEREF GetBuffer(); + OpenCLBuffer* _out = GetCLBufferOutArg(_cols_a * _cols_b) PTR_DEREF GetBuffer(); double _in_1_data[]; double _in_2_data[]; @@ -1515,16 +1516,16 @@ class Matrix { _source.GetRawArray(_in_1_data); _target.GetRawArray(_in_2_data); - MatMulCL_CPU(_m_dim, _n_dim, _p_dim, _in_1_data, _in_2_data, _out_data); + MatMulCL_CPU(_cols_a, _rows_a, _cols_b, _in_1_data, _in_2_data, _out_data); - cl_program_matmul REF_DEREF SetArg(0, _n_dim); - cl_program_matmul REF_DEREF SetArg(1, _m_dim); - cl_program_matmul REF_DEREF SetArg(2, _p_dim); + cl_program_matmul REF_DEREF SetArg(0, (int)_rows_a); + cl_program_matmul REF_DEREF SetArg(1, (int)_cols_a); + cl_program_matmul REF_DEREF SetArg(2, (int)_cols_b); cl_program_matmul REF_DEREF SetArg(3, _in_1); cl_program_matmul REF_DEREF SetArg(4, _in_2); cl_program_matmul REF_DEREF SetArg(5, _out); - if (!cl_program_matmul_single REF_DEREF Run()) { + if (!cl_program_matmul REF_DEREF Run()) { Alert("Errpr: Could not run Matrix::MatMulCL() over OpenCL!"); DebugBreak(); } diff --git a/OpenCL.h b/OpenCL.h index ffeb1314f..b6fe7bc54 100644 --- a/OpenCL.h +++ b/OpenCL.h @@ -61,6 +61,7 @@ class OpenCLBuffer : public Dynamic { DebugBreak(); return; } + ArrayResize(_arr, buffer_size); CLBufferRead(buffer_handle, _arr); } @@ -147,6 +148,7 @@ class OpenCLProgram : public Dynamic { * your version isn't greater that the one already set in the buffer. */ void SetArg(int _index, double value) { CLSetKernelArg(kernel_handle, _index, value); } + void SetArg(int _index, int value) { CLSetKernelArg(kernel_handle, _index, value); } /** * Passes argument to the kernel. Will not set kernel argument if not needed. @@ -479,7 +481,7 @@ class OpenCL { /** * Allocates memory to be later passed to OpenCLProgram. */ - static OpenCLBuffer* Alloc(int _size) { return new OpenCLBuffer(_size); } + static OpenCLBuffer* Alloc(int _size, unsigned int _flags) { return new OpenCLBuffer(_size, _flags); } /** * Compiles given program and returns its id or -1 in case of error. diff --git a/tests/OpenCLTest.mq5 b/tests/OpenCLTest.mq5 index 800eb08ed..c26cf3153 100644 --- a/tests/OpenCLTest.mq5 +++ b/tests/OpenCLTest.mq5 @@ -40,7 +40,7 @@ int OnInit() { double result[] = {0}; - Ref buffer = OpenCL::Alloc(1 /* 1 double */); + Ref buffer = OpenCL::Alloc(1 /* 1 double */, CL_MEM_READ_WRITE); if (!program REF_DEREF Run(buffer.Ptr())) { Alert("Error running program!"); From 00001304f0216660b8d793c0ab06c5bb7126bfdb Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 22 Mar 2024 20:21:07 +0100 Subject: [PATCH 101/123] Refs EA31337/EA31337-indicators-stats#2. Closed to finish Indi_AccountStats indicator. --- Account/Account.h | 1 + Account/AccountBase.h | 40 ++++ Account/AccountMt.h | 15 +- Indicator.enum.h | 25 ++- Indicator/IndicatorCandle.h | 28 ++- Indicator/IndicatorTick.h | 2 +- Indicator/tests/classes/IndicatorTfDummy.h | 12 +- Indicator/tests/classes/IndicatorTickDummy.h | 16 +- IndicatorData.mqh | 10 +- Indicators/Account/Indi_AccountStats.mqh | 207 ++++++++++++++++++ .../Account/tests/Indi_AccountStats.test.mq4 | 27 +++ .../Account/tests/Indi_AccountStats.test.mq5 | 61 ++++++ Indicators/Indi_AMA.mqh | 8 - Indicators/Tick/Indi_TickMt.mqh | 6 +- Storage/IValueStorage.h | 5 + Storage/ValueStorage.h | 9 + Storage/ValueStorage.native.h | 19 +- 17 files changed, 444 insertions(+), 47 deletions(-) create mode 100644 Indicators/Account/Indi_AccountStats.mqh create mode 100644 Indicators/Account/tests/Indi_AccountStats.test.mq4 create mode 100644 Indicators/Account/tests/Indi_AccountStats.test.mq5 diff --git a/Account/Account.h b/Account/Account.h index 5e50510d5..a42e5822c 100644 --- a/Account/Account.h +++ b/Account/Account.h @@ -56,4 +56,5 @@ class Account : public AccountBase { */ ~Account() {} }; + #endif // ACCOUNT_H diff --git a/Account/AccountBase.h b/Account/AccountBase.h index 9d3ae7253..187649570 100644 --- a/Account/AccountBase.h +++ b/Account/AccountBase.h @@ -56,6 +56,46 @@ class AccountBase : public Dynamic { * Class deconstructor. */ ~AccountBase() {} + + /** + * Returns balance value of the current account. + */ + virtual datetime GetDateTime() { return TimeCurrent(); }; + + /** + * Returns balance value of the current account. + */ + virtual float GetBalance() = 0; + + /** + * Returns credit value of the current account. + */ + virtual float GetCredit() = 0; + + /** + * Returns profit value of the current account. + */ + virtual float GetProfit() = 0; + + /** + * Returns equity value of the current account. + */ + virtual float GetEquity() = 0; + + /** + * Returns margin value of the current account. + */ + virtual float GetMarginUsed() = 0; + + /** + * Returns free margin value of the current account. + */ + virtual float GetMarginFree() = 0; + + /** + * Get account available margin. + */ + virtual float GetMarginAvail() = 0; }; #endif // ACCOUNTBASE_H diff --git a/Account/AccountMt.h b/Account/AccountMt.h index c03c300f9..66f053591 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -42,12 +42,13 @@ class AccountMt; #include "Account.define.h" #include "Account.enum.h" #include "Account.extern.h" +#include "Account.h" #include "Account.struct.h" /** * Class to provide functions that return parameters of the current account. */ -class AccountMt { +class AccountMt : public AccountBase { protected: // Struct variables. BufferStruct entries; @@ -136,7 +137,7 @@ class AccountMt { * Returns balance value of the current account. */ static double AccountBalance() { return AccountInfoDouble(ACCOUNT_BALANCE); } - float GetBalance() { + float GetBalance() override { // @todo: Adds caching. // return UpdateStats(ACC_BALANCE, AccountBalance()); return (float)AccountMt::AccountBalance(); @@ -146,7 +147,7 @@ class AccountMt { * Returns credit value of the current account. */ static double AccountCredit() { return AccountInfoDouble(ACCOUNT_CREDIT); } - float GetCredit() { + float GetCredit() override { // @todo: Adds caching. // return UpdateStats(ACC_CREDIT, AccountCredit()); return (float)AccountMt::AccountCredit(); @@ -156,7 +157,7 @@ class AccountMt { * Returns profit value of the current account. */ static double AccountProfit() { return AccountInfoDouble(ACCOUNT_PROFIT); } - float GetProfit() { + float GetProfit() override { // @todo: Adds caching. // return UpdateStats(ACC_PROFIT, AccountProfit()); return (float)AccountMt::AccountProfit(); @@ -166,7 +167,7 @@ class AccountMt { * Returns equity value of the current account. */ static double AccountEquity() { return AccountInfoDouble(ACCOUNT_EQUITY); } - float GetEquity() { + float GetEquity() override { // @todo: Adds caching. // return UpdateStats(ACC_EQUITY, AccountEquity()); return (float)AccountMt::AccountEquity(); @@ -198,7 +199,7 @@ class AccountMt { * Returns free margin value of the current account. */ static double AccountFreeMargin() { return AccountInfoDouble(ACCOUNT_MARGIN_FREE); } - float GetMarginFree() { + float GetMarginFree() override { // @todo: Adds caching. // return UpdateStats(ACC_MARGIN_FREE, AccountFreeMargin()); return (float)AccountMt::AccountFreeMargin(); @@ -267,7 +268,7 @@ class AccountMt { * Get account available margin. */ static double AccountAvailMargin() { return fmin(AccountFreeMargin(), AccountTotalBalance()); } - float GetMarginAvail() { return (float)AccountAvailMargin(); } + float GetMarginAvail() override { return (float)AccountAvailMargin(); } /** * Returns the calculation mode of free margin allowed to open orders on the current account. diff --git a/Indicator.enum.h b/Indicator.enum.h index b2b07a3a4..c20b4e8b6 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -44,6 +44,7 @@ enum ENUM_INDICATOR_ACTION { enum ENUM_INDICATOR_TYPE { INDI_NONE = 0, // (None) INDI_AC, // Accelerator Oscillator + INDI_ACCOUNT_STATS, // Account Stats INDI_AD, // Accumulation/Distribution INDI_ADX, // Average Directional Index INDI_ADXW, // ADX by Welles Wilder @@ -237,9 +238,24 @@ enum ENUM_INDI_VS_TYPE { 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 + INDI_VS_TYPE_INDEX_LAST = INDI_VS_TYPE_INDEX_9, + + // Account Stats. + INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME, + INDI_VS_TYPE_ACCOUNT_STATS_BALANCE, + INDI_VS_TYPE_ACCOUNT_STATS_CREDIT, + INDI_VS_TYPE_ACCOUNT_STATS_EQUITY, + INDI_VS_TYPE_ACCOUNT_STATS_PROFIT, + INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED, + INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE, + INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL, + INDI_VS_TYPE_ACCOUNT_STATS_INDEX_FIRST = INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME, + INDI_VS_TYPE_ACCOUNT_STATS_INDEX_LAST = INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL, }; +#define INDI_VS_TYPE_ACCOUNT_STATS_BUFFERS_COUNT \ + (INDI_VS_TYPE_ACCOUNT_STATS_INDEX_LAST - INDI_VS_TYPE_ACCOUNT_STATS_INDEX_FIRST + 1) + // Indicator flags. enum ENUM_INDI_FLAGS { INDI_FLAG_INDEXABLE_BY_SHIFT, // Indicator supports indexation by shift. @@ -269,4 +285,11 @@ enum ENUM_INDI_DS_MODE_KIND { 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. }; + +// Type of entry +enum ENUM_INDI_EMITTED_ENTRY_TYPE { + INDI_EMITTED_ENTRY_TYPE_PARENT, // Undetermined type of entry from direct parent indicator. + INDI_EMITTED_ENTRY_TYPE_TICK, + INDI_EMITTED_ENTRY_TYPE_CANDLE, +}; //+------------------------------------------------------------------+ diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 8221afe82..da34844ca 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -32,6 +32,7 @@ // Includes. #include "../Buffer/BufferCandle.h" #include "../Candle.struct.h" +#include "../Indicator.enum.h" #include "../Indicator.mqh" #include "../Storage/ValueStorage.price_median.h" #include "../Storage/ValueStorage.price_typical.h" @@ -310,7 +311,7 @@ class IndicatorCandle : public Indicator { void EmitHistory() override { for (DictStructIterator> iter(icdata.Begin()); iter.IsValid(); ++iter) { IndicatorDataEntry _entry = CandleToEntry(iter.Key(), iter.Value()); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_CANDLE); } } @@ -342,7 +343,7 @@ class IndicatorCandle : public Indicator { /** * Adds tick's price to the matching candle and updates its OHLC values. */ - void UpdateCandle(long _tick_timestamp, double _price) { + CandleOCTOHLC UpdateCandle(long _tick_timestamp, double _price) { long _candle_timestamp = CalcCandleTimestamp(_tick_timestamp); #ifdef __debug_verbose__ @@ -368,6 +369,8 @@ class IndicatorCandle : public Indicator { } icdata.Add(_candle, _candle_timestamp); + + return _candle; } /** @@ -380,12 +383,25 @@ class IndicatorCandle : public Indicator { /** * Called when data source emits new entry (historic or future one). */ - void OnDataSourceEntry(IndicatorDataEntry& entry) override { - // Updating candle from bid price. - UpdateCandle(entry.timestamp, entry[1]); + void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + Indicator::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } + + long _candle_timestamp = CalcCandleTimestamp(entry.timestamp); // Updating tick & bar indices. - counter.OnTick(CalcCandleTimestamp(entry.timestamp)); + counter.OnTick(_candle_timestamp); + + // Updating candle from bid price. + CandleOCTOHLC _candle = UpdateCandle(entry.timestamp, entry[1]); + + // Emitting candle for children. + IndicatorDataEntry _candle_entry = CandleToEntry(_candle_timestamp, _candle); + EmitEntry(_candle_entry, INDI_EMITTED_ENTRY_TYPE_CANDLE); }; /** diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 5438923cb..cf01dfe83 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -164,7 +164,7 @@ class IndicatorTick : public Indicator { void EmitHistory() override { for (DictStructIterator> iter(itdata.Begin()); iter.IsValid(); ++iter) { IndicatorDataEntry _entry = TickToEntry(iter.Key(), iter.Value()); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); } } diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 019b800d8..f49a8161d 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -48,11 +48,13 @@ class IndicatorTfDummy : public IndicatorTf { string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } - void OnDataSourceEntry(IndicatorDataEntry& entry) override { - // When overriding OnDataSourceEntry() we have to remember to call parent - // method, because IndicatorCandle also need to invoke it in order to - // create/update matching candle. - IndicatorTf::OnDataSourceEntry(entry); + void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + IndicatorTf::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } #ifdef __debug_indicator__ Print(GetFullName(), " got new tick at ", entry.timestamp, diff --git a/Indicator/tests/classes/IndicatorTickDummy.h b/Indicator/tests/classes/IndicatorTickDummy.h index dfd59e9a3..3e6bab0ab 100644 --- a/Indicator/tests/classes/IndicatorTickDummy.h +++ b/Indicator/tests/classes/IndicatorTickDummy.h @@ -59,13 +59,13 @@ class IndicatorTickDummy : public IndicatorTick _t7(4.2f, 4.21f); TickAB _t8(4.8f, 4.81f); - EmitEntry(TickToEntry(1000, _t1)); - EmitEntry(TickToEntry(1500, _t2)); - EmitEntry(TickToEntry(2000, _t3)); - EmitEntry(TickToEntry(3000, _t4)); - EmitEntry(TickToEntry(4000, _t5)); - EmitEntry(TickToEntry(4100, _t6)); - EmitEntry(TickToEntry(4200, _t7)); - EmitEntry(TickToEntry(4800, _t8)); + EmitEntry(TickToEntry(1000, _t1), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(1500, _t2), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(2000, _t3), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(3000, _t4), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4000, _t5), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4100, _t6), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4200, _t7), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4800, _t8), INDI_EMITTED_ENTRY_TYPE_TICK); }; }; diff --git a/IndicatorData.mqh b/IndicatorData.mqh index 46225b8d3..bc0c498b1 100644 --- a/IndicatorData.mqh +++ b/IndicatorData.mqh @@ -1616,10 +1616,10 @@ class IndicatorData : public IndicatorBase { /** * Sends entry to listening indicators. */ - void EmitEntry(IndicatorDataEntry& entry) { + void EmitEntry(IndicatorDataEntry& entry, ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) { for (int i = 0; i < ArraySize(listeners); ++i) { if (listeners[i].ObjectExists()) { - listeners[i].Ptr().OnDataSourceEntry(entry); + listeners[i].Ptr().OnDataSourceEntry(entry, type); } } } @@ -1683,7 +1683,11 @@ class IndicatorData : public IndicatorBase { /** * Called when data source emits new entry (historic or future one). */ - virtual void OnDataSourceEntry(IndicatorDataEntry& entry){}; + virtual void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) { + // Sending entry to all chilren listeners (from highest parent to lowest child). + EmitEntry(entry, type); + }; virtual void OnTick() {} diff --git a/Indicators/Account/Indi_AccountStats.mqh b/Indicators/Account/Indi_AccountStats.mqh new file mode 100644 index 000000000..da45fef7d --- /dev/null +++ b/Indicators/Account/Indi_AccountStats.mqh @@ -0,0 +1,207 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Includes. +#include "../../Account/AccountBase.h" +#include "../../BufferStruct.mqh" +#include "../../Indicator.mqh" +#include "../../Platform.h" +#include "../../Storage/Objects.h" + +// Structs. +struct Indi_AccountStats_Params : IndicatorParams { + // Applied price. + ENUM_APPLIED_PRICE ap; + + // Account to use. + Ref account; + + // Struct constructor. + Indi_AccountStats_Params(AccountBase *_account = nullptr, int _shift = 0) + : IndicatorParams(INDI_ACCOUNT_STATS), account(_account) { + SetShift(_shift); + }; + Indi_AccountStats_Params(Indi_AccountStats_Params &_params) { THIS_REF = _params; }; + + // Getters. + AccountBase *GetAccount() { return account.Ptr(); } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return ap; } + + // Setters. + void SetAccount(AccountBase *_account) { account = _account; } + void SetAppliedPrice(ENUM_APPLIED_PRICE _ap) { ap = _ap; } +}; + +/** + * Price Indicator. + */ +class Indi_AccountStats : public Indicator { + Ref> buffer_date_time; + Ref> buffer_balance; + Ref> buffer_credit; + Ref> buffer_equity; + Ref> buffer_profit; + Ref> buffer_margin_used; + Ref> buffer_margin_free; + Ref> buffer_margin_avail; + + public: + /** + * Class constructor. + */ + Indi_AccountStats(Indi_AccountStats_Params &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : Indicator(_p, + IndicatorDataParams::GetInstance(INDI_VS_TYPE_ACCOUNT_STATS_BUFFERS_COUNT, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + InitAccountStats(); + }; + Indi_AccountStats(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(Indi_AccountStats_Params(), + IndicatorDataParams::GetInstance(INDI_VS_TYPE_ACCOUNT_STATS_BUFFERS_COUNT, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + InitAccountStats(); + }; + void InitAccountStats() { + buffer_date_time = new NativeValueStorage(); + buffer_balance = new NativeValueStorage(); + buffer_credit = new NativeValueStorage(); + buffer_equity = new NativeValueStorage(); + buffer_profit = new NativeValueStorage(); + buffer_margin_used = new NativeValueStorage(); + buffer_margin_free = new NativeValueStorage(); + buffer_margin_avail = new NativeValueStorage(); + } + + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + virtual unsigned int GetSuitableDataSourceTypes() { + // We require that candle indicator is attached. + 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; } + + /** + * Checks whether indicator has a valid value for a given shift. + */ + virtual bool HasValidEntry(int _shift = 0) { return GetBarTime(_shift) != 0; } + + /** + * Returns the indicator's value. + */ + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + + // Converting mode into value storage type. + ENUM_INDI_VS_TYPE _vs_type = (ENUM_INDI_VS_TYPE)(INDI_VS_TYPE_ACCOUNT_STATS_INDEX_FIRST + _mode); + + // Retrieving data from specific value storage. + switch (_vs_type) { + case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: + return ((ValueStorage *)GetSpecificValueStorage(_vs_type))PTR_DEREF FetchSeries(_ishift); + case INDI_VS_TYPE_ACCOUNT_STATS_BALANCE: + case INDI_VS_TYPE_ACCOUNT_STATS_CREDIT: + case INDI_VS_TYPE_ACCOUNT_STATS_EQUITY: + case INDI_VS_TYPE_ACCOUNT_STATS_PROFIT: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL: + return ((ValueStorage *)GetSpecificValueStorage(_vs_type))PTR_DEREF FetchSeries(_ishift); + default: + Alert("Error: Indi_AccountStats: Invalid mode passed to GetEntryValue()!"); + DebugBreak(); + return EMPTY_VALUE; + } + } + + /** + * Returns value storage of given kind. + */ + IValueStorage *GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + // Returning Price indicator which provides applied price in the only buffer #0. + switch (_type) { + case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: + return buffer_date_time.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_BALANCE: + return buffer_balance.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_CREDIT: + return buffer_credit.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_EQUITY: + return buffer_equity.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_PROFIT: + return buffer_profit.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED: + return buffer_margin_used.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE: + return buffer_margin_free.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL: + return buffer_margin_avail.Ptr(); + default: + // Trying in parent class. + return Indicator::GetSpecificValueStorage(_type); + } + } + + /** + * Checks whether indicator support given value storage type. + */ + bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + switch (_type) { + case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: + case INDI_VS_TYPE_ACCOUNT_STATS_BALANCE: + case INDI_VS_TYPE_ACCOUNT_STATS_CREDIT: + case INDI_VS_TYPE_ACCOUNT_STATS_EQUITY: + case INDI_VS_TYPE_ACCOUNT_STATS_PROFIT: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL: + return true; + default: + // Trying in parent class. + return Indicator::HasSpecificValueStorage(_type); + } + } + + /** + * Called when data source emits new entry (historic or future one). + */ + virtual void OnDataSourceEntry(IndicatorDataEntry &entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) { + Indicator::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_CANDLE) { + return; + } + + // Adding new account stats entry. + + Print("New candle: ", entry.ToString()); + } +}; diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq4 b/Indicators/Account/tests/Indi_AccountStats.test.mq4 new file mode 100644 index 000000000..8356c50b5 --- /dev/null +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq4 @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| 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 + * Test functionality of Indi_AC indicator class. + */ + +#include "Indi_AC.test.mq5" diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq5 b/Indicators/Account/tests/Indi_AccountStats.test.mq5 new file mode 100644 index 000000000..c81e0da79 --- /dev/null +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq5 @@ -0,0 +1,61 @@ +//+------------------------------------------------------------------+ +//| 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. +#include "../../../Account/AccountMt.h" +#include "../../../Platform.h" +#include "../../../Test.mqh" +#include "../Indi_AccountStats.mqh" + +/** + * @file + * Test functionality of Indi_AccountStats indicator class. + */ + +Ref indi_account_mt; + +int OnInit() { + Ref account_mt = new AccountMt(); + Indi_AccountStats_Params indi_params(account_mt.Ptr()); + indi_account_mt = new Indi_AccountStats(indi_params); + + Platform::Init(); + + Platform::AddWithDefaultBindings(indi_account_mt.Ptr()); + + bool _result = true; + assertTrueOrFail(indi_account_mt 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_account_mt REF_DEREF GetEntry(); + bool _is_ready = indi_account_mt REF_DEREF Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)); + bool _is_valid = _entry.IsValid(); + Print(indi_account_mt REF_DEREF ToString(), _is_ready ? "" : " (Not yet ready)"); + if (_is_ready && !_is_valid) { + Print(indi_account_mt REF_DEREF ToString(), " (Invalid entry!)"); + assertTrueOrExit(_entry.IsValid(), "Invalid entry!"); + } + } +} \ No newline at end of file diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index ec615c8ac..4fde34ef7 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -256,14 +256,6 @@ class Indi_AMA : public Indicator { return _value; } - /** - * Called when data source emits new entry (historic or future one). - */ - void OnDataSourceEntry(IndicatorDataEntry &entry) override { - // Just to be able to make a breakpoint here. - int x = 4; - }; - /** * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on * some data source. diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 726004fff..b60ee2d04 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -159,7 +159,7 @@ class Indi_TickMt : public IndicatorTick { _tmp_ticks[i].ask, ", ", _tmp_ticks[i].bid); #endif - EmitEntry(TickToEntry(_tmp_ticks[i].time, _tick)); + EmitEntry(TickToEntry(_tmp_ticks[i].time, _tick), INDI_EMITTED_ENTRY_TYPE_TICK); if (_num_yet_to_copy <= 0) { break; @@ -205,7 +205,7 @@ class Indi_TickMt : public IndicatorTick { // DebugBreak(); // Just emitting zeroes in case of error. TickAB _tick(0, 0); - EmitEntry(TickToEntry(TimeCurrent(), _tick)); + EmitEntry(TickToEntry(TimeCurrent(), _tick), INDI_EMITTED_ENTRY_TYPE_TICK); return; } @@ -224,6 +224,6 @@ class Indi_TickMt : public IndicatorTick { TickAB _tick(_ask, _bid); IndicatorDataEntry _entry(TickToEntry(_time, _tick)); StoreEntry(_entry); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); } }; diff --git a/Storage/IValueStorage.h b/Storage/IValueStorage.h index 290c2552d..6f4897bf6 100644 --- a/Storage/IValueStorage.h +++ b/Storage/IValueStorage.h @@ -72,6 +72,11 @@ class IValueStorage : public Dynamic { DebugBreak(); return false; } + + /** + * Returns real array index for this given shift. + **/ + virtual int GetRealIndex(int _shift) { return IsSeries() ? (Size() - 1 - _shift) : _shift; } }; /** diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index 6c7979ba0..865b2d651 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -181,6 +181,15 @@ class ValueStorage : public IValueStorage { DebugBreak(); } + /** + * Inserts new value at the end of the buffer. If buffer works as As-Series, + * then new value will act as the one at index 0. + */ + virtual void Append(C _value) { + Alert(__FUNCSIG__, " does not implement Append()!"); + DebugBreak(); + } + /** * Sets buffer drawing attributes. Currently does nothing. */ diff --git a/Storage/ValueStorage.native.h b/Storage/ValueStorage.native.h index 46ca12565..0c6180881 100644 --- a/Storage/ValueStorage.native.h +++ b/Storage/ValueStorage.native.h @@ -60,19 +60,28 @@ class NativeValueStorage : public ValueStorage { * Fetches value from a given shift. Takes into consideration as-series flag. */ C Fetch(int _shift) override { - if (_shift < 0 || _shift >= ArraySize(_values)) { + if (_shift < 0 || _shift >= Size()) { return (C)EMPTY_VALUE; - // Print("Invalid buffer data index: ", _shift, ". Buffer size: ", ArraySize(_values)); - // DebugBreak(); } - return _values[_shift]; + int _index = GetRealIndex(_shift); + + return _values[_index]; } /** * Stores value at a given shift. Takes into consideration as-series flag. */ - void Store(int _shift, C _value) override { Array::ArrayStore(_values, _shift, _value, 4096); } + void Store(int _shift, C _value) override { + if (_shift < 0 || _shift >= Size()) { + Alert("Error: NativeValueStorage: Invalid buffer data index: ", _shift, ". Buffer size: ", Size()); + DebugBreak(); + } + + int _index = GetRealIndex(_shift); + + Array::ArrayStore(_values, _index, _value, 4096); + } /** * Returns number of values available to fetch (size of the values buffer). From 5330e448f2b4cb7bbc5a540b5c19cbcef32537ff Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 27 Mar 2024 15:13:43 +0100 Subject: [PATCH 102/123] WIP. Refs EA31337/EA31337-indicators-stats#2. Indi_AccountStats closer to be finished. Awaiting to fix MT5 compiler bug. --- IndicatorData.mqh | 48 ++++++++++--------- Indicators/Account/Indi_AccountStats.mqh | 26 ++++++++-- .../Account/tests/Indi_AccountStats.test.mq5 | 2 +- Storage/ValueStorage.native.h | 9 ++++ 4 files changed, 58 insertions(+), 27 deletions(-) diff --git a/IndicatorData.mqh b/IndicatorData.mqh index bc0c498b1..990c2e1f3 100644 --- a/IndicatorData.mqh +++ b/IndicatorData.mqh @@ -68,7 +68,7 @@ class IndicatorData : public IndicatorBase { case IDATA_ICUSTOM: break; case IDATA_INDICATOR: - if (indi_src.IsSet() == NULL) { + if (indi_src.IsSet()) { // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); // SetDataSource(_indi_price, true, PRICE_OPEN); } @@ -109,7 +109,7 @@ class IndicatorData : public IndicatorBase { /** * Class constructor. */ - IndicatorData(const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + IndicatorData(const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = nullptr, int _indi_mode = 0) : do_draw(false), idparams(_idparams), indi_src(_indi_src) { Init(); } @@ -572,9 +572,9 @@ class IndicatorData : public IndicatorBase { * Returns currently selected data source doing validation. */ IndicatorData* GetDataSource(bool _validate = true) { - IndicatorData* _result = NULL; + IndicatorData* _result = nullptr; - if (GetDataSourceRaw() != NULL) { + if (GetDataSourceRaw() != nullptr) { _result = GetDataSourceRaw(); } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) { int _source_id = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)); @@ -603,7 +603,7 @@ class IndicatorData : public IndicatorBase { // Requesting potential data source. _result = OnDataSourceRequest(); - if (_result != NULL) { + if (_result != nullptr) { // Initializing with new data source. SetDataSource(_result); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR); @@ -621,7 +621,7 @@ class IndicatorData : public IndicatorBase { * Returns given data source type. Used by i*OnIndicator methods if indicator's Calculate() uses other indicators. */ IndicatorData* GetDataSource(ENUM_INDICATOR_TYPE _type) { - IndicatorData* _result = NULL; + IndicatorData* _result = nullptr; if (indicators.KeyExists((int)_type)) { _result = indicators[(int)_type].Ptr(); } else { @@ -697,11 +697,15 @@ class IndicatorData : public IndicatorBase { } if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_INDICATOR && - GetDataSourceRaw() == NULL && _try_initialize) { + GetDataSourceRaw() == nullptr && _try_initialize) { SetDataSource(OnDataSourceRequest()); } - return GetDataSourceRaw() != NULL; + IndicatorData* _ptr = GetDataSourceRaw(); + + bool _result = _ptr != nullptr; + + return _result; } /** @@ -802,7 +806,7 @@ class IndicatorData : public IndicatorBase { indi_src.Ptr().RemoveListener(THIS_PTR); } indi_src = _indi; - if (_indi != NULL) { + if (_indi != nullptr) { 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); @@ -862,7 +866,7 @@ class IndicatorData : public IndicatorBase { last_tick_time = _current_time; // Checking and potentially initializing new data source. - if (HasDataSource(true) != NULL) { + if (HasDataSource(true)) { // Ticking data source if not yet ticked. GetDataSource().Tick(); } @@ -905,13 +909,13 @@ class IndicatorData : public IndicatorBase { * Loads and validates built-in indicators whose can be used as data source. */ void ValidateDataSource(IndicatorData* _target, IndicatorData* _source) { - if (_target == NULL) { + if (_target == nullptr) { Alert("Internal Error! _target is NULL in ", __FUNCTION_LINE__, "."); DebugBreak(); return; } - if (_source == NULL) { + if (_source == nullptr) { Alert("Error! You have to select source indicator's via SetDataSource()."); DebugBreak(); return; @@ -1129,7 +1133,7 @@ class IndicatorData : public IndicatorBase { _originator PTR_DEREF GetFullName(), "!"); DebugBreak(); } - return NULL; + return nullptr; } } @@ -1146,7 +1150,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's struct value via index. */ - virtual IndicatorDataEntry GetEntry(long _index = 0) = NULL; + virtual IndicatorDataEntry GetEntry(long _index = 0) = 0; /** * Returns the indicator's struct value via timestamp. @@ -1171,7 +1175,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's entry value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) = NULL; + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) = 0; /** * Returns the shift of the maximum value over a specific number of periods depending on type. @@ -1238,7 +1242,7 @@ class IndicatorData : public IndicatorBase { * * When indicator values are not valid, returns empty signals. */ - virtual IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) = NULL; + virtual IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) = 0; /** * Returns spread for the bar. @@ -1331,7 +1335,7 @@ class IndicatorData : public IndicatorBase { ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " "IndicatorBase::GetSpecificAppliedPriceValueStorage()!"); DebugBreak(); - return NULL; + return nullptr; } } @@ -1374,7 +1378,7 @@ class IndicatorData : public IndicatorBase { "Volume) in the hierarchy!"); DebugBreak(); } - return NULL; + return nullptr; } /** @@ -1390,7 +1394,7 @@ class IndicatorData : public IndicatorBase { virtual IValueStorage* GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { Print("Error: ", GetFullName(), " indicator has no storage type ", EnumToString(_type), "!"); DebugBreak(); - return NULL; + return nullptr; } /** @@ -1632,7 +1636,7 @@ class IndicatorData : public IndicatorBase { /** * Provides built-in indicators whose can be used as data source. */ - virtual IndicatorData* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } + virtual IndicatorData* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return nullptr; } /** * Checks whether indicator support given value storage type. @@ -1700,7 +1704,7 @@ class IndicatorData : public IndicatorBase { " without explicitly selecting an indicator, ", GetFullName(), " must override OnDataSourceRequest() method and return new instance of data source to be used by default."); DebugBreak(); - return NULL; + return nullptr; } /** @@ -1708,7 +1712,7 @@ class IndicatorData : public IndicatorBase { */ virtual IndicatorData* DataSourceRequestReturnDefault(int _applied_price) { DebugBreak(); - return NULL; + return nullptr; } /** diff --git a/Indicators/Account/Indi_AccountStats.mqh b/Indicators/Account/Indi_AccountStats.mqh index da45fef7d..975064d96 100644 --- a/Indicators/Account/Indi_AccountStats.mqh +++ b/Indicators/Account/Indi_AccountStats.mqh @@ -145,7 +145,6 @@ class Indi_AccountStats : public Indicator { * Returns value storage of given kind. */ IValueStorage *GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { - // Returning Price indicator which provides applied price in the only buffer #0. switch (_type) { case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: return buffer_date_time.Ptr(); @@ -200,8 +199,27 @@ class Indi_AccountStats : public Indicator { return; } - // Adding new account stats entry. - - Print("New candle: ", entry.ToString()); + // New candle means that account stats for current index 0 will be that we + // will now extract and store in the buffers. + + // Extracting current account stats. + datetime stats_date_time = iparams.GetAccount() PTR_DEREF GetDateTime(); + float stats_balance = iparams.GetAccount() PTR_DEREF GetBalance(); + float stats_credit = iparams.GetAccount() PTR_DEREF GetCredit(); + float stats_profit = iparams.GetAccount() PTR_DEREF GetProfit(); + float stats_equity = iparams.GetAccount() PTR_DEREF GetEquity(); + float stats_margin_used = iparams.GetAccount() PTR_DEREF GetMarginUsed(); + float stats_margin_free = iparams.GetAccount() PTR_DEREF GetMarginFree(); + float stats_margin_avail = iparams.GetAccount() PTR_DEREF GetMarginAvail(); + + // Appending account stats into buffers. + buffer_date_time REF_DEREF Append(stats_date_time); + buffer_balance REF_DEREF Append(stats_balance); + buffer_credit REF_DEREF Append(stats_credit); + buffer_profit REF_DEREF Append(stats_profit); + buffer_equity REF_DEREF Append(stats_equity); + buffer_margin_used REF_DEREF Append(stats_margin_used); + buffer_margin_free REF_DEREF Append(stats_margin_free); + buffer_margin_avail REF_DEREF Append(stats_margin_avail); } }; diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq5 b/Indicators/Account/tests/Indi_AccountStats.test.mq5 index c81e0da79..9f72f4356 100644 --- a/Indicators/Account/tests/Indi_AccountStats.test.mq5 +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq5 @@ -48,7 +48,7 @@ int OnInit() { void OnTick() { Platform::Tick(); - if (Platform::IsNewHour()) { + if (Platform::IsNewMinute()) { IndicatorDataEntry _entry = indi_account_mt REF_DEREF GetEntry(); bool _is_ready = indi_account_mt REF_DEREF Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)); bool _is_valid = _entry.IsValid(); diff --git a/Storage/ValueStorage.native.h b/Storage/ValueStorage.native.h index 0c6180881..7fb8219fc 100644 --- a/Storage/ValueStorage.native.h +++ b/Storage/ValueStorage.native.h @@ -83,6 +83,15 @@ class NativeValueStorage : public ValueStorage { Array::ArrayStore(_values, _index, _value, 4096); } + /** + * Inserts new value at the end of the buffer. If buffer works as As-Series, + * then new value will act as the one at index 0. + */ + void Append(C _value) override { + Resize(Size() + 1, 4096); + Store(Size() - 1, _value); + } + /** * Returns number of values available to fetch (size of the values buffer). */ From dce2921eaa9431bba219e0675f925124df43a05d Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 26 Apr 2024 21:31:19 +0200 Subject: [PATCH 103/123] Refs #738. WIP. Matrix multiplication via OpenCL. Working on OpenCL buffers caching when passing matrices into kernel arguments. Got rid of templated version of Run() and RunMany(). --- Matrix.mqh | 207 +++++++++++++----------------- OpenCL.h | 298 ++++++++++--------------------------------- tests/OpenCLTest.mq5 | 5 +- 3 files changed, 159 insertions(+), 351 deletions(-) diff --git a/Matrix.mqh b/Matrix.mqh index eea71b0a3..45fbf5b6b 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -643,7 +643,7 @@ class MatrixDimension { } /** - * Extracts dimensions's values to the given array. Used internally. + * Extracts dimensions' values to the given array. Used internally. */ void FillArray(X& array[], int& offset) { int i; @@ -732,44 +732,6 @@ class MatrixDimension { enum ENUM_MATRIX_FLAGS { MATRIX_FLAGS_NONE, MATRIX_FLAGS_USE_OPENCL }; -/** - * Buffer used for CL operations. - */ -template -class MatrixOpenCLBuffer : public Dynamic { - // Flattened matrix data. - ARRAY(X, data); - - // Current version of the data. - long version; - - // CL buffer. - Ref buffer; - - public: - /** - * Constructor. - */ - MatrixOpenCLBuffer(int _size, unsigned int _flags) { - version = 0; - buffer = OpenCL::Alloc(_size, _flags); - ArrayResize(data, _size); - } - - /** - * Prepares buffer to be used by CL. Copies flattened data from the given matrix into buffer. - */ - void FillData(const Matrix& src) { - src.GetRawArray(data); - buffer REF_DEREF Write(data, version); - } - - /** - * Returns pointer to the CL buffer. - */ - OpenCLBuffer* GetBuffer() { return buffer.Ptr(); } -}; - /** * Matrix class. */ @@ -779,10 +741,14 @@ class Matrix { // First/root dimension. MatrixDimension* ptr_first_dimension; +#ifdef MATRIX_USE_OPENCL + // Map of data size -> CL buffer to be used e.g., by CL-based MatMul method. - static DictStruct>> cl_buffers_in_0; - static DictStruct>> cl_buffers_in_1; - static DictStruct>> cl_buffers_out; + static DictStruct> cl_buffers_in_0; + static DictStruct> cl_buffers_in_1; + static DictStruct> cl_buffers_out; + +#endif // Array with declaration of items per matrix's dimension. int dimensions[MATRIX_DIMENSIONS]; @@ -796,14 +762,25 @@ class Matrix { // Flags. int flags; - // Unique id of the matrix. - int uuid; + // Static counter, so each new matrix will have its own version. For new + // matrices new 32-bit range of versions are given and it should be more + // that enough. + static unsigned long version_counter; + + // Cache of previously flattened data. + ARRAY(X, flattened_cache); - // Static counter, so each matrix will have its own uuid. - static int uuid_counter; + // Version of the data that was flattened. + unsigned long flattened_cache_version; - // OpenCL program. + // Version of the data stored in dimensions arrays. Incremented after each + // change to this matrix. + unsigned long version; + + // OpenCL program for multi-core MatMul. static Ref cl_program_matmul; + + // OpenCL program for single-core MatMul. static Ref cl_program_matmul_single; /** @@ -814,7 +791,7 @@ class Matrix { #ifdef MATRIX_USE_OPENCL InitializeOpenCL(); #endif - uuid = uuid_counter++; + Initialize(); } /** @@ -826,7 +803,7 @@ class Matrix { #ifdef MATRIX_USE_OPENCL InitializeOpenCL(); #endif - uuid = uuid_counter++; + Initialize(); } /** @@ -837,7 +814,7 @@ class Matrix { #ifdef MATRIX_USE_OPENCL InitializeOpenCL(); #endif - uuid = uuid_counter++; + Initialize(); } /** @@ -853,8 +830,9 @@ class Matrix { InitializeOpenCL(); #endif - // We mark new matrix as unique one, even though we clone another matrix. - uuid = uuid_counter++; + // Note that we mark new matrix as unique one, even though we clone another + // matrix. + Initialize(); } /** @@ -864,6 +842,18 @@ class Matrix { private: Matrix(const Matrix* _right) {} + /** + * Initializes new or copy of another matrix. + */ + void Initialize() { + // Cache will have version lower that the data so matrix will be flattened in the first occasion. + flattened_cache_version = version_counter; + version = version_counter + 1; + + // Each new matrix will have its own 32-bit range of versions. + version_counter += UINT_MAX; + } + #ifdef MATRIX_USE_OPENCL /** @@ -891,13 +881,13 @@ class Matrix { /** * Returns/allocs and returns buffer of the given size to be used in CL operations as first input parameter. */ - static MatrixOpenCLBuffer* GetCLBufferInArg0(int _size) { - Ref> _buffer; + static OpenCLBuffer* GetCLBufferInArg0(int _size) { + Ref _buffer; _buffer = cl_buffers_in_0.GetByKey(_size, _buffer); if (!_buffer.IsSet()) { - _buffer = new MatrixOpenCLBuffer(_size, CL_MEM_READ_ONLY); + _buffer = new OpenCLBuffer(_size, CL_MEM_READ_ONLY); cl_buffers_in_0.Set(_size, _buffer); } @@ -907,13 +897,13 @@ class Matrix { /** * Returns/allocs and returns buffer of the given size to be used in CL operations as second input parameter. */ - static MatrixOpenCLBuffer* GetCLBufferInArg1(int _size) { - Ref> _buffer; + static OpenCLBuffer* GetCLBufferInArg1(int _size) { + Ref _buffer; _buffer = cl_buffers_in_1.GetByKey(_size, _buffer); if (!_buffer.IsSet()) { - _buffer = new MatrixOpenCLBuffer(_size, CL_MEM_READ_ONLY); + _buffer = new OpenCLBuffer(_size, CL_MEM_READ_ONLY); cl_buffers_in_1.Set(_size, _buffer); } @@ -923,13 +913,13 @@ class Matrix { /** * Returns/allocs and returns buffer of the given size to be used in CL operations as output parameter. */ - static MatrixOpenCLBuffer* GetCLBufferOutArg(int _size) { - Ref> _buffer; + static OpenCLBuffer* GetCLBufferOutArg(int _size) { + Ref _buffer; _buffer = cl_buffers_out.GetByKey(_size, _buffer); if (!_buffer.IsSet()) { - _buffer = new MatrixOpenCLBuffer(_size, CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR); + _buffer = new OpenCLBuffer(_size, CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR); cl_buffers_out.Set(_size, _buffer); } @@ -1411,7 +1401,6 @@ class Matrix { static void MatMul(Matrix& source, Matrix& target, Matrix& output) { #ifdef MATRIX_USE_OPENCL - // MatMulCL(source, target, output); MatMulCL(source, target, output); return; #endif @@ -1433,6 +1422,8 @@ class Matrix { } } +#ifdef MATRIX_USE_OPENCL + /** * Performs matrix multiplication via OpenCL. Note that MATRIX_USE_OPENCL must be defined in order matrix to use this * method. @@ -1446,48 +1437,32 @@ class Matrix { unsigned int _cols_a = _source.GetRange(1); unsigned int _cols_b = _target.GetRange(1); - OpenCLBuffer* _in_1 = GetCLBufferInArg0(_rows_a * _cols_a) PTR_DEREF GetBuffer(); - OpenCLBuffer* _in_2 = GetCLBufferInArg1(_cols_a * _cols_b) PTR_DEREF GetBuffer(); - OpenCLBuffer* _out = GetCLBufferOutArg(_rows_a * _cols_b) PTR_DEREF GetBuffer(); + // Reusable 0-offset. + static ARRAY(unsigned int, _global_work_offset) = {0U, 0U}; - double _in_1_data[]; - double _in_2_data[]; - double _out_data[]; + ARRAY(unsigned int, _global_work_size) = {(unsigned int)_rows_a, (unsigned int)_cols_b}; - // ArrayResize(_out_data, _out PTR_DEREF GetSizeItems()); + // @todo Make local work size adapt to output matrix size. + ARRAY(unsigned int, _local_work_size) = {1U, 1U}; - _source.GetRawArray(_in_1_data); - _target.GetRawArray(_in_2_data); - - _in_1 PTR_DEREF Write(_in_1_data); - _in_2 PTR_DEREF Write(_in_2_data); - - cl_program_matmul REF_DEREF SetArg(0, _in_1); - cl_program_matmul REF_DEREF SetArg(1, _in_2); - cl_program_matmul REF_DEREF SetArg(2, _out); + cl_program_matmul REF_DEREF SetArg(0, _source, OPENCL_MATRIX_ARG_IN_1); + cl_program_matmul REF_DEREF SetArg(1, _target, OPENCL_MATRIX_ARG_IN_2); + cl_program_matmul REF_DEREF SetArg(2, _output, OPENCL_MATRIX_ARG_OUT); cl_program_matmul REF_DEREF SetArg(3, (int)_rows_a); cl_program_matmul REF_DEREF SetArg(4, (int)_cols_a); cl_program_matmul REF_DEREF SetArg(5, (int)_cols_b); - ARRAY(unsigned int, _global_work_offset); - ARRAY(unsigned int, _global_work_size); - ARRAY(unsigned int, _local_work_size); - - ArrayPush(_global_work_offset, 0U); - ArrayPush(_global_work_offset, 0U); - ArrayPush(_global_work_size, (unsigned int)_rows_a); - ArrayPush(_global_work_size, (unsigned int)_cols_b); - ArrayPush(_local_work_size, 1U); - ArrayPush(_local_work_size, 1U); - - if (!cl_program_matmul REF_DEREF RunMany(2, _global_work_offset, _global_work_size, _local_work_size)) { + if (!cl_program_matmul REF_DEREF RunMany(2U, _global_work_offset, _global_work_size, _local_work_size)) { Alert("Error: Could not run Matrix::MatMulCL() over OpenCL!"); DebugBreak(); } - _out PTR_DEREF Read(_out_data); - + // Extracting data from + ARRAY(X, _out_data); + ArrayResize(_out_data, _rows_a * _cols_b); + _output.GetBuffer() PTR_DEREF Read(_out_data); _output.SetShape(_rows_a, _cols_b); + _output.FillFromArray(_out_data); } /** @@ -1535,27 +1510,7 @@ class Matrix { // _output.SetShape(num_outputs); } - static void MatMulCL_CPU(int Mdim, int Ndim, int Pdim, double& A[], double& B[], double& C[]) { - /* - for (int i = 0; i < Mdim; ++i) { - for (int j = 0; j < Pdim; ++j) { - C[i * Pdim + j] = 0.0; - for (int k = 0; k < Ndim; ++k) { - C[i * Pdim + j] += A[i * Ndim + k] * B[k * Pdim + j]; - } - } - } - */ - - int i, j, k; - for (i = 0; i < Ndim; i++) { - for (j = 0; j < Mdim; j++) { - for (k = 0; k < Pdim; k++) { // C(i,j) = sum(over k) A(i,k) * B(k,j) - C[i * Pdim + j] += A[i * Ndim + k] * B[k * Pdim + j]; - } - } - } - } +#endif /** * Performs matrix multiplication. @@ -1703,6 +1658,12 @@ class Matrix { return result; } + /** + * Fills matrix from flattened data. Shape of the array must be initialized + * before deflatenning. + */ + void Deflatten(const ARRAY_REF(X, array)) {} + /** * Initializer that generates tensors with a uniform distribution. */ @@ -2564,32 +2525,36 @@ class Matrix { } }; +#ifdef MATRIX_USE_OPENCL + #ifdef __MQL__ template -static int Matrix::uuid_counter = 0; +static unsigned long Matrix::version_counter = 0UL; template static Ref Matrix::cl_program_matmul; template static Ref Matrix::cl_program_matmul_single; template -static DictStruct>> Matrix::cl_buffers_in_0; +static DictStruct> Matrix::cl_buffers_in_0; template -static DictStruct>> Matrix::cl_buffers_in_1; +static DictStruct> Matrix::cl_buffers_in_1; template -static DictStruct>> Matrix::cl_buffers_out; +static DictStruct> Matrix::cl_buffers_out; #else template -static int Matrix::uuid_counter = 0; +static unsigned long Matrix::version_counter = 0UL; template static Ref Matrix::cl_program_matmul; template static Ref Matrix::cl_program_matmul_single; template -static DictStruct>> Matrix::cl_buffers_in_0; +static DictStruct> Matrix::cl_buffers_in_0; template -static DictStruct>> Matrix::cl_buffers_in_1; +static DictStruct> Matrix::cl_buffers_in_1; template -static DictStruct>> Matrix::cl_buffers_out; +static DictStruct> Matrix::cl_buffers_out; #endif #endif + +#endif \ No newline at end of file diff --git a/OpenCL.h b/OpenCL.h index b6fe7bc54..0ce41a1f1 100644 --- a/OpenCL.h +++ b/OpenCL.h @@ -9,6 +9,11 @@ // Forward declarations; class OpenCLProgram; +template +class Matrix; + +// Type of the matrix passed as argument to the OpenCLProgram. +enum ENUM_OPENCL_MATRIX_ARG { OPENCL_MATRIX_ARG_IN_1, OPENCL_MATRIX_ARG_IN_2, OPENCL_MATRIX_ARG_OUT }; /** * Memory buffer. @@ -20,8 +25,8 @@ class OpenCLBuffer : public Dynamic { // Allocated buffer size. int buffer_size; - // Buffer version. Should be incremented after each change. - long version; + // Version of the data. The same one that was passed to the Write() method. + unsigned long version; public: /** @@ -29,10 +34,15 @@ class OpenCLBuffer : public Dynamic { */ OpenCLBuffer(int _size, unsigned int _flags = CL_MEM_READ_WRITE); + /** + * Checks whether stored data version differs from the passed version. + */ + bool RequiresReupload(unsigned long _data_version) { return _data_version == ULONG_MAX || version != _data_version; } + /** * Writes/uploads data into buffer if needed. */ - void Write(const ARRAY_REF(double, _arr), long _arr_version = -1) { + void Write(const ARRAY_REF(double, _arr), unsigned long _data_version = ULONG_MAX) { if (ArraySize(_arr) > buffer_size) { Alert("Array passed is too large for the allocated buffer. Tries to pass ", ArraySize(_arr), " elements into buffer of size ", buffer_size, "."); @@ -40,15 +50,13 @@ class OpenCLBuffer : public Dynamic { return; } - // Do we need to reupload data into GPU? - if (_arr_version != -1 && _arr_version <= version) { - // Buffer has already up-to-date data. + if (!RequiresReupload(_data_version)) { return; } CLBufferWrite(buffer_handle, _arr); - version = (_arr_version != -1) ? _arr_version : (version + 1); + version = _data_version; } /** @@ -78,7 +86,7 @@ class OpenCLBuffer : public Dynamic { /** * Returns data version. */ - long GetVersion() { return version; } + unsigned long GetVersion() { return version; } /** * Returns handle to buffer. @@ -109,7 +117,7 @@ class OpenCLProgram : public Dynamic { int arg_handles[OPENCL_PROGRAM_MAX_ARGS]; // Version of argument data. Used to check if buffer needs to be reuploaded. - long arg_versions[OPENCL_PROGRAM_MAX_ARGS]; + unsigned long arg_versions[OPENCL_PROGRAM_MAX_ARGS]; public: /** @@ -140,6 +148,13 @@ class OpenCLProgram : public Dynamic { */ void SetArgLocalMem(int _index, unsigned long _mem_size) { CLSetKernelArgMemLocal(kernel_handle, _index, _mem_size); } + /** + * Checks whether given argument requires reupload of the buffer into GPU. + */ + bool RequiresReupload(int _index, OpenCLBuffer* _buffer, unsigned long _data_version) { + return _buffer PTR_DEREF GetHandle() != arg_handles[_index] || _data_version != arg_versions[_index]; + } + /** * Passes argument to the kernel. Will not set kernel argument if not needed. * @@ -157,10 +172,10 @@ class OpenCLProgram : public Dynamic { * which you can pass version of your data, so no reupload will take place if * your version isn't greater that the one already set in the buffer. */ - void SetArg(int _index, OpenCLBuffer* _buffer) { - if (_buffer PTR_DEREF GetHandle() == arg_handles[_index] && - _buffer PTR_DEREF GetVersion() >= arg_versions[_index]) { - // Already uploaded recent version. + void SetArg(int _index, OpenCLBuffer* _buffer, unsigned long _data_version) { + if (!RequiresReupload(_index, _buffer, _data_version)) { + // Buffer is already set via CLSetKernelArgMem() and argument's version + // is the same as _data_version. return; } @@ -174,115 +189,53 @@ class OpenCLProgram : public Dynamic { } /** - * Executes a single kernel. - */ - bool Run() { - if (!CLExecute(kernel_handle)) { - Alert("OpenCL error occured when tried to run kernel: ", GetLastError(), "!"); - return false; + * Passes matrix argument to the kernel. Will not upload data if not needed. + * + * The idea is to retrieve existing buffer that matches matrix size and its + * purpose. If such buffer already exists in the same version in the argument + * slot then no reupload will take place. + */ + template + void SetArg(int _index, Matrix& _matrix, ENUM_OPENCL_MATRIX_ARG _matrix_type) { + unsigned long _matrix_data_version = _matrix.GetVersion(); + OpenCLBuffer* _buffer = nullptr; + + switch (_matrix_type) { + case OPENCL_MATRIX_ARG_IN_1: + _buffer = GetCLBufferInArg0(_matrix.GetSize()); + break; + + case OPENCL_MATRIX_ARG_IN_2: + _buffer = GetCLBufferInArg1(_matrix.GetSize()); + break; + + case OPENCL_MATRIX_ARG_OUT: + _buffer = GetCLBufferOutArg(_matrix.GetSize()); + break; } - return true; - } + if (RequiresReupload(_index, _buffer, _matrix_data_version)) { + // Flattening matrix data in order to upload it into GPU. + double _flattened_data[]; + _matrix.GetRawArray(_flattened_data); - /** - * Executes a single kernel. Allows passing arugments to kernel. - */ - template - bool Run(A a) { - SetArg(0, a); - return Run(); - } + _buffer PTR_DEREF Write(_flattened_data) - /** - * Executes a single kernel. Allows passing arugments to kernel. - */ - template - bool Run(A a, B b) { - SetArg(0, a); - SetArg(1, b); - return Run(); - } - - /** - * Executes a single kernel. Allows passing arugments to kernel. - */ - template - bool Run(A a, B b, C c) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - return Run(); - } - - /** - * Executes a single kernel. Allows passing arugments to kernel. - */ - template - bool Run(A a, B b, C c, D d) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - SetArg(3, d); - return Run(); - } - - /** - * Executes a single kernel. Allows passing arugments to kernel. - */ - template - bool Run(A a, B b, C c, D d, E e) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - SetArg(3, d); - SetArg(4, e); - return Run(); - } - - /** - * Executes a single kernel. Allows passing arugments to kernel. - */ - template - bool Run(A a, B b, C c, D d, E e, F f) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - SetArg(3, d); - SetArg(4, e); - SetArg(5, f); - return Run(); + // Do we need to reupload the data? + SetArg(_index, _buffer, _matrix_data_version); + } } /** - * Executes a single kernel. Allows passing arugments to kernel. + * Executes a single kernel. */ - template - bool Run(A a, B b, C c, D d, E e, F f, G g) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - SetArg(3, d); - SetArg(4, e); - SetArg(5, f); - SetArg(6, g); - return Run(); - } + bool Run() { + if (!CLExecute(kernel_handle)) { + Alert("OpenCL error occured when tried to run kernel: ", GetLastError(), "!"); + return false; + } - /** - * Executes a single kernel. Allows passing arugments to kernel. - */ - template - bool Run(A a, B b, C c, D d, E e, F f, G g, H h) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - SetArg(3, d); - SetArg(4, e); - SetArg(5, f); - SetArg(6, g); - SetArg(7, h); - return Run(); + return true; } /** @@ -298,121 +251,6 @@ class OpenCLProgram : public Dynamic { return true; } - /** - * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. - */ - template - bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), - const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a) { - SetArg(0, a); - return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); - } - - /** - * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. - */ - template - bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), - const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, - B b) { - SetArg(0, a); - SetArg(1, b); - return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); - } - - /** - * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. - */ - template - bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), - const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, - B b, C c) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); - } - - /** - * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. - */ - template - bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), - const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, - B b, C c, D d) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - SetArg(3, d); - return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); - } - - /** - * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. - */ - template - bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), - const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, - B b, C c, D d, E e) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - SetArg(3, d); - SetArg(4, e); - return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); - } - - /** - * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. - */ - template - bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), - const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, - B b, C c, D d, E e, F f) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - SetArg(3, d); - SetArg(4, e); - SetArg(5, f); - return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); - } - - /** - * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. - */ - template - bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), - const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, - B b, C c, D d, E e, F f, G g) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - SetArg(3, d); - SetArg(4, e); - SetArg(5, f); - SetArg(6, g); - return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); - } - - /** - * Executes multiple kernels where work is subdivided among kernels. Allows passing arugments to kernels. - */ - template - bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), - const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size), A a, - B b, C c, D d, E e, F f, G g, H h) { - SetArg(0, a); - SetArg(1, b); - SetArg(2, c); - SetArg(3, d); - SetArg(4, e); - SetArg(5, f); - SetArg(6, g); - SetArg(7, h); - return RunMany(_dimension, _global_work_offset, _global_work_size, _local_work_size); - } - /** * Returns handle to OpenCL program. */ @@ -542,5 +380,7 @@ OpenCLBuffer::OpenCLBuffer(int _size, unsigned int _flags) { DebugBreak(); } buffer_size = _size; - version = 0; + // Ensuring there won't be initial version clash when checking if buffer data + // need to be reuploaded. + version = ULONG_MAX; } diff --git a/tests/OpenCLTest.mq5 b/tests/OpenCLTest.mq5 index c26cf3153..0e0d2ef50 100644 --- a/tests/OpenCLTest.mq5 +++ b/tests/OpenCLTest.mq5 @@ -42,7 +42,9 @@ int OnInit() { Ref buffer = OpenCL::Alloc(1 /* 1 double */, CL_MEM_READ_WRITE); - if (!program REF_DEREF Run(buffer.Ptr())) { + program REF_DEREF SetArg(0, buffer.Ptr(), ULONG_MAX); + + if (!program REF_DEREF Run()) { Alert("Error running program!"); } @@ -57,6 +59,7 @@ int OnInit() { Print("in2 shape: ", in2 PTR_DEREF GetRange(0), " x ", in2 PTR_DEREF GetRange(1)); out = in1 PTR_DEREF MatMul(in2); Print("out shape: ", out PTR_DEREF GetRange(0), " x ", out PTR_DEREF GetRange(1)); + Print("out data: ", out PTR_DEREF ToString()); delete in1; delete in2; From d290033b9d26c725593c33b6d467ebf6dbfa9f93 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 27 Apr 2024 17:25:22 +0100 Subject: [PATCH 104/123] Std: Uses Alert() and DebugBreak() for MQL only --- Std.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Std.h b/Std.h index bdf345ab7..637aa766c 100644 --- a/Std.h +++ b/Std.h @@ -308,23 +308,29 @@ struct AsSeriesReleaseEnsurer { AsSeriesReleaseEnsurer(int _num_buffs) : released(false), num_buffs(_num_buffs) {} void done(int _num_buffs) { if (_num_buffs != num_buffs) { +#ifdef __MQL__ Alert("You have acquired ", num_buffs, " buffers via ACQUIRE_BUFFER", num_buffs, "(), but now trying to release with mismatched RELEASE_BUFFER", _num_buffs, "()!"); DebugBreak(); +#endif } if (released) { +#ifdef __MQL__ Alert("You have used RELEASE_BUFFER", num_buffs, "() again which is not required!"); DebugBreak(); +#endif } released = true; } ~AsSeriesReleaseEnsurer() { if (!released) { +#ifdef __MQL__ Alert("You have used ACQUIRE_BUFFER", num_buffs, "() but didn't release buffer(s) via RELEASE_BUFFER", num_buffs, "() before returning from the scope!"); DebugBreak(); +#endif } } }; From ad24e5b786147864e696c5d29380d8171baa2302 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 1 May 2024 20:07:17 +0200 Subject: [PATCH 105/123] Refs #738. Matrix multiplication via OpenCL. Ready for testing. --- Matrix.matmul.naive.cl | 29 +++---- Matrix.mqh | 166 ++++++++++++++++++++++++++--------------- OpenCL.h | 34 +++++++-- tests/MatrixTest.mq5 | 15 ++-- tests/OpenCLTest.mq5 | 2 +- 5 files changed, 148 insertions(+), 98 deletions(-) diff --git a/Matrix.matmul.naive.cl b/Matrix.matmul.naive.cl index 612c2eb97..7ce5b64a1 100644 --- a/Matrix.matmul.naive.cl +++ b/Matrix.matmul.naive.cl @@ -1,23 +1,14 @@ #pragma OPENCL EXTENSION cl_khr_fp64 : enable -__kernel void matmul( - __global double* A, - __global double* B, - __global double* C, - int rowsA, - int colsA, - int colsB - ) -{ - int row = get_global_id(0); - int col = get_global_id(1); - - double sum = 0.0; - - for(int k = 0; k < colsA; ++k) { - sum += A[row * colsA + k] * B[k * colsB + col]; - //sum += col; +__kernel void matmul(__global double* A, __global double* B, __global double* C, int rowsA, int colsA, int colsB) { + int i = get_global_id(0); + int j = get_global_id(1); + + if (i < rowsA && j < colsB) { + float sum = 0.0f; + for (int k = 0; k < colsA; ++k) { + sum += A[i * colsA + k] * B[k * colsB + j]; + } + C[i * colsB + j] = sum; } - - C[row * colsB + col] = sum; } \ No newline at end of file diff --git a/Matrix.mqh b/Matrix.mqh index 45fbf5b6b..53d161160 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -878,6 +878,21 @@ class Matrix { #endif public: + /** + * Returns matrix's data version. + */ + unsigned long GetVersion() { return version; } + + /** + * Returns matrix flattened data version. + */ + unsigned long GetFlattenedCacheVersion() { return flattened_cache_version; } + + /** + * Acknowledges matrix that it's data has been changed. + */ + void Modified() { ++version; } + /** * Returns/allocs and returns buffer of the given size to be used in CL operations as first input parameter. */ @@ -958,6 +973,8 @@ class Matrix { num_dimensions = i; RecalculateSize(); + + Modified(); } void RecalculateSize() { @@ -1045,12 +1062,14 @@ class Matrix { size *= dimensions[i]; } } + + Modified(); } /** * Returns length of the given dimension. */ - int GetRange(int _dimension) { + int GetRangeRaw(int _dimension) { if (_dimension >= MATRIX_DIMENSIONS) { Print("Matrix::GetRange(): Dimension should be between 0 and ", MATRIX_DIMENSIONS - 1, ". Got ", _dimension, "!"); return -1; @@ -1059,6 +1078,22 @@ class Matrix { return dimensions[_dimension]; } + /** + * Returns length of the given dimension. In case that e.g., dimension 0 has values, dimension 1 will return range 1. + */ + int GetRange(int _dimension) { + if (_dimension < num_dimensions) { + return GetRangeRaw(_dimension); + } + + if (_dimension == num_dimensions) { + // Last dimension always contain values. + return 1; + } + + return 0; + } + /** * Returns total number of values the matrix contain of. */ @@ -1081,6 +1116,7 @@ class Matrix { int initial_container_size = ptr_first_dimension.DuplicateDimension(_level, _num); dimensions[_level] += _num * initial_container_size; RecalculateSize(); + Modified(); } /** @@ -1209,6 +1245,8 @@ class Matrix { } accessor = _value; + + Modified(); } /** @@ -1231,6 +1269,7 @@ class Matrix { void Add(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_ADD, value); + Modified(); } } @@ -1245,6 +1284,7 @@ class Matrix { void Sub(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_SUBTRACT, value); + Modified(); } } @@ -1259,6 +1299,7 @@ class Matrix { void Mul(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_MULTIPLY, value); + Modified(); } } @@ -1273,6 +1314,7 @@ class Matrix { void Div(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_DIVIDE, value); + Modified(); } } @@ -1282,6 +1324,7 @@ class Matrix { void Fill(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_FILL, value); + Modified(); } } @@ -1291,6 +1334,7 @@ class Matrix { void FillRandom(int _seed = -1) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_FILL_RANDOM, _seed); + Modified(); } } @@ -1300,6 +1344,7 @@ class Matrix { void FillRandom(X _start, X _end, int _seed = -1) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_FILL_RANDOM_RANGE, _start, _end, _seed); + Modified(); } } @@ -1309,6 +1354,7 @@ class Matrix { void FillPosAdd() { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_FILL_POS_ADD); + Modified(); } } @@ -1318,11 +1364,12 @@ class Matrix { void FillPosMul() { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_FILL_POS_MUL); + Modified(); } } /** - * Replaces existing matrix's values by random value from a given range. + * Calculates sum fo all matrix's values. */ X Sum() { X _out1 = 0, _out2; @@ -1370,9 +1417,13 @@ class Matrix { return MinOf((X)0); } + /** + * Performs power operation on all matrix's values. + */ void Power(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_POWER, value); + Modified(); } } @@ -1420,6 +1471,8 @@ class Matrix { output[output_idx] += source[input_idx].Val() * target[output_idx][input_idx].Val(); } } + + output.Modified(); } #ifdef MATRIX_USE_OPENCL @@ -1440,10 +1493,16 @@ class Matrix { // Reusable 0-offset. static ARRAY(unsigned int, _global_work_offset) = {0U, 0U}; - ARRAY(unsigned int, _global_work_size) = {(unsigned int)_rows_a, (unsigned int)_cols_b}; + // Local work size (up to 8 x 8). + static ARRAY(unsigned int, _local_work_size) = {MathMin(_rows_a, 8U), MathMin(_cols_a, 8U)}; - // @todo Make local work size adapt to output matrix size. - ARRAY(unsigned int, _local_work_size) = {1U, 1U}; + // Our global size could be greater that data. + ARRAY(unsigned int, _global_work_size) = { + (unsigned int)MathCeil((double)_rows_a / _local_work_size[0]) * _local_work_size[0], + (unsigned int)MathCeil((double)_cols_a / _local_work_size[1]) * _local_work_size[1], + }; + + _output.SetShape(_rows_a, _cols_b); cl_program_matmul REF_DEREF SetArg(0, _source, OPENCL_MATRIX_ARG_IN_1); cl_program_matmul REF_DEREF SetArg(1, _target, OPENCL_MATRIX_ARG_IN_2); @@ -1460,56 +1519,11 @@ class Matrix { // Extracting data from ARRAY(X, _out_data); ArrayResize(_out_data, _rows_a * _cols_b); - _output.GetBuffer() PTR_DEREF Read(_out_data); + cl_program_matmul REF_DEREF GetArgBuffer(2) PTR_DEREF Read(_out_data); _output.SetShape(_rows_a, _cols_b); _output.FillFromArray(_out_data); } - /** - * Performs matrix multiplication via OpenCL. Note that MATRIX_USE_OPENCL must be defined in order matrix to use this - * method. - */ - static void MatMulCLSingle(Matrix& _source, Matrix& _target, Matrix& _output) { - if (_source.GetRange(1) != _target.GetRange(0)) { - Alert("Inconsistent size of matrices!"); - } - - unsigned int _cols_a = _source.GetRange(0); - unsigned int _rows_a = _source.GetRange(1); - unsigned int _cols_b = _target.GetRange(1); - - OpenCLBuffer* _in_1 = GetCLBufferInArg0(_rows_a * _cols_b) PTR_DEREF GetBuffer(); - OpenCLBuffer* _in_2 = GetCLBufferInArg1(_cols_b * _cols_a) PTR_DEREF GetBuffer(); - OpenCLBuffer* _out = GetCLBufferOutArg(_cols_a * _cols_b) PTR_DEREF GetBuffer(); - - double _in_1_data[]; - double _in_2_data[]; - double _out_data[]; - - ArrayResize(_out_data, _out PTR_DEREF GetSizeItems()); - - _source.GetRawArray(_in_1_data); - _target.GetRawArray(_in_2_data); - - MatMulCL_CPU(_cols_a, _rows_a, _cols_b, _in_1_data, _in_2_data, _out_data); - - cl_program_matmul REF_DEREF SetArg(0, (int)_rows_a); - cl_program_matmul REF_DEREF SetArg(1, (int)_cols_a); - cl_program_matmul REF_DEREF SetArg(2, (int)_cols_b); - cl_program_matmul REF_DEREF SetArg(3, _in_1); - cl_program_matmul REF_DEREF SetArg(4, _in_2); - cl_program_matmul REF_DEREF SetArg(5, _out); - - if (!cl_program_matmul REF_DEREF Run()) { - Alert("Errpr: Could not run Matrix::MatMulCL() over OpenCL!"); - DebugBreak(); - } - - _out PTR_DEREF Read(_out_data); - - // _output.SetShape(num_outputs); - } - #endif /** @@ -1563,6 +1577,7 @@ class Matrix { void operator+=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); + Modified(); } } @@ -1585,6 +1600,7 @@ class Matrix { void operator-=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); + Modified(); } } @@ -1607,6 +1623,7 @@ class Matrix { void operator*=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + Modified(); } } @@ -1629,16 +1646,29 @@ class Matrix { void operator/=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); + Modified(); } } /** * Fills array with all values from the matrix. */ - void GetRawArray(X& array[]) const { - ArrayResize(array, GetSize()); + void GetRawArray(X& array[]) { + if (flattened_cache_version == version) { + // No need to flatten again as our cache is up to date. + ArrayCopy(array, flattened_cache); + return; + } + + // Filling target array with flattened matrix data. int offset = 0; + ArrayResize(array, GetSize()); ptr_first_dimension.FillArray(array, offset); + + // Copying target array into our flattened data cache. + ArrayResize(flattened_cache, 0, 1024); + ArrayCopy(flattened_cache, array); + flattened_cache_version = version; } /** @@ -1658,12 +1688,6 @@ class Matrix { return result; } - /** - * Fills matrix from flattened data. Shape of the array must be initialized - * before deflatenning. - */ - void Deflatten(const ARRAY_REF(X, array)) {} - /** * Initializer that generates tensors with a uniform distribution. */ @@ -1696,6 +1720,8 @@ class Matrix { int offset = 0; ptr_first_dimension.FromArray(_array, offset); + + Modified(); } /** @@ -1703,17 +1729,24 @@ class Matrix { */ void FillTruncatedNormal(X _mean, X _stddev, int _seeds = -1) { Print("Matrix::FillTruncatedNormal() is not yet implemented!"); + Modified(); } /** * The Glorot normal initializer, also called Xavier normal initializer. */ - void FillGlorotNormal(int _seed = -1) { Print("Matrix::FillGlorotNormal() is not yet implemented!"); } + void FillGlorotNormal(int _seed = -1) { + Print("Matrix::FillGlorotNormal() is not yet implemented!"); + Modified(); + } /** * The Glorot uniform initializer, also called Xavier uniform initializer. */ - void FillGlorotUniform(int _seed = -1) { Print("Matrix::FillGlorotUniform() is not yet implemented!"); } + void FillGlorotUniform(int _seed = -1) { + Print("Matrix::FillGlorotUniform() is not yet implemented!"); + Modified(); + } /** * Initializer that generates the identity matrix. @@ -1736,7 +1769,10 @@ class Matrix { /** * Initializer that generates an orthogonal matrix. */ - void FillOrthogonal(X _gain, int _seed = -1) { Print("Matrix::FillOrthogonal() is not yet implemented!"); } + void FillOrthogonal(X _gain, int _seed = -1) { + Print("Matrix::FillOrthogonal() is not yet implemented!"); + Modified(); + } /** * Calculates absolute difference between this tensor and given one using optional weights tensor. @@ -1801,6 +1837,7 @@ class Matrix { void ReduceSimple(bool _only_last_dimension = true, ENUM_MATRIX_OPERATION _reduce_op = MATRIX_OPERATION_SUM) { if (ptr_first_dimension != NULL) { ptr_first_dimension.ReduceSimple(_only_last_dimension ? GetDimensions() - 1 : 0, _reduce_op); + Modified(); } } @@ -1816,6 +1853,7 @@ class Matrix { } RecalculateSize(); + Modified(); } /** @@ -2056,6 +2094,7 @@ class Matrix { int _out3; if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_RELU, 0, 0, 0, _out1, _out2, _out3); + Modified(); } } @@ -2086,6 +2125,7 @@ class Matrix { } else { this[_1d][_2d][_3d][_4d][_5d] = value; } + Modified(); } Matrix* GetConv2d(int _in_channels, int _out_channels, int _krn_1d, int _krn_2d, @@ -2370,6 +2410,8 @@ class Matrix { Print("Matrix::ChunkOp(): Invalid operation ", EnumToString(_op), "!"); } + // Note: ChuckOp() does not modify the matrix. + return 0; } diff --git a/OpenCL.h b/OpenCL.h index 0ce41a1f1..b6aa15303 100644 --- a/OpenCL.h +++ b/OpenCL.h @@ -119,6 +119,10 @@ class OpenCLProgram : public Dynamic { // Version of argument data. Used to check if buffer needs to be reuploaded. unsigned long arg_versions[OPENCL_PROGRAM_MAX_ARGS]; + // Buffers passed as arguments. Note that we store weak references, so we + // need to check if buffer still exists. + WeakRef arg_buffers[OPENCL_PROGRAM_MAX_ARGS]; + public: /** * Constructor. @@ -127,6 +131,7 @@ class OpenCLProgram : public Dynamic { for (int i = 0; i < OPENCL_PROGRAM_MAX_ARGS; ++i) { arg_handles[i] = INVALID_HANDLE; arg_versions[i] = -1; + arg_buffers[i] = nullptr; } } @@ -186,6 +191,22 @@ class OpenCLProgram : public Dynamic { // Storing buffer version in the argument slot. arg_versions[_index] = _buffer PTR_DEREF GetVersion(); + + // Storing pointer to the buffer as weak reference. + arg_buffers[_index] = _buffer; + } + + /** + * Returns buffer passed as argument. + */ + OpenCLBuffer* GetArgBuffer(int _index) { + if (!arg_buffers[_index].ObjectExists()) { + Alert("Error: Trying to retrieve buffer at argument index ", _index, + ", but the buffer was either not set or deleted."); + DebugBreak(); + } + + return arg_buffers[_index].Ptr(); } /** @@ -202,15 +223,15 @@ class OpenCLProgram : public Dynamic { switch (_matrix_type) { case OPENCL_MATRIX_ARG_IN_1: - _buffer = GetCLBufferInArg0(_matrix.GetSize()); + _buffer = _matrix.GetCLBufferInArg0(_matrix.GetSize()); break; case OPENCL_MATRIX_ARG_IN_2: - _buffer = GetCLBufferInArg1(_matrix.GetSize()); + _buffer = _matrix.GetCLBufferInArg1(_matrix.GetSize()); break; case OPENCL_MATRIX_ARG_OUT: - _buffer = GetCLBufferOutArg(_matrix.GetSize()); + _buffer = _matrix.GetCLBufferOutArg(_matrix.GetSize()); break; } @@ -218,11 +239,8 @@ class OpenCLProgram : public Dynamic { // Flattening matrix data in order to upload it into GPU. double _flattened_data[]; _matrix.GetRawArray(_flattened_data); - - _buffer PTR_DEREF Write(_flattened_data) - - // Do we need to reupload the data? - SetArg(_index, _buffer, _matrix_data_version); + _buffer PTR_DEREF Write(_flattened_data); + SetArg(_index, _buffer, _matrix_data_version); } } diff --git a/tests/MatrixTest.mq5 b/tests/MatrixTest.mq5 index f1d3d679e..8f0aa09b2 100644 --- a/tests/MatrixTest.mq5 +++ b/tests/MatrixTest.mq5 @@ -595,30 +595,29 @@ int OnInit() { assertTrueOrFail(matrix_24_relu.ToString(false, 4) == "[0.0000,0.0000,0.0000,1.0000,2.0000]", "Matrix::Relu(): Invalid result!"); - Matrix matrix_26("[1, 2, 3]"); + Matrix matrix_26("[[1, 2, 3]]"); Matrix matrix_27( "[[1, 1, 1]" " [0, 1, 0]" " [0, 0, 2]]"); Matrix* ptr_matrix_27_matmul = matrix_26 ^ matrix_27; - - assertTrueOrFail(ptr_matrix_27_matmul.ToString(false, 2) == "[6.00,2.00,6.00]", + assertTrueOrFail(ptr_matrix_27_matmul.ToString(false, 2) == "[[1.00,3.00,7.00]]", "Matrix::operator=(MatrixDimension): Invalid result!"); - Matrix matrix_27_bias("[1, 0, 5]"); + Matrix matrix_27_bias("[[1, 0, 5]]"); Matrix* ptr_matrix_27_add = ptr_matrix_27_matmul + matrix_27_bias; - assertTrueOrFail(ptr_matrix_27_add.ToString(false, 0) == "[7,2,11]", "Matrix::operator+(Matrix): Invalid result!"); + assertTrueOrFail(ptr_matrix_27_add.ToString(false, 0) == "[[2,3,12]]", "Matrix::operator+(Matrix): Invalid result!"); Matrix* ptr_matrix_27_sub = ptr_matrix_27_matmul - matrix_27_bias; - assertTrueOrFail(ptr_matrix_27_sub.ToString(false, 0) == "[5,2,1]", "Matrix::operator+(Matrix): Invalid result!"); + assertTrueOrFail(ptr_matrix_27_sub.ToString(false, 0) == "[[0,3,2]]", "Matrix::operator+(Matrix): Invalid result!"); Matrix* ptr_matrix_27_mul = ptr_matrix_27_matmul * matrix_27_bias; - assertTrueOrFail(ptr_matrix_27_mul.ToString(false, 0) == "[6,0,30]", "Matrix::operator+(Matrix): Invalid result!"); + assertTrueOrFail(ptr_matrix_27_mul.ToString(false, 0) == "[[1,0,35]]", "Matrix::operator+(Matrix): Invalid result!"); - delete ptr_matrix_27_matmul; delete ptr_matrix_27_add; + delete ptr_matrix_27_matmul; delete ptr_matrix_27_sub; delete ptr_matrix_27_mul; diff --git a/tests/OpenCLTest.mq5 b/tests/OpenCLTest.mq5 index 0e0d2ef50..65eb84a19 100644 --- a/tests/OpenCLTest.mq5 +++ b/tests/OpenCLTest.mq5 @@ -55,7 +55,7 @@ int OnInit() { Matrix *in1, *in2, *out; in1 = Matrix::CreateFromString("[[1,2,3], [4,5,6]]"); // 2 x 3 Print("in1 shape: ", in1 PTR_DEREF GetRange(0), " x ", in1 PTR_DEREF GetRange(1)); - in2 = Matrix::CreateFromString("[[7,8,9,10], [11,12,13,14], [15,16,17,18]]"); // 3 x 4 + in2 = Matrix::CreateFromString("[[7,8,9,10,11], [11,12,13,14,16], [15,16,17,18,19]]"); // 3 x 5 Print("in2 shape: ", in2 PTR_DEREF GetRange(0), " x ", in2 PTR_DEREF GetRange(1)); out = in1 PTR_DEREF MatMul(in2); Print("out shape: ", out PTR_DEREF GetRange(0), " x ", out PTR_DEREF GetRange(1)); From 979924a0afb39cfc1160608b1f52263f93eb288c Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 2 May 2024 00:18:59 +0100 Subject: [PATCH 106/123] Merge branch 'v3.007-dev-new' into HEAD * v3.007-dev-new: (246 commits) Taskable: Fixes compilation for Taskable.test.mq4 Std: Uses Alert() and DebugBreak() for MQL only Workaround for closing order conditions after orders are loaded from active pool (GH-705) Trade: TradeParams: Adds max_spread Order: Fixes the current volume value when data in orequest is missing Order: Refresh order after modification Trade: Disables filling modes for MQL4 Account/AccountMt: Fixes zero division Refs EA31337-classes/EA31337-indicators-other#13, EA31337-classes/EA31337-indicators-other#15. WIP. TDI-RT-Clone and Heiken_Ashi_Smoothed indicators made to work in MT5. GHA: Compile: Adds support for path input ACQUIRE_BUFFERn / RELEASE_BUFFERn functionality required for EA31337/EA31337-indicators-stats#1 SerializerConverter: Fixes error: member reference base type 'C *' is not a structure Fixes nullptr undeclared identifier Minor fixes C++ compatibility fixes. Account/AccountMt: Fixes zero division GHA: Compile: Support for workflow calls GHA: Compile: Skips clean-up by default GHA: Fixes compilation workflows Trade: Disables filling modes for MQL4 ... --- Array.mqh | 2 +- Indicator.struct.h | 2 +- .../Account/tests/Indi_AccountStats.test.mq5 | 2 +- Matrix.matmul.cl | 115 +++++ Matrix.matmul.naive.cl | 14 + Matrix.matmul.test.cl | 19 + Matrix.mqh | 357 +++++++++++++++- OpenCL.h | 404 ++++++++++++++++++ Std.h | 166 +------ tests/MatrixTest.mq5 | 15 +- tests/OpenCLTest.mq5 | 70 +++ 11 files changed, 980 insertions(+), 186 deletions(-) create mode 100644 Matrix.matmul.cl create mode 100644 Matrix.matmul.naive.cl create mode 100644 Matrix.matmul.test.cl create mode 100644 OpenCL.h create mode 100644 tests/OpenCLTest.mq5 diff --git a/Array.mqh b/Array.mqh index 943927f2b..bfb0a0392 100644 --- a/Array.mqh +++ b/Array.mqh @@ -772,7 +772,7 @@ template template void ArrayPush(ARRAY_REF(X, array), X value) { - ArrayResize(Array::ArraySize(array) + 1); + ArrayResize(array, ArraySize(array) + 1); array[ArraySize(array) - 1] = value; } template diff --git a/Indicator.struct.h b/Indicator.struct.h index 67619a877..cde778669 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -152,7 +152,7 @@ struct IndicatorParams { } void SetMaxParams(int _value) { max_params = _value; - ArrayResize(input_params, max_params); + ArrayResize(input_params, (int)max_params); } void SetName(string _name) { name = _name; }; void SetShift(int _shift) { shift = _shift; } diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq5 b/Indicators/Account/tests/Indi_AccountStats.test.mq5 index 9f72f4356..ffb2666f3 100644 --- a/Indicators/Account/tests/Indi_AccountStats.test.mq5 +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq5 @@ -58,4 +58,4 @@ void OnTick() { assertTrueOrExit(_entry.IsValid(), "Invalid entry!"); } } -} \ No newline at end of file +} diff --git a/Matrix.matmul.cl b/Matrix.matmul.cl new file mode 100644 index 000000000..e718259f1 --- /dev/null +++ b/Matrix.matmul.cl @@ -0,0 +1,115 @@ +#define WIDTH 1 +#define TSM 128 // The tile-size in dimension M +#define TSN 128 // The tile-size in dimension N +#define TSK 16 // The tile-size in dimension K +#define WPTM 8 // The work-per-thread in dimension M +#define WPTN 8 // The work-per-thread in dimension N +#define RTSM (TSM/WPTM) // The reduced tile-size in dimension M +#define RTSN (TSN/WPTN) // The reduced tile-size in dimension N +#define LPTA ((TSK*TSM)/(RTSM*RTSN)) // Loads-per-thread for A +#define LPTB ((TSK*TSN)/(RTSM*RTSN)) // Loads-per-thread for B +__kernel void matmul(const int M, const int N, const int K, + const __global double* A, + const __global double* B, + __global float* C) { + + // Thread identifiers + const int tidm = get_local_id(0); // Local row ID (max: TSM/WPTM) + const int tidn = get_local_id(1); // Local col ID (max: TSN/WPTN) + const int offsetM = TSM*get_group_id(0); // Work-group offset + const int offsetN = TSN*get_group_id(1); // Work-group offset + + // Local memory to fit a tile of A and B + __local float Asub[TSK][TSM]; + __local float Bsub[TSK][TSN]; + + // Allocate register space + float Areg; + float Breg[WPTN]; + float acc[WPTM][WPTN]; + + // Initialise the accumulation registers + for (int wm=0; wm @@ -31,6 +33,11 @@ #endif #include "Math.h" +#include "OpenCL.h" + +#resource "Matrix.matmul.cl" as string CLSource_Matrix_MatMul +#resource "Matrix.matmul.naive.cl" as string CLSource_Matrix_MatMul_Naive +#resource "Matrix.matmul.test.cl" as string CLSource_Matrix_MatMul_Test #define MATRIX_DIMENSIONS 6 #define MATRIX_VALUES_ARRAY_INCREMENT 500 @@ -157,6 +164,7 @@ struct MatrixDimensionAccessor { if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { \ Print("Error: Trying to use matrix", ptr_matrix.Repr(), \ "'s value operator " #OP " in a dimension which doesn't contain values!"); \ + DebugBreak(); \ return; \ } \ \ @@ -174,6 +182,7 @@ struct MatrixDimensionAccessor { void operator=(X _value) { if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { Print("Error: Trying to set matrix", ptr_matrix.Repr(), "'s value in a dimension which doesn't contain values!"); + DebugBreak(); return; } @@ -186,6 +195,7 @@ struct MatrixDimensionAccessor { X Val() { if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { Print("Error: Trying to get value from matrix", ptr_matrix.Repr(), "'s dimension which doesn't contain values!"); + DebugBreak(); return (X)EMPTY_VALUE; } @@ -199,6 +209,7 @@ struct MatrixDimensionAccessor { X ValOrZero() { if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { Print("Error: Trying to get value from matrix", ptr_matrix.Repr(), "'s dimension which doesn't contain values!"); + DebugBreak(); return (X)EMPTY_VALUE; } @@ -632,7 +643,7 @@ class MatrixDimension { } /** - * Extracts dimensions's values to the given array. Used internally. + * Extracts dimensions' values to the given array. Used internally. */ void FillArray(X& array[], int& offset) { int i; @@ -719,6 +730,8 @@ class MatrixDimension { } }; +enum ENUM_MATRIX_FLAGS { MATRIX_FLAGS_NONE, MATRIX_FLAGS_USE_OPENCL }; + /** * Matrix class. */ @@ -728,6 +741,15 @@ class Matrix { // First/root dimension. MatrixDimension* ptr_first_dimension; +#ifdef MATRIX_USE_OPENCL + + // Map of data size -> CL buffer to be used e.g., by CL-based MatMul method. + static DictStruct> cl_buffers_in_0; + static DictStruct> cl_buffers_in_1; + static DictStruct> cl_buffers_out; + +#endif + // Array with declaration of items per matrix's dimension. int dimensions[MATRIX_DIMENSIONS]; @@ -737,10 +759,40 @@ class Matrix { // Number of matrix dimensions. int num_dimensions; + // Flags. + int flags; + + // Static counter, so each new matrix will have its own version. For new + // matrices new 32-bit range of versions are given and it should be more + // that enough. + static unsigned long version_counter; + + // Cache of previously flattened data. + ARRAY(X, flattened_cache); + + // Version of the data that was flattened. + unsigned long flattened_cache_version; + + // Version of the data stored in dimensions arrays. Incremented after each + // change to this matrix. + unsigned long version; + + // OpenCL program for multi-core MatMul. + static Ref cl_program_matmul; + + // OpenCL program for single-core MatMul. + static Ref cl_program_matmul_single; + /** * Constructor. */ - Matrix(string _data) { FromString(_data); } + Matrix(string _data) { + FromString(_data); +#ifdef MATRIX_USE_OPENCL + InitializeOpenCL(); +#endif + Initialize(); + } /** * Constructor. @@ -748,12 +800,22 @@ class Matrix { Matrix(const int num_1d = 0, const int num_2d = 0, const int num_3d = 0, const int num_4d = 0, const int num_5d = 0) { ptr_first_dimension = NULL; SetShape(num_1d, num_2d, num_3d, num_4d, num_5d); +#ifdef MATRIX_USE_OPENCL + InitializeOpenCL(); +#endif + Initialize(); } /** * Constructor. */ - Matrix(MatrixDimension* _dimension) : ptr_first_dimension(NULL) { Initialize(_dimension); } + Matrix(MatrixDimension* _dimension) : ptr_first_dimension(NULL) { + Initialize(_dimension); +#ifdef MATRIX_USE_OPENCL + InitializeOpenCL(); +#endif + Initialize(); + } /** * Copy constructor. @@ -764,6 +826,13 @@ class Matrix { } Initialize(_right.ptr_first_dimension.Clone()); +#ifdef MATRIX_USE_OPENCL + InitializeOpenCL(); +#endif + + // Note that we mark new matrix as unique one, even though we clone another + // matrix. + Initialize(); } /** @@ -773,7 +842,105 @@ class Matrix { private: Matrix(const Matrix* _right) {} + /** + * Initializes new or copy of another matrix. + */ + void Initialize() { + // Cache will have version lower that the data so matrix will be flattened in the first occasion. + flattened_cache_version = version_counter; + version = version_counter + 1; + + // Each new matrix will have its own 32-bit range of versions. + version_counter += UINT_MAX; + } + +#ifdef MATRIX_USE_OPENCL + + /** + * + */ + void InitializeOpenCL() { + if (cl_program_matmul.IsSet()) { + // Already initialized. + return; + } + + cl_program_matmul = OpenCL::Compile(CLSource_Matrix_MatMul_Naive, "matmul"); + + cl_program_matmul_single = OpenCL::Compile( + "#pragma OPENCL EXTENSION cl_khr_fp64 : enable" NL "__kernel void matmul(" NL "const int Mdim," NL + "const int Ndim," NL "const int Pdim," NL "__global float *A," NL "__global float *B," NL "__global float *C" NL + ")" NL "{" NL "int i, j, k;" NL "for (i=0; i _buffer; + + _buffer = cl_buffers_in_0.GetByKey(_size, _buffer); + + if (!_buffer.IsSet()) { + _buffer = new OpenCLBuffer(_size, CL_MEM_READ_ONLY); + cl_buffers_in_0.Set(_size, _buffer); + } + + return _buffer.Ptr(); + } + + /** + * Returns/allocs and returns buffer of the given size to be used in CL operations as second input parameter. + */ + static OpenCLBuffer* GetCLBufferInArg1(int _size) { + Ref _buffer; + + _buffer = cl_buffers_in_1.GetByKey(_size, _buffer); + + if (!_buffer.IsSet()) { + _buffer = new OpenCLBuffer(_size, CL_MEM_READ_ONLY); + cl_buffers_in_1.Set(_size, _buffer); + } + + return _buffer.Ptr(); + } + + /** + * Returns/allocs and returns buffer of the given size to be used in CL operations as output parameter. + */ + static OpenCLBuffer* GetCLBufferOutArg(int _size) { + Ref _buffer; + + _buffer = cl_buffers_out.GetByKey(_size, _buffer); + + if (!_buffer.IsSet()) { + _buffer = new OpenCLBuffer(_size, CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR); + cl_buffers_out.Set(_size, _buffer); + } + + return _buffer.Ptr(); + } + /** * Matrix initializer. */ @@ -799,12 +966,15 @@ class Matrix { break; } else { Print("Internal error: unknown dimension type!"); + DebugBreak(); } } num_dimensions = i; RecalculateSize(); + + Modified(); } void RecalculateSize() { @@ -892,12 +1062,14 @@ class Matrix { size *= dimensions[i]; } } + + Modified(); } /** * Returns length of the given dimension. */ - int GetRange(int _dimension) { + int GetRangeRaw(int _dimension) { if (_dimension >= MATRIX_DIMENSIONS) { Print("Matrix::GetRange(): Dimension should be between 0 and ", MATRIX_DIMENSIONS - 1, ". Got ", _dimension, "!"); return -1; @@ -906,10 +1078,26 @@ class Matrix { return dimensions[_dimension]; } + /** + * Returns length of the given dimension. In case that e.g., dimension 0 has values, dimension 1 will return range 1. + */ + int GetRange(int _dimension) { + if (_dimension < num_dimensions) { + return GetRangeRaw(_dimension); + } + + if (_dimension == num_dimensions) { + // Last dimension always contain values. + return 1; + } + + return 0; + } + /** * Returns total number of values the matrix contain of. */ - int GetSize() { return size; } + int GetSize() const { return size; } /** * Returns number of matrix dimensions. @@ -928,6 +1116,7 @@ class Matrix { int initial_container_size = ptr_first_dimension.DuplicateDimension(_level, _num); dimensions[_level] += _num * initial_container_size; RecalculateSize(); + Modified(); } /** @@ -1056,6 +1245,8 @@ class Matrix { } accessor = _value; + + Modified(); } /** @@ -1078,6 +1269,7 @@ class Matrix { void Add(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_ADD, value); + Modified(); } } @@ -1092,6 +1284,7 @@ class Matrix { void Sub(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_SUBTRACT, value); + Modified(); } } @@ -1106,6 +1299,7 @@ class Matrix { void Mul(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_MULTIPLY, value); + Modified(); } } @@ -1120,6 +1314,7 @@ class Matrix { void Div(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_DIVIDE, value); + Modified(); } } @@ -1129,6 +1324,7 @@ class Matrix { void Fill(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_FILL, value); + Modified(); } } @@ -1138,6 +1334,7 @@ class Matrix { void FillRandom(int _seed = -1) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_FILL_RANDOM, _seed); + Modified(); } } @@ -1147,6 +1344,7 @@ class Matrix { void FillRandom(X _start, X _end, int _seed = -1) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_FILL_RANDOM_RANGE, _start, _end, _seed); + Modified(); } } @@ -1156,6 +1354,7 @@ class Matrix { void FillPosAdd() { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_FILL_POS_ADD); + Modified(); } } @@ -1165,11 +1364,12 @@ class Matrix { void FillPosMul() { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_FILL_POS_MUL); + Modified(); } } /** - * Replaces existing matrix's values by random value from a given range. + * Calculates sum fo all matrix's values. */ X Sum() { X _out1 = 0, _out2; @@ -1217,9 +1417,13 @@ class Matrix { return MinOf((X)0); } + /** + * Performs power operation on all matrix's values. + */ void Power(X value) { if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_POWER, value); + Modified(); } } @@ -1247,6 +1451,11 @@ class Matrix { } static void MatMul(Matrix& source, Matrix& target, Matrix& output) { +#ifdef MATRIX_USE_OPENCL + MatMulCL(source, target, output); + return; +#endif + if (source.GetSize() != target.GetRange(1)) { Alert("Inconsistent size of matrices!"); } @@ -1262,8 +1471,61 @@ class Matrix { output[output_idx] += source[input_idx].Val() * target[output_idx][input_idx].Val(); } } + + output.Modified(); } +#ifdef MATRIX_USE_OPENCL + + /** + * Performs matrix multiplication via OpenCL. Note that MATRIX_USE_OPENCL must be defined in order matrix to use this + * method. + */ + static void MatMulCL(Matrix& _source, Matrix& _target, Matrix& _output) { + if (_source.GetRange(1) != _target.GetRange(0)) { + Alert("Inconsistent size of matrices!"); + } + + unsigned int _rows_a = _source.GetRange(0); + unsigned int _cols_a = _source.GetRange(1); + unsigned int _cols_b = _target.GetRange(1); + + // Reusable 0-offset. + static ARRAY(unsigned int, _global_work_offset) = {0U, 0U}; + + // Local work size (up to 8 x 8). + static ARRAY(unsigned int, _local_work_size) = {MathMin(_rows_a, 8U), MathMin(_cols_a, 8U)}; + + // Our global size could be greater that data. + ARRAY(unsigned int, _global_work_size) = { + (unsigned int)MathCeil((double)_rows_a / _local_work_size[0]) * _local_work_size[0], + (unsigned int)MathCeil((double)_cols_a / _local_work_size[1]) * _local_work_size[1], + }; + + _output.SetShape(_rows_a, _cols_b); + + cl_program_matmul REF_DEREF SetArg(0, _source, OPENCL_MATRIX_ARG_IN_1); + cl_program_matmul REF_DEREF SetArg(1, _target, OPENCL_MATRIX_ARG_IN_2); + cl_program_matmul REF_DEREF SetArg(2, _output, OPENCL_MATRIX_ARG_OUT); + cl_program_matmul REF_DEREF SetArg(3, (int)_rows_a); + cl_program_matmul REF_DEREF SetArg(4, (int)_cols_a); + cl_program_matmul REF_DEREF SetArg(5, (int)_cols_b); + + if (!cl_program_matmul REF_DEREF RunMany(2U, _global_work_offset, _global_work_size, _local_work_size)) { + Alert("Error: Could not run Matrix::MatMulCL() over OpenCL!"); + DebugBreak(); + } + + // Extracting data from + ARRAY(X, _out_data); + ArrayResize(_out_data, _rows_a * _cols_b); + cl_program_matmul REF_DEREF GetArgBuffer(2) PTR_DEREF Read(_out_data); + _output.SetShape(_rows_a, _cols_b); + _output.FillFromArray(_out_data); + } + +#endif + /** * Performs matrix multiplication. */ @@ -1273,6 +1535,15 @@ class Matrix { return output; } + /** + * Performs matrix multiplication. + */ + Matrix* MatMul(Matrix* target) { + Matrix* output = new Matrix(); + MatMul(this, target, output); + return output; + } + /** * Performs matrix multiplication. */ @@ -1306,6 +1577,7 @@ class Matrix { void operator+=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); + Modified(); } } @@ -1328,6 +1600,7 @@ class Matrix { void operator-=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); + Modified(); } } @@ -1350,6 +1623,7 @@ class Matrix { void operator*=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + Modified(); } } @@ -1372,6 +1646,7 @@ class Matrix { void operator/=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); + Modified(); } } @@ -1379,9 +1654,21 @@ class Matrix { * Fills array with all values from the matrix. */ void GetRawArray(X& array[]) { - ArrayResize(array, GetSize()); + if (flattened_cache_version == version) { + // No need to flatten again as our cache is up to date. + ArrayCopy(array, flattened_cache); + return; + } + + // Filling target array with flattened matrix data. int offset = 0; + ArrayResize(array, GetSize()); ptr_first_dimension.FillArray(array, offset); + + // Copying target array into our flattened data cache. + ArrayResize(flattened_cache, 0, 1024); + ArrayCopy(flattened_cache, array); + flattened_cache_version = version; } /** @@ -1433,6 +1720,8 @@ class Matrix { int offset = 0; ptr_first_dimension.FromArray(_array, offset); + + Modified(); } /** @@ -1440,17 +1729,24 @@ class Matrix { */ void FillTruncatedNormal(X _mean, X _stddev, int _seeds = -1) { Print("Matrix::FillTruncatedNormal() is not yet implemented!"); + Modified(); } /** * The Glorot normal initializer, also called Xavier normal initializer. */ - void FillGlorotNormal(int _seed = -1) { Print("Matrix::FillGlorotNormal() is not yet implemented!"); } + void FillGlorotNormal(int _seed = -1) { + Print("Matrix::FillGlorotNormal() is not yet implemented!"); + Modified(); + } /** * The Glorot uniform initializer, also called Xavier uniform initializer. */ - void FillGlorotUniform(int _seed = -1) { Print("Matrix::FillGlorotUniform() is not yet implemented!"); } + void FillGlorotUniform(int _seed = -1) { + Print("Matrix::FillGlorotUniform() is not yet implemented!"); + Modified(); + } /** * Initializer that generates the identity matrix. @@ -1473,7 +1769,10 @@ class Matrix { /** * Initializer that generates an orthogonal matrix. */ - void FillOrthogonal(X _gain, int _seed = -1) { Print("Matrix::FillOrthogonal() is not yet implemented!"); } + void FillOrthogonal(X _gain, int _seed = -1) { + Print("Matrix::FillOrthogonal() is not yet implemented!"); + Modified(); + } /** * Calculates absolute difference between this tensor and given one using optional weights tensor. @@ -1538,6 +1837,7 @@ class Matrix { void ReduceSimple(bool _only_last_dimension = true, ENUM_MATRIX_OPERATION _reduce_op = MATRIX_OPERATION_SUM) { if (ptr_first_dimension != NULL) { ptr_first_dimension.ReduceSimple(_only_last_dimension ? GetDimensions() - 1 : 0, _reduce_op); + Modified(); } } @@ -1553,6 +1853,7 @@ class Matrix { } RecalculateSize(); + Modified(); } /** @@ -1793,6 +2094,7 @@ class Matrix { int _out3; if (ptr_first_dimension) { ptr_first_dimension.Op(MATRIX_OPERATION_RELU, 0, 0, 0, _out1, _out2, _out3); + Modified(); } } @@ -1823,6 +2125,7 @@ class Matrix { } else { this[_1d][_2d][_3d][_4d][_5d] = value; } + Modified(); } Matrix* GetConv2d(int _in_channels, int _out_channels, int _krn_1d, int _krn_2d, @@ -2107,6 +2410,8 @@ class Matrix { Print("Matrix::ChunkOp(): Invalid operation ", EnumToString(_op), "!"); } + // Note: ChuckOp() does not modify the matrix. + return 0; } @@ -2262,4 +2567,36 @@ class Matrix { } }; +#ifdef MATRIX_USE_OPENCL + +#ifdef __MQL__ +template +static unsigned long Matrix::version_counter = 0UL; +template +static Ref Matrix::cl_program_matmul; +template +static Ref Matrix::cl_program_matmul_single; +template +static DictStruct> Matrix::cl_buffers_in_0; +template +static DictStruct> Matrix::cl_buffers_in_1; +template +static DictStruct> Matrix::cl_buffers_out; +#else +template +static unsigned long Matrix::version_counter = 0UL; +template +static Ref Matrix::cl_program_matmul; +template +static Ref Matrix::cl_program_matmul_single; +template +static DictStruct> Matrix::cl_buffers_in_0; +template +static DictStruct> Matrix::cl_buffers_in_1; +template +static DictStruct> Matrix::cl_buffers_out; +#endif + +#endif + #endif diff --git a/OpenCL.h b/OpenCL.h new file mode 100644 index 000000000..b6aa15303 --- /dev/null +++ b/OpenCL.h @@ -0,0 +1,404 @@ +#ifndef __MQL__ +#pragma once +#endif + +#include "DictStruct.mqh" + +// Defines. +#define OPENCL_PROGRAM_MAX_ARGS 8 + +// Forward declarations; +class OpenCLProgram; +template +class Matrix; + +// Type of the matrix passed as argument to the OpenCLProgram. +enum ENUM_OPENCL_MATRIX_ARG { OPENCL_MATRIX_ARG_IN_1, OPENCL_MATRIX_ARG_IN_2, OPENCL_MATRIX_ARG_OUT }; + +/** + * Memory buffer. + */ +class OpenCLBuffer : public Dynamic { + // Handle to memory buffer. + int buffer_handle; + + // Allocated buffer size. + int buffer_size; + + // Version of the data. The same one that was passed to the Write() method. + unsigned long version; + + public: + /** + * Constructor. + */ + OpenCLBuffer(int _size, unsigned int _flags = CL_MEM_READ_WRITE); + + /** + * Checks whether stored data version differs from the passed version. + */ + bool RequiresReupload(unsigned long _data_version) { return _data_version == ULONG_MAX || version != _data_version; } + + /** + * Writes/uploads data into buffer if needed. + */ + void Write(const ARRAY_REF(double, _arr), unsigned long _data_version = ULONG_MAX) { + if (ArraySize(_arr) > buffer_size) { + Alert("Array passed is too large for the allocated buffer. Tries to pass ", ArraySize(_arr), + " elements into buffer of size ", buffer_size, "."); + DebugBreak(); + return; + } + + if (!RequiresReupload(_data_version)) { + return; + } + + CLBufferWrite(buffer_handle, _arr); + + version = _data_version; + } + + /** + * Reads data from buffer. + */ + void Read(ARRAY_REF(double, _arr)) { + if (!ArrayIsDynamic(_arr) && ArraySize(_arr) < buffer_size) { + Alert("Array passed is too small to be the target. Buffer has size ", buffer_size, + " and you tried to read it into buffer of size ", ArraySize(_arr), "."); + DebugBreak(); + return; + } + ArrayResize(_arr, buffer_size); + CLBufferRead(buffer_handle, _arr); + } + + /** + * Returns buffer size in bytes. + */ + int GetSizeBytes() { return buffer_size * sizeof(double); } + + /** + * Returns buffer size in items. + */ + int GetSizeItems() { return buffer_size; } + + /** + * Returns data version. + */ + unsigned long GetVersion() { return version; } + + /** + * Returns handle to buffer. + */ + int GetHandle() { return buffer_handle; } + + /** + * Destructor. + */ + ~OpenCLBuffer() { + if (buffer_handle != INVALID_HANDLE) { + CLBufferFree(buffer_handle); + } + } +}; + +/** + * Single program (code) + kernel (function name) to be invoked. + */ +class OpenCLProgram : public Dynamic { + // Handle to program. + int program_handle; + + // Handle to kernel. + int kernel_handle; + + // Buffer handles previously passed as arguments. Used to check if buffer needs to be reuploaded. + int arg_handles[OPENCL_PROGRAM_MAX_ARGS]; + + // Version of argument data. Used to check if buffer needs to be reuploaded. + unsigned long arg_versions[OPENCL_PROGRAM_MAX_ARGS]; + + // Buffers passed as arguments. Note that we store weak references, so we + // need to check if buffer still exists. + WeakRef arg_buffers[OPENCL_PROGRAM_MAX_ARGS]; + + public: + /** + * Constructor. + */ + OpenCLProgram() : program_handle(INVALID_HANDLE), kernel_handle(INVALID_HANDLE) { + for (int i = 0; i < OPENCL_PROGRAM_MAX_ARGS; ++i) { + arg_handles[i] = INVALID_HANDLE; + arg_versions[i] = -1; + arg_buffers[i] = nullptr; + } + } + + /** + * Destructor. + */ + ~OpenCLProgram() { + if (kernel_handle != INVALID_HANDLE) { + CLKernelFree(kernel_handle); + } + + if (program_handle != INVALID_HANDLE) { + CLProgramFree(program_handle); + } + } + + /** + * Passes local memory size argument to the kernel. + */ + void SetArgLocalMem(int _index, unsigned long _mem_size) { CLSetKernelArgMemLocal(kernel_handle, _index, _mem_size); } + + /** + * Checks whether given argument requires reupload of the buffer into GPU. + */ + bool RequiresReupload(int _index, OpenCLBuffer* _buffer, unsigned long _data_version) { + return _buffer PTR_DEREF GetHandle() != arg_handles[_index] || _data_version != arg_versions[_index]; + } + + /** + * Passes argument to the kernel. Will not set kernel argument if not needed. + * + * Note that buffer reuploading is to be done via OpenCLBuffer::Write() in + * which you can pass version of your data, so no reupload will take place if + * your version isn't greater that the one already set in the buffer. + */ + void SetArg(int _index, double value) { CLSetKernelArg(kernel_handle, _index, value); } + void SetArg(int _index, int value) { CLSetKernelArg(kernel_handle, _index, value); } + + /** + * Passes argument to the kernel. Will not set kernel argument if not needed. + * + * Note that buffer reuploading is to be done via OpenCLBuffer::Write() in + * which you can pass version of your data, so no reupload will take place if + * your version isn't greater that the one already set in the buffer. + */ + void SetArg(int _index, OpenCLBuffer* _buffer, unsigned long _data_version) { + if (!RequiresReupload(_index, _buffer, _data_version)) { + // Buffer is already set via CLSetKernelArgMem() and argument's version + // is the same as _data_version. + return; + } + + CLSetKernelArgMem(kernel_handle, _index, _buffer PTR_DEREF GetHandle()); + + // Buffer will occupy argument slot. + arg_handles[_index] = _buffer PTR_DEREF GetHandle(); + + // Storing buffer version in the argument slot. + arg_versions[_index] = _buffer PTR_DEREF GetVersion(); + + // Storing pointer to the buffer as weak reference. + arg_buffers[_index] = _buffer; + } + + /** + * Returns buffer passed as argument. + */ + OpenCLBuffer* GetArgBuffer(int _index) { + if (!arg_buffers[_index].ObjectExists()) { + Alert("Error: Trying to retrieve buffer at argument index ", _index, + ", but the buffer was either not set or deleted."); + DebugBreak(); + } + + return arg_buffers[_index].Ptr(); + } + + /** + * Passes matrix argument to the kernel. Will not upload data if not needed. + * + * The idea is to retrieve existing buffer that matches matrix size and its + * purpose. If such buffer already exists in the same version in the argument + * slot then no reupload will take place. + */ + template + void SetArg(int _index, Matrix& _matrix, ENUM_OPENCL_MATRIX_ARG _matrix_type) { + unsigned long _matrix_data_version = _matrix.GetVersion(); + OpenCLBuffer* _buffer = nullptr; + + switch (_matrix_type) { + case OPENCL_MATRIX_ARG_IN_1: + _buffer = _matrix.GetCLBufferInArg0(_matrix.GetSize()); + break; + + case OPENCL_MATRIX_ARG_IN_2: + _buffer = _matrix.GetCLBufferInArg1(_matrix.GetSize()); + break; + + case OPENCL_MATRIX_ARG_OUT: + _buffer = _matrix.GetCLBufferOutArg(_matrix.GetSize()); + break; + } + + if (RequiresReupload(_index, _buffer, _matrix_data_version)) { + // Flattening matrix data in order to upload it into GPU. + double _flattened_data[]; + _matrix.GetRawArray(_flattened_data); + _buffer PTR_DEREF Write(_flattened_data); + SetArg(_index, _buffer, _matrix_data_version); + } + } + + /** + * Executes a single kernel. + */ + bool Run() { + if (!CLExecute(kernel_handle)) { + Alert("OpenCL error occured when tried to run kernel: ", GetLastError(), "!"); + return false; + } + + return true; + } + + /** + * Executes multiple kernels where work is subdivided among kernels. + */ + bool RunMany(unsigned int _dimension, const ARRAY_REF(unsigned int, _global_work_offset), + const ARRAY_REF(unsigned int, _global_work_size), const ARRAY_REF(unsigned int, _local_work_size)) { + if (!CLExecute(kernel_handle, _dimension, _global_work_offset, _global_work_size, _local_work_size)) { + Alert("OpenCL error occured when tried to run kernel: ", GetLastError(), "!"); + return false; + } + + return true; + } + + /** + * Returns handle to OpenCL program. + */ + int GetProgramHandle() { return program_handle; } + + /** + * Sets handle to OpenCL program. + */ + void SetProgramHandle(int _handle) { + if (program_handle != -1) { + Alert("Cannot change program handle!"); + DebugBreak(); + return; + } + program_handle = _handle; + } + + /** + * Returns handle to OpenCL kernel. + */ + int GetKernelHandle() { return kernel_handle; } + + /** + * Sets handle to OpenCL kernel. + */ + void SetKernelHandle(int _handle) { + if (kernel_handle != -1) { + Alert("Cannot change kernel handle!"); + DebugBreak(); + return; + } + kernel_handle = _handle; + } +}; + +/** + * Wrapper for OpenCL. + */ +class OpenCL { + // OpenCL handles. + static int context_handle; + + // OpenCL memory handles. + static int cl_mem_0, cl_mem_1, cl_mem_2; + + DictStruct> programs; + + public: + /** + * Initializes CL contexts. Called automatically by OpenCLLifetimeManager. + */ + static void Initialize() { + context_handle = CLContextCreate(); + if (context_handle == INVALID_HANDLE) { + Alert("Could not create OpenCL context. Error code: ", GetLastError(), "."); + DebugBreak(); + return; + } + } + + /** + * Frees CL contexts. Called automatically by OpenCLLifetimeManager. + */ + static void Deinitialize() { CLContextFree(context_handle); } + + /** + * Allocates memory to be later passed to OpenCLProgram. + */ + static OpenCLBuffer* Alloc(int _size, unsigned int _flags) { return new OpenCLBuffer(_size, _flags); } + + /** + * Compiles given program and returns its id or -1 in case of error. + */ + static OpenCLProgram* Compile(string _source, string _fn_name) { + OpenCLProgram* _program = new OpenCLProgram(); + + // Log of CLProgramCreate(). + string _compilation_log; + + _program PTR_DEREF SetProgramHandle(CLProgramCreate(context_handle, _source, _compilation_log)); + + if (_program PTR_DEREF GetProgramHandle() == INVALID_HANDLE) { + Alert("Could not create OpenCL program. Error code: ", GetLastError(), ". Compilation log: ", _compilation_log, + "."); + DebugBreak(); + return nullptr; + } + + _program PTR_DEREF SetKernelHandle(CLKernelCreate(_program PTR_DEREF GetProgramHandle(), _fn_name)); + + if (_program PTR_DEREF GetKernelHandle() == INVALID_HANDLE) { + Alert("Could not create OpenCL kernel. Error code: ", GetLastError(), "."); + DebugBreak(); + return nullptr; + } + + return _program; + } + + /** + * Returns handle to OpenCL context. + */ + static int GetContextHandle() { return context_handle; } +}; + +static int OpenCL::context_handle; + +/** + * Manages initialization and deinitialization of static variables for OpenCL class. + */ +class OpenCLLifetimeManager { + public: + OpenCLLifetimeManager() { OpenCL::Initialize(); } + + ~OpenCLLifetimeManager() { OpenCL::Deinitialize(); } +}; + +OpenCLLifetimeManager __opencl_lifetime_manager; + +/** + * OpenCLBuffer constructor. + */ +OpenCLBuffer::OpenCLBuffer(int _size, unsigned int _flags) { + buffer_handle = CLBufferCreate(OpenCL::GetContextHandle(), _size * sizeof(double), _flags); + if (buffer_handle == INVALID_HANDLE) { + Alert("Could not create OpenCL buffer. Error code: ", GetLastError(), "."); + DebugBreak(); + } + buffer_size = _size; + // Ensuring there won't be initial version clash when checking if buffer data + // need to be reuploaded. + version = ULONG_MAX; +} diff --git a/Std.h b/Std.h index 2ac13ea7a..7e59afd4c 100644 --- a/Std.h +++ b/Std.h @@ -93,9 +93,7 @@ * @usage * ARRAY_REF(, ) */ -#define ARRAY_TYPE(T) T[] #define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS -#define FIXED_ARRAY_REF(T, N, S) ARRAY_REF(T, N) #define CONST_ARRAY_REF(T, N) const N ARRAY_DECLARATION_BRACKETS @@ -119,9 +117,7 @@ * @usage * ARRAY_REF(, ) */ -#define ARRAY_TYPE(T) _cpp_array -#define ARRAY_REF(T, N) ARRAY_TYPE(T)& N -#define FIXED_ARRAY_REF(T, N, S) T(&N)[S] +#define ARRAY_REF(T, N) _cpp_array& N #define CONST_ARRAY_REF(T, N) const _cpp_array& N @@ -302,163 +298,3 @@ inline _NULL_VALUE::operator const std::string() const { #else #define NULL_VALUE NULL #endif - -/** - * Standarization of specifying ArraySetAsSeries for OnCalculate(). - * Automatically determines required ArraySetAsSeries for buffers on start and - * end of given code block that uses given buffers. - */ - -#define SET_BUFFER_AS_SERIES_FOR_TARGET(A) ArraySetAsSeries(A, false); - -#ifdef __MQL4__ -#define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, true); -#else -#define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, false); -#endif - -// Ensures that we do RELEASE_BUFFERx after ACQUIRE_BUFFERx. -struct AsSeriesReleaseEnsurer { - bool released; - int num_buffs; - AsSeriesReleaseEnsurer(int _num_buffs) : released(false), num_buffs(_num_buffs) {} - void done(int _num_buffs) { - if (_num_buffs != num_buffs) { -#ifdef __MQL__ - Alert("You have acquired ", num_buffs, " buffers via ACQUIRE_BUFFER", num_buffs, - "(), but now trying to release with mismatched RELEASE_BUFFER", _num_buffs, "()!"); - DebugBreak(); -#endif - } - - if (released) { -#ifdef __MQL__ - Alert("You have used RELEASE_BUFFER", num_buffs, "() again which is not required!"); - DebugBreak(); -#endif - } - - released = true; - } - ~AsSeriesReleaseEnsurer() { - if (!released) { -#ifdef __MQL__ - Alert("You have used ACQUIRE_BUFFER", num_buffs, "() but didn't release buffer(s) via RELEASE_BUFFER", num_buffs, - "() before returning from the scope!"); - DebugBreak(); -#endif - } - } -}; - -#define SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(NUM_BUFFS) \ - AsSeriesReleaseEnsurer _as_series_release_ensurer(NUM_BUFFS); -#define SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(NUM_BUFFS) _as_series_release_ensurer.done(NUM_BUFFS); - -// Acquiring buffer is preparing it to be used as in MQL5. -#define ACQUIRE_BUFFER1(A) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(1); -#define ACQUIRE_BUFFER2(A, B) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(2); -#define ACQUIRE_BUFFER3(A, B, C) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(3); -#define ACQUIRE_BUFFER4(A, B, C, D) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(4); -#define ACQUIRE_BUFFER5(A, B, C, D, E) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(5); -#define ACQUIRE_BUFFER6(A, B, C, D, E, F) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(6); -#define ACQUIRE_BUFFER7(A, B, C, D, E, F, G) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(G); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(7); -#define ACQUIRE_BUFFER8(A, B, C, D, E, F, G, H) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(G); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(H); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(8); - -// Releasing buffer is setting its AsSeries as the default in the host language. -#define RELEASE_BUFFER1(A) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(1); -#define RELEASE_BUFFER2(A, B) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(2); -#define RELEASE_BUFFER3(A, B, C) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(3); -#define RELEASE_BUFFER4(A, B, C, D) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(4); -#define RELEASE_BUFFER5(A, B, C, D, E) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(5); -#define RELEASE_BUFFER6(A, B, C, D, E, F) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ - SET_BUFFER_AS_SERIES_FOR_HOST(F); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(6); -#define RELEASE_BUFFER7(A, B, C, D, E, F, G) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ - SET_BUFFER_AS_SERIES_FOR_HOST(F); \ - SET_BUFFER_AS_SERIES_FOR_HOST(G); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(7); -#define RELEASE_BUFFER8(A, B, C, D, E, F, G, H) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ - SET_BUFFER_AS_SERIES_FOR_HOST(F); \ - SET_BUFFER_AS_SERIES_FOR_HOST(G); \ - SET_BUFFER_AS_SERIES_FOR_HOST(H); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(8); diff --git a/tests/MatrixTest.mq5 b/tests/MatrixTest.mq5 index 1462baec6..72af18d8c 100644 --- a/tests/MatrixTest.mq5 +++ b/tests/MatrixTest.mq5 @@ -595,30 +595,29 @@ int OnInit() { assertTrueOrFail(matrix_24_relu.ToString(false, 4) == "[0.0000,0.0000,0.0000,1.0000,2.0000]", "Matrix::Relu(): Invalid result!"); - Matrix matrix_26("[1, 2, 3]"); + Matrix matrix_26("[[1, 2, 3]]"); Matrix matrix_27( "[[1, 1, 1]" " [0, 1, 0]" " [0, 0, 2]]"); Matrix* ptr_matrix_27_matmul = matrix_26 ^ matrix_27; - - assertTrueOrFail(ptr_matrix_27_matmul.ToString(false, 2) == "[6.00,2.00,6.00]", + assertTrueOrFail(ptr_matrix_27_matmul.ToString(false, 2) == "[[1.00,3.00,7.00]]", "Matrix::operator=(MatrixDimension): Invalid result!"); - Matrix matrix_27_bias("[1, 0, 5]"); + Matrix matrix_27_bias("[[1, 0, 5]]"); Matrix* ptr_matrix_27_add = ptr_matrix_27_matmul + matrix_27_bias; - assertTrueOrFail(ptr_matrix_27_add.ToString(false, 0) == "[7,2,11]", "Matrix::operator+(Matrix): Invalid result!"); + assertTrueOrFail(ptr_matrix_27_add.ToString(false, 0) == "[[2,3,12]]", "Matrix::operator+(Matrix): Invalid result!"); Matrix* ptr_matrix_27_sub = ptr_matrix_27_matmul - matrix_27_bias; - assertTrueOrFail(ptr_matrix_27_sub.ToString(false, 0) == "[5,2,1]", "Matrix::operator+(Matrix): Invalid result!"); + assertTrueOrFail(ptr_matrix_27_sub.ToString(false, 0) == "[[0,3,2]]", "Matrix::operator+(Matrix): Invalid result!"); Matrix* ptr_matrix_27_mul = ptr_matrix_27_matmul * matrix_27_bias; - assertTrueOrFail(ptr_matrix_27_mul.ToString(false, 0) == "[6,0,30]", "Matrix::operator+(Matrix): Invalid result!"); + assertTrueOrFail(ptr_matrix_27_mul.ToString(false, 0) == "[[1,0,35]]", "Matrix::operator+(Matrix): Invalid result!"); - delete ptr_matrix_27_matmul; delete ptr_matrix_27_add; + delete ptr_matrix_27_matmul; delete ptr_matrix_27_sub; delete ptr_matrix_27_mul; diff --git a/tests/OpenCLTest.mq5 b/tests/OpenCLTest.mq5 new file mode 100644 index 000000000..65eb84a19 --- /dev/null +++ b/tests/OpenCLTest.mq5 @@ -0,0 +1,70 @@ +//+------------------------------------------------------------------+ +//| 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 + * Test functionality of Ticker class. + */ + +// Includes. +#include "../Matrix.mqh" +#include "../OpenCL.h" + +/** + * Implements initialization function. + */ +int OnInit() { + Ref program = + OpenCL::Compile("#pragma OPENCL EXTENSION cl_khr_fp64 : enable" NL + "__kernel void test(__global double *data) {" NL " data[0] = 5;" NL "}" NL, + + "test"); + + double result[] = {0}; + + Ref buffer = OpenCL::Alloc(1 /* 1 double */, CL_MEM_READ_WRITE); + + program REF_DEREF SetArg(0, buffer.Ptr(), ULONG_MAX); + + if (!program REF_DEREF Run()) { + Alert("Error running program!"); + } + + buffer REF_DEREF Read(result); + + Print("Output: ", result[0]); + + Matrix *in1, *in2, *out; + in1 = Matrix::CreateFromString("[[1,2,3], [4,5,6]]"); // 2 x 3 + Print("in1 shape: ", in1 PTR_DEREF GetRange(0), " x ", in1 PTR_DEREF GetRange(1)); + in2 = Matrix::CreateFromString("[[7,8,9,10,11], [11,12,13,14,16], [15,16,17,18,19]]"); // 3 x 5 + Print("in2 shape: ", in2 PTR_DEREF GetRange(0), " x ", in2 PTR_DEREF GetRange(1)); + out = in1 PTR_DEREF MatMul(in2); + Print("out shape: ", out PTR_DEREF GetRange(0), " x ", out PTR_DEREF GetRange(1)); + Print("out data: ", out PTR_DEREF ToString()); + + delete in1; + delete in2; + delete out; + + ExpertRemove(); + return (INIT_SUCCEEDED); +} From 6f4492ceb3185e1ca9e52545b41ee2e5a2dbe91d Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 2 May 2024 14:58:23 +0200 Subject: [PATCH 107/123] Refs #738. Matrix multiplication fallback for MT4. CPU version now uses new API for reading/writing directly to flat arrays. --- Matrix.mqh | 166 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 129 insertions(+), 37 deletions(-) diff --git a/Matrix.mqh b/Matrix.mqh index 5d36121e7..4aa2dce9e 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -24,7 +24,9 @@ #ifndef MATRIX_MQH #define MATRIX_MQH +#ifdef __MQL5__ #define MATRIX_USE_OPENCL +#endif #ifdef USE_MQL_MATH_STAT #ifdef __MQL5__ @@ -33,11 +35,14 @@ #endif #include "Math.h" + +#ifdef MATRIX_USE_OPENCL #include "OpenCL.h" #resource "Matrix.matmul.cl" as string CLSource_Matrix_MatMul #resource "Matrix.matmul.naive.cl" as string CLSource_Matrix_MatMul_Naive #resource "Matrix.matmul.test.cl" as string CLSource_Matrix_MatMul_Test +#endif // MATRIX_USE_OPENCL #define MATRIX_DIMENSIONS 6 #define MATRIX_VALUES_ARRAY_INCREMENT 500 @@ -748,7 +753,7 @@ class Matrix { static DictStruct> cl_buffers_in_1; static DictStruct> cl_buffers_out; -#endif +#endif // MATRIX_USE_OPENCL // Array with declaration of items per matrix's dimension. int dimensions[MATRIX_DIMENSIONS]; @@ -777,12 +782,16 @@ class Matrix { // change to this matrix. unsigned long version; +#ifdef MATRIX_USE_OPENCL + // OpenCL program for multi-core MatMul. static Ref cl_program_matmul; // OpenCL program for single-core MatMul. static Ref cl_program_matmul_single; +#endif // MATRIX_USE_OPENCL + /** * Constructor. */ @@ -857,7 +866,7 @@ class Matrix { #ifdef MATRIX_USE_OPENCL /** - * + * Initializes OpenCL programs. */ void InitializeOpenCL() { if (cl_program_matmul.IsSet()) { @@ -875,9 +884,57 @@ class Matrix { "matmul"); } -#endif +#endif // MATRIX_USE_OPENCL public: + /** + * Returns value from a flattened data cache (flattens data firstly if neccessary). + */ + X FlatRead(int _idx) { + FlattenMaybe(); + return flattened_cache[_idx]; + } + + /** + * Writes value into flattened data cache (creates/clears cache if needed). + */ + void FlatWrite(int _idx, X value) { + if (version > flattened_cache_version) { + // Matrix has new data. Updating flattened data cache. + GetRawArrayNoCache(flattened_cache); + flattened_cache_version = version; + } + + flattened_cache[_idx] = value; + ++flattened_cache_version; + } + + /** + * Initializes matrix from the flattened data cache. Used after FlatWrite() to apply changes. + */ + void FlatApply() { + if (version >= flattened_cache_version) { + return; + } + + unsigned long _new_version = flattened_cache_version; + + FillFromArray(flattened_cache); + + version = flattened_cache_version = _new_version; + } + + /** + * Will prepare flattened data cache if needed. + */ + void FlattenMaybe() { + if (flattened_cache_version >= version) { + return; + } + GetRawArrayNoCache(flattened_cache); + flattened_cache_version = version; + } + /** * Returns matrix's data version. */ @@ -893,6 +950,8 @@ class Matrix { */ void Modified() { ++version; } +#ifdef MATRIX_USE_OPENCL + /** * Returns/allocs and returns buffer of the given size to be used in CL operations as first input parameter. */ @@ -941,6 +1000,8 @@ class Matrix { return _buffer.Ptr(); } +#endif // MATRIX_USE_OPENCL + /** * Matrix initializer. */ @@ -1450,29 +1511,42 @@ class Matrix { return MinOf((X)0); } - static void MatMul(Matrix& source, Matrix& target, Matrix& output) { + /** + * Performs matrix multiplication on CPU or GPU. + */ + static void MatMul(Matrix& _source, Matrix& _target, Matrix& _output) { #ifdef MATRIX_USE_OPENCL - MatMulCL(source, target, output); - return; + MatMulCL(_source, _target, _output); +#else + MatMulCPU(_source, _target, _output); #endif + } - if (source.GetSize() != target.GetRange(1)) { + /** + * Performs matrix multiplication on CPU. + */ + static void MatMulCPU(Matrix& _source, Matrix& _target, Matrix& _output) { + if (_source.GetSize() != _target.GetRange(1)) { Alert("Inconsistent size of matrices!"); } - int num_outputs = target.GetRange(0); - int num_inputs = target.GetRange(1); + int _rows_a = _source.GetRange(0); + int _cols_a = _source.GetRange(1); + int _cols_b = _target.GetRange(1); - output.SetShape(num_outputs); + _output.SetShape(_rows_a, _cols_b); - for (int output_idx = 0; output_idx < num_outputs; ++output_idx) { - output[output_idx] = 0; - for (int input_idx = 0; input_idx < num_inputs; ++input_idx) { - output[output_idx] += source[input_idx].Val() * target[output_idx][input_idx].Val(); + for (int i = 0; i < _rows_a; i++) { + for (int j = 0; j < _cols_b; j++) { + double sum = 0.0; + for (int k = 0; k < _cols_a; k++) { + sum += _source.FlatRead(i * _cols_a + k) * _target.FlatRead(k * _cols_b + j); + } + _output.FlatWrite(i * _cols_b + j, sum); } } - output.Modified(); + _output.FlatApply(); } #ifdef MATRIX_USE_OPENCL @@ -1650,6 +1724,16 @@ class Matrix { } } + /** + * Fills array with all values from the matrix. + */ + void GetRawArrayNoCache(X& array[]) { + // Filling target array with flattened matrix data. + int offset = 0; + ArrayResize(array, GetSize()); + ptr_first_dimension.FillArray(array, offset); + } + /** * Fills array with all values from the matrix. */ @@ -1660,10 +1744,7 @@ class Matrix { return; } - // Filling target array with flattened matrix data. - int offset = 0; - ArrayResize(array, GetSize()); - ptr_first_dimension.FillArray(array, offset); + GetRawArrayNoCache(array); // Copying target array into our flattened data cache. ArrayResize(flattened_cache, 0, 1024); @@ -1712,6 +1793,9 @@ class Matrix { } #endif + /** + * Fills matrix with the flattened data. Also fill flattened data cache. + */ void FillFromArray(X& _array[]) { if (ArraySize(_array) != GetSize()) { Print("Matrix::FillFromArray(): input array (", ArraySize(_array), " elements) must be the same size as matrix (", @@ -1720,8 +1804,12 @@ class Matrix { int offset = 0; ptr_first_dimension.FromArray(_array, offset); - Modified(); + + // We also fill flattened data cache. + ArrayResize(flattened_cache, ArraySize(_array)); + ArrayCopy(flattened_cache, _array); + flattened_cache_version = version; } /** @@ -2567,36 +2655,40 @@ class Matrix { } }; +#ifdef __MQL__ +template +unsigned long Matrix::version_counter = 0; +#else +template +unsigned long Matrix::version_counter = 0; +#endif // __MQL__ + #ifdef MATRIX_USE_OPENCL #ifdef __MQL__ template -static unsigned long Matrix::version_counter = 0UL; -template -static Ref Matrix::cl_program_matmul; +Ref Matrix::cl_program_matmul; template -static Ref Matrix::cl_program_matmul_single; +Ref Matrix::cl_program_matmul_single; template -static DictStruct> Matrix::cl_buffers_in_0; +DictStruct> Matrix::cl_buffers_in_0; template -static DictStruct> Matrix::cl_buffers_in_1; +DictStruct> Matrix::cl_buffers_in_1; template -static DictStruct> Matrix::cl_buffers_out; +DictStruct> Matrix::cl_buffers_out; #else template -static unsigned long Matrix::version_counter = 0UL; +Ref Matrix::cl_program_matmul; template -static Ref Matrix::cl_program_matmul; +Ref Matrix::cl_program_matmul_single; template -static Ref Matrix::cl_program_matmul_single; +DictStruct> Matrix::cl_buffers_in_0; template -static DictStruct> Matrix::cl_buffers_in_0; +DictStruct> Matrix::cl_buffers_in_1; template -static DictStruct> Matrix::cl_buffers_in_1; -template -static DictStruct> Matrix::cl_buffers_out; -#endif +DictStruct> Matrix::cl_buffers_out; +#endif // __MQL__ -#endif +#endif // MATRIX_USE_OPENCL -#endif +#endif // MATRIX_MQH From 4a8e93519ac1024ad6a9b2cae7fb6f5b774d8cb2 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 2 May 2024 14:58:23 +0200 Subject: [PATCH 108/123] Refs #738. Matrix multiplication fallback for MT4. CPU version now uses new API for reading/writing directly to flat arrays. --- .../Account/tests/Indi_AccountStats.test.mq4 | 4 +- Matrix.mqh | 166 ++++++++++++++---- 2 files changed, 131 insertions(+), 39 deletions(-) diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq4 b/Indicators/Account/tests/Indi_AccountStats.test.mq4 index 8356c50b5..d8a5e20cc 100644 --- a/Indicators/Account/tests/Indi_AccountStats.test.mq4 +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq4 @@ -21,7 +21,7 @@ /** * @file - * Test functionality of Indi_AC indicator class. + * Test functionality of Indi_AccountStats indicator class. */ -#include "Indi_AC.test.mq5" +#include "Indi_AccountStats.test.mq5" diff --git a/Matrix.mqh b/Matrix.mqh index 5d36121e7..4aa2dce9e 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -24,7 +24,9 @@ #ifndef MATRIX_MQH #define MATRIX_MQH +#ifdef __MQL5__ #define MATRIX_USE_OPENCL +#endif #ifdef USE_MQL_MATH_STAT #ifdef __MQL5__ @@ -33,11 +35,14 @@ #endif #include "Math.h" + +#ifdef MATRIX_USE_OPENCL #include "OpenCL.h" #resource "Matrix.matmul.cl" as string CLSource_Matrix_MatMul #resource "Matrix.matmul.naive.cl" as string CLSource_Matrix_MatMul_Naive #resource "Matrix.matmul.test.cl" as string CLSource_Matrix_MatMul_Test +#endif // MATRIX_USE_OPENCL #define MATRIX_DIMENSIONS 6 #define MATRIX_VALUES_ARRAY_INCREMENT 500 @@ -748,7 +753,7 @@ class Matrix { static DictStruct> cl_buffers_in_1; static DictStruct> cl_buffers_out; -#endif +#endif // MATRIX_USE_OPENCL // Array with declaration of items per matrix's dimension. int dimensions[MATRIX_DIMENSIONS]; @@ -777,12 +782,16 @@ class Matrix { // change to this matrix. unsigned long version; +#ifdef MATRIX_USE_OPENCL + // OpenCL program for multi-core MatMul. static Ref cl_program_matmul; // OpenCL program for single-core MatMul. static Ref cl_program_matmul_single; +#endif // MATRIX_USE_OPENCL + /** * Constructor. */ @@ -857,7 +866,7 @@ class Matrix { #ifdef MATRIX_USE_OPENCL /** - * + * Initializes OpenCL programs. */ void InitializeOpenCL() { if (cl_program_matmul.IsSet()) { @@ -875,9 +884,57 @@ class Matrix { "matmul"); } -#endif +#endif // MATRIX_USE_OPENCL public: + /** + * Returns value from a flattened data cache (flattens data firstly if neccessary). + */ + X FlatRead(int _idx) { + FlattenMaybe(); + return flattened_cache[_idx]; + } + + /** + * Writes value into flattened data cache (creates/clears cache if needed). + */ + void FlatWrite(int _idx, X value) { + if (version > flattened_cache_version) { + // Matrix has new data. Updating flattened data cache. + GetRawArrayNoCache(flattened_cache); + flattened_cache_version = version; + } + + flattened_cache[_idx] = value; + ++flattened_cache_version; + } + + /** + * Initializes matrix from the flattened data cache. Used after FlatWrite() to apply changes. + */ + void FlatApply() { + if (version >= flattened_cache_version) { + return; + } + + unsigned long _new_version = flattened_cache_version; + + FillFromArray(flattened_cache); + + version = flattened_cache_version = _new_version; + } + + /** + * Will prepare flattened data cache if needed. + */ + void FlattenMaybe() { + if (flattened_cache_version >= version) { + return; + } + GetRawArrayNoCache(flattened_cache); + flattened_cache_version = version; + } + /** * Returns matrix's data version. */ @@ -893,6 +950,8 @@ class Matrix { */ void Modified() { ++version; } +#ifdef MATRIX_USE_OPENCL + /** * Returns/allocs and returns buffer of the given size to be used in CL operations as first input parameter. */ @@ -941,6 +1000,8 @@ class Matrix { return _buffer.Ptr(); } +#endif // MATRIX_USE_OPENCL + /** * Matrix initializer. */ @@ -1450,29 +1511,42 @@ class Matrix { return MinOf((X)0); } - static void MatMul(Matrix& source, Matrix& target, Matrix& output) { + /** + * Performs matrix multiplication on CPU or GPU. + */ + static void MatMul(Matrix& _source, Matrix& _target, Matrix& _output) { #ifdef MATRIX_USE_OPENCL - MatMulCL(source, target, output); - return; + MatMulCL(_source, _target, _output); +#else + MatMulCPU(_source, _target, _output); #endif + } - if (source.GetSize() != target.GetRange(1)) { + /** + * Performs matrix multiplication on CPU. + */ + static void MatMulCPU(Matrix& _source, Matrix& _target, Matrix& _output) { + if (_source.GetSize() != _target.GetRange(1)) { Alert("Inconsistent size of matrices!"); } - int num_outputs = target.GetRange(0); - int num_inputs = target.GetRange(1); + int _rows_a = _source.GetRange(0); + int _cols_a = _source.GetRange(1); + int _cols_b = _target.GetRange(1); - output.SetShape(num_outputs); + _output.SetShape(_rows_a, _cols_b); - for (int output_idx = 0; output_idx < num_outputs; ++output_idx) { - output[output_idx] = 0; - for (int input_idx = 0; input_idx < num_inputs; ++input_idx) { - output[output_idx] += source[input_idx].Val() * target[output_idx][input_idx].Val(); + for (int i = 0; i < _rows_a; i++) { + for (int j = 0; j < _cols_b; j++) { + double sum = 0.0; + for (int k = 0; k < _cols_a; k++) { + sum += _source.FlatRead(i * _cols_a + k) * _target.FlatRead(k * _cols_b + j); + } + _output.FlatWrite(i * _cols_b + j, sum); } } - output.Modified(); + _output.FlatApply(); } #ifdef MATRIX_USE_OPENCL @@ -1650,6 +1724,16 @@ class Matrix { } } + /** + * Fills array with all values from the matrix. + */ + void GetRawArrayNoCache(X& array[]) { + // Filling target array with flattened matrix data. + int offset = 0; + ArrayResize(array, GetSize()); + ptr_first_dimension.FillArray(array, offset); + } + /** * Fills array with all values from the matrix. */ @@ -1660,10 +1744,7 @@ class Matrix { return; } - // Filling target array with flattened matrix data. - int offset = 0; - ArrayResize(array, GetSize()); - ptr_first_dimension.FillArray(array, offset); + GetRawArrayNoCache(array); // Copying target array into our flattened data cache. ArrayResize(flattened_cache, 0, 1024); @@ -1712,6 +1793,9 @@ class Matrix { } #endif + /** + * Fills matrix with the flattened data. Also fill flattened data cache. + */ void FillFromArray(X& _array[]) { if (ArraySize(_array) != GetSize()) { Print("Matrix::FillFromArray(): input array (", ArraySize(_array), " elements) must be the same size as matrix (", @@ -1720,8 +1804,12 @@ class Matrix { int offset = 0; ptr_first_dimension.FromArray(_array, offset); - Modified(); + + // We also fill flattened data cache. + ArrayResize(flattened_cache, ArraySize(_array)); + ArrayCopy(flattened_cache, _array); + flattened_cache_version = version; } /** @@ -2567,36 +2655,40 @@ class Matrix { } }; +#ifdef __MQL__ +template +unsigned long Matrix::version_counter = 0; +#else +template +unsigned long Matrix::version_counter = 0; +#endif // __MQL__ + #ifdef MATRIX_USE_OPENCL #ifdef __MQL__ template -static unsigned long Matrix::version_counter = 0UL; -template -static Ref Matrix::cl_program_matmul; +Ref Matrix::cl_program_matmul; template -static Ref Matrix::cl_program_matmul_single; +Ref Matrix::cl_program_matmul_single; template -static DictStruct> Matrix::cl_buffers_in_0; +DictStruct> Matrix::cl_buffers_in_0; template -static DictStruct> Matrix::cl_buffers_in_1; +DictStruct> Matrix::cl_buffers_in_1; template -static DictStruct> Matrix::cl_buffers_out; +DictStruct> Matrix::cl_buffers_out; #else template -static unsigned long Matrix::version_counter = 0UL; +Ref Matrix::cl_program_matmul; template -static Ref Matrix::cl_program_matmul; +Ref Matrix::cl_program_matmul_single; template -static Ref Matrix::cl_program_matmul_single; +DictStruct> Matrix::cl_buffers_in_0; template -static DictStruct> Matrix::cl_buffers_in_0; +DictStruct> Matrix::cl_buffers_in_1; template -static DictStruct> Matrix::cl_buffers_in_1; -template -static DictStruct> Matrix::cl_buffers_out; -#endif +DictStruct> Matrix::cl_buffers_out; +#endif // __MQL__ -#endif +#endif // MATRIX_USE_OPENCL -#endif +#endif // MATRIX_MQH From 82244e2fc04698ca58dcc7085203da2a8adcaecf Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 3 May 2024 15:18:37 +0100 Subject: [PATCH 109/123] Fixes Account.test.mq5, AccountForex.test.mq5 and Exchange.test.mq5 tests --- Account/AccountBase.h | 2 ++ Account/tests/Account.test.mq5 | 40 ++++++++++++++++++++++++++++- Account/tests/AccountForex.test.mq5 | 40 ++++++++++++++++++++++++++++- Exchange/tests/Exchange.test.mq5 | 38 ++++++++++++++++++++++++++- 4 files changed, 117 insertions(+), 3 deletions(-) diff --git a/Account/AccountBase.h b/Account/AccountBase.h index 5cb522e24..359d4c0ed 100644 --- a/Account/AccountBase.h +++ b/Account/AccountBase.h @@ -57,6 +57,8 @@ class AccountBase : public Dynamic { */ ~AccountBase() {} + /* Virtual methods */ + /** * Returns balance value of the current account. */ diff --git a/Account/tests/Account.test.mq5 b/Account/tests/Account.test.mq5 index 67b1ca128..286017e2c 100644 --- a/Account/tests/Account.test.mq5 +++ b/Account/tests/Account.test.mq5 @@ -28,12 +28,50 @@ #include "../../Test.mqh" #include "../Account.h" +// Test classes. +class AccountTest : public Account { + /** + * Returns balance value of the current account. + */ + float GetBalance() { return 0; } + + /** + * Returns credit value of the current account. + */ + float GetCredit() { return 0; } + + /** + * Returns profit value of the current account. + */ + float GetProfit() { return 0; } + + /** + * Returns equity value of the current account. + */ + float GetEquity() { return 0; } + + /** + * Returns margin value of the current account. + */ + float GetMarginUsed() { return 0; } + + /** + * Returns free margin value of the current account. + */ + float GetMarginFree() { return 0; } + + /** + * Get account available margin. + */ + float GetMarginAvail() { return 0; } +}; + /** * Implements OnInit(). */ int OnInit() { bool _result = true; - Account acc1; + AccountTest acc1; // ... return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; } diff --git a/Account/tests/AccountForex.test.mq5 b/Account/tests/AccountForex.test.mq5 index 350526aea..2e01162b8 100644 --- a/Account/tests/AccountForex.test.mq5 +++ b/Account/tests/AccountForex.test.mq5 @@ -28,12 +28,50 @@ #include "../../Test.mqh" #include "../AccountForex.h" +// Test classes. +class AccountForexTest : public Account { + /** + * Returns balance value of the current account. + */ + float GetBalance() { return 0; } + + /** + * Returns credit value of the current account. + */ + float GetCredit() { return 0; } + + /** + * Returns profit value of the current account. + */ + float GetProfit() { return 0; } + + /** + * Returns equity value of the current account. + */ + float GetEquity() { return 0; } + + /** + * Returns margin value of the current account. + */ + float GetMarginUsed() { return 0; } + + /** + * Returns free margin value of the current account. + */ + float GetMarginFree() { return 0; } + + /** + * Get account available margin. + */ + float GetMarginAvail() { return 0; } +}; + /** * Implements OnInit(). */ int OnInit() { bool _result = true; - Account acc1; + AccountForexTest acc1; // ... return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; } diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 index d3d289c61..498c0c791 100644 --- a/Exchange/tests/Exchange.test.mq5 +++ b/Exchange/tests/Exchange.test.mq5 @@ -30,7 +30,43 @@ #include "../Exchange.h" // Test classes. -class AccountDummy : public AccountBase {}; // +class AccountDummy : public AccountBase { + /** + * Returns balance value of the current account. + */ + float GetBalance() { return 0; } + + /** + * Returns credit value of the current account. + */ + float GetCredit() { return 0; } + + /** + * Returns profit value of the current account. + */ + float GetProfit() { return 0; } + + /** + * Returns equity value of the current account. + */ + float GetEquity() { return 0; } + + /** + * Returns margin value of the current account. + */ + float GetMarginUsed() { return 0; } + + /** + * Returns free margin value of the current account. + */ + float GetMarginFree() { return 0; } + + /** + * Get account available margin. + */ + float GetMarginAvail() { return 0; } +}; + class ExchangeDummy : public Exchange {}; class SymbolDummy : public SymbolInfo {}; class TradeDummy : public Trade { From 8095e1105e13777f2172d67b8a4b0296bfec45f4 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 6 May 2024 21:05:17 +0200 Subject: [PATCH 110/123] Refs #11. WIP. Making indicators to use Platform::OnCalculate(), Platform::Tick() and IndicatorData::EmitHistory(). --- IndicatorLegacy.h | 6 +++++- Platform.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/IndicatorLegacy.h b/IndicatorLegacy.h index 471e84676..696b37f36 100644 --- a/IndicatorLegacy.h +++ b/IndicatorLegacy.h @@ -23,6 +23,7 @@ #ifdef __MQL4__ #include +#include #include #include #include @@ -30,11 +31,14 @@ #ifdef INDICATOR_LEGACY_VERSION_MT5 /** - * Replacement for future OnCalculate(). Currently not used, but could be handy in the future. + * Replacement for future OnCalculate(). */ int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { + // We need to call Platform::Tick() and maybe also IndicatorData::EmitHistory() before. + Platform::OnCalculate(rates_total, prev_calculated); + int _num_calculated = OnCalculateMT5(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread); diff --git a/Platform.h b/Platform.h index 88ec23736..1188c2e56 100644 --- a/Platform.h +++ b/Platform.h @@ -52,6 +52,9 @@ class Platform { // Whether to clear passed periods on consecutive Platform::UpdateTime(). static bool time_clear_flags; + // Whether history for all the indicators was emitted. + static bool emitted_history; + // List of added indicators. static DictStruct> indis; @@ -96,6 +99,38 @@ class Platform { time_clear_flags = true; } + /** + * Called by indicators' OnCalculate() method in order to prepare history via + * IndicatorData::EmitHistory() and to call Tick() for each OnCalculate() + * call so Tick indicator can emit new tick and Candle indicator can update + * or add new candle data to be used by all indicators added to the platform + * via Platform::Add...(). + */ + static void OnCalculate(const int rates_total, const int prev_calculated) { + if (!emitted_history) { + for (DictStructIterator> _iter = indis.Begin(); _iter.IsValid(); ++_iter) { + EmitHistory(_iter.Value().Ptr()); + } + emitted_history = true; + } + + // We're ready for a tick. + Tick(); + } + + /** + * Emits history for parent indicators in hierarchy and then for the indicator itself. + */ + static void EmitHistory(IndicatorData *_indi) { + IndicatorData *_parent = _indi PTR_DEREF GetDataSource(false); + + if (_parent != nullptr) { + EmitHistory(_parent); + } + + _indi PTR_DEREF EmitHistory(); + } + /** * Returns dictionary of added indicators (keyed by unique id). */ @@ -306,6 +341,7 @@ bool Platform::initialized = false; DateTime Platform::time = 0; unsigned int Platform::time_flags = 0; bool Platform::time_clear_flags = true; +bool Platform::emitted_history = false; DictStruct> Platform::indis; DictStruct> Platform::indis_dflt; @@ -340,3 +376,9 @@ DictStruct> Platform::indis_dflt; } #define TEST_INDICATOR_DEFAULT_BINDINGS(C) TEST_INDICATOR_DEFAULT_BINDINGS_PARAMS(C, ) + +// Auto-initializer for Platform class. +class PlatformAutoInitializer { + public: + PlatformAutoInitializer() { Platform::Init(); } +} _platform_auto_initializer; \ No newline at end of file From 6859c3a321e191639388b20bcc8a75c6a06dc0a7 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 6 May 2024 21:39:30 +0200 Subject: [PATCH 111/123] Fixed problem with casting string to ENUM_LOG_LEVEL via indicator params' Get() and Set() methods. Also fixed formatting of files. --- EA.mqh | 25 +++++++++++++------------ Exchange/tests/Exchange.test.mq5 | 4 ++-- Log.mqh | 9 +++++++-- Strategy.mqh | 25 ++++++++++++------------- Trade.mqh | 15 ++++++++------- 5 files changed, 42 insertions(+), 36 deletions(-) diff --git a/EA.mqh b/EA.mqh index 3d7bdb6d4..16cccca33 100644 --- a/EA.mqh +++ b/EA.mqh @@ -30,8 +30,8 @@ #define EA_MQH // Includes. -#include "Chart.mqh" #include "./Chart.struct.static.h" +#include "Chart.mqh" #include "Data.struct.h" #include "Dict.mqh" #include "DictObject.mqh" @@ -114,12 +114,12 @@ class EA : public Taskable { Init(); // Initialize a trade instance for the current chart and symbol. Ref _source = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); - TradeParams _tparams(0, 1.0f, 0, eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + TradeParams _tparams(0, 1.0f, 0, (ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); 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))); - //_trade.GetLogger().SetLevel(eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + logger.SetLevel((ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + //_trade.GetLogger().SetLevel((ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); } /** @@ -409,11 +409,11 @@ class EA : public Taskable { _strat.OnOrderOpen(_oparams); // Send the request. _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 (!_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 (_trade.IsTradeRecommended()) { logger.Debug( StringFormat("Error while sending a trade request! Entry: %s", @@ -421,7 +421,8 @@ class EA : public Taskable { __FUNCTION_LINE__, StringFormat("Code: %d, Msg: %s", _LastError, Terminal::GetErrorText(_LastError))); } #ifdef __debug_ea__ - Print(__FUNCTION_LINE__ + "(): " + SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()); + Print(__FUNCTION_LINE__ + + "(): " + SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()); #endif } return _result; @@ -766,8 +767,8 @@ class EA : public Taskable { Ref _strat = ((SClass *)NULL).Init(_tf, THIS_PTR); _strat.Ptr().Set(STRAT_PARAM_ID, _magic_no); _strat.Ptr().Set(TRADE_PARAM_MAGIC_NO, _magic_no); - _strat.Ptr().Set(STRAT_PARAM_LOG_LEVEL, - eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + _strat.Ptr().Set(STRAT_PARAM_LOG_LEVEL, + (ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); _strat.Ptr().Set(STRAT_PARAM_TF, _tf); _strat.Ptr().Set(STRAT_PARAM_TYPE, _type); _strat.Ptr().OnInit(); diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 index 498c0c791..797c44274 100644 --- a/Exchange/tests/Exchange.test.mq5 +++ b/Exchange/tests/Exchange.test.mq5 @@ -96,8 +96,8 @@ bool TestExchange01() { exchange REF_DEREF SymbolAdd(symbol02.Ptr(), "Symbol02"); // Attach instances of dummy trades. - Ref trade01 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT)); - Ref trade02 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT)); + Ref trade01 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, Period())); + Ref trade02 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, Period())); exchange REF_DEREF TradeAdd(trade01.Ptr(), "Trade01"); exchange REF_DEREF TradeAdd(trade02.Ptr(), "Trade02"); diff --git a/Log.mqh b/Log.mqh index c55c526d6..13bc13fd4 100644 --- a/Log.mqh +++ b/Log.mqh @@ -76,8 +76,7 @@ class Log : public Object { /** * Class copy constructor. */ - Log(const Log &_log) : filename(_log.filename), last_entry(_log.last_entry), log_level(_log.log_level) { - } + Log(const Log &_log) : filename(_log.filename), last_entry(_log.last_entry), log_level(_log.log_level) {} /** * Class deconstructor. @@ -345,4 +344,10 @@ bool Log::AddLastError(string prefix, long suffix) { return Add(V_ERROR, Terminal::GetLastErrorText(), prefix, StringFormat("%d", suffix)); } +// Specialization of StringToType() for enum. +void StringToType(string _value, ENUM_LOG_LEVEL &_out) { + // Maybe parse the string? + _out = V_NONE; +} + #endif diff --git a/Strategy.mqh b/Strategy.mqh index 115b7660a..79ab81eba 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -668,7 +668,7 @@ class Strategy : public Taskable { virtual void OnInit() { // Link log instances. logger.Link(trade.Ptr().GetLogger()); - trade.Ptr().GetLogger().SetLevel(sparams.Get(STRAT_PARAM_LOG_LEVEL)); + trade.Ptr().GetLogger().SetLevel((ENUM_LOG_LEVEL)sparams.Get(STRAT_PARAM_LOG_LEVEL)); // Sets strategy stops. SetStops(THIS_PTR, THIS_PTR); // trade.SetStrategy(&this); // @fixme @@ -926,12 +926,12 @@ class Strategy : public Taskable { bool _result = true; if (_method != 0) { int _shift = _method / 64; - 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, 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)) @@ -1054,15 +1054,14 @@ 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 REF_DEREF HasBarOrder(_cmd, _shift); // 1 - if (METHOD(_method, 1)) _result |= _result || !IsTrend(_cmd); // 2 + 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 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 + _result |= _result || Open[_shift] > High[_shift + 1] || Open[_shift] < Low[_shift + 1]; // 8 + 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 |= diff --git a/Trade.mqh b/Trade.mqh index 4c4daf932..4ec0a0ec5 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -830,7 +830,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // @todo: _order.IsPending()? _result &= orders_active.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); logger.Link(_order.GetLogger()); - _order PTR_DEREF GetLogger().SetLevel(tparams.Get(TRADE_PARAM_LOG_LEVEL)); + _order PTR_DEREF GetLogger().SetLevel((ENUM_LOG_LEVEL)tparams.Get(TRADE_PARAM_LOG_LEVEL)); } else { _result &= orders_history.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); } @@ -894,11 +894,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.Error( - StringFormat("Failed to close the order: %d! Error: %d (%s)", _order REF_DEREF Get(ORDER_PROP_TICKET), - _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), - Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), - __FUNCTION_LINE__); + logger.Error(StringFormat("Failed to close the order: %d! Error: %d (%s)", + _order REF_DEREF Get(ORDER_PROP_TICKET), + _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), + Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), + __FUNCTION_LINE__); continue; } } else { @@ -932,7 +932,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. order_last = _order; } else { logger.Error( - StringFormat("Failed to close the order: %d! Error: %d (%s)", _order REF_DEREF Get(ORDER_PROP_TICKET), + StringFormat("Failed to close the order: %d! Error: %d (%s)", + _order REF_DEREF Get(ORDER_PROP_TICKET), _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), __FUNCTION_LINE__); From 36a2b12a8e185726e99cb502ebc3212e6e724a4b Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 6 May 2024 21:39:30 +0200 Subject: [PATCH 112/123] Fixed problem with casting string to ENUM_LOG_LEVEL via indicator params' Get() and Set() methods. Also fixed formatting of files. --- EA.mqh | 25 ++++++++++--------- Exchange/tests/Exchange.test.mq5 | 4 +-- .../Account/tests/Indi_AccountStats.test.mq5 | 2 +- Log.mqh | 9 +++++-- Strategy.mqh | 25 +++++++++---------- Trade.mqh | 15 +++++------ 6 files changed, 43 insertions(+), 37 deletions(-) diff --git a/EA.mqh b/EA.mqh index 3d7bdb6d4..16cccca33 100644 --- a/EA.mqh +++ b/EA.mqh @@ -30,8 +30,8 @@ #define EA_MQH // Includes. -#include "Chart.mqh" #include "./Chart.struct.static.h" +#include "Chart.mqh" #include "Data.struct.h" #include "Dict.mqh" #include "DictObject.mqh" @@ -114,12 +114,12 @@ class EA : public Taskable { Init(); // Initialize a trade instance for the current chart and symbol. Ref _source = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); - TradeParams _tparams(0, 1.0f, 0, eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + TradeParams _tparams(0, 1.0f, 0, (ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); 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))); - //_trade.GetLogger().SetLevel(eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + logger.SetLevel((ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + //_trade.GetLogger().SetLevel((ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); } /** @@ -409,11 +409,11 @@ class EA : public Taskable { _strat.OnOrderOpen(_oparams); // Send the request. _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 (!_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 (_trade.IsTradeRecommended()) { logger.Debug( StringFormat("Error while sending a trade request! Entry: %s", @@ -421,7 +421,8 @@ class EA : public Taskable { __FUNCTION_LINE__, StringFormat("Code: %d, Msg: %s", _LastError, Terminal::GetErrorText(_LastError))); } #ifdef __debug_ea__ - Print(__FUNCTION_LINE__ + "(): " + SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()); + Print(__FUNCTION_LINE__ + + "(): " + SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()); #endif } return _result; @@ -766,8 +767,8 @@ class EA : public Taskable { Ref _strat = ((SClass *)NULL).Init(_tf, THIS_PTR); _strat.Ptr().Set(STRAT_PARAM_ID, _magic_no); _strat.Ptr().Set(TRADE_PARAM_MAGIC_NO, _magic_no); - _strat.Ptr().Set(STRAT_PARAM_LOG_LEVEL, - eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + _strat.Ptr().Set(STRAT_PARAM_LOG_LEVEL, + (ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); _strat.Ptr().Set(STRAT_PARAM_TF, _tf); _strat.Ptr().Set(STRAT_PARAM_TYPE, _type); _strat.Ptr().OnInit(); diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 index 498c0c791..aff8fa3f9 100644 --- a/Exchange/tests/Exchange.test.mq5 +++ b/Exchange/tests/Exchange.test.mq5 @@ -96,8 +96,8 @@ bool TestExchange01() { exchange REF_DEREF SymbolAdd(symbol02.Ptr(), "Symbol02"); // Attach instances of dummy trades. - Ref trade01 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT)); - Ref trade02 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT)); + Ref trade01 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, (ENUM_TIMEFRAMES)Period())); + Ref trade02 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, (ENUM_TIMEFRAMES)Period())); exchange REF_DEREF TradeAdd(trade01.Ptr(), "Trade01"); exchange REF_DEREF TradeAdd(trade02.Ptr(), "Trade02"); diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq5 b/Indicators/Account/tests/Indi_AccountStats.test.mq5 index ffb2666f3..81bca2d2d 100644 --- a/Indicators/Account/tests/Indi_AccountStats.test.mq5 +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq5 @@ -39,7 +39,7 @@ int OnInit() { Platform::Init(); - Platform::AddWithDefaultBindings(indi_account_mt.Ptr()); + Platform::AddWithDefaultBindings(indi_account_mt.Ptr(), _Symbol, (ENUM_TIMEFRAMES)Period()); bool _result = true; assertTrueOrFail(indi_account_mt REF_DEREF IsValid(), "Error on IsValid!"); diff --git a/Log.mqh b/Log.mqh index c55c526d6..13bc13fd4 100644 --- a/Log.mqh +++ b/Log.mqh @@ -76,8 +76,7 @@ class Log : public Object { /** * Class copy constructor. */ - Log(const Log &_log) : filename(_log.filename), last_entry(_log.last_entry), log_level(_log.log_level) { - } + Log(const Log &_log) : filename(_log.filename), last_entry(_log.last_entry), log_level(_log.log_level) {} /** * Class deconstructor. @@ -345,4 +344,10 @@ bool Log::AddLastError(string prefix, long suffix) { return Add(V_ERROR, Terminal::GetLastErrorText(), prefix, StringFormat("%d", suffix)); } +// Specialization of StringToType() for enum. +void StringToType(string _value, ENUM_LOG_LEVEL &_out) { + // Maybe parse the string? + _out = V_NONE; +} + #endif diff --git a/Strategy.mqh b/Strategy.mqh index 115b7660a..79ab81eba 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -668,7 +668,7 @@ class Strategy : public Taskable { virtual void OnInit() { // Link log instances. logger.Link(trade.Ptr().GetLogger()); - trade.Ptr().GetLogger().SetLevel(sparams.Get(STRAT_PARAM_LOG_LEVEL)); + trade.Ptr().GetLogger().SetLevel((ENUM_LOG_LEVEL)sparams.Get(STRAT_PARAM_LOG_LEVEL)); // Sets strategy stops. SetStops(THIS_PTR, THIS_PTR); // trade.SetStrategy(&this); // @fixme @@ -926,12 +926,12 @@ class Strategy : public Taskable { bool _result = true; if (_method != 0) { int _shift = _method / 64; - 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, 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)) @@ -1054,15 +1054,14 @@ 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 REF_DEREF HasBarOrder(_cmd, _shift); // 1 - if (METHOD(_method, 1)) _result |= _result || !IsTrend(_cmd); // 2 + 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 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 + _result |= _result || Open[_shift] > High[_shift + 1] || Open[_shift] < Low[_shift + 1]; // 8 + 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 |= diff --git a/Trade.mqh b/Trade.mqh index 4c4daf932..4ec0a0ec5 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -830,7 +830,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // @todo: _order.IsPending()? _result &= orders_active.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); logger.Link(_order.GetLogger()); - _order PTR_DEREF GetLogger().SetLevel(tparams.Get(TRADE_PARAM_LOG_LEVEL)); + _order PTR_DEREF GetLogger().SetLevel((ENUM_LOG_LEVEL)tparams.Get(TRADE_PARAM_LOG_LEVEL)); } else { _result &= orders_history.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); } @@ -894,11 +894,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.Error( - StringFormat("Failed to close the order: %d! Error: %d (%s)", _order REF_DEREF Get(ORDER_PROP_TICKET), - _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), - Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), - __FUNCTION_LINE__); + logger.Error(StringFormat("Failed to close the order: %d! Error: %d (%s)", + _order REF_DEREF Get(ORDER_PROP_TICKET), + _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), + Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), + __FUNCTION_LINE__); continue; } } else { @@ -932,7 +932,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. order_last = _order; } else { logger.Error( - StringFormat("Failed to close the order: %d! Error: %d (%s)", _order REF_DEREF Get(ORDER_PROP_TICKET), + StringFormat("Failed to close the order: %d! Error: %d (%s)", + _order REF_DEREF Get(ORDER_PROP_TICKET), _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), __FUNCTION_LINE__); From 42ccf6a9cc6ca53fb64e8cf686234d703fa70ef6 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 17 May 2024 19:28:18 +0200 Subject: [PATCH 113/123] Legacy code for MT4. OnCalculate() automatic ticking, ArraySetAsSeries() for buffers and support for calling MT5 code from MT4. --- Indicator/IndicatorData.h | 7 +++ Indicator/IndicatorTf.provider.h | 5 +++ IndicatorLegacy.h | 44 ++++++++++++++++-- Indicators/Tick/Indi_TickMt.mqh | 76 ++++++++++++++++++++++++++++++-- 4 files changed, 126 insertions(+), 6 deletions(-) diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 4d69e8c41..29fde9ff6 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -1438,6 +1438,13 @@ class IndicatorData : public IndicatorBase { return false; } + /** + * Fetches historic ticks for a given index (absolute shift) range. + */ + virtual bool FetchHistoryByIndexRange(int _index_from, int _index_to, ARRAY_REF(TickTAB, _out_ticks)) { + return false; + } + /** * Fetches historic ticks for a given start time and minimum number of tick to retrieve. */ diff --git a/Indicator/IndicatorTf.provider.h b/Indicator/IndicatorTf.provider.h index 5197aaa73..63669b218 100644 --- a/Indicator/IndicatorTf.provider.h +++ b/Indicator/IndicatorTf.provider.h @@ -139,9 +139,14 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { long _candle_length_ms = (long)spc * 1000; long _ticks_to_ms = _ticks_from_ms + _candle_length_ms - 1; + // We will try to fetch history by two methods. + // 1. By time range if IndicatorTick supports that way. if (!_indi_tick PTR_DEREF FetchHistoryByTimeRange(_ticks_from_ms, _ticks_to_ms, _ticks)) { + // 2. By number of bars if IndicatorTick supports that way. + // if (!_indi_tick PTR_DEREF FetchHistoryByIndexRange(_ticks_from_index, _ticks_to_ms, _ticks))) { // There is no more ticks in the history, giving up. break; + //} } if (ArraySize(_ticks) > 0) { diff --git a/IndicatorLegacy.h b/IndicatorLegacy.h index f63c6347d..188d02fd7 100644 --- a/IndicatorLegacy.h +++ b/IndicatorLegacy.h @@ -23,28 +23,66 @@ #ifdef __MQL4__ #include +#include #include #include #include -#include + +#ifndef INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER +#define INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER +#endif + +#ifndef INDICATOR_LEGACY_VERSION_RELEASE_BUFFER +#define INDICATOR_LEGACY_VERSION_RELEASE_BUFFER +#endif #ifdef INDICATOR_LEGACY_VERSION_MT5 +#ifndef INDICATOR_LEGACY_VERSION_SHORT + /** - * Replacement for future OnCalculate(). + * Replacement for future OHLC-based OnCalculate(). */ int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { // We need to call Platform::Tick() and maybe also IndicatorData::EmitHistory() before. Platform::OnCalculate(rates_total, prev_calculated); - + + INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER; + int _num_calculated = OnCalculateMT5(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread); + INDICATOR_LEGACY_VERSION_RELEASE_BUFFER; + + return _num_calculated; +} + +#else + +/** + * Replacement for future price-based OnCalculate(). + */ +int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double& price[]) { + // We need to call Platform::Tick() and maybe also IndicatorData::EmitHistory() before. + Platform::OnCalculate(rates_total, prev_calculated); + + INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER; + + // NOTE: If compiler sees an error here about parameter conversion then you + // probably must do: + // #define INDICATOR_LEGACY_VERSION_SHORT + // before including IndicatorLegacy.h + int _num_calculated = OnCalculateMT5(rates_total, prev_calculated, begin, price); + + INDICATOR_LEGACY_VERSION_RELEASE_BUFFER; + return _num_calculated; } +#endif + #define OnCalculate OnCalculateMT5 /** diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 259d6712a..98e33a884 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -43,6 +43,12 @@ struct Indi_TickMtParams : IndicatorParams { // MT platform's tick-based indicator. class Indi_TickMt : public IndicatorTick> { + // Caching _to_ms in FetchHistoryByTimeRange() in order to start from last + // shift and don't loop over the same bars again. + long _cache_fetch_history_shift_to_ms; + // Shift to start with if given _to_ms is less that cached _cache_fetch_history_shift_to_ms. + long _cache_fetch_history_shift_shift; + public: Indi_TickMt(Indi_TickMtParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) @@ -61,7 +67,10 @@ class Indi_TickMt : public IndicatorTick, _out_ticks)) { ArrayResize(_out_ticks, 0); +#ifdef __MQL4__ + // Searching from current bar to older ones. + int _shift; + + if (_to_ms <= _cache_fetch_history_shift_to_ms) { + _shift = _cache_fetch_history_shift_shift; + } else { + _shift = 0; + } + + string _symbol = GetSymbol(); + + while (true) { + double _time = (double)iTime(_symbol, PERIOD_M1, _shift); + + if (_time == 0) { + // Invalid time. + break; + } + + long _time_ms = (long)_time * 1000; + + if (_time_ms > _to_ms) { + // No yet get into valid time range. + ++_shift; + continue; + } + + if (_time_ms < _from_ms) { + // No more ticks. + break; + } + + TickTAB _tick_o(_time_ms, iOpen(_Symbol, PERIOD_M1, _shift)); + TickTAB _tick_h(_time_ms, iHigh(_Symbol, PERIOD_M1, _shift)); + TickTAB _tick_l(_time_ms, iLow(_Symbol, PERIOD_M1, _shift)); + TickTAB _tick_c(_time_ms, iClose(_Symbol, PERIOD_M1, _shift)); + ArrayPushObject(_out_ticks, _tick_o); + ArrayPushObject(_out_ticks, _tick_h); + ArrayPushObject(_out_ticks, _tick_l); + ArrayPushObject(_out_ticks, _tick_c); + ++_shift; + } + + if (_shift != -1) { + _cache_fetch_history_shift_to_ms = _to_ms; + _cache_fetch_history_shift_shift = _shift; + } + + return ArraySize(_out_ticks) != 0; +#else static MqlTick _tmp_ticks[]; ArrayResize(_tmp_ticks, 0); - // There's no history in MQL4. -#ifndef __MQL4__ int _tries = 10; while (_tries > 0) { @@ -154,6 +212,18 @@ class Indi_TickMt : public IndicatorTick, _out_ticks)) { + return false; + } + + /** + * Sends historic entries to listening indicators. May be overriden. + */ + virtual void EmitHistory() {} + void OnTick(int _global_tick_index) override { #ifdef __MQL4__ // Refreshes Ask/Bid constants. From d8eb065e8be78fa2da05757a688a82a68e3965ed Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 22 May 2024 19:39:38 +0200 Subject: [PATCH 114/123] WIP. Trying to make indicators to work with historic ticks. Also changed .clang-format in order to indent macros. Changed Indi_Bands's OnCalculate param names in order to prevent warnings. --- .clang-format | 1 + Indicator/Indicator.h | 11 +- Indicator/IndicatorTf.provider.h | 8 +- IndicatorLegacy.h | 413 +++++++++++++++++------------- Indicators/Indi_Bands.mqh | 34 +-- Indicators/Indi_MA.mqh | 13 +- Indicators/Tick/Indi_TickMt.mqh | 24 +- Std.h | 426 +++++++++++++++++-------------- 8 files changed, 522 insertions(+), 408 deletions(-) diff --git a/.clang-format b/.clang-format index 3442bc765..d64b4533c 100644 --- a/.clang-format +++ b/.clang-format @@ -2,3 +2,4 @@ Language: Cpp BasedOnStyle: Google ColumnLimit: 120 +IndentPPDirectives: BeforeHash diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 53474ff19..ee68fe330 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -687,10 +687,13 @@ class Indicator : public IndicatorData { } if (_LastError != ERR_SUCCESS) { - datetime _bar_dt = (datetime)_bar_time; - Print("Error: Code ", _LastError, " while trying to retrieve entry at shift ", _rel_shift, " (absolute ", - ToAbsShift(_rel_shift), "), mode ", _mode, ", time ", _bar_dt); - DebugBreak(); + if (_LastError != 4806) { + // Error occured and it's not "4806 Requested data not found". + datetime _bar_dt = (datetime)_bar_time; + Print("Error: Code ", _LastError, " while trying to retrieve entry at shift ", _rel_shift, " (absolute ", + ToAbsShift(_rel_shift), "), mode ", _mode, ", time ", _bar_dt); + DebugBreak(); + } } } GetEntryAlter(_entry, _rel_shift); diff --git a/Indicator/IndicatorTf.provider.h b/Indicator/IndicatorTf.provider.h index 63669b218..3318b58da 100644 --- a/Indicator/IndicatorTf.provider.h +++ b/Indicator/IndicatorTf.provider.h @@ -25,8 +25,8 @@ #define INDICATOR_TF_PROVIDER_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif /** @@ -159,9 +159,11 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { // Adding candle to the output array. ArrayPushObject(_out_arr, _candle); - --_num_items; } + // Even if we don't form an item (a candle), we assume we've done one item. + --_num_items; + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { _from_time_ms += _candle_length_ms; } else { diff --git a/IndicatorLegacy.h b/IndicatorLegacy.h index 188d02fd7..31ee7226e 100644 --- a/IndicatorLegacy.h +++ b/IndicatorLegacy.h @@ -4,86 +4,138 @@ */ #ifndef __MQL__ -#pragma once + #pragma once #endif +// Includes. +#include "Platform.h" + #ifdef INDICATOR_LEGACY_VERSION_MT4 -#define INDICATOR_LEGACY_VERSION_DEFINED + #define INDICATOR_LEGACY_VERSION_DEFINED #endif #ifdef INDICATOR_LEGACY_VERSION_MT5 -#define INDICATOR_LEGACY_VERSION_DEFINED + #define INDICATOR_LEGACY_VERSION_DEFINED #endif -#ifndef INDICATOR_LEGACY_VERSION_DEFINED -#define INDICATOR_LEGACY_VERSION_MT5 -#define INDICATOR_LEGACY_VERSION_DEFINED +#ifdef INDICATOR_STANDALONE_VERSION_LONG + #define INDICATOR_STANDALONE_VERSION_DEFINED #endif -#ifdef __MQL4__ +#ifdef INDICATOR_STANDALONE_VERSION_SHORT + #define INDICATOR_STANDALONE_VERSION_DEFINED +#endif -#include -#include -#include -#include -#include +#ifdef INDICATOR_STANDALONE_VERSION_DEFINED + +/** + * Wrapper for future OnInit(). We may need to init indicator with candle and + * tick inidicator in the hierarchy. + */ +int OnInit() { + int _result = OnInitOriginal(); + Platform::AddWithDefaultBindings(INDICATOR_STANDALONE_INDI_PTR, Symbol(), (ENUM_TIMEFRAMES)Period()); + return _result; +} + + #define OnInit OnInitOriginal + + // In standalone mode without legacy mode we also need to wrap OnCalculate() as + // we need to call Platform::OnCalculate(). The only difference is that we + // don't need to change buffer's AsSeries flag in MT5. + #ifndef INDICATOR_LEGACY_VERSION_DEFINED + #ifndef INDICATOR_LEGACY_EMIT_ONCALCULATE_WRAPPER + #define INDICATOR_LEGACY_EMIT_ONCALCULATE_WRAPPER + #endif + + // No work required for buffers. + #define INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER + #define INDICATOR_LEGACY_VERSION_RELEASE_BUFFER + #ifdef INDICATOR_STANDALONE_VERSION_LONG + // We don't want to write two OnCalculate() wrappers. One is enough. + #define INDICATOR_LEGACY_VERSION_LONG + #endif // INDICATOR_STANDALONE_VERSION_LONG + #ifdef INDICATOR_STANDALONE_VERSION_SHORT + // We don't want to write two OnCalculate() wrappers. One is enough. + #define INDICATOR_LEGACY_VERSION_SHORT + #endif // INDICATOR_STANDALONE_VERSION_LONG + #endif // INDICATOR_LEGACY_VERSION_DEFINED + +#endif // INDICATOR_STANDALONE_VERSION_DEFINED #ifndef INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER -#define INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER + #define INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER #endif #ifndef INDICATOR_LEGACY_VERSION_RELEASE_BUFFER -#define INDICATOR_LEGACY_VERSION_RELEASE_BUFFER + #define INDICATOR_LEGACY_VERSION_RELEASE_BUFFER #endif -#ifdef INDICATOR_LEGACY_VERSION_MT5 +#ifdef INDICATOR_LEGACY_EMIT_ONCALCULATE_WRAPPER -#ifndef INDICATOR_LEGACY_VERSION_SHORT + #include + #include + #include + #include + #include + + #ifdef INDICATOR_LEGACY_VERSION_SHORT /** - * Replacement for future OHLC-based OnCalculate(). + * Wrapper for future price-based OnCalculate(). */ -int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], - const double& high[], const double& low[], const double& close[], const long& tick_volume[], - const long& volume[], const int& spread[]) { +int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double& price[]) { // We need to call Platform::Tick() and maybe also IndicatorData::EmitHistory() before. Platform::OnCalculate(rates_total, prev_calculated); INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER; - int _num_calculated = - OnCalculateMT5(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread); + // NOTE: If compiler sees an error here about 'time' parameter conversion + // then you probably must do: + // #define INDICATOR_LEGACY_VERSION_LONG + // before including IndicatorLegacy.h + int _num_calculated = OnCalculateMT5(rates_total, prev_calculated, begin, price); INDICATOR_LEGACY_VERSION_RELEASE_BUFFER; return _num_calculated; } -#else + #endif // INDICATOR_LEGACY_VERSION_SHORT + + #ifdef INDICATOR_LEGACY_VERSION_LONG /** - * Replacement for future price-based OnCalculate(). + * Wrapper for future OHLC-based OnCalculate(). */ -int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double& price[]) { +int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], + const double& high[], const double& low[], const double& close[], const long& tick_volume[], + const long& volume[], const int& spread[]) { // We need to call Platform::Tick() and maybe also IndicatorData::EmitHistory() before. Platform::OnCalculate(rates_total, prev_calculated); - INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER; - - // NOTE: If compiler sees an error here about parameter conversion then you - // probably must do: + // NOTE: If compiler sees an error here about parameter conversion + // then you probably must do: // #define INDICATOR_LEGACY_VERSION_SHORT // before including IndicatorLegacy.h - int _num_calculated = OnCalculateMT5(rates_total, prev_calculated, begin, price); + INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER; + + int _num_calculated = + OnCalculateMT5(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread); INDICATOR_LEGACY_VERSION_RELEASE_BUFFER; return _num_calculated; } -#endif + #endif // INDICATOR_LEGACY_VERSION_LONG -#define OnCalculate OnCalculateMT5 + #define OnCalculate OnCalculateMT5 + +#endif // INDICATOR_LEGACY_EMIT_ONCALCULATE_WRAPPER + +#ifdef __MQL4__ + #ifdef INDICATOR_LEGACY_VERSION_MT5 /** * Wrapper class to be used by MQL4 code to allow calling MQL5's indicator functions like iMA() in MQL4. @@ -188,10 +240,10 @@ int CopyBuffer(int _handle, int _mode, int _start, int _count, double& _buffer[] return _num_copied; } -/** - * Defines wrapper class and global iNAME() indicator function (e.g., iMA(), iATR()). - */ -// Print(#FN_NAME " key = ", _key); \ + /** + * Defines wrapper class and global iNAME() indicator function (e.g., iMA(), iATR()). + */ + // Print(#FN_NAME " key = ", _key); \ #define DEFINE_LEGACY_INDICATOR(FN_NAME, BUILTIN_NAME, TYPED_PARAMS_COMMA, TYPED_PARAMS_NO_UDL_SEMICOLON, UNTYPED_PARAMS_COMMA_KEY, UNTYPED_PARAMS_COMMA_VALUES, ASSIGNMENTS_COMMA, UNTYPED_PARAMS_NO_UDL_COMMA_VALUES) \ class BUILTIN_NAME##Legacy : public IndicatorLegacy { \ TYPED_PARAMS_NO_UDL_SEMICOLON; \ @@ -218,92 +270,95 @@ int FN_NAME(TYPED_PARAMS_COMMA) { \ return PTR_ATTRIB(_indi.Ptr(), GetHandle()); \ } -/** - * 1-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_1(FN_NAME, INDI_NAME, T1, N1) \ - DEFINE_LEGACY_INDICATOR(INDI_NAME, T1 _##N1, T1 N1, _##N1, _##N1, N1(_##N1), N1); - -/** - * 2-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_2(FN_NAME, INDI_NAME, T1, N1, T2, N2) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2, T1 N1 SEMICOLON T2 N2, _##N1 COMMA _##N2, \ - _##N1 COMMA _##N2, N1(_##N1) COMMA N2(_##N2), N1 COMMA N2); - -/** - * 3-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_3(FN_NAME, INDI_NAME, T1, N1, T2, N2, T3, N3) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3, _##N1 COMMA _##N2 COMMA _##N3, \ - _##N1 COMMA _##N2 COMMA _##N3, N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3), \ - N1 COMMA N2 COMMA N3); - -/** - * 4-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_4(FN_NAME, INDI_NAME) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, \ - N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4), N1 COMMA N2 COMMA N3 COMMA N4); - -/** - * 5-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_5(FN_NAME, INDI_NAME) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ - N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5), \ - N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5); - -/** - * 6-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_6(FN_NAME, INDI_NAME) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, \ - T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ - N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6), \ - N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6); - -/** - * 7-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_7(FN_NAME, INDI_NAME) \ - DEFINE_LEGACY_INDICATOR( \ - FN_NAME, INDI_NAME, \ - T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 _##N7, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 SEMICOLON T7 N7, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ - N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) COMMA N7(_##N7), \ - N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7); - -/** - * 8-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_8(FN_NAME, INDI_NAME) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, \ - T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 \ - _##N7 COMMA T8 _##N8, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 \ - SEMICOLON T7 N7 SEMICOLON T8 N8, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ - N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) \ - COMMA N7(_##N7) COMMA N8(_##N8), \ - N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7 COMMA N8); - -/** - * Replacement for future StringConcatenate(). - */ -#define StringConcatenate StringConcatenateMT5 + /** + * 1-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_1(FN_NAME, INDI_NAME, T1, N1) \ + DEFINE_LEGACY_INDICATOR(INDI_NAME, T1 _##N1, T1 N1, _##N1, _##N1, N1(_##N1), N1); + + /** + * 2-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_2(FN_NAME, INDI_NAME, T1, N1, T2, N2) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2, T1 N1 SEMICOLON T2 N2, _##N1 COMMA _##N2, \ + _##N1 COMMA _##N2, N1(_##N1) COMMA N2(_##N2), N1 COMMA N2); + + /** + * 3-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_3(FN_NAME, INDI_NAME, T1, N1, T2, N2, T3, N3) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3, _##N1 COMMA _##N2 COMMA _##N3, \ + _##N1 COMMA _##N2 COMMA _##N3, N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3), \ + N1 COMMA N2 COMMA N3); + + /** + * 4-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_4(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4), \ + N1 COMMA N2 COMMA N3 COMMA N4); + + /** + * 5-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_5(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5); + + /** + * 6-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_6(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR( \ + FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6); + + /** + * 7-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_7(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR( \ + FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 _##N7, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 SEMICOLON T7 N7, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) COMMA N7(_##N7), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7); + + /** + * 8-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_8(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR( \ + FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 _##N7 COMMA T8 \ + _##N8, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 SEMICOLON T7 N7 \ + SEMICOLON T8 N8, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) COMMA N7(_##N7) \ + COMMA N8(_##N8), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7 COMMA N8); + + /** + * Replacement for future StringConcatenate(). + */ + #define StringConcatenate StringConcatenateMT5 /** * MQL4 wrapper of MQL5's StringConcatenate(). @@ -395,66 +450,66 @@ DEFINE_LEGACY_INDICATOR_2(iAD, iAD, string, symbol, int, period); // int iATR(string symbol, ENUM_TIMEFRAMES period, int ma_period); DEFINE_LEGACY_INDICATOR_3(iATR, iATR, string, symbol, int, period, int, ma_period); -// int iRSI(string symbol, ENUM_TIMEFRAMES period, int ma_period, int applied_price); -#define T1 string -#define N1 symbol -#define T2 int -#define N2 period -#define T3 int -#define N3 ma_period -#define T4 int -#define N4 applied_price + // int iRSI(string symbol, ENUM_TIMEFRAMES period, int ma_period, int applied_price); + #define T1 string + #define N1 symbol + #define T2 int + #define N2 period + #define T3 int + #define N3 ma_period + #define T4 int + #define N4 applied_price DEFINE_LEGACY_INDICATOR_4(iRSI, iRSI) -#undef T1 -#undef N1 -#undef T2 -#undef N2 -#undef T3 -#undef N3 -#undef T4 -#undef N4 -#undef T5 -#undef N5 -#undef T6 -#undef N6 - -// int iMA(string symbol, ENUM_TIMEFRAMES period, int ma_period, int ma_shift, ENUM_MA_METHOD ma_method, -#define T1 string -#define N1 symbol -#define T2 int -#define N2 period -#define T3 int -#define N3 ma_period -#define T4 int -#define N4 ma_shift -#define T5 int -#define N5 ma_method -#define T6 int -#define N6 applied_price + #undef T1 + #undef N1 + #undef T2 + #undef N2 + #undef T3 + #undef N3 + #undef T4 + #undef N4 + #undef T5 + #undef N5 + #undef T6 + #undef N6 + + // int iMA(string symbol, ENUM_TIMEFRAMES period, int ma_period, int ma_shift, ENUM_MA_METHOD ma_method, + #define T1 string + #define N1 symbol + #define T2 int + #define N2 period + #define T3 int + #define N3 ma_period + #define T4 int + #define N4 ma_shift + #define T5 int + #define N5 ma_method + #define T6 int + #define N6 applied_price DEFINE_LEGACY_INDICATOR_6(iMA, iMA) -#undef T1 -#undef N1 -#undef T2 -#undef N2 -#undef T3 -#undef N3 -#undef T4 -#undef N4 -#undef T5 -#undef N5 -#undef T6 -#undef N6 - -#endif // INDICATOR_LEGACY_VERSION_MT5 -#endif // __MQL4__ + #undef T1 + #undef N1 + #undef T2 + #undef N2 + #undef T3 + #undef N3 + #undef T4 + #undef N4 + #undef T5 + #undef N5 + #undef T6 + #undef N6 + + #endif // INDICATOR_LEGACY_VERSION_MT5 +#endif // __MQL4__ #ifdef __MQL5__ -#ifdef INDICATOR_LEGACY_VERSION_MT4 + #ifdef INDICATOR_LEGACY_VERSION_MT4 -/** - * Replacement for future StringConcatenate(). - */ -#define StringConcatenate StringConcatenateMT4 + /** + * Replacement for future StringConcatenate(). + */ + #define StringConcatenate StringConcatenateMT4 /** * MQL5 wrapper of MQL4's StringConcatenate(). @@ -522,5 +577,5 @@ string StringConcatenateMT4(string& _result, A _a) { return (string)_a; } -#endif // INDICATOR_LEGACY_VERSION_MT4 -#endif // __MQL5__ + #endif // INDICATOR_LEGACY_VERSION_MT4 +#endif // __MQL5__ diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index 9300cb9c5..fcd390dbd 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -176,33 +176,33 @@ class Indi_Bands : public Indicator { /** * OnCalculate() method for Bands indicator. */ - static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &ExtMLBuffer, - ValueStorage &ExtTLBuffer, ValueStorage &ExtBLBuffer, - ValueStorage &ExtStdDevBuffer, int InpBandsPeriod, int InpBandsShift, - double InpBandsDeviations) { + static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &_ExtMLBuffer, + ValueStorage &_ExtTLBuffer, ValueStorage &_ExtBLBuffer, + ValueStorage &_ExtStdDevBuffer, int _InpBandsPeriod, int _InpBandsShift, + double _InpBandsDeviations) { int ExtBandsPeriod, ExtBandsShift; double ExtBandsDeviations; int ExtPlotBegin = 0; - if (InpBandsPeriod < 2) { + if (_InpBandsPeriod < 2) { ExtBandsPeriod = 20; PrintFormat("Incorrect value for input variable InpBandsPeriod=%d. Indicator will use value=%d for calculations.", - InpBandsPeriod, ExtBandsPeriod); + _InpBandsPeriod, ExtBandsPeriod); } else - ExtBandsPeriod = InpBandsPeriod; - if (InpBandsShift < 0) { + ExtBandsPeriod = _InpBandsPeriod; + if (_InpBandsShift < 0) { ExtBandsShift = 0; PrintFormat("Incorrect value for input variable InpBandsShift=%d. Indicator will use value=%d for calculations.", - InpBandsShift, ExtBandsShift); + _InpBandsShift, ExtBandsShift); } else - ExtBandsShift = InpBandsShift; - if (InpBandsDeviations == 0.0) { + ExtBandsShift = _InpBandsShift; + if (_InpBandsDeviations == 0.0) { ExtBandsDeviations = 2.0; PrintFormat( "Incorrect value for input variable InpBandsDeviations=%f. Indicator will use value=%f for calculations.", - InpBandsDeviations, ExtBandsDeviations); + _InpBandsDeviations, ExtBandsDeviations); } else - ExtBandsDeviations = InpBandsDeviations; + ExtBandsDeviations = _InpBandsDeviations; if (rates_total < ExtPlotBegin) return (0); //--- indexes draw begin settings, when we've recieved previous begin @@ -221,13 +221,13 @@ class Indi_Bands : public Indicator { //--- main cycle for (int i = pos; i < rates_total && !IsStopped(); i++) { //--- middle line - ExtMLBuffer[i] = Indi_MA::SimpleMA(i, ExtBandsPeriod, price); + _ExtMLBuffer[i] = Indi_MA::SimpleMA(i, ExtBandsPeriod, price); //--- calculate and write down StdDev - ExtStdDevBuffer[i] = StdDev_Func(i, price, ExtMLBuffer, ExtBandsPeriod); + _ExtStdDevBuffer[i] = StdDev_Func(i, price, _ExtMLBuffer, ExtBandsPeriod); //--- upper line - ExtTLBuffer[i] = ExtMLBuffer[i] + ExtBandsDeviations * ExtStdDevBuffer[i].Get(); + _ExtTLBuffer[i] = _ExtMLBuffer[i] + ExtBandsDeviations * _ExtStdDevBuffer[i].Get(); //--- lower line - ExtBLBuffer[i] = ExtMLBuffer[i] - ExtBandsDeviations * ExtStdDevBuffer[i].Get(); + _ExtBLBuffer[i] = _ExtMLBuffer[i] - ExtBandsDeviations * _ExtStdDevBuffer[i].Get(); } //--- OnCalculate done. Return new prev_calculated. return (rates_total); diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 1af92cd2e..051e8cd29 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -25,6 +25,8 @@ #define INDI_MA_MQH // Includes. +#include + #include "../Dict.mqh" #include "../DictObject.mqh" #include "../Indicator/Indicator.h" @@ -33,7 +35,14 @@ #include "../Storage/ValueStorage.h" #include "../String.mqh" -#ifndef __MQL4__ +#ifdef __MQL4__ +// MQL4 version of the method doesn't have last parameter. +int LinearWeightedMAOnBuffer(const int rates_total, const int prev_calculated, const int begin, const int period, + const double &price[], double &buffer[]) { + int _weight_sum; + return LinearWeightedMAOnBuffer(rates_total, prev_calculated, begin, period, price, buffer, _weight_sum); +} +#else // !__MQL__4 // Defines global functions (for MQL4 backward compability). double iMA(string _symbol, int _tf, int _ma_period, int _ma_shift, int _ma_method, int _ap, int _shift) { ResetLastError(); @@ -45,7 +54,7 @@ double iMAOnArray(double &_arr[], int _total, int _period, int _ma_shift, int _m ResetLastError(); return Indi_MA::iMAOnArray(_arr, _total, _period, _ma_shift, _ma_method, _abs_shift, _cache); } -#endif +#endif // __MQL4__ // Structs. struct IndiMAParams : IndicatorParams { diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 98e33a884..320c3f298 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -196,10 +196,10 @@ class Indi_TickMt : public IndicatorTick _tick(_tmp_ticks[i]); -#ifdef __debug_verbose__ + #ifdef __debug_verbose__ Print("Fetched tick at ", TimeToString(_tmp_ticks[i].time, TIME_DATE | TIME_MINUTES | TIME_SECONDS), ": ", _tmp_ticks[i].ask, ", ", _tmp_ticks[i].bid); -#endif + #endif ArrayPushObject(_out_ticks, _tick); } @@ -232,6 +232,9 @@ class Indi_TickMt : public IndicatorTick -#include -#include -#include + #include + #include + #include + #include #endif #ifndef __MQL__ -#define __FUNCSIG__ __FUNCTION__ + #define __FUNCSIG__ __FUNCTION__ #endif #ifdef __MQL__ -#define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE)this) = ((TYPE)VALUE) + #define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE)this) = ((TYPE)VALUE) #else -#define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE&)*this) = ((TYPE&)VALUE) + #define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE&)*this) = ((TYPE&)VALUE) #endif // Pointers. #ifdef __MQL__ -#define GET_PTR(obj) GetPointer(obj) -#define THIS_ATTR -#define THIS_PTR (&this) -#define THIS_REF this -#define PTR_DEREF . -#define PTR_ATTRIB(O, A) O.A -#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(). -#define int64 long + #define GET_PTR(obj) GetPointer(obj) + #define THIS_ATTR + #define THIS_PTR (&this) + #define THIS_REF this + #define PTR_DEREF . + #define PTR_ATTRIB(O, A) O.A + #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(). + #define int64 long #else -#define GET_PTR(obj) (*obj) -#define THIS_ATTR this-> -#define THIS_PTR (this) -#define THIS_REF (*this) -#define PTR_DEREF -> -#define PTR_ATTRIB(O, A) O->A -#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()-> -#define int64 long long + #define GET_PTR(obj) (*obj) + #define THIS_ATTR this-> + #define THIS_PTR (this) + #define THIS_REF (*this) + #define PTR_DEREF -> + #define PTR_ATTRIB(O, A) O->A + #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()-> + #define int64 long long #endif // References. #ifdef __cplusplus -#define REF(X) (&X) + #define REF(X) (&X) #else -#define REF(X) X& + #define REF(X) X& #endif // Arrays and references to arrays. #define _COMMA , #ifdef __MQL__ -#define ARRAY_DECLARATION_BRACKETS [] + #define ARRAY_DECLARATION_BRACKETS [] #else -// C++'s _cpp_array is an object, so no brackets are needed. -#define ARRAY_DECLARATION_BRACKETS + // C++'s _cpp_array is an object, so no brackets are needed. + #define ARRAY_DECLARATION_BRACKETS #endif #ifdef __MQL__ -/** - * Reference to object. - */ -#define CONST_REF_TO(T) const T + /** + * Reference to object. + */ + #define CONST_REF_TO(T) const T -/** - * Reference to the array. - * - * @usage - * ARRAY_REF(, ) - */ -#define ARRAY_TYPE(T) T[] -#define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS -#define FIXED_ARRAY_REF(T, N, S) ARRAY_REF(T, N) + /** + * Reference to the array. + * + * @usage + * ARRAY_REF(, ) + */ + #define ARRAY_TYPE(T) T[] + #define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS + #define FIXED_ARRAY_REF(T, N, S) ARRAY_REF(T, N) -#define CONST_ARRAY_REF(T, N) const N ARRAY_DECLARATION_BRACKETS + #define CONST_ARRAY_REF(T, N) const N ARRAY_DECLARATION_BRACKETS -/** - * Array definition. - * - * @usage - * ARRAY(, ) - */ -#define ARRAY(T, N) T N[] + /** + * Array definition. + * + * @usage + * ARRAY(, ) + */ + #define ARRAY(T, N) T N[] #else -/** - * Reference to object. - */ -#define CONST_REF_TO(T) const T& + /** + * Reference to object. + */ + #define CONST_REF_TO(T) const T& -/** + /** - * Reference to the array. - * - * @usage - * ARRAY_REF(, ) - */ -#define ARRAY_TYPE(T) _cpp_array -#define ARRAY_REF(T, N) ARRAY_TYPE(T)& N -#define FIXED_ARRAY_REF(T, N, S) T(&N)[S] + * Reference to the array. + * + * @usage + * ARRAY_REF(, ) + */ + #define ARRAY_TYPE(T) _cpp_array + #define ARRAY_REF(T, N) ARRAY_TYPE(T) & N + #define FIXED_ARRAY_REF(T, N, S) T(&N)[S] -#define CONST_ARRAY_REF(T, N) const _cpp_array& N + #define CONST_ARRAY_REF(T, N) const _cpp_array& N -/** - * Array definition. - * - * @usage - * ARRAY(, ) - */ -#define ARRAY(T, N) ::_cpp_array N + /** + * Array definition. + * + * @usage + * ARRAY(, ) + */ + #define ARRAY(T, N) ::_cpp_array N #endif // typename(T) #ifndef __MQL__ -#define typename(T) typeid(T).name() + #define typename(T) typeid(T).name() #endif // C++ array class. @@ -235,19 +235,19 @@ class _cpp_array { void setIsSeries(bool _isSeries) { m_isSeries = _isSeries; } }; -#ifdef EMSCRIPTEN -#include + #ifdef EMSCRIPTEN + #include -#define REGISTER_ARRAY_OF(N, T, D) \ - EMSCRIPTEN_BINDINGS(N) { \ - emscripten::register_vector(D "CppVector"); \ - emscripten::class_<_cpp_array>(D) \ - .constructor() \ - .function("Push", &_cpp_array::push) \ - .function("Size", &_cpp_array::size); \ - } + #define REGISTER_ARRAY_OF(N, T, D) \ + EMSCRIPTEN_BINDINGS(N) { \ + emscripten::register_vector(D "CppVector"); \ + emscripten::class_<_cpp_array>(D) \ + .constructor() \ + .function("Push", &_cpp_array::push) \ + .function("Size", &_cpp_array::size); \ + } -#endif + #endif template class _cpp_array; @@ -270,14 +270,14 @@ class color { // MQL defines. #ifndef __MQL__ -#define WHOLE_ARRAY -1 // For processing the entire array. + #define WHOLE_ARRAY -1 // For processing the entire array. #endif // Converts string into C++-style string pointer. #ifdef __MQL__ -#define C_STR(S) S + #define C_STR(S) S #else -#define C_STR(S) cstring_from(S) + #define C_STR(S) cstring_from(S) inline const char* cstring_from(const std::string& _value) { return _value.c_str(); } #endif @@ -295,19 +295,19 @@ inline bool IsNull(const string& str) { return str == ""; } * STRUCT_ENUM(, ) */ #ifdef __MQL4__ -#define STRUCT_ENUM(S, E) E + #define STRUCT_ENUM(S, E) E #else -#define STRUCT_ENUM(S, E) S::E + #define STRUCT_ENUM(S, E) S::E #endif #ifndef __MQL__ -// Additional enum values for ENUM_SYMBOL_INFO_DOUBLE -#define SYMBOL_MARGIN_LIMIT ((ENUM_SYMBOL_INFO_DOUBLE)46) -#define SYMBOL_MARGIN_MAINTENANCE ((ENUM_SYMBOL_INFO_DOUBLE)43) -#define SYMBOL_MARGIN_LONG ((ENUM_SYMBOL_INFO_DOUBLE)44) -#define SYMBOL_MARGIN_SHORT ((ENUM_SYMBOL_INFO_DOUBLE)45) -#define SYMBOL_MARGIN_STOP ((ENUM_SYMBOL_INFO_DOUBLE)47) -#define SYMBOL_MARGIN_STOPLIMIT ((ENUM_SYMBOL_INFO_DOUBLE)48) + // Additional enum values for ENUM_SYMBOL_INFO_DOUBLE + #define SYMBOL_MARGIN_LIMIT ((ENUM_SYMBOL_INFO_DOUBLE)46) + #define SYMBOL_MARGIN_MAINTENANCE ((ENUM_SYMBOL_INFO_DOUBLE)43) + #define SYMBOL_MARGIN_LONG ((ENUM_SYMBOL_INFO_DOUBLE)44) + #define SYMBOL_MARGIN_SHORT ((ENUM_SYMBOL_INFO_DOUBLE)45) + #define SYMBOL_MARGIN_STOP ((ENUM_SYMBOL_INFO_DOUBLE)47) + #define SYMBOL_MARGIN_STOPLIMIT ((ENUM_SYMBOL_INFO_DOUBLE)48) #endif template @@ -360,14 +360,14 @@ template <> _NULL_VALUE::operator string() const { return _empty_string; } -#define NULL_STRING "" + #define NULL_STRING "" #else -#define NULL_VALUE NULL -#define NULL_STRING NULL + #define NULL_VALUE NULL + #define NULL_STRING NULL #endif #ifndef __MQL__ -#include "Chart.enum.h" + #include "Chart.enum.h" /** * Returns currently selected period for platform. */ @@ -389,9 +389,9 @@ extern ENUM_TIMEFRAMES Period(); #define SET_BUFFER_AS_SERIES_FOR_TARGET(A) ArraySetAsSeries(A, false); #ifdef __MQL4__ -#define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, true); + #define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, true); #else -#define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, false); + #define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, false); #endif // Ensures that we do RELEASE_BUFFERx after ACQUIRE_BUFFERx. @@ -427,109 +427,141 @@ struct AsSeriesReleaseEnsurer { #define SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(NUM_BUFFS) _as_series_release_ensurer.done(NUM_BUFFS); // Acquiring buffer is preparing it to be used as in MQL5. -#define ACQUIRE_BUFFER1(A) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ +#define ACQUIRE_BUFFER1_NO_ENSURE(A) SET_BUFFER_AS_SERIES_FOR_TARGET(A); +#define ACQUIRE_BUFFER2_NO_ENSURE(A, B) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); +#define ACQUIRE_BUFFER3_NO_ENSURE(A, B, C) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); +#define ACQUIRE_BUFFER4_NO_ENSURE(A, B, C, D) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); +#define ACQUIRE_BUFFER5_NO_ENSURE(A, B, C, D, E) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); +#define ACQUIRE_BUFFER6_NO_ENSURE(A, B, C, D, E, F) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(F); +#define ACQUIRE_BUFFER7_NO_ENSURE(A, B, C, D, E, F, G) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(G); +#define ACQUIRE_BUFFER8_NO_ENSURE(A, B, C, D, E, F, G, H) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(G); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(H); + +#define ACQUIRE_BUFFER1(A) \ + ACQUIRE_BUFFER1_NO_ENSURE(A); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(1); -#define ACQUIRE_BUFFER2(A, B) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ +#define ACQUIRE_BUFFER2(A, B) \ + ACQUIRE_BUFFER2_NO_ENSURE(A, B); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(2); #define ACQUIRE_BUFFER3(A, B, C) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + ACQUIRE_BUFFER3_NO_ENSURE(A, B, C); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(3); -#define ACQUIRE_BUFFER4(A, B, C, D) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ +#define ACQUIRE_BUFFER4(A, B, C, D) \ + ACQUIRE_BUFFER4_NO_ENSURE(A, B, C, D); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(4); -#define ACQUIRE_BUFFER5(A, B, C, D, E) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ +#define ACQUIRE_BUFFER5(A, B, C, D, E) \ + ACQUIRE_BUFFER5_NO_ENSURE(A, B, C, D, E); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(5); -#define ACQUIRE_BUFFER6(A, B, C, D, E, F) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ +#define ACQUIRE_BUFFER6(A, B, C, D, E, F) \ + ACQUIRE_BUFFER6_NO_ENSURE(A, B, C, D, E, F); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(6); -#define ACQUIRE_BUFFER7(A, B, C, D, E, F, G) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(G); \ +#define ACQUIRE_BUFFER7(A, B, C, D, E, F, G) \ + ACQUIRE_BUFFER7_NO_ENSURE(A, B, C, D, E, F, G); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(7); -#define ACQUIRE_BUFFER8(A, B, C, D, E, F, G, H) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(G); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(H); \ +#define ACQUIRE_BUFFER8(A, B, C, D, E, F, G, H) \ + ACQUIRE_BUFFER8_NO_ENSURE(A, B, C, D, E, F, G, H); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(8); // Releasing buffer is setting its AsSeries as the default in the host language. -#define RELEASE_BUFFER1(A) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ +#define RELEASE_BUFFER1_NO_ENSURE(A) SET_BUFFER_AS_SERIES_FOR_HOST(A) +#define RELEASE_BUFFER2_NO_ENSURE(A, B) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); +#define RELEASE_BUFFER3_NO_ENSURE(A, B, C) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); +#define RELEASE_BUFFER4_NO_ENSURE(A, B, C, D) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); +#define RELEASE_BUFFER5_NO_ENSURE(A, B, C, D, E) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); +#define RELEASE_BUFFER6_NO_ENSURE(A, B, C, D, E, F) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); \ + SET_BUFFER_AS_SERIES_FOR_HOST(F); +#define RELEASE_BUFFER7_NO_ENSURE(A, B, C, D, E, F, G) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); \ + SET_BUFFER_AS_SERIES_FOR_HOST(F); \ + SET_BUFFER_AS_SERIES_FOR_HOST(G); +#define RELEASE_BUFFER8_NO_ENSURE(A, B, C, D, E, F, G, H) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); \ + SET_BUFFER_AS_SERIES_FOR_HOST(F); \ + SET_BUFFER_AS_SERIES_FOR_HOST(G); \ + SET_BUFFER_AS_SERIES_FOR_HOST(H); + +#define RELEASE_BUFFER1(A) \ + RELEASE_BUFFER1_NO_ENSURE(A); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(1); -#define RELEASE_BUFFER2(A, B) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ +#define RELEASE_BUFFER2(A, B) \ + RELEASE_BUFFER2_NO_ENSURE(A, B); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(2); -#define RELEASE_BUFFER3(A, B, C) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ +#define RELEASE_BUFFER3(A, B, C) \ + RELEASE_BUFFER3_NO_ENSURE(A, B, C); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(3); -#define RELEASE_BUFFER4(A, B, C, D) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ +#define RELEASE_BUFFER4(A, B, C, D) \ + RELEASE_BUFFER4_NO_ENSURE(A, B, C, D); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(4); -#define RELEASE_BUFFER5(A, B, C, D, E) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ +#define RELEASE_BUFFER5(A, B, C, D, E) \ + RELEASE_BUFFER5_NO_ENSURE(A, B, C, D, E); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(5); -#define RELEASE_BUFFER6(A, B, C, D, E, F) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ - SET_BUFFER_AS_SERIES_FOR_HOST(F); \ +#define RELEASE_BUFFER6(A, B, C, D, E, F) \ + RELEASE_BUFFER6_NO_ENSURE(A, B, C, D, E, F); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(6); -#define RELEASE_BUFFER7(A, B, C, D, E, F, G) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ - SET_BUFFER_AS_SERIES_FOR_HOST(F); \ - SET_BUFFER_AS_SERIES_FOR_HOST(G); \ +#define RELEASE_BUFFER7(A, B, C, D, E, F, G) \ + RELEASE_BUFFER7_NO_ENSURE(A, B, C, D, E, F, G); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(7); -#define RELEASE_BUFFER8(A, B, C, D, E, F, G, H) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ - SET_BUFFER_AS_SERIES_FOR_HOST(F); \ - SET_BUFFER_AS_SERIES_FOR_HOST(G); \ - SET_BUFFER_AS_SERIES_FOR_HOST(H); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(8); +#define RELEASE_BUFFER8(A, B, C, D, E, F, G, H) \ + RELEASE_BUFFER8_NO_ENSURE(A, B, C, D, E, F, G, H); \ + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(8); \ No newline at end of file From 92ee47a4326e7389bd01cff2a74825f13c73532f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 22 May 2024 19:39:38 +0200 Subject: [PATCH 115/123] WIP. Fixes In ItemsHistory and ItemsHistoryTfCandleProvider for Candle indicator and fixes in Indi_TickMt. Still requires work in the area where ticks are used to form candles. --- Candle.struct.h | 19 ++- Dict.enum.h | 8 +- DictBase.mqh | 39 ++++- DictStruct.mqh | 6 +- Indicator/IndicatorCandle.h | 25 +++- Indicator/IndicatorData.h | 32 +++- Indicator/IndicatorRenko.h | 148 ++++++++++--------- Indicator/IndicatorTf.provider.h | 18 ++- Indicator/tests/classes/IndicatorTfDummy.h | 14 +- Indicators/Account/Indi_AccountStats.mqh | 7 +- Indicators/Tick/Indi_TickMt.mqh | 162 ++++++++++++++------- Platform.h | 10 +- Storage/ItemsHistory.h | 18 ++- 13 files changed, 338 insertions(+), 168 deletions(-) diff --git a/Candle.struct.h b/Candle.struct.h index ebbe5b3ce..17b6f287d 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Forward class declaration. @@ -252,9 +252,12 @@ struct CandleOCTOHLC : CandleOHLC { } /** - * Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price. + * Initializes candle with a given start time, length in seconds, first tick's timestamp and its price. */ void Init(int _start_time, int _length, long _timestamp_ms = -1, T _price = 0) { + if (_start_time < 0) { + Print("Error!"); + } is_complete = false; start_time = _start_time; length = _length; @@ -269,7 +272,14 @@ struct CandleOCTOHLC : CandleOHLC { */ void Update(long _timestamp_ms, T _price) { if (!ContainsTimeMs(_timestamp_ms)) { - Print("Error: Cannot update candle. Given time doesn't fit in candle's time-frame!"); + Print("Error: Cannot update candle. Given time doesn't fit in candle's time-frame! Given time ", _timestamp_ms, + ", but candle range is ", (long)start_time * 1000, " - ", (long)(start_time + length) * 1000, "."); + if (_timestamp_ms < (long)start_time * 1000) { + Print("Looks like given time is ", (long)start_time * 1000 - _timestamp_ms, " ms before the candle starts."); + } else { + Print("Looks like given time is ", _timestamp_ms - (long)(start_time + length) * 1000, + " ms after the candle ends."); + } DebugBreak(); } @@ -277,6 +287,7 @@ struct CandleOCTOHLC : CandleOHLC { if (_is_init || _timestamp_ms < open_timestamp_ms) { open_timestamp_ms = _timestamp_ms; + start_time = int(_timestamp_ms / 1000); open = _price; } if (_is_init || _timestamp_ms > close_timestamp_ms) { diff --git a/Dict.enum.h b/Dict.enum.h index 99474def2..99618ba5b 100644 --- a/Dict.enum.h +++ b/Dict.enum.h @@ -26,12 +26,12 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif -#define DICT_GROW_UP_PERCENT_DEFAULT 25 -#define DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS 10 +#define DICT_GROW_UP_PERCENT_DEFAULT 50 +#define DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS 20 /** * Whether Dict operates in yet uknown mode, as dict or as list. diff --git a/DictBase.mqh b/DictBase.mqh index 269f9ddd2..9e3bbd95b 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -361,17 +361,50 @@ class DictBase { /** * Specialization of hashing function. */ - unsigned int Hash(unsigned int x) { return x; } + unsigned int Hash(float x) { return (unsigned int)((unsigned long)x * 10000 % 10000); } /** * Specialization of hashing function. */ - unsigned int Hash(int x) { return (unsigned int)x; } + unsigned int Hash(int value) { + value ^= (value >> 8); + value ^= (value << 3); + value ^= (value >> 9); + value ^= (value >> 4); + value ^= (value << 6); + value ^= (value >> 14); + return value; + } /** * Specialization of hashing function. */ - unsigned int Hash(float x) { return (unsigned int)((unsigned long)x * 10000 % 10000); } + unsigned int Hash(unsigned int value) { return Hash((int)value); } + + /** + * Specialization of hashing function. + */ + unsigned int Hash(long value) { + value ^= (value >> 33); + value ^= (value << 21); + value ^= (value >> 17); + + // Step 2: Combine upper and lower 32 bits to form a 32-bit hash + long hash = (int)(value ^ (value >> 32)); + + // Step 3: Further bit manipulation to spread the bits + hash ^= (hash >> 16); + hash *= 0x85ebca6b; // A large prime number + hash ^= (hash >> 13); + hash *= 0xc2b2ae35; // Another large prime number + hash ^= (hash >> 16); + return int(value >> 32); + } + + /** + * Specialization of hashing function. + */ + unsigned int Hash(unsigned long value) { return Hash((unsigned long)value); } }; #endif diff --git a/DictStruct.mqh b/DictStruct.mqh index b7bb1a173..97ee6ea1f 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -22,7 +22,7 @@ // Prevents processing this includes file for the second time. #ifndef __MQL__ -#pragma once + #pragma once #endif // Includes. @@ -433,7 +433,9 @@ class DictStruct : public DictBase { DictSlotsRef new_DictSlots; - if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) return false; + if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) { + return false; + } int i; diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index f8b7fdd0c..4efb3e3e1 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -25,8 +25,8 @@ #define INDICATOR_CANDLE_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -46,7 +46,7 @@ #include "TickBarCounter.h" #ifndef INDI_CANDLE_HISTORY_SIZE -#define INDI_CANDLE_HISTORY_SIZE 86400 + #define INDI_CANDLE_HISTORY_SIZE 86400 #endif // Indicator modes. @@ -368,7 +368,14 @@ class IndicatorCandle : public Indicator { /** * Called when data source emits new entry (new one in ascending order). */ - void OnDataSourceEntry(IndicatorDataEntry& entry) override { + void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + Indicator::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } + // Parent indicator (e.g., Indi_TickMt) emitted an entry containing tick's // ask and bid price. As an abstract class, we really don't know how to // update/create candles so we just pass the entry into history's @@ -376,6 +383,16 @@ class IndicatorCandle : public Indicator { history.GetItemProvider() PTR_DEREF OnTick(&history, entry.timestamp * 1000, (float)entry[0], (float)entry[1]); }; + /** + * Called when data source expects to emit given number of entries for given type. + * + * Called e.g., from Tick indicator in order Candle indicator to enlarge + * possible history size by given number of entries. We have to do that, + * because otherwise, we could end up with OnCalculate() working on partial + * history candles. + */ + void OnDataSourceWillEmitEntries(ENUM_INDI_EMITTED_ENTRY_TYPE _type, int _num_entries) override {} + /** * Returns value storage of given kind. */ diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 29fde9ff6..18e560613 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -25,8 +25,8 @@ #define INDICATOR_DATA_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Forward class declaration. @@ -1757,10 +1757,21 @@ class IndicatorData : public IndicatorBase { /** * Sends entry to listening indicators. */ - void EmitEntry(IndicatorDataEntry& entry) { + void EmitEntry(IndicatorDataEntry& _entry, ENUM_INDI_EMITTED_ENTRY_TYPE _type = INDI_EMITTED_ENTRY_TYPE_PARENT) { for (int i = 0; i < ArraySize(listeners); ++i) { if (listeners[i].ObjectExists()) { - listeners[i].Ptr().OnDataSourceEntry(entry); + listeners[i].Ptr().OnDataSourceEntry(_entry, _type); + } + } + } + + /** + * Sends information about expected number of emitted entries to listening indicators. + */ + void WillEmitEntries(ENUM_INDI_EMITTED_ENTRY_TYPE _type, int _num_entries) { + for (int i = 0; i < ArraySize(listeners); ++i) { + if (listeners[i].ObjectExists()) { + listeners[i].Ptr().OnDataSourceWillEmitEntries(_type, _num_entries); } } } @@ -1824,7 +1835,18 @@ class IndicatorData : public IndicatorBase { /** * Called when data source emits new entry (historic or future one). */ - virtual void OnDataSourceEntry(IndicatorDataEntry& entry){}; + virtual void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) {} + + /** + * Called when data source expects to emit given number of entries for given type. + * + * Called e.g., from Tick indicator in order Candle indicator to enlarge + * possible history size by given number of entries. We have to do that, + * because otherwise, we could end up with OnCalculate() working on partial + * history candles. + */ + virtual void OnDataSourceWillEmitEntries(ENUM_INDI_EMITTED_ENTRY_TYPE _type, int _num_entries) {} /** * Called when new tick is retrieved from attached data source. diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index df4a403da..be9888e3d 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -30,8 +30,8 @@ #define INDICATOR_RENKO_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -171,97 +171,103 @@ class IndicatorRenko : public IndicatorCandle>::OnDataSourceEntry(entry, type); - if (entry.timestamp < last_entry_ts) { - Print("Error: IndicatorRenko doesn't support sending entries in non-ascending order!"); - DebugBreak(); - } + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } + /* + @todo Move logic into ItemsHistoryRenkoCandleProvider class. - // We'll be updating candle from bid price. - double _price = entry[1]; + if (entry.timestamp < last_entry_ts) { + Print("Error: IndicatorRenko doesn't support sending entries in non-ascending order!"); + DebugBreak(); + } - CandleOCTOHLC _candle; - CandleOCTOHLC _last_completed_candle; - ENUM_INDI_RENKO_CANDLE_TYPE _last_completed_candle_type; + // We'll be updating candle from bid price. + double _price = entry[1]; - if (last_completed_candle_ts != 0) { - _last_completed_candle = icdata.GetByKey(last_completed_candle_ts); - _last_completed_candle_type = GetCandleType(_last_completed_candle); - } else { - _last_completed_candle_type = INDI_RENKO_CANDLE_TYPE_NONE; - } + CandleOCTOHLC _candle; + CandleOCTOHLC _last_completed_candle; + ENUM_INDI_RENKO_CANDLE_TYPE _last_completed_candle_type; - if (last_incomplete_candle_ts != 0) { - // There is previous candle. Retrieving and updating it. - _candle = icdata.GetByKey(last_incomplete_candle_ts); - _candle.Update(entry.timestamp, _price); + if (last_completed_candle_ts != 0) { + _last_completed_candle = icdata.GetByKey(last_completed_candle_ts); + _last_completed_candle_type = GetCandleType(_last_completed_candle); + } else { + _last_completed_candle_type = INDI_RENKO_CANDLE_TYPE_NONE; + } - // Checking for close price difference. - if (RenkoConditionMet(_last_completed_candle_type, _candle, _price)) { - // Closing current candle. - _candle.is_complete = true; - } + if (last_incomplete_candle_ts != 0) { + // There is previous candle. Retrieving and updating it. + _candle = icdata.GetByKey(last_incomplete_candle_ts); + _candle.Update(entry.timestamp, _price); + + // Checking for close price difference. + if (RenkoConditionMet(_last_completed_candle_type, _candle, _price)) { + // Closing current candle. + _candle.is_complete = true; + } - // Updating candle. - icdata.Add(_candle, last_incomplete_candle_ts); + // Updating candle. + icdata.Add(_candle, last_incomplete_candle_ts); - Print("Updated Candle: ", _candle.ToString()); + Print("Updated Candle: ", _candle.ToString()); - if (_candle.is_complete) { - last_completed_candle_ts = last_incomplete_candle_ts; - last_incomplete_candle_ts = 0; - } + if (_candle.is_complete) { + last_completed_candle_ts = last_incomplete_candle_ts; + last_incomplete_candle_ts = 0; + } + } else { + // There is no incomplete candle, creating one. + if (last_completed_candle_ts != 0) { + // Price of the last candle will be used to initialize open price for new, incomplete candle. + double _last_close_price = _last_completed_candle.close; + _candle = CandleOCTOHLC(_last_close_price, _last_close_price, _last_close_price, _last_close_price, + entry.timestamp, entry.timestamp); + // Current price will be added to newly created incomplete candle. + _candle.Update(entry.timestamp, _price); } else { - // There is no incomplete candle, creating one. - if (last_completed_candle_ts != 0) { - // Price of the last candle will be used to initialize open price for new, incomplete candle. - double _last_close_price = _last_completed_candle.close; - _candle = CandleOCTOHLC(_last_close_price, _last_close_price, _last_close_price, _last_close_price, - entry.timestamp, entry.timestamp); - // Current price will be added to newly created incomplete candle. - _candle.Update(entry.timestamp, _price); - } else { - // There was no completed candle. Creating new, incomplete candle from current price. - _candle = CandleOCTOHLC(_price, _price, _price, _price, entry.timestamp, entry.timestamp); - } + // There was no completed candle. Creating new, incomplete candle from current price. + _candle = CandleOCTOHLC(_price, _price, _price, _price, entry.timestamp, entry.timestamp); + } - _candle.is_complete = false; + _candle.is_complete = false; - // Creating new candle. - icdata.Add(_candle, entry.timestamp); + // Creating new candle. + icdata.Add(_candle, entry.timestamp); - Print("Added candle: ", _candle.ToString(), " now there is ", icdata.Size(), " candles in the buffer."); + Print("Added candle: ", _candle.ToString(), " now there is ", icdata.Size(), " candles in the buffer."); - last_incomplete_candle_ts = entry.timestamp; - } + last_incomplete_candle_ts = entry.timestamp; + } - static int iteration = 0; + static int iteration = 0; - ++iteration; + ++iteration; - Print("Iteration: ", iteration); + Print("Iteration: ", iteration); - if (iteration > 1793) { - // Print(icdata.ToJSON()); - } + if (iteration > 1793) { + // Print(icdata.ToJSON()); + } - Print("Last Incomplete Time: ", TimeToString(last_incomplete_candle_ts, TIME_DATE | TIME_MINUTES | - TIME_SECONDS), " (", last_incomplete_candle_ts, ")"); Print("Last Incomplete Candle: ", - icdata.GetByKey(last_incomplete_candle_ts).ToString()); Print("Last Completed Time: ", - TimeToString(last_completed_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS), " (", last_completed_candle_ts, - ")"); Print("Last Completed Candle: ", icdata.GetByKey(last_completed_candle_ts).ToString()); + Print("Last Incomplete Time: ", TimeToString(last_incomplete_candle_ts, TIME_DATE | TIME_MINUTES | + TIME_SECONDS), " (", last_incomplete_candle_ts, ")"); Print("Last Incomplete Candle: ", + icdata.GetByKey(last_incomplete_candle_ts).ToString()); Print("Last Completed Time: ", + TimeToString(last_completed_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS), " (", last_completed_candle_ts, + ")"); Print("Last Completed Candle: ", icdata.GetByKey(last_completed_candle_ts).ToString()); - // Updating tick & bar indices. Bar time is time of the last completed candle. - // Print(last_completed_candle_ts); - counter.OnTick(last_completed_candle_ts); + // Updating tick & bar indices. Bar time is time of the last completed candle. + // Print(last_completed_candle_ts); + counter.OnTick(last_completed_candle_ts); - Print("---------"); + Print("---------"); - last_entry_ts = entry.timestamp; - */ + last_entry_ts = entry.timestamp; + */ }; /** diff --git a/Indicator/IndicatorTf.provider.h b/Indicator/IndicatorTf.provider.h index 3318b58da..bb7e75928 100644 --- a/Indicator/IndicatorTf.provider.h +++ b/Indicator/IndicatorTf.provider.h @@ -125,19 +125,33 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { // In order to (re)generate candle, we need to fetch ticks within a fixed time-frame and then update that candle // with all fetched ticks. For IndicatorTf, there is no difference between (re)generating backwards or forwards, // as candles are time-framed. The only problem is that there may be missing candles in fetched time-frames. We - // just need to skip such time-frame and fetch ticks for next time-frame. In order to determine + // just need to skip such time-frame and fetch ticks for next time-frame. IndicatorData* _indi_tick = indi PTR_DEREF GetTick(); // Ticks to form a candle. static ARRAY(TickTAB, _ticks); + if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + // For backward direction we need to start from the beginning of the candle as _from_time_ms determines it's + // ending. + //_ticks_to_ms = _ticks_from_ms + (_candle_length_ms - 1); + } else { + //_ticks_to_ms = _ticks_from_ms - (_candle_length_ms - 1); + } + while (_num_items > 0) { // Calculating time from which and to which we want to retrieve ticks to form a candle. int _ticks_from_s = GetCandleTimeFromTimeMs(_from_time_ms, spc); long _ticks_from_ms = (long)_ticks_from_s * 1000; long _candle_length_ms = (long)spc * 1000; - long _ticks_to_ms = _ticks_from_ms + _candle_length_ms - 1; + long _ticks_to_ms; + + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + _ticks_to_ms = _ticks_from_ms + (_candle_length_ms - 1); + } else { + _ticks_to_ms = _ticks_from_ms - (_candle_length_ms - 1); + } // We will try to fetch history by two methods. // 1. By time range if IndicatorTick supports that way. diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 4b2a73c03..a292e6b08 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -25,8 +25,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -49,11 +49,17 @@ class IndicatorTfDummy : public IndicatorTf { string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } - void OnDataSourceEntry(IndicatorDataEntry& entry) override { + void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + IndicatorTf::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } + // When overriding OnDataSourceEntry() we have to remember to call parent // method, because IndicatorCandle also need to invoke it in order to // create/update matching candle. - IndicatorTf::OnDataSourceEntry(entry); #ifdef __debug_indicator__ Print(GetFullName(), " got new tick at ", entry.timestamp, diff --git a/Indicators/Account/Indi_AccountStats.mqh b/Indicators/Account/Indi_AccountStats.mqh index ece3896dc..367fd1866 100644 --- a/Indicators/Account/Indi_AccountStats.mqh +++ b/Indicators/Account/Indi_AccountStats.mqh @@ -191,14 +191,13 @@ class Indi_AccountStats : public Indicator { /** * Called when data source emits new entry (historic or future one). */ - virtual void OnDataSourceEntry(IndicatorDataEntry &entry/*, ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT*/) { - /* - Indicator::OnDataSourceEntry(entry, type); + virtual void OnDataSourceEntry(IndicatorDataEntry &entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + Indicator::OnDataSourceEntry(entry, type); if (type != INDI_EMITTED_ENTRY_TYPE_CANDLE) { return; } - */ // New candle means that account stats for current index 0 will be that we // will now extract and store in the buffers. diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 320c3f298..6001716ce 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -127,60 +127,11 @@ class Indi_TickMt : public IndicatorTick, _out_ticks)) { + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) override { ArrayResize(_out_ticks, 0); -#ifdef __MQL4__ - // Searching from current bar to older ones. - int _shift; - - if (_to_ms <= _cache_fetch_history_shift_to_ms) { - _shift = _cache_fetch_history_shift_shift; - } else { - _shift = 0; - } - - string _symbol = GetSymbol(); - - while (true) { - double _time = (double)iTime(_symbol, PERIOD_M1, _shift); - - if (_time == 0) { - // Invalid time. - break; - } - - long _time_ms = (long)_time * 1000; - - if (_time_ms > _to_ms) { - // No yet get into valid time range. - ++_shift; - continue; - } - - if (_time_ms < _from_ms) { - // No more ticks. - break; - } - - TickTAB _tick_o(_time_ms, iOpen(_Symbol, PERIOD_M1, _shift)); - TickTAB _tick_h(_time_ms, iHigh(_Symbol, PERIOD_M1, _shift)); - TickTAB _tick_l(_time_ms, iLow(_Symbol, PERIOD_M1, _shift)); - TickTAB _tick_c(_time_ms, iClose(_Symbol, PERIOD_M1, _shift)); - ArrayPushObject(_out_ticks, _tick_o); - ArrayPushObject(_out_ticks, _tick_h); - ArrayPushObject(_out_ticks, _tick_l); - ArrayPushObject(_out_ticks, _tick_c); - ++_shift; - } - - if (_shift != -1) { - _cache_fetch_history_shift_to_ms = _to_ms; - _cache_fetch_history_shift_shift = _shift; - } - - return ArraySize(_out_ticks) != 0; -#else +#ifdef __MQL5__ + // In MQL5 we firstly try to fetch ticks by CopyTicksRange. static MqlTick _tmp_ticks[]; ArrayResize(_tmp_ticks, 0); @@ -203,13 +154,54 @@ class Indi_TickMt : public IndicatorTick 0) { + return true; + } else { + // No ticks found. We will try to create ticks from historic OHLC values. + break; + } } } + #endif - // To many tries. Probably no ticks at the given range. - return false; + // In MQL4 or MQL5 (if there's no history returned by CopyTicksRange) we + // try to create and return OHLC ticks by calling iOpen/iHigh/iLow/iClose + // for each bar in history. Candle indicator will form candles from those + // 4 ticks per bar. + + string _symbol = GetSymbol(); + ARRAY(MqlRates, _rates); + + if (!CopyRates(_symbol, PERIOD_M1, (datetime)(int)(_from_ms / 1000), (datetime)(int)(_to_ms / 1000), _rates)) { + // Failure. + return false; + } + + if (ArraySize(_rates) == 0) { + // 0 ticks is OK. + return true; + } + + ArrayResize(_out_ticks, ArraySize(_rates) * 4); // Number of ticks * OHLC(4). + + int _tick_idx = 0; + + for (int i = 0; i < ArraySize(_rates); ++i) { + long _time_ms = (long)_rates[i].time * 1000; + // Note that we modify the time in order to simulate real open/close time. + TickTAB _tick_o(_time_ms + 0, _rates[i].open, _rates[i].open); + TickTAB _tick_h(_time_ms + 1, _rates[i].high, _rates[i].high); + TickTAB _tick_l(_time_ms + 2, _rates[i].low, _rates[i].low); + TickTAB _tick_c(_time_ms + 3, _rates[i].close, _rates[i].close); + + _out_ticks[_tick_idx++] = _tick_o; + _out_ticks[_tick_idx++] = _tick_h; + _out_ticks[_tick_idx++] = _tick_l; + _out_ticks[_tick_idx++] = _tick_c; + } + + return ArraySize(_out_ticks) != 0; } /** @@ -222,7 +214,65 @@ class Indi_TickMt : public IndicatorTick, _ticks); + if (!FetchHistoryByTimeRange( + (long)iTime(GetSymbol(), PERIOD_M1, _num_bars) * 1000, + (long)iTime(GetSymbol(), PERIOD_M1, 0) * 1000, + _ticks + )) { + // No history at all. + Print("Indi_TickMt: FetchHistoryByTimeRange() also end up with no history. We will work without history."); + return; + } + + if (ArraySize(_ticks) != _num_bars * 4) { + Alert("Error: Inconsistent number of ticks in the history! There should be as many ticks as 4 times the + number of bars!"); DebugBreak(); + } + + history.ReserveAdditionalHistoryMaxSize(ArraySize(_ticks)); + // @todo Calculate number of emitted candles. + // WillEmitEntries(INDI_EMITTED_ENTRY_TYPE_CANDLE, _num_candles); + for (int i = 0; i < ArraySize(_ticks); ++i) { + TickAB _tick(_ticks[i].ask, _ticks[i].bid); + IndicatorDataEntry _entry(TickToEntry(_ticks[i].time_ms, _tick)); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); + // Appending tick into the history. + AppendEntry(_entry); + #ifdef __debug__ + if (i % 10000 == 0 || i == ArraySize(_ticks) - 1) { + Print("Indi_TickMt: EmitHistory(): Done ", i, " / ", ArraySize(_ticks)); + } + #endif + } + } + else { + // We're good as CopyTicks() returned some history. + history.ReserveAdditionalHistoryMaxSize(ArraySize(_tmp_ticks)); + for (int i = 0; i < ArraySize(_tmp_ticks); ++i) { + TickAB _tick(_tmp_ticks[i].ask, _tmp_ticks[i].bid); + IndicatorDataEntry _entry(TickToEntry(_tmp_ticks[i].time_msc / 1000, _tick)); + EmitEntry(_entry); + // Appending tick into the history. + AppendEntry(_entry); + } + } + */ + } void OnTick(int _global_tick_index) override { #ifdef __MQL4__ diff --git a/Platform.h b/Platform.h index 780d4c116..5d67bd29c 100644 --- a/Platform.h +++ b/Platform.h @@ -32,11 +32,11 @@ #include "Std.h" #ifdef __MQLBUILD__ -#include "Indicators/Tick/Indi_TickMt.mqh" -#define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickMt + #include "Indicators/Tick/Indi_TickMt.mqh" + #define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickMt #else -#include "Indicators/Tick/Indi_TickRandom.mqh" -#define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickRandom + #include "Indicators/Tick/Indi_TickRandom.mqh" + #define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickRandom #endif #include "SymbolInfo.struct.static.h" @@ -121,7 +121,7 @@ class Platform { static void OnCalculate(const int rates_total, const int prev_calculated) { if (!emitted_history) { for (DictStructIterator> _iter = indis.Begin(); _iter.IsValid(); ++_iter) { - EmitHistory(_iter.Value().Ptr()); + // EmitHistory(_iter.Value().Ptr()); } emitted_history = true; } diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index d1edaed1e..fdff0cc8e 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -25,8 +25,8 @@ #define ITEMS_HISTORY_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif #include "../DictStruct.mqh" @@ -161,6 +161,16 @@ class ItemsHistory { */ unsigned int GetPeakSize() { return peak_size; } + /** + * Increments maximum size of historic items. + */ + void ReserveAdditionalHistoryMaxSize(unsigned int size) { history_max_size += size; } + + /** + * Changes maximum size of historic items. + */ + void SetHistoryMaxSize(unsigned int size) { history_max_size += size; } + /** * Will regenerate items from item provider. "_dir" indicates if we have to prepend or append items. */ @@ -352,11 +362,11 @@ class ItemsHistory { */ bool EnsureShiftExists(int _shift) { if (history.Size() == 0) { - return false; + // return false; } #ifdef __debug_items_history__ - Print("EnsureShiftExists(", _shift, ")"); + // Print("EnsureShiftExists(", _shift, ")"); #endif int _index = GetShiftIndex(_shift); From 7187581e4670b98addfa085a26c17009162f3a78 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 6 May 2024 21:39:30 +0200 Subject: [PATCH 116/123] Fixed problem with casting string to ENUM_LOG_LEVEL via indicator params' Get() and Set() methods. Also fixed formatting of files. --- EA.mqh | 25 ++++++++++--------- Exchange/tests/Exchange.test.mq5 | 4 +-- .../Account/tests/Indi_AccountStats.test.mq5 | 2 +- Log.mqh | 9 +++++-- Strategy.mqh | 25 +++++++++---------- Trade.mqh | 15 +++++------ 6 files changed, 43 insertions(+), 37 deletions(-) diff --git a/EA.mqh b/EA.mqh index 3d7bdb6d4..16cccca33 100644 --- a/EA.mqh +++ b/EA.mqh @@ -30,8 +30,8 @@ #define EA_MQH // Includes. -#include "Chart.mqh" #include "./Chart.struct.static.h" +#include "Chart.mqh" #include "Data.struct.h" #include "Dict.mqh" #include "DictObject.mqh" @@ -114,12 +114,12 @@ class EA : public Taskable { Init(); // Initialize a trade instance for the current chart and symbol. Ref _source = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); - TradeParams _tparams(0, 1.0f, 0, eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + TradeParams _tparams(0, 1.0f, 0, (ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); 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))); - //_trade.GetLogger().SetLevel(eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + logger.SetLevel((ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + //_trade.GetLogger().SetLevel((ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); } /** @@ -409,11 +409,11 @@ class EA : public Taskable { _strat.OnOrderOpen(_oparams); // Send the request. _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 (!_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 (_trade.IsTradeRecommended()) { logger.Debug( StringFormat("Error while sending a trade request! Entry: %s", @@ -421,7 +421,8 @@ class EA : public Taskable { __FUNCTION_LINE__, StringFormat("Code: %d, Msg: %s", _LastError, Terminal::GetErrorText(_LastError))); } #ifdef __debug_ea__ - Print(__FUNCTION_LINE__ + "(): " + SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()); + Print(__FUNCTION_LINE__ + + "(): " + SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()); #endif } return _result; @@ -766,8 +767,8 @@ class EA : public Taskable { Ref _strat = ((SClass *)NULL).Init(_tf, THIS_PTR); _strat.Ptr().Set(STRAT_PARAM_ID, _magic_no); _strat.Ptr().Set(TRADE_PARAM_MAGIC_NO, _magic_no); - _strat.Ptr().Set(STRAT_PARAM_LOG_LEVEL, - eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + _strat.Ptr().Set(STRAT_PARAM_LOG_LEVEL, + (ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); _strat.Ptr().Set(STRAT_PARAM_TF, _tf); _strat.Ptr().Set(STRAT_PARAM_TYPE, _type); _strat.Ptr().OnInit(); diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 index 498c0c791..aff8fa3f9 100644 --- a/Exchange/tests/Exchange.test.mq5 +++ b/Exchange/tests/Exchange.test.mq5 @@ -96,8 +96,8 @@ bool TestExchange01() { exchange REF_DEREF SymbolAdd(symbol02.Ptr(), "Symbol02"); // Attach instances of dummy trades. - Ref trade01 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT)); - Ref trade02 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT)); + Ref trade01 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, (ENUM_TIMEFRAMES)Period())); + Ref trade02 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, (ENUM_TIMEFRAMES)Period())); exchange REF_DEREF TradeAdd(trade01.Ptr(), "Trade01"); exchange REF_DEREF TradeAdd(trade02.Ptr(), "Trade02"); diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq5 b/Indicators/Account/tests/Indi_AccountStats.test.mq5 index ffb2666f3..81bca2d2d 100644 --- a/Indicators/Account/tests/Indi_AccountStats.test.mq5 +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq5 @@ -39,7 +39,7 @@ int OnInit() { Platform::Init(); - Platform::AddWithDefaultBindings(indi_account_mt.Ptr()); + Platform::AddWithDefaultBindings(indi_account_mt.Ptr(), _Symbol, (ENUM_TIMEFRAMES)Period()); bool _result = true; assertTrueOrFail(indi_account_mt REF_DEREF IsValid(), "Error on IsValid!"); diff --git a/Log.mqh b/Log.mqh index c55c526d6..13bc13fd4 100644 --- a/Log.mqh +++ b/Log.mqh @@ -76,8 +76,7 @@ class Log : public Object { /** * Class copy constructor. */ - Log(const Log &_log) : filename(_log.filename), last_entry(_log.last_entry), log_level(_log.log_level) { - } + Log(const Log &_log) : filename(_log.filename), last_entry(_log.last_entry), log_level(_log.log_level) {} /** * Class deconstructor. @@ -345,4 +344,10 @@ bool Log::AddLastError(string prefix, long suffix) { return Add(V_ERROR, Terminal::GetLastErrorText(), prefix, StringFormat("%d", suffix)); } +// Specialization of StringToType() for enum. +void StringToType(string _value, ENUM_LOG_LEVEL &_out) { + // Maybe parse the string? + _out = V_NONE; +} + #endif diff --git a/Strategy.mqh b/Strategy.mqh index 115b7660a..79ab81eba 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -668,7 +668,7 @@ class Strategy : public Taskable { virtual void OnInit() { // Link log instances. logger.Link(trade.Ptr().GetLogger()); - trade.Ptr().GetLogger().SetLevel(sparams.Get(STRAT_PARAM_LOG_LEVEL)); + trade.Ptr().GetLogger().SetLevel((ENUM_LOG_LEVEL)sparams.Get(STRAT_PARAM_LOG_LEVEL)); // Sets strategy stops. SetStops(THIS_PTR, THIS_PTR); // trade.SetStrategy(&this); // @fixme @@ -926,12 +926,12 @@ class Strategy : public Taskable { bool _result = true; if (_method != 0) { int _shift = _method / 64; - 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, 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)) @@ -1054,15 +1054,14 @@ 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 REF_DEREF HasBarOrder(_cmd, _shift); // 1 - if (METHOD(_method, 1)) _result |= _result || !IsTrend(_cmd); // 2 + 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 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 + _result |= _result || Open[_shift] > High[_shift + 1] || Open[_shift] < Low[_shift + 1]; // 8 + 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 |= diff --git a/Trade.mqh b/Trade.mqh index 4c4daf932..4ec0a0ec5 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -830,7 +830,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // @todo: _order.IsPending()? _result &= orders_active.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); logger.Link(_order.GetLogger()); - _order PTR_DEREF GetLogger().SetLevel(tparams.Get(TRADE_PARAM_LOG_LEVEL)); + _order PTR_DEREF GetLogger().SetLevel((ENUM_LOG_LEVEL)tparams.Get(TRADE_PARAM_LOG_LEVEL)); } else { _result &= orders_history.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); } @@ -894,11 +894,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.Error( - StringFormat("Failed to close the order: %d! Error: %d (%s)", _order REF_DEREF Get(ORDER_PROP_TICKET), - _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), - Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), - __FUNCTION_LINE__); + logger.Error(StringFormat("Failed to close the order: %d! Error: %d (%s)", + _order REF_DEREF Get(ORDER_PROP_TICKET), + _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), + Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), + __FUNCTION_LINE__); continue; } } else { @@ -932,7 +932,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. order_last = _order; } else { logger.Error( - StringFormat("Failed to close the order: %d! Error: %d (%s)", _order REF_DEREF Get(ORDER_PROP_TICKET), + StringFormat("Failed to close the order: %d! Error: %d (%s)", + _order REF_DEREF Get(ORDER_PROP_TICKET), _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), __FUNCTION_LINE__); From 6a38ad36af65acfb0d839eb0d62c10355356489d Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 26 Jun 2024 18:45:52 +0200 Subject: [PATCH 117/123] Committing the ItemsHistory-related code before merging `v3.008-dev-new`. This code is not yet ready to merge. --- Candle.struct.h | 7 +- Indicator/IndicatorCandle.provider.h | 13 +- Indicator/IndicatorTf.h | 17 +- Indicator/IndicatorTf.provider.h | 41 ++++- Indicator/IndicatorTf.struct.h | 11 +- Indicator/IndicatorTick.provider.h | 21 ++- Indicator/tests/classes/IndicatorTfDummy.h | 5 +- Indicators/Tick/Indi_TickMt.mqh | 4 +- Platform.h | 5 +- Storage/ItemsHistory.h | 171 +++++++++++++-------- 10 files changed, 189 insertions(+), 106 deletions(-) diff --git a/Candle.struct.h b/Candle.struct.h index 17b6f287d..2a05bc513 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -275,10 +275,11 @@ struct CandleOCTOHLC : CandleOHLC { Print("Error: Cannot update candle. Given time doesn't fit in candle's time-frame! Given time ", _timestamp_ms, ", but candle range is ", (long)start_time * 1000, " - ", (long)(start_time + length) * 1000, "."); if (_timestamp_ms < (long)start_time * 1000) { - Print("Looks like given time is ", (long)start_time * 1000 - _timestamp_ms, " ms before the candle starts."); + long _ms = (long)start_time * 1000 - _timestamp_ms; + Print("Looks like given time is ", _ms, " ms (", (double)_ms / 1000, " s) before the candle starts."); } else { - Print("Looks like given time is ", _timestamp_ms - (long)(start_time + length) * 1000, - " ms after the candle ends."); + long _ms = _timestamp_ms - (long)(start_time + length) * 1000; + Print("Looks like given time is ", _ms, " ms (", (double)_ms / 1000, "s) after the candle ends."); } DebugBreak(); } diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index b6737c945..f20b5f69e 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -25,8 +25,8 @@ #define INDICATOR_CANDLE_PROVIDER_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -62,6 +62,15 @@ class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider, ItemsHistoryCandleProvider>* _history, int _start_index, + int _end_index, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + return false; + } }; #endif diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index db9ab8980..f4b8c996d 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -25,11 +25,12 @@ #define INDICATOR_TF_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. +#include "../Chart.struct.tf.h" #include "IndicatorCandle.h" #include "IndicatorTf.provider.h" @@ -50,25 +51,16 @@ class IndicatorTf : public IndicatorCandle(iparams.GetSecsPerCandle(), THIS_PTR)); + history.SetItemProvider(new ItemsHistoryTfCandleProvider(ChartTf::TfToSeconds(GetTf()), THIS_PTR)); } public: /* Special methods */ - /** - * Class constructor with timeframe enum. - */ - IndicatorTf(unsigned int _spc) { - iparams.SetSecsPerCandle(_spc); - Init(); - } - /** * Class constructor with timeframe enum. */ IndicatorTf(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - iparams.SetSecsPerCandle(ChartTf::TfToSeconds(_tf)); tf = _tf; Init(); } @@ -77,7 +69,6 @@ class IndicatorTf : public IndicatorCandle { /** * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we - * want previous or next items from selected starting point. + * want previous or next items from selected starting point. Should return false if retrieving items by this method + * is not available. */ - void GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _from_time_ms, + bool GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. if (_from_time_ms != 0) { @@ -140,6 +141,8 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { //_ticks_to_ms = _ticks_from_ms - (_candle_length_ms - 1); } + bool _is_first_item = true; + while (_num_items > 0) { // Calculating time from which and to which we want to retrieve ticks to form a candle. int _ticks_from_s = GetCandleTimeFromTimeMs(_from_time_ms, spc); @@ -147,10 +150,23 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { long _candle_length_ms = (long)spc * 1000; long _ticks_to_ms; + _ticks_to_ms = _ticks_from_ms + (_candle_length_ms - 1); + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { - _ticks_to_ms = _ticks_from_ms + (_candle_length_ms - 1); - } else { - _ticks_to_ms = _ticks_from_ms - (_candle_length_ms - 1); + // Backwards. + if (_is_first_item) { + // As _from_time_ms in backward direction is next candle time - 1ms + // then we need to include it in our calculations. + long _new_start_ms = _from_time_ms - (_candle_length_ms - 1); + long _new_end_ms = _from_time_ms; + + _ticks_from_ms = _new_start_ms; + _ticks_from_s = int(_new_start_ms / 1000); + _from_time_ms = _new_start_ms; + _ticks_to_ms = _new_end_ms; + + _is_first_item = false; + } } // We will try to fetch history by two methods. @@ -178,6 +194,10 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { // Even if we don't form an item (a candle), we assume we've done one item. --_num_items; + if (_num_items % 10000 == 0) { + Print(_num_items, " left to process..."); + } + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { _from_time_ms += _candle_length_ms; } else { @@ -188,6 +208,17 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { Print("Error: GetItems() for IndicatorTf can only work with given _from_time_ms!"); DebugBreak(); } + + return true; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, int _start_index, + int _end_index, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + return false; } /** diff --git a/Indicator/IndicatorTf.struct.h b/Indicator/IndicatorTf.struct.h index 49b31ab0c..606023e17 100644 --- a/Indicator/IndicatorTf.struct.h +++ b/Indicator/IndicatorTf.struct.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -36,13 +36,8 @@ /* Structure for IndicatorTf class parameters. */ struct IndicatorTfParams : IndicatorParams { ChartTf tf; - unsigned int spc; // Seconds per candle. // Struct constructor. - IndicatorTfParams(string _name = "", unsigned int _spc = 60) : IndicatorParams(_name), spc(_spc) {} - // Getters. - unsigned int GetSecsPerCandle() { return spc; } - // Setters. - void SetSecsPerCandle(unsigned int _spc) { spc = _spc; } + IndicatorTfParams(string _name, ENUM_TIMEFRAMES _tf) : IndicatorParams(_name) { tf.SetTf(_tf); } // Copy constructor. IndicatorTfParams(const IndicatorTfParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { THIS_REF = _params; diff --git a/Indicator/IndicatorTick.provider.h b/Indicator/IndicatorTick.provider.h index 16659088a..40aef5054 100644 --- a/Indicator/IndicatorTick.provider.h +++ b/Indicator/IndicatorTick.provider.h @@ -25,8 +25,8 @@ #define INDICATOR_TICK_PROVIDER_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -57,12 +57,21 @@ class ItemsHistoryTickProvider : public ItemsHistoryItemProvider> { /** * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we - * want previous or next items from selected starting point. + * want previous or next items from selected starting point. Should return false if retrieving items by this method + * is not available. */ - void GetItems(ItemsHistory, ItemsHistoryTickProvider>* _history, long _from_time_ms, + bool GetItems(ItemsHistory, ItemsHistoryTickProvider>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(TickTAB, _out_arr)) { - // Method is called if there is a missing item (tick) in the history. We need to regenerate it. - indi PTR_DEREF FetchHistoryByStartTimeAndCount(_from_time_ms, _dir, _num_items, _out_arr); + return false; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryTickProvider>* _history, int _start_index, int _end_index, + ARRAY_REF(TickTAB, _out_arr)) { + return false; } /** diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index a292e6b08..7ff6269c8 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -35,7 +35,7 @@ // Params for dummy candle-based indicator. struct IndicatorTfDummyParams : IndicatorTfParams { - IndicatorTfDummyParams(unsigned int _spc = 60) : IndicatorTfParams("IndicatorTf", _spc) {} + IndicatorTfDummyParams(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTfParams("IndicatorTf", _tf) {} }; /** @@ -43,11 +43,10 @@ struct IndicatorTfDummyParams : IndicatorTfParams { */ class IndicatorTfDummy : public IndicatorTf { public: - IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} IndicatorTfDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTf(_tf) {} IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi = 0) : IndicatorTf(_tfi) {} - string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } + string GetName() override { return "IndicatorTfDummy(" + EnumToString(GetTf()) + ")"; } void OnDataSourceEntry(IndicatorDataEntry& entry, ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 6001716ce..7de3b4050 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -295,7 +295,7 @@ class Indi_TickMt : public IndicatorTick _tick(0, 0); IndicatorDataEntry _entry(TickToEntry(TimeCurrent(), _tick)); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); // Appending tick into the history. AppendEntry(_entry); return; @@ -324,7 +324,7 @@ class Indi_TickMt : public IndicatorTick _tick(_ask, _bid); IndicatorDataEntry _entry(TickToEntry(_time, _tick)); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); // Appending tick into the history. AppendEntry(_entry); } diff --git a/Platform.h b/Platform.h index 5d67bd29c..d92d8dd76 100644 --- a/Platform.h +++ b/Platform.h @@ -32,11 +32,14 @@ #include "Std.h" #ifdef __MQLBUILD__ + #include "Indicators/Tf/Indi_TfMt.h" #include "Indicators/Tick/Indi_TickMt.mqh" #define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickMt + #define PLATFORM_DEFAULT_INDICATOR_TF Indi_TfMt #else #include "Indicators/Tick/Indi_TickRandom.mqh" #define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickRandom + #define PLATFORM_DEFAULT_INDICATOR_TF IndicatorTfDummy #endif #include "SymbolInfo.struct.static.h" @@ -274,7 +277,7 @@ class Platform { 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)); + _indi_candle = Objects::Set(_key, new PLATFORM_DEFAULT_INDICATOR_TF(_tf)); // Adding indicator to list of default indicators in order to tick it on every Tick() call. Ref _ref = _indi_candle; diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index fdff0cc8e..3e10d25af 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -56,13 +56,21 @@ class ItemsHistoryItemProvider : public Dynamic { /** * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we - * want previous or next items from selected starting point. + * want previous or next items from selected starting point. Should return false if retrieving items by this method + * is not available. */ - void GetItems(ItemsHistory>* _history, long _from_time_ms, + bool GetItems(ItemsHistory>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(IV, _out_arr)) { - // Method is called if there is a missing item (candle) in the history. We need to regenerate it. - Print("Error: Retrieving items by this item provider is not implemented!"); - DebugBreak(); + return false; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory>* _history, int _start_index, int _end_index, + ARRAY_REF(IV, _out_arr)) { + return false; } /** @@ -179,80 +187,111 @@ class ItemsHistory { Print("RegenerateHistory(", _from_index, ", ", _to_index, ", ", EnumToString(_dir), "), ", GetInfo()); #endif - static ARRAY(IV, _items); // Items generated by provider. - ArrayResize(_items, 0); - int _item_count = _to_index - _from_index + 1; - long _from_time_ms; - IV _item; - - // Calculating time to be passed to GetItems(). - if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { - if (history.Size() == 0) { -#ifdef __debug_items_history__ - Print("RegenerateHistory: Getting initial time from item provider"); -#endif - - // Time from we'll be getting items will be the time of the first possible item/candle/tick. - _from_time_ms = item_provider REF_DEREF GetInitialTimeMs(); - } else { -#ifdef __debug_items_history__ - Print("RegenerateHistory: Getting last valid item at index ", last_valid_index); -#endif - // Time will be the time of last valid item + item's length + 1ms. - // Note that ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. - _item = GetItemByIndex(last_valid_index); - _from_time_ms = _item.GetTimeMs() + _item.GetLengthMs() + 1; - } - - long _current_time_ms = TimeCurrent() * 1000; - - if (_from_time_ms > (long)TimeCurrent() * 1000) { - // There won't be items in the future. - return; - } - } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { - if (history.Size() == 0) { - // Time from we'll be getting items will be the time of the first possible item/candle/tick - 1ms. - _from_time_ms = item_provider REF_DEREF GetInitialTimeMs() - 1; - } else { -#ifdef __debug_items_history__ - Print("RegenerateHistory: Getting first valid item at index ", first_valid_index); -#endif + // Static buffer for items generated by the item provider. + static ARRAY(IV, _items); + ArrayResize(_items, 0); - // Time will be the time of the first valid item - 1ms. - _item = GetItemByIndex(first_valid_index); - _from_time_ms = _item.GetTimeMs() - 1; - } - } else { - Print("Error: We shouldn't be here!"); - DebugBreak(); - return; - } + // Currently we only support getting items via start -> end indices. - item_provider REF_DEREF GetItems(THIS_PTR, _from_time_ms, _dir, _item_count, _items); + item_provider REF_DEREF GetItems(THIS_PTR, _from_index, _to_index, _items); if (ArraySize(_items) != _item_count) { -// There's really no problem if number of generated items are less than -// requested. -// @todo However, if there's too many calls for RegenerateHistory then we -// need to find a way to make it exit earlier. #ifdef __debug_items_history__ Print("RegenerateHistory: Notice: Requested ", _item_count, " historic items, got ", ArraySize(_items), ". from index = ", _from_index, ", to index = ", _to_index, ", dir = ", EnumToString(_dir), " (", GetInfo(), ")"); #endif - return; } - for (int i = 0; i < _item_count; ++i) { - if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + int i; + + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + for (i = 0; i < _item_count; ++i) { Append(_items[i], false); - } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + } + } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + // Our _items array contain most recent items at the start, so we have to iterate from the end in order to prepend + // items. + if (peak_size <= 1) { + // It's the first time we're trying to retrieve historic items. We need to make sure all history will fit in the + // buffer. Note that we use <= 1, because Tick indicator could already have appeneded first candle. + history_max_size = MathMax(history_max_size, history.Size() + _item_count); + } + for (i = 0; i < _item_count; ++i) { Prepend(_items[i], false); } } + + /* + + int _item_count = _to_index - _from_index + 1; + long _from_time_ms; + IV _item; + + // Calculating time to be passed to GetItems(). + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + if (history.Size() == 0) { + #ifdef __debug_items_history__ + Print("RegenerateHistory: Getting initial time from item provider"); + #endif + + // Time from we'll be getting items will be the time of the first possible item/candle/tick. + _from_time_ms = item_provider REF_DEREF GetInitialTimeMs(); + } else { + #ifdef __debug_items_history__ + Print("RegenerateHistory: Getting last valid item at index ", last_valid_index); + #endif + + // Time will be the time of last valid item + item's length + 1ms. + // Note that ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. + _item = GetItemByIndex(last_valid_index); + _from_time_ms = _item.GetTimeMs() + _item.GetLengthMs() + 1; + } + + long _current_time_ms = TimeCurrent() * 1000; + + if (_from_time_ms > (long)TimeCurrent() * 1000) { + // There won't be items in the future. + return; + } + } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + if (history.Size() == 0) { + // Time from we'll be getting items will be the time of the first possible item/candle/tick - 1ms. + _from_time_ms = item_provider REF_DEREF GetInitialTimeMs() - 1; + } else { + #ifdef __debug_items_history__ + Print("RegenerateHistory: Getting first valid item at index ", first_valid_index); + #endif + + // Time will be the time of the first valid item - 1ms. + _item = GetItemByIndex(first_valid_index); + _from_time_ms = _item.GetTimeMs() - 1; + } + } else { + Print("Error: We shouldn't be here!"); + DebugBreak(); + return; + } + + item_provider REF_DEREF GetItems(THIS_PTR, _from_time_ms, _dir, _item_count, _items); + + if (ArraySize(_items) != _item_count) { + // There's really no problem if number of generated items are less than + // requested. + // @todo However, if there's too many calls for RegenerateHistory then we + // need to find a way to make it exit earlier. + #ifdef __debug_items_history__ + Print("RegenerateHistory: Notice: Requested ", _item_count, " historic items, got ", ArraySize(_items), + ". from index = ", _from_index, ", to index = ", _to_index, ", dir = ", EnumToString(_dir), " (", + GetInfo(), + ")"); + #endif + return; + } + + */ } string GetInfo() { @@ -473,7 +512,13 @@ class ItemsHistory { return (datetime)0; } - return (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); + datetime _dt = (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); + +#ifdef __debug_items_history__ + Print("GetItemTimeByShift(", _shift, "), ", GetInfo(), " = ", _dt); +#endif + + return _dt; } /** From 63f1ddbfefd1252a360fe293ed9b5008369dce79 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 27 Jun 2024 12:33:12 +0200 Subject: [PATCH 118/123] Fixes compilation errors in MT4 and MT5. --- Candle.struct.h | 5 +++-- Indicator/IndicatorCandle.provider.h | 5 ++--- Indicator/IndicatorRenko.provider.h | 18 +++++++++++++++--- Indicator/IndicatorTf.h | 2 +- Indicators/Account/Indi_AccountStats.mqh | 2 +- Indicators/Tick/Indi_TickMt.mqh | 2 +- Object.mqh | 5 ----- Platform.h | 16 ++++++++-------- Std.h | 23 ++++++++++++----------- 9 files changed, 43 insertions(+), 35 deletions(-) diff --git a/Candle.struct.h b/Candle.struct.h index 85f439323..74e9c9bab 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -284,11 +284,12 @@ struct CandleOCTOHLC : CandleOHLC { if (!ContainsTimeMs(_timestamp_ms)) { Print("Error: Cannot update candle. Given time doesn't fit in candle's time-frame! Given time ", _timestamp_ms, ", but candle range is ", (long)start_time * 1000, " - ", (long)(start_time + length) * 1000, "."); + long _ms; if (_timestamp_ms < (long)start_time * 1000) { - long _ms = (long)start_time * 1000 - _timestamp_ms; + _ms = (long)start_time * 1000 - _timestamp_ms; Print("Looks like given time is ", _ms, " ms (", (double)_ms / 1000, " s) before the candle starts."); } else { - long _ms = _timestamp_ms - (long)(start_time + length) * 1000; + _ms = _timestamp_ms - (long)(start_time + length) * 1000; Print("Looks like given time is ", _ms, " ms (", (double)_ms / 1000, "s) after the candle ends."); } DebugBreak(); diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index 2f57dcfbb..4cbccc76c 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -56,11 +56,10 @@ class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider, ItemsHistoryCandleProvider>* _history, long _from_time_ms, + bool GetItems(ItemsHistory, ItemsHistoryCandleProvider>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. - Print("Error: Retrieving items by this item provider is not implemented!"); - DebugBreak(); + return false; } /** diff --git a/Indicator/IndicatorRenko.provider.h b/Indicator/IndicatorRenko.provider.h index e987f12ba..63c483a80 100644 --- a/Indicator/IndicatorRenko.provider.h +++ b/Indicator/IndicatorRenko.provider.h @@ -25,8 +25,8 @@ #define INDICATOR_RENKO_PROVIDER_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif /** @@ -68,12 +68,24 @@ class ItemsHistoryRenkoCandleProvider : public ItemsHistoryCandleProvider { * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we * want previous or next items from selected starting point. */ - void GetItems(ItemsHistory, ItemsHistoryRenkoCandleProvider>* _history, long _from_time_ms, + bool GetItems(ItemsHistory, ItemsHistoryRenkoCandleProvider>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. Print("IndicatorRenko is not yet implemented!"); DebugBreak(); + return false; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryRenkoCandleProvider>* _history, int _start_index, + int _end_index, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + Print("IndicatorRenko is not yet implemented!"); + DebugBreak(); + return false; } }; diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 5e44cf291..f00021569 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -87,7 +87,7 @@ class IndicatorTf : public IndicatorCandle { */ virtual void OnDataSourceEntry(IndicatorDataEntry &entry, ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { - Indicator::OnDataSourceEntry(entry, type); + Indicator::OnDataSourceEntry(entry, type); if (type != INDI_EMITTED_ENTRY_TYPE_CANDLE) { return; diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 28b15a7cb..0bd2f29a9 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -264,7 +264,7 @@ class Indi_TickMt : public IndicatorTick @@ -122,18 +123,18 @@ */ #define CONST_REF_TO(T) const T& - /** +/** - * Reference to the array. - * - * @usage - * ARRAY_REF(, ) - */ -#define ARRAY_TYPE(T) _cpp_array -#define ARRAY_REF(T, N) ARRAY_TYPE(T) & N -#define FIXED_ARRAY_REF(T, N, S) T(&N)[S] +* Reference to the array. +* +* @usage +* ARRAY_REF(, ) +*/ + #define ARRAY_TYPE(T) _cpp_array + #define ARRAY_REF(T, N) ARRAY_TYPE(T) & N + #define FIXED_ARRAY_REF(T, N, S) T(&N)[S] -#define CONST_ARRAY_REF(T, N) const _cpp_array& N + #define CONST_ARRAY_REF(T, N) const _cpp_array& N #define CONST_ARRAY_REF(T, N) const _cpp_array& N /** @@ -568,4 +569,4 @@ struct AsSeriesReleaseEnsurer { SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(7); #define RELEASE_BUFFER8(A, B, C, D, E, F, G, H) \ RELEASE_BUFFER8_NO_ENSURE(A, B, C, D, E, F, G, H); \ - SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(8); \ No newline at end of file + SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(8); From c132e9b6f7194769a456b890f9a1ced3b8752734 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 27 Jun 2024 13:08:17 +0200 Subject: [PATCH 119/123] Added missing files. --- Indicators/Tf/Indi_TfMt.h | 100 +++++++++++++++++ Indicators/Tf/Indi_TfMt.provider.h | 173 +++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 Indicators/Tf/Indi_TfMt.h create mode 100644 Indicators/Tf/Indi_TfMt.provider.h diff --git a/Indicators/Tf/Indi_TfMt.h b/Indicators/Tf/Indi_TfMt.h new file mode 100644 index 000000000..ae2f16811 --- /dev/null +++ b/Indicators/Tf/Indi_TfMt.h @@ -0,0 +1,100 @@ +//+------------------------------------------------------------------+ +//| 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 + * Tf-based candle indicator for MT. + */ + +#ifndef __MQL__ + // Allows the preprocessor to include a header file when it is needed. + #pragma once +#endif + +// Includes. +#include "../../Indicator/IndicatorCandle.h" +#include "Indi_TfMt.provider.h" + +// Params for MT Tf-based candle indicator. +struct Indi_TfMtParams : IndicatorTfParams { + Indi_TfMtParams(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTfParams("IndicatorTf", _tf) {} +}; + +/** + * Tf-based candle indicator for MT. + */ +class Indi_TfMt : public IndicatorCandle> { + protected: + // Time-frame used to create candles. + ENUM_TIMEFRAMES tf; + + /* Protected methods */ + + /** + * Initialize class. + * + * Called on constructor. + */ + void Init() { history.SetItemProvider(new ItemsHistoryTfMtCandleProvider(THIS_PTR)); } + + public: + /* Special methods */ + + /** + * Class constructor with timeframe enum. + */ + Indi_TfMt(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + tf = _tf; + Init(); + } + + /** + * Class constructor with timeframe index. + */ + Indi_TfMt(ENUM_TIMEFRAMES_INDEX _tfi = 0) { + tf = ChartTf::IndexToTf(_tfi); + Init(); + } + + /** + * Class constructor with parameters. + */ + Indi_TfMt(Indi_TfMtParams& _icparams, const IndicatorDataParams& _idparams) { Init(); } + + /** + * Gets indicator's time-frame. + */ + ENUM_TIMEFRAMES GetTf() override { return tf; } + + /** + * Returns current tick index (incremented every OnTick()). + */ + int GetTickIndex() override { return history.GetItemProvider() PTR_DEREF GetTickIndex(); } + + /** + * Returns the number of bars on the chart decremented by iparams.shift. + */ + int GetBars() override { + // Will return number of bars prepended and appended to the history, + // even if those bars were cleaned up because of history's candle limit. + return ::Bars(GetSymbol(), GetTf()) - iparams.shift; + } +}; diff --git a/Indicators/Tf/Indi_TfMt.provider.h b/Indicators/Tf/Indi_TfMt.provider.h new file mode 100644 index 000000000..4af7095de --- /dev/null +++ b/Indicators/Tf/Indi_TfMt.provider.h @@ -0,0 +1,173 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __MQL__ + // Allows the preprocessor to include a header file when it is needed. + #pragma once +#endif + +/** + * Candle grouping and regeneration for time-frame based candles. + */ +template +class ItemsHistoryTfMtCandleProvider : public ItemsHistoryCandleProvider { + // Pointer to Tf Indicator, e.g., Indi_TfMt or IndicatorTfDummy. Used to fetch data by fixed timeframe candles. + IndicatorData* indi; + + // Current tick index. Effectively a number of ticks generated by attached Tick indicator. + int tick_index; + + public: + /** + * Constructor. + */ + ItemsHistoryTfMtCandleProvider(IndicatorData* _indi_tf) : indi(_indi_tf), tick_index(0) {} + + /** + * Called when new tick was emitted from IndicatorTick-based source. + */ + virtual void OnTick(ItemsHistory, ItemsHistoryTfMtCandleProvider>* _history, long _time_ms, + float _ask, float _bid) { + ++tick_index; + + // Seconds per candle calculated from TF. + int _spc = (int)ChartTf::TfToSeconds(indi PTR_DEREF GetTf()); + + Print("Indi_TfMt's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | TIME_SECONDS), + ", ", _ask, ", ", _bid); + + // We know that tick's timestamp will be ahead of the last tick and thus + // inside or ahead of the last created candle. In order to retrieve last + // valid candle, we need to use ItemsHistory::GetItemByShift(0) to check if + // we have to update last or create/append new candle. + CandleOCTOHLC _candle; + + // Will regenerate candles up to the last added candle ever. We have to + // call it, because some of the previous actions may have removed some of + // the recent candles. Note that OnTick() advances its _time_ms in + // ascending order, so all we need to most recent history. + // + // Note that EnsureShiftExists() may return false when there never been any + // candle added. + _history PTR_DEREF EnsureShiftExists(0); + + if (_history PTR_DEREF TryGetItemByShift(0, _candle, false) && _candle.ContainsTimeMs(_time_ms)) { + // Time given fits in the last added candle's time-frame, updating the candle with given price. + _candle.Update(_time_ms, _bid); + + // Storing candle in the history. + _history PTR_DEREF Update(_candle, _history PTR_DEREF GetShiftIndex(0)); + } else { + CandleOCTOHLC _candle_tmp; + + // We don't want to regenerate history, because at the start there will bo no candle however. + if (_history PTR_DEREF TryGetItemByShift(0, _candle_tmp, false)) { + // Print("Completed candle: ", _candle_tmp.ToString()); + // Print("Real candle: ", iOpen(NULL, Period(), 1), " ", iHigh(NULL, Period(), 1), " ", + // iLow(NULL, Period(), 1), " ", ChartStatic::iClose(NULL, (ENUM_TIMEFRAMES)Period(), 1)); + // Print("--"); + } + + // Either there is no candle at shift 0 or given time doesn't fit in the #0 candle's time-frame. + _candle.Init(GetCandleTimeFromTimeMs(_time_ms, _spc), _spc, _time_ms, _bid); + + // Adding candle as the most recent item in the history. It will now become the candle at shift 0. + _history PTR_DEREF Append(_candle); + } + } + + /** + * Returns current tick index. Effectively a number of ticks generated by + * attached IndicatorTick. + */ + int GetTickIndex() { return tick_index; } + + /** + * Returns start time of the candle (the place it's on the chart) for the given tick's time in milliseconds. + */ + int GetCandleTimeFromTimeMs(long _time_ms, int _length_in_secs) { + return (int)((_time_ms - _time_ms % ((long)_length_in_secs * 1000)) / 1000); + } + + /** + * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we + * want previous or next items from selected starting point. Should return false if retrieving items by this method + * is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryTfMtCandleProvider>* _history, long _from_time_ms, + ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + return false; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryTfMtCandleProvider>* _history, int _start_index, + int _end_index, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + Print("Indi_TfMt::GetItems()"); + + // Converting absolute indices into MT shifts. + int _num_bars = _end_index - _start_index + 1; + // Current candle index. Could be 0 if no candles have been added or if there is only one candle added so far. + int _current_index = _history PTR_DEREF GetCurrentIndex(); + int _start_shift = _current_index - _start_index; + int _end_shift = _current_index - _end_index; + + Print("Indi_TfMt::GetItems(): Will fetch ", _num_bars, " bars between shift ", _start_shift, " and ", _end_shift); + + // Seconds per candle calculated from TF. + int _spc = (int)ChartTf::TfToSeconds(indi PTR_DEREF GetTf()); + + // Static, reusable array of rates. + static ARRAY(MqlRates, _rates); + int _count = _end_index - _start_index + 1; + ArrayResize(_rates, _count); + + Print("CopyRates(", indi PTR_DEREF GetSymbol(), ", ", EnumToString(indi PTR_DEREF GetTf()), ", ", _start_index, + ", ", _count, ", ...)"); + + // As GetItems() will only be called for missing candles, we can just ask MT for OHLCs and return them. + // Note that we have to specify most recent shift and count of history ticks to return. + // Also note that CopyRates() will insert oldest candle at the start of _rates array, so we have to inverse items in + // the array in order all candles be from most recent to the oldest ones. + int _num_copied = CopyRates(indi PTR_DEREF GetSymbol(), indi PTR_DEREF GetTf(), _end_shift, _count, _rates); + ArrayResize(_out_arr, _num_copied); + + for (int i = 0; i < _num_copied; ++i) { + MqlRates _rate = _rates[i]; + int _start_secs = (int)(long)_rate.time; + CandleOCTOHLC _candle(_rate.open, _rate.high, _rate.low, _rate.close, _start_secs, _spc, + (long)_start_secs * 1000, long(_start_secs + _spc) * 1000 - 1, (int)_rate.tick_volume); + // Reversing output, so most recent candle will be at start. + _out_arr[_num_copied - i - 1] = _candle; + } + + ArrayResize(_rates, 0); + return true; + } + + /** + * Returns information about item provider. + */ + string const ToString() override { return "Indi_TfMt candle provider on " + indi PTR_DEREF GetFullName(); } +}; From 2a805d1d560ff8c0130cdd783a15f72902952989 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 27 Jun 2024 13:48:38 +0200 Subject: [PATCH 120/123] Removed unnecessary include. Fixes LinearWeightedMAOnBuffer() call in MT4. --- Indicators/Indi_MA.mqh | 95 +++++++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 0c7eb3634..f3f1801ab 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -24,9 +24,6 @@ #ifndef INDI_MA_MQH #define INDI_MA_MQH -// Includes. -#include - #include "../Dict.mqh" #include "../DictObject.mqh" #include "../Indicator/Indicator.h" @@ -35,27 +32,6 @@ #include "../Storage/ValueStorage.h" #include "../String.mqh" -#ifdef __MQL4__ -// MQL4 version of the method doesn't have last parameter. -int LinearWeightedMAOnBuffer(const int rates_total, const int prev_calculated, const int begin, const int period, - const double &price[], double &buffer[]) { - int _weight_sum; - return LinearWeightedMAOnBuffer(rates_total, prev_calculated, begin, period, price, buffer, _weight_sum); -} -#else // !__MQL__4 -// Defines global functions (for MQL4 backward compability). -double iMA(string _symbol, int _tf, int _ma_period, int _ma_shift, int _ma_method, int _ap, int _shift) { - ResetLastError(); - return Indi_MA::iMA(_symbol, (ENUM_TIMEFRAMES)_tf, _ma_period, _ma_shift, (ENUM_MA_METHOD)_ma_method, - (ENUM_APPLIED_PRICE)_ap, _shift); -} -double iMAOnArray(double &_arr[], int _total, int _period, int _ma_shift, int _ma_method, int _abs_shift, - IndicatorCalculateCache *_cache = NULL) { - ResetLastError(); - return Indi_MA::iMAOnArray(_arr, _total, _period, _ma_shift, _ma_method, _abs_shift, _cache); -} -#endif // __MQL4__ - // Structs. struct IndiMAParams : IndicatorParams { unsigned int period; @@ -552,6 +528,55 @@ class Indi_MA : public Indicator { return (rates_total); } + static int LinearWeightedMAOnBuffer(const int rates_total, const int prev_calculated, const int begin, + const int period, const ARRAY_REF(double, price), ARRAY_REF(double, buffer), + int &weight_sum) { + int i, k; + + // Check period. + if (period <= 1 || period > (rates_total - begin)) return (0); + // Save as_series flags. + bool as_series_price = ArrayGetAsSeries(price); + bool as_series_buffer = ArrayGetAsSeries(buffer); + + ArraySetAsSeries(price, false); + ArraySetAsSeries(buffer, false); + // Calculate start position. + int start_position; + + if (prev_calculated == 0) { + // First calculation or number of bars was changed. + // Set empty value for first bars. + start_position = period + begin; + + for (i = 0; i < start_position; i++) buffer[i] = 0.0; + // Calculate first visible value. + double first_value = 0; + int wsum = 0; + + for (i = begin, k = 1; i < start_position; i++, k++) { + first_value += k * price[i]; + wsum += k; + } + + buffer[start_position - 1] = first_value / wsum; + weight_sum = wsum; + } else + start_position = prev_calculated - 1; + // Main loop. + for (i = start_position; i < rates_total; i++) { + double sum = 0; + + for (int j = 0; j < period; j++) sum += (period - j) * price[i - j]; + + buffer[i] = sum / weight_sum; + } + // Restore as_series flags. + ArraySetAsSeries(price, as_series_price); + ArraySetAsSeries(buffer, as_series_buffer); + return (rates_total); + } + static int SmoothedMAOnBuffer(const int rates_total, const int prev_calculated, const int begin, const int period, ValueStorage &price, ValueStorage &buffer) { int i; @@ -785,4 +810,26 @@ class Indi_MA : public Indicator { iparams.applied_array = _applied_price; } }; + +#ifdef __MQL4__ +// MQL4 version of the method doesn't have last parameter. +int LinearWeightedMAOnBuffer(const int rates_total, const int prev_calculated, const int begin, const int period, + const double &price[], double &buffer[]) { + int _weight_sum; + return Indi_MA::LinearWeightedMAOnBuffer(rates_total, prev_calculated, begin, period, price, buffer, _weight_sum); +} +#else // !__MQL__4 +// Defines global functions (for MQL4 backward compability). +double iMA(string _symbol, int _tf, int _ma_period, int _ma_shift, int _ma_method, int _ap, int _shift) { + ResetLastError(); + return Indi_MA::iMA(_symbol, (ENUM_TIMEFRAMES)_tf, _ma_period, _ma_shift, (ENUM_MA_METHOD)_ma_method, + (ENUM_APPLIED_PRICE)_ap, _shift); +} +double iMAOnArray(double &_arr[], int _total, int _period, int _ma_shift, int _ma_method, int _abs_shift, + IndicatorCalculateCache *_cache = NULL) { + ResetLastError(); + return Indi_MA::iMAOnArray(_arr, _total, _period, _ma_shift, _ma_method, _abs_shift, _cache); +} +#endif // __MQL4__ + #endif // INDI_MA_MQH From e7ba4d53591d388342d6dbd9109f3fc9b01387c0 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 1 Jul 2024 19:04:05 +0200 Subject: [PATCH 121/123] WIP. Dict now uses class instead of struct in order to prevent copying slots two times. There is still a problem with GetEntry() using too many entries. --- Dict.enum.h | 2 +- Dict.mqh | 22 +++++++++++++++++++--- DictBase.mqh | 11 ++++++----- DictObject.mqh | 28 ++++++++++++++++++++++------ DictSlotsRef.h | 20 ++++++++++---------- DictStruct.mqh | 25 +++++++++++++++++++++---- Indicator/IndicatorCandle.h | 10 +++++++--- Indicator/IndicatorCandle.provider.h | 2 +- Indicator/IndicatorTick.h | 8 ++++---- Indicators/Tf/Indi_TfMt.provider.h | 4 ++++ Storage/ItemsHistory.h | 17 ++++++++++++++--- 11 files changed, 109 insertions(+), 40 deletions(-) diff --git a/Dict.enum.h b/Dict.enum.h index 99618ba5b..c746f87e3 100644 --- a/Dict.enum.h +++ b/Dict.enum.h @@ -30,7 +30,7 @@ #pragma once #endif -#define DICT_GROW_UP_PERCENT_DEFAULT 50 +#define DICT_GROW_UP_PERCENT_DEFAULT 100 #define DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS 20 /** diff --git a/Dict.mqh b/Dict.mqh index 5d30563ce..f123cf539 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -90,6 +90,8 @@ class Dict : public DictBase { } void Clear() { + _DictSlots_ref = new DictSlotsRef(); + for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { if (THIS_ATTR _DictSlots_ref.DictSlots[i].IsUsed()) THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); } @@ -210,7 +212,7 @@ class Dict : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V value, bool allow_resize) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, const K key, V value, bool allow_resize) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeDict; else if (THIS_ATTR _mode != DictModeDict) { @@ -315,7 +317,7 @@ class Dict : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, V value) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, V value) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeList; else if (THIS_ATTR _mode != DictModeList) { @@ -353,6 +355,18 @@ class Dict : public DictBase { MathMax(10, (int)((float)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } + public: + /** + * Ensures that there is at least given number of slots in dict. + */ + bool Reserve(int _size) { + if (_size <= ArraySize(THIS_ATTR _DictSlots_ref.DictSlots)) { + return true; + } + return Resize(_size); + } + + protected: /** * Shrinks or expands array of DictSlots. */ @@ -362,7 +376,7 @@ class Dict : public DictBase { return true; } - DictSlotsRef new_DictSlots; + DictSlotsRef* new_DictSlots = new DictSlotsRef(); if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) return false; @@ -389,6 +403,8 @@ class Dict : public DictBase { // Freeing old DictSlots array. ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots); + delete THIS_ATTR _DictSlots_ref; + THIS_ATTR _DictSlots_ref = new_DictSlots; return true; diff --git a/DictBase.mqh b/DictBase.mqh index 234c09d92..187191f2d 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -62,12 +62,13 @@ class DictBase { _mode = DictModeUnknown; _flags = 0; overflow_listener = nullptr; + _DictSlots_ref = new DictSlotsRef(); } /** * Destructor. */ - ~DictBase() {} + ~DictBase() { delete _DictSlots_ref; } DictIteratorBase Begin() { // Searching for first item index. @@ -106,7 +107,7 @@ class DictBase { /** * Returns slot by key. */ - DictSlot* GetSlotByKey(DictSlotsRef& dictSlotsRef, const K _key, unsigned int& position) { + DictSlot* GetSlotByKey(DictSlotsRef*& dictSlotsRef, const K _key, unsigned int& position) { unsigned int numSlots = ArraySize(dictSlotsRef.DictSlots); if (numSlots == 0) return NULL; @@ -137,7 +138,7 @@ class DictBase { /** * Returns slot by position. */ - DictSlot* GetSlotByPos(DictSlotsRef& dictSlotsRef, const unsigned int position) { + DictSlot* GetSlotByPos(DictSlotsRef*& dictSlotsRef, const unsigned int position) { return dictSlotsRef.DictSlots[position].IsUsed() ? &dictSlotsRef.DictSlots[position] : NULL; } @@ -335,9 +336,9 @@ class DictBase { protected: /** - * Array of DictSlots. + * Pointer to array of DictSlots. */ - DictSlotsRef _DictSlots_ref; + DictSlotsRef* _DictSlots_ref; DictOverflowListener overflow_listener; unsigned int overflow_listener_max_conflicts; diff --git a/DictObject.mqh b/DictObject.mqh index 4a851cb31..63db36d87 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -21,8 +21,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif #include "Convert.basic.h" @@ -105,6 +105,8 @@ class DictObject : public DictBase { } void Clear() { + _DictSlots_ref = new DictSlotsRef(); + for (unsigned int i = 0; i < (unsigned int)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots); ++i) { this PTR_DEREF _DictSlots_ref.DictSlots[i].SetFlags(0); } @@ -210,7 +212,7 @@ class DictObject : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, const K key, V& value, bool allow_resize) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeDict; else if (THIS_ATTR _mode != DictModeDict) { @@ -315,7 +317,7 @@ class DictObject : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, V& value) { if (this PTR_DEREF _mode == DictModeUnknown) this PTR_DEREF _mode = DictModeList; else if (this PTR_DEREF _mode != DictModeList) { @@ -354,6 +356,18 @@ class DictObject : public DictBase { 10, (int)((float)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } + public: + /** + * Ensures that there is at least given number of slots in dict. + */ + bool Reserve(int _size) { + if (_size <= ArraySize(THIS_ATTR _DictSlots_ref.DictSlots)) { + return true; + } + return Resize(_size); + } + + protected: /** * Shrinks or expands array of DictSlots. */ @@ -364,7 +378,7 @@ class DictObject : public DictBase { return true; } - DictSlotsRef new_DictSlots; + DictSlotsRef* new_DictSlots = new DictSlotsRef(); int i; @@ -389,7 +403,9 @@ class DictObject : public DictBase { // Freeing old DictSlots array. ArrayFree(this PTR_DEREF _DictSlots_ref.DictSlots); - this PTR_DEREF _DictSlots_ref = new_DictSlots; + delete THIS_ATTR _DictSlots_ref; + + THIS_ATTR _DictSlots_ref = new_DictSlots; return true; } diff --git a/DictSlotsRef.h b/DictSlotsRef.h index ff90c8b17..32da49a6e 100644 --- a/DictSlotsRef.h +++ b/DictSlotsRef.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -42,7 +42,8 @@ template class DictSlot; template -struct DictSlotsRef { +class DictSlotsRef { + public: ARRAY(DictSlot, DictSlots); // Incremental index for dict operating in list mode. @@ -61,14 +62,13 @@ struct DictSlotsRef { _avg_conflicts = 0; } - void operator=(DictSlotsRef& r) { - Util::ArrayCopy(DictSlots, r.DictSlots); - _list_index = r._list_index; - _num_used = r._num_used; - _num_conflicts = r._num_conflicts; - _avg_conflicts = r._avg_conflicts; - } + private: + /** + * Private assignment operator to avoid invalid copying. + */ + void operator=(DictSlotsRef& r) {} + public: /** * Adds given number of conflicts for an insert action, so we can store average number of conflicts. */ diff --git a/DictStruct.mqh b/DictStruct.mqh index 5f7ff54b3..5b5c6e1c9 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -90,6 +90,9 @@ class DictStruct : public DictBase { } void Clear() { + delete _DictSlots_ref; + _DictSlots_ref = new DictSlotsRef(); + for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); } @@ -256,7 +259,7 @@ class DictStruct : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, const K key, V& value, bool allow_resize) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeDict; else if (THIS_ATTR _mode != DictModeDict) { @@ -361,7 +364,7 @@ class DictStruct : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, V& value) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeList; else if (THIS_ATTR _mode != DictModeList) { @@ -398,6 +401,18 @@ class DictStruct : public DictBase { MathMax(10, (int)((float)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } + public: + /** + * Ensures that there is at least given number of slots in dict. + */ + bool Reserve(int _size) { + if (_size <= ArraySize(THIS_ATTR _DictSlots_ref.DictSlots)) { + return true; + } + return Resize(_size); + } + + protected: /** * Shrinks or expands array of DictSlots. */ @@ -407,7 +422,7 @@ class DictStruct : public DictBase { return true; } - DictSlotsRef new_DictSlots; + DictSlotsRef* new_DictSlots = new DictSlotsRef(); if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) { return false; @@ -432,7 +447,9 @@ class DictStruct : public DictBase { } } // Freeing old DictSlots array. - ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots); + ArrayFree(THIS_ATTR _DictSlots_ref PTR_DEREF DictSlots); + + delete THIS_ATTR _DictSlots_ref; THIS_ATTR _DictSlots_ref = new_DictSlots; diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 8a75ed9b4..7b8ad1c86 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -96,11 +96,11 @@ class IndicatorCandle : public Indicator { */ IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(INDI_CANDLE_HISTORY_SIZE) { + : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(THIS_PTR, INDI_CANDLE_HISTORY_SIZE) { Init(); } IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name), history(INDI_CANDLE_HISTORY_SIZE) { + : Indicator(_itype, _shift, _name), history(THIS_PTR, INDI_CANDLE_HISTORY_SIZE) { Init(); } @@ -361,7 +361,11 @@ class IndicatorCandle : public Indicator { * because otherwise, we could end up with OnCalculate() working on partial * history candles. */ - void OnDataSourceWillEmitEntries(ENUM_INDI_EMITTED_ENTRY_TYPE _type, int _num_entries) override {} + void OnDataSourceWillEmitEntries(ENUM_INDI_EMITTED_ENTRY_TYPE _type, int _num_entries) override { + if (_type == INDI_EMITTED_ENTRY_TYPE_CANDLE) { + idata.Reserve(_num_entries); + } + } /** * Returns value storage of given kind. diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index 4cbccc76c..1b45a6cac 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -34,7 +34,7 @@ #include "../Storage/ItemsHistory.h" /** - * Regenerates candles and updates exising candles from new ticks. Subclasses by IndicatorTf, IndicatorRenko. + * Regenerates candles and updates exising candles from new ticks. Subclassed by IndicatorTf, IndicatorRenko. */ template class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider> { diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 29c298696..f9bbfbb9e 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -25,8 +25,8 @@ #define INDICATOR_TICK_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -83,7 +83,7 @@ class IndicatorTick : public Indicator { */ IndicatorTick(string _symbol, const TS& _itparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_itparams, _idparams, _indi_src, _indi_mode) { + : Indicator(_itparams, _idparams, _indi_src, _indi_mode), history(THIS_PTR) { itparams = _itparams; if (_indi_src != NULL) { THIS_ATTR SetDataSource(_indi_src, _indi_mode); @@ -92,7 +92,7 @@ class IndicatorTick : public Indicator { Init(); } IndicatorTick(string _symbol, ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name) { + : Indicator(_itype, _shift, _name), history(THIS_PTR) { symbol = _symbol; Init(); } diff --git a/Indicators/Tf/Indi_TfMt.provider.h b/Indicators/Tf/Indi_TfMt.provider.h index 4af7095de..55e9cf0e3 100644 --- a/Indicators/Tf/Indi_TfMt.provider.h +++ b/Indicators/Tf/Indi_TfMt.provider.h @@ -153,6 +153,10 @@ class ItemsHistoryTfMtCandleProvider : public ItemsHistoryCandleProvider { int _num_copied = CopyRates(indi PTR_DEREF GetSymbol(), indi PTR_DEREF GetTf(), _end_shift, _count, _rates); ArrayResize(_out_arr, _num_copied); + // Acknowledging indicator that we will emit _num_copied number of candles. + _history PTR_DEREF GetIndicator() + PTR_DEREF OnDataSourceWillEmitEntries(INDI_EMITTED_ENTRY_TYPE_CANDLE, _num_copied); + for (int i = 0; i < _num_copied; ++i) { MqlRates _rate = _rates[i]; int _start_secs = (int)(long)_rate.time; diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index 5560e8ffc..1420a5076 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -100,6 +100,9 @@ class ItemsHistoryItemProvider : public Dynamic { */ template class ItemsHistory { + // Indicator the history is provided for. + IndicatorData* indi; + // Provides items from bound provider. Ref item_provider; @@ -136,13 +139,16 @@ class ItemsHistory { /** * Constructor */ - ItemsHistory(unsigned int _history_max_size = 0) - : history_max_size(_history_max_size), + ItemsHistory(IndicatorData* _indi, unsigned int _history_max_size = 0) + : indi(_indi), + history_max_size(_history_max_size), current_index(0), first_valid_index(0), first_valid_index_ever(0), last_valid_index(0), - peak_size(0) {} + peak_size(0) { + history.SetMaxConflicts(25); + } /** * Returns item provider. @@ -163,6 +169,11 @@ class ItemsHistory { } */ + /** + * Returns indicator the history is provided for. + */ + IndicatorData* GetIndicator() { return indi; } + /** * Returns maximum number of items that occupied the history. Could be used e.g., to determine how many bars could be * retrieved from history and past the history. From eb38f883b9625208dad6e292c9b71ba8249b847e Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 27 Jul 2024 21:01:36 +0100 Subject: [PATCH 122/123] Comments out Alert()/DebugBreak() for non-MQL --- Std.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Std.h b/Std.h index a5005583d..b31c8c581 100644 --- a/Std.h +++ b/Std.h @@ -406,6 +406,7 @@ struct AsSeriesReleaseEnsurer { AsSeriesReleaseEnsurer(int _num_buffs) : released(false), num_buffs(_num_buffs) {} void done(int _num_buffs) { if (_num_buffs != num_buffs) { +#ifdef __MQL__ Alert("You have acquired ", num_buffs, " buffers via ACQUIRE_BUFFER", num_buffs, "(), but now trying to release with mismatched RELEASE_BUFFER", _num_buffs, "()!"); DebugBreak(); @@ -415,15 +416,18 @@ struct AsSeriesReleaseEnsurer { Alert("You have used RELEASE_BUFFER", num_buffs, "() again which is not required!"); DebugBreak(); } +#endif released = true; } ~AsSeriesReleaseEnsurer() { +#ifdef __MQL__ if (!released) { Alert("You have used ACQUIRE_BUFFER", num_buffs, "() but didn't release buffer(s) via RELEASE_BUFFER", num_buffs, "() before returning from the scope!"); DebugBreak(); } +#endif } }; From 146a127a98f104d1dc73184021f04ec3ef13201f Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 5 Aug 2024 15:49:48 +0100 Subject: [PATCH 123/123] Fixes typo in devcontainer.json --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 84285b19d..48b74cfac 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -43,7 +43,7 @@ // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile "image": "mcr.microsoft.com/devcontainers/base:jammy", - "name": "EA31337" + "name": "EA31337", // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. "remoteUser": "vscode",