diff --git a/.github/workflows/test-indicators.yml b/.github/workflows/test-indicators.yml new file mode 100644 index 000000000..d49351f5e --- /dev/null +++ b/.github/workflows/test-indicators.yml @@ -0,0 +1,128 @@ +--- +name: Test Indicators + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Indicator**' + - 'Indicators/**' + - '.github/workflows/test-indicators.yml' + push: + paths: + - 'Indicator**' + - 'Indicators/**' + - '.github/workflows/test-indicators.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: 'Indicators/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' + + Indicators-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Indicators/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - Indi_AC.test + - Indi_AD.test + - Indi_ADX.test + - Indi_ADXW.test + - Indi_AMA.test + - Indi_AO.test + - Indi_ASI.test + - Indi_ATR.test + - Indi_Alligator.test + - Indi_AppliedPrice.test + - Indi_BWMFI.test + - Indi_BWZT.test + - Indi_Bands.test + - Indi_BearsPower.test + - Indi_BullsPower.test + - Indi_CCI.test + - Indi_CHO.test + - Indi_CHV.test + - Indi_ColorBars.test + - Indi_ColorCandlesDaily.test + - Indi_ColorLine.test + - Indi_CustomMovingAverage.test + - Indi_DEMA.test + - Indi_DeMarker.test + - Indi_Demo.test + - Indi_DetrendedPrice.test + - Indi_Drawer.test + - Indi_Envelopes.test + - Indi_Force.test + - Indi_FractalAdaptiveMA.test + - Indi_Fractals.test + - Indi_Gator.test + - Indi_HeikenAshi.test + - Indi_Ichimoku.test + - Indi_Killzones.test + - Indi_MA.test + - Indi_MACD.test + - Indi_MFI.test + - Indi_MassIndex.test + - Indi_Momentum.test + - Indi_OBV.test + - Indi_OsMA.test + - Indi_Pattern.test + - Indi_Pivot.test + - Indi_Price.test + # - Indi_PriceChannel.test + - Indi_PriceFeeder.test + - Indi_PriceVolumeTrend.test + - Indi_RS.test + - Indi_RSI.test + - Indi_RVI.test + - Indi_RateOfChange.test + - Indi_SAR.test + - Indi_StdDev.test + - Indi_Stochastic.test + - Indi_TEMA.test + - Indi_TRIX.test + - Indi_UltimateOscillator.test + - Indi_VIDYA.test + - Indi_VROC.test + - Indi_Volumes.test + - Indi_WPR.test + - Indi_WilliamsAD.test + # - Indi_ZigZag.test + # - Indi_ZigZagColor.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: 2020 + TestExpert: ${{ matrix.test }} diff --git a/.github/workflows/test-trade.yml b/.github/workflows/test-trade.yml new file mode 100644 index 000000000..744585359 --- /dev/null +++ b/.github/workflows/test-trade.yml @@ -0,0 +1,60 @@ +--- +name: Test Trade + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Trade/**.h' + - '.github/workflows/test-trade.yml' + push: + paths: + - 'Trade/**.h' + - '.github/workflows/test-trade.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: 'Trade/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' + + Trade-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Trade/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - TradeSignalTest + - TradeSignalManagerTest + steps: + - uses: actions/download-artifact@v2 + with: + name: files-ex4 + - name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + Script: ${{ matrix.test }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2bc531166..81d269619 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,6 +58,7 @@ jobs: - BufferStructTest - BufferTest - ChartTest + - CompileIndicatorsTest - ConditionTest - DatabaseTest - DrawIndicatorTest @@ -90,93 +91,6 @@ jobs: BtYears: 2020 TestExpert: ${{ matrix.test }} - Indicators-MQL4: - defaults: - run: - shell: bash - working-directory: Indicators/tests - needs: Compile - runs-on: ubuntu-latest - strategy: - matrix: - test: - - Indi_AC.test - - Indi_AD.test - # - Indi_ADX.test - - Indi_ADXW.test - - Indi_AMA.test - - Indi_AO.test - - Indi_ASI.test - - Indi_ATR.test - - Indi_Alligator.test - # - Indi_AppliedPrice.test - # - Indi_BWMFI.test - # - Indi_BWZT.test - # - Indi_Bands.test - # - Indi_BearsPower.test - # - Indi_BullsPower.test - # - Indi_CCI.test - # - Indi_CHO.test - # - Indi_CHV.test - # - Indi_ColorBars.test - # - Indi_ColorCandlesDaily.test - # - Indi_ColorLine.test - # - Indi_CustomMovingAverage.test - # - Indi_DEMA.test - # - Indi_DeMarker.test - # - Indi_Demo.test - # - Indi_DetrendedPrice.test - # - Indi_Drawer.test - # - Indi_Envelopes.test - # - Indi_Force.test - # - Indi_FractalAdaptiveMA.test - # - Indi_Fractals.test - # - Indi_Gator.test - # - Indi_HeikenAshi.test - # - Indi_Ichimoku.test - # - Indi_MA.test - # - Indi_MACD.test - # - Indi_MFI.test - # - Indi_MarketFacilitationIndex.test - # - Indi_MassIndex.test - # - Indi_Momentum.test - # - Indi_OBV.test - # - Indi_OsMA.test - # - Indi_Pattern.test - # - Indi_Pivot.test - # - Indi_Price.test - # - Indi_PriceChannel.test - # - Indi_PriceFeeder.test - # - Indi_PriceVolumeTrend.test - # - Indi_RS.test - # - Indi_RSI.test - # - Indi_RVI.test - # - Indi_RateOfChange.test - # - Indi_SAR.test - # - Indi_StdDev.test - # - Indi_Stochastic.test - # - Indi_TEMA.test - # - Indi_TRIX.test - # - Indi_UltimateOscillator.test - # - Indi_VIDYA.test - # - Indi_VROC.test - # - Indi_Volumes.test - # - Indi_WPR.test - # - Indi_WilliamsAD.test - # - Indi_ZigZag.test - # - Indi_ZigZagColor.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: 2020 - TestExpert: ${{ matrix.test }} - Scripts-MQL4: defaults: run: @@ -189,7 +103,6 @@ jobs: test: # - 3DTest - CollectionTest - - CompileIndicatorsTest - ConfigTest - ConvertTest - DateTimeTest @@ -236,3 +149,23 @@ jobs: with: Script: ${{ matrix.test }} RunOnFail: "exit 0" + + Trade-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Trade/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - TradeSignalTest + steps: + - uses: actions/download-artifact@v2 + with: + name: files-ex4 + - name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + Script: ${{ matrix.test }} diff --git a/Action.mqh b/Action.mqh index 85f9a3a9b..5ed379560 100644 --- a/Action.mqh +++ b/Action.mqh @@ -141,7 +141,7 @@ class Action { #ifdef INDICATOR_MQH case ACTION_TYPE_INDICATOR: if (Object::IsValid(_entry.obj)) { - _result = ((Indicator *)_entry.obj).ExecuteAction((ENUM_INDICATOR_ACTION)_entry.action_id); + _result = ((IndicatorBase *)_entry.obj).ExecuteAction((ENUM_INDICATOR_ACTION)_entry.action_id); } else { _result = false; _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); diff --git a/Bar.enum.h b/Bar.enum.h index 11c5c7911..e4c834f7e 100644 --- a/Bar.enum.h +++ b/Bar.enum.h @@ -38,5 +38,4 @@ enum ENUM_PP_TYPE { PP_FLOOR = 4, // Most basic and popular type of pivots used in Forex trading technical analysis PP_TOM_DEMARK = 5, // Tom DeMark's pivot point (predicted lows and highs of the period) PP_WOODIE = 6, // Woodie's pivot point are giving more weight to the Close price of the previous period - FINAL_ENUM_PP_TYPE_ENTRY }; diff --git a/Chart.define.h b/Chart.define.h index e0903d891..7f06e374a 100644 --- a/Chart.define.h +++ b/Chart.define.h @@ -27,6 +27,29 @@ /* Defines */ +// Define type of timeframe periods using bitwise values. +#define M1B (1 << M1) // 1 minute +#define M2B (1 << M2) // 2 minutes (non-standard) +#define M3B (1 << M3) // 3 minutes (non-standard) +#define M4B (1 << M4) // 4 minutes (non-standard) +#define M5B (1 << M5) // 5 minutes +#define M6B (1 << M6) // 6 minutes (non-standard) +#define M10B (1 << M10) // 10 minutes (non-standard) +#define M12B (1 << M12) // 12 minutes (non-standard) +#define M15B (1 << M15) // 15 minutes +#define M20B (1 << M20) // 20 minutes (non-standard) +#define M30B (1 << M30) // 30 minutes +#define H1B (1 << H1) // 1 hour +#define H2B (1 << H2) // 2 hours (non-standard) +#define H3B (1 << H3) // 3 hours (non-standard) +#define H4B (1 << H4) // 4 hours +#define H6B (1 << H6) // 6 hours (non-standard) +#define H8B (1 << H8) // 8 hours (non-standard) +#define H12B (1 << H12) // 12 hours (non-standard) +#define D1B (1 << D1) // Daily +#define W1B (1 << W1) // Weekly +#define MN1B (1 << MN1) // Monthly + #ifndef __MQL4__ // Chart. #define CHART_BAR 0 diff --git a/Chart.enum.h b/Chart.enum.h index f8ad5dc22..1bafacd19 100644 --- a/Chart.enum.h +++ b/Chart.enum.h @@ -88,20 +88,6 @@ enum ENUM_TIMEFRAMES_INDEX { FINAL_ENUM_TIMEFRAMES_INDEX = 21 }; -/* Define type of periods using bitwise operators. */ -enum ENUM_TIMEFRAMES_BITS { - M1B = 1 << 0, // =1: 1 minute - M5B = 1 << 1, // =2: 5 minutes - M15B = 1 << 2, // =4: 15 minutes - M30B = 1 << 3, // =8: 30 minutes - H1B = 1 << 4, // =16: 1 hour - H4B = 1 << 5, // =32: 4 hours - H8B = 1 << 6, // =64: 8 hours - D1B = 1 << 7, // =128: Daily - W1B = 1 << 8, // =256: Weekly - MN1B = 1 << 9, // =512: Monthly -}; - #ifndef __MQLBUILD__ /** * Defines chart timeframes. diff --git a/Chart.struct.static.h b/Chart.struct.static.h index b34665fa9..7034f7bef 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -277,10 +277,16 @@ struct ChartStatic { * * If local history is empty (not loaded), function returns 0. */ - static long iVolume(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, uint _shift = 0) { + static long iVolume(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) { #ifdef __MQL4__ - return ::iVolume(_symbol, _tf, _shift); // Same as: Volume[_shift] -#else // __MQL5__ + ResetLastError(); + long _volume = ::iVolume(_symbol, _tf, _shift); // Same as: Volume[_shift] + if (_LastError != ERR_NO_ERROR) { + _volume = EMPTY_VALUE; + ResetLastError(); + } + return _volume; +#else // __MQL5__ ARRAY(long, _arr); ArraySetAsSeries(_arr, true); return (_shift >= 0 && CopyTickVolume(_symbol, _tf, _shift, 1, _arr) > 0) ? _arr[0] : -1; diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 46c80f026..cc9e1d3e9 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -122,7 +122,7 @@ struct ChartTf { * @param * _tf ENUM_TIMEFRAMES_INDEX Specify timeframe index enum. */ - static ENUM_TIMEFRAMES IndexToTf(ENUM_TIMEFRAMES_INDEX index) { + static ENUM_TIMEFRAMES const IndexToTf(ENUM_TIMEFRAMES_INDEX index) { // @todo: Convert it into a loop and using tf constant, see: TfToIndex(). switch (index) { case M1: diff --git a/Condition.mqh b/Condition.mqh index 27183866b..915cbcd4e 100644 --- a/Condition.mqh +++ b/Condition.mqh @@ -167,7 +167,7 @@ class Condition { #ifdef INDICATOR_MQH case COND_TYPE_INDICATOR: if (Object::IsValid(_entry.obj)) { - _result = ((Indicator *)_entry.obj).CheckCondition((ENUM_INDICATOR_CONDITION)_entry.cond_id, _entry.args); + _result = ((IndicatorBase *)_entry.obj).CheckCondition((ENUM_INDICATOR_CONDITION)_entry.cond_id, _entry.args); } else { // Static method not supported. _result = false; diff --git a/Dict.enum.h b/Dict.enum.h new file mode 100644 index 000000000..33887918c --- /dev/null +++ b/Dict.enum.h @@ -0,0 +1,34 @@ +//+------------------------------------------------------------------+ +//| 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 Dicts's enums and defines. + */ + +#ifndef __MQL__ +// 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 diff --git a/Dict.mqh b/Dict.mqh index 2ca902d28..3fe692a31 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -112,7 +112,7 @@ class Dict : public DictBase { * Inserts or replaces value for a given key. */ bool Set(K key, V value) { - if (!InsertInto(_DictSlots_ref, key, value)) return false; + if (!InsertInto(_DictSlots_ref, key, value, true)) return false; return true; } @@ -204,7 +204,14 @@ class Dict : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V value) { + bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V value, bool allow_resize) { + // Will resize dict if there were performance problems before. + if (allow_resize && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + } + if (_mode == DictModeUnknown) _mode = DictModeDict; else if (_mode != DictModeDict) { @@ -227,8 +234,8 @@ class Dict : public DictBase { } if (keySlot == NULL) { - // We need to expand array of DictSlotsRef.DictSlots (by 25%). - if (!Resize(MathMax(10, (int)((float)ArraySize(dictSlotsRef.DictSlots) * 1.25)))) return false; + // We need to expand array of DictSlotsRef.DictSlots (by 25% by default). + if (!GrowUp()) return false; } } @@ -268,6 +275,8 @@ class Dict : public DictBase { // Slot overwrite is not needed. Using empty slot. ++dictSlotsRef._num_used; } + + dictSlotsRef.AddConflicts(_num_conflicts); } dictSlotsRef.DictSlots[position].key = key; @@ -289,8 +298,8 @@ class Dict : public DictBase { } if (dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { - // No DictSlotsRef.DictSlots available, we need to expand array of DictSlotsRef.DictSlots (by 25%). - if (!Resize(MathMax(10, (int)((float)ArraySize(dictSlotsRef.DictSlots) * 1.25)))) return false; + // No DictSlotsRef.DictSlots available, we need to expand array of DictSlotsRef.DictSlots. + if (!GrowUp()) return false; } unsigned int position = Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); @@ -309,10 +318,17 @@ class Dict : public DictBase { return true; } + /** + * 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)))); + } + /** * Shrinks or expands array of DictSlots. */ - bool Resize(unsigned int new_size) { + bool Resize(int new_size) { if (new_size <= MathMin(_DictSlots_ref._num_used, ArraySize(_DictSlots_ref.DictSlots))) { // We already use minimum number of slots possible. return true; @@ -322,7 +338,7 @@ class Dict : public DictBase { if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) return false; - unsigned int i; + int i; for (i = 0; i < new_size; ++i) { new_DictSlots.DictSlots[i].SetFlags(0); @@ -331,11 +347,11 @@ 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 < (unsigned int)ArraySize(_DictSlots_ref.DictSlots); ++i) { + for (i = 0; i < ArraySize(_DictSlots_ref.DictSlots); ++i) { if (!_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)) + if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].key, _DictSlots_ref.DictSlots[i].value, false)) return false; } else { if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].value)) return false; diff --git a/DictBase.mqh b/DictBase.mqh index 8976c3514..534f91e8a 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -26,6 +26,7 @@ // Includes. #include "Convert.mqh" +#include "Dict.enum.h" #include "DictIteratorBase.mqh" #include "DictSlot.mqh" #include "Serializer.mqh" @@ -43,6 +44,14 @@ enum ENUM_DICT_OVERFLOW_REASON { DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, }; +/** + * Dictionary flags. + */ +enum ENUM_DICT_FLAG { + DICT_FLAG_NONE = 0, + DICT_FLAG_FILL_HOLES_UNSORTED = 1, +}; + /** * Dictionary overflow listener. arguments are: * - ENUM_DICT_OVERFLOW_REASON overflow_reason @@ -65,11 +74,15 @@ class DictBase { // Whether Dict operates in yet uknown mode, as dict or as list. DictMode _mode; + // Dictionary flags. + int _flags; + public: DictBase() { _hash = rand(); _current_id = 0; _mode = DictModeUnknown; + _flags = 0; } /** @@ -92,6 +105,16 @@ class DictBase { const unsigned int GetSlotCount() const { return ArraySize(_DictSlots_ref.DictSlots); } + /** + * Adds flags to dict. + */ + void AddFlags(int flags) { _flags |= flags; } + + /** + * Checks whether dict have all given flags. + */ + bool HasFlags(int flags) { return (_flags & flags) == flags; } + DictSlot* GetSlot(const unsigned int index) { if (index >= GetSlotCount()) { // Index of out bounds. @@ -146,16 +169,50 @@ class DictBase { int GetMode() { return _mode; } + /** + * Removes value from the dictionary by the given iterator. Could be used to remove value on Dict with + * DICT_FLAG_FILL_HOLES_UNSORTED flag. + */ + void Unset(DictIteratorBase& iter) { + InternalUnset(iter.Key()); + if (HasFlags(DICT_FLAG_FILL_HOLES_UNSORTED)) { + // After incrementing, iterator will use moved slot. + iter.ShiftPosition(-1, true); + } + } + /** * Removes value from the dictionary by the given key (if exists). */ void Unset(const K key) { + if (HasFlags(DICT_FLAG_FILL_HOLES_UNSORTED)) { + Print( + "Unset on Dict with DICT_FLAG_FILL_HOLES_UNSORTED flag must be called by passing the iterator, instead of " + "the key. Thus way iterator will continue with proper value after incrementation."); + DebugBreak(); + return; + } + InternalUnset(key); + } + + /** + * Removes value from the dictionary by the given key (if exists). + */ + void InternalUnset(const K key) { if (ArraySize(_DictSlots_ref.DictSlots) == 0) { // Nothing to unset. return; } - unsigned int position = Hash(key) % ArraySize(_DictSlots_ref.DictSlots); + unsigned int position; + + if (GetMode() == DictModeList) { + // In list mode value index is the slot index. + position = (int)key; + } else { + position = Hash(key) % ArraySize(_DictSlots_ref.DictSlots); + } + unsigned int tries_left = ArraySize(_DictSlots_ref.DictSlots); while (tries_left-- > 0) { @@ -164,11 +221,32 @@ class DictBase { return; } - if (_DictSlots_ref.DictSlots[position].IsUsed() && _DictSlots_ref.DictSlots[position].HasKey() && - _DictSlots_ref.DictSlots[position].key == key) { - // Key perfectly matches, it indicates key exists in the dictionary. + bool _should_be_removed = false; + + if (_DictSlots_ref.DictSlots[position].IsUsed()) { + if (GetMode() == DictModeList) { + _should_be_removed = position == (int)key; + } else { + _should_be_removed = + _DictSlots_ref.DictSlots[position].HasKey() && _DictSlots_ref.DictSlots[position].key == key; + } + } + + if (_should_be_removed) { + // Key/index perfectly matches, it indicates key/index exists in the dictionary. _DictSlots_ref.DictSlots[position].RemoveFlags(DICT_SLOT_IS_USED); - --_DictSlots_ref._num_used; + + if (GetMode() == DictModeDict) { + // In List mode we don't decrement number of used elements. + --_DictSlots_ref._num_used; + } else if (HasFlags(DICT_FLAG_FILL_HOLES_UNSORTED)) { + // This is List mode and we need to fill this hole. + FillHoleUnsorted(position); + } + return; + } else if (GetMode() == DictModeList) { + Print("Internal error. Slot should have been removed!"); + DebugBreak(); return; } @@ -179,6 +257,24 @@ class DictBase { // No key found. } + /** + * Moves last slot to given one to fill the hole after removing the value. + */ + void FillHoleUnsorted(int _hole_slot_idx) { + // After moving last element to fill the hole we + if (_hole_slot_idx == Size() - 1) { + // We've just removed last element, thus don't need to do anything. + } else { + // Moving last slot into given one. + _DictSlots_ref.DictSlots[_hole_slot_idx] = _DictSlots_ref.DictSlots[Size() - 1]; + + // Marking last slot as unused. + _DictSlots_ref.DictSlots[Size() - 1].RemoveFlags(DICT_SLOT_IS_USED); + } + // One element less in the List-based Dict. + --_DictSlots_ref._num_used; + } + /** * Returns number of used DictSlots. */ diff --git a/DictIteratorBase.mqh b/DictIteratorBase.mqh index 330a3c84d..16fafb8a8 100644 --- a/DictIteratorBase.mqh +++ b/DictIteratorBase.mqh @@ -26,6 +26,7 @@ #endif #include "DictBase.mqh" +#include "DictSlotsRef.h" #include "SerializerConversions.h" template @@ -36,20 +37,23 @@ class DictIteratorBase { protected: DictBase* _dict; int _hash; - unsigned int _slotIdx; - unsigned int _index; + int _slotIdx; + int _index; + bool _invalid_until_incremented; public: /** * Constructor. */ - DictIteratorBase() : _dict(NULL) {} + DictIteratorBase() : _dict(NULL) { _invalid_until_incremented = false; } /** * Constructor. */ - DictIteratorBase(DictBase& dict, unsigned int slotIdx) - : _dict(&dict), _hash(dict.GetHash()), _slotIdx(slotIdx), _index(0) {} + DictIteratorBase(DictBase& dict, int slotIdx) + : _dict(&dict), _hash(dict.GetHash()), _slotIdx(slotIdx), _index(0) { + _invalid_until_incremented = false; + } /** * Copy constructor. @@ -58,7 +62,9 @@ class DictIteratorBase { : _dict(right._dict), _hash(right._dict ? right._dict.GetHash() : 0), _slotIdx(right._slotIdx), - _index(right._index) {} + _index(right._index) { + _invalid_until_incremented = false; + } /** * Iterator incrementation operator. @@ -67,6 +73,7 @@ class DictIteratorBase { // Going to the next slot. ++_slotIdx; ++_index; + _invalid_until_incremented = false; DictSlot* slot = _dict.GetSlot(_slotIdx); @@ -83,15 +90,31 @@ class DictIteratorBase { bool HasKey() { return _dict.GetSlot(_slotIdx).HasKey(); } - K Key() { return _dict.GetMode() == DictModeList ? (K)_slotIdx : _dict.GetSlot(_slotIdx).key; } + K Key() { + CheckValidity(); + return _dict.GetMode() == DictModeList ? (K)_slotIdx : _dict.GetSlot(_slotIdx).key; + } string KeyAsString(bool includeQuotes = false) { return HasKey() ? SerializerConversions::ValueToString(Key(), includeQuotes) : ""; } - unsigned int Index() { return _index; } + int Index() { + CheckValidity(); + return _index; + } + + V Value() { + CheckValidity(); + return _dict.GetSlot(_slotIdx).value; + } - V Value() { return _dict.GetSlot(_slotIdx).value; } + void CheckValidity() { + if (_invalid_until_incremented) { + Alert("Iterator must be incremented before using it again!"); + DebugBreak(); + } + } bool IsValid() { return _dict != NULL; } @@ -108,22 +131,10 @@ class DictIteratorBase { return _index == _dict.Size() - 1; } -}; - -template -class DictSlot; - -template -struct DictSlotsRef { - DictSlot DictSlots[]; - - // Incremental index for dict operating in list mode. - unsigned int _list_index; - - unsigned int _num_used; - DictSlotsRef() { - _list_index = 0; - _num_used = 0; + void ShiftPosition(int shift, bool invalid_until_incremented = false) { + _slotIdx += shift; + _index += shift; + _invalid_until_incremented |= invalid_until_incremented; } }; diff --git a/DictObject.mqh b/DictObject.mqh index 25bcba852..4491707cb 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -114,7 +114,7 @@ class DictObject : public DictBase { * Inserts or replaces value for a given key. */ bool Set(K key, V& value) { - if (!InsertInto(_DictSlots_ref, key, value)) return false; + if (!InsertInto(_DictSlots_ref, key, value, true)) return false; return true; } @@ -191,7 +191,14 @@ class DictObject : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value) { + bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { + // Will resize dict if there were performance problems before. + if (allow_resize && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + } + if (_mode == DictModeUnknown) _mode = DictModeDict; else if (_mode != DictModeDict) { @@ -214,8 +221,8 @@ class DictObject : public DictBase { } if (keySlot == NULL) { - // We need to expand array of DictSlotsRef.DictSlots (by 25%). - if (!Resize(MathMax(10, (int)((float)ArraySize(dictSlotsRef.DictSlots) * 1.25)))) return false; + // We need to expand array of DictSlotsRef.DictSlots. + if (!GrowUp()) return false; } } @@ -255,6 +262,8 @@ class DictObject : public DictBase { // Slot overwrite is not needed. Using empty slot. ++dictSlotsRef._num_used; } + + dictSlotsRef.AddConflicts(_num_conflicts); } dictSlotsRef.DictSlots[position].key = key; @@ -276,8 +285,8 @@ class DictObject : public DictBase { } if (dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { - // No DictSlotsRef.DictSlots available, we need to expand array of DictSlotsRef.DictSlots (by 25%). - if (!Resize(MathMax(10, (int)((float)ArraySize(dictSlotsRef.DictSlots) * 1.25)))) return false; + // No DictSlotsRef.DictSlots available, we need to expand array of DictSlotsRef.DictSlots. + if (!GrowUp()) return false; } unsigned int position = Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); @@ -296,10 +305,17 @@ class DictObject : public DictBase { return true; } + /** + * 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)))); + } + /** * Shrinks or expands array of DictSlots. */ - bool Resize(unsigned int new_size) { + bool Resize(int new_size) { if (new_size <= MathMin(_DictSlots_ref._num_used, ArraySize(_DictSlots_ref.DictSlots))) { // We already use minimum number of slots possible. return true; @@ -307,14 +323,20 @@ class DictObject : public DictBase { DictSlotsRef new_DictSlots; + int i; + if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) return false; + for (i = 0; i < new_size; ++i) { + new_DictSlots.DictSlots[i].SetFlags(0); + } + // Copies entire array of DictSlots into new array of DictSlots. Hashes will be rehashed. - for (unsigned int i = 0; i < (unsigned int)ArraySize(_DictSlots_ref.DictSlots); ++i) { + for (i = 0; i < ArraySize(_DictSlots_ref.DictSlots); ++i) { if (!_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)) + if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].key, _DictSlots_ref.DictSlots[i].value, false)) return false; } else { if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].value)) return false; diff --git a/DictSlotsRef.h b/DictSlotsRef.h new file mode 100644 index 000000000..140140c49 --- /dev/null +++ b/DictSlotsRef.h @@ -0,0 +1,72 @@ +//+------------------------------------------------------------------+ +//| 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 + * DictSlotsRef struct. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "Dict.enum.h" + +template +class DictSlot; + +template +struct DictSlotsRef { + DictSlot DictSlots[]; + + // Incremental index for dict operating in list mode. + int _list_index; + + int _num_used; + + int _num_conflicts; + + float _avg_conflicts; + + DictSlotsRef() { + _list_index = 0; + _num_used = 0; + _num_conflicts = 0; + _avg_conflicts = 0; + } + + /** + * Adds given number of conflicts for an insert action, so we can store average number of conflicts. + */ + void AddConflicts(int num) { + if (num != 0) { + _avg_conflicts += float(num) / ++_num_conflicts; + } + } + + /** + * Checks whethere there is no performance problems with slots. + */ + bool IsPerformant() { return _avg_conflicts < DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS; } +}; diff --git a/DictStruct.mqh b/DictStruct.mqh index 9c9647cdf..99d39cc90 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -126,7 +126,7 @@ class DictStruct : public DictBase { * Inserts or replaces value for a given key. */ bool Set(K key, V& value) { - if (!InsertInto(_DictSlots_ref, key, value)) return false; + if (!InsertInto(_DictSlots_ref, key, value, true)) return false; return true; } @@ -234,7 +234,14 @@ class DictStruct : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value) { + bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { + // Will resize dict if there were performance problems before. + if (allow_resize && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + } + if (_mode == DictModeUnknown) _mode = DictModeDict; else if (_mode != DictModeDict) { @@ -256,8 +263,8 @@ class DictStruct : public DictBase { } if (keySlot == NULL) { - // We need to expand array of DictSlotsRef.DictSlots (by 25%). - if (!Resize(MathMax(10, (int)((float)ArraySize(dictSlotsRef.DictSlots) * 1.25)))) return false; + // We need to expand array of DictSlotsRef.DictSlots. + if (!GrowUp()) return false; } } @@ -297,6 +304,8 @@ class DictStruct : public DictBase { // Slot overwrite is not needed. Using empty slot. ++dictSlotsRef._num_used; } + + dictSlotsRef.AddConflicts(_num_conflicts); } dictSlotsRef.DictSlots[position].key = key; @@ -317,8 +326,8 @@ class DictStruct : public DictBase { } if (dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { - // No DictSlotsRef.DictSlots available, we need to expand array of DictSlotsRef.DictSlots (by 25%). - if (!Resize(MathMax(10, (int)((float)ArraySize(dictSlotsRef.DictSlots) * 1.25)))) return false; + // No DictSlotsRef.DictSlots available, we need to expand array of DictSlotsRef.DictSlots. + if (!GrowUp()) return false; } unsigned int position = Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); @@ -337,10 +346,17 @@ class DictStruct : public DictBase { return true; } + /** + * 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)))); + } + /** * Shrinks or expands array of DictSlots. */ - bool Resize(unsigned int new_size) { + bool Resize(int new_size) { if (new_size <= MathMin(_DictSlots_ref._num_used, ArraySize(_DictSlots_ref.DictSlots))) { // We already use minimum number of slots possible. return true; @@ -350,12 +366,18 @@ class DictStruct : public DictBase { if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) return false; + int i; + + for (i = 0; i < new_size; ++i) { + new_DictSlots.DictSlots[i].SetFlags(0); + } + // Copies entire array of DictSlots into new array of DictSlots. Hashes will be rehashed. - for (unsigned int i = 0; i < (unsigned int)ArraySize(_DictSlots_ref.DictSlots); ++i) { + for (i = 0; i < ArraySize(_DictSlots_ref.DictSlots); ++i) { if (!_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)) + if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].key, _DictSlots_ref.DictSlots[i].value, false)) return false; } else { if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].value)) return false; diff --git a/Draw.mqh b/Draw.mqh index bcfcfe647..350f89bf6 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -31,6 +31,7 @@ class Draw; // Includes. #include "Chart.mqh" +#include "Data.define.h" #ifndef __MQL4__ // Defines macros (for MQL4 backward compatibility). diff --git a/DrawIndicator.mqh b/DrawIndicator.mqh index 35e5557b7..7017a81eb 100644 --- a/DrawIndicator.mqh +++ b/DrawIndicator.mqh @@ -36,7 +36,7 @@ #include "Object.mqh" // Forward declaration. -class Indicator; +class IndicatorBase; class DrawPoint { public: @@ -56,7 +56,7 @@ class DrawIndicator { protected: color color_line; Draw* draw; - Indicator* indi; + IndicatorBase* indi; public: // Object variables. @@ -67,8 +67,8 @@ class DrawIndicator { /** * Class constructor. */ - DrawIndicator(Indicator* _indi) : indi(_indi) { - color_line = Object::IsValid(_indi) ? _indi.GetParams().indi_color : clrRed; + DrawIndicator(IndicatorBase* _indi) : indi(_indi) { + // color_line = Object::IsValid(_indi) ? _indi.GetParams().indi_color : clrRed; // @fixme draw = new Draw(); } diff --git a/EA.mqh b/EA.mqh index ee5d6ce23..9a602ef76 100644 --- a/EA.mqh +++ b/EA.mqh @@ -49,6 +49,8 @@ #include "Task.mqh" #include "Terminal.mqh" #include "Trade.mqh" +#include "Trade/TradeSignal.h" +#include "Trade/TradeSignalManager.h" class EA { protected: @@ -61,7 +63,6 @@ class EA { // Data variables. BufferStruct data_chart; - BufferStruct> strat_signals; BufferStruct data_symbol; Dict ddata; // Custom user data. Dict idata; // Custom user data. @@ -72,6 +73,7 @@ class EA { EAParams eparams; EAProcessResult eresults; EAState estate; + TradeSignalManager tsm; public: /** @@ -126,6 +128,56 @@ class EA { return trade.GetByKey(_symbol != NULL ? _symbol : _Symbol).Get(_state); } + /** + * Gets a strategy's signal entry. + * + * @param Strategy _strat + * Reference to strategy to get the signal from. + * @param bool _trade_allowed + * True if trade is allowed. + * @param int _shift + * Bar shift. + * + * @return + * Returns TradeSignalEntry struct. + */ + TradeSignalEntry GetStrategySignalEntry(Strategy *_strat, bool _trade_allowed = true, int _shift = -1) { + // float _bf = 1.0; + float _scl = _strat.Get(STRAT_PARAM_SCL); + float _sol = _strat.Get(STRAT_PARAM_SOL); + int _scfm = _strat.Get(STRAT_PARAM_SCFM); + int _scft = _strat.Get(STRAT_PARAM_SCFT); + int _scm = _strat.Get(STRAT_PARAM_SCM); + int _sob = _strat.Get(STRAT_PARAM_SOB); + int _sofm = _strat.Get(STRAT_PARAM_SOFM); + int _soft = _strat.Get(STRAT_PARAM_SOFT); + int _som = _strat.Get(STRAT_PARAM_SOM); + int _ss = _shift >= 0 ? _shift : _strat.Get(STRAT_PARAM_SHIFT); + unsigned int _signals = 0; + // sparams.Get(STRAT_PARAM_WEIGHT)); + if (_trade_allowed) { + // Process boost factor and lot size. + // sresult.SetBoostFactor(sparams.IsBoosted() ? SignalOpenBoost(ORDER_TYPE_BUY, _sob) : 1.0f); + // sresult.SetLotSize(sparams.GetLotSizeWithFactor()); + // Process open signals when trade is allowed. + _signals |= _strat.SignalOpen(ORDER_TYPE_BUY, _som, _sol, _ss) ? SIGNAL_OPEN_BUY_MAIN : 0; + _signals |= !_strat.SignalOpenFilterMethod(ORDER_TYPE_BUY, _sofm) ? SIGNAL_OPEN_BUY_FILTER : 0; + _signals |= _strat.SignalOpen(ORDER_TYPE_SELL, _som, _sol, _ss) ? SIGNAL_OPEN_SELL_MAIN : 0; + _signals |= !_strat.SignalOpenFilterMethod(ORDER_TYPE_SELL, _sofm) ? SIGNAL_OPEN_SELL_FILTER : 0; + _signals |= !_strat.SignalOpenFilterTime(_soft) ? SIGNAL_OPEN_TIME_FILTER : 0; + } + // Process close signals. + _signals |= _strat.SignalClose(ORDER_TYPE_BUY, _scm, _scl, _ss) ? SIGNAL_CLOSE_BUY_MAIN : 0; + _signals |= !_strat.SignalCloseFilter(ORDER_TYPE_BUY, _scfm) ? SIGNAL_CLOSE_BUY_FILTER : 0; + _signals |= _strat.SignalClose(ORDER_TYPE_SELL, _scm, _scl, _ss) ? SIGNAL_CLOSE_SELL_MAIN : 0; + _signals |= !_strat.SignalCloseFilter(ORDER_TYPE_SELL, _scfm) ? SIGNAL_CLOSE_SELL_FILTER : 0; + _signals |= !_strat.SignalCloseFilterTime(_scfm) ? SIGNAL_OPEN_TIME_FILTER : 0; + TradeSignalEntry _sentry(_signals, _strat.Get(STRAT_PARAM_TF), _strat.Get(STRAT_PARAM_ID)); + _sentry.Set(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_STRENGTH), _strat.SignalOpen(_sofm, _sol, _ss)); + _sentry.Set(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_TIME), ::TimeGMT()); + return _sentry; + } + /* Setters */ /** @@ -192,32 +244,34 @@ class EA { bool _result = true; int _last_error = ERR_NO_ERROR; ResetLastError(); - DictStruct _ds = strat_signals.GetByKey(_tick.time); - for (DictStructIterator _dsi = _ds.Begin(); _dsi.IsValid(); ++_dsi) { - StrategySignal _signal = _dsi.Value(); - if (_signal.CheckSignals(STRAT_SIGNAL_PROCESSED)) { + for (DictObjectIterator _iter = tsm.GetIterSignalsActive(); _iter.IsValid(); ++_iter) { + bool _result_local = true; + TradeSignal *_signal = _iter.Value(); + if (_signal.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_PROCESSED))) { // Ignores already processed signals. - // @todo: Not in use yet. continue; } - Strategy *_strat = _signal.GetStrategy(); Trade *_trade = trade.GetByKey(_Symbol); + Strategy *_strat = + strats.GetByKey(_signal.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_MAGIC_ID))).Ptr(); if (_trade.Get(TRADE_STATE_ORDERS_ACTIVE)) { float _sig_close = _signal.GetSignalClose(); + string _comment_close = + _strat != NULL && _sig_close != 0.0f ? _strat.GetOrderCloseComment() : __FUNCTION_LINE__; // Check if we should close the orders. if (_sig_close >= 0.5f) { // Close signal for buy order. - _result &= _trade.OrdersCloseViaProp2( - ORDER_MAGIC, _strat.Get(STRAT_PARAM_ID), ORDER_TYPE, ORDER_TYPE_BUY, MATH_COND_EQ, - ORDER_REASON_CLOSED_BY_SIGNAL, _strat.GetOrderCloseComment()); + _trade.OrdersCloseViaProp2( + ORDER_MAGIC, _signal.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_MAGIC_ID)), ORDER_TYPE, + ORDER_TYPE_BUY, MATH_COND_EQ, ORDER_REASON_CLOSED_BY_SIGNAL, _comment_close); // Buy orders closed. _strat.OnOrderClose(ORDER_TYPE_BUY); } if (_sig_close <= -0.5f) { // Close signal for sell order. - _result &= _trade.OrdersCloseViaProp2( - ORDER_MAGIC, _strat.Get(STRAT_PARAM_ID), ORDER_TYPE, ORDER_TYPE_SELL, MATH_COND_EQ, - ORDER_REASON_CLOSED_BY_SIGNAL, _strat.GetOrderCloseComment()); + _trade.OrdersCloseViaProp2( + ORDER_MAGIC, _signal.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_MAGIC_ID)), ORDER_TYPE, + ORDER_TYPE_SELL, MATH_COND_EQ, ORDER_REASON_CLOSED_BY_SIGNAL, _comment_close); // Sell orders closed. _strat.OnOrderClose(ORDER_TYPE_SELL); } @@ -225,15 +279,17 @@ class EA { if (_trade_allowed) { float _sig_open = _signal.GetSignalOpen(); unsigned int _sig_f = eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_SIGNAL_FILTER)); + string _comment_open = _strat != NULL && _sig_open != 0.0f ? _strat.GetOrderOpenComment() : __FUNCTION_LINE__; // Open orders on signals. if (_sig_open >= 0.5f) { // Open signal for buy. // When H1 or H4 signal filter is enabled, do not open minute-based orders on opposite or neutral signals. - if (_sig_f == 0 || GetSignalOpenFiltered(_signal, _sig_f) >= 0.5f) { - _strat.Set(TRADE_PARAM_ORDER_COMMENT, _strat.GetOrderOpenComment("B:")); + if (_sig_f == 0) { // @fixme: || GetSignalOpenFiltered(_signal, _sig_f) >= 0.5f) { + _strat.Set(TRADE_PARAM_ORDER_COMMENT, _comment_open); // Buy order open. - _result &= TradeRequest(ORDER_TYPE_BUY, _Symbol, _strat); - if (_result && eparams.CheckSignalFilter(STRUCT_ENUM(EAParams, EA_PARAM_SIGNAL_FILTER_FIRST))) { + _result_local &= TradeRequest(ORDER_TYPE_BUY, _Symbol, _strat); + if (_result_local && eparams.CheckSignalFilter(STRUCT_ENUM(EAParams, EA_PARAM_SIGNAL_FILTER_FIRST))) { + _signal.Set(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_PROCESSED), true); break; } } @@ -241,16 +297,19 @@ class EA { if (_sig_open <= -0.5f) { // Open signal for sell. // When H1 or H4 signal filter is enabled, do not open minute-based orders on opposite or neutral signals. - if (_sig_f == 0 || GetSignalOpenFiltered(_signal, _sig_f) <= -0.5f) { - _strat.Set(TRADE_PARAM_ORDER_COMMENT, _strat.GetOrderOpenComment("S:")); + if (_sig_f == 0) { // @fixme: || GetSignalOpenFiltered(_signal, _sig_f) <= -0.5f) { + _strat.Set(TRADE_PARAM_ORDER_COMMENT, _comment_open); // Sell order open. - _result &= TradeRequest(ORDER_TYPE_SELL, _Symbol, _strat); - if (_result && eparams.CheckSignalFilter(STRUCT_ENUM(EAParams, EA_PARAM_SIGNAL_FILTER_FIRST))) { + _result_local &= TradeRequest(ORDER_TYPE_SELL, _Symbol, _strat); + if (_result_local && eparams.CheckSignalFilter(STRUCT_ENUM(EAParams, EA_PARAM_SIGNAL_FILTER_FIRST))) { + _signal.Set(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_PROCESSED), true); break; } } } - if (!_result) { + if (_result_local) { + _signal.Set(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_PROCESSED), true); + } else { _last_error = GetLastError(); switch (_last_error) { case ERR_NOT_ENOUGH_MEMORY: @@ -262,13 +321,14 @@ class EA { } } } + _result &= _result_local; } _last_error = GetLastError(); if (_last_error > 0) { logger.Warning(StringFormat("Processing signals failed! Code: %d", _last_error), __FUNCTION_LINE__); } - // Remove signals after processing. - strat_signals.Unset(_tick.time); + // Refresh signals after processing. + tsm.Refresh(); return _result && _last_error == 0; } @@ -328,20 +388,22 @@ class EA { _can_trade &= _can_trade && !_strat.IsSuspended(); _can_trade &= _can_trade && !_strat.CheckCondition(STRAT_COND_TRADE_COND, TRADE_COND_HAS_STATE, TRADE_STATE_TRADE_CANNOT); - StrategySignal _signal = _strat.ProcessSignals(_can_trade); - if (_signal.GetSignalClose() != _signal.GetSignalOpen()) { - SignalAdd(_signal, _tick.time); + TradeSignalEntry _sentry = GetStrategySignalEntry(_strat, _can_trade, _strat.Get(STRAT_PARAM_SHIFT)); + if (_sentry.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_SIGNALS)) > 0) { + TradeSignal _signal(_sentry); + if (_signal.GetSignalClose() != _signal.GetSignalOpen()) { + tsm.SignalAdd(_signal); //, _tick.time); + } + StgProcessResult _strat_result = _strat.GetProcessResult(); + eresults.last_error = fmax(eresults.last_error, _strat_result.last_error); + eresults.stg_errored += (int)_strat_result.last_error > ERR_NO_ERROR; + eresults.stg_processed++; } - StgProcessResult _strat_result = _strat.GetProcessResult(); - eresults.last_error = fmax(eresults.last_error, _strat_result.last_error); - eresults.stg_errored += (int)_strat_result.last_error > ERR_NO_ERROR; - eresults.stg_processed++; } } } // Process all strategies' signals and trigger trading orders. - ProcessSignals(GetMarket().GetLastTick(), - eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_SIGNAL_FILTER))); + ProcessSignals(_tick, eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_SIGNAL_FILTER))); if (eresults.last_error > ERR_NO_ERROR) { // On error, print logs. logger.Flush(); @@ -373,7 +435,7 @@ class EA { if (eparams.CheckFlagDataStore(EA_DATA_STORE_INDICATOR)) { for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { Strategy *_strati = iter.Value().Ptr(); - Indicator *_indi = _strati.GetParams().GetIndicator(); + IndicatorBase *_indi = _strati.GetIndicator(); if (_indi != NULL) { ENUM_TIMEFRAMES _itf = _indi.GetParams().tf.GetTf(); IndicatorDataEntry _ientry = _indi.GetEntry(); @@ -574,6 +636,7 @@ class EA { * @return * Returns 1 when buy signal exists, -1 for sell, otherwise 0 for neutral signal. */ + /* @fixme: Convert into TradeSignal format. float GetSignalOpenFiltered(StrategySignal &_signal, unsigned int _sf) { float _result = _signal.GetSignalOpen(); ENUM_TIMEFRAMES _sig_tf = _signal.Get(STRUCT_ENUM(StrategySignal, STRATEGY_SIGNAL_PROP_TF)); @@ -600,15 +663,7 @@ class EA { } return _result; } - - /** - * Adds strategy's signal for further processing. - */ - bool SignalAdd(StrategySignal &_signal, long _time) { - DictStruct _ds = strat_signals.GetByKey(_time); - _ds.Push(_signal); - return strat_signals.Set(_time, _ds); - } + */ /* Tasks */ @@ -742,7 +797,9 @@ class EA { Order *_order = oiter.Value().Ptr(); if (!_order.ShouldUpdate()) { continue; - } else if (_order.IsClosed()) { + } + _order.ProcessConditions(); + if (_order.IsClosed()) { _trade.OrderMoveToHistory(_order); continue; } @@ -1042,6 +1099,7 @@ class EA { } if ((estate.new_periods & DATETIME_HOUR) != 0) { // New hour started. + tsm.Refresh(); } if ((estate.new_periods & DATETIME_DAY) != 0) { // New day started. @@ -1052,7 +1110,6 @@ class EA { } if ((estate.new_periods & DATETIME_WEEK) != 0) { // New week started. - strat_signals.Clear(); } if ((estate.new_periods & DATETIME_MONTH) != 0) { // New month started. diff --git a/EA.struct.h b/EA.struct.h index aa36c2e5e..cc8cda2ba 100644 --- a/EA.struct.h +++ b/EA.struct.h @@ -222,16 +222,16 @@ struct EAProcessResult { /* Defines EA state variables. */ struct EAState { - unsigned short flags; // Action flags. + unsigned int flags; // Action flags. unsigned int new_periods; // Started periods. DateTime last_updated; // Last updated. // Constructor. - EAState() { AddFlags(EA_STATE_FLAG_ACTIVE | EA_STATE_FLAG_ENABLED); } + EAState() { EAState::AddFlags(EA_STATE_FLAG_ACTIVE | EA_STATE_FLAG_ENABLED); } // Struct methods. // Flag methods. - bool CheckFlag(unsigned short _flag) { return bool(flags & _flag); } - void AddFlags(unsigned short _flags) { flags |= _flags; } - void RemoveFlags(unsigned short _flags) { flags &= ~_flags; } + bool CheckFlag(unsigned int _flag) { return bool(flags & _flag); } + void AddFlags(unsigned int _flags) { flags |= _flags; } + void RemoveFlags(unsigned int _flags) { flags &= ~_flags; } void SetFlag(ENUM_EA_STATE_FLAGS _flag, bool _value) { if (_value) { AddFlags(_flag); @@ -239,7 +239,7 @@ struct EAState { RemoveFlags(_flag); } } - void SetFlags(unsigned short _flags) { flags = _flags; } + void SetFlags(unsigned int _flags) { flags = _flags; } // State methods. bool IsActive() { return CheckFlag(EA_STATE_FLAG_ACTIVE); } bool IsConnected() { return CheckFlag(EA_STATE_FLAG_CONNECTED); } diff --git a/Indicator.define.h b/Indicator.define.h index 40e0d811c..08c221d64 100644 --- a/Indicator.define.h +++ b/Indicator.define.h @@ -41,14 +41,14 @@ return EMPTY_VALUE; \ } \ } \ - int _bars_calc = BarsCalculated(_handle); \ + 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) { \ + if (::CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { \ return EMPTY_VALUE; \ } \ return _res[0]; diff --git a/Indicator.enum.h b/Indicator.enum.h index 1ed25def6..fe21abd88 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -82,6 +82,7 @@ enum ENUM_INDICATOR_TYPE { INDI_GATOR, // Gator Oscillator INDI_HEIKENASHI, // Heiken Ashi INDI_ICHIMOKU, // Ichimoku Kinko Hyo + INDI_KILLZONES, // Killzones INDI_MA, // Moving Average INDI_MACD, // MACD INDI_MA_ON_PRICE, // Moving Average (on Price). @@ -127,10 +128,12 @@ enum ENUM_INDICATOR_TYPE { /* Defines type of source data for indicator. */ enum ENUM_IDATA_SOURCE_TYPE { - IDATA_BUILTIN, // Platform built-in + IDATA_BUILTIN = 0, // Platform built-in + IDATA_CHART, // Chart calculation IDATA_ICUSTOM, // iCustom: Custom indicator file IDATA_ICUSTOM_LEGACY, // iCustom: Custom, legacy, provided by MT indicator file IDATA_INDICATOR, // OnIndicator: Another indicator as a source of data + IDATA_ONCALCULATE, // OnCalculate: Custom calculation function IDATA_MATH // Math-based indicator }; diff --git a/Indicator.mqh b/Indicator.mqh index b13030b5f..3717c10aa 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -39,6 +39,7 @@ class Chart; #include "Indicator.struct.h" #include "Indicator.struct.serialize.h" #include "Indicator.struct.signal.h" +#include "IndicatorBase.h" #include "Math.h" #include "Object.mqh" #include "Refs.mqh" @@ -49,34 +50,14 @@ class Chart; #include "Storage/ValueStorage.indicator.h" #include "Storage/ValueStorage.native.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 - /** * Class to deal with indicators. */ -class Indicator : public Chart { +template +class Indicator : public IndicatorBase { protected: // Structs. - BufferStruct idata; - DrawIndicator* draw; - IndicatorParams iparams; - IndicatorState istate; - void* mydata; - bool is_feeding; // Whether FeedHistoryEntries is already working. - bool is_fed; // Whether FeedHistoryEntries already done its job. - DictStruct> indicators; // Indicators list keyed by id. - bool indicator_builtin; - ARRAY(ValueStorage*, value_storages); - IndicatorCalculateCache cache; + TS iparams; public: /* Indicator enumerations */ @@ -96,20 +77,22 @@ class Indicator : public Chart { /** * Class constructor. */ - Indicator() {} - Indicator(IndicatorParams& _iparams) : Chart(_iparams.GetTf()), draw(NULL), is_feeding(false), is_fed(false) { + Indicator(const TS& _iparams, IndicatorBase* _indi_src = NULL, bool _indi_managed = true, int _indi_mode = 0) + : IndicatorBase(_iparams.GetTf(), NULL) { iparams = _iparams; SetName(_iparams.name != "" ? _iparams.name : EnumToString(iparams.itype)); + if (_indi_src != NULL) { + SetDataSource(_indi_src, _indi_managed, _indi_mode); + } Init(); } - Indicator(const IndicatorParams& _iparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) - : Chart(_tf), draw(NULL), is_feeding(false), is_fed(false) { + 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 = "") - : Chart(_tf), draw(NULL), is_feeding(false), is_fed(false) { + : IndicatorBase(_tf) { iparams.SetIndicatorType(_itype); iparams.SetShift(_shift); SetName(_name != "" ? _name : EnumToString(iparams.itype)); @@ -120,22 +103,15 @@ class Indicator : public Chart { * Class deconstructor. */ ~Indicator() { - ReleaseHandle(); DeinitDraw(); - for (int i = 0; i < ArraySize(value_storages); ++i) { - if (value_storages[i] != NULL) { - delete value_storages[i]; - } - } - - if (iparams.indi_data_source != NULL && iparams.indi_managed) { + if (indi_src != NULL && iparams.indi_managed) { // User selected custom, managed data source. - if (CheckPointer(iparams.indi_data_source) == POINTER_INVALID) { + if (CheckPointer(indi_src) == POINTER_INVALID) { DebugBreak(); } - delete iparams.indi_data_source; - iparams.indi_data_source = NULL; + delete indi_src; + indi_src = NULL; } } @@ -143,6 +119,18 @@ class Indicator : public Chart { bool Init() { ArrayResize(value_storages, iparams.GetMaxModes()); + switch (iparams.GetDataSourceType()) { + case IDATA_BUILTIN: + break; + case IDATA_ICUSTOM: + break; + case IDATA_INDICATOR: + if (indi_src == NULL) { + // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); + // SetDataSource(_indi_price, true, PRICE_OPEN); + } + break; + } return InitDraw(); } @@ -151,7 +139,7 @@ class Indicator : public Chart { */ bool InitDraw() { if (iparams.is_draw && !Object::IsValid(draw)) { - draw = new DrawIndicator(&this); + draw = new DrawIndicator(THIS_PTR); draw.SetColorLine(iparams.indi_color); } return iparams.is_draw; @@ -168,124 +156,14 @@ class Indicator : public Chart { } } - /* Defines MQL backward compatible methods */ - - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(DUMMY); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a COMMA _b); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, int _mode, - int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, int _mode, - int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, - int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, - int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, - G _g, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, - G _g, H _h, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, - G _g, H _h, I _i, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, - G _g, H _h, I _i, J _j, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i COMMA _j); -#endif - } + /* Getters */ - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, - G _g, H _h, I _i, J _j, K _k, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i COMMA _j COMMA _k); -#endif + /** + * Gets an indicator property flag. + */ + bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, int _shift = -1) { + IndicatorDataEntry _entry = GetEntry(_shift >= 0 ? _shift : iparams.GetShift()); + return _entry.CheckFlag(_prop); } /* Buffer methods */ @@ -419,6 +297,39 @@ class Indicator : public Chart { return _is_valid; } + /** + * CopyBuffer() method to be used on Indicator instance with ValueStorage buffer. + * + * Note that data will be copied so that the oldest element will be located at the start of the physical memory + * allocated for the array + */ + /* + static int CopyBuffer(IndicatorBase * _indi, int _mode, int _start, int _count, ValueStorage& _buffer, + int _rates_total) { int _num_copied = 0; int _buffer_size = ArraySize(_buffer); + + if (_buffer_size < _rates_total) { + _buffer_size = ArrayResize(_buffer, _rates_total); + } + + for (int i = _start; i < _count; ++i) { + IndicatorDataEntry _entry = _indi.GetEntry(i); + + if (!_entry.IsValid()) { + break; + } + + T _value = _entry.GetValue(_mode); + + // Print(_value); + + _buffer[_buffer_size - i - 1] = _value; + ++_num_copied; + } + + return _num_copied; + } + */ + /** * Validates currently selected indicator used as data source. */ @@ -431,7 +342,7 @@ class Indicator : public Chart { /** * Loads and validates built-in indicators whose can be used as data source. */ - void ValidateDataSource(Indicator* _target, Indicator* _source) { + void ValidateDataSource(IndicatorBase* _target, IndicatorBase* _source) { if (_target == NULL) { Alert("Internal Error! _target is NULL in ", __FUNCTION_LINE__, "."); DebugBreak(); @@ -449,19 +360,18 @@ class Indicator : public Chart { return; } - if (_source.iparams.max_modes > 1 && _target.GetDataSourceMode() == -1) { + if (_source.GetModeCount() > 1 && _target.GetDataSourceMode() == -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.iparams.SetDataSourceMode(0); + _target.SetDataSourceMode(0); DebugBreak(); - } else if (_source.iparams.max_modes == 1 && _target.GetDataSourceMode() == -1) { - _target.iparams.SetDataSourceMode(0); - } else if (_target.GetDataSourceMode() < 0 || - (unsigned int)_target.GetDataSourceMode() > _source.iparams.max_modes) { + } else if (_source.GetModeCount() == 1 && _target.GetDataSourceMode() == -1) { + _target.SetDataSourceMode(0); + } else if (_target.GetDataSourceMode() < 0 || _target.GetDataSourceMode() > _source.GetModeCount()) { Alert("Error! ", _target.GetName(), " must select valid source indicator's mode via SetDataSourceMode(int) between 0 and ", - _source.iparams.GetMaxModes(), "."); + _source.GetModeCount(), "."); DebugBreak(); } } @@ -474,14 +384,15 @@ class Indicator : public Chart { void ValidateDataSourceMode(int& _out_mode) { if (_out_mode == -1) { // First mode will be used by default, or, if selected indicator has more than one mode, error will happen. - if (iparams.max_modes != 1) { + if (iparams.GetMaxModes() != 1) { Alert("Error: ", GetName(), " must have exactly one possible mode in order to skip using SetDataSourceMode()!"); DebugBreak(); } _out_mode = 0; - } else if (_out_mode + 1 > (int)iparams.max_modes) { - Alert("Error: ", GetName(), " have ", iparams.max_modes, " mode(s) buy you tried to reference mode with index ", - _out_mode, "! Ensure that you properly set mode via SetDataSourceMode()."); + } else if (_out_mode + 1 > (int)iparams.GetMaxModes()) { + Alert("Error: ", GetName(), " have ", iparams.GetMaxModes(), + " mode(s) buy you tried to reference mode with index ", _out_mode, + "! Ensure that you properly set mode via SetDataSourceMode()."); DebugBreak(); } } @@ -489,47 +400,7 @@ class Indicator : public Chart { /** * Provides built-in indicators whose can be used as data source. */ - virtual Indicator* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } - - /** - * Whether data source is selected. - */ - bool HasDataSource() { return iparams.GetDataSource() != NULL || iparams.GetDataSourceId() != -1; } - - /** - * Returns currently selected data source without any validation. - */ - Indicator* GetDataSourceRaw() { return iparams.GetDataSource(); } - - /** - * Returns currently selected data source doing validation. - */ - Indicator* GetDataSource() { - Indicator* _result = NULL; - if (iparams.GetDataSource() != NULL) { - _result = iparams.GetDataSource(); - } else if (iparams.GetDataSourceId() != -1) { - int _source_id = iparams.GetDataSourceId(); - - if (indicators.KeyExists(_source_id)) { - _result = indicators[_source_id].Ptr(); - } else { - Ref _source = FetchDataSource((ENUM_INDICATOR_TYPE)_source_id); - - if (!_source.IsSet()) { - Alert(GetName(), " has no built-in source indicator ", _source_id); - } else { - indicators.Set(_source_id, _source); - - _result = _source.Ptr(); - } - } - } - - ValidateDataSource(&this, _result); - - return _result; - } + virtual IndicatorBase* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } /* Operator overloading methods */ @@ -542,160 +413,6 @@ class Indicator : public Chart { /* Getters */ - /** - * Returns buffers' cache. - */ - 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. - */ - template - T Get(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop) { - return istate.Get(_prop); - } - - /** - * Gets an indicator property flag. - */ - bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, int _shift = 0) { - IndicatorDataEntry _entry = GetEntry(_shift); - return _entry.CheckFlag(_prop); - } - - /* State methods */ - - /** - * Checks for crossover. - * - * @return - * Returns true when values are crossing over, otherwise false. - */ - bool IsCrossover(int _shift1 = 0, int _shift2 = 1, int _mode1 = 0, int _mode2 = 0) { - double _curr_value1 = GetEntry(_shift1)[_mode1]; - double _prev_value1 = GetEntry(_shift2)[_mode1]; - double _curr_value2 = GetEntry(_shift1)[_mode2]; - double _prev_value2 = GetEntry(_shift2)[_mode2]; - return ((_curr_value1 > _prev_value1 && _curr_value2 < _prev_value2) || - (_prev_value1 > _curr_value1 && _prev_value2 < _curr_value2)); - } - - /** - * Checks if values are decreasing. - * - * @param int _rows - * Numbers of rows to check. - * @param int _mode - * Indicator index mode to check. - * @param int _shift - * Shift which is the final value to take into the account. - * - * @return - * Returns true when values are increasing. - */ - bool IsDecreasing(int _rows = 1, int _mode = 0, int _shift = 0) { - bool _result = true; - for (int i = _shift + _rows - 1; i >= _shift && _result; i--) { - IndicatorDataEntry _entry_curr = GetEntry(i); - IndicatorDataEntry _entry_prev = GetEntry(i + 1); - _result &= _entry_curr.IsValid() && _entry_prev.IsValid() && _entry_curr[_mode] < _entry_prev[_mode]; - if (!_result) { - break; - } - } - return _result; - } - - /** - * Checks if value decreased by the given percentage value. - * - * @param int _pct - * Percentage value to use for comparison. - * @param int _mode - * Indicator index mode to use. - * @param int _shift - * Indicator value shift to use. - * @param int _count - * Count of bars to compare change backward. - * @param int _hundreds - * When true, use percentage in hundreds, otherwise 1 is 100%. - * - * @return - * Returns true when value increased. - */ - bool IsDecByPct(float _pct, int _mode = 0, int _shift = 0, int _count = 1, bool _hundreds = true) { - bool _result = true; - IndicatorDataEntry _v0 = GetEntry(_shift); - IndicatorDataEntry _v1 = GetEntry(_shift + _count); - _result &= _v0.IsValid() && _v1.IsValid(); - _result &= _result && Math::ChangeInPct(_v1[_mode], _v0[_mode], _hundreds) < _pct; - return _result; - } - - /** - * Checks if values are increasing. - * - * @param int _rows - * Numbers of rows to check. - * @param int _mode - * Indicator index mode to check. - * @param int _shift - * Shift which is the final value to take into the account. - * - * @return - * Returns true when values are increasing. - */ - bool IsIncreasing(int _rows = 1, int _mode = 0, int _shift = 0) { - bool _result = true; - for (int i = _shift + _rows - 1; i >= _shift && _result; i--) { - IndicatorDataEntry _entry_curr = GetEntry(i); - IndicatorDataEntry _entry_prev = GetEntry(i + 1); - _result &= _entry_curr.IsValid() && _entry_prev.IsValid() && _entry_curr[_mode] > _entry_prev[_mode]; - if (!_result) { - break; - } - } - return _result; - } - - /** - * Checks if value increased by the given percentage value. - * - * @param int _pct - * Percentage value to use for comparison. - * @param int _mode - * Indicator index mode to use. - * @param int _shift - * Indicator value shift to use. - * @param int _count - * Count of bars to compare change backward. - * @param int _hundreds - * When true, use percentage in hundreds, otherwise 1 is 100%. - * - * @return - * Returns true when value increased. - */ - bool IsIncByPct(float _pct, int _mode = 0, int _shift = 0, int _count = 1, bool _hundreds = true) { - bool _result = true; - IndicatorDataEntry _v0 = GetEntry(_shift); - IndicatorDataEntry _v1 = GetEntry(_shift + _count); - _result &= _v0.IsValid() && _v1.IsValid(); - _result &= _result && Math::ChangeInPct(_v1[_mode], _v0[_mode], _hundreds) > _pct; - return _result; - } - - /* Getters */ - - int GetDataSourceMode() { return iparams.GetDataSourceMode(); } - /** * Returns the highest bar's index (shift). */ @@ -706,7 +423,7 @@ class Indicator : public Chart { int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); for (int shift = start_bar; shift <= last_bar; ++shift) { - double value = GetEntry(shift).GetMax(iparams.max_modes); + double value = GetEntry(shift).GetMax(GetModeCount()); if (value > max) { max = value; max_idx = shift; @@ -726,7 +443,7 @@ class Indicator : public Chart { 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(iparams.max_modes); + double value = GetEntry(shift).GetMin(GetModeCount()); if (value < min) { min = value; min_idx = shift; @@ -745,7 +462,7 @@ class Indicator : public Chart { int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); for (int shift = start_bar; shift <= last_bar; ++shift) { - double value = GetEntry(shift).GetMax(iparams.max_modes); + double value = GetEntry(shift).GetMax(iparams.GetMaxModes()); if (max == NULL || value > max) { max = value; } @@ -763,7 +480,7 @@ class Indicator : public Chart { 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(iparams.max_modes); + double value = GetEntry(shift).GetMin(iparams.GetMaxModes()); if (min == NULL || value < min) { min = value; } @@ -782,8 +499,8 @@ class Indicator : public Chart { int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); for (int shift = start_bar; shift <= last_bar; ++shift) { - double value_min = GetEntry(shift).GetMin(iparams.max_modes); - double value_max = GetEntry(shift).GetMax(iparams.max_modes); + double value_min = GetEntry(shift).GetMin(iparams.GetMaxModes()); + double value_max = GetEntry(shift).GetMax(iparams.GetMaxModes()); sum += value_min + value_max; num_values += 2; @@ -806,7 +523,7 @@ class Indicator : public Chart { ArrayResize(array, num_bars); for (int shift = start_bar; shift <= last_bar; ++shift) { - array[index++] = GetEntry(shift).GetAvg(iparams.max_modes); + array[index++] = GetEntry(shift).GetAvg(iparams.GetMaxModes()); } ArraySort(array); @@ -821,6 +538,48 @@ class Indicator : public Chart { return median; } + /** + * Returns currently selected data source doing validation. + */ + IndicatorBase* GetDataSource() { + IndicatorBase* _result = NULL; + + if (GetDataSourceRaw() != NULL) { + _result = GetDataSourceRaw(); + } else if (iparams.GetDataSourceId() != -1) { + int _source_id = iparams.GetDataSourceId(); + + if (indicators.KeyExists(_source_id)) { + _result = indicators[_source_id].Ptr(); + } else { + Ref _source = FetchDataSource((ENUM_INDICATOR_TYPE)_source_id); + + if (!_source.IsSet()) { + Alert(GetName(), " has no built-in source indicator ", _source_id); + DebugBreak(); + } else { + indicators.Set(_source_id, _source); + + _result = _source.Ptr(); + } + } + } + + ValidateDataSource(&this, _result); + + return _result; + } + + /** + * Gets number of modes available to retrieve by GetValue(). + */ + virtual int GetModeCount() { return 0; } + + /** + * Whether data source is selected. + */ + virtual bool HasDataSource() { return GetDataSourceRaw() != NULL || iparams.GetDataSourceId() != -1; } + /** * Gets indicator's params. */ @@ -854,21 +613,11 @@ class Indicator : public Chart { return _signals; } - /** - * Get indicator type. - */ - ENUM_INDICATOR_TYPE GetType() { return iparams.itype; } - /** * Get pointer to data of indicator. */ BufferStruct* GetData() { return GetPointer(idata); } - /** - * Get data type of indicator. - */ - ENUM_DATATYPE GetDataType() { return iparams.dtype; } - /** * Get name of the indicator. */ @@ -879,9 +628,7 @@ class Indicator : public Chart { */ string GetFullName() { return iparams.name + "[" + IntegerToString(iparams.GetMaxModes()) + "]" + - (HasDataSource() ? (" (over " + GetDataSource().GetName() + "[" + - IntegerToString(GetDataSource().GetParams().GetMaxModes()) + "])") - : ""); + (HasDataSource() ? (" (over " + GetDataSource().GetFullName() + ")") : ""); } /** @@ -890,7 +637,7 @@ class Indicator : public Chart { string GetDescriptiveName() { string name = iparams.name + " ("; - switch (iparams.idstype) { + switch (iparams.GetDataSourceType()) { case IDATA_BUILTIN: name += "built-in, "; break; @@ -902,7 +649,7 @@ class Indicator : public Chart { break; } - name += IntegerToString(iparams.max_modes) + (iparams.max_modes == 1 ? " mode" : " modes"); + name += IntegerToString(iparams.GetMaxModes()) + (iparams.GetMaxModes() == 1 ? " mode" : " modes"); return name + ")"; } @@ -917,6 +664,14 @@ class Indicator : public Chart { Chart::Set(_param, _value); } + /** + * Sets indicator data source. + */ + void SetDataSource(IndicatorBase* _indi, bool _managed, int _input_mode) { + indi_src = _indi; + iparams.SetDataSource(-1, _input_mode, _managed); + } + /** * Sets name of the indicator. */ @@ -1117,124 +872,16 @@ class Indicator : public Chart { return true; } - /** - * Feed history entries. - */ - void FeedHistoryEntries(int period, int shift = 0) { - if (is_feeding || is_fed) { - // Avoiding forever loop. - return; - } - - is_feeding = true; - - for (int i = shift + period; i > shift; --i) { - if (ChartStatic::iPrice(PRICE_OPEN, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), i) <= - 0) { - // No data for that entry - continue; - } - - GetEntry(i); - } - - is_feeding = false; - is_fed = true; - } - - ValueStorage* GetValueStorage(int _mode = 0) { - if (value_storages[_mode] == NULL) { - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); - } - return value_storages[_mode]; - } - - /** - * Returns indicator value for a given shift and mode. - */ - template - T GetValue(int _shift = 0, int _mode = -1) { - T _result; - int _index = _mode != -1 ? _mode : iparams.indi_mode; - GetEntry(_shift).values[_index].Get(_result); - ResetLastError(); - return _result; - } - - /** - * Returns price corresponding to indicator value for a given shift and mode. - * - * Can be useful for calculating trailing stops based on the indicator. - * - * @return - * Returns price value of the corresponding indicator values. - */ - template - float GetValuePrice(int _shift = 0, int _mode = 0, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL) { - float _price = 0; - if (iparams.GetIDataValueRange() != IDATA_RANGE_PRICE) { - _price = (float)GetPrice(_ap, _shift); - } else if (iparams.GetIDataValueRange() == IDATA_RANGE_PRICE) { - // When indicator values are the actual prices. - T _values[4]; - if (!CopyValues(_values, 4, _shift, _mode)) { - // When values aren't valid, return 0. - return _price; - } - datetime _bar_time = GetBarTime(_shift); - float _value = 0; - BarOHLC _ohlc(_values, _bar_time); - _price = _ohlc.GetAppliedPrice(_ap); - } - return _price; - } - - /** - * Returns values for a given shift. - * - * Note: Remember to check if shift exists by HasValidEntry(shift). - */ - template - bool GetValues(int _shift, T& _out1, T& _out2) { - IndicatorDataEntry _entry = GetEntry(_shift); - _out1 = _entry.values[0]; - _out2 = _entry.values[1]; - bool _result = GetLastError() != 4401; - ResetLastError(); - return _result; - } - - template - bool GetValues(int _shift, T& _out1, T& _out2, T& _out3) { - IndicatorDataEntry _entry = GetEntry(_shift); - _out1 = _entry.values[0]; - _out2 = _entry.values[1]; - _out3 = _entry.values[2]; - bool _result = GetLastError() != 4401; - ResetLastError(); - return _result; - } - - template - bool GetValues(int _shift, T& _out1, T& _out2, T& _out3, T& _out4) { - IndicatorDataEntry _entry = GetEntry(_shift); - _out1 = _entry.values[0]; - _out2 = _entry.values[1]; - _out3 = _entry.values[2]; - _out4 = _entry.values[3]; - bool _result = GetLastError() != 4401; - ResetLastError(); - return _result; - } + ENUM_IDATA_VALUE_RANGE GetIDataValueRange() { return iparams.idvrange; } virtual void OnTick() { Chart::OnTick(); if (iparams.is_draw) { // Print("Drawing ", GetName(), iparams.indi_data != NULL ? (" (over " + iparams.indi_data.GetName() + ")") : ""); - for (int i = 0; i < (int)iparams.max_modes; ++i) - draw.DrawLineTo(GetName() + "_" + IntegerToString(i) + "_" + IntegerToString(iparams.indi_mode), GetBarTime(0), - GetEntry(0)[i], iparams.draw_window); + for (int i = 0; i < (int)iparams.GetMaxModes(); ++i) + draw.DrawLineTo(GetName() + "_" + IntegerToString(i) + "_" + IntegerToString(iparams.GetDataSourceMode()), + GetBarTime(0), GetEntry(0)[i], iparams.draw_window); } } @@ -1252,6 +899,26 @@ class Indicator : public Chart { */ virtual bool IsDataSourceModeSelectable() { return true; } + /** + * Checks if indicator entry is valid. + * + * @return + * Returns true if entry is valid (has valid values), otherwise false. + */ + virtual bool IsValidEntry(IndicatorDataEntry& _entry) { + bool _result = true; + _result &= !_entry.HasValue(NULL); + _result &= !_entry.HasValue(EMPTY_VALUE); + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLE)) { + _result &= !_entry.HasValue(DBL_MAX); + } else if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_FLOAT)) { + _result &= !_entry.HasValue(FLT_MAX); + } else if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_INT)) { + _result &= !_entry.HasValue(INT_MAX); + } + return _result; + } + /** * Update indicator. */ @@ -1262,12 +929,31 @@ class Indicator : public Chart { /** * Returns the indicator's struct value. + * + * @see: IndicatorDataEntry. + * + * @return + * Returns IndicatorDataEntry struct filled with indicator values. */ virtual IndicatorDataEntry GetEntry(int _shift = 0) { - IndicatorDataEntry _entry(iparams.max_modes); - _entry = idata.GetByKey(GetBarTime(_shift), _entry); + long _bar_time = GetBarTime(_shift); + IndicatorDataEntry _entry = idata.GetByKey(_bar_time); + if (!_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) { + _entry.Resize(iparams.GetMaxModes()); + _entry.timestamp = GetBarTime(_shift); + for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) { + _entry.values[_mode] = GetValue(_mode, _shift); + } + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); + if (_entry.IsValid()) { + idata.Add(_entry, _bar_time); + } else { + _entry.AddFlags(INDI_ENTRY_FLAG_INSUFFICIENT_DATA); + } + } return _entry; - }; + } /** * Returns the indicator's entry value. @@ -1278,6 +964,15 @@ class Indicator : public Chart { return _param; } + /** + * Returns the indicator's value. + */ + virtual double GetValue(int _mode = 0, int _shift = 0) { + istate.is_changed = false; + istate.is_ready = false; + return EMPTY_VALUE; + } + /** * Returns the indicator's value in plain format. */ @@ -1291,68 +986,4 @@ class Indicator : public Chart { } }; -/** - * BarsCalculated() method to be used on Indicator instance. - */ -int BarsCalculated(Indicator* _indi, int _bars_required) { - if (_bars_required == 0) { - return _bars_required; - } - - IndicatorDataEntry _entry = _indi.GetEntry(_bars_required - 1); - // GetEntry() could end up with an error. It is okay. - ResetLastError(); - - int _valid_history_count = 0; - - if (!_entry.IsValid()) { - // We don't have sufficient data. Counting how much data we have. - - for (int i = 0; i < _bars_required; ++i) { - IndicatorDataEntry _check_entry = _indi.GetEntry(i); - if (!_check_entry.IsValid()) { - break; - } - ++_valid_history_count; - } - } else { - _valid_history_count = _bars_required; - } - - return _valid_history_count; -} - -/** - * CopyBuffer() method to be used on Indicator instance with ValueStorage buffer. - * - * Note that data will be copied so that the oldest element will be located at the start of the physical memory - * allocated for the array - */ -template -int CopyBuffer(Indicator* _indi, int _mode, int _start, int _count, ValueStorage& _buffer, int _rates_total) { - int _num_copied = 0; - int _buffer_size = ArraySize(_buffer); - - if (_buffer_size < _rates_total) { - _buffer_size = ArrayResize(_buffer, _rates_total); - } - - for (int i = _start; i < _count; ++i) { - IndicatorDataEntry _entry = _indi.GetEntry(i); - - if (!_entry.IsValid()) { - break; - } - - T _value = _entry.GetValue(_mode); - - // Print(_value); - - _buffer[_buffer_size - i - 1] = _value; - ++_num_copied; - } - - return _num_copied; -} - #endif diff --git a/Indicator.struct.cache.h b/Indicator.struct.cache.h index 209983beb..2c4df7097 100644 --- a/Indicator.struct.cache.h +++ b/Indicator.struct.cache.h @@ -32,6 +32,7 @@ // Includes. #include "Refs.mqh" +#include "Storage/ValueStorage.h" /** * Holds buffers used to cache values calculated via OnCalculate methods. @@ -113,6 +114,11 @@ class IndicatorCalculateCache : public Dynamic { */ bool HasBuffers() { return ArraySize(buffers) != 0; } + /** + * Returns number of added buffers. + */ + int NumBuffers() { return ArraySize(buffers); } + /** * Returns existing or new cache as a child of current one. Useful when indicator uses other indicators and requires * unique caches for them. diff --git a/Indicator.struct.h b/Indicator.struct.h index 51c99d028..8bedbd5b0 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -31,6 +31,7 @@ #endif // Forward declaration. +template class Indicator; struct ChartParams; @@ -353,6 +354,7 @@ struct IndicatorDataEntry { /* Structure for indicator parameters. */ struct IndicatorParams { + public: // @todo: Change it to protected. string name; // Name of the indicator. int shift; // Shift (relative to the current bar, 0 - default). unsigned int max_buffers; // Max buffers to store. @@ -367,33 +369,32 @@ struct IndicatorParams { color indi_color; // Indicator color. int indi_data_source_id; // Id of the indicator to be used as data source. int indi_data_source_mode; // Mode used as input from data source. - Indicator *indi_data_source; // Custom indicator to be used as data source. bool indi_managed; // Whether indicator should be owned by indicator. ARRAY(DataParamEntry, input_params); // Indicator input params. - int indi_mode; // Index of indicator data to be used as data source. bool is_draw; // Draw active. int draw_window; // Drawing window. string custom_indi_name; // Name of the indicator passed to iCustom() method. + public: /* Special methods */ // Constructor. - IndicatorParams(ENUM_INDICATOR_TYPE _itype = INDI_NONE, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, - string _name = "") + 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(""), + dtype(_dtype), name(_name), shift(0), - max_modes(1), + max_modes(_max_modes), max_buffers(10), idstype(_idstype), idvrange(IDATA_RANGE_UNKNOWN), - indi_data_source(NULL), indi_data_source_id(-1), indi_data_source_mode(0), itype(_itype), is_draw(false), indi_color(clrNONE), - indi_mode(0), - draw_window(0) { - SetDataSourceType(_idstype); + draw_window(0), + tf(_tf) { Init(); }; IndicatorParams(string _name, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) @@ -404,32 +405,35 @@ struct IndicatorParams { max_buffers(10), idstype(_idstype), idvrange(IDATA_RANGE_UNKNOWN), - indi_data_source(NULL), indi_data_source_id(-1), indi_data_source_mode(0), is_draw(false), indi_color(clrNONE), - indi_mode(0), draw_window(0) { - SetDataSourceType(_idstype); Init(); }; + // Copy constructor. + IndicatorParams(IndicatorParams &_iparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : tf(_tf) { + this = _iparams; + if (_tf != PERIOD_CURRENT) { + tf.SetTf(_tf); + } + } void Init() {} /* Getters */ - string GetCustomIndicatorName() { return custom_indi_name; } - Indicator *GetDataSource() { return indi_data_source; } - int GetDataSourceId() { return indi_data_source_id; } - int GetDataSourceMode() { return indi_data_source_mode; } - color GetIndicatorColor() { return indi_color; } - int GetMaxModes() { return (int)max_modes; } - int GetMaxParams() { return (int)max_params; } - int GetShift() { return shift; } - ENUM_DATATYPE GetDataValueType() { return dtype; } - ENUM_IDATA_SOURCE_TYPE GetDataSourceType() { return idstype; } - ENUM_IDATA_VALUE_RANGE GetIDataValueRange() { return idvrange; } - ENUM_TIMEFRAMES GetTf() { return tf.GetTf(); } + string GetCustomIndicatorName() const { return custom_indi_name; } + int GetDataSourceId() const { return indi_data_source_id; } + int GetDataSourceMode() const { return indi_data_source_mode; } + color GetIndicatorColor() const { return indi_color; } + int GetMaxModes() const { return (int)max_modes; } + int GetMaxParams() const { return (int)max_params; } + int GetShift() const { return shift; } + ENUM_DATATYPE GetDataValueType() const { return dtype; } + ENUM_IDATA_SOURCE_TYPE GetDataSourceType() const { return idstype; } + ENUM_IDATA_VALUE_RANGE GetIDataValueRange() const { return idvrange; } + ENUM_TIMEFRAMES GetTf() const { return tf.GetTf(); } template - T GetInputParam(int _index, T _default) { + T GetInputParam(int _index, T _default) const { DataParamEntry _param = input_params[_index]; switch (_param.type) { case TYPE_BOOL: @@ -465,15 +469,9 @@ struct IndicatorParams { draw_window = _window; } void SetIndicatorColor(color _clr) { indi_color = _clr; } - void SetDataSource(int _id, int _input_mode = -1) { + void SetDataSource(int _id, int _input_mode = -1, bool _managed = true) { indi_data_source_id = _id; indi_data_source_mode = _input_mode; - idstype = IDATA_INDICATOR; - } - void SetDataSource(Indicator *_indi, bool _managed = true, int _input_mode = -1) { - indi_data_source_id = -1; - indi_data_source = _indi; - indi_data_source_mode = _input_mode; indi_managed = _managed; idstype = IDATA_INDICATOR; } diff --git a/Indicator.struct.serialize.h b/Indicator.struct.serialize.h index 0b47a476a..d7bd36a23 100644 --- a/Indicator.struct.serialize.h +++ b/Indicator.struct.serialize.h @@ -36,9 +36,9 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { _s.Pass(THIS_REF, "datetime", timestamp, SERIALIZER_FIELD_FLAG_DYNAMIC); _s.Pass(THIS_REF, "flags", flags, SERIALIZER_FIELD_FLAG_DYNAMIC); for (int i = 0; i < _asize; i++) { - // _s.Pass(THIS_REF, (string)i, values[i], SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); // Can this - // work? _s.Pass(THIS_REF, (string)i, GetEntry(i), SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); // - // Can this work? + // _s.Pass(THIS_REF, (string)i, values[i], SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); // Can + // this work? _s.Pass(THIS_REF, (string)i, GetEntry(i), SERIALIZER_FIELD_FLAG_DYNAMIC | + // SERIALIZER_FIELD_FLAG_FEATURE); // Can this work? if (CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLE)) { _s.Pass(THIS_REF, (string)i, values[i].vdbl, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); @@ -92,7 +92,6 @@ SerializerNodeType IndicatorParams::Serialize(Serializer &s) { // s.PassObject(this, "indicator", indi_data); // @todo // s.Pass(THIS_REF, "indi_data_ownership", indi_data_ownership); s.Pass(THIS_REF, "indi_color", indi_color, SERIALIZER_FIELD_FLAG_HIDDEN); - s.Pass(THIS_REF, "indi_mode", indi_mode); s.Pass(THIS_REF, "is_draw", is_draw); s.Pass(THIS_REF, "draw_window", draw_window, SERIALIZER_FIELD_FLAG_HIDDEN); s.Pass(THIS_REF, "custom_indi_name", custom_indi_name); diff --git a/Indicator.struct.signal.h b/Indicator.struct.signal.h index 1ac6dcd75..954e02172 100644 --- a/Indicator.struct.signal.h +++ b/Indicator.struct.signal.h @@ -56,7 +56,8 @@ struct IndicatorSignal { // Constructors. IndicatorSignal(int _signals = 0) : signals(_signals) {} - IndicatorSignal(ARRAY_REF(IndicatorDataEntry, _data), IndicatorParams &_ip, ChartParams &_cp, int _m1 = 0, int _m2 = 0) + IndicatorSignal(ARRAY_REF(IndicatorDataEntry, _data), IndicatorParams &_ip, ChartParams &_cp, int _m1 = 0, + int _m2 = 0) : signals(0) { CalcSignals(_data, _ip, _cp, _m1, _m2); } diff --git a/IndicatorBase.h b/IndicatorBase.h new file mode 100644 index 000000000..eed35dcdb --- /dev/null +++ b/IndicatorBase.h @@ -0,0 +1,1045 @@ +//+------------------------------------------------------------------+ +//| 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 + * Base interface for Indicator class. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Forward declaration. +class Chart; + +// Includes. +#include "Array.mqh" +#include "BufferStruct.mqh" +#include "Chart.mqh" +#include "DateTime.mqh" +#include "DrawIndicator.mqh" +#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 "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). +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 + +/** + * Class to deal with indicators. + */ +class IndicatorBase : public Chart { + protected: + BufferStruct idata; + DrawIndicator* draw; + IndicatorState istate; + void* mydata; + bool is_fed; // Whether calc_start_bar is already calculated. + int calc_start_bar; // Index of the first valid bar (from 0). + DictStruct> indicators; // Indicators list keyed by id. + bool indicator_builtin; + ARRAY(ValueStorage*, value_storages); + IndicatorBase* indi_src; // // Indicator used as data source. + int indi_src_mode; // Mode of source indicator + IndicatorCalculateCache cache; + + public: + /* Indicator enumerations */ + + /* + * Default enumerations: + * + * ENUM_MA_METHOD values: + * 0: MODE_SMA (Simple averaging) + * 1: MODE_EMA (Exponential averaging) + * 2: MODE_SMMA (Smoothed averaging) + * 3: MODE_LWMA (Linear-weighted averaging) + */ + + /* Special methods */ + + /** + * 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; + } + + /** + * Class deconstructor. + */ + virtual ~IndicatorBase() { + ReleaseHandle(); + + for (int i = 0; i < ArraySize(value_storages); ++i) { + if (value_storages[i] != NULL) { + delete value_storages[i]; + } + } + } + + /* Defines MQL backward compatible methods */ + + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(DUMMY); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a COMMA _b); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, int _mode, + int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, int _mode, + int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, + int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, + int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, + G _g, int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, + G _g, H _h, int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, + G _g, H _h, I _i, int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, + G _g, H _h, I _i, J _j, int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i COMMA _j); +#endif + } + + template + double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, + G _g, H _h, I _i, J _j, K _k, int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _mode, _shift); +#else // __MQL5__ + ICUSTOM_DEF(COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i COMMA _j COMMA _k); +#endif + } + + /* Buffer methods */ + + virtual string CacheKey() { return GetName(); } + + /** + * Initializes a cached proxy between i*OnArray() methods and OnCalculate() + * used by custom indicators. + * + * Note that OnCalculateProxy() method sets incoming price array as not + * series. It will be reverted back by SetPrevCalculated(). It is because + * OnCalculate() methods assumes that prices are set as not series. + * + * For real example how you can use this method, look at + * Indi_MA::iMAOnArray() method. + * + * Usage: + * + * static double iFooOnArray(double &price[], int total, int period, + * int foo_shift, int foo_method, int shift, string cache_name = "") + * { + * if (cache_name != "") { + * String cache_key; + * cache_key.Add(cache_name); + * cache_key.Add(period); + * cache_key.Add(foo_method); + * + * Ref cache = Indicator::OnCalculateProxy(cache_key.ToString(), price, total); + * + * int prev_calculated = + * Indi_Foo::Calculate(total, cache.Ptr().prev_calculated, 0, price, cache.Ptr().buffer1, ma_method, period); + * + * cache.Ptr().SetPrevCalculated(price, prev_calculated); + * + * return cache.Ptr().GetValue(1, shift + ma_shift); + * } + * else { + * // Default iFooOnArray. + * } + * + * WARNING: Do not use shifts when creating cache_key, as this will create many invalid buffers. + */ + /* + static IndicatorCalculateCache OnCalculateProxy(string key, double& price[], int& total) { + if (total == 0) { + total = ArraySize(price); + } + + // Stores previously calculated value. + static DictStruct cache; + + unsigned int position; + IndicatorCalculateCache cache_item; + + if (cache.KeyExists(key, position)) { + cache_item = cache.GetByKey(key); + } else { + IndicatorCalculateCache cache_item_new(1, ArraySize(price)); + cache_item = cache_item_new; + cache.Set(key, cache_item); + } + + // Number of bars available in the chart. Same as length of the input `array`. + int rates_total = ArraySize(price); + + int begin = 0; + + cache_item.Resize(rates_total); + + cache_item.price_was_as_series = ArrayGetAsSeries(price); + ArraySetAsSeries(price, false); + + return cache_item; + } + */ + + /** + * Gets indicator data from a buffer and copy into struct array. + * + * @return + * Returns true of successful copy. + * Returns false on invalid values. + */ + bool CopyEntries(IndicatorDataEntry& _data[], int _count, int _start_shift = 0) { + bool _is_valid = true; + if (ArraySize(_data) < _count) { + _is_valid &= ArrayResize(_data, _count) > 0; + } + for (int i = 0; i < _count; i++) { + IndicatorDataEntry _entry = GetEntry(_start_shift + i); + _is_valid &= _entry.IsValid(); + _data[i] = _entry; + } + return _is_valid; + } + + /** + * Gets indicator data from a buffer and copy into array of values. + * + * @return + * Returns true of successful copy. + * Returns false on invalid values. + */ + template + bool CopyValues(T& _data[], int _count, int _start_shift = 0, int _mode = 0) { + bool _is_valid = true; + if (ArraySize(_data) < _count) { + _count = ArrayResize(_data, _count); + _count = _count > 0 ? _count : ArraySize(_data); + } + for (int i = 0; i < _count; i++) { + IndicatorDataEntry _entry = GetEntry(_start_shift + i); + _is_valid &= _entry.IsValid(); + _data[i] = (T)_entry[_mode]; + } + return _is_valid; + } + + /** + * Validates currently selected indicator used as data source. + */ + void ValidateSelectedDataSource() { + if (HasDataSource()) { + ValidateDataSource(THIS_PTR, GetDataSourceRaw()); + } + } + + /** + * Loads and validates built-in indicators whose can be used as data source. + */ + virtual void ValidateDataSource(IndicatorBase* _target, IndicatorBase* _source) {} + + /** + * Checks whether indicator have given mode index. + * + * If given mode is -1 (default one) and indicator has exactly one mode, then mode index will be replaced by 0. + */ + virtual void ValidateDataSourceMode(int& _out_mode) {} + + /** + * Provides built-in indicators whose can be used as data source. + */ + virtual IndicatorBase* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } + + /** + * Returns currently selected data source without any validation. + */ + IndicatorBase* GetDataSourceRaw() { return indi_src; } + + /* Operator overloading methods */ + + /** + * Access indicator entry data using [] operator. + */ + IndicatorDataEntry operator[](int _shift) { return GetEntry(_shift); } + IndicatorDataEntry operator[](ENUM_INDICATOR_INDEX _shift) { return GetEntry(_shift); } + IndicatorDataEntry operator[](datetime _dt) { return idata[_dt]; } + + /* Getters */ + + /** + * Returns buffers' cache. + */ + 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. + */ + template + T Get(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop) { + return istate.Get(_prop); + } + + /** + * Gets number of modes available to retrieve by GetValue(). + */ + virtual int GetModeCount() { return 0; } + + /* State methods */ + + /** + * Checks for crossover. + * + * @return + * Returns true when values are crossing over, otherwise false. + */ + bool IsCrossover(int _shift1 = 0, int _shift2 = 1, int _mode1 = 0, int _mode2 = 0) { + double _curr_value1 = GetEntry(_shift1)[_mode1]; + double _prev_value1 = GetEntry(_shift2)[_mode1]; + double _curr_value2 = GetEntry(_shift1)[_mode2]; + double _prev_value2 = GetEntry(_shift2)[_mode2]; + return ((_curr_value1 > _prev_value1 && _curr_value2 < _prev_value2) || + (_prev_value1 > _curr_value1 && _prev_value2 < _curr_value2)); + } + + /** + * Checks if values are decreasing. + * + * @param int _rows + * Numbers of rows to check. + * @param int _mode + * Indicator index mode to check. + * @param int _shift + * Shift which is the final value to take into the account. + * + * @return + * Returns true when values are increasing. + */ + bool IsDecreasing(int _rows = 1, int _mode = 0, int _shift = 0) { + bool _result = true; + for (int i = _shift + _rows - 1; i >= _shift && _result; i--) { + IndicatorDataEntry _entry_curr = GetEntry(i); + IndicatorDataEntry _entry_prev = GetEntry(i + 1); + _result &= _entry_curr.IsValid() && _entry_prev.IsValid() && _entry_curr[_mode] < _entry_prev[_mode]; + if (!_result) { + break; + } + } + return _result; + } + + /** + * Checks if value decreased by the given percentage value. + * + * @param int _pct + * Percentage value to use for comparison. + * @param int _mode + * Indicator index mode to use. + * @param int _shift + * Indicator value shift to use. + * @param int _count + * Count of bars to compare change backward. + * @param int _hundreds + * When true, use percentage in hundreds, otherwise 1 is 100%. + * + * @return + * Returns true when value increased. + */ + bool IsDecByPct(float _pct, int _mode = 0, int _shift = 0, int _count = 1, bool _hundreds = true) { + bool _result = true; + IndicatorDataEntry _v0 = GetEntry(_shift); + IndicatorDataEntry _v1 = GetEntry(_shift + _count); + _result &= _v0.IsValid() && _v1.IsValid(); + _result &= _result && Math::ChangeInPct(_v1[_mode], _v0[_mode], _hundreds) < _pct; + return _result; + } + + /** + * Checks if values are increasing. + * + * @param int _rows + * Numbers of rows to check. + * @param int _mode + * Indicator index mode to check. + * @param int _shift + * Shift which is the final value to take into the account. + * + * @return + * Returns true when values are increasing. + */ + bool IsIncreasing(int _rows = 1, int _mode = 0, int _shift = 0) { + bool _result = true; + for (int i = _shift + _rows - 1; i >= _shift && _result; i--) { + IndicatorDataEntry _entry_curr = GetEntry(i); + IndicatorDataEntry _entry_prev = GetEntry(i + 1); + _result &= _entry_curr.IsValid() && _entry_prev.IsValid() && _entry_curr[_mode] > _entry_prev[_mode]; + if (!_result) { + break; + } + } + return _result; + } + + /** + * Checks if value increased by the given percentage value. + * + * @param int _pct + * Percentage value to use for comparison. + * @param int _mode + * Indicator index mode to use. + * @param int _shift + * Indicator value shift to use. + * @param int _count + * Count of bars to compare change backward. + * @param int _hundreds + * When true, use percentage in hundreds, otherwise 1 is 100%. + * + * @return + * Returns true when value increased. + */ + bool IsIncByPct(float _pct, int _mode = 0, int _shift = 0, int _count = 1, bool _hundreds = true) { + bool _result = true; + IndicatorDataEntry _v0 = GetEntry(_shift); + IndicatorDataEntry _v1 = GetEntry(_shift + _count); + _result &= _v0.IsValid() && _v1.IsValid(); + _result &= _result && Math::ChangeInPct(_v1[_mode], _v0[_mode], _hundreds) > _pct; + return _result; + } + + /* Getters */ + + /** + * Whether data source is selected. + */ + virtual bool HasDataSource() { return false; } + + /** + * Returns currently selected data source doing validation. + */ + virtual IndicatorBase* GetDataSource() { return NULL; } + + 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. + * + * When indicator values are not valid, returns empty signals. + */ + virtual IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) { + IndicatorSignal _signal; + return _signal; + } + + /** + * Get indicator type. + */ + virtual ENUM_INDICATOR_TYPE GetType() { return INDI_NONE; } + + /** + * Get pointer to data of indicator. + */ + BufferStruct* GetData() { return GetPointer(idata); } + + /** + * Get data type of indicator. + */ + virtual ENUM_DATATYPE GetDataType() { return (ENUM_DATATYPE)-1; } + + /** + * Get name of the indicator. + */ + virtual string GetName() { return ""; } + + /** + * Get full name of the indicator (with "over ..." part). + */ + virtual string GetFullName() { return GetName(); } + + /** + * Get more descriptive name of the indicator. + */ + virtual string GetDescriptiveName() { return GetName(); } + + /* Setters */ + + /** + * Sets an indicator's chart parameter value. + */ + template + void Set(ENUM_CHART_PARAM _param, T _value) { + Chart::Set(_param, _value); + } + + /** + * Sets indicator data source. + */ + virtual void SetDataSource(IndicatorBase* _indi, bool _managed, int _input_mode) = 0; + + /** + * Sets data source's input mode. + */ + void SetDataSourceMode(int _mode) { indi_src_mode = _mode; } + + /** + * Sets name of the indicator. + */ + virtual void SetName(string _name) {} + + /** + * Sets indicator's handle. + * + * Note: Not supported in MT4. + */ + virtual void SetHandle(int _handle) {} + + /** + * Sets indicator's symbol. + */ + void SetSymbol(string _symbol) { Set(CHART_PARAM_SYMBOL, _symbol); } + + /* Conditions */ + + /** + * Checks for indicator condition. + * + * @param ENUM_INDICATOR_CONDITION _cond + * Indicator condition. + * @param MqlParam[] _args + * Condition arguments. + * @return + * Returns true when the condition is met. + */ + bool CheckCondition(ENUM_INDICATOR_CONDITION _cond, DataParamEntry& _args[]) { + switch (_cond) { + case INDI_COND_ENTRY_IS_MAX: + // @todo: Add arguments, check if the entry value is max. + return false; + case INDI_COND_ENTRY_IS_MIN: + // @todo: Add arguments, check if the entry value is min. + return false; + case INDI_COND_ENTRY_GT_AVG: + // @todo: Add arguments, check if... + // Indicator entry value is greater than average. + return false; + case INDI_COND_ENTRY_GT_MED: + // @todo: Add arguments, check if... + // Indicator entry value is greater than median. + return false; + case INDI_COND_ENTRY_LT_AVG: + // @todo: Add arguments, check if... + // Indicator entry value is lesser than average. + return false; + case INDI_COND_ENTRY_LT_MED: + // @todo: Add arguments, check if... + // Indicator entry value is lesser than median. + return false; + default: + GetLogger().Error(StringFormat("Invalid indicator condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + return false; + } + } + bool CheckCondition(ENUM_INDICATOR_CONDITION _cond) { + ARRAY(DataParamEntry, _args); + return IndicatorBase::CheckCondition(_cond, _args); + } + + /** + * Execute Indicator action. + * + * @param ENUM_INDICATOR_ACTION _action + * Indicator action to execute. + * @param MqlParam _args + * Indicator action arguments. + * @return + * Returns true when the action has been executed successfully. + */ + virtual bool ExecuteAction(ENUM_INDICATOR_ACTION _action, 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(); + idata.Clear(_arg1); + return true; + default: + GetLogger().Error(StringFormat("Invalid Indicator action: %s!", EnumToString(_action), __FUNCTION_LINE__)); + return false; + } + return _result; + } + bool ExecuteAction(ENUM_INDICATOR_ACTION _action) { + ARRAY(DataParamEntry, _args); + return ExecuteAction(_action, _args); + } + bool ExecuteAction(ENUM_INDICATOR_ACTION _action, long _arg1) { + ARRAY(DataParamEntry, _args); + DataParamEntry _param1 = _arg1; + ArrayPushObject(_args, _param1); + _args[0].integer_value = _arg1; + return ExecuteAction(_action, _args); + } + + /* 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; + } + + /** + * Checks whether indicator has a valid value for a given shift. + */ + virtual bool HasValidEntry(int _shift = 0) { + unsigned int position; + long bar_time = GetBarTime(_shift); + + if (idata.KeyExists(bar_time, position)) { + return idata.GetByPos(position).IsValid(); + } + + 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; + } + + /** + * Returns shift at which the last known valid entry exists for a given + * period (or from the start, when period is not specified). + */ + bool GetLastValidEntryShift(int& out_shift, int period = 0) { + out_shift = 0; + + while (true) { + if ((period != 0 && out_shift >= period) || !HasValidEntry(out_shift + 1)) + return out_shift > 0; // Current shift is always invalid. + + ++out_shift; + } + + return out_shift > 0; + } + + /** + * Returns shift at which the oldest known valid entry exists for a given + * period (or from the start, when period is not specified). + */ + bool GetOldestValidEntryShift(int& out_shift, int& out_num_valid, int shift = 0, int period = 0) { + bool found = false; + // Counting from previous up to previous - period. + for (out_shift = shift + 1; out_shift < shift + period + 1; ++out_shift) { + if (!HasValidEntry(out_shift)) { + --out_shift; + out_num_valid = out_shift - shift; + return found; + } else + found = true; + } + + --out_shift; + out_num_valid = out_shift - shift; + return found; + } + + /** + * Checks whether indicator has valid at least given number of last entries + * (counting from given shift or 0). + */ + bool HasAtLeastValidLastEntries(int period, int shift = 0) { + for (int i = 0; i < period; ++i) + if (!HasValidEntry(shift + i)) return false; + + return true; + } + + virtual ENUM_IDATA_VALUE_RANGE GetIDataValueRange() = 0; + + ValueStorage* GetValueStorage(int _mode = 0) { + if (value_storages[_mode] == NULL) { + value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + } + return value_storages[_mode]; + } + + /** + * Returns indicator value for a given shift and mode. + */ + template + T GetValue(int _shift = 0, int _mode = -1) { + T _result; + int _index = _mode != -1 ? _mode : GetDataSourceMode(); + GetEntry(_shift).values[_index].Get(_result); + ResetLastError(); + return _result; + } + + /** + * Returns price corresponding to indicator value for a given shift and mode. + * + * Can be useful for calculating trailing stops based on the indicator. + * + * @return + * Returns price value of the corresponding indicator values. + */ + template + float GetValuePrice(int _shift = 0, int _mode = 0, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL) { + float _price = 0; + if (GetIDataValueRange() != IDATA_RANGE_PRICE) { + _price = (float)GetPrice(_ap, _shift); + } else if (GetIDataValueRange() == IDATA_RANGE_PRICE) { + // When indicator values are the actual prices. + T _values[4]; + if (!CopyValues(_values, 4, _shift, _mode)) { + // When values aren't valid, return 0. + return _price; + } + datetime _bar_time = GetBarTime(_shift); + float _value = 0; + BarOHLC _ohlc(_values, _bar_time); + _price = _ohlc.GetAppliedPrice(_ap); + } + return _price; + } + + /** + * Returns values for a given shift. + * + * Note: Remember to check if shift exists by HasValidEntry(shift). + */ + template + bool GetValues(int _shift, T& _out1, T& _out2) { + IndicatorDataEntry _entry = GetEntry(_shift); + _out1 = _entry.values[0]; + _out2 = _entry.values[1]; + bool _result = GetLastError() != 4401; + ResetLastError(); + return _result; + } + + template + bool GetValues(int _shift, T& _out1, T& _out2, T& _out3) { + IndicatorDataEntry _entry = GetEntry(_shift); + _out1 = _entry.values[0]; + _out2 = _entry.values[1]; + _out3 = _entry.values[2]; + bool _result = GetLastError() != 4401; + ResetLastError(); + return _result; + } + + template + bool GetValues(int _shift, T& _out1, T& _out2, T& _out3, T& _out4) { + IndicatorDataEntry _entry = GetEntry(_shift); + _out1 = _entry.values[0]; + _out2 = _entry.values[1]; + _out3 = _entry.values[2]; + _out4 = _entry.values[3]; + bool _result = GetLastError() != 4401; + ResetLastError(); + return _result; + } + + virtual void OnTick() {} + + /* Data representation methods */ + + /* Virtual methods */ + + /** + * Returns stored data in human-readable format. + */ + // virtual bool ToString() = NULL; // @fixme? + + /** + * Whether we can and have to select mode when specifying data source. + */ + virtual bool IsDataSourceModeSelectable() { return true; } + + /** + * Update indicator. + */ + virtual bool Update() { + // @todo + return false; + }; + + /** + * Returns the indicator's struct value. + */ + virtual IndicatorDataEntry GetEntry(int _shift = 0) { + IndicatorDataEntry _entry; + return _entry; + }; + + /** + * Returns the indicator's entry value. + */ + virtual MqlParam GetEntryValue(int _shift = 0, int _mode = 0) { + MqlParam _param = {TYPE_FLOAT}; + _param.double_value = (float)GetEntry(_shift).GetValue(_mode); + return _param; + } + + /** + * Returns the indicator's value in plain format. + */ + virtual string ToString(int _shift = 0) { + IndicatorDataEntry _entry = GetEntry(_shift); + int _serializer_flags = + SERIALIZER_FLAG_SKIP_HIDDEN | SERIALIZER_FLAG_INCLUDE_DEFAULT | SERIALIZER_FLAG_INCLUDE_DYNAMIC; + SerializerConverter _stub_indi = + SerializerConverter::MakeStubObject(_serializer_flags, _entry.GetSize()); + return SerializerConverter::FromObject(_entry, _serializer_flags).ToString(0, &_stub_indi); + } + + int GetBarsCalculated() { + int _bars = Bars(GetSymbol(), GetTf()); + + if (!is_fed) { + calc_start_bar = 0; + + // Calculating start_bar. + for (int i = 0; i < _bars; ++i) { + // Iterating from the oldest. + IndicatorDataEntry _entry = GetEntry(_bars - i - 1); + + if (_entry.IsValid()) { + // From this point we assume that future entries will be all valid. + calc_start_bar = i; + is_fed = true; + + return _bars - calc_start_bar; + } + } + } + + // Assuming all entries are calculated (even if have invalid values). + return _bars; + } +}; + +/** + * CopyBuffer() method to be used on Indicator instance with ValueStorage buffer. + * + * Note that data will be copied so that the oldest element will be located at the start of the physical memory + * allocated for the array + */ +template +int CopyBuffer(IndicatorBase* _indi, int _mode, int _start, int _count, ValueStorage& _buffer, int _rates_total) { + int _num_copied = 0; + int _buffer_size = ArraySize(_buffer); + + if (_buffer_size < _rates_total) { + _buffer_size = ArrayResize(_buffer, _rates_total); + } + + for (int i = _start; i < _count; ++i) { + IndicatorDataEntry _entry = _indi.GetEntry(i); + + if (!_entry.IsValid()) { + break; + } + + T _value = _entry.GetValue(_mode); + + // Print(_value); + + _buffer[_buffer_size - i - 1] = _value; + ++_num_copied; + } + + return _num_copied; +} + +/** + * BarsCalculated()-compatible method to be used on Indicator instance. + */ +int BarsCalculated(IndicatorBase* _indi) { return _indi.GetBarsCalculated(); } diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index bfd955cf2..9ec62d809 100644 --- a/Indicators/Bitwise/Indi_Candle.mqh +++ b/Indicators/Bitwise/Indi_Candle.mqh @@ -32,16 +32,14 @@ // Structs. struct CandleParams : IndicatorParams { // Struct constructor. - void CandleParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_CANDLE; - max_modes = 1; - SetDataValueType(TYPE_INT); + CandleParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorParams(INDI_CANDLE, 1, TYPE_INT) { SetDataValueRange(IDATA_RANGE_RANGE); + SetDataSourceType(IDATA_BUILTIN); shift = _shift; tf = _tf; }; - void CandleParams(CandleParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + CandleParams(CandleParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -49,16 +47,13 @@ struct CandleParams : IndicatorParams { /** * Implements Candle Pattern Detector. */ -class Indi_Candle : public Indicator { - protected: - CandleParams params; - +class Indi_Candle : public Indicator { public: /** * Class constructor. */ - Indi_Candle(CandleParams &_params) : params(_params), Indicator((IndicatorParams)_params){}; - Indi_Candle(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_CANDLE, _tf) { params.tf = _tf; }; + Indi_Candle(CandleParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_Candle(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_CANDLE, _tf) { iparams.tf = _tf; }; /** * Returns the indicator's struct value. @@ -66,7 +61,7 @@ class Indi_Candle : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { @@ -75,7 +70,7 @@ class Indi_Candle : public Indicator { ResetLastError(); BarOHLC _ohlcs[1]; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: // In this mode, price is fetched from chart. _ohlcs[0] = Chart::GetOHLC(_shift); @@ -84,7 +79,7 @@ class Indi_Candle : public 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 (GetDataSource() == NULL) { + if (indi_src == NULL) { GetLogger().Error( "In order use custom indicator as a source, you need to select one using SetIndicatorData() method, " "which is a part of CandleParams structure.", @@ -98,10 +93,10 @@ class Indi_Candle : public Indicator { return _entry; } - _ohlcs[0].open = GetDataSource().GetValue(_shift, PRICE_OPEN); - _ohlcs[0].high = GetDataSource().GetValue(_shift, PRICE_HIGH); - _ohlcs[0].low = GetDataSource().GetValue(_shift, PRICE_LOW); - _ohlcs[0].close = GetDataSource().GetValue(_shift, PRICE_CLOSE); + _ohlcs[0].open = indi_src.GetValue(_shift, PRICE_OPEN); + _ohlcs[0].high = indi_src.GetValue(_shift, PRICE_HIGH); + _ohlcs[0].low = indi_src.GetValue(_shift, PRICE_LOW); + _ohlcs[0].close = indi_src.GetValue(_shift, PRICE_CLOSE); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -116,7 +111,7 @@ class Indi_Candle : public Indicator { istate.is_ready = true; if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index eecbeb1c0..e280631f4 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -32,17 +32,13 @@ double iAC(string _symbol, int _tf, int _shift) { return Indi_AC::iAC(_symbol, ( // Structs. struct ACParams : IndicatorParams { // Struct constructor. - void ACParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_AC; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); + ACParams(int _shift = 0) : IndicatorParams(INDI_AC, 1, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Accelerator"); shift = _shift; - tf = _tf; }; - void ACParams(ACParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ACParams(ACParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -50,16 +46,13 @@ struct ACParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_AC : public Indicator { - protected: - ACParams params; - +class Indi_AC : public Indicator { public: /** * Class constructor. */ - Indi_AC(ACParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_AC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_AC, _tf) { params.SetTf(_tf); }; + Indi_AC(ACParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_AC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_AC, _tf){}; /** * Returns the indicator value. @@ -69,7 +62,7 @@ class Indi_AC : public Indicator { * - https://www.mql5.com/en/docs/indicators/iac */ static double iAC(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iAC(_symbol, _tf, _shift); #else // __MQL5__ @@ -87,7 +80,7 @@ class Indi_AC : public Indicator { 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); + int _bars_calc = ::BarsCalculated(_handle); if (GetLastError() > 0) { return EMPTY_VALUE; } else if (_bars_calc <= 2) { @@ -105,16 +98,16 @@ class Indi_AC : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_AC::iAC(GetSymbol(), GetTf(), _shift, GetPointer(this)); + _value = Indi_AC::iAC(GetSymbol(), GetTf(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -124,29 +117,6 @@ class Indi_AC : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns reusable indicator for a given symbol and time-frame. */ diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index afe5b1d50..b935032f5 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -31,17 +31,13 @@ double iAD(string _symbol, int _tf, int _shift) { return Indi_AD::iAD(_symbol, ( // Structs. struct ADParams : IndicatorParams { // Struct constructor. - ADParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_AD; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); + ADParams(int _shift = 0) : IndicatorParams(INDI_AD, 1, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\AD"); shift = _shift; - tf = _tf; }; - ADParams(ADParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ADParams(ADParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -49,16 +45,13 @@ struct ADParams : IndicatorParams { /** * Implements the Accumulation/Distribution indicator. */ -class Indi_AD : public Indicator { - protected: - ADParams params; - +class Indi_AD : public Indicator { public: /** * Class constructor. */ - Indi_AD(ADParams &_p) : Indicator((IndicatorParams)_p) { params = _p; }; - Indi_AD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_AD, _tf) { params.SetTf(_tf); }; + Indi_AD(ADParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_AD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_AD, _tf) { iparams.SetTf(_tf); }; /** * Returns the indicator value. @@ -68,7 +61,7 @@ class Indi_AD : public Indicator { * - https://www.mql5.com/en/docs/indicators/iad */ static double iAD(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iAD(_symbol, _tf, _shift); #else // __MQL5__ @@ -104,18 +97,16 @@ class Indi_AD : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_AD::iAD(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), _shift, - GetPointer(this)); + _value = Indi_AD::iAD(GetSymbol(), GetTf(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -125,29 +116,6 @@ class Indi_AD : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index ed2d792a2..104c0ca15 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -37,14 +37,11 @@ struct ADXParams : IndicatorParams { unsigned int period; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - void ADXParams(unsigned int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) - : period(_period), applied_price(_ap) { - itype = itype == INDI_NONE ? INDI_ADX : itype; + ADXParams(unsigned int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0, + ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) + : period(_period), applied_price(_ap), IndicatorParams(INDI_ADX, FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE) { SetDataSourceType(_idstype); - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_RANGE); - SetMaxModes(FINAL_INDI_ADX_LINE_ENTRY); SetShift(_shift); switch (idstype) { case IDATA_ICUSTOM: @@ -52,15 +49,10 @@ struct ADXParams : IndicatorParams { SetCustomIndicatorName("Examples\\ADX"); } break; - case IDATA_INDICATOR: - if (indi_data_source == NULL) { - SetDataSource(Indi_Price::GetCached(_shift, _tf, applied_price, _period)); - } - break; } }; - void ADXParams(ADXParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ADXParams(ADXParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -68,15 +60,12 @@ struct ADXParams : IndicatorParams { /** * Implements the Average Directional Movement Index indicator. */ -class Indi_ADX : public Indicator { - protected: - ADXParams params; - +class Indi_ADX : public Indicator { public: /** * Class constructor. */ - Indi_ADX(ADXParams &_p) : params(_p.period, _p.applied_price), Indicator((IndicatorParams)_p) { params = _p; } + Indi_ADX(ADXParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} Indi_ADX(ENUM_TIMEFRAMES _tf) : Indicator(INDI_ADX, _tf) {} /** @@ -90,7 +79,7 @@ class Indi_ADX : public Indicator { ENUM_APPLIED_PRICE _applied_price, // (MT5): not used int _mode = LINE_MAIN_ADX, // (MT4/MT5): 0 - MODE_MAIN/MAIN_LINE, 1 - // MODE_PLUSDI/PLUSDI_LINE, 2 - MODE_MINUSDI/MINUSDI_LINE - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iADX(_symbol, _tf, _period, _applied_price, _mode, _shift); #else // __MQL5__ @@ -126,18 +115,17 @@ class Indi_ADX : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { + virtual double GetValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_ADX::iADX(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - GetAppliedPrice(), _mode, _shift, GetPointer(this)); + _value = Indi_ADX::iADX(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -147,30 +135,6 @@ class Indi_ADX : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = Indi_ADX::GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue((double)NULL) && !_entry.HasValue(EMPTY_VALUE) && - _entry.IsWithinRange(0.0, 100.0)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -180,19 +144,26 @@ class Indi_ADX : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return Indicator::IsValidEntry(_entry) && _entry.IsWithinRange(0.0, 100.0); + } + /* Getters */ /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get applied price value. * * Note: Not used in MT5. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -201,7 +172,7 @@ class Indi_ADX : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -211,6 +182,6 @@ class Indi_ADX : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 4ca230c58..ee8ac7436 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -36,8 +36,8 @@ // Structs. struct ADXWParams : ADXParams { // Struct constructor. - void ADXWParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) + ADXWParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0, + ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) : ADXParams(_period, _ap, _shift, _tf, _idstype) { itype = itype == INDI_NONE || itype == INDI_ADX ? INDI_ADXW : itype; switch (idstype) { @@ -46,29 +46,28 @@ struct ADXWParams : ADXParams { break; } }; - void ADXWParams(ADXWParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : ADXParams(_params, _tf) {} - void ADXWParams(ADXParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : ADXParams(_params, _tf) {} + ADXWParams(ADXWParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; + tf = _tf; + }; }; /** * Implements the Average Directional Movement Index indicator by Welles Wilder. */ -class Indi_ADXW : public Indicator { - protected: - ADXWParams params; - +class Indi_ADXW : public Indicator { public: /** * Class constructor. */ - Indi_ADXW(ADXWParams &_params) : params(_params.period), Indicator((IndicatorParams)_params) { params = _params; }; - Indi_ADXW(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_ADXW, _tf) { params.tf = _tf; }; + Indi_ADXW(ADXWParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_ADXW(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_ADXW, _tf){}; /** * Built-in version of ADX Wilder. */ static double iADXWilder(string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, int _mode = LINE_MAIN_ADX, - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iADXWilder(_symbol, _tf, _ma_period), _mode, _shift); #else @@ -216,16 +215,16 @@ class Indi_ADXW : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { + virtual double GetValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + 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); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, _mode, _shift); break; default: @@ -236,29 +235,6 @@ class Indi_ADXW : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_DOUBLE, true); - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -273,7 +249,7 @@ class Indi_ADXW : public Indicator { /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /* Setters */ @@ -282,6 +258,6 @@ class Indi_ADXW : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } }; diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index 0041828d0..1e16b0a81 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -35,37 +35,26 @@ struct IndiAMAParams : IndicatorParams { unsigned int ama_shift; ENUM_APPLIED_PRICE applied_price; // Struct constructor. - void IndiAMAParams(int _period = 10, int _fast_period = 2, int _slow_period = 30, int _ama_shift = 0, - ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, - ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) + IndiAMAParams(int _period = 10, int _fast_period = 2, int _slow_period = 30, int _ama_shift = 0, + ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) : period(_period), fast_period(_fast_period), slow_period(_slow_period), ama_shift(_ama_shift), - applied_price(_ap) { - itype = itype == INDI_NONE ? INDI_AMA : itype; - SetDataSourceType(_idstype); - SetDataValueType(TYPE_DOUBLE); + applied_price(_ap), + IndicatorParams(INDI_AMA, 1, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_PRICE); - SetMaxModes(1); SetShift(_shift); - tf = _tf; switch (idstype) { case IDATA_ICUSTOM: if (custom_indi_name == "") { SetCustomIndicatorName("Examples\\AMA"); } break; - case IDATA_INDICATOR: - if (GetDataSource() == NULL) { - SetDataSource(Indi_Price::GetCached(_shift, _tf, _ap, _period), false); - SetDataSourceMode(0); - } - break; } }; - void IndiAMAParams(IndiAMAParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + IndiAMAParams(IndiAMAParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -73,22 +62,20 @@ struct IndiAMAParams : IndicatorParams { /** * Implements the AMA indicator. */ -class Indi_AMA : public Indicator { - protected: - IndiAMAParams params; - +class Indi_AMA : public Indicator { public: /** * Class constructor. */ - Indi_AMA(IndiAMAParams &_params) : params(_params.period), Indicator((IndicatorParams)_params) { params = _params; }; - Indi_AMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_AMA, _tf) { params.tf = _tf; }; + Indi_AMA(IndiAMAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_AMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_AMA, _tf){}; /** * Built-in version of AMA. */ static double iAMA(string _symbol, ENUM_TIMEFRAMES _tf, int _ama_period, int _fast_ema_period, int _slow_ema_period, - int _ama_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + int _ama_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, + IndicatorBase *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN( ::iAMA(_symbol, _tf, _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, _ap), _mode, _shift); @@ -212,16 +199,16 @@ class Indi_AMA : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_AMA::iAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), GetAMAShift(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ GetPeriod(), + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), GetAMAShift() /*]*/, _mode, _shift); break; @@ -237,29 +224,6 @@ class Indi_AMA : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -274,27 +238,27 @@ class Indi_AMA : public Indicator { /** * Get AMA shift. */ - unsigned int GetAMAShift() { return params.ama_shift; } + unsigned int GetAMAShift() { return iparams.ama_shift; } /** * Get period. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get fast period. */ - unsigned int GetFastPeriod() { return params.fast_period; } + unsigned int GetFastPeriod() { return iparams.fast_period; } /** * Get slow period. */ - unsigned int GetSlowPeriod() { return params.slow_period; } + unsigned int GetSlowPeriod() { return iparams.slow_period; } /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -303,7 +267,7 @@ class Indi_AMA : public Indicator { */ void SetAMAShift(unsigned int _ama_shift) { istate.is_changed = true; - params.ama_shift = _ama_shift; + iparams.ama_shift = _ama_shift; } /** @@ -311,7 +275,7 @@ class Indi_AMA : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -319,7 +283,7 @@ class Indi_AMA : public Indicator { */ void SetFastPeriod(unsigned int _fast_period) { istate.is_changed = true; - params.fast_period = _fast_period; + iparams.fast_period = _fast_period; } /** @@ -327,7 +291,7 @@ class Indi_AMA : public Indicator { */ void SetSlowPeriod(unsigned int _slow_period) { istate.is_changed = true; - params.slow_period = _slow_period; + iparams.slow_period = _slow_period; } /** @@ -335,6 +299,6 @@ class Indi_AMA : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index d93977120..8d974e9ae 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -31,21 +31,16 @@ double iAO(string _symbol, int _tf, int _shift) { return Indi_AO::iAO(_symbol, ( // Structs. struct AOParams : IndicatorParams { // Struct constructor. - void AOParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_AO; + AOParams(int _shift = 0) : IndicatorParams(INDI_AO, 2, TYPE_DOUBLE) { #ifdef __MQL4__ max_modes = 1; -#else - max_modes = 2; #endif - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Awesome_Oscillator"); shift = _shift; - tf = _tf; }; - void AOParams(AOParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + AOParams(AOParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -53,16 +48,13 @@ struct AOParams : IndicatorParams { /** * Implements the Awesome oscillator. */ -class Indi_AO : public Indicator { - protected: - AOParams params; - +class Indi_AO : public Indicator { public: /** * Class constructor. */ - Indi_AO(AOParams &_p) : Indicator((IndicatorParams)_p) { params = _p; }; - Indi_AO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : params(_tf), Indicator(INDI_AO, _tf){}; + Indi_AO(AOParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_AO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_AO, _tf){}; /** * Returns the indicator value. @@ -72,7 +64,7 @@ class Indi_AO : public Indicator { * - https://www.mql5.com/en/docs/indicators/iao */ static double iAO(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, int _mode = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ // Note: In MQL4 _mode is not supported. return ::iAO(_symbol, _tf, _shift); @@ -91,7 +83,7 @@ class Indi_AO : public Indicator { 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); + int _bars_calc = ::BarsCalculated(_handle); if (GetLastError() > 0) { return EMPTY_VALUE; } else if (_bars_calc <= 2) { @@ -109,18 +101,16 @@ class Indi_AO : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_AO::iAO(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), _shift, _mode, - GetPointer(this)); + _value = Indi_AO::iAO(GetSymbol(), GetTf(), _shift, _mode, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -130,29 +120,6 @@ class Indi_AO : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, _entry.values[0].Get() != EMPTY_VALUE); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns reusable indicator for a given symbol and time-frame. */ @@ -165,6 +132,11 @@ class Indi_AO : public Indicator { return _ptr; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return _entry.values[0].Get() != EMPTY_VALUE; } + /** * Returns the indicator's entry value. */ diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index 25019c8df..9e2fa43b4 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -30,19 +30,15 @@ struct ASIParams : IndicatorParams { unsigned int period; double mpc; // Struct constructor. - void ASIParams(double _mpc = 300.0, int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_ASI; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); + ASIParams(double _mpc = 300.0, int _shift = 0) + : IndicatorParams(INDI_ASI, 1, TYPE_DOUBLE, PERIOD_CURRENT, IDATA_ONCALCULATE) { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ASI"); - SetDataSourceType(IDATA_BUILTIN); mpc = _mpc; shift = _shift; - tf = _tf; }; - void ASIParams(ASIParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ASIParams(ASIParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -50,22 +46,19 @@ struct ASIParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_ASI : public Indicator { - protected: - ASIParams params; - +class Indi_ASI : public Indicator { public: /** * Class constructor. */ - Indi_ASI(ASIParams &_params) : params(_params.mpc), Indicator((IndicatorParams)_params) { params = _params; }; - Indi_ASI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_ASI, _tf) { params.tf = _tf; }; + Indi_ASI(ASIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_ASI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_ASI, _tf){}; /** * Built-in version of ASI. */ static double iASI(string _symbol, ENUM_TIMEFRAMES _tf, double _mpc, int _mode = 0, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_ASI", _mpc)); return iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mpc, _mode, _shift, _cache); } @@ -162,17 +155,21 @@ class Indi_ASI : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { - case IDATA_BUILTIN: - _value = Indi_ASI::iASI(GetSymbol(), GetTf(), /*[*/ GetMaximumPriceChanging() /*]*/, _mode, _shift, THIS_PTR); - break; + switch (iparams.idstype) { case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetMaximumPriceChanging() /*]*/, 0, _shift); break; + case IDATA_ONCALCULATE: { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(GetSymbol(), GetTf(), + Util::MakeKey("Indi_ASI", GetMaximumPriceChanging())); + _value = + iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, GetMaximumPriceChanging(), _mode, _shift, _cache); + break; + } default: SetUserError(ERR_INVALID_PARAMETER); } @@ -181,29 +178,6 @@ class Indi_ASI : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -218,7 +192,7 @@ class Indi_ASI : public Indicator { /** * Get maximum price changing value. */ - double GetMaximumPriceChanging() { return params.mpc; } + double GetMaximumPriceChanging() { return iparams.mpc; } /* Setters */ @@ -227,6 +201,6 @@ class Indi_ASI : public Indicator { */ void GetMaximumPriceChanging(double _mpc) { istate.is_changed = true; - params.mpc = _mpc; + iparams.mpc = _mpc; } }; diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index e005da486..72e536663 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -34,18 +34,13 @@ double iATR(string _symbol, int _tf, int _period, int _shift) { struct ATRParams : IndicatorParams { unsigned int period; // Struct constructors. - void ATRParams(unsigned int _period = 14, int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _symbol = NULL) - : period(_period) { - itype = INDI_ATR; - max_modes = 1; + ATRParams(unsigned int _period = 14, int _shift = 0) : period(_period), IndicatorParams(INDI_ATR, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ATR"); - tf = _tf; }; - void ATRParams(ATRParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ATRParams(ATRParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -55,15 +50,13 @@ struct ATRParams : IndicatorParams { * * Note: It doesn't give independent signals. It is used to define volatility (trend strength). */ -class Indi_ATR : public Indicator { +class Indi_ATR : public Indicator { public: - ATRParams params; - /** * Class constructor. */ - Indi_ATR(ATRParams &_p) : params(_p.period), Indicator((IndicatorParams)_p) { params = _p; } - Indi_ATR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_ATR, _tf) { params.SetTf(_tf); }; + Indi_ATR(ATRParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_ATR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_ATR, _tf){}; /** * Returns the indicator value. @@ -73,7 +66,7 @@ class Indi_ATR : public Indicator { * - https://www.mql5.com/en/docs/indicators/iatr */ static double iATR(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iATR(_symbol, _tf, _period, _shift); #else // __MQL5__ @@ -109,16 +102,16 @@ class Indi_ATR : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_ATR::iATR(GetSymbol(), GetTf(), GetPeriod(), _shift, GetPointer(this)); + _value = Indi_ATR::iATR(GetSymbol(), GetTf(), GetPeriod(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -128,29 +121,6 @@ class Indi_ATR : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -167,8 +137,8 @@ class Indi_ATR : public Indicator { Indi_ATR *_ptr; string _key = Util::MakeKey(_symbol, (int)_tf, _period); if (!Objects::TryGet(_key, _ptr)) { - ATRParams _params(_period, _tf); - _ptr = Objects::Set(_key, new Indi_ATR(_params)); + ATRParams _p(_period, _tf); + _ptr = Objects::Set(_key, new Indi_ATR(_p)); _ptr.SetSymbol(_symbol); } return _ptr; @@ -179,7 +149,7 @@ class Indi_ATR : public Indicator { /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /* Setters */ @@ -188,6 +158,6 @@ class Indi_ATR : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } }; diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index cb7877526..9784d0876 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -70,8 +70,8 @@ struct AlligatorParams : IndicatorParams { ENUM_MA_METHOD ma_method; // Averaging method. ENUM_APPLIED_PRICE applied_price; // Applied price. // Struct constructors. - void AlligatorParams(int _jp = 13, int _js = 8, int _tp = 8, int _ts = 5, int _lp = 5, int _ls = 3, - ENUM_MA_METHOD _mm = MODE_SMMA, ENUM_APPLIED_PRICE _ap = PRICE_MEDIAN, int _shift = 0) + AlligatorParams(int _jp = 13, int _js = 8, int _tp = 8, int _ts = 5, int _lp = 5, int _ls = 3, + ENUM_MA_METHOD _mm = MODE_SMMA, ENUM_APPLIED_PRICE _ap = PRICE_MEDIAN, int _shift = 0) : jaw_period(_jp), jaw_shift(_js), teeth_period(_tp), @@ -79,17 +79,14 @@ struct AlligatorParams : IndicatorParams { lips_period(_lp), lips_shift(_ls), ma_method(_mm), - applied_price(_ap) { - itype = INDI_ALLIGATOR; - max_modes = FINAL_ALLIGATOR_LINE_ENTRY; + applied_price(_ap), + IndicatorParams(INDI_ALLIGATOR, FINAL_ALLIGATOR_LINE_ENTRY, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_PRICE); - SetDataSourceType(IDATA_BUILTIN); SetCustomIndicatorName("Examples\\Alligator"); }; - void AlligatorParams(AlligatorParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + AlligatorParams(AlligatorParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -97,15 +94,12 @@ struct AlligatorParams : IndicatorParams { /** * Implements the Alligator indicator. */ -class Indi_Alligator : public Indicator { +class Indi_Alligator : public Indicator { public: - AlligatorParams params; - /** * Class constructor. */ - Indi_Alligator(AlligatorParams &_p) : Indicator((IndicatorParams)_p) { params = _p; } - Indi_Alligator(AlligatorParams &_p, ENUM_TIMEFRAMES _tf) : Indicator(INDI_ALLIGATOR, _tf) { params = _p; } + Indi_Alligator(AlligatorParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} Indi_Alligator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_ADX, _tf){}; /** @@ -129,7 +123,7 @@ class Indi_Alligator : public Indicator { static double iAlligator(string _symbol, ENUM_TIMEFRAMES _tf, int _jaw_period, int _jaw_shift, int _teeth_period, int _teeth_shift, int _lips_period, int _lips_shift, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_PRICE _applied_price, ENUM_ALLIGATOR_LINE _mode, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iAlligator(_symbol, _tf, _jaw_period, _jaw_shift, _teeth_period, _teeth_shift, _lips_period, _lips_shift, _ma_method, _applied_price, _mode, _shift); @@ -167,7 +161,7 @@ class Indi_Alligator : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_ALLIGATOR_LINE _mode, int _shift = 0) { + virtual double GetValue(int _mode, int _shift = 0) { #ifdef __MQL4__ if (_mode == 0) { // In MQL4 mode 0 should be treated as mode 1 as Alligator buffers starts from index 1. @@ -176,17 +170,15 @@ class Indi_Alligator : public Indicator { #endif ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Alligator::iAlligator(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), - GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice(), _mode, - _shift, GetPointer(this)); + _value = Indi_Alligator::iAlligator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), + GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), + GetAppliedPrice(), (ENUM_ALLIGATOR_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice() @@ -207,18 +199,17 @@ class Indi_Alligator : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { + for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) { _entry.values[_mode] = GetValue((ENUM_ALLIGATOR_LINE)_mode, _shift); } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, - !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGt(0)); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } @@ -238,47 +229,54 @@ class Indi_Alligator : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGt(0); + } + /* Class getters */ /** * Get jaw period value. */ - int GetJawPeriod() { return params.jaw_period; } + int GetJawPeriod() { return iparams.jaw_period; } /** * Get jaw shift value. */ - int GetJawShift() { return params.jaw_shift; } + int GetJawShift() { return iparams.jaw_shift; } /** * Get teeth period value. */ - int GetTeethPeriod() { return params.teeth_period; } + int GetTeethPeriod() { return iparams.teeth_period; } /** * Get teeth shift value. */ - int GetTeethShift() { return params.teeth_shift; } + int GetTeethShift() { return iparams.teeth_shift; } /** * Get lips period value. */ - int GetLipsPeriod() { return params.lips_period; } + int GetLipsPeriod() { return iparams.lips_period; } /** * Get lips shift value. */ - int GetLipsShift() { return params.lips_shift; } + int GetLipsShift() { return iparams.lips_shift; } /** * Get MA method. */ - ENUM_MA_METHOD GetMAMethod() { return params.ma_method; } + ENUM_MA_METHOD GetMAMethod() { return iparams.ma_method; } /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Class setters */ @@ -287,7 +285,7 @@ class Indi_Alligator : public Indicator { */ void SetJawPeriod(int _jaw_period) { istate.is_changed = true; - params.jaw_period = _jaw_period; + iparams.jaw_period = _jaw_period; } /** @@ -295,7 +293,7 @@ class Indi_Alligator : public Indicator { */ void SetJawShift(int _jaw_shift) { istate.is_changed = true; - params.jaw_shift = _jaw_shift; + iparams.jaw_shift = _jaw_shift; } /** @@ -303,7 +301,7 @@ class Indi_Alligator : public Indicator { */ void SetTeethPeriod(int _teeth_period) { istate.is_changed = true; - params.teeth_period = _teeth_period; + iparams.teeth_period = _teeth_period; } /** @@ -311,7 +309,7 @@ class Indi_Alligator : public Indicator { */ void SetTeethShift(int _teeth_shift) { istate.is_changed = true; - params.teeth_period = _teeth_shift; + iparams.teeth_period = _teeth_shift; } /** @@ -319,7 +317,7 @@ class Indi_Alligator : public Indicator { */ void SetLipsPeriod(int _lips_period) { istate.is_changed = true; - params.lips_period = _lips_period; + iparams.lips_period = _lips_period; } /** @@ -327,7 +325,7 @@ class Indi_Alligator : public Indicator { */ void SetLipsShift(int _lips_shift) { istate.is_changed = true; - params.lips_period = _lips_shift; + iparams.lips_period = _lips_shift; } /** @@ -335,7 +333,7 @@ class Indi_Alligator : public Indicator { */ void SetMAMethod(ENUM_MA_METHOD _ma_method) { istate.is_changed = true; - params.ma_method = _ma_method; + iparams.ma_method = _ma_method; } /** @@ -343,6 +341,6 @@ class Indi_Alligator : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_AppliedPrice.mqh b/Indicators/Indi_AppliedPrice.mqh index a83920e50..c8fdf1b7b 100644 --- a/Indicators/Indi_AppliedPrice.mqh +++ b/Indicators/Indi_AppliedPrice.mqh @@ -28,19 +28,15 @@ struct AppliedPriceParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructor. - AppliedPriceParams(ENUM_APPLIED_PRICE _applied_price = PRICE_OPEN, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_APPLIED_PRICE; - max_modes = 1; + AppliedPriceParams(ENUM_APPLIED_PRICE _applied_price = PRICE_OPEN, int _shift = 0) + : IndicatorParams(INDI_APPLIED_PRICE, 1, TYPE_DOUBLE) { applied_price = _applied_price; - SetDataValueType(TYPE_DOUBLE); - SetDataValueRange(IDATA_RANGE_PRICE); SetDataSourceType(IDATA_INDICATOR); + SetDataValueRange(IDATA_RANGE_PRICE); shift = _shift; - tf = _tf; }; - AppliedPriceParams(AppliedPriceParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + AppliedPriceParams(AppliedPriceParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -48,18 +44,16 @@ struct AppliedPriceParams : IndicatorParams { /** * Implements the "Applied Price over OHCL Indicator" indicator, e.g. over Indi_Price. */ -class Indi_AppliedPrice : public Indicator { - protected: - AppliedPriceParams params; - +class Indi_AppliedPrice : public Indicator { public: /** * Class constructor. */ - Indi_AppliedPrice(AppliedPriceParams &_params) : params(_params), Indicator((IndicatorParams)_params){}; - Indi_AppliedPrice(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : params(PRICE_OPEN, 0, _tf), Indicator(INDI_PRICE, _tf){}; + Indi_AppliedPrice(AppliedPriceParams &_p, IndicatorBase *_indi_src = NULL) + : Indicator(_p, _indi_src){}; + Indi_AppliedPrice(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_PRICE, _tf){}; - static double iAppliedPriceOnIndicator(Indicator *_indi, ENUM_APPLIED_PRICE _applied_price, int _shift = 0) { + static double iAppliedPriceOnIndicator(IndicatorBase *_indi, ENUM_APPLIED_PRICE _applied_price, int _shift = 0) { double _ohlc[4]; _indi[_shift].GetArray(_ohlc, 4); return BarOHLC::GetAppliedPrice(_applied_price, _ohlc[0], _ohlc[1], _ohlc[2], _ohlc[3]); @@ -68,21 +62,28 @@ class Indi_AppliedPrice : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_INDICATOR: if (HasDataSource()) { - // Future validation of GetDataSource() will check if we set mode for source indicator + // Future validation of indi_src will check if we set mode for source indicator // (e.g. for applied price of Indi_Price). iparams.SetDataSourceMode(GetAppliedPrice()); + } else { + Print("Indi_AppliedPrice requires source indicator to be set via SetDataSource()!"); + DebugBreak(); } - if (GetDataSource().GetParams().GetMaxModes() != 4) { + + // @fixit + /* + if (indi_src.GetParams().GetMaxModes() != 4) { Print("Indi_AppliedPrice indicator requires that has at least 4 modes/buffers (OHLC)!"); DebugBreak(); } - _value = Indi_AppliedPrice::iAppliedPriceOnIndicator(GetDataSource(), GetAppliedPrice(), _shift); + */ + _value = Indi_AppliedPrice::iAppliedPriceOnIndicator(indi_src, GetAppliedPrice(), _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -92,29 +93,6 @@ class Indi_AppliedPrice : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -129,7 +107,7 @@ class Indi_AppliedPrice : public Indicator { /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -138,6 +116,6 @@ class Indi_AppliedPrice : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index 3929ea7db..0b192e89d 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -42,18 +42,15 @@ enum ENUM_MFI_COLOR { // Structs. struct BWMFIParams : IndicatorParams { + ENUM_APPLIED_VOLUME ap; // @todo // Struct constructors. - BWMFIParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_BWMFI; - max_modes = FINAL_BWMFI_BUFFER_ENTRY; - SetDataValueType(TYPE_DOUBLE); + BWMFIParams(int _shift = 0) : IndicatorParams(INDI_BWMFI, FINAL_BWMFI_BUFFER_ENTRY, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); - SetCustomIndicatorName("Examples\\MarketFacilitationIndex"); shift = _shift; - tf = _tf; + SetCustomIndicatorName("Examples\\MarketFacilitationIndex"); }; - BWMFIParams(BWMFIParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + BWMFIParams(BWMFIParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -61,15 +58,12 @@ struct BWMFIParams : IndicatorParams { /** * Implements the Market Facilitation Index by Bill Williams indicator. */ -class Indi_BWMFI : public Indicator { - protected: - BWMFIParams params; - +class Indi_BWMFI : public Indicator { public: /** * Class constructor. */ - Indi_BWMFI(IndicatorParams &_p) : Indicator((IndicatorParams)_p) {} + Indi_BWMFI(BWMFIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} Indi_BWMFI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_BWMFI, _tf) {} /** @@ -80,7 +74,7 @@ class Indi_BWMFI : public Indicator { * - https://www.mql5.com/en/docs/indicators/ibwmfi */ static double iBWMFI(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - ENUM_BWMFI_BUFFER _mode = BWMFI_BUFFER, Indicator *_obj = NULL) { + ENUM_BWMFI_BUFFER _mode = BWMFI_BUFFER, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ // Adjusting shift for MT4. _shift++; @@ -118,18 +112,17 @@ class Indi_BWMFI : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_BWMFI_BUFFER _mode = BWMFI_BUFFER, int _shift = 0) { + virtual double GetValue(int _mode = BWMFI_BUFFER, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = _value = iBWMFI(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), _shift, _mode, - GetPointer(this)); + _value = Indi_BWMFI::iBWMFI(GetSymbol(), GetTf(), _shift, (ENUM_BWMFI_BUFFER)_mode, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, + _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -145,7 +138,7 @@ class Indi_BWMFI : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { @@ -186,9 +179,9 @@ class Indi_BWMFI : public Indicator { _histcolor = GetValue(BWMFI_HISTCOLOR, _shift); #endif _entry.values[BWMFI_HISTCOLOR] = _histcolor; - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, _entry.values[BWMFI_BUFFER] != 0 && !_entry.HasValue(EMPTY_VALUE)); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); idata.Add(_entry, _bar_time); } } diff --git a/Indicators/Indi_BWZT.mqh b/Indicators/Indi_BWZT.mqh index 4da952fe2..f57d94355 100644 --- a/Indicators/Indi_BWZT.mqh +++ b/Indicators/Indi_BWZT.mqh @@ -23,6 +23,7 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" #include "Indi_AC.mqh" #include "Indi_AO.mqh" @@ -32,18 +33,13 @@ struct BWZTParams : IndicatorParams { unsigned int second_period; unsigned int sum_period; // Struct constructor. - void BWZTParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_BWZT; - max_modes = 5; - SetDataValueType(TYPE_DOUBLE); + BWZTParams(int _shift = 0) : IndicatorParams(INDI_BWZT, 5, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\BW-ZoneTrade"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; }; - void BWZTParams(BWZTParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + BWZTParams(BWZTParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -51,25 +47,22 @@ struct BWZTParams : IndicatorParams { /** * Implements the Bill Williams' Zone Trade. */ -class Indi_BWZT : public Indicator { - protected: - BWZTParams params; - +class Indi_BWZT : public Indicator { public: /** * Class constructor. */ - Indi_BWZT(BWZTParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_BWZT(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_BWZT, _tf) { params.tf = _tf; }; + Indi_BWZT(BWZTParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_BWZT(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_BWZT, _tf){}; /** * Built-in version of BWZT. */ - static double iBWZT(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + static double iBWZT(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_BWZT"); - Indicator *_indi_ac = Indi_AC::GetCached(_symbol, _tf); - Indicator *_indi_ao = Indi_AO::GetCached(_symbol, _tf); + Indi_AC *_indi_ac = Indi_AC::GetCached(_symbol, _tf); + Indi_AO *_indi_ao = Indi_AO::GetCached(_symbol, _tf); return iBWZTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache, _indi_ac, _indi_ao); } @@ -78,7 +71,7 @@ class Indi_BWZT : public Indicator { * Calculates BWZT on the array of values. */ static double iBWZTOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _shift, - IndicatorCalculateCache *_cache, Indicator *_indi_ac, Indicator *_indi_ao, + IndicatorCalculateCache *_cache, Indi_AC *_indi_ac, Indi_AO *_indi_ao, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -105,15 +98,15 @@ class Indi_BWZT : public Indicator { ValueStorage &ExtHBuffer, ValueStorage &ExtLBuffer, ValueStorage &ExtCBuffer, ValueStorage &ExtColorBuffer, ValueStorage &ExtAOBuffer, ValueStorage &ExtACBuffer, int DATA_LIMIT, - Indicator *ExtACHandle, Indicator *ExtAOHandle) { + IndicatorBase *ExtACHandle, IndicatorBase *ExtAOHandle) { if (rates_total < DATA_LIMIT) return (0); // Not all data may be calculated. - int calculated = BarsCalculated(ExtACHandle, rates_total); + int calculated = BarsCalculated(ExtACHandle); if (calculated < rates_total) { // Not all data of ExtACHandle is calculated. return (0); } - calculated = BarsCalculated(ExtAOHandle, rates_total); + calculated = BarsCalculated(ExtAOHandle); if (calculated < rates_total) { // Not all data of ExtAOHandle is calculated. return (0); @@ -166,15 +159,15 @@ class Indi_BWZT : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_BWZT::iBWZT(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -184,29 +177,6 @@ class Indi_BWZT : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index 1ba81ec8f..36ec12abd 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -64,18 +64,19 @@ struct BandsParams : IndicatorParams { unsigned int bshift; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - void BandsParams(unsigned int _period = 20, double _deviation = 2, int _bshift = 0, - ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : period(_period), deviation(_deviation), bshift(_bshift), applied_price(_ap) { - itype = INDI_BANDS; - max_modes = FINAL_BANDS_LINE_ENTRY; + BandsParams(unsigned int _period = 20, double _deviation = 2, int _bshift = 0, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, + int _shift = 0) + : period(_period), + deviation(_deviation), + bshift(_bshift), + applied_price(_ap), + IndicatorParams(INDI_BANDS, FINAL_BANDS_LINE_ENTRY, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_PRICE); SetCustomIndicatorName("Examples\\BB"); }; - void BandsParams(BandsParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + BandsParams(BandsParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -83,23 +84,14 @@ struct BandsParams : IndicatorParams { /** * Implements the Bollinger Bands® indicator. */ -class Indi_Bands : public Indicator { - protected: - // Structs. - BandsParams params; - +class Indi_Bands : public Indicator { public: /** * Class constructor. */ - Indi_Bands(BandsParams &_p) - : params(_p.period, _p.deviation, _p.shift, _p.applied_price), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_Bands(BandsParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.period, _p.deviation, _p.shift, _p.applied_price), Indicator(INDI_BANDS, _tf) { - params = _p; - } + Indi_Bands(BandsParams &_p, IndicatorBase *_indi_src = NULL, bool _managed = true, int _mode = 0) + : Indicator(_p, _indi_src, _managed, _mode) {} + Indi_Bands(ENUM_TIMEFRAMES _tf) : Indicator(INDI_BANDS, _tf) {} /** * Returns the indicator value. @@ -110,7 +102,7 @@ class Indi_Bands : public Indicator { */ static double iBands(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, double _deviation, int _bands_shift, ENUM_APPLIED_PRICE _applied_price, ENUM_BANDS_LINE _mode = BAND_BASE, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { ResetLastError(); #ifdef __MQL4__ @@ -150,11 +142,11 @@ class Indi_Bands : public Indicator { * * When _applied_price is set to -1, method will */ - static double iBandsOnIndicator(Indicator *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, + static double iBandsOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, double _deviation, int _bands_shift, ENUM_BANDS_LINE _mode, // (MT4/MT5): 0 - MODE_MAIN/BASE_LINE, 1 - // MODE_UPPER/UPPER_BAND, 2 - MODE_LOWER/LOWER_BAND - int _shift, Indicator *_target = NULL) { + int _shift, Indi_Bands *_target = NULL) { double _indi_value_buffer[]; double _std_dev; double _line_value; @@ -242,32 +234,29 @@ class Indi_Bands : public Indicator { * extern double deviation; * extern ENUM_APPLIED_PRICE applied_price; // Required only for MQL4. * - * Also, remember to use params.SetCustomIndicatorName(name) method to choose - * indicator name, e.g.,: params.SetCustomIndicatorName("Examples\\BB"); + * Also, remember to use iparams.SetCustomIndicatorName(name) method to choose + * indicator name, e.g.,: iparams.SetCustomIndicatorName("Examples\\BB"); * * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - double GetValue(ENUM_BANDS_LINE _mode, int _shift = 0) { + virtual double GetValue(int _mode = BAND_BASE, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = - Indi_Bands::iBands(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - GetDeviation(), GetBandsShift(), GetAppliedPrice(), _mode, _shift, GetPointer(this)); + _value = Indi_Bands::iBands(GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), + GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.custom_indi_name, /* [ */ GetPeriod(), GetBandsShift(), GetDeviation(), - GetAppliedPrice() /* ] */, _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), 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(), Get(CHART_PARAM_SYMBOL), - Get(CHART_PARAM_TF), GetPeriod(), GetDeviation(), - GetBandsShift(), _mode, _shift, &this); + _value = Indi_Bands::iBandsOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), + GetBandsShift(), (ENUM_BANDS_LINE)_mode, _shift, THIS_PTR); break; } istate.is_changed = false; @@ -275,31 +264,6 @@ class Indi_Bands : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue((ENUM_BANDS_LINE)_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, - !_entry.HasValue((double)NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGt(0) && - _entry.values[BAND_LOWER].GetDbl() < _entry.values[BAND_UPPER].GetDbl()); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -310,10 +274,18 @@ class Indi_Bands : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return !_entry.HasValue((double)NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGt(0) && + _entry.values[BAND_LOWER].GetDbl() < _entry.values[BAND_UPPER].GetDbl(); + } + /** * Provides built-in indicators whose can be used as data source. */ - virtual Indicator *FetchDataSource(ENUM_INDICATOR_TYPE _id) { + virtual IndicatorBase *FetchDataSource(ENUM_INDICATOR_TYPE _id) { if (_id == INDI_BANDS) { BandsParams bands_params(); return new Indi_Bands(bands_params); @@ -337,7 +309,7 @@ class Indi_Bands : public Indicator { return new Indi_StdDev(stddev_params); } - return Indicator::FetchDataSource(_id); + return IndicatorBase::FetchDataSource(_id); } /* Getters */ @@ -345,22 +317,22 @@ class Indi_Bands : public Indicator { /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get deviation value. */ - double GetDeviation() { return params.deviation; } + double GetDeviation() { return iparams.deviation; } /** * Get bands shift value. */ - unsigned int GetBandsShift() { return params.bshift; } + unsigned int GetBandsShift() { return iparams.bshift; } /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -369,7 +341,7 @@ class Indi_Bands : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -377,7 +349,7 @@ class Indi_Bands : public Indicator { */ void SetDeviation(double _deviation) { istate.is_changed = true; - params.deviation = _deviation; + iparams.deviation = _deviation; } /** @@ -385,7 +357,7 @@ class Indi_Bands : public Indicator { */ void SetBandsShift(int _bshift) { istate.is_changed = true; - params.bshift = _bshift; + iparams.bshift = _bshift; } /** @@ -393,6 +365,6 @@ class Indi_Bands : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index ddc259ddb..1732a0c90 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -33,19 +33,16 @@ double iBearsPower(string _symbol, int _tf, int _period, int _ap, int _shift) { // Structs. struct BearsPowerParams : IndicatorParams { unsigned int period; - ENUM_APPLIED_PRICE applied_price; // (MT5): not used + ENUM_APPLIED_PRICE applied_price; // Struct constructors. - void BearsPowerParams(unsigned int _period, ENUM_APPLIED_PRICE _ap, int _shift = 0) - : period(_period), applied_price(_ap) { - itype = INDI_BEARS; - max_modes = 1; + BearsPowerParams(unsigned int _period = 13, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + : period(_period), applied_price(_ap), IndicatorParams(INDI_BEARS, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Bears"); }; - void BearsPowerParams(BearsPowerParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + BearsPowerParams(BearsPowerParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -53,20 +50,13 @@ struct BearsPowerParams : IndicatorParams { /** * Implements the Bears Power indicator. */ -class Indi_BearsPower : public Indicator { +class Indi_BearsPower : public Indicator { public: - BearsPowerParams params; - /** * Class constructor. */ - Indi_BearsPower(BearsPowerParams &_p) : params(_p.period, _p.applied_price), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_BearsPower(BearsPowerParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.period, _p.applied_price), Indicator(INDI_BEARS, _tf) { - params = _p; - } + Indi_BearsPower(BearsPowerParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_BearsPower(ENUM_TIMEFRAMES _tf) : Indicator(INDI_BEARS, _tf) {} /** * Returns the indicator value. @@ -77,7 +67,7 @@ class Indi_BearsPower : public Indicator { */ static double iBearsPower(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, ENUM_APPLIED_PRICE _applied_price, // (MT5): not used - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iBearsPower(_symbol, _tf, _period, _applied_price, _shift); #else // __MQL5__ @@ -113,18 +103,17 @@ class Indi_BearsPower : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = _value = iBearsPower(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetPeriod(), GetAppliedPrice(), _shift, GetPointer(this)); + _value = _value = iBearsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -134,29 +123,6 @@ class Indi_BearsPower : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue((double)NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -171,14 +137,14 @@ class Indi_BearsPower : public Indicator { /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get applied price value. * * Note: Not used in MT5. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -187,7 +153,7 @@ class Indi_BearsPower : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -197,6 +163,6 @@ class Indi_BearsPower : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index fc08d911b..c1cf5ac9a 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -35,17 +35,14 @@ struct BullsPowerParams : IndicatorParams { unsigned int period; ENUM_APPLIED_PRICE applied_price; // (MT5): not used // Struct constructor. - void BullsPowerParams(unsigned int _period, ENUM_APPLIED_PRICE _ap, int _shift = 0) - : period(_period), applied_price(_ap) { - itype = INDI_BULLS; - max_modes = 1; + BullsPowerParams(unsigned int _period = 13, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + : period(_period), applied_price(_ap), IndicatorParams(INDI_BULLS, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Bulls"); }; - void BullsPowerParams(BullsPowerParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + BullsPowerParams(BullsPowerParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -53,22 +50,13 @@ struct BullsPowerParams : IndicatorParams { /** * Implements the Bulls Power indicator. */ -class Indi_BullsPower : public Indicator { - protected: - // Struct variables. - BullsPowerParams params; - +class Indi_BullsPower : public Indicator { public: /** * Class constructor. */ - Indi_BullsPower(BullsPowerParams &_p) : params(_p.period, _p.applied_price), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_BullsPower(BullsPowerParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.period, _p.applied_price), Indicator(INDI_BULLS, _tf) { - params = _p; - } + Indi_BullsPower(BullsPowerParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_BullsPower(ENUM_TIMEFRAMES _tf) : Indicator(INDI_BULLS, _tf) {} /** * Returns the indicator value. @@ -79,7 +67,7 @@ class Indi_BullsPower : public Indicator { */ static double iBullsPower(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, ENUM_APPLIED_PRICE _applied_price, // (MT5): not used - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iBullsPower(_symbol, _tf, _period, _applied_price, _shift); #else // __MQL5__ @@ -115,18 +103,17 @@ class Indi_BullsPower : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = iBullsPower(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - GetAppliedPrice(), _shift, GetPointer(this)); + _value = iBullsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /**/ GetPeriod() /**/, _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetPeriod() /**/, + _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -136,29 +123,6 @@ class Indi_BullsPower : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -173,14 +137,14 @@ class Indi_BullsPower : public Indicator { /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get applied price value. * * Note: Not used in MT5. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -189,7 +153,7 @@ class Indi_BullsPower : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -199,6 +163,6 @@ class Indi_BullsPower : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index 76e4642af..27a0cb14a 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -41,17 +41,14 @@ struct CCIParams : IndicatorParams { unsigned int period; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - void CCIParams(unsigned int _period = 14, ENUM_APPLIED_PRICE _applied_price = PRICE_OPEN, int _shift = 0) - : period(_period), applied_price(_applied_price) { - itype = INDI_CCI; - max_modes = 1; + CCIParams(unsigned int _period = 14, ENUM_APPLIED_PRICE _applied_price = PRICE_OPEN, int _shift = 0) + : period(_period), applied_price(_applied_price), IndicatorParams(INDI_CCI, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\CCI"); }; - void CCIParams(CCIParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + CCIParams(CCIParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -59,20 +56,13 @@ struct CCIParams : IndicatorParams { /** * Implements the Commodity Channel Index indicator. */ -class Indi_CCI : public Indicator { +class Indi_CCI : public Indicator { public: - CCIParams params; - /** * Class constructor. */ - Indi_CCI(CCIParams &_p) : params(_p.period, _p.applied_price, _p.shift), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_CCI(CCIParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.period, _p.applied_price, _p.shift), Indicator(INDI_CCI, _tf) { - params = _p; - } + Indi_CCI(CCIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_CCI(ENUM_TIMEFRAMES _tf) : Indicator(INDI_CCI, _tf) {} /** * Returns the indicator value. @@ -82,7 +72,7 @@ class Indi_CCI : public Indicator { * - https://www.mql5.com/en/docs/indicators/icci */ static double iCCI(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, ENUM_APPLIED_PRICE _applied_price, - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iCCI(_symbol, _tf, _period, _applied_price, _shift); #else // __MQL5__ @@ -115,12 +105,12 @@ class Indi_CCI : public Indicator { #endif } - static double iCCIOnIndicator(Indicator *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, int _mode, - int _shift = 0) { + static double iCCIOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, + int _mode, int _shift = 0) { _indi.ValidateDataSourceMode(_mode); double _indi_value_buffer[]; - IndicatorDataEntry _entry(_indi.GetParams().GetMaxModes()); + IndicatorDataEntry _entry(_indi.GetModeCount()); ArrayResize(_indi_value_buffer, _period); @@ -172,33 +162,32 @@ class Indi_CCI : public Indicator { * extern unsigned int period; * extern ENUM_APPLIED_PRICE applied_price; // Required only for MQL4. * - * Also, remember to use params.SetCustomIndicatorName(name) method to choose - * indicator name, e.g.,: params.SetCustomIndicatorName("Examples\\CCI"); + * Also, remember to use iparams.SetCustomIndicatorName(name) method to choose + * indicator name, e.g.,: iparams.SetCustomIndicatorName("Examples\\CCI"); * * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { 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_CCI::iCCI(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - GetAppliedPrice(), _shift /* + params.shift*/, GetPointer(this)); + _value = + Indi_CCI::iCCI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _shift /* + iparams.shift*/, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.custom_indi_name, /* [ */ GetPeriod(), GetAppliedPrice() /* ] */, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), 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(), Get(CHART_PARAM_SYMBOL), - Get(CHART_PARAM_TF), GetPeriod(), GetDataSourceMode(), - _shift /* + params.shift*/); + _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDataSourceMode(), + _shift /* + iparams.shift*/); break; } istate.is_ready = _LastError == ERR_NO_ERROR; @@ -206,27 +195,6 @@ class Indi_CCI : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - _entry.values[0] = GetValue(0); - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -241,12 +209,12 @@ class Indi_CCI : public Indicator { /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -255,7 +223,7 @@ class Indi_CCI : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -263,6 +231,6 @@ class Indi_CCI : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index a9515f31f..18a54a404 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -23,6 +23,8 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" +#include "../Util.h" #include "Indi_MA.mqh" // Structs. @@ -32,23 +34,19 @@ struct CHOParams : IndicatorParams { ENUM_MA_METHOD smooth_method; ENUM_APPLIED_VOLUME input_volume; // Struct constructor. - void CHOParams(int _fast_ma = 3, int _slow_ma = 10, ENUM_MA_METHOD _smooth_method = MODE_EMA, - ENUM_APPLIED_VOLUME _input_volume = VOLUME_TICK, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + CHOParams(int _fast_ma = 3, int _slow_ma = 10, ENUM_MA_METHOD _smooth_method = MODE_EMA, + ENUM_APPLIED_VOLUME _input_volume = VOLUME_TICK, int _shift = 0) + : IndicatorParams(INDI_CHAIKIN, 1, TYPE_DOUBLE) { fast_ma = _fast_ma; input_volume = _input_volume; - itype = INDI_CHAIKIN; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\CHO"); shift = _shift; slow_ma = _slow_ma; smooth_method = _smooth_method; - tf = _tf; }; - void CHOParams(CHOParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + CHOParams(CHOParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -56,27 +54,20 @@ struct CHOParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_CHO : public Indicator { - protected: - CHOParams params; - +class Indi_CHO : public Indicator { public: /** * Class constructor. */ - Indi_CHO(CHOParams &_params) - : params(_params.fast_ma, _params.slow_ma, _params.smooth_method, _params.input_volume), - Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_CHO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_CHAIKIN, _tf) { params.tf = _tf; }; + Indi_CHO(CHOParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_CHO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_CHAIKIN, _tf){}; /** * Built-in version of Chaikin Oscillator. */ static double iChaikin(string _symbol, ENUM_TIMEFRAMES _tf, int _fast_ma_period, int _slow_ma_period, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iChaikin(_symbol, _tf, _fast_ma_period, _slow_ma_period, _ma_method, _av), _mode, _shift); @@ -175,18 +166,17 @@ class Indi_CHO : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_CHO::iChaikin(GetSymbol(), GetTf(), /*[*/ GetSlowMA(), GetFastMA(), GetSmoothMethod(), GetInputVolume() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetFastMA(), GetSlowMA(), GetSmoothMethod(), - GetInputVolume() /*]*/, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastMA(), + GetSlowMA(), GetSmoothMethod(), GetInputVolume() /*]*/, 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -196,29 +186,6 @@ class Indi_CHO : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -233,22 +200,22 @@ class Indi_CHO : public Indicator { /** * Get fast moving average. */ - unsigned int GetFastMA() { return params.fast_ma; } + unsigned int GetFastMA() { return iparams.fast_ma; } /** * Get slow moving average. */ - unsigned int GetSlowMA() { return params.slow_ma; } + unsigned int GetSlowMA() { return iparams.slow_ma; } /** * Get smooth method. */ - ENUM_MA_METHOD GetSmoothMethod() { return params.smooth_method; } + ENUM_MA_METHOD GetSmoothMethod() { return iparams.smooth_method; } /** * Get input volume. */ - ENUM_APPLIED_VOLUME GetInputVolume() { return params.input_volume; } + ENUM_APPLIED_VOLUME GetInputVolume() { return iparams.input_volume; } /* Setters */ @@ -257,7 +224,7 @@ class Indi_CHO : public Indicator { */ void SetFastMA(unsigned int _fast_ma) { istate.is_changed = true; - params.fast_ma = _fast_ma; + iparams.fast_ma = _fast_ma; } /** @@ -265,7 +232,7 @@ class Indi_CHO : public Indicator { */ void SetSlowMA(unsigned int _slow_ma) { istate.is_changed = true; - params.slow_ma = _slow_ma; + iparams.slow_ma = _slow_ma; } /** @@ -273,7 +240,7 @@ class Indi_CHO : public Indicator { */ void SetSmoothMethod(ENUM_MA_METHOD _smooth_method) { istate.is_changed = true; - params.smooth_method = _smooth_method; + iparams.smooth_method = _smooth_method; } /** @@ -281,6 +248,6 @@ class Indi_CHO : public Indicator { */ void SetInputVolume(ENUM_APPLIED_VOLUME _input_volume) { istate.is_changed = true; - params.input_volume = _input_volume; + iparams.input_volume = _input_volume; } }; diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index 03770e765..2a903b142 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -23,6 +23,8 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" +#include "../Util.h" #include "Indi_MA.mqh" // Enums. @@ -34,23 +36,18 @@ struct CHVParams : IndicatorParams { unsigned int chv_period; ENUM_CHV_SMOOTH_METHOD smooth_method; // Struct constructor. - void CHVParams(int _smooth_period = 10, int _chv_period = 10, - ENUM_CHV_SMOOTH_METHOD _smooth_method = CHV_SMOOTH_METHOD_EMA, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + CHVParams(int _smooth_period = 10, int _chv_period = 10, + ENUM_CHV_SMOOTH_METHOD _smooth_method = CHV_SMOOTH_METHOD_EMA, int _shift = 0) + : IndicatorParams(INDI_CHAIKIN_V, 1, TYPE_DOUBLE) { chv_period = _chv_period; - itype = INDI_CHAIKIN_V; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\CHV"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; smooth_method = _smooth_method; smooth_period = _smooth_period; - tf = _tf; }; - void CHVParams(CHVParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + CHVParams(CHVParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -58,25 +55,19 @@ struct CHVParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_CHV : public Indicator { - protected: - CHVParams params; - +class Indi_CHV : public Indicator { public: /** * Class constructor. */ - Indi_CHV(CHVParams &_params) - : params(_params.smooth_period, _params.chv_period, _params.smooth_method), Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_CHV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_CHAIKIN_V, _tf) { params.tf = _tf; }; + Indi_CHV(CHVParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_CHV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_CHAIKIN_V, _tf){}; /** * Built-in version of Chaikin Volatility. */ static double iCHV(string _symbol, ENUM_TIMEFRAMES _tf, int _smooth_period, int _chv_period, - ENUM_CHV_SMOOTH_METHOD _smooth_method, int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + ENUM_CHV_SMOOTH_METHOD _smooth_method, int _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( _symbol, _tf, Util::MakeKey("Indi_CHV", _smooth_period, _chv_period, _smooth_method)); return iCHVOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _smooth_period, _chv_period, _smooth_method, _mode, @@ -171,16 +162,16 @@ class Indi_CHV : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_CHV::iCHV(GetSymbol(), GetTf(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/, - _mode, _shift); + _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _shift); break; default: @@ -191,29 +182,6 @@ class Indi_CHV : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -228,17 +196,17 @@ class Indi_CHV : public Indicator { /** * Get smooth period. */ - unsigned int GetSmoothPeriod() { return params.smooth_period; } + unsigned int GetSmoothPeriod() { return iparams.smooth_period; } /** * Get Chaikin period. */ - unsigned int GetCHVPeriod() { return params.chv_period; } + unsigned int GetCHVPeriod() { return iparams.chv_period; } /** * Get smooth method. */ - ENUM_CHV_SMOOTH_METHOD GetSmoothMethod() { return params.smooth_method; } + ENUM_CHV_SMOOTH_METHOD GetSmoothMethod() { return iparams.smooth_method; } /* Setters */ @@ -247,7 +215,7 @@ class Indi_CHV : public Indicator { */ void SetSmoothPeriod(unsigned int _smooth_period) { istate.is_changed = true; - params.smooth_period = _smooth_period; + iparams.smooth_period = _smooth_period; } /** @@ -255,7 +223,7 @@ class Indi_CHV : public Indicator { */ void SetCHVPeriod(unsigned int _chv_period) { istate.is_changed = true; - params.chv_period = _chv_period; + iparams.chv_period = _chv_period; } /** @@ -263,6 +231,6 @@ class Indi_CHV : public Indicator { */ void SetSmoothMethod(ENUM_CHV_SMOOTH_METHOD _smooth_method) { istate.is_changed = true; - params.smooth_method = _smooth_method; + iparams.smooth_method = _smooth_method; } }; diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index ea61fb171..9ec6677dc 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -23,22 +23,18 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" // Structs. struct ColorBarsParams : IndicatorParams { // Struct constructor. - void ColorBarsParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_COLOR_BARS; - max_modes = 5; - SetDataValueType(TYPE_DOUBLE); + ColorBarsParams(int _shift = 0) : IndicatorParams(INDI_COLOR_BARS, 5, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ColorBars"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; }; - void ColorBarsParams(ColorBarsParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ColorBarsParams(ColorBarsParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -46,21 +42,19 @@ struct ColorBarsParams : IndicatorParams { /** * Implements Color Bars */ -class Indi_ColorBars : public Indicator { - protected: - ColorBarsParams params; - +class Indi_ColorBars : public Indicator { public: /** * Class constructor. */ - Indi_ColorBars(ColorBarsParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_ColorBars(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_COLOR_BARS, _tf) { params.tf = _tf; }; + Indi_ColorBars(ColorBarsParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_ColorBars(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_COLOR_BARS, _tf){}; /** * "Built-in" version of Color Bars. */ - static double iColorBars(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + static double iColorBars(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, + IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_ColorCandlesDaily"); return iColorBarsOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -118,15 +112,15 @@ class Indi_ColorBars : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ColorBars::iColorBars(GetSymbol(), GetTf(), _mode, _shift, GetPointer(this)); + _value = Indi_ColorBars::iColorBars(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -136,29 +130,6 @@ class Indi_ColorBars : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index b21b93ec6..001c6e518 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -23,22 +23,18 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" // Structs. struct ColorCandlesDailyParams : IndicatorParams { // Struct constructor. - void ColorCandlesDailyParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_COLOR_CANDLES_DAILY; - max_modes = 5; - SetDataValueType(TYPE_DOUBLE); + ColorCandlesDailyParams(int _shift = 0) : IndicatorParams(INDI_COLOR_CANDLES_DAILY, 5, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ColorCandlesDaily"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; }; - void ColorCandlesDailyParams(ColorCandlesDailyParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ColorCandlesDailyParams(ColorCandlesDailyParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -46,23 +42,19 @@ struct ColorCandlesDailyParams : IndicatorParams { /** * Implements Color Bars */ -class Indi_ColorCandlesDaily : public Indicator { - protected: - ColorCandlesDailyParams params; - +class Indi_ColorCandlesDaily : public Indicator { public: /** * Class constructor. */ - Indi_ColorCandlesDaily(ColorCandlesDailyParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_ColorCandlesDaily(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_COLOR_CANDLES_DAILY, _tf) { - params.tf = _tf; - }; + Indi_ColorCandlesDaily(ColorCandlesDailyParams &_p, IndicatorBase *_indi_src = NULL) + : Indicator(_p, _indi_src){}; + Indi_ColorCandlesDaily(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_COLOR_CANDLES_DAILY, _tf){}; /** * "Built-in" version of Color Candles Daily. */ - static double iCCD(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + static double iCCD(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_ColorCandlesDaily"); return iCCDOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -117,15 +109,15 @@ class Indi_ColorCandlesDaily : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ColorCandlesDaily::iCCD(GetSymbol(), GetTf(), _mode, _shift, GetPointer(this)); + _value = Indi_ColorCandlesDaily::iCCD(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -135,29 +127,6 @@ class Indi_ColorCandlesDaily : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index bfab1ac01..2b154bf0c 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -23,23 +23,19 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" #include "Indi_MA.mqh" // Structs. struct ColorLineParams : IndicatorParams { // Struct constructor. - void ColorLineParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_COLOR_LINE; - max_modes = 2; - SetDataValueType(TYPE_DOUBLE); + ColorLineParams(int _shift = 0) : IndicatorParams(INDI_COLOR_LINE, 2, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ColorLine"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; }; - void ColorLineParams(ColorLineParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ColorLineParams(ColorLineParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -47,24 +43,22 @@ struct ColorLineParams : IndicatorParams { /** * Implements Color Bars */ -class Indi_ColorLine : public Indicator { - protected: - ColorLineParams params; - +class Indi_ColorLine : public Indicator { public: /** * Class constructor. */ - Indi_ColorLine(ColorLineParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_ColorLine(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_COLOR_LINE, _tf) { params.tf = _tf; }; + Indi_ColorLine(ColorLineParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_ColorLine(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_COLOR_LINE, _tf){}; /** * "Built-in" version of Color Line. */ - static double iColorLine(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + static double iColorLine(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, + IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_ColorLine"); - Indicator *_indi_ma = Indi_MA::GetCached(_symbol, _tf, 10, 0, MODE_EMA, PRICE_CLOSE); + Indi_MA *_indi_ma = Indi_MA::GetCached(_symbol, _tf, 10, 0, MODE_EMA, PRICE_CLOSE); return iColorLineOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache, _indi_ma); } @@ -73,7 +67,7 @@ class Indi_ColorLine : public Indicator { * Calculates Color Line on the array of values. */ static double iColorLineOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _mode, int _shift, - IndicatorCalculateCache *_cache, Indicator *_indi_ma, + IndicatorCalculateCache *_cache, IndicatorBase *_indi_ma, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -95,12 +89,13 @@ class Indi_ColorLine : public Indicator { * OnCalculate() method for Color Line indicator. */ static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &ExtColorLineBuffer, - ValueStorage &ExtColorsBuffer, Indicator *ExtMAHandle) { + ValueStorage &ExtColorsBuffer, IndicatorBase *ExtMAHandle) { static int ticks = 0, modified = 0; // Check data. - int i, calculated = BarsCalculated(ExtMAHandle, rates_total); + int i, calculated = BarsCalculated(ExtMAHandle); + // @added History of 100 values should be enough for MA. if (calculated < rates_total) { - Print("Not all data of ExtMAHandle is calculated (", calculated, " bars). Error ", GetLastError()); + // Not all data of ExtMAHandle is calculated. return (0); } // First calculation or number of bars was changed. @@ -176,16 +171,15 @@ class Indi_ColorLine : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ColorLine::iColorLine(GetSymbol(), GetTf(), _mode, _shift, GetPointer(this)); + _value = Indi_ColorLine::iColorLine(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -195,29 +189,6 @@ class Indi_ColorLine : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ diff --git a/Indicators/Indi_CustomMovingAverage.mqh b/Indicators/Indi_CustomMovingAverage.mqh index a5dab8e2e..78f9114c6 100644 --- a/Indicators/Indi_CustomMovingAverage.mqh +++ b/Indicators/Indi_CustomMovingAverage.mqh @@ -30,23 +30,23 @@ struct CustomMovingAverageParams : IndicatorParams { unsigned int smooth_shift; ENUM_MA_METHOD smooth_method; // Struct constructor. - void CustomMovingAverageParams(int _smooth_period = 13, int _smooth_shift = 0, - ENUM_MA_METHOD _smooth_method = MODE_SMMA, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_CUSTOM_MOVING_AVG; - max_modes = 3; - SetDataValueType(TYPE_DOUBLE); + CustomMovingAverageParams(int _smooth_period = 13, int _smooth_shift = 0, ENUM_MA_METHOD _smooth_method = MODE_SMMA, + int _shift = 0) + : IndicatorParams(INDI_CUSTOM_MOVING_AVG, 3, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); - SetCustomIndicatorName("Examples\\Custom Moving Average"); SetDataSourceType(IDATA_ICUSTOM); +#ifdef __MQL5__ + SetCustomIndicatorName("Examples\\Custom Moving Average"); +#else + SetCustomIndicatorName("Custom Moving Averages"); +#endif shift = _shift; smooth_method = _smooth_method; smooth_period = _smooth_period; smooth_shift = _smooth_shift; - tf = _tf; }; - void CustomMovingAverageParams(CustomMovingAverageParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + CustomMovingAverageParams(CustomMovingAverageParams& _params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -54,32 +54,25 @@ struct CustomMovingAverageParams : IndicatorParams { /** * Implements the Custom Moving Average indicator. */ -class Indi_CustomMovingAverage : public Indicator { - protected: - CustomMovingAverageParams params; - +class Indi_CustomMovingAverage : public Indicator { public: /** * Class constructor. */ - Indi_CustomMovingAverage(CustomMovingAverageParams &_params) : Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_CustomMovingAverage(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_CUSTOM_MOVING_AVG, _tf) { - params.tf = _tf; - }; + Indi_CustomMovingAverage(CustomMovingAverageParams& _p, IndicatorBase* _indi_src = NULL) + : Indicator(_p, _indi_src){}; + Indi_CustomMovingAverage(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_CUSTOM_MOVING_AVG, _tf){}; /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), GetSmoothShift(), - GetSmoothMethod() /*]*/, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), + GetSmoothShift(), GetSmoothMethod() /*]*/, 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -89,29 +82,6 @@ class Indi_CustomMovingAverage : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -126,17 +96,17 @@ class Indi_CustomMovingAverage : public Indicator { /** * Get smooth period. */ - unsigned int GetSmoothPeriod() { return params.smooth_period; } + unsigned int GetSmoothPeriod() { return iparams.smooth_period; } /** * Get smooth shift. */ - unsigned int GetSmoothShift() { return params.smooth_shift; } + unsigned int GetSmoothShift() { return iparams.smooth_shift; } /** * Get smooth method. */ - ENUM_MA_METHOD GetSmoothMethod() { return params.smooth_method; } + ENUM_MA_METHOD GetSmoothMethod() { return iparams.smooth_method; } /* Setters */ @@ -145,7 +115,7 @@ class Indi_CustomMovingAverage : public Indicator { */ void SetSmoothPeriod(unsigned int _smooth_period) { istate.is_changed = true; - params.smooth_period = _smooth_period; + iparams.smooth_period = _smooth_period; } /** @@ -153,7 +123,7 @@ class Indi_CustomMovingAverage : public Indicator { */ void SetSmoothShift(unsigned int _smooth_shift) { istate.is_changed = true; - params.smooth_shift = _smooth_shift; + iparams.smooth_shift = _smooth_shift; } /** @@ -161,6 +131,6 @@ class Indi_CustomMovingAverage : public Indicator { */ void SetSmoothMethod(ENUM_MA_METHOD _smooth_method) { istate.is_changed = true; - params.smooth_method = _smooth_method; + iparams.smooth_method = _smooth_method; } }; diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index 32d1a0f82..e27ef8a1a 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -41,32 +41,21 @@ struct DEMAParams : IndicatorParams { unsigned int period; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - void DEMAParams(unsigned int _period, int _ma_shift, ENUM_APPLIED_PRICE _ap, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) - : period(_period), ma_shift(_ma_shift), applied_price(_ap) { - itype = itype == INDI_NONE ? INDI_DEMA : itype; - SetDataSourceType(_idstype); - SetDataValueType(TYPE_DOUBLE); + DEMAParams(unsigned int _period = 14, int _ma_shift = 0, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + : period(_period), ma_shift(_ma_shift), applied_price(_ap), IndicatorParams(INDI_DEMA, 1, TYPE_DOUBLE) { + SetCustomIndicatorName("Examples\\DEMA"); SetDataValueRange(IDATA_RANGE_PRICE); - SetMaxModes(1); SetShift(_shift); - tf = _tf; switch (idstype) { case IDATA_ICUSTOM: if (custom_indi_name == "") { SetCustomIndicatorName("Examples\\DEMA"); } break; - case IDATA_INDICATOR: - if (GetDataSource() == NULL) { - SetDataSource(Indi_Price::GetCached(_shift, _tf, _ap, _period), false); - SetDataSourceMode(0); - } - break; } }; - void DEMAParams(DEMAParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + DEMAParams(DEMAParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -74,22 +63,13 @@ struct DEMAParams : IndicatorParams { /** * Implements the Moving Average indicator. */ -class Indi_DEMA : public Indicator { - protected: - DEMAParams params; - +class Indi_DEMA : public Indicator { public: /** * Class constructor. */ - Indi_DEMA(DEMAParams &_p) - : params(_p.period, _p.ma_shift, _p.applied_price, _p.shift), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_DEMA(DEMAParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.period, _p.ma_shift, _p.applied_price, _p.shift), Indicator(INDI_DEMA, _tf) { - params = _p; - } + Indi_DEMA(DEMAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_DEMA(ENUM_TIMEFRAMES _tf) : Indicator(INDI_DEMA, _tf) {} /** * Updates the indicator value. @@ -98,7 +78,7 @@ class Indi_DEMA : public Indicator { * - https://www.mql5.com/en/docs/indicators/IDEMA */ 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, Indicator *_obj = NULL) { + ENUM_APPLIED_PRICE _applied_price, int _shift = 0, int _mode = 0, IndicatorBase *_obj = NULL) { ResetLastError(); #ifdef __MQL5__ int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; @@ -128,15 +108,15 @@ class Indi_DEMA : public Indicator { } return _res[0]; #else - Indi_Price *_indi_price = Indi_Price::GetCached(_shift, _tf, _applied_price, _period); + Indi_Price *_indi_price = Indi_Price::GetCached(_symbol, _tf, _shift); // Note that _applied_price and Indi_Price mode indices are compatible. return Indi_DEMA::iDEMAOnIndicator(_indi_price.GetCache(), _indi_price, 0, _period, _ma_shift, _shift); #endif } - static double iDEMAOnIndicator(IndicatorCalculateCache *cache, Indicator *indi, int indi_mode, + static double iDEMAOnIndicator(IndicatorCalculateCache *cache, IndicatorBase *_indi, int indi_mode, unsigned int ma_period, unsigned int ma_shift, int shift) { - return iDEMAOnArray(indi.GetValueStorage(indi_mode), 0, ma_period, ma_shift, shift, cache); + return iDEMAOnArray(_indi.GetValueStorage(indi_mode), 0, ma_period, ma_shift, shift, cache); } static double iDEMAOnArray(ValueStorage &price, int total, unsigned int ma_period, unsigned int ma_shift, @@ -185,29 +165,25 @@ class Indi_DEMA : public Indicator { return (rates_total); } - /** - - /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: // We're getting DEMA from Price indicator. istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_DEMA::iDEMA(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - GetMAShift(), GetAppliedPrice(), _shift, _mode, GetPointer(this)); + _value = Indi_DEMA::iDEMA(GetSymbol(), 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, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.custom_indi_name, /*[*/ GetPeriod(), GetMAShift(), GetAppliedPrice() /*]*/, _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /*[*/ GetPeriod(), GetMAShift(), + GetAppliedPrice() /*]*/, _mode, _shift); break; case IDATA_INDICATOR: // Calculating DEMA value from specified indicator. @@ -226,17 +202,17 @@ class Indi_DEMA : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { + for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) { _entry.values[_mode] = GetValue(_mode, _shift); } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, _entry.IsGt(0) && _entry.IsLt(DBL_MAX)); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } @@ -252,6 +228,13 @@ class Indi_DEMA : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return Indicator::IsValidEntry(_entry) && _entry.IsGt(0) && _entry.IsLt(DBL_MAX); + } + /* Getters */ /** @@ -259,21 +242,21 @@ class Indi_DEMA : public Indicator { * * Averaging period for the calculation of the moving average. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get DEMA shift value. * * Indicators line offset relate to the chart by timeframe. */ - unsigned int GetMAShift() { return params.ma_shift; } + unsigned int GetMAShift() { return iparams.ma_shift; } /** * Get applied price value. * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -284,7 +267,7 @@ class Indi_DEMA : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -292,7 +275,7 @@ class Indi_DEMA : public Indicator { */ void SetMAShift(int _ma_shift) { istate.is_changed = true; - params.ma_shift = _ma_shift; + iparams.ma_shift = _ma_shift; } /** @@ -305,7 +288,7 @@ class Indi_DEMA : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; #endif // INDI_DEMA_MQH diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index 56674d3f7..3a63bedc1 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -34,16 +34,14 @@ double iDeMarker(string _symbol, int _tf, int _period, int _shift) { struct DeMarkerParams : IndicatorParams { unsigned int period; // Struct constructors. - void DeMarkerParams(unsigned int _period, int _shift = 0) : period(_period) { - itype = INDI_DEMARKER; - max_modes = 1; + DeMarkerParams(unsigned int _period = 14, int _shift = 0) + : period(_period), IndicatorParams(INDI_DEMARKER, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\DeMarker"); }; - void DeMarkerParams(DeMarkerParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + DeMarkerParams(DeMarkerParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -51,17 +49,13 @@ struct DeMarkerParams : IndicatorParams { /** * Implements the DeMarker indicator. */ -class Indi_DeMarker : public Indicator { +class Indi_DeMarker : public Indicator { public: - DeMarkerParams params; - /** * Class constructor. */ - Indi_DeMarker(DeMarkerParams &_p) : params(_p.period), Indicator((IndicatorParams)_p) { params = _p; } - Indi_DeMarker(DeMarkerParams &_p, ENUM_TIMEFRAMES _tf) : params(_p.period), Indicator(INDI_DEMARKER, _tf) { - params = _p; - } + Indi_DeMarker(DeMarkerParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_DeMarker(ENUM_TIMEFRAMES _tf) : Indicator(INDI_DEMARKER, _tf) {} /** * Returns the indicator value. @@ -71,7 +65,7 @@ class Indi_DeMarker : public Indicator { * - https://www.mql5.com/en/docs/indicators/idemarker */ static double iDeMarker(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iDeMarker(_symbol, _tf, _period, _shift); #else // __MQL5__ @@ -107,19 +101,17 @@ class Indi_DeMarker : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = _value = - Indi_DeMarker::iDeMarker(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - _shift, GetPointer(this)); + _value = _value = Indi_DeMarker::iDeMarker(GetSymbol(), GetTf(), GetPeriod(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -129,29 +121,6 @@ class Indi_DeMarker : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -166,7 +135,7 @@ class Indi_DeMarker : public Indicator { /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /* Setters */ @@ -175,6 +144,6 @@ class Indi_DeMarker : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } }; diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index bd149b74b..b0a6880a5 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -33,32 +33,19 @@ // Structs. struct DemoIndiParams : IndicatorParams { // Struct constructors. - void DemoIndiParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, - ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) { - itype = itype == INDI_NONE ? INDI_DEMO : itype; - max_modes = 1; - SetDataSourceType(_idstype); - SetDataValueType(TYPE_DOUBLE); + DemoIndiParams(int _shift = 0) : IndicatorParams(INDI_DEMO, 1, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); - SetMaxModes(1); SetShift(_shift); - tf = _tf; switch (idstype) { case IDATA_ICUSTOM: if (custom_indi_name == "") { SetCustomIndicatorName("Examples\\Demo"); } break; - case IDATA_INDICATOR: - if (GetDataSource() == NULL) { - SetDataSource(Indi_Price::GetCached(_shift, _tf), false); - SetDataSourceMode(0); - } - break; } }; - void DemoIndiParams(DemoIndiParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + DemoIndiParams(DemoIndiParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -66,41 +53,27 @@ struct DemoIndiParams : IndicatorParams { /** * Demo/Dummy Indicator. */ -class Indi_Demo : public Indicator { - protected: - DemoIndiParams params; - +class Indi_Demo : public Indicator { public: /** * Class constructor. */ - Indi_Demo(DemoIndiParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_Demo(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : params(_tf), Indicator(INDI_DEMO, _tf){}; - - /** - * Initialize indicator data drawing on custom data. - */ - bool InitDraw() { - if (iparams.is_draw) { - draw = new DrawIndicator(&this); - } - return iparams.is_draw; - } + Indi_Demo(DemoIndiParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_Demo(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_DEMO, _tf){}; /** * Returns the indicator value. */ static double iDemo(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { return 0.1 + (0.1 * _obj.GetBarIndex()); } /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { - double _value = Indi_Demo::iDemo(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), _shift, - GetPointer(this)); + virtual double GetValue(int _mode = 0, int _shift = 0) { + double _value = Indi_Demo::iDemo(GetSymbol(), GetTf(), _shift, THIS_PTR); istate.is_ready = true; istate.is_changed = false; if (iparams.is_draw) { @@ -109,29 +82,6 @@ class Indi_Demo : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.AddFlags(INDI_ENTRY_FLAG_IS_VALID); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index 1179224fb..d3d9e9b68 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -23,6 +23,7 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.price.h" #include "Indi_MA.mqh" // Structs. @@ -30,23 +31,16 @@ struct DetrendedPriceParams : IndicatorParams { unsigned int period; ENUM_APPLIED_PRICE applied_price; // Struct constructor. - void DetrendedPriceParams(int _period = 12, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + DetrendedPriceParams(int _period = 12, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + : IndicatorParams(INDI_DETRENDED_PRICE, 1, TYPE_DOUBLE) { applied_price = _ap; - itype = INDI_DETRENDED_PRICE; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\DPO"); - // INDI_DETRENDED_PRICE[1]: bar 1: 1525392000,130,-0.00001143 - // SetDataSourceType(IDATA_ICUSTOM); - SetDataSourceType(IDATA_BUILTIN); period = _period; shift = _shift; - tf = _tf; }; - void DetrendedPriceParams(DetrendedPriceParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + DetrendedPriceParams(DetrendedPriceParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -54,22 +48,20 @@ struct DetrendedPriceParams : IndicatorParams { /** * Implements Detrended Price Oscillator. */ -class Indi_DetrendedPrice : public Indicator { - protected: - DetrendedPriceParams params; - +class Indi_DetrendedPrice : public Indicator { public: /** * Class constructor. */ - Indi_DetrendedPrice(DetrendedPriceParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_DetrendedPrice(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_DETRENDED_PRICE, _tf) { params.tf = _tf; }; + Indi_DetrendedPrice(DetrendedPriceParams &_p, IndicatorBase *_indi_src = NULL) + : Indicator(_p, _indi_src){}; + Indi_DetrendedPrice(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_DETRENDED_PRICE, _tf){}; /** * Built-in version of AMA. */ static double iDPO(string _symbol, ENUM_TIMEFRAMES _tf, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_symbol, _tf, _ap, Util::MakeKey("Indi_DPO", _period, (int)_ap)); return iDPOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _mode, _shift, _cache); @@ -123,16 +115,16 @@ class Indi_DetrendedPrice : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_DetrendedPrice::iDPO(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _shift); break; default: @@ -143,29 +135,6 @@ class Indi_DetrendedPrice : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -180,12 +149,12 @@ class Indi_DetrendedPrice : public Indicator { /** * Get period. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -194,7 +163,7 @@ class Indi_DetrendedPrice : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -202,6 +171,6 @@ class Indi_DetrendedPrice : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index d6f81854b..ad16647bf 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -31,35 +31,21 @@ struct IndicatorParams; #include "Indi_Drawer.struct.h" #include "Indi_Price.mqh" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compability). -double iDrawer(string _symbol, int _tf, int _period, int _ap, int _shift) { - return Indi_Drawer::iDrawer(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); -} -#endif - /** * Implements the Relative Strength Index indicator. */ -class Indi_Drawer : public Indicator { - public: - DrawerParams params; - DictStruct aux_data; +class Indi_Drawer : public Indicator { Redis redis; + public: /** * Class constructor. */ - Indi_Drawer(const DrawerParams &_params) : params(_params), Indicator((IndicatorParams)_params), redis(true) { - params = _params; - Init(); - } - Indi_Drawer(const DrawerParams &_params, ENUM_TIMEFRAMES _tf) - : params(_params), Indicator(INDI_DRAWER, _tf), redis(true) { - // @fixme - params.tf = _tf; + Indi_Drawer(const DrawerParams &_p, IndicatorBase *_indi_src = NULL) + : Indicator(_p, _indi_src), redis(true) { Init(); } + Indi_Drawer(ENUM_TIMEFRAMES _tf) : Indicator(INDI_DRAWER, _tf), redis(true) { Init(); } void Init() { // Drawer is always ready. @@ -103,7 +89,6 @@ class Indi_Drawer : public Indicator { // Assuming that passed values are correct. entry.AddFlags(INDI_ENTRY_FLAG_IS_VALID); - idata.Add(entry, _args[0].integer_value); return true; } @@ -112,7 +97,7 @@ class Indi_Drawer : public Indicator { } virtual void OnTick() { - Indicator::OnTick(); + Indicator::OnTick(); ActionEntry action(INDI_ACTION_SET_VALUE); ArrayResize(action.args, 3); @@ -162,167 +147,41 @@ class Indi_Drawer : public Indicator { * - https://docs.mql4.com/indicators/irsi * - https://www.mql5.com/en/docs/indicators/irsi */ - static double iDrawer(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _period = 14, - ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, Indicator *_obj = NULL) { + static double iDrawer(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, + IndicatorBase *_obj = NULL) { return 1.0; } /** - * Calculates non-SMMA version of Drawer on another indicator (uses iDrawerOnArray). + * Performs drawing on data from other indicator. */ - static double iDrawerOnArrayOnIndicator(Indicator *_indi, string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, - unsigned int _period = 14, ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, - int _shift = 0, Indi_Drawer *_obj = NULL) { - int i; - 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]; - } - - result = iDrawerOnArray(indi_values, 0, _period - 1, 0); - - return result; - } - - /** - * Calculates SMMA-based (same as iDrawer method) Drawer on another indicator. - * - * @see https://school.stockcharts.com/doku.php?id=technical_indicators:relative_strength_index_rsi - * - * Reson behind iDrawer with SSMA and not just iDrawerOnArray() (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 - * also means that Drawer values become more accurate as the calculation period - * extends. SharpCharts uses at least 250 data points prior to the starting - * date of any chart (assuming that much data exists) when calculating its - * Drawer values. To exactly replicate our Drawer numbers, a formula will need at - * least 250 data points." - */ - static double iDrawerOnIndicator(Indicator *_indi, Indi_Drawer *_obj, string _symbol = NULL, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _period = 14, - ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0) { - long _bar_time_curr = _obj.GetBarTime(_shift); - long _bar_time_prev = _obj.GetBarTime(_shift + 1); - if (fmin(_bar_time_curr, _bar_time_prev) < 0) { - // Return empty value on invalid bar time. - return EMPTY_VALUE; - } - // Looks like MT uses specified period as start of the SMMA calculations. - _obj.FeedHistoryEntries(_period); - - int i; - double indi_values[]; - ArrayResize(indi_values, _period); - - double result; - - // SMMA-based version of Drawer. - DrawerGainLossData last_data, new_data; - unsigned int data_position; - double diff; - int _mode = _obj.GetParams().indi_mode; - - if (!_obj.aux_data.KeyExists(_bar_time_prev, data_position)) { - // No previous SMMA-based average gain and loss. Calculating SMA-based ones. - double sum_gain = 0; - double sum_loss = 0; - - for (i = 1; i < (int)_period; i++) { - double price_new = _indi[(_shift + 1) + i - 1][_mode]; - double price_old = _indi[(_shift + 1) + i][_mode]; - - if (price_new == 0.0 || price_old == 0.0) { - // Missing history price data, skipping calculations. - return 0.0; - } - - diff = price_new - price_old; - - if (diff > 0) { - sum_gain += diff; - } else { - sum_loss += -diff; - } - } - - // Calculating SMA-based values. - last_data.avg_gain = sum_gain / _period; - last_data.avg_loss = sum_loss / _period; - } else { - // Data already exists, retrieving it by position got by KeyExists(). - last_data = _obj.aux_data.GetByPos(data_position); - } - - diff = _indi[_shift][_mode] - _indi[_shift + 1][_mode]; - - double curr_gain = 0; - double curr_loss = 0; - - if (diff > 0) - curr_gain += diff; - else - curr_loss += -diff; - - new_data.avg_gain = (last_data.avg_gain * (_period - 1) + curr_gain) / _period; - new_data.avg_loss = (last_data.avg_loss * (_period - 1) + curr_loss) / _period; - - _obj.aux_data.Set(_bar_time_curr, new_data); - - if (new_data.avg_loss == 0.0) - // @fixme Why 0 loss? - return 0; - - double rs = new_data.avg_gain / new_data.avg_loss; - - result = 100.0 - (100.0 / (1.0 + rs)); - - return result; + static double iDrawerOnIndicator(IndicatorBase *_indi, Indi_Drawer *_obj, string _symbol = NULL, + ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) { + // This method is not yet implemented. + return 1.0; } /** - * Calculates Drawer on the array of values. + * Performs drawing from data in array. */ static double iDrawerOnArray(double &array[], int total, int period, int shift) { return 0; } /** * Returns the indicator's value. - * - * For IDATA_ICUSTOM mode, use those three externs: - * - * extern unsigned int period; - * extern ENUM_APPLIED_PRICE applied_price; // Required only for MQL4. - * extern int shift; - * - * Also, remember to use params.SetCustomIndicatorName(name) method to choose - * indicator name, e.g.,: params.SetCustomIndicatorName("Examples\\Drawer"); - * - * Note that in MQL5 Applied Price must be passed as the last parameter - * (before mode and shift). */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Drawer::iDrawer(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetPeriod(), GetAppliedPrice(), _shift, GetPointer(this)); - break; - case IDATA_ICUSTOM: - istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.custom_indi_name, /* [ */ GetPeriod(), GetAppliedPrice() /* ] */, 0, _shift); + _value = Indi_Drawer::iDrawer(GetSymbol(), GetTf(), _shift, THIS_PTR); break; case IDATA_INDICATOR: - _value = Indi_Drawer::iDrawerOnIndicator(params.indi_data_source, GetPointer(this), - Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetPeriod(), GetAppliedPrice(), _shift); + _value = Indi_Drawer::iDrawerOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), _shift); break; + default: + SetUserError(ERR_INVALID_PARAMETER); } istate.is_changed = false; return _value; @@ -332,13 +191,13 @@ class Indi_Drawer : public Indicator { * Returns the indicator's struct value. */ IndicatorDataEntry GetEntry(int _shift = 0) { - unsigned int i; + int i; long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(iparams.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (_bar_time < 0) { // Return empty value on invalid bar time. - for (i = 0; i < iparams.max_modes; ++i) { + for (i = 0; i < iparams.GetMaxModes(); ++i) { _entry.values[i] = EMPTY_VALUE; } return _entry; @@ -349,11 +208,12 @@ class Indi_Drawer : public Indicator { // Missing entry (which is correct). _entry.timestamp = GetBarTime(_shift); - for (i = 0; i < iparams.max_modes; ++i) { + for (i = 0; i < iparams.GetMaxModes(); ++i) { + // Fetching history data is not yet implemented. _entry.values[i] = 0; } - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); _entry.AddFlags(INDI_ENTRY_FLAG_IS_VALID | INDI_ENTRY_FLAG_INSUFFICIENT_DATA); } return _entry; @@ -377,19 +237,19 @@ class Indi_Drawer : public Indicator { /* Getters */ /** - * Get indicator params. + * Get indicator iparams. */ - DrawerParams GetParams() { return params; } + DrawerParams GetParams() { return iparams; } /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -398,7 +258,7 @@ class Indi_Drawer : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -406,6 +266,6 @@ class Indi_Drawer : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_Drawer.struct.h b/Indicators/Indi_Drawer.struct.h index cfbb402c6..d033752b6 100644 --- a/Indicators/Indi_Drawer.struct.h +++ b/Indicators/Indi_Drawer.struct.h @@ -35,27 +35,15 @@ struct DrawerParams : IndicatorParams { unsigned int period; ENUM_APPLIED_PRICE applied_price; - // Struct constructors. - void DrawerParams(const DrawerParams &r) { - period = r.period; - applied_price = r.applied_price; - custom_indi_name = r.custom_indi_name; - } - void DrawerParams(unsigned int _period, ENUM_APPLIED_PRICE _ap) : period(_period), applied_price(_ap) { - itype = INDI_DRAWER; - max_modes = 0; - custom_indi_name = "Examples\\Drawer"; - SetDataValueType(TYPE_DOUBLE); + DrawerParams(unsigned int _period = 10, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE) + : period(_period), applied_price(_ap), IndicatorParams(INDI_DRAWER, 0, TYPE_DOUBLE) { + // Fetching history data is not yet implemented. + SetCustomIndicatorName("Examples\\Drawer"); }; - void DrawerParams(DrawerParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + DrawerParams(DrawerParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; - if (idstype == IDATA_INDICATOR && indi_data_source == NULL) { - PriceIndiParams price_params(_tf); - SetDataSource(new Indi_Price(price_params), true); - } }; - void DrawerParams(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : period(12), applied_price(PRICE_WEIGHTED) { tf = _tf; } // Serializers. SERIALIZER_EMPTY_STUB; SerializerNodeType Serialize(Serializer &s); @@ -75,4 +63,5 @@ SerializerNodeType DrawerParams::Serialize(Serializer &s) { struct DrawerGainLossData { double avg_gain; double avg_loss; + DrawerGainLossData() { avg_gain = avg_loss = 0.0; } }; diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 99c359845..de7ac1da7 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -49,23 +49,24 @@ struct EnvelopesParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; double deviation; // Struct constructors. - void EnvelopesParams(int _ma_period = 13, int _ma_shift = 0, ENUM_MA_METHOD _ma_method = MODE_SMA, - ENUM_APPLIED_PRICE _ap = PRICE_OPEN, double _deviation = 2, int _shift = 0) - : ma_period(_ma_period), ma_shift(_ma_shift), ma_method(_ma_method), applied_price(_ap), deviation(_deviation) { - itype = INDI_ENVELOPES; -#ifdef __MQL5__ - // There is no LINE_MAIN in MQL5 for Envelopes. - max_modes = 2; -#else + EnvelopesParams(int _ma_period = 13, int _ma_shift = 0, ENUM_MA_METHOD _ma_method = MODE_SMA, + ENUM_APPLIED_PRICE _ap = PRICE_OPEN, double _deviation = 2, int _shift = 0) + : ma_period(_ma_period), + ma_shift(_ma_shift), + ma_method(_ma_method), + applied_price(_ap), + deviation(_deviation), + IndicatorParams(INDI_ENVELOPES, 2, TYPE_DOUBLE) { +#ifdef __MQL4__ + // There is extra LINE_MAIN in MQL4 for Envelopes. max_modes = 3; #endif shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_PRICE); SetCustomIndicatorName("Examples\\Envelopes"); }; - void EnvelopesParams(EnvelopesParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + EnvelopesParams(EnvelopesParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -73,25 +74,13 @@ struct EnvelopesParams : IndicatorParams { /** * Implements the Envelopes indicator. */ -class Indi_Envelopes : public Indicator { - protected: - // Structs. - EnvelopesParams params; - +class Indi_Envelopes : public Indicator { public: /** * Class constructor. */ - Indi_Envelopes(EnvelopesParams &_p) - : params(_p.ma_period, _p.ma_shift, _p.ma_method, _p.applied_price, _p.deviation), - Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_Envelopes(EnvelopesParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.ma_period, _p.ma_shift, _p.ma_method, _p.applied_price, _p.deviation), - Indicator(INDI_ENVELOPES, _tf) { - params = _p; - } + Indi_Envelopes(EnvelopesParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_Envelopes(ENUM_TIMEFRAMES _tf) : Indicator(INDI_ENVELOPES, _tf) {} /** * Returns the indicator value. @@ -104,7 +93,7 @@ class Indi_Envelopes : public Indicator { int _ma_shift, ENUM_APPLIED_PRICE _ap, double _deviation, int _mode, // (MT4 _mode): 0 - MODE_MAIN, 1 - MODE_UPPER, 2 - MODE_LOWER; (MT5 _mode): 0 - // UPPER_LINE, 1 - LOWER_LINE - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { ResetLastError(); #ifdef __MQL4__ return ::iEnvelopes(_symbol, _tf, _ma_period, _ma_method, _ma_shift, _ap, _deviation, _mode, _shift); @@ -147,7 +136,7 @@ class Indi_Envelopes : public Indicator { #endif } - static double iEnvelopesOnIndicator(IndicatorCalculateCache *_cache, Indicator *_indi, string _symbol, + static double iEnvelopesOnIndicator(IndicatorCalculateCache *_cache, IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, ENUM_MA_METHOD _ma_method, // (MT4/MT5): MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA int _indi_mode, // Source indicator's mode index. May be -1 to use first buffer @@ -207,25 +196,23 @@ class Indi_Envelopes : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Envelopes::iEnvelopes(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetMAPeriod(), GetMAMethod(), GetMAShift(), GetAppliedPrice(), - GetDeviation(), _mode, _shift, GetPointer(this)); + _value = Indi_Envelopes::iEnvelopes(GetSymbol(), GetTf(), GetMAPeriod(), GetMAMethod(), GetMAShift(), + GetAppliedPrice(), GetDeviation(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /**/ GetMAPeriod(), GetMAMethod(), GetMAShift(), - GetAppliedPrice(), GetDeviation() /**/, _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetMAPeriod(), + GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation() /**/, _mode, _shift); break; case IDATA_INDICATOR: - _value = Indi_Envelopes::iEnvelopesOnIndicator( - GetCache(), GetDataSource(), Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetMAPeriod(), GetMAMethod(), GetDataSourceMode(), GetMAShift(), GetDeviation(), _mode, _shift); + _value = Indi_Envelopes::iEnvelopesOnIndicator(GetCache(), GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), + GetMAMethod(), GetDataSourceMode(), GetMAShift(), GetDeviation(), + _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -241,7 +228,7 @@ class Indi_Envelopes : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { @@ -252,10 +239,9 @@ class Indi_Envelopes : public Indicator { // The LINE_MAIN only exists in MQL4 for Envelopes. _entry.values[LINE_MAIN] = GetValue((ENUM_LO_UP_LINE)LINE_MAIN, _shift); #endif - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, - !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGt(0)); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } @@ -275,32 +261,39 @@ class Indi_Envelopes : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return Indicator::IsValidEntry(_entry) && _entry.IsGt(0); + } + /* Getters */ /** * Get MA period value. */ - int GetMAPeriod() { return params.ma_period; } + int GetMAPeriod() { return iparams.ma_period; } /** * Set MA method. */ - ENUM_MA_METHOD GetMAMethod() { return params.ma_method; } + ENUM_MA_METHOD GetMAMethod() { return iparams.ma_method; } /** * Get MA shift value. */ - int GetMAShift() { return params.ma_shift; } + int GetMAShift() { return iparams.ma_shift; } /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /** * Get deviation value. */ - double GetDeviation() { return params.deviation; } + double GetDeviation() { return iparams.deviation; } /* Setters */ @@ -309,7 +302,7 @@ class Indi_Envelopes : public Indicator { */ void SetMAPeriod(int _ma_period) { istate.is_changed = true; - params.ma_period = _ma_period; + iparams.ma_period = _ma_period; } /** @@ -317,7 +310,7 @@ class Indi_Envelopes : public Indicator { */ void SetMAMethod(ENUM_MA_METHOD _ma_method) { istate.is_changed = true; - params.ma_method = _ma_method; + iparams.ma_method = _ma_method; } /** @@ -325,7 +318,7 @@ class Indi_Envelopes : public Indicator { */ void SetMAShift(int _ma_shift) { istate.is_changed = true; - params.ma_shift = _ma_shift; + iparams.ma_shift = _ma_shift; } /** @@ -333,7 +326,7 @@ class Indi_Envelopes : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _ap) { istate.is_changed = true; - params.applied_price = _ap; + iparams.applied_price = _ap; } /** @@ -341,6 +334,6 @@ class Indi_Envelopes : public Indicator { */ void SetDeviation(double _deviation) { istate.is_changed = true; - params.deviation = _deviation; + iparams.deviation = _deviation; } }; diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index bc986d20d..1b69fa76e 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -48,17 +48,15 @@ struct ForceParams : IndicatorParams { ENUM_MA_METHOD ma_method; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - void ForceParams(unsigned int _period, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_PRICE _ap, int _shift = 0) - : period(_period), ma_method(_ma_method), applied_price(_ap) { - itype = INDI_FORCE; - max_modes = 1; + ForceParams(unsigned int _period = 13, ENUM_MA_METHOD _ma_method = MODE_SMA, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, + int _shift = 0) + : period(_period), ma_method(_ma_method), applied_price(_ap), IndicatorParams(INDI_FORCE, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Force_Index"); }; - void ForceParams(ForceParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ForceParams(ForceParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -66,22 +64,14 @@ struct ForceParams : IndicatorParams { /** * Implements the Force Index indicator. */ -class Indi_Force : public Indicator { +class Indi_Force : public Indicator { protected: - // Structs. - ForceParams params; - public: /** * Class constructor. */ - Indi_Force(ForceParams &_p) : params(_p.period, _p.ma_method, _p.applied_price), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_Force(ForceParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.period, _p.ma_method, _p.applied_price), Indicator(INDI_FORCE, _tf) { - params = _p; - } + Indi_Force(ForceParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_Force(ENUM_TIMEFRAMES _tf) : Indicator(INDI_FORCE, _tf) {} /** * Returns the indicator value. @@ -91,7 +81,7 @@ class Indi_Force : public Indicator { * - https://www.mql5.com/en/docs/indicators/iforce */ static double iForce(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, ENUM_MA_METHOD _ma_method, - ENUM_APPLIED_PRICE _applied_price, int _shift = 0, Indicator *_obj = NULL) { + ENUM_APPLIED_PRICE _applied_price, int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iForce(_symbol, _tf, _period, _ma_method, _applied_price, _shift); #else // __MQL5__ @@ -127,19 +117,18 @@ class Indi_Force : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Force::iForce(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - GetMAMethod(), GetAppliedPrice(), _shift, GetPointer(this)); + _value = + Indi_Force::iForce(GetSymbol(), GetTf(), GetPeriod(), GetMAMethod(), GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetMAMethod(), GetAppliedPrice(), - VOLUME_TICK /*]*/, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), + GetMAMethod(), GetAppliedPrice(), VOLUME_TICK /*]*/, 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -149,29 +138,6 @@ class Indi_Force : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -186,17 +152,17 @@ class Indi_Force : public Indicator { /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get MA method. */ - ENUM_MA_METHOD GetMAMethod() { return params.ma_method; } + ENUM_MA_METHOD GetMAMethod() { return iparams.ma_method; } /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -205,7 +171,7 @@ class Indi_Force : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -213,7 +179,7 @@ class Indi_Force : public Indicator { */ void SetMAMethod(ENUM_MA_METHOD _ma_method) { istate.is_changed = true; - params.ma_method = _ma_method; + iparams.ma_method = _ma_method; } /** @@ -221,6 +187,6 @@ class Indi_Force : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index 5a813e4d5..e47f56aa7 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -23,29 +23,26 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" // Structs. -struct FrIndiAMAParams : IndicatorParams { +struct IndiFrAMAParams : IndicatorParams { unsigned int frama_shift; unsigned int period; ENUM_APPLIED_PRICE applied_price; // Struct constructor. - void FrIndiAMAParams(int _period = 14, int _frama_shift = 0, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + IndiFrAMAParams(int _period = 14, int _frama_shift = 0, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + : IndicatorParams(INDI_FRAMA, 1, TYPE_DOUBLE) { frama_shift = _frama_shift; - itype = INDI_FRAMA; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\FrAMA"); applied_price = _ap; period = _period; shift = _shift; - tf = _tf; }; - void FrIndiAMAParams(FrIndiAMAParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + IndiFrAMAParams(IndiFrAMAParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -53,25 +50,19 @@ struct FrIndiAMAParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_FrAMA : public Indicator { - protected: - FrIndiAMAParams params; - +class Indi_FrAMA : public Indicator { public: /** * Class constructor. */ - Indi_FrAMA(FrIndiAMAParams &_params) - : params(_params.period, _params.frama_shift), Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_FrAMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_FRAMA, _tf) { params.tf = _tf; }; + Indi_FrAMA(IndiFrAMAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_FrAMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_FRAMA, _tf){}; /** * 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, Indicator *_obj = NULL) { + int _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iFrAMA(_symbol, _tf, _ma_period, _ma_shift, _ap), _mode, _shift); #else @@ -142,16 +133,16 @@ class Indi_FrAMA : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_FrAMA::iFrAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFRAMAShift(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ GetPeriod(), + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetFRAMAShift() /*]*/, 0, _shift); break; default: @@ -162,29 +153,6 @@ class Indi_FrAMA : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -199,17 +167,17 @@ class Indi_FrAMA : public Indicator { /** * Get period. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get FRAMA shift. */ - unsigned int GetFRAMAShift() { return params.frama_shift; } + unsigned int GetFRAMAShift() { return iparams.frama_shift; } /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -218,7 +186,7 @@ class Indi_FrAMA : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -226,7 +194,7 @@ class Indi_FrAMA : public Indicator { */ void SetFRAMAShift(unsigned int _frama_shift) { istate.is_changed = true; - params.frama_shift = _frama_shift; + iparams.frama_shift = _frama_shift; } /** @@ -234,6 +202,6 @@ class Indi_FrAMA : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index ff41504d7..87e5e097e 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -33,17 +33,13 @@ double iFractals(string _symbol, int _tf, int _mode, int _shift) { // Structs. struct FractalsParams : IndicatorParams { // Struct constructors. - void FractalsParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_FRACTALS; - max_modes = FINAL_LO_UP_LINE_ENTRY; - SetDataValueType(TYPE_DOUBLE); + FractalsParams(int _shift = 0) : IndicatorParams(INDI_FRACTALS, FINAL_LO_UP_LINE_ENTRY, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_ARROW); SetCustomIndicatorName("Examples\\Fractals"); shift = _shift; - tf = _tf; }; - void FractalsParams(FractalsParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + FractalsParams(FractalsParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -51,15 +47,12 @@ struct FractalsParams : IndicatorParams { /** * Implements the Fractals indicator. */ -class Indi_Fractals : public Indicator { - protected: - FractalsParams params; - +class Indi_Fractals : public Indicator { public: /** * Class constructor. */ - Indi_Fractals(IndicatorParams &_p) : Indicator((IndicatorParams)_p) {} + Indi_Fractals(FractalsParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} Indi_Fractals(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_FRACTALS, _tf) {} /** @@ -72,7 +65,7 @@ class Indi_Fractals : public Indicator { static double iFractals(string _symbol, ENUM_TIMEFRAMES _tf, ENUM_LO_UP_LINE _mode, // (MT4 _mode): 1 - MODE_UPPER, 2 - MODE_LOWER int _shift = 0, // (MT5 _mode): 0 - UPPER_LINE, 1 - LOWER_LINE - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iFractals(_symbol, _tf, _mode, _shift); #else // __MQL5__ @@ -108,18 +101,16 @@ class Indi_Fractals : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_LO_UP_LINE _mode, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = _value = Indi_Fractals::iFractals( - Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), _mode, _shift, GetPointer(this)); + _value = _value = Indi_Fractals::iFractals(GetSymbol(), GetTf(), (ENUM_LO_UP_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -135,25 +126,20 @@ class Indi_Fractals : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { _entry.timestamp = GetBarTime(_shift); _entry.values[LINE_UPPER] = GetValue(LINE_UPPER, _shift); _entry.values[LINE_LOWER] = GetValue(LINE_LOWER, _shift); - double _wrong_value = (double)NULL; - ; #ifdef __MQL4__ // In MT4 line identifiers starts from 1, so populating also at 0. _entry.values[0] = _entry.values[LINE_UPPER]; - // In MT4, the empty value for iFractals is 0, not EMPTY_VALUE=DBL_MAX as in MT5. - // So the wrong value is the opposite. - _wrong_value = EMPTY_VALUE; #endif - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(_wrong_value)); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } @@ -168,4 +154,17 @@ class Indi_Fractals : public Indicator { _param.double_value = GetEntry(_shift)[_mode]; return _param; } + + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + double _wrong_value = (double)NULL; +#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. + _wrong_value = EMPTY_VALUE; +#endif + return !_entry.HasValue(_wrong_value); + } }; diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index 6a02f8473..78f74fc98 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -78,8 +78,8 @@ struct GatorParams : IndicatorParams { ENUM_MA_METHOD ma_method; // Averaging method. ENUM_APPLIED_PRICE applied_price; // Applied price. // Struct constructors. - void GatorParams(int _jp, int _js, int _tp, int _ts, int _lp, int _ls, ENUM_MA_METHOD _mm, ENUM_APPLIED_PRICE _ap, - int _shift = 0) + GatorParams(int _jp = 13, int _js = 8, int _tp = 8, int _ts = 5, int _lp = 5, int _ls = 3, + ENUM_MA_METHOD _mm = MODE_SMMA, ENUM_APPLIED_PRICE _ap = PRICE_MEDIAN, int _shift = 0) : jaw_period(_jp), jaw_shift(_js), teeth_period(_tp), @@ -87,16 +87,14 @@ struct GatorParams : IndicatorParams { lips_period(_lp), lips_shift(_ls), ma_method(_mm), - applied_price(_ap) { - itype = INDI_GATOR; - max_modes = FINAL_GATOR_LINE_HISTOGRAM_ENTRY; + applied_price(_ap), + IndicatorParams(INDI_GATOR, FINAL_GATOR_LINE_HISTOGRAM_ENTRY, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Gator"); }; - void GatorParams(GatorParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + GatorParams(GatorParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -104,26 +102,13 @@ struct GatorParams : IndicatorParams { /** * Implements the Gator oscillator. */ -class Indi_Gator : public Indicator { - protected: - GatorParams params; - +class Indi_Gator : public Indicator { public: /** * Class constructor. */ - Indi_Gator(GatorParams &_p) - : params(_p.jaw_period, _p.jaw_shift, _p.teeth_period, _p.teeth_shift, _p.lips_period, _p.lips_shift, - _p.ma_method, _p.applied_price), - Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_Gator(GatorParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.jaw_period, _p.jaw_shift, _p.teeth_period, _p.teeth_shift, _p.lips_period, _p.lips_shift, - _p.ma_method, _p.applied_price), - Indicator(INDI_GATOR, _tf) { - params = _p; - } + Indi_Gator(GatorParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_Gator(ENUM_TIMEFRAMES _tf) : Indicator(INDI_GATOR, _tf) {} /** * Returns the indicator value. @@ -146,7 +131,7 @@ class Indi_Gator : public Indicator { static double iGator(string _symbol, ENUM_TIMEFRAMES _tf, int _jaw_period, int _jaw_shift, int _teeth_period, int _teeth_shift, int _lips_period, int _lips_shift, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_PRICE _applied_price, ENUM_GATOR_HISTOGRAM _mode, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iGator(_symbol, _tf, _jaw_period, _jaw_shift, _teeth_period, _teeth_shift, _lips_period, _lips_shift, _ma_method, _applied_price, _mode, _shift); @@ -184,19 +169,18 @@ class Indi_Gator : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_GATOR_HISTOGRAM _mode, int _shift = 0) { + virtual double GetValue(int _mode, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Gator::iGator(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), - GetLipsShift(), GetMAMethod(), GetAppliedPrice(), _mode, _shift, GetPointer(this)); + _value = Indi_Gator::iGator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), + GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice(), + (ENUM_GATOR_HISTOGRAM)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /**/ + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice() @@ -217,7 +201,7 @@ class Indi_Gator : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { @@ -234,11 +218,9 @@ class Indi_Gator : public Indicator { _entry.values[LINE_UPPER_HISTCOLOR] = GetValue(LINE_UPPER_HISTCOLOR, _shift); _entry.values[LINE_LOWER_HISTCOLOR] = GetValue(LINE_LOWER_HISTCOLOR, _shift); #endif - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, - !_entry.HasValue(EMPTY_VALUE) && (_entry.values[LINE_UPPER_HISTOGRAM].GetDbl() != 0 || - _entry.values[LINE_LOWER_HISTOGRAM].GetDbl() != 0)); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } @@ -254,47 +236,55 @@ class Indi_Gator : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return !_entry.HasValue(EMPTY_VALUE) && + (_entry.values[LINE_UPPER_HISTOGRAM].GetDbl() != 0 || _entry.values[LINE_LOWER_HISTOGRAM].GetDbl() != 0); + } + /* Getters */ /** * Get jaw period value. */ - unsigned int GetJawPeriod() { return params.jaw_period; } + unsigned int GetJawPeriod() { return iparams.jaw_period; } /** * Get jaw shift value. */ - unsigned int GetJawShift() { return params.jaw_shift; } + unsigned int GetJawShift() { return iparams.jaw_shift; } /** * Get teeth period value. */ - unsigned int GetTeethPeriod() { return params.teeth_period; } + unsigned int GetTeethPeriod() { return iparams.teeth_period; } /** * Get teeth shift value. */ - unsigned int GetTeethShift() { return params.teeth_shift; } + unsigned int GetTeethShift() { return iparams.teeth_shift; } /** * Get lips period value. */ - unsigned int GetLipsPeriod() { return params.lips_period; } + unsigned int GetLipsPeriod() { return iparams.lips_period; } /** * Get lips shift value. */ - unsigned int GetLipsShift() { return params.lips_shift; } + unsigned int GetLipsShift() { return iparams.lips_shift; } /** * Get MA method. */ - ENUM_MA_METHOD GetMAMethod() { return params.ma_method; } + ENUM_MA_METHOD GetMAMethod() { return iparams.ma_method; } /** * Get applied price value. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -303,7 +293,7 @@ class Indi_Gator : public Indicator { */ void SetJawPeriod(int _jaw_period) { istate.is_changed = true; - params.jaw_period = _jaw_period; + iparams.jaw_period = _jaw_period; } /** @@ -311,7 +301,7 @@ class Indi_Gator : public Indicator { */ void SetJawShift(int _jaw_shift) { istate.is_changed = true; - params.jaw_shift = _jaw_shift; + iparams.jaw_shift = _jaw_shift; } /** @@ -319,7 +309,7 @@ class Indi_Gator : public Indicator { */ void SetTeethPeriod(int _teeth_period) { istate.is_changed = true; - params.teeth_period = _teeth_period; + iparams.teeth_period = _teeth_period; } /** @@ -327,7 +317,7 @@ class Indi_Gator : public Indicator { */ void SetTeethShift(int _teeth_shift) { istate.is_changed = true; - params.teeth_period = _teeth_shift; + iparams.teeth_period = _teeth_shift; } /** @@ -335,7 +325,7 @@ class Indi_Gator : public Indicator { */ void SetLipsPeriod(int _lips_period) { istate.is_changed = true; - params.lips_period = _lips_period; + iparams.lips_period = _lips_period; } /** @@ -343,7 +333,7 @@ class Indi_Gator : public Indicator { */ void SetLipsShift(int _lips_shift) { istate.is_changed = true; - params.lips_period = _lips_shift; + iparams.lips_period = _lips_shift; } /** @@ -351,7 +341,7 @@ class Indi_Gator : public Indicator { */ void SetMAMethod(ENUM_MA_METHOD _ma_method) { istate.is_changed = true; - params.ma_method = _ma_method; + iparams.ma_method = _ma_method; } /** @@ -359,6 +349,6 @@ class Indi_Gator : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index bbc9896b1..eb6e18b06 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -50,22 +50,17 @@ enum ENUM_HA_MODE { // Structs. struct HeikenAshiParams : IndicatorParams { // Struct constructors. - void HeikenAshiParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_HEIKENASHI; - max_modes = FINAL_HA_MODE_ENTRY; - SetDataValueType(TYPE_DOUBLE); + HeikenAshiParams(int _shift = 0) : IndicatorParams(INDI_HEIKENASHI, FINAL_HA_MODE_ENTRY, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); // @fixit It draws candles! - SetDataSourceType(IDATA_BUILTIN); #ifdef __MQL4__ SetCustomIndicatorName("Heiken Ashi"); #else SetCustomIndicatorName("Examples\\Heiken_Ashi"); #endif shift = _shift; - tf = _tf; }; - void HeikenAshiParams(HeikenAshiParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + HeikenAshiParams(HeikenAshiParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -73,22 +68,19 @@ struct HeikenAshiParams : IndicatorParams { /** * Implements the Heiken-Ashi indicator. */ -class Indi_HeikenAshi : public Indicator { - protected: - HeikenAshiParams params; - +class Indi_HeikenAshi : public Indicator { public: /** * Class constructor. */ - Indi_HeikenAshi(IndicatorParams &_p) : Indicator((IndicatorParams)_p) {} + Indi_HeikenAshi(HeikenAshiParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} Indi_HeikenAshi(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_HEIKENASHI, _tf) {} /** * Returns value for iHeikenAshi indicator. */ static double iCustomLegacyHeikenAshi(string _symbol, ENUM_TIMEFRAMES _tf, string _name, int _mode, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ // Low and High prices could be in reverse order when using MT4's built-in indicator, so we need to retrieve both // and return correct one. @@ -138,7 +130,7 @@ class Indi_HeikenAshi : public Indicator { * "Built-in" version of Heiken Ashi. */ static double iHeikenAshi(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, - Indicator *_obj = NULL) { + Indi_HeikenAshi *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_HeikenAshi"); return iHeikenAshiOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -203,20 +195,37 @@ class Indi_HeikenAshi : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_HA_MODE _mode, int _shift = 0) { + virtual double GetValue(int _mode = HA_OPEN, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_HeikenAshi::iHeikenAshi(GetSymbol(), GetTf(), _mode, _shift, GetPointer(this)); +#ifdef __MQL4__ + // Converting MQL4's enum into MQL5 one, as OnCalculate uses further one. + switch (_mode) { + case HA_OPEN: + _mode = (ENUM_HA_MODE)0; + break; + case HA_HIGH: + _mode = (ENUM_HA_MODE)1; + break; + case HA_LOW: + _mode = (ENUM_HA_MODE)2; + break; + case HA_CLOSE: + _mode = (ENUM_HA_MODE)3; + break; + } +#endif + _value = Indi_HeikenAshi::iHeikenAshi(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), 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(), params.GetCustomIndicatorName(), _mode, - _shift, GetPointer(this)); + _value = Indi_HeikenAshi::iCustomLegacyHeikenAshi(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, + _shift, THIS_PTR); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -232,19 +241,17 @@ class Indi_HeikenAshi : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { + for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) { _entry.values[_mode] = GetValue((ENUM_HA_MODE)_mode, _shift); } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && - !_entry.HasValue(EMPTY_VALUE) && _entry.IsGt(0) && - _entry.values[HA_LOW].GetDbl() < _entry.values[HA_HIGH].GetDbl()); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } @@ -259,4 +266,12 @@ class Indi_HeikenAshi : public Indicator { GetEntry(_shift).values[_mode].Get(_param.double_value); return _param; } + + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGt(0) && + _entry.values[HA_LOW].GetDbl() < _entry.values[HA_HIGH].GetDbl(); + } }; diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index f58d56d5b..b2a70f6de 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -67,17 +67,17 @@ struct IchimokuParams : IndicatorParams { unsigned int kijun_sen; unsigned int senkou_span_b; // Struct constructors. - void IchimokuParams(unsigned int _ts, unsigned int _ks, unsigned int _ss_b, int _shift = 0) - : tenkan_sen(_ts), kijun_sen(_ks), senkou_span_b(_ss_b) { - itype = INDI_ICHIMOKU; - max_modes = FINAL_ICHIMOKU_LINE_ENTRY; + IchimokuParams(unsigned int _ts = 9, unsigned int _ks = 26, unsigned int _ss_b = 52, int _shift = 0) + : tenkan_sen(_ts), + kijun_sen(_ks), + senkou_span_b(_ss_b), + IndicatorParams(INDI_ICHIMOKU, FINAL_ICHIMOKU_LINE_ENTRY, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_PRICE); // @fixit Not sure if not mixed. SetCustomIndicatorName("Examples\\Ichimoku"); }; - void IchimokuParams(IchimokuParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + IchimokuParams(IchimokuParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -85,22 +85,13 @@ struct IchimokuParams : IndicatorParams { /** * Implements the Ichimoku Kinko Hyo indicator. */ -class Indi_Ichimoku : public Indicator { - protected: - IchimokuParams params; - +class Indi_Ichimoku : public Indicator { public: /** * Class constructor. */ - Indi_Ichimoku(IchimokuParams &_p) - : params(_p.tenkan_sen, _p.kijun_sen, _p.senkou_span_b), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_Ichimoku(IchimokuParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.tenkan_sen, _p.kijun_sen, _p.senkou_span_b), Indicator(INDI_ICHIMOKU, _tf) { - params = _p; - } + Indi_Ichimoku(IchimokuParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_Ichimoku(ENUM_TIMEFRAMES _tf) : Indicator(INDI_ICHIMOKU, _tf) {} /** * Returns the indicator value. @@ -114,7 +105,7 @@ class Indi_Ichimoku : public Indicator { * - https://www.mql5.com/en/docs/indicators/iichimoku */ static double iIchimoku(string _symbol, ENUM_TIMEFRAMES _tf, int _tenkan_sen, int _kijun_sen, int _senkou_span_b, - int _mode, int _shift = 0, Indicator *_obj = NULL) { + int _mode, int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iIchimoku(_symbol, _tf, _tenkan_sen, _kijun_sen, _senkou_span_b, _mode, _shift); #else // __MQL5__ @@ -150,20 +141,18 @@ class Indi_Ichimoku : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_ICHIMOKU_LINE _mode, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = - Indi_Ichimoku::iIchimoku(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetTenkanSen(), GetKijunSen(), GetSenkouSpanB(), _mode, _shift, GetPointer(this)); + _value = Indi_Ichimoku::iIchimoku(GetSymbol(), GetTf(), GetTenkanSen(), GetKijunSen(), GetSenkouSpanB(), _mode, + _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetTenkanSen(), GetKijunSen(), GetSenkouSpanB() /*]*/, - _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetTenkanSen(), + GetKijunSen(), GetSenkouSpanB() /*]*/, _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -179,7 +168,7 @@ class Indi_Ichimoku : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { @@ -194,10 +183,9 @@ class Indi_Ichimoku : public Indicator { _entry.values[LINE_SENKOUSPANA] = GetValue(LINE_SENKOUSPANA, _shift); _entry.values[LINE_SENKOUSPANB] = GetValue(LINE_SENKOUSPANB, _shift); _entry.values[LINE_CHIKOUSPAN] = GetValue(LINE_CHIKOUSPAN, _shift + 26); - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, - !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGt(0)); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } @@ -213,22 +201,29 @@ class Indi_Ichimoku : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return Indicator::IsValidEntry(_entry) && _entry.IsGt(0); + } + /* Getters */ /** * Get period of Tenkan-sen line. */ - unsigned int GetTenkanSen() { return params.tenkan_sen; } + unsigned int GetTenkanSen() { return iparams.tenkan_sen; } /** * Get period of Kijun-sen line. */ - unsigned int GetKijunSen() { return params.kijun_sen; } + unsigned int GetKijunSen() { return iparams.kijun_sen; } /** * Get period of Senkou Span B line. */ - unsigned int GetSenkouSpanB() { return params.senkou_span_b; } + unsigned int GetSenkouSpanB() { return iparams.senkou_span_b; } /* Setters */ @@ -237,7 +232,7 @@ class Indi_Ichimoku : public Indicator { */ void SetTenkanSen(unsigned int _tenkan_sen) { istate.is_changed = true; - params.tenkan_sen = _tenkan_sen; + iparams.tenkan_sen = _tenkan_sen; } /** @@ -245,7 +240,7 @@ class Indi_Ichimoku : public Indicator { */ void SetKijunSen(unsigned int _kijun_sen) { istate.is_changed = true; - params.kijun_sen = _kijun_sen; + iparams.kijun_sen = _kijun_sen; } /** @@ -253,6 +248,6 @@ class Indi_Ichimoku : public Indicator { */ void SetSenkouSpanB(unsigned int _senkou_span_b) { istate.is_changed = true; - params.senkou_span_b = _senkou_span_b; + iparams.senkou_span_b = _senkou_span_b; } }; diff --git a/Indicators/Indi_Killzones.mqh b/Indicators/Indi_Killzones.mqh new file mode 100644 index 000000000..6454e49d3 --- /dev/null +++ b/Indicators/Indi_Killzones.mqh @@ -0,0 +1,203 @@ +//+------------------------------------------------------------------+ +//| 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 "../Indicator.mqh" +#include "../Market.struct.h" + +// Defines enumerations. +enum ENUM_INDI_KILLZONES_MODE { + INDI_KILLZONES_MODE_CHICAGO_HIGH = 0, + INDI_KILLZONES_MODE_CHICAGO_LOW, + INDI_KILLZONES_MODE_FRANKFURT_HIGH, + INDI_KILLZONES_MODE_FRANKFURT_LOW, + INDI_KILLZONES_MODE_HONGKONG_HIGH, + INDI_KILLZONES_MODE_HONGKONG_LOW, + INDI_KILLZONES_MODE_LONDON_HIGH, + INDI_KILLZONES_MODE_LONDON_LOW, + INDI_KILLZONES_MODE_NEWYORK_HIGH, + INDI_KILLZONES_MODE_NEWYORK_LOW, + INDI_KILLZONES_MODE_SYDNEY_HIGH, + INDI_KILLZONES_MODE_SYDNEY_LOW, + INDI_KILLZONES_MODE_TOKYO_HIGH, + INDI_KILLZONES_MODE_TOKYO_LOW, + INDI_KILLZONES_MODE_WELLINGTON_HIGH, + INDI_KILLZONES_MODE_WELLINGTON_LOW, + FINAL_INDI_KILLZONES_MODE_ENTRY, +}; + +// Defines structs. +struct IndiKillzonesParams : IndicatorParams { + ENUM_PP_TYPE method; // Pivot point calculation method. + // Struct constructor. + IndiKillzonesParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + : IndicatorParams(INDI_PIVOT, FINAL_INDI_KILLZONES_MODE_ENTRY, TYPE_FLOAT) { + SetDataValueRange(IDATA_RANGE_MIXED); + SetDataSourceType(IDATA_CHART); + SetShift(_shift); + tf = _tf; + }; + IndiKillzonesParams(IndiKillzonesParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; + tf = _tf; + }; +}; + +struct Indi_Killzones_Time : MarketTimeForex { + float highs[FINAL_INDI_KILLZONES_MODE_ENTRY / 2], lows[FINAL_INDI_KILLZONES_MODE_ENTRY / 2]; + datetime reset_last; + Indi_Killzones_Time() : reset_last(0), MarketTimeForex(::TimeGMT()) { + ArrayFill(highs, 0, ArraySize(highs), 0.0f); + ArrayFill(lows, 0, ArraySize(lows), 0.0f); + } + bool CheckHours(int _index) { + bool _result = MarketTimeForex::CheckHours(1 << _index); + if (!_result) { + Reset(_index); + } + return _result; + } + float GetHigh(int _index) { return highs[_index]; } + float GetLow(int _index) { return lows[_index]; } + void Reset(int _index) { + highs[_index] = 0.0f; + lows[_index] = 0.0f; + } + void Update(float _value, int _index) { + highs[_index] = _value > highs[_index] ? _value : highs[_index]; + lows[_index] = _value < lows[_index] || lows[_index] == 0.0f ? _value : lows[_index]; + } +}; + +/** + * Implements Pivot Detector. + */ +class Indi_Killzones : public Indicator { + protected: + Indi_Killzones_Time ikt; + + public: + /** + * Class constructor. + */ + Indi_Killzones(IndiKillzonesParams &_p, IndicatorBase *_indi_src = NULL) + : Indicator(_p, _indi_src) {} + Indi_Killzones(ENUM_TIMEFRAMES _tf) : Indicator(INDI_KILLZONES, _tf) {} + + /** + * Returns the indicator's value. + */ + float GetValue(unsigned int _mode, int _shift = 0) { + ResetLastError(); + float _value = FLT_MAX; + int _index = (int)_mode / 2; + switch (iparams.idstype) { + case IDATA_BUILTIN: + // Builtin mode not supported. + SetUserError(ERR_INVALID_PARAMETER); + istate.is_ready = false; + break; + case IDATA_CHART: + ikt.Set(::TimeGMT()); + if (ikt.CheckHours(_index)) { + // Pass values to check for new highs or lows. + ikt.Update(_mode % 2 == 0 ? (float)GetHigh(_shift) : (float)GetLow(_shift), _index); + } + // Set a final value. + _value = _mode % 2 == 0 ? ikt.GetHigh(_index) : ikt.GetLow(_index); + break; + default: + SetUserError(ERR_INVALID_PARAMETER); + } + return _value; + } + + /** + * Checks if value is valid. + */ + bool IsValidValue(float _value, unsigned int _mode = 0, int _shift = 0) { return _value > 0.0f; } + + /** + * Returns the indicator's struct value. + */ + IndicatorDataEntry GetEntry(int _shift = 0) { + long _bar_time = GetBarTime(_shift); + IndicatorDataEntry _entry = idata.GetByKey(_bar_time); + if (!_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) { + _entry.Resize(iparams.GetMaxModes()); + _entry.timestamp = GetBarTime(_shift); + for (unsigned int _mode = 0; _mode < (uint)iparams.GetMaxModes(); _mode++) { + float _value = GetValue(_mode, _shift); + _entry.values[_mode] = IsValidValue(_value, _mode, _shift) ? _value : 0.0f; + } + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); + if (_entry.IsValid()) { + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); + idata.Add(_entry, _bar_time); + istate.is_changed = false; + istate.is_ready = true; + } else { + _entry.AddFlags(INDI_ENTRY_FLAG_INSUFFICIENT_DATA); + istate.is_ready = false; + } + } + return _entry; + } + + /** + * Returns the indicator's entry value. + */ + MqlParam GetEntryValue(int _shift = 0, int _mode = 0) { + MqlParam _param = {TYPE_INT}; + _param.integer_value = GetEntry(_shift).GetValue(_mode); + return _param; + } + + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return _entry.IsGe(0) && !_entry.HasValue(FLT_MAX); + } + + /* Getters */ + + /** + * Get pivot point calculation method. + */ + ENUM_PP_TYPE GetMethod() { return iparams.method; } + + /* Setters */ + + /** + * Set pivot point calculation method. + */ + void SetMethod(ENUM_PP_TYPE _method) { + istate.is_changed = true; + iparams.method = _method; + } + + /** + * Whether we can and have to select mode when specifying data source. + */ + virtual bool IsDataSourceModeSelectable() { return false; } +}; diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 319cc5649..12888ee03 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -52,18 +52,19 @@ struct MAParams : IndicatorParams { ENUM_MA_METHOD ma_method; ENUM_APPLIED_PRICE applied_array; // Struct constructors. - void MAParams(unsigned int _period = 13, int _ma_shift = 10, ENUM_MA_METHOD _ma_method = MODE_SMA, - ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : period(_period), ma_shift(_ma_shift), ma_method(_ma_method), applied_array(_ap) { - itype = INDI_MA; - max_modes = 1; + MAParams(unsigned int _period = 13, int _ma_shift = 10, ENUM_MA_METHOD _ma_method = MODE_SMA, + ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) + : period(_period), + ma_shift(_ma_shift), + ma_method(_ma_method), + applied_array(_ap), + IndicatorParams(INDI_MA, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_PRICE); SetCustomIndicatorName("Examples\\Moving Average"); }; - void MAParams(MAParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + MAParams(MAParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -71,21 +72,13 @@ struct MAParams : IndicatorParams { /** * Implements the Moving Average indicator. */ -class Indi_MA : public Indicator { - protected: - MAParams params; - +class Indi_MA : public Indicator { public: /** * Class constructor. */ - Indi_MA(MAParams &_p) : params(_p.period, _p.shift, _p.ma_method, _p.applied_array), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_MA(MAParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.period, _p.shift, _p.ma_method, _p.applied_array), Indicator(INDI_MA, _tf) { - params = _p; - } + Indi_MA(MAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_MA(ENUM_TIMEFRAMES _tf) : Indicator(INDI_MA, _tf) {} /** * Returns the indicator value. @@ -96,7 +89,7 @@ class Indi_MA : public Indicator { */ static double iMA(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _ma_period, unsigned int _ma_shift, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_PRICE _applied_array, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { ResetLastError(); #ifdef __MQL4__ return ::iMA(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_array, _shift); @@ -133,11 +126,11 @@ class Indi_MA : public Indicator { /** * Calculates MA on another indicator. */ - static double iMAOnIndicator(IndicatorCalculateCache *cache, Indicator *indi, int indi_mode, string symbol, - ENUM_TIMEFRAMES tf, unsigned int ma_period, unsigned int ma_shift, + static double iMAOnIndicator(IndicatorCalculateCache *cache, IndicatorBase *_indi, int indi_mode, + string symbol, ENUM_TIMEFRAMES tf, unsigned int ma_period, unsigned int ma_shift, ENUM_MA_METHOD ma_method, // (MT4/MT5): MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA int shift = 0) { - return iMAOnArray(indi.GetValueStorage(indi_mode), 0, ma_period, ma_shift, ma_method, shift, cache); + return iMAOnArray(_indi.GetValueStorage(indi_mode), 0, ma_period, ma_shift, ma_method, shift, cache); } /** @@ -634,25 +627,23 @@ class Indi_MA : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_MA::iMA(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - GetMAShift(), GetMAMethod(), GetAppliedPrice(), _shift, GetPointer(this)); + _value = Indi_MA::iMA(GetSymbol(), 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, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.custom_indi_name, /* [ */ GetPeriod(), GetMAShift(), GetMAMethod(), - GetAppliedPrice() /* ] */, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), 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(), - Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), + _value = Indi_MA::iMAOnIndicator(GetCache(), GetDataSource(), GetDataSourceMode(), GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), _shift); break; } @@ -661,31 +652,6 @@ class Indi_MA : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - IndicatorDataEntry _entry = idata.GetByKey(_bar_time); - if (!_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) { - _entry.Resize(params.max_modes); - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && - !_entry.HasValue(EMPTY_VALUE) && - !_entry.HasValue(DBL_MAX)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } else { - _entry.AddFlags(INDI_ENTRY_FLAG_INSUFFICIENT_DATA); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -703,8 +669,8 @@ class Indi_MA : public Indicator { Indi_MA *_ptr; string _key = Util::MakeKey(_symbol, (int)_tf, _period, _ma_shift, (int)_ma_method, (int)_ap); if (!Objects::TryGet(_key, _ptr)) { - MAParams _params(_period, _ma_shift, _ma_method, _ap); - _ptr = Objects::Set(_key, new Indi_MA(_params)); + MAParams _p(_period, _ma_shift, _ma_method, _ap); + _ptr = Objects::Set(_key, new Indi_MA(_p)); _ptr.SetSymbol(_symbol); } return _ptr; @@ -717,26 +683,26 @@ class Indi_MA : public Indicator { * * Averaging period for the calculation of the moving average. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get MA shift value. * * Indicators line offset relate to the chart by timeframe. */ - unsigned int GetMAShift() { return params.ma_shift; } + unsigned int GetMAShift() { return iparams.ma_shift; } /** * Set MA method (smoothing type). */ - ENUM_MA_METHOD GetMAMethod() { return params.ma_method; } + ENUM_MA_METHOD GetMAMethod() { return iparams.ma_method; } /** * Get applied price value. * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_array; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_array; } /* Setters */ @@ -747,7 +713,7 @@ class Indi_MA : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -755,7 +721,7 @@ class Indi_MA : public Indicator { */ void SetMAShift(int _ma_shift) { istate.is_changed = true; - params.ma_shift = _ma_shift; + iparams.ma_shift = _ma_shift; } /** @@ -765,7 +731,7 @@ class Indi_MA : public Indicator { */ void SetMAMethod(ENUM_MA_METHOD _ma_method) { istate.is_changed = true; - params.ma_method = _ma_method; + iparams.ma_method = _ma_method; } /** @@ -778,7 +744,7 @@ class Indi_MA : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_array) { istate.is_changed = true; - params.applied_array = _applied_array; + iparams.applied_array = _applied_array; } }; #endif // INDI_MA_MQH diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index e4caca10d..56c718d88 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -38,17 +38,19 @@ struct MACDParams : IndicatorParams { unsigned int signal_period; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - void MACDParams(unsigned int _efp, unsigned int _esp, unsigned int _sp, ENUM_APPLIED_PRICE _ap, int _shift = 0) - : ema_fast_period(_efp), ema_slow_period(_esp), signal_period(_sp), applied_price(_ap) { - itype = INDI_MACD; - max_modes = FINAL_SIGNAL_LINE_ENTRY; + MACDParams(unsigned int _efp = 12, unsigned int _esp = 26, unsigned int _sp = 9, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, + int _shift = 0) + : ema_fast_period(_efp), + ema_slow_period(_esp), + signal_period(_sp), + applied_price(_ap), + IndicatorParams(INDI_MACD, FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\MACD"); }; - void MACDParams(MACDParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + MACDParams(MACDParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -56,23 +58,13 @@ struct MACDParams : IndicatorParams { /** * Implements the Moving Averages Convergence/Divergence indicator. */ -class Indi_MACD : public Indicator { - protected: - MACDParams params; - +class Indi_MACD : public Indicator { public: /** * Class constructor. */ - Indi_MACD(MACDParams &_p) - : params(_p.ema_fast_period, _p.ema_slow_period, _p.signal_period, _p.applied_price), - Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_MACD(MACDParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.ema_fast_period, _p.ema_slow_period, _p.signal_period, _p.applied_price), Indicator(INDI_MACD, _tf) { - params = _p; - } + Indi_MACD(MACDParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_MACD(ENUM_TIMEFRAMES _tf) : Indicator(INDI_MACD, _tf) {} /** * Returns the indicator value. @@ -85,7 +77,7 @@ class Indi_MACD : public Indicator { string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _ema_fast_period, unsigned int _ema_slow_period, unsigned int _signal_period, ENUM_APPLIED_PRICE _applied_price, ENUM_SIGNAL_LINE _mode = LINE_MAIN, // (MT4/MT5 _mode): 0 - MODE_MAIN/MAIN_LINE, 1 - MODE_SIGNAL/SIGNAL_LINE - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iMACD(_symbol, _tf, _ema_fast_period, _ema_slow_period, _signal_period, _applied_price, _mode, _shift); #else // __MQL5__ @@ -122,20 +114,19 @@ class Indi_MACD : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_SIGNAL_LINE _mode = LINE_MAIN, int _shift = 0) { + virtual double GetValue(int _mode = LINE_MAIN, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = - Indi_MACD::iMACD(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetEmaFastPeriod(), - GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice(), _mode, _shift, GetPointer(this)); + _value = Indi_MACD::iMACD(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), + GetAppliedPrice(), (ENUM_SIGNAL_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), GetEmaSlowPeriod(), - GetSignalPeriod(), GetAppliedPrice() /*]*/, _mode, _shift); + _value = + iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), + GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -151,18 +142,17 @@ class Indi_MACD : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { + for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) { _entry.values[_mode] = GetValue((ENUM_SIGNAL_LINE)_mode, _shift); } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, - !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGt(0)); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } @@ -178,6 +168,13 @@ class Indi_MACD : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGt(0); + } + /* Getters */ /** @@ -185,28 +182,28 @@ class Indi_MACD : public Indicator { * * Averaging period for the calculation of the moving average. */ - unsigned int GetEmaFastPeriod() { return params.ema_fast_period; } + unsigned int GetEmaFastPeriod() { return iparams.ema_fast_period; } /** * Get slow EMA period value. * * Averaging period for the calculation of the moving average. */ - unsigned int GetEmaSlowPeriod() { return params.ema_slow_period; } + unsigned int GetEmaSlowPeriod() { return iparams.ema_slow_period; } /** * Get signal period value. * * Averaging period for the calculation of the moving average. */ - unsigned int GetSignalPeriod() { return params.signal_period; } + unsigned int GetSignalPeriod() { return iparams.signal_period; } /** * Get applied price value. * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -217,7 +214,7 @@ class Indi_MACD : public Indicator { */ void SetEmaFastPeriod(unsigned int _ema_fast_period) { istate.is_changed = true; - params.ema_fast_period = _ema_fast_period; + iparams.ema_fast_period = _ema_fast_period; } /** @@ -227,7 +224,7 @@ class Indi_MACD : public Indicator { */ void SetEmaSlowPeriod(unsigned int _ema_slow_period) { istate.is_changed = true; - params.ema_slow_period = _ema_slow_period; + iparams.ema_slow_period = _ema_slow_period; } /** @@ -237,7 +234,7 @@ class Indi_MACD : public Indicator { */ void SetSignalPeriod(unsigned int _signal_period) { istate.is_changed = true; - params.signal_period = _signal_period; + iparams.signal_period = _signal_period; } /** @@ -250,6 +247,6 @@ class Indi_MACD : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index 21db3bc2d..a4bc99d6f 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -35,17 +35,14 @@ struct MFIParams : IndicatorParams { unsigned int ma_period; ENUM_APPLIED_VOLUME applied_volume; // Ignored in MT4. // Struct constructors. - void MFIParams(unsigned int _ma_period, ENUM_APPLIED_VOLUME _av = NULL, int _shift = 0) - : ma_period(_ma_period), applied_volume(_av) { - itype = INDI_MFI; - max_modes = 1; + MFIParams(unsigned int _ma_period = 14, ENUM_APPLIED_VOLUME _av = VOLUME_TICK, int _shift = 0) + : ma_period(_ma_period), applied_volume(_av), IndicatorParams(INDI_MFI, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\MFI"); }; - void MFIParams(MFIParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + MFIParams(MFIParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -53,18 +50,13 @@ struct MFIParams : IndicatorParams { /** * Implements the Money Flow Index indicator. */ -class Indi_MFI : public Indicator { - protected: - MFIParams params; - +class Indi_MFI : public Indicator { public: /** * Class constructor. */ - Indi_MFI(MFIParams &_p) : params(_p.ma_period, _p.applied_volume), Indicator((IndicatorParams)_p) { params = _p; } - Indi_MFI(MFIParams &_p, ENUM_TIMEFRAMES _tf) : params(_p.ma_period, _p.applied_volume), Indicator(INDI_MFI, _tf) { - params = _p; - } + Indi_MFI(MFIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_MFI(ENUM_TIMEFRAMES _tf) : Indicator(INDI_MFI, _tf) {} /** * Calculates the Money Flow Index indicator and returns its value. @@ -74,7 +66,7 @@ class Indi_MFI : public Indicator { * - https://www.mql5.com/en/docs/indicators/imfi */ static double iMFI(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iMFI(_symbol, _tf, _period, _shift); #else // __MQL5__ @@ -83,7 +75,7 @@ class Indi_MFI : public Indicator { } static double iMFI(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, ENUM_APPLIED_VOLUME _applied_volume, // Not used in MT4. - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, Indi_MFI *_obj = NULL) { #ifdef __MQL4__ return ::iMFI(_symbol, _tf, _period, _shift); #else // __MQL5__ @@ -119,23 +111,21 @@ class Indi_MFI : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; #ifdef __MQL4__ - _value = - Indi_MFI::iMFI(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), _shift); + _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), _shift); #else // __MQL5__ - _value = Indi_MFI::iMFI(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - GetAppliedVolume(), _shift, GetPointer(this)); + _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedVolume(), _shift, THIS_PTR); #endif break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetPeriod(), VOLUME_TICK /*]*/, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), + VOLUME_TICK /*]*/, 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -145,29 +135,6 @@ class Indi_MFI : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue((double)NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -184,14 +151,14 @@ class Indi_MFI : public Indicator { * * Period (amount of bars) for calculation of the indicator. */ - unsigned int GetPeriod() { return params.ma_period; } + unsigned int GetPeriod() { return iparams.ma_period; } /** * Get applied volume type. * * Note: Ignored in MT4. */ - ENUM_APPLIED_VOLUME GetAppliedVolume() { return params.applied_volume; } + ENUM_APPLIED_VOLUME GetAppliedVolume() { return iparams.applied_volume; } /* Setters */ @@ -202,7 +169,7 @@ class Indi_MFI : public Indicator { */ void SetPeriod(unsigned int _ma_period) { istate.is_changed = true; - params.ma_period = _ma_period; + iparams.ma_period = _ma_period; } /** @@ -215,6 +182,6 @@ class Indi_MFI : public Indicator { */ void SetAppliedVolume(ENUM_APPLIED_VOLUME _applied_volume) { istate.is_changed = true; - params.applied_volume = _applied_volume; + iparams.applied_volume = _applied_volume; } }; diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index 41dc0804a..0dc8e32e1 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -23,6 +23,7 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" #include "Indi_MA.mqh" // Structs. @@ -31,22 +32,17 @@ struct MassIndexParams : IndicatorParams { int second_period; int sum_period; // Struct constructor. - void MassIndexParams(int _period = 9, int _second_period = 9, int _sum_period = 25, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_MASS_INDEX; - max_modes = 1; + MassIndexParams(int _period = 9, int _second_period = 9, int _sum_period = 25, int _shift = 0) + : IndicatorParams(INDI_MASS_INDEX, 1, TYPE_DOUBLE) { period = _period; second_period = _second_period; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\MI"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; sum_period = _sum_period; - tf = _tf; }; - void MassIndexParams(MassIndexParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + MassIndexParams(MassIndexParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -54,25 +50,19 @@ struct MassIndexParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_MassIndex : public Indicator { - protected: - MassIndexParams params; - +class Indi_MassIndex : public Indicator { public: /** * Class constructor. */ - Indi_MassIndex(MassIndexParams &_params) - : params(_params.period, _params.second_period, _params.sum_period), Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_MassIndex(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_MASS_INDEX, _tf) { params.tf = _tf; }; + Indi_MassIndex(MassIndexParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_MassIndex(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_MASS_INDEX, _tf){}; /** * Built-in version of Mass Index. */ static double iMI(string _symbol, ENUM_TIMEFRAMES _tf, int _period, int _second_period, int _sum_period, - int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + int _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( _symbol, _tf, Util::MakeKey("Indi_MassIndex", _period, _second_period, _sum_period)); return iMIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _second_period, _sum_period, _mode, _shift, @@ -162,16 +152,16 @@ class Indi_MassIndex : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_MassIndex::iMI(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ GetPeriod(), + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _shift); break; default: @@ -182,29 +172,6 @@ class Indi_MassIndex : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -219,17 +186,17 @@ class Indi_MassIndex : public Indicator { /** * Get period. */ - int GetPeriod() { return params.period; } + int GetPeriod() { return iparams.period; } /** * Get second period. */ - int GetSecondPeriod() { return params.second_period; } + int GetSecondPeriod() { return iparams.second_period; } /** * Get sum period. */ - int GetSumPeriod() { return params.sum_period; } + int GetSumPeriod() { return iparams.sum_period; } /* Setters */ @@ -238,7 +205,7 @@ class Indi_MassIndex : public Indicator { */ void SetPeriod(int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -246,7 +213,7 @@ class Indi_MassIndex : public Indicator { */ void SetSecondPeriod(int _second_period) { istate.is_changed = true; - params.second_period = _second_period; + iparams.second_period = _second_period; } /** @@ -254,6 +221,6 @@ class Indi_MassIndex : public Indicator { */ void SetSumPeriod(int _sum_period) { istate.is_changed = true; - params.sum_period = _sum_period; + iparams.sum_period = _sum_period; } }; diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index c93f435d5..7fe181e88 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -45,17 +45,14 @@ struct MomentumParams : IndicatorParams { unsigned int period; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - void MomentumParams(unsigned int _period = 12, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : period(_period), applied_price(_ap) { - itype = INDI_MOMENTUM; - max_modes = 1; + MomentumParams(unsigned int _period = 12, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) + : period(_period), applied_price(_ap), IndicatorParams(INDI_MOMENTUM, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Momentum"); }; - void MomentumParams(MomentumParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + MomentumParams(MomentumParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -63,21 +60,13 @@ struct MomentumParams : IndicatorParams { /** * Implements the Momentum indicator. */ -class Indi_Momentum : public Indicator { - protected: - MomentumParams params; - +class Indi_Momentum : public Indicator { public: /** * Class constructor. */ - Indi_Momentum(MomentumParams &_p) : params(_p.period, _p.applied_price, _p.shift), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_Momentum(MomentumParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.period, _p.applied_price, _p.shift), Indicator(INDI_MOMENTUM, _tf) { - params = _p; - } + Indi_Momentum(MomentumParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_Momentum(ENUM_TIMEFRAMES _tf) : Indicator(INDI_MOMENTUM, _tf) {} /** * Returns the indicator value. @@ -87,7 +76,7 @@ class Indi_Momentum : public Indicator { * - https://www.mql5.com/en/docs/indicators/imomentum */ static double iMomentum(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, ENUM_APPLIED_PRICE _ap, - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iMomentum(_symbol, _tf, _period, _ap, _shift); #else // __MQL5__ @@ -120,10 +109,10 @@ class Indi_Momentum : public Indicator { #endif } - static double iMomentumOnIndicator(Indicator *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, + static double iMomentumOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, int _mode, int _shift = 0) { double _indi_value_buffer[]; - IndicatorDataEntry _entry(_indi.GetParams().GetMaxModes()); + IndicatorDataEntry _entry(_indi.GetModeCount()); _period += 1; @@ -151,29 +140,28 @@ class Indi_Momentum : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { 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(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetPeriod(), GetAppliedPrice(), params.shift + _shift, GetPointer(this)); + _value = Indi_Momentum::iMomentum(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), iparams.shift + _shift, + THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), 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(), Get(CHART_PARAM_SYMBOL), - Get(CHART_PARAM_TF), GetPeriod(), - GetDataSourceMode(), params.shift + _shift); + _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), + GetDataSourceMode(), iparams.shift + _shift); if (iparams.is_draw) { - draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(params.shift + _shift), _value, 1); + draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + _shift), _value, 1); } break; } @@ -182,29 +170,6 @@ class Indi_Momentum : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -221,14 +186,14 @@ class Indi_Momentum : public Indicator { * * Averaging period (bars count) for the calculation of the price change. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get applied price value. * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -239,7 +204,7 @@ class Indi_Momentum : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -252,6 +217,6 @@ class Indi_Momentum : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _ap) { istate.is_changed = true; - params.applied_price = _ap; + iparams.applied_price = _ap; } }; diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index 2ba02b584..fa6568bb6 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -35,30 +35,23 @@ struct OBVParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // MT4 only. ENUM_APPLIED_VOLUME applied_volume; // MT5 only. // Struct constructors. - void OBVParams(int _shift = 0) { - itype = INDI_OBV; - max_modes = 1; + OBVParams(int _shift = 0) : IndicatorParams(INDI_OBV, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\OBV"); applied_price = PRICE_CLOSE; applied_volume = VOLUME_TICK; } - void OBVParams(ENUM_APPLIED_VOLUME _av, int _shift = 0) : applied_volume(_av) { - itype = INDI_OBV; + OBVParams(ENUM_APPLIED_VOLUME _av, int _shift = 0) : applied_volume(_av), IndicatorParams(INDI_OBV, 1, TYPE_DOUBLE) { max_modes = 1; shift = _shift; - SetDataValueType(TYPE_DOUBLE); }; - void OBVParams(ENUM_APPLIED_PRICE _ap, int _shift = 0) : applied_price(_ap) { - itype = INDI_OBV; + OBVParams(ENUM_APPLIED_PRICE _ap, int _shift = 0) : applied_price(_ap), IndicatorParams(INDI_OBV, 1, TYPE_DOUBLE) { max_modes = 1; shift = _shift; - SetDataValueType(TYPE_DOUBLE); }; - void OBVParams(OBVParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + OBVParams(OBVParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -66,31 +59,12 @@ struct OBVParams : IndicatorParams { /** * Implements the On Balance Volume indicator. */ -class Indi_OBV : public Indicator { - protected: - OBVParams params; - +class Indi_OBV : public Indicator { public: /** * Class constructor. */ - Indi_OBV(OBVParams &_p) -#ifdef __MQL4__ - : params(_p.applied_price), -#else - : params(_p.applied_volume), -#endif - Indicator((IndicatorParams)_p) { - } - Indi_OBV(OBVParams &_p, ENUM_TIMEFRAMES _tf) -#ifdef __MQL4__ - : params(_p.applied_price), -#else - : params(_p.applied_volume), -#endif - Indicator(INDI_OBV, _tf) { - params = _p; - } + Indi_OBV(OBVParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} Indi_OBV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_OBV, _tf) {} /** @@ -106,7 +80,7 @@ class Indi_OBV : public Indicator { #else ENUM_APPLIED_VOLUME _applied = VOLUME_TICK, // MT5 only. #endif - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iOBV(_symbol, _tf, _applied, _shift); #else // __MQL5__ @@ -142,23 +116,21 @@ class Indi_OBV : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; #ifdef __MQL4__ - _value = Indi_OBV::iOBV(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetAppliedPrice(), _shift); + _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedPrice(), _shift); #else // __MQL5__ - _value = Indi_OBV::iOBV(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetAppliedVolume(), _shift, GetPointer(this)); + _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedVolume(), _shift, THIS_PTR); #endif break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, + 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -168,29 +140,6 @@ class Indi_OBV : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -207,12 +156,12 @@ class Indi_OBV : public Indicator { * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /** * Get applied volume type (MT5 only). */ - ENUM_APPLIED_VOLUME GetAppliedVolume() { return params.applied_volume; } + ENUM_APPLIED_VOLUME GetAppliedVolume() { return iparams.applied_volume; } /* Setters */ @@ -226,7 +175,7 @@ class Indi_OBV : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } /** @@ -237,6 +186,6 @@ class Indi_OBV : public Indicator { */ void SetAppliedVolume(ENUM_APPLIED_VOLUME _applied_volume) { istate.is_changed = true; - params.applied_volume = _applied_volume; + iparams.applied_volume = _applied_volume; } }; diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index 8acf31092..09f64e4d3 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -38,17 +38,18 @@ struct OsMAParams : IndicatorParams { int signal_period; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - void OsMAParams(int _efp, int _esp, int _sp, ENUM_APPLIED_PRICE _ap, int _shift = 0) - : ema_fast_period(_efp), ema_slow_period(_esp), signal_period(_sp), applied_price(_ap) { - itype = INDI_OSMA; - max_modes = 1; + OsMAParams(int _efp = 12, int _esp = 26, int _sp = 9, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + : ema_fast_period(_efp), + ema_slow_period(_esp), + signal_period(_sp), + applied_price(_ap), + IndicatorParams(INDI_OSMA, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\OsMA"); }; - void OsMAParams(OsMAParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + OsMAParams(OsMAParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -56,23 +57,13 @@ struct OsMAParams : IndicatorParams { /** * Implements the Moving Average of Oscillator indicator. */ -class Indi_OsMA : public Indicator { - protected: - OsMAParams params; - +class Indi_OsMA : public Indicator { public: /** * Class constructor. */ - Indi_OsMA(OsMAParams &_p) - : params(_p.ema_fast_period, _p.ema_slow_period, _p.signal_period, _p.applied_price), - Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_OsMA(OsMAParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.ema_fast_period, _p.ema_slow_period, _p.signal_period, _p.applied_price), Indicator(INDI_OSMA, _tf) { - params = _p; - } + Indi_OsMA(OsMAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_OsMA(ENUM_TIMEFRAMES _tf) : Indicator(INDI_OSMA, _tf) {} /** * Returns the indicator value. @@ -82,7 +73,8 @@ class Indi_OsMA : public Indicator { * - https://www.mql5.com/en/docs/indicators/iosma */ static double iOsMA(string _symbol, ENUM_TIMEFRAMES _tf, int _ema_fast_period, int _ema_slow_period, - int _signal_period, ENUM_APPLIED_PRICE _applied_price, int _shift = 0, Indicator *_obj = NULL) { + int _signal_period, ENUM_APPLIED_PRICE _applied_price, int _shift = 0, + IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iOsMA(_symbol, _tf, _ema_fast_period, _ema_slow_period, _signal_period, _applied_price, _shift); #else // __MQL5__ @@ -119,20 +111,19 @@ class Indi_OsMA : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = - Indi_OsMA::iOsMA(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetEmaFastPeriod(), - GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice(), _shift, GetPointer(this)); + _value = Indi_OsMA::iOsMA(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), + GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), GetEmaSlowPeriod(), - GetSignalPeriod(), GetAppliedPrice() /*]*/, 0, _shift); + _value = + iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), + GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -142,29 +133,6 @@ class Indi_OsMA : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue((double)NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -181,28 +149,28 @@ class Indi_OsMA : public Indicator { * * Averaging period for the calculation of the moving average. */ - int GetEmaFastPeriod() { return params.ema_fast_period; } + int GetEmaFastPeriod() { return iparams.ema_fast_period; } /** * Get slow EMA period value. * * Averaging period for the calculation of the moving average. */ - int GetEmaSlowPeriod() { return params.ema_slow_period; } + int GetEmaSlowPeriod() { return iparams.ema_slow_period; } /** * Get signal period value. * * Averaging period for the calculation of the moving average. */ - int GetSignalPeriod() { return params.signal_period; } + int GetSignalPeriod() { return iparams.signal_period; } /** * Get applied price value. * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -213,7 +181,7 @@ class Indi_OsMA : public Indicator { */ void SetEmaFastPeriod(int _ema_fast_period) { istate.is_changed = true; - params.ema_fast_period = _ema_fast_period; + iparams.ema_fast_period = _ema_fast_period; } /** @@ -223,7 +191,7 @@ class Indi_OsMA : public Indicator { */ void SetEmaSlowPeriod(int _ema_slow_period) { istate.is_changed = true; - params.ema_slow_period = _ema_slow_period; + iparams.ema_slow_period = _ema_slow_period; } /** @@ -233,7 +201,7 @@ class Indi_OsMA : public Indicator { */ void SetSignalPeriod(int _signal_period) { istate.is_changed = true; - params.signal_period = _signal_period; + iparams.signal_period = _signal_period; } /** @@ -246,6 +214,6 @@ class Indi_OsMA : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_Pattern.mqh b/Indicators/Indi_Pattern.mqh index 6ddd9d8f7..9e359f816 100644 --- a/Indicators/Indi_Pattern.mqh +++ b/Indicators/Indi_Pattern.mqh @@ -32,17 +32,12 @@ // Structs. struct IndiPatternParams : IndicatorParams { // Struct constructor. - void IndiPatternParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_PATTERN; - max_modes = 5; - SetDataValueType(TYPE_INT); + IndiPatternParams(int _shift = 0) : IndicatorParams(INDI_PATTERN, 5, TYPE_INT) { SetDataValueRange(IDATA_RANGE_BITWISE); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; }; - void IndiPatternParams(IndiPatternParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + IndiPatternParams(IndiPatternParams& _params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -50,16 +45,13 @@ struct IndiPatternParams : IndicatorParams { /** * Implements Pattern Detector. */ -class Indi_Pattern : public Indicator { - protected: - IndiPatternParams params; - +class Indi_Pattern : public Indicator { public: /** * Class constructor. */ - Indi_Pattern(IndiPatternParams &_params) : params(_params), Indicator((IndicatorParams)_params){}; - Indi_Pattern(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_PATTERN, _tf) { params.tf = _tf; }; + Indi_Pattern(IndiPatternParams& _p, IndicatorBase* _indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_Pattern(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_PATTERN, _tf) { iparams.tf = _tf; }; /** * Returns the indicator's struct value. @@ -67,7 +59,7 @@ class Indi_Pattern : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.GetMaxModes()); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { @@ -78,10 +70,10 @@ class Indi_Pattern : public Indicator { int i; int _value = WRONG_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: // In this mode, price is fetched from chart. - for (i = 0; i < params.GetMaxModes(); ++i) { + for (i = 0; i < iparams.GetMaxModes(); ++i) { _ohlcs[i] = Chart::GetOHLC(_shift + i); if (!_ohlcs[i].IsValid()) { // Return empty entry on invalid candles. @@ -93,7 +85,7 @@ class Indi_Pattern : public 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 (GetDataSource() == NULL) { + if (indi_src == NULL) { GetLogger().Error( "In order use custom indicator as a source, you need to select one using SetIndicatorData() method, " "which is a part of PatternParams structure.", @@ -106,11 +98,11 @@ class Indi_Pattern : public Indicator { return _value; } - for (i = 0; i < params.GetMaxModes(); ++i) { - _ohlcs[i].open = GetDataSource().GetValue(_shift + i, PRICE_OPEN); - _ohlcs[i].high = GetDataSource().GetValue(_shift + i, PRICE_HIGH); - _ohlcs[i].low = GetDataSource().GetValue(_shift + i, PRICE_LOW); - _ohlcs[i].close = GetDataSource().GetValue(_shift + i, PRICE_CLOSE); + for (i = 0; i < iparams.GetMaxModes(); ++i) { + _ohlcs[i].open = indi_src.GetValue(_shift + i, PRICE_OPEN); + _ohlcs[i].high = indi_src.GetValue(_shift + i, PRICE_HIGH); + _ohlcs[i].low = indi_src.GetValue(_shift + i, PRICE_LOW); + _ohlcs[i].close = indi_src.GetValue(_shift + i, PRICE_CLOSE); if (!_ohlcs[i].IsValid()) { // Return empty entry on invalid candles. return _entry; @@ -123,22 +115,26 @@ class Indi_Pattern : public Indicator { PatternEntry pattern(_ohlcs); - for (int _mode = 0; _mode < params.GetMaxModes(); _mode++) { + for (int _mode = 0; _mode < iparams.GetMaxModes(); _mode++) { _entry.values[_mode] = pattern[_mode + 1]; } _entry.SetFlag(INDI_ENTRY_FLAG_IS_BITWISE, true); - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, _ohlcs[0].IsValid() && _entry.values[1] > 0); - + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry) && _ohlcs[0].IsValid()); if (_entry.IsValid()) { istate.is_ready = true; - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } return _entry; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry& _entry) { return _entry.values[1] > 0; } + /** * Returns the indicator's entry value. */ diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index a0830313b..392e24bde 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -30,18 +30,13 @@ struct IndiPivotParams : IndicatorParams { ENUM_PP_TYPE method; // Pivot point calculation method. // Struct constructor. - void IndiPivotParams(ENUM_PP_TYPE _method = PP_CLASSIC, int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_PIVOT; - max_modes = 9; + IndiPivotParams(ENUM_PP_TYPE _method = PP_CLASSIC, int _shift = 0) : IndicatorParams(INDI_PIVOT, 9, TYPE_FLOAT) { method = _method; - SetDataValueType(TYPE_FLOAT); SetDataValueRange(IDATA_RANGE_MIXED); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; }; - void IndiPivotParams(IndiPivotParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + IndiPivotParams(IndiPivotParams& _params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -49,16 +44,13 @@ struct IndiPivotParams : IndicatorParams { /** * Implements Pivot Detector. */ -class Indi_Pivot : public Indicator { - protected: - IndiPivotParams params; - +class Indi_Pivot : public Indicator { public: /** * Class constructor. */ - Indi_Pivot(IndiPivotParams &_params) : params(_params), Indicator((IndicatorParams)_params){}; - Indi_Pivot(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_PIVOT, _tf) { params.tf = _tf; }; + Indi_Pivot(IndiPivotParams& _p, IndicatorBase* _indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_Pivot(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_PIVOT, _tf) { iparams.tf = _tf; }; /** * Returns the indicator's struct value. @@ -66,7 +58,7 @@ class Indi_Pivot : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { @@ -76,7 +68,7 @@ class Indi_Pivot : public Indicator { BarOHLC _ohlc; int _value = WRONG_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: // In this mode, price is fetched from chart. _ohlc = Chart::GetOHLC(_shift); @@ -98,10 +90,10 @@ class Indi_Pivot : public Indicator { return _value; } - _ohlc.open = GetDataSource().GetValue(_shift, PRICE_OPEN); - _ohlc.high = GetDataSource().GetValue(_shift, PRICE_HIGH); - _ohlc.low = GetDataSource().GetValue(_shift, PRICE_LOW); - _ohlc.close = GetDataSource().GetValue(_shift, PRICE_CLOSE); + _ohlc.open = indi_src.GetValue(_shift, PRICE_OPEN); + _ohlc.high = indi_src.GetValue(_shift, PRICE_HIGH); + _ohlc.low = indi_src.GetValue(_shift, PRICE_LOW); + _ohlc.close = indi_src.GetValue(_shift, PRICE_CLOSE); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -111,24 +103,27 @@ class Indi_Pivot : public Indicator { _entry.values[3].vflt, _entry.values[4].vflt, _entry.values[5].vflt, _entry.values[6].vflt, _entry.values[7].vflt, _entry.values[8].vflt); - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, true); - - istate.is_ready = true; - + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); + istate.is_ready = true; } } return _entry; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry& _entry) { return true; } // @todo + /** * Returns the indicator's entry value. */ MqlParam GetEntryValue(int _shift = 0, int _mode = 0) { - MqlParam _param = {TYPE_INT}; - _param.integer_value = GetEntry(_shift).GetValue(_mode); + MqlParam _param = {TYPE_FLOAT}; + _param.double_value = GetEntry(_shift).GetValue(_mode); return _param; } @@ -137,7 +132,7 @@ class Indi_Pivot : public Indicator { /** * Get pivot point calculation method. */ - ENUM_PP_TYPE GetMethod() { return params.method; } + ENUM_PP_TYPE GetMethod() { return iparams.method; } /* Setters */ @@ -146,7 +141,7 @@ class Indi_Pivot : public Indicator { */ void SetMethod(ENUM_PP_TYPE _method) { istate.is_changed = true; - params.method = _method; + iparams.method = _method; } /** diff --git a/Indicators/Indi_Price.mqh b/Indicators/Indi_Price.mqh index 659669c41..e63781147 100644 --- a/Indicators/Indi_Price.mqh +++ b/Indicators/Indi_Price.mqh @@ -38,15 +38,12 @@ enum ENUM_INDI_PRICE_MODE { // Structs. struct PriceIndiParams : IndicatorParams { - ENUM_APPLIED_PRICE applied_price; - // Struct constructor. - void PriceIndiParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_APPLIED_PRICE _ap = PRICE_MEDIAN) - : applied_price(_ap) { - itype = itype == INDI_NONE ? INDI_PRICE : itype; - max_modes = FINAL_INDI_PRICE_MODE; - SetDataValueType(TYPE_DOUBLE); + PriceIndiParams(int _shift = 0) : IndicatorParams(INDI_PRICE, FINAL_INDI_PRICE_MODE, TYPE_DOUBLE) { SetShift(_shift); + }; + PriceIndiParams(PriceIndiParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -54,24 +51,19 @@ struct PriceIndiParams : IndicatorParams { /** * Price Indicator. */ -class Indi_Price : public Indicator { - protected: - PriceIndiParams params; - +class Indi_Price : public Indicator { public: /** * Class constructor. */ - Indi_Price(PriceIndiParams &_p) : Indicator((IndicatorParams)_p) { params = _p; }; - Indi_Price(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_APPLIED_PRICE _ap = PRICE_MEDIAN) - : params(_shift, _tf, _ap), Indicator(INDI_PRICE, _tf){}; + Indi_Price(PriceIndiParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_Price(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_PRICE, _tf){}; /** * Returns the indicator value. */ - static double iPrice(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - Indi_Price *_obj = NULL) { - ENUM_APPLIED_PRICE _ap = _obj == NULL ? PRICE_MEDIAN : _obj.params.applied_price; + static double iPrice(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, + ENUM_APPLIED_PRICE _ap = PRICE_MEDIAN, int _shift = 0, Indi_Price *_obj = NULL) { return ChartStatic::iPrice(_ap, _symbol, _tf, _shift); } @@ -83,9 +75,8 @@ class Indi_Price : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_APPLIED_PRICE _ap, int _shift = 0) { - double _value = - ChartStatic::iPrice(_ap, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), _shift); + virtual double GetValue(int _mode = PRICE_TYPICAL, int _shift = 0) { + double _value = ChartStatic::iPrice((ENUM_APPLIED_PRICE)_mode, GetSymbol(), GetTf(), _shift); istate.is_ready = true; istate.is_changed = false; return _value; @@ -97,7 +88,7 @@ class Indi_Price : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { @@ -107,7 +98,7 @@ class Indi_Price : public Indicator { _entry.values[INDI_PRICE_MODE_CLOSE] = GetValue(PRICE_CLOSE, _shift); _entry.values[INDI_PRICE_MODE_LOW] = GetValue(PRICE_LOW, _shift); _entry.AddFlags(INDI_ENTRY_FLAG_IS_VALID); - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } return _entry; @@ -125,18 +116,18 @@ class Indi_Price : public Indicator { /** * Returns already cached version of Indi_Price for a given parameters. */ - static Indi_Price *GetCached(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, - ENUM_APPLIED_PRICE _applied_price = PRICE_TYPICAL, unsigned int _period = 0) { + static Indi_Price *GetCached(string _symbol, ENUM_TIMEFRAMES _tf, int _shift) { String _cache_key; - _cache_key.Add((int)_shift); + _cache_key.Add(_symbol); _cache_key.Add((int)_tf); - _cache_key.Add((int)_period); - _cache_key.Add((int)_applied_price); + _cache_key.Add(_shift); string _key = _cache_key.ToString(); Indi_Price *_indi_price; if (!Objects::TryGet(_key, _indi_price)) { - PriceIndiParams _indi_price_params(_shift, _tf, _applied_price); + 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); } return _indi_price; } diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index b0c6d950e..5d9e497d6 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -28,19 +28,15 @@ struct PriceChannelParams : IndicatorParams { unsigned int period; // Struct constructor. - void PriceChannelParams(unsigned int _period = 22, int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_PRICE_CHANNEL; - max_modes = 3; + PriceChannelParams(unsigned int _period = 22, int _shift = 0) : IndicatorParams(INDI_PRICE_CHANNEL, 3, TYPE_DOUBLE) { period = _period; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Price_Channel"); SetDataSourceType(IDATA_ICUSTOM); shift = _shift; - tf = _tf; }; - void PriceChannelParams(PriceChannelParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + PriceChannelParams(PriceChannelParams& _params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -48,29 +44,25 @@ struct PriceChannelParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_PriceChannel : public Indicator { - protected: - PriceChannelParams params; - +class Indi_PriceChannel : public Indicator { public: /** * Class constructor. */ - Indi_PriceChannel(PriceChannelParams &_params) : params(_params.period), Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_PriceChannel(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_PRICE_CHANNEL, _tf) { params.tf = _tf; }; + Indi_PriceChannel(PriceChannelParams& _p, IndicatorBase* _indi_src = NULL) + : Indicator(_p, _indi_src){}; + Indi_PriceChannel(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_PRICE_CHANNEL, _tf){}; /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -80,29 +72,6 @@ class Indi_PriceChannel : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -117,7 +86,7 @@ class Indi_PriceChannel : public Indicator { /** * Get period. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /* Setters */ @@ -126,6 +95,6 @@ class Indi_PriceChannel : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } }; diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index 1173d01eb..ea078ffcb 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -32,70 +32,66 @@ struct PriceFeederIndiParams : IndicatorParams { /** * Struct constructor. */ - void PriceFeederIndiParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_PRICE_FEEDER; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); - shift = _shift; - tf = _tf; - } + PriceFeederIndiParams(int _shift = 0) : IndicatorParams(INDI_PRICE_FEEDER, 1, TYPE_DOUBLE) { shift = _shift; } /** * Struct constructor. * * @todo Use more modes (full OHCL). */ - void PriceFeederIndiParams(const double& _price_data[], int _total = 0) { - itype = INDI_PRICE_FEEDER; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); + PriceFeederIndiParams(const double& _price_data[], int _total = 0) + : IndicatorParams(INDI_PRICE_FEEDER, 1, TYPE_DOUBLE) { tf = PERIOD_CURRENT; ArrayCopy(price_data, _price_data, 0, 0, _total == 0 ? WHOLE_ARRAY : _total); }; + PriceFeederIndiParams(PriceFeederIndiParams& _params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; + tf = _tf; + }; }; /** * Price Indicator. */ -class Indi_PriceFeeder : public Indicator { - protected: - PriceFeederIndiParams params; - +class Indi_PriceFeeder : public Indicator { public: /** * Class constructor. */ - Indi_PriceFeeder(PriceFeederIndiParams& _p) : Indicator((IndicatorParams)_p) { params = _p; }; - Indi_PriceFeeder(const double& _price_data[], int _total = 0) - : params(_price_data, _total), Indicator(INDI_PRICE_FEEDER){}; + Indi_PriceFeeder(PriceFeederIndiParams& _p, IndicatorBase* _indi_src = NULL) + : Indicator(_p, _indi_src){}; + Indi_PriceFeeder(const double& _price_data[], int _total = 0) : Indicator(INDI_PRICE_FEEDER) { + ArrayCopy(iparams.price_data, _price_data); + }; + Indi_PriceFeeder(ENUM_TIMEFRAMES _tf) : Indicator(INDI_PRICE_FEEDER, _tf) {} - void SetPrices(const double& _price_data[], int _total = 0) { params = PriceFeederIndiParams(_price_data, _total); } + void SetPrices(const double& _price_data[], int _total = 0) { iparams = PriceFeederIndiParams(_price_data, _total); } /** * Checks whether indicator has a valid value for a given shift. */ - virtual bool HasValidEntry(int _shift = 0) { return _shift >= 0 && _shift < ArraySize(params.price_data); } + virtual bool HasValidEntry(int _shift = 0) { return _shift >= 0 && _shift < ArraySize(iparams.price_data); } /** * Returns the indicator's value. */ - double GetValue(ENUM_APPLIED_PRICE _ap, int _shift = 0) { - int data_size = ArraySize(params.price_data); + virtual double GetValue(ENUM_APPLIED_PRICE _ap, int _shift = 0) { + int data_size = ArraySize(iparams.price_data); if (_shift >= data_size || _shift < 0) return DBL_MIN; - double _value = params.price_data[data_size - _shift - 1]; + double _value = iparams.price_data[data_size - _shift - 1]; istate.is_ready = true; istate.is_changed = false; return _value; } void OnTick() { - Indicator::OnTick(); + Indicator::OnTick(); if (iparams.is_draw) { IndicatorDataEntry _entry = GetEntry(0); - for (int i = 0; i < (int)iparams.max_modes; ++i) { + for (int i = 0; i < (int)iparams.GetMaxModes(); ++i) { draw.DrawLineTo(GetName() + "_" + IntegerToString(i), GetBarTime(0), _entry.values[i].GetDbl()); } } @@ -107,14 +103,14 @@ class Indi_PriceFeeder : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { _entry.timestamp = GetBarTime(_shift); _entry.values[0].Set(GetValue(PRICE_OPEN, _shift)); _entry.AddFlags(INDI_ENTRY_FLAG_IS_VALID); - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } return _entry; diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index ebb585331..b8c9efcac 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -23,25 +23,21 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" // Structs. struct PriceVolumeTrendParams : IndicatorParams { ENUM_APPLIED_VOLUME applied_volume; // Struct constructor. - void PriceVolumeTrendParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + PriceVolumeTrendParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0) + : IndicatorParams(INDI_PRICE_VOLUME_TREND, 1, TYPE_DOUBLE) { applied_volume = _applied_volume; - itype = INDI_PRICE_VOLUME_TREND; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\PVT"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; }; - void PriceVolumeTrendParams(PriceVolumeTrendParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + PriceVolumeTrendParams(PriceVolumeTrendParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -49,27 +45,20 @@ struct PriceVolumeTrendParams : IndicatorParams { /** * Implements the Price Volume Trend indicator. */ -class Indi_PriceVolumeTrend : public Indicator { - protected: - PriceVolumeTrendParams params; - +class Indi_PriceVolumeTrend : public Indicator { public: /** * Class constructor. */ - Indi_PriceVolumeTrend(PriceVolumeTrendParams &_params) - : params(_params.applied_volume), Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_PriceVolumeTrend(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_PRICE_VOLUME_TREND, _tf) { - params.tf = _tf; - }; + Indi_PriceVolumeTrend(PriceVolumeTrendParams &_p, IndicatorBase *_indi_src = NULL) + : Indicator(_p, _indi_src){}; + Indi_PriceVolumeTrend(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_PRICE_VOLUME_TREND, _tf){}; /** * Built-in version of Price Volume Trend. */ static double iPVT(string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_PriceVolumeTrend", (int)_av)); return iPVTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _shift, _cache); } @@ -131,16 +120,16 @@ class Indi_PriceVolumeTrend : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_PriceVolumeTrend::iPVT(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetAppliedVolume() /*]*/, 0, _shift); break; default: @@ -151,29 +140,6 @@ class Indi_PriceVolumeTrend : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -188,7 +154,7 @@ class Indi_PriceVolumeTrend : public Indicator { /** * Get applied volume. */ - ENUM_APPLIED_VOLUME GetAppliedVolume() { return params.applied_volume; } + ENUM_APPLIED_VOLUME GetAppliedVolume() { return iparams.applied_volume; } /* Setters */ @@ -197,6 +163,6 @@ class Indi_PriceVolumeTrend : public Indicator { */ void SetPeriod(ENUM_APPLIED_VOLUME _applied_volume) { istate.is_changed = true; - params.applied_volume = _applied_volume; + iparams.applied_volume = _applied_volume; } }; diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index 48eece0ae..800b9ef84 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -30,19 +30,15 @@ struct RSParams : IndicatorParams { ENUM_APPLIED_VOLUME applied_volume; // Struct constructor. - void RSParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + RSParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0) + : IndicatorParams(INDI_RS, 2, TYPE_DOUBLE) { applied_volume = _applied_volume; - itype = INDI_RS; - max_modes = 2; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetDataSourceType(IDATA_MATH); shift = _shift; - tf = _tf; }; - void RSParams(RSParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + RSParams(RSParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -50,35 +46,31 @@ struct RSParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_RS : public Indicator { - protected: - RSParams params; - Ref iprice; +class Indi_RS : public Indicator { DictStruct> imath; public: /** * Class constructor. */ - Indi_RS(RSParams &_params) : params(_params), Indicator((IndicatorParams)_params) { Init(); }; - Indi_RS(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_RS, _tf) { - params.tf = _tf; - Init(); - }; + Indi_RS(RSParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) { Init(); }; + Indi_RS(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_RS, _tf) { Init(); }; void Init() { - if (params.GetDataSourceType() == IDATA_MATH) { - PriceIndiParams _iprice_params(); - iprice = new Indi_Price(_iprice_params); - - MathParams _imath0_params(MATH_OP_SUB, PRICE_CLOSE, 0, PRICE_CLOSE, 1); - _imath0_params.SetDataSource(iprice.Ptr(), false); - Ref _imath0 = new Indi_Math(_imath0_params); - - MathParams _imath1_params(MATH_OP_SUB, PRICE_CLOSE, 1, PRICE_CLOSE, 0); - _imath1_params.SetDataSource(iprice.Ptr(), false); - Ref _imath1 = new Indi_Math(_imath1_params); - + if (iparams.GetDataSourceType() == IDATA_MATH) { + 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); + + MathParams _imath0_p(MATH_OP_SUB, PRICE_CLOSE, 0, PRICE_CLOSE, 1); + MathParams _imath1_p(MATH_OP_SUB, PRICE_CLOSE, 1, PRICE_CLOSE, 0); + _imath0_p.SetTf(GetTf()); + _imath1_p.SetTf(GetTf()); + Ref _imath0 = new Indi_Math(_imath0_p); + Ref _imath1 = new Indi_Math(_imath1_p); + _imath0.Ptr().SetDataSource(_iprice, false, 0); + _imath1.Ptr().SetDataSource(_iprice, false, 0); imath.Set(0, _imath0); imath.Set(1, _imath1); } @@ -87,10 +79,10 @@ class Indi_RS : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_MATH: _value = imath[_mode].Ptr().GetValue(); break; @@ -102,29 +94,6 @@ class Indi_RS : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, true); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -134,12 +103,17 @@ class Indi_RS : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return true; } + /* Getters */ /** * Get applied volume. */ - ENUM_APPLIED_VOLUME GetAppliedVolume() { return params.applied_volume; } + ENUM_APPLIED_VOLUME GetAppliedVolume() { return iparams.applied_volume; } /* Setters */ @@ -148,6 +122,6 @@ class Indi_RS : public Indicator { */ void SetAppliedVolume(ENUM_APPLIED_VOLUME _applied_volume) { istate.is_changed = true; - params.applied_volume = _applied_volume; + iparams.applied_volume = _applied_volume; } }; diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index ce168bf34..84453e216 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -43,29 +43,28 @@ double iRSIOnArray(double &_arr[], int _total, int _period, int _shift) { // Structs. struct RSIParams : IndicatorParams { - unsigned int period; + protected: + int period; ENUM_APPLIED_PRICE applied_price; - // Struct constructors. - void RSIParams(const RSIParams &r) { - period = r.period; - applied_price = r.applied_price; - custom_indi_name = r.custom_indi_name; - } - void RSIParams(unsigned int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : period(_period), applied_price(_ap) { - itype = INDI_RSI; - max_modes = 1; + public: + RSIParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) + : applied_price(_ap), IndicatorParams(INDI_RSI, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\RSI"); + SetPeriod(_period); }; - void RSIParams(RSIParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + RSIParams(RSIParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; - void RSIParams(ENUM_TIMEFRAMES _tf) : period(12), applied_price(PRICE_WEIGHTED) { tf = _tf; } + // Getters. + ENUM_APPLIED_PRICE GetAppliedPrice() { return applied_price; } + int GetPeriod() { return period; } + // Setters. + void SetPeriod(int _period) { period = _period; } + void SetAppliedPrice(ENUM_APPLIED_PRICE _ap) { applied_price = _ap; } // Serializers. SERIALIZER_EMPTY_STUB; SerializerNodeType Serialize(Serializer &s) { @@ -87,19 +86,15 @@ struct RSIGainLossData { /** * Implements the Relative Strength Index indicator. */ -class Indi_RSI : public Indicator { - public: - RSIParams params; +class Indi_RSI : public Indicator { DictStruct aux_data; + public: /** * Class constructor. */ - Indi_RSI(const RSIParams &_params) : params(_params), Indicator((IndicatorParams)_params) { params = _params; } - Indi_RSI(const RSIParams &_params, ENUM_TIMEFRAMES _tf) : params(_params), Indicator(INDI_RSI, _tf) { - // @fixme - params.tf = _tf; - } + Indi_RSI(RSIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_RSI(ENUM_TIMEFRAMES _tf) : Indicator(INDI_RSI, _tf) {} /** * Returns the indicator value. @@ -109,7 +104,7 @@ class Indi_RSI : public Indicator { * - https://www.mql5.com/en/docs/indicators/irsi */ static double iRSI(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _period = 14, - ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, Indicator *_obj = NULL) { + ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iRSI(_symbol, _tf, _period, _applied_price, _shift); #else // __MQL5__ @@ -145,9 +140,11 @@ class Indi_RSI : public Indicator { /** * Calculates non-SMMA version of RSI on another indicator (uses iRSIOnArray). */ - static double iRSIOnArrayOnIndicator(Indicator *_indi, string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, - unsigned int _period = 14, ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, - int _shift = 0, Indi_RSI *_obj = NULL) { + template + static double iRSIOnArrayOnIndicator(IndicatorBase *_indi, string _symbol = NULL, + ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _period = 14, + ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, + Indi_RSI *_obj = NULL) { int i; double indi_values[]; ArrayResize(indi_values, _period); @@ -178,7 +175,7 @@ class Indi_RSI : public Indicator { * RSI values. To exactly replicate our RSI numbers, a formula will need at * least 250 data points." */ - static double iRSIOnIndicator(Indicator *_indi, Indi_RSI *_obj, string _symbol = NULL, + static double iRSIOnIndicator(IndicatorBase *_indi, Indi_RSI *_obj, string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _period = 14, ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0) { long _bar_time_curr = _obj.GetBarTime(_shift); @@ -187,8 +184,6 @@ class Indi_RSI : public Indicator { // Return empty value on invalid bar time. return EMPTY_VALUE; } - // Looks like MT uses specified period as start of the SMMA calculations. - _obj.FeedHistoryEntries(_period); int i; double indi_values[]; @@ -200,7 +195,7 @@ class Indi_RSI : public Indicator { RSIGainLossData last_data, new_data; unsigned int data_position; double diff; - int _mode = _obj.GetParams().indi_mode; + int _mode = _obj.GetDataSourceMode(); if (!_obj.aux_data.KeyExists(_bar_time_prev, data_position)) { // No previous SMMA-based average gain and loss. Calculating SMA-based ones. @@ -309,30 +304,28 @@ class Indi_RSI : public Indicator { * extern ENUM_APPLIED_PRICE applied_price; // Required only for MQL4. * extern int shift; * - * Also, remember to use params.SetCustomIndicatorName(name) method to choose - * indicator name, e.g.,: params.SetCustomIndicatorName("Examples\\RSI"); + * Also, remember to use iparams.SetCustomIndicatorName(name) method to choose + * indicator name, e.g.,: iparams.SetCustomIndicatorName("Examples\\RSI"); * * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_RSI::iRSI(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - GetAppliedPrice(), _shift, GetPointer(this)); + _value = Indi_RSI::iRSI(GetSymbol(), 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, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.custom_indi_name, /* [ */ GetPeriod(), GetAppliedPrice() /* ] */, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ iparams.GetPeriod(), + iparams.GetAppliedPrice() /* ] */, 0, _shift); break; case IDATA_INDICATOR: - _value = - Indi_RSI::iRSIOnIndicator(GetDataSource(), GetPointer(this), Get(CHART_PARAM_SYMBOL), - Get(CHART_PARAM_TF), GetPeriod(), GetAppliedPrice(), _shift); + _value = Indi_RSI::iRSIOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), iparams.GetPeriod(), + iparams.GetAppliedPrice(), _shift); break; } istate.is_ready = GetLastError() == ERR_NO_ERROR; @@ -341,30 +334,6 @@ class Indi_RSI : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_DOUBLE, iparams.GetDataValueType() == TYPE_DOUBLE); - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -374,68 +343,33 @@ class Indi_RSI : public Indicator { return _param; } - /* Getters */ - - /** - * Get indicator params. - */ - RSIParams GetParams() { return params; } - - /** - * Get period value. - */ - unsigned int GetPeriod() { return params.period; } - - /** - * Get applied price value. - */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } - - /* Setters */ - - /** - * Set period value. - */ - void SetPeriod(unsigned int _period) { - istate.is_changed = true; - params.period = _period; - } - - /** - * Set applied price value. - */ - void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { - istate.is_changed = true; - params.applied_price = _applied_price; - } - /** * Provides built-in indicators whose can be used as data source. */ - virtual Indicator *FetchDataSource(ENUM_INDICATOR_TYPE _id) { + virtual IndicatorBase *FetchDataSource(ENUM_INDICATOR_TYPE _id) { if (_id == INDI_BANDS) { - BandsParams bands_params(); + BandsParams bands_params; return new Indi_Bands(bands_params); } else if (_id == INDI_CCI) { - CCIParams cci_params(); + CCIParams cci_params; return new Indi_CCI(cci_params); } else if (_id == INDI_ENVELOPES) { - EnvelopesParams env_params(); + EnvelopesParams env_params; return new Indi_Envelopes(env_params); } else if (_id == INDI_MOMENTUM) { - MomentumParams mom_params(); + MomentumParams mom_params; return new Indi_Momentum(mom_params); } else if (_id == INDI_MA) { - MAParams ma_params(); + MAParams ma_params; return new Indi_MA(ma_params); } else if (_id == INDI_RSI) { - RSIParams _rsi_params(); + RSIParams _rsi_params; return new Indi_RSI(_rsi_params); } else if (_id == INDI_STDDEV) { - StdDevParams stddev_params(); + StdDevParams stddev_params; return new Indi_StdDev(stddev_params); } - return Indicator::FetchDataSource(_id); + return IndicatorBase::FetchDataSource(_id); } }; diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index 3052880cd..419385ddf 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -34,16 +34,14 @@ double iRVI(string _symbol, int _tf, int _period, int _mode, int _shift) { struct RVIParams : IndicatorParams { unsigned int period; // Struct constructors. - void RVIParams(unsigned int _period, int _shift = 0) : period(_period) { - itype = INDI_RVI; - max_modes = FINAL_SIGNAL_LINE_ENTRY; + RVIParams(unsigned int _period = 10, int _shift = 0) + : period(_period), IndicatorParams(INDI_RVI, FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\RVI"); }; - void RVIParams(RVIParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + RVIParams(RVIParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -51,16 +49,13 @@ struct RVIParams : IndicatorParams { /** * Implements the Relative Vigor Index indicator. */ -class Indi_RVI : public Indicator { - protected: - RVIParams params; - +class Indi_RVI : public Indicator { public: /** * Class constructor. */ - Indi_RVI(const RVIParams &_p) : params(_p.period), Indicator((IndicatorParams)_p) { params = _p; } - Indi_RVI(const RVIParams &_p, ENUM_TIMEFRAMES _tf) : params(_p.period), Indicator(INDI_RVI, _tf) { params = _p; } + Indi_RVI(const RVIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_RVI(ENUM_TIMEFRAMES _tf) : Indicator(INDI_RVI, _tf) {} /** * Returns the indicator value. @@ -72,7 +67,7 @@ class Indi_RVI : public Indicator { static double iRVI( string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _period = 10, ENUM_SIGNAL_LINE _mode = LINE_MAIN, // (MT4/MT5): 0 - MODE_MAIN/MAIN_LINE, 1 - MODE_SIGNAL/SIGNAL_LINE - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iRVI(_symbol, _tf, _period, _mode, _shift); #else // __MQL5__ @@ -108,18 +103,17 @@ class Indi_RVI : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_SIGNAL_LINE _mode = LINE_MAIN, int _shift = 0) { + virtual double GetValue(int _mode = LINE_MAIN, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_RVI::iRVI(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - _mode, _shift, GetPointer(this)); + _value = Indi_RVI::iRVI(GetSymbol(), GetTf(), GetPeriod(), (ENUM_SIGNAL_LINE)_mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -129,29 +123,6 @@ class Indi_RVI : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue((ENUM_SIGNAL_LINE)_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -161,12 +132,19 @@ class Indi_RVI : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE); + } + /* Getters */ /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /* Setters */ @@ -175,6 +153,6 @@ class Indi_RVI : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } }; diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index 264c81fb4..95f6208b3 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -23,27 +23,23 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.price.h" // Structs. struct RateOfChangeParams : IndicatorParams { unsigned int period; ENUM_APPLIED_PRICE applied_price; // Struct constructor. - void RateOfChangeParams(int _period = 12, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + RateOfChangeParams(int _period = 12, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + : IndicatorParams(INDI_RATE_OF_CHANGE, 1, TYPE_DOUBLE) { applied_price = _ap; - itype = INDI_RATE_OF_CHANGE; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ROC"); - SetDataSourceType(IDATA_BUILTIN); period = _period; shift = _shift; - tf = _tf; }; - void RateOfChangeParams(RateOfChangeParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + RateOfChangeParams(RateOfChangeParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -51,24 +47,20 @@ struct RateOfChangeParams : IndicatorParams { /** * Implements the Rate of Change indicator. */ -class Indi_RateOfChange : public Indicator { - protected: - RateOfChangeParams params; - +class Indi_RateOfChange : public Indicator { public: /** * Class constructor. */ - Indi_RateOfChange(RateOfChangeParams &_params) : params(_params.period), Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_RateOfChange(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_RATE_OF_CHANGE, _tf) { params.tf = _tf; }; + Indi_RateOfChange(RateOfChangeParams &_p, IndicatorBase *_indi_src = NULL) + : Indicator(_p, _indi_src){}; + Indi_RateOfChange(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_RATE_OF_CHANGE, _tf){}; /** * Built-in version of Rate of Change. */ static double iROC(string _symbol, ENUM_TIMEFRAMES _tf, int _period, ENUM_APPLIED_PRICE _ap, int _mode = 0, - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_symbol, _tf, _ap, Util::MakeKey("Indi_RateOfChange", _period, (int)_ap)); return iROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _mode, _shift, _cache); @@ -117,16 +109,16 @@ class Indi_RateOfChange : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_RateOfChange::iROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _shift); break; default: @@ -137,29 +129,6 @@ class Indi_RateOfChange : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -174,12 +143,12 @@ class Indi_RateOfChange : public Indicator { /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /** * Get period. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /* Setters */ @@ -188,7 +157,7 @@ class Indi_RateOfChange : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } /** @@ -196,6 +165,6 @@ class Indi_RateOfChange : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } }; diff --git a/Indicators/Indi_SAR.mqh b/Indicators/Indi_SAR.mqh index 71ea42780..8ee26d8c2 100644 --- a/Indicators/Indi_SAR.mqh +++ b/Indicators/Indi_SAR.mqh @@ -35,16 +35,14 @@ struct SARParams : IndicatorParams { double step; double max; // Struct constructors. - void SARParams(double _step = 0.02, double _max = 0.2, int _shift = 0) : step(_step), max(_max) { - itype = INDI_SAR; - max_modes = 1; + SARParams(double _step = 0.02, double _max = 0.2, int _shift = 0) + : step(_step), max(_max), IndicatorParams(INDI_SAR, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_PRICE); // @fixit It draws single dot for each bar! SetCustomIndicatorName("Examples\\ParabolicSAR"); }; - void SARParams(SARParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + SARParams(SARParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -52,16 +50,13 @@ struct SARParams : IndicatorParams { /** * Implements the Parabolic Stop and Reverse system indicator. */ -class Indi_SAR : public Indicator { - protected: - SARParams params; - +class Indi_SAR : public Indicator { public: /** * Class constructor. */ - Indi_SAR(SARParams &_p) : params(_p.step, _p.max), Indicator((IndicatorParams)_p) { params = _p; } - Indi_SAR(SARParams &_p, ENUM_TIMEFRAMES _tf) : params(_p.step, _p.max), Indicator(INDI_SAR, _tf) { params = _p; } + Indi_SAR(SARParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_SAR(ENUM_TIMEFRAMES _tf) : Indicator(INDI_SAR, _tf) {} /** * Returns the indicator value. @@ -71,7 +66,7 @@ class Indi_SAR : public Indicator { * - https://www.mql5.com/en/docs/indicators/isar */ static double iSAR(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, double _step = 0.02, - double _max = 0.2, int _shift = 0, Indicator *_obj = NULL) { + double _max = 0.2, int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iSAR(_symbol, _tf, _step, _max, _shift); #else // __MQL5__ @@ -107,18 +102,17 @@ class Indi_SAR : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_SAR::iSAR(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetStep(), - GetMax(), _shift, GetPointer(this)); + _value = Indi_SAR::iSAR(GetSymbol(), GetTf(), GetStep(), GetMax(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetStep(), GetMax() /*]*/, _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetStep(), + GetMax() /*]*/, _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -128,29 +122,6 @@ class Indi_SAR : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -165,12 +136,12 @@ class Indi_SAR : public Indicator { /** * Get step of price increment. */ - double GetStep() { return params.step; } + double GetStep() { return iparams.step; } /** * Get the maximum step. */ - double GetMax() { return params.max; } + double GetMax() { return iparams.max; } /* Setters */ @@ -179,7 +150,7 @@ class Indi_SAR : public Indicator { */ void SetStep(double _step) { istate.is_changed = true; - params.step = _step; + iparams.step = _step; } /** @@ -187,6 +158,6 @@ class Indi_SAR : public Indicator { */ void SetMax(double _max) { istate.is_changed = true; - params.max = _max; + iparams.max = _max; } }; diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index b0d0cb1c6..6ab6024fc 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -50,18 +50,19 @@ struct StdDevParams : IndicatorParams { ENUM_MA_METHOD ma_method; ENUM_APPLIED_PRICE applied_price; // Struct constructors. - void StdDevParams(int _ma_period = 13, int _ma_shift = 10, ENUM_MA_METHOD _ma_method = MODE_SMA, - ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : ma_period(_ma_period), ma_shift(_ma_shift), ma_method(_ma_method), applied_price(_ap) { - itype = INDI_STDDEV; - max_modes = 1; + StdDevParams(int _ma_period = 13, int _ma_shift = 10, ENUM_MA_METHOD _ma_method = MODE_SMA, + ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) + : ma_period(_ma_period), + ma_shift(_ma_shift), + ma_method(_ma_method), + applied_price(_ap), + IndicatorParams(INDI_STDDEV, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\StdDev"); }; - void StdDevParams(StdDevParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + StdDevParams(StdDevParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -69,22 +70,13 @@ struct StdDevParams : IndicatorParams { /** * Implements the Standard Deviation indicator. */ -class Indi_StdDev : public Indicator { - protected: - StdDevParams params; - +class Indi_StdDev : public Indicator { public: /** * Class constructor. */ - Indi_StdDev(StdDevParams &_p) - : params(_p.ma_period, _p.ma_shift, _p.ma_method, _p.applied_price), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_StdDev(StdDevParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.ma_period, _p.ma_shift, _p.ma_method, _p.applied_price), Indicator(INDI_STDDEV, _tf) { - params = _p; - } + Indi_StdDev(StdDevParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_StdDev(ENUM_TIMEFRAMES _tf) : Indicator(INDI_STDDEV, _tf) {} /** * Calculates the Standard Deviation indicator and returns its value. @@ -94,7 +86,7 @@ class Indi_StdDev : public Indicator { * - https://www.mql5.com/en/docs/indicators/istddev */ static double iStdDev(string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, int _ma_shift, ENUM_MA_METHOD _ma_method, - ENUM_APPLIED_PRICE _applied_price, int _shift = 0, Indicator *_obj = NULL) { + ENUM_APPLIED_PRICE _applied_price, int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iStdDev(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_price, _shift); #else // __MQL5__ @@ -130,12 +122,13 @@ class Indi_StdDev : public Indicator { /** * Note that this method operates on current price (set by _applied_price). */ - static double iStdDevOnIndicator(Indicator *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, int _ma_shift, - ENUM_APPLIED_PRICE _applied_price, int _shift = 0, Indicator *_obj = NULL) { + static double iStdDevOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, + int _ma_shift, ENUM_APPLIED_PRICE _applied_price, int _shift = 0, + Indi_StdDev *_obj = NULL) { double _indi_value_buffer[]; double _std_dev; int i; - int _mode = _obj != NULL ? _obj.GetParams().indi_mode : 0; + int _mode = _obj != NULL ? _obj.GetDataSourceMode() : 0; ArrayResize(_indi_value_buffer, _ma_period); @@ -209,34 +202,33 @@ class Indi_StdDev : public Indicator { Indi_PriceFeeder indi_price_feeder(price); MAParams ma_params(period, 0, ma_method, PRICE_OPEN); - ma_params.SetDataSource(&indi_price_feeder, false, 0); // Using first and only mode from price feeder. - Indi_MA indi_ma(ma_params); + Indi_MA *_indi_ma = + Indi_MA::GetCached("Indi_StdDev:Unbuffered", (ENUM_TIMEFRAMES)-1, period, 0, ma_method, (ENUM_APPLIED_PRICE)-1); + _indi_ma.SetDataSource(&indi_price_feeder, false, 0); // Using first and only mode from price feeder. - return iStdDevOnIndicator(&indi_ma, NULL, NULL, period, 0, PRICE_OPEN, /*unused*/ 0); + return iStdDevOnIndicator(_indi_ma, NULL, NULL, period, 0, PRICE_OPEN, /*unused*/ 0); } /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = - Indi_StdDev::iStdDev(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetMAPeriod(), - GetMAShift(), GetMAMethod(), GetAppliedPrice(), _shift, GetPointer(this)); + _value = Indi_StdDev::iStdDev(GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), GetMAMethod(), + GetAppliedPrice(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = - iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetMAPeriod(), GetMAShift(), GetMAMethod() /*]*/, 0, _shift); + _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), + iparams.GetCustomIndicatorName(), /*[*/ GetMAPeriod(), GetMAShift(), GetMAMethod() /*]*/, 0, + _shift); break; case IDATA_INDICATOR: - _value = Indi_StdDev::iStdDevOnIndicator(GetDataSource(), Get(CHART_PARAM_SYMBOL), - Get(CHART_PARAM_TF), GetMAPeriod(), GetMAShift(), - GetAppliedPrice(), _shift, GetPointer(this)); + _value = Indi_StdDev::iStdDevOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), + GetAppliedPrice(), _shift, THIS_PTR); break; } istate.is_ready = _LastError == ERR_NO_ERROR; @@ -244,27 +236,6 @@ class Indi_StdDev : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - _entry.values[0].Set(GetValue(_shift)); - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -281,26 +252,26 @@ class Indi_StdDev : public Indicator { * * Averaging period for the calculation of the moving average. */ - int GetMAPeriod() { return params.ma_period; } + int GetMAPeriod() { return iparams.ma_period; } /** * Get MA shift value. * * Indicators line offset relate to the chart by timeframe. */ - unsigned int GetMAShift() { return params.ma_shift; } + unsigned int GetMAShift() { return iparams.ma_shift; } /** * Set MA method (smoothing type). */ - ENUM_MA_METHOD GetMAMethod() { return params.ma_method; } + ENUM_MA_METHOD GetMAMethod() { return iparams.ma_method; } /** * Get applied price value. * * The desired price base for calculations. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -311,7 +282,7 @@ class Indi_StdDev : public Indicator { */ void SetMAPeriod(int _ma_period) { istate.is_changed = true; - params.ma_period = _ma_period; + iparams.ma_period = _ma_period; } /** @@ -319,7 +290,7 @@ class Indi_StdDev : public Indicator { */ void SetMAShift(int _ma_shift) { istate.is_changed = true; - params.ma_shift = _ma_shift; + iparams.ma_shift = _ma_shift; } /** @@ -329,7 +300,7 @@ class Indi_StdDev : public Indicator { */ void SetMAMethod(ENUM_MA_METHOD _ma_method) { istate.is_changed = true; - params.ma_method = _ma_method; + iparams.ma_method = _ma_method; } /** @@ -342,6 +313,6 @@ class Indi_StdDev : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index 9c9908f86..fe6d8972b 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -40,18 +40,20 @@ struct StochParams : IndicatorParams { ENUM_MA_METHOD ma_method; ENUM_STO_PRICE price_field; // Struct constructors. - void StochParams(int _kperiod, int _dperiod, int _slowing, ENUM_MA_METHOD _ma_method, ENUM_STO_PRICE _pf, - int _shift = 0) - : kperiod(_kperiod), dperiod(_dperiod), slowing(_slowing), ma_method(_ma_method), price_field(_pf) { - itype = INDI_STOCHASTIC; - max_modes = FINAL_SIGNAL_LINE_ENTRY; + StochParams(int _kperiod = 5, int _dperiod = 3, int _slowing = 3, ENUM_MA_METHOD _ma_method = MODE_SMA, + ENUM_STO_PRICE _pf = STO_LOWHIGH, int _shift = 0) + : kperiod(_kperiod), + dperiod(_dperiod), + slowing(_slowing), + ma_method(_ma_method), + price_field(_pf), + IndicatorParams(INDI_STOCHASTIC, FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\Stochastic"); }; - void StochParams(StochParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + StochParams(StochParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -59,22 +61,13 @@ struct StochParams : IndicatorParams { /** * Implements the Stochastic Oscillator. */ -class Indi_Stochastic : public Indicator { - protected: - StochParams params; - +class Indi_Stochastic : public Indicator { public: /** * Class constructor. */ - Indi_Stochastic(StochParams &_p) - : params(_p.kperiod, _p.dperiod, _p.slowing, _p.ma_method, _p.price_field), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_Stochastic(StochParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.kperiod, _p.dperiod, _p.slowing, _p.ma_method, _p.price_field), Indicator(INDI_STOCHASTIC, _tf) { - params = _p; - } + Indi_Stochastic(StochParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_Stochastic(ENUM_TIMEFRAMES _tf) : Indicator(INDI_STOCHASTIC, _tf) {} /** * Calculates the Stochastic Oscillator and returns its value. @@ -89,7 +82,7 @@ class Indi_Stochastic : public Indicator { ENUM_STO_PRICE _price_field, // (MT4 _price_field): 0 - Low/High, 1 - Close/Close // (MT5 _price_field): STO_LOWHIGH - Low/High, STO_CLOSECLOSE - Close/Close int _mode, // (MT4): 0 - MODE_MAIN/MAIN_LINE, 1 - MODE_SIGNAL/SIGNAL_LINE - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iStochastic(_symbol, _tf, _kperiod, _dperiod, _slowing, _ma_method, _price_field, _mode, _shift); #else // __MQL5__ @@ -126,20 +119,18 @@ class Indi_Stochastic : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_SIGNAL_LINE _mode = LINE_MAIN, int _shift = 0) { + virtual double GetValue(int _mode = LINE_MAIN, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Stochastic::iStochastic(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - GetKPeriod(), GetDPeriod(), GetSlowing(), GetMAMethod(), GetPriceField(), - _mode, _shift, GetPointer(this)); + _value = Indi_Stochastic::iStochastic(GetSymbol(), GetTf(), GetKPeriod(), GetDPeriod(), GetSlowing(), + GetMAMethod(), GetPriceField(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetKPeriod(), GetDPeriod(), GetSlowing() /*]*/, _mode, - _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetKPeriod(), + GetDPeriod(), GetSlowing() /*]*/, _mode, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -150,36 +141,10 @@ class Indi_Stochastic : public Indicator { } /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue((ENUM_SIGNAL_LINE)_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, - !_entry.HasValue((double)NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGe(0)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - - /** - * Returns the indicator's entry value. + * Checks if indicator entry values are valid. */ - MqlParam GetEntryValue(int _shift = 0, int _mode = 0) { - MqlParam _param = {TYPE_DOUBLE}; - GetEntry(_shift).values[_mode].Get(_param.double_value); - return _param; + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return !_entry.HasValue((double)NULL) && !_entry.HasValue(EMPTY_VALUE) && _entry.IsGe(0); } /* Getters */ @@ -187,27 +152,27 @@ class Indi_Stochastic : public Indicator { /** * Get period of the %K line. */ - int GetKPeriod() { return params.kperiod; } + int GetKPeriod() { return iparams.kperiod; } /** * Get period of the %D line. */ - int GetDPeriod() { return params.dperiod; } + int GetDPeriod() { return iparams.dperiod; } /** * Get slowing value. */ - int GetSlowing() { return params.slowing; } + int GetSlowing() { return iparams.slowing; } /** * Set MA method. */ - ENUM_MA_METHOD GetMAMethod() { return params.ma_method; } + ENUM_MA_METHOD GetMAMethod() { return iparams.ma_method; } /** * Get price field parameter. */ - ENUM_STO_PRICE GetPriceField() { return params.price_field; } + ENUM_STO_PRICE GetPriceField() { return iparams.price_field; } /* Setters */ @@ -216,7 +181,7 @@ class Indi_Stochastic : public Indicator { */ void SetKPeriod(int _kperiod) { istate.is_changed = true; - params.kperiod = _kperiod; + iparams.kperiod = _kperiod; } /** @@ -224,7 +189,7 @@ class Indi_Stochastic : public Indicator { */ void SetDPeriod(int _dperiod) { istate.is_changed = true; - params.dperiod = _dperiod; + iparams.dperiod = _dperiod; } /** @@ -232,7 +197,7 @@ class Indi_Stochastic : public Indicator { */ void SetSlowing(int _slowing) { istate.is_changed = true; - params.slowing = _slowing; + iparams.slowing = _slowing; } /** @@ -240,7 +205,7 @@ class Indi_Stochastic : public Indicator { */ void SetMAMethod(ENUM_MA_METHOD _ma_method) { istate.is_changed = true; - params.ma_method = _ma_method; + iparams.ma_method = _ma_method; } /** @@ -248,6 +213,6 @@ class Indi_Stochastic : public Indicator { */ void SetPriceField(ENUM_STO_PRICE _price_field) { istate.is_changed = true; - params.price_field = _price_field; + iparams.price_field = _price_field; } }; diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index 6c84ca1a3..8d49fbfcf 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -32,22 +32,17 @@ struct TEMAParams : IndicatorParams { unsigned int tema_shift; ENUM_APPLIED_PRICE applied_price; // Struct constructor. - void TEMAParams(int _period = 14, int _tema_shift = 0, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + TEMAParams(int _period = 14, int _tema_shift = 0, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + : IndicatorParams(INDI_TEMA, 1, TYPE_DOUBLE) { applied_price = _ap; - itype = INDI_TEMA; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\TEMA"); - SetDataSourceType(IDATA_BUILTIN); period = _period; shift = _shift; tema_shift = _tema_shift; - tf = _tf; }; - void TEMAParams(TEMAParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + TEMAParams(TEMAParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -55,24 +50,19 @@ struct TEMAParams : IndicatorParams { /** * Implements the Triple Exponential Moving Average indicator. */ -class Indi_TEMA : public Indicator { - protected: - TEMAParams params; - +class Indi_TEMA : public Indicator { public: /** * Class constructor. */ - Indi_TEMA(TEMAParams &_params) : params(_params.period, _params.tema_shift), Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_TEMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_TEMA, _tf) { params.tf = _tf; }; + Indi_TEMA(TEMAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_TEMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_TEMA, _tf){}; /** * Built-in version of TEMA. */ static double iTEMA(string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, - int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + int _mode = 0, int _shift = 0, Indi_TEMA *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iTEMA(_symbol, _tf, _ma_period, _ma_shift, _ap), _mode, _shift); #else @@ -136,16 +126,16 @@ class Indi_TEMA : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_TEMA::iTEMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetTEMAShift(), GetAppliedPrice() /*]*/, 0, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ GetPeriod(), + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetTEMAShift() /*]*/, 0, _shift); break; default: @@ -162,15 +152,15 @@ class Indi_TEMA : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { _entry.timestamp = GetBarTime(_shift); _entry.values[0] = GetValue(_shift); - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } @@ -186,22 +176,29 @@ class Indi_TEMA : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE); + } + /* Getters */ /** * Get period. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get TEMA shift. */ - unsigned int GetTEMAShift() { return params.tema_shift; } + unsigned int GetTEMAShift() { return iparams.tema_shift; } /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -210,7 +207,7 @@ class Indi_TEMA : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -218,7 +215,7 @@ class Indi_TEMA : public Indicator { */ void SetTEMAShift(unsigned int _tema_shift) { istate.is_changed = true; - params.tema_shift = _tema_shift; + iparams.tema_shift = _tema_shift; } /** @@ -226,6 +223,6 @@ class Indi_TEMA : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index 9d00d9d79..0f67564b7 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -32,21 +32,16 @@ struct TRIXParams : IndicatorParams { unsigned int tema_shift; ENUM_APPLIED_PRICE applied_price; // Struct constructor. - void TRIXParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + TRIXParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + : IndicatorParams(INDI_TRIX, 1, TYPE_DOUBLE) { applied_price = _ap; - itype = INDI_TRIX; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\TRIX"); - SetDataSourceType(IDATA_BUILTIN); period = _period; shift = _shift; - tf = _tf; }; - void TRIXParams(TRIXParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + TRIXParams(TRIXParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -54,22 +49,19 @@ struct TRIXParams : IndicatorParams { /** * Implements the Triple Exponential Average indicator. */ -class Indi_TRIX : public Indicator { - protected: - TRIXParams params; - +class Indi_TRIX : public Indicator { public: /** * Class constructor. */ - Indi_TRIX(TRIXParams &_params) : params(_params.period), Indicator((IndicatorParams)_params) { params = _params; }; - Indi_TRIX(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_TRIX, _tf) { params.tf = _tf; }; + Indi_TRIX(TRIXParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_TRIX(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_TRIX, _tf){}; /** * Built-in version of TriX. */ static double iTriX(string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, ENUM_APPLIED_PRICE _ap, int _mode = 0, - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iTriX(_symbol, _tf, _ma_period, _ap), _mode, _shift); #else @@ -135,16 +127,16 @@ class Indi_TRIX : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_TRIX::iTriX(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _shift); break; default: @@ -155,29 +147,6 @@ class Indi_TRIX : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -192,12 +161,12 @@ class Indi_TRIX : public Indicator { /** * Get period. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -206,7 +175,7 @@ class Indi_TRIX : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -214,6 +183,6 @@ class Indi_TRIX : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index 1c22bd851..eb891c964 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -23,7 +23,9 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" #include "Indi_ATR.mqh" +#include "Indi_MA.mqh" // Structs. struct UltimateOscillatorParams : IndicatorParams { @@ -35,34 +37,21 @@ struct UltimateOscillatorParams : IndicatorParams { int slow_k; // Struct constructor. - void UltimateOscillatorParams(int _fast_period = 7, int _middle_period = 14, int _slow_period = 28, int _fast_k = 4, - int _middle_k = 2, int _slow_k = 1, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + UltimateOscillatorParams(int _fast_period = 7, int _middle_period = 14, int _slow_period = 28, int _fast_k = 4, + int _middle_k = 2, int _slow_k = 1, int _shift = 0) + : IndicatorParams(INDI_ULTIMATE_OSCILLATOR, 1, TYPE_DOUBLE) { fast_k = _fast_k; fast_period = _fast_period; - itype = INDI_ULTIMATE_OSCILLATOR; - max_modes = 1; middle_k = _middle_k; middle_period = _middle_period; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); - // SetDataSourceType(IDATA_ICUSTOM); - SetDataSourceType(IDATA_BUILTIN); SetCustomIndicatorName("Examples\\Ultimate_Oscillator"); - // IC: INDI_ULTIMATE_OSCILLATOR[1]: bar 1: 1525392000,130,45.93870749 - // IC: INDI_ULTIMATE_OSCILLATOR[1]: bar 1: 1525392120,130,36.36985216 - // IC: INDI_ULTIMATE_OSCILLATOR[1]: bar 1: 1525392180,130,40.82834908 - - // BIN: INDI_ULTIMATE_OSCILLATOR[1]: bar 2: 1525392240,130,53.10341381 - - // SetDataSourceType(IDATA_ICUSTOM); shift = _shift; slow_k = _slow_k; slow_period = _slow_period; - tf = _tf; }; - void UltimateOscillatorParams(UltimateOscillatorParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + UltimateOscillatorParams(UltimateOscillatorParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -70,34 +59,29 @@ struct UltimateOscillatorParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_UltimateOscillator : public Indicator { - protected: - UltimateOscillatorParams params; - +class Indi_UltimateOscillator : public Indicator { public: /** * Class constructor. */ - Indi_UltimateOscillator(UltimateOscillatorParams &_params) : Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_UltimateOscillator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_ULTIMATE_OSCILLATOR, _tf) { - params.tf = _tf; - }; + Indi_UltimateOscillator(UltimateOscillatorParams &_p, IndicatorBase *_indi_src = NULL) + : Indicator(_p, _indi_src){}; + Indi_UltimateOscillator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_ULTIMATE_OSCILLATOR, _tf){}; /** * Built-in version of Ultimate Oscillator. */ static double iUO(string _symbol, ENUM_TIMEFRAMES _tf, int _fast_period, int _middle_period, int _slow_period, - int _fast_k, int _middle_k, int _slow_k, int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + int _fast_k, int _middle_k, int _slow_k, int _mode = 0, int _shift = 0, + IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( _symbol, _tf, Util::MakeKey("Indi_UltimateOscillator", _fast_period, _middle_period, _slow_period, _fast_k, _middle_k, _slow_k)); - Indicator *_indi_atr_fast = Indi_ATR::GetCached(_symbol, _tf, _fast_period); - Indicator *_indi_atr_middle = Indi_ATR::GetCached(_symbol, _tf, _middle_period); - Indicator *_indi_atr_slow = Indi_ATR::GetCached(_symbol, _tf, _slow_period); + IndicatorBase *_indi_atr_fast = Indi_ATR::GetCached(_symbol, _tf, _fast_period); + IndicatorBase *_indi_atr_middle = Indi_ATR::GetCached(_symbol, _tf, _middle_period); + IndicatorBase *_indi_atr_slow = Indi_ATR::GetCached(_symbol, _tf, _slow_period); return iUOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _fast_period, _middle_period, _slow_period, _fast_k, _middle_k, _slow_k, _mode, _shift, _cache, _indi_atr_fast, _indi_atr_middle, _indi_atr_slow); @@ -108,8 +92,8 @@ class Indi_UltimateOscillator : public Indicator { */ 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, - IndicatorCalculateCache *_cache, Indicator *_indi_atr_fast, - Indicator *_indi_atr_middle, Indicator *_indi_atr_slow, bool _recalculate = false) { + IndicatorCalculateCache *_cache, IndicatorBase *_indi_atr_fast, + IndicatorBase *_indi_atr_middle, IndicatorBase *_indi_atr_slow, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); if (!_cache.HasBuffers()) { @@ -135,27 +119,29 @@ class Indi_UltimateOscillator : public Indicator { ValueStorage &ExtBPBuffer, ValueStorage &ExtFastATRBuffer, ValueStorage &ExtMiddleATRBuffer, ValueStorage &ExtSlowATRBuffer, int InpFastPeriod, int InpMiddlePeriod, int InpSlowPeriod, int InpFastK, int InpMiddleK, - int InpSlowK, Indicator *ExtFastATRhandle, Indicator *ExtMiddleATRhandle, - Indicator *ExtSlowATRhandle) { + int InpSlowK, Indi_ATR *ExtFastATRhandle, Indi_ATR *ExtMiddleATRhandle, + Indi_ATR *ExtSlowATRhandle) { double ExtDivider = InpFastK + InpMiddleK + InpSlowK; double true_low; int ExtMaxPeriod = InpSlowPeriod; 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, rates_total); + int calculated = BarsCalculated(ExtFastATRhandle); if (calculated < rates_total) { // Not all data of ExtFastATRhandle is calculated. return (0); } - calculated = BarsCalculated(ExtMiddleATRhandle, rates_total); + calculated = BarsCalculated(ExtMiddleATRhandle); if (calculated < rates_total) { // Not all data of ExtFastATRhandle is calculated. return (0); } - calculated = BarsCalculated(ExtSlowATRhandle, rates_total); + calculated = BarsCalculated(ExtSlowATRhandle); if (calculated < rates_total) { // Not all data of ExtFastATRhandle is calculated. return (0); @@ -222,17 +208,17 @@ class Indi_UltimateOscillator : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_UltimateOscillator::iUO(GetSymbol(), GetTf(), /*[*/ GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), GetMiddleK(), GetSlowK() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), GetMiddleK(), GetSlowK() /*]*/, @@ -246,29 +232,6 @@ class Indi_UltimateOscillator : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -283,32 +246,32 @@ class Indi_UltimateOscillator : public Indicator { /** * Get fast period. */ - int GetFastPeriod() { return params.fast_period; } + int GetFastPeriod() { return iparams.fast_period; } /** * Get middle period. */ - int GetMiddlePeriod() { return params.middle_period; } + int GetMiddlePeriod() { return iparams.middle_period; } /** * Get slow period. */ - int GetSlowPeriod() { return params.slow_period; } + int GetSlowPeriod() { return iparams.slow_period; } /** * Get fast k. */ - int GetFastK() { return params.fast_k; } + int GetFastK() { return iparams.fast_k; } /** * Get middle k. */ - int GetMiddleK() { return params.middle_k; } + int GetMiddleK() { return iparams.middle_k; } /** * Get slow k. */ - int GetSlowK() { return params.slow_k; } + int GetSlowK() { return iparams.slow_k; } /* Setters */ @@ -317,7 +280,7 @@ class Indi_UltimateOscillator : public Indicator { */ void SetFastPeriod(int _fast_period) { istate.is_changed = true; - params.fast_period = _fast_period; + iparams.fast_period = _fast_period; } /** @@ -325,7 +288,7 @@ class Indi_UltimateOscillator : public Indicator { */ void SetMiddlePeriod(int _middle_period) { istate.is_changed = true; - params.middle_period = _middle_period; + iparams.middle_period = _middle_period; } /** @@ -333,7 +296,7 @@ class Indi_UltimateOscillator : public Indicator { */ void SetSlowPeriod(int _slow_period) { istate.is_changed = true; - params.slow_period = _slow_period; + iparams.slow_period = _slow_period; } /** @@ -341,7 +304,7 @@ class Indi_UltimateOscillator : public Indicator { */ void SetFastK(int _fast_k) { istate.is_changed = true; - params.fast_k = _fast_k; + iparams.fast_k = _fast_k; } /** @@ -349,7 +312,7 @@ class Indi_UltimateOscillator : public Indicator { */ void SetMiddleK(int _middle_k) { istate.is_changed = true; - params.middle_k = _middle_k; + iparams.middle_k = _middle_k; } /** @@ -357,6 +320,6 @@ class Indi_UltimateOscillator : public Indicator { */ void SetSlowK(int _slow_k) { istate.is_changed = true; - params.slow_k = _slow_k; + iparams.slow_k = _slow_k; } }; diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index 7c9f9727e..b2a54fcfb 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -33,23 +33,19 @@ struct VIDYAParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructor. - void VIDYAParams(unsigned int _cmo_period = 9, unsigned int _ma_period = 14, unsigned int _vidya_shift = 0, - ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + VIDYAParams(unsigned int _cmo_period = 9, unsigned int _ma_period = 14, unsigned int _vidya_shift = 0, + ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) + : IndicatorParams(INDI_VIDYA, 1, TYPE_DOUBLE) { applied_price = _ap; cmo_period = _cmo_period; - itype = INDI_VIDYA; ma_period = _ma_period; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\VIDYA"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; vidya_shift = _vidya_shift; }; - void VIDYAParams(VIDYAParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + VIDYAParams(VIDYAParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -57,22 +53,19 @@ struct VIDYAParams : IndicatorParams { /** * Implements the Variable Index Dynamic Average indicator. */ -class Indi_VIDYA : public Indicator { - protected: - VIDYAParams params; - +class Indi_VIDYA : public Indicator { public: /** * Class constructor. */ - Indi_VIDYA(VIDYAParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_VIDYA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_VIDYA, _tf) { params.tf = _tf; }; + Indi_VIDYA(VIDYAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_VIDYA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_VIDYA, _tf){}; /** * Built-in version of iVIDyA. */ static double iVIDyA(string _symbol, ENUM_TIMEFRAMES _tf, int _cmo_period, int _ema_period, int _ma_shift, - ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iVIDyA(_symbol, _tf, _cmo_period, _ema_period, _ma_shift, _ap), _mode, _shift); #else @@ -154,16 +147,16 @@ class Indi_VIDYA : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_VIDYA::iVIDyA(GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift(), GetAppliedPrice() /*]*/, 0, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), /*[*/ + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift() /*]*/, @@ -177,29 +170,6 @@ class Indi_VIDYA : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -214,22 +184,22 @@ class Indi_VIDYA : public Indicator { /** * Get CMO period. */ - unsigned int GetCMOPeriod() { return params.cmo_period; } + unsigned int GetCMOPeriod() { return iparams.cmo_period; } /** * Get MA period. */ - unsigned int GetMAPeriod() { return params.ma_period; } + unsigned int GetMAPeriod() { return iparams.ma_period; } /** * Get VIDYA shift. */ - unsigned int GetVIDYAShift() { return params.vidya_shift; } + unsigned int GetVIDYAShift() { return iparams.vidya_shift; } /** * Get applied price. */ - ENUM_APPLIED_PRICE GetAppliedPrice() { return params.applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return iparams.applied_price; } /* Setters */ @@ -238,7 +208,7 @@ class Indi_VIDYA : public Indicator { */ void SetCMOPeriod(unsigned int _cmo_period) { istate.is_changed = true; - params.cmo_period = _cmo_period; + iparams.cmo_period = _cmo_period; } /** @@ -246,7 +216,7 @@ class Indi_VIDYA : public Indicator { */ void SetMAPeriod(unsigned int _ma_period) { istate.is_changed = true; - params.ma_period = _ma_period; + iparams.ma_period = _ma_period; } /** @@ -254,7 +224,7 @@ class Indi_VIDYA : public Indicator { */ void SetVIDYAShift(unsigned int _vidya_shift) { istate.is_changed = true; - params.vidya_shift = _vidya_shift; + iparams.vidya_shift = _vidya_shift; } /** @@ -262,6 +232,6 @@ class Indi_VIDYA : public Indicator { */ void SetAppliedPrice(ENUM_APPLIED_PRICE _applied_price) { istate.is_changed = true; - params.applied_price = _applied_price; + iparams.applied_price = _applied_price; } }; diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index 5a1d21654..b6ff5f053 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -23,27 +23,23 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" // Structs. struct VROCParams : IndicatorParams { unsigned int period; ENUM_APPLIED_VOLUME applied_volume; // Struct constructor. - void VROCParams(unsigned int _period = 25, ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + VROCParams(unsigned int _period = 25, ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0) + : IndicatorParams(INDI_VROC, 1, TYPE_DOUBLE) { applied_volume = _applied_volume; - itype = INDI_VROC; - max_modes = 1; period = _period; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\VROC"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; }; - void VROCParams(VROCParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + VROCParams(VROCParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -51,22 +47,19 @@ struct VROCParams : IndicatorParams { /** * Implements the Volume Rate of Change indicator. */ -class Indi_VROC : public Indicator { - protected: - VROCParams params; - +class Indi_VROC : public Indicator { public: /** * Class constructor. */ - Indi_VROC(VROCParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_VROC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_VROC, _tf) { params.tf = _tf; }; + Indi_VROC(VROCParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_VROC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_VROC, _tf){}; /** * Built-in version of VROC. */ static double iVROC(string _symbol, ENUM_TIMEFRAMES _tf, int _period, ENUM_APPLIED_VOLUME _av, int _mode = 0, - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_VROC", _period, (int)_av)); return iVROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _av, _mode, _shift, _cache); } @@ -137,16 +130,16 @@ class Indi_VROC : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_VROC::iVROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _shift); break; default: @@ -157,29 +150,6 @@ class Indi_VROC : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -194,12 +164,12 @@ class Indi_VROC : public Indicator { /** * Get period volume. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /** * Get applied volume. */ - ENUM_APPLIED_VOLUME GetAppliedVolume() { return params.applied_volume; } + ENUM_APPLIED_VOLUME GetAppliedVolume() { return iparams.applied_volume; } /* Setters */ @@ -208,7 +178,7 @@ class Indi_VROC : public Indicator { */ void SetPeriod(ENUM_APPLIED_VOLUME _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } /** @@ -216,6 +186,6 @@ class Indi_VROC : public Indicator { */ void SetAppliedVolume(ENUM_APPLIED_VOLUME _applied_volume) { istate.is_changed = true; - params.applied_volume = _applied_volume; + iparams.applied_volume = _applied_volume; } }; diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index 2fec77e98..5862fecde 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -23,25 +23,22 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" // Structs. struct VolumesParams : IndicatorParams { ENUM_APPLIED_VOLUME applied_volume; // Struct constructor. - void VolumesParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + VolumesParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0) + : IndicatorParams(INDI_VOLUMES, 2, TYPE_DOUBLE) { applied_volume = _applied_volume; - itype = INDI_VOLUMES; - max_modes = 2; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Volumes"); - SetDataSourceType(IDATA_ICUSTOM); + SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; }; - void VolumesParams(VolumesParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + VolumesParams(VolumesParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -49,24 +46,19 @@ struct VolumesParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_Volumes : public Indicator { - protected: - VolumesParams params; - +class Indi_Volumes : public Indicator { public: /** * Class constructor. */ - Indi_Volumes(VolumesParams &_params) : params(_params.applied_volume), Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_Volumes(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_VOLUMES, _tf) { params.tf = _tf; }; + Indi_Volumes(VolumesParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_Volumes(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_VOLUMES, _tf){}; /** * Built-in version of Volumes. */ static double iVolumes(string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0, - Indicator *_obj = NULL) { + IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_Volumes", (int)_av)); return iVolumesOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _shift, _cache); } @@ -98,6 +90,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); + // Starting work. int pos = prev_calculated - 1; // Correct position. @@ -105,6 +98,7 @@ class Indi_Volumes : public Indicator { ExtVolumesBuffer[0] = 0; pos = 1; } + // Main cycle. if (InpVolumeType == VOLUME_TICK) CalculateVolume(pos, rates_total, tick_volume, ExtVolumesBuffer, ExtColorsBuffer); @@ -130,15 +124,15 @@ class Indi_Volumes : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_Volumes::iVolumes(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetAppliedVolume() /*]*/, _mode, _shift); break; default: @@ -149,29 +143,6 @@ class Indi_Volumes : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -186,7 +157,7 @@ class Indi_Volumes : public Indicator { /** * Get applied volume. */ - ENUM_APPLIED_VOLUME GetAppliedVolume() { return params.applied_volume; } + ENUM_APPLIED_VOLUME GetAppliedVolume() { return iparams.applied_volume; } /* Setters */ @@ -195,6 +166,6 @@ class Indi_Volumes : public Indicator { */ void SetAppliedVolume(ENUM_APPLIED_VOLUME _applied_volume) { istate.is_changed = true; - params.applied_volume = _applied_volume; + iparams.applied_volume = _applied_volume; } }; diff --git a/Indicators/Indi_WPR.mqh b/Indicators/Indi_WPR.mqh index 433443763..d478065f7 100644 --- a/Indicators/Indi_WPR.mqh +++ b/Indicators/Indi_WPR.mqh @@ -34,16 +34,13 @@ double iWPR(string _symbol, int _tf, int _period, int _shift) { struct WPRParams : IndicatorParams { unsigned int period; // Struct constructors. - void WPRParams(unsigned int _period, int _shift = 0) : period(_period) { - itype = INDI_WPR; - max_modes = 1; + WPRParams(unsigned int _period = 14, int _shift = 0) : period(_period), IndicatorParams(INDI_WPR, 1, TYPE_DOUBLE) { shift = _shift; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\WPR"); }; - void WPRParams(WPRParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + WPRParams(WPRParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -51,16 +48,13 @@ struct WPRParams : IndicatorParams { /** * Implements the Larry Williams' Percent Range. */ -class Indi_WPR : public Indicator { - protected: - WPRParams params; - +class Indi_WPR : public Indicator { public: /** * Class constructor. */ - Indi_WPR(WPRParams &_p) : params(_p.period), Indicator((IndicatorParams)_p) { params = _p; } - Indi_WPR(WPRParams &_p, ENUM_TIMEFRAMES _tf) : params(_p.period), Indicator(INDI_WPR, _tf) { params = _p; } + Indi_WPR(WPRParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_WPR(ENUM_TIMEFRAMES _tf) : Indicator(INDI_WPR, _tf) {} /** * Calculates the Larry Williams' Percent Range and returns its value. @@ -70,7 +64,7 @@ class Indi_WPR : public Indicator { * - https://www.mql5.com/en/docs/indicators/iwpr */ static double iWPR(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _period = 14, - int _shift = 0, Indicator *_obj = NULL) { + int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL4__ return ::iWPR(_symbol, _tf, _period, _shift); #else // __MQL5__ @@ -106,18 +100,17 @@ class Indi_WPR : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_WPR::iWPR(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(), - _shift, GetPointer(this)); + _value = Indi_WPR::iWPR(GetSymbol(), GetTf(), GetPeriod(), _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, + 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -127,29 +120,6 @@ class Indi_WPR : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue((double)NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -164,7 +134,7 @@ class Indi_WPR : public Indicator { /** * Get period value. */ - unsigned int GetPeriod() { return params.period; } + unsigned int GetPeriod() { return iparams.period; } /* Setters */ @@ -173,6 +143,6 @@ class Indi_WPR : public Indicator { */ void SetPeriod(unsigned int _period) { istate.is_changed = true; - params.period = _period; + iparams.period = _period; } }; diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index 9719ca282..5b553f2d4 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -23,22 +23,18 @@ // Includes. #include "../BufferStruct.mqh" #include "../Indicator.mqh" +#include "../Storage/ValueStorage.all.h" // Structs. struct WilliamsADParams : IndicatorParams { // Struct constructor. - void WilliamsADParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_WILLIAMS_AD; - max_modes = 1; - SetDataValueType(TYPE_DOUBLE); + WilliamsADParams(int _shift = 0) : IndicatorParams(INDI_WILLIAMS_AD, 1, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\W_AD"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; - tf = _tf; }; - void WilliamsADParams(WilliamsADParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + WilliamsADParams(WilliamsADParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -46,21 +42,18 @@ struct WilliamsADParams : IndicatorParams { /** * Implements the Volume Rate of Change indicator. */ -class Indi_WilliamsAD : public Indicator { - protected: - WilliamsADParams params; - +class Indi_WilliamsAD : public Indicator { public: /** * Class constructor. */ - Indi_WilliamsAD(WilliamsADParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_WilliamsAD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_WILLIAMS_AD, _tf) { params.tf = _tf; }; + Indi_WilliamsAD(WilliamsADParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_WilliamsAD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_WILLIAMS_AD, _tf){}; /** * Built-in version of Williams' AD. */ - static double iWAD(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + static double iWAD(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_WilliamsAD"); return iWADOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -130,15 +123,15 @@ class Indi_WilliamsAD : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_WilliamsAD::iWAD(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), params.GetCustomIndicatorName(), 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), 0, _shift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -148,29 +141,6 @@ class Indi_WilliamsAD : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index e4e804c22..dccdf6070 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -34,18 +34,17 @@ struct ZigZagParams : IndicatorParams { unsigned int deviation; unsigned int backstep; // Struct constructors. - void ZigZagParams(unsigned int _depth, unsigned int _deviation, unsigned int _backstep, int _shift = 0) - : depth(_depth), deviation(_deviation), backstep(_backstep) { - itype = INDI_ZIGZAG; - max_modes = FINAL_ZIGZAG_LINE_ENTRY; + ZigZagParams(unsigned int _depth = 12, unsigned int _deviation = 5, unsigned int _backstep = 3, int _shift = 0) + : depth(_depth), + deviation(_deviation), + backstep(_backstep), + IndicatorParams(INDI_ZIGZAG, FINAL_ZIGZAG_LINE_ENTRY, TYPE_DOUBLE) { shift = _shift; - SetDataSourceType(IDATA_BUILTIN); SetCustomIndicatorName("Examples\\ZigZag"); - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_PRICE); // @fixit Draws lines between lowest and highest prices! }; - void ZigZagParams(ZigZagParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ZigZagParams(ZigZagParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -59,27 +58,19 @@ enum EnSearchMode { /** * Implements ZigZag indicator. */ -class Indi_ZigZag : public Indicator { - protected: - ZigZagParams params; - +class Indi_ZigZag : public Indicator { public: /** * Class constructor. */ - Indi_ZigZag(ZigZagParams &_p) : params(_p.depth, _p.deviation, _p.backstep), Indicator((IndicatorParams)_p) { - params = _p; - } - Indi_ZigZag(ZigZagParams &_p, ENUM_TIMEFRAMES _tf) - : params(_p.depth, _p.deviation, _p.backstep), Indicator(INDI_ZIGZAG, _tf) { - params = _p; - } + Indi_ZigZag(ZigZagParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} + Indi_ZigZag(ENUM_TIMEFRAMES _tf) : Indicator(INDI_ZIGZAG, _tf) {} /** * Returns value for ZigZag indicator. */ static double iCustomZigZag(string _symbol, ENUM_TIMEFRAMES _tf, string _name, int _depth, int _deviation, - int _backstep, ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + int _backstep, ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { #ifdef __MQL5__ int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; double _res[]; @@ -116,7 +107,7 @@ class Indi_ZigZag : public Indicator { * Returns value for ZigZag indicator. */ static double iZigZag(string _symbol, ENUM_TIMEFRAMES _tf, int _depth, int _deviation, int _backstep, - ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0, Indicator *_obj = NULL) { + ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0, Indi_ZigZag *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_ZigZag", _depth, _deviation, _backstep)); return iZigZagOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, _shift, @@ -344,18 +335,18 @@ class Indi_ZigZag : public Indicator { /** * Returns the indicator's value. */ - double GetValue(ENUM_ZIGZAG_LINE _mode, int _shift = 0) { + virtual double GetValue(int _mode, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ZigZag::iZigZag(GetSymbol(), GetTf(), GetDepth(), GetDeviation(), GetBackstep(), _mode, _shift, - GetPointer(this)); + _value = Indi_ZigZag::iZigZag(GetSymbol(), 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(), params.GetCustomIndicatorName(), GetDepth(), - GetDeviation(), GetBackstep(), _mode, _shift, GetPointer(this)); + _value = Indi_ZigZag::iCustomZigZag(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), GetDepth(), + GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, _shift, THIS_PTR); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -371,17 +362,17 @@ class Indi_ZigZag : public Indicator { IndicatorDataEntry GetEntry(int _shift = 0) { long _bar_time = GetBarTime(_shift); unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); + IndicatorDataEntry _entry(iparams.GetMaxModes()); if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { + for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) { _entry.values[_mode] = GetValue((ENUM_ZIGZAG_LINE)_mode, _shift); } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(EMPTY_VALUE)); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); idata.Add(_entry, _bar_time); } } @@ -397,22 +388,27 @@ class Indi_ZigZag : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return !_entry.HasValue(EMPTY_VALUE); } + /* Getters */ /** * Get depth. */ - unsigned int GetDepth() { return params.depth; } + unsigned int GetDepth() { return iparams.depth; } /** * Get deviation. */ - unsigned int GetDeviation() { return params.deviation; } + unsigned int GetDeviation() { return iparams.deviation; } /** * Get backstep. */ - unsigned int GetBackstep() { return params.backstep; } + unsigned int GetBackstep() { return iparams.backstep; } /* Setters */ @@ -421,7 +417,7 @@ class Indi_ZigZag : public Indicator { */ void SetDepth(unsigned int _depth) { istate.is_changed = true; - params.depth = _depth; + iparams.depth = _depth; } /** @@ -429,7 +425,7 @@ class Indi_ZigZag : public Indicator { */ void SetDeviation(unsigned int _deviation) { istate.is_changed = true; - params.deviation = _deviation; + iparams.deviation = _deviation; } /** @@ -437,6 +433,6 @@ class Indi_ZigZag : public Indicator { */ void SetBackstep(unsigned int _backstep) { istate.is_changed = true; - params.backstep = _backstep; + iparams.backstep = _backstep; } }; diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 2ec756b94..0b8825bc2 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -31,22 +31,18 @@ struct ZigZagColorParams : IndicatorParams { unsigned int backstep; // Struct constructor. - void ZigZagColorParams(unsigned int _depth = 12, unsigned int _deviation = 5, unsigned int _backstep = 3, - int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + ZigZagColorParams(unsigned int _depth = 12, unsigned int _deviation = 5, unsigned int _backstep = 3, int _shift = 0) + : IndicatorParams(INDI_ZIGZAG_COLOR, 3, TYPE_DOUBLE) { backstep = _backstep; depth = _depth; deviation = _deviation; - itype = INDI_ZIGZAG_COLOR; - max_modes = 3; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ZigZagColor"); SetDataSourceType(IDATA_ICUSTOM); shift = _shift; - tf = _tf; }; - void ZigZagColorParams(ZigZagColorParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + ZigZagColorParams(ZigZagColorParams& _params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -54,30 +50,24 @@ struct ZigZagColorParams : IndicatorParams { /** * Implements the Volume Rate of Change indicator. */ -class Indi_ZigZagColor : public Indicator { - protected: - ZigZagColorParams params; - +class Indi_ZigZagColor : public Indicator { public: /** * Class constructor. */ - Indi_ZigZagColor(ZigZagColorParams &_params) - : params(_params.depth, _params.deviation, _params.backstep), Indicator((IndicatorParams)_params) { - params = _params; - }; - Indi_ZigZagColor(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_VROC, _tf) { params.tf = _tf; }; + Indi_ZigZagColor(ZigZagColorParams& _p, IndicatorBase* _indi_src = NULL) + : Indicator(_p, _indi_src){}; + Indi_ZigZagColor(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_VROC, _tf){}; /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - params.GetCustomIndicatorName(), + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetDepth(), GetDeviation(), GetBackstep() /*]*/, _mode, _shift); break; default: @@ -88,29 +78,6 @@ class Indi_ZigZagColor : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, _entry.values[0].Get() != EMPTY_VALUE); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -120,22 +87,27 @@ class Indi_ZigZagColor : public Indicator { return _param; } + /** + * Checks if indicator entry values are valid. + */ + virtual bool IsValidEntry(IndicatorDataEntry& _entry) { return _entry.values[0].Get() != EMPTY_VALUE; } + /* Getters */ /** * Get depth. */ - unsigned int GetDepth() { return params.depth; } + unsigned int GetDepth() { return iparams.depth; } /** * Get deviation. */ - unsigned int GetDeviation() { return params.deviation; } + unsigned int GetDeviation() { return iparams.deviation; } /** * Get backstep. */ - unsigned int GetBackstep() { return params.backstep; } + unsigned int GetBackstep() { return iparams.backstep; } /* Setters */ @@ -144,7 +116,7 @@ class Indi_ZigZagColor : public Indicator { */ void SetDepth(unsigned int _depth) { istate.is_changed = true; - params.depth = _depth; + iparams.depth = _depth; } /** @@ -152,7 +124,7 @@ class Indi_ZigZagColor : public Indicator { */ void SetDeviation(unsigned int _deviation) { istate.is_changed = true; - params.deviation = _deviation; + iparams.deviation = _deviation; } /** @@ -160,6 +132,6 @@ class Indi_ZigZagColor : public Indicator { */ void SetBackstep(unsigned int _backstep) { istate.is_changed = true; - params.backstep = _backstep; + iparams.backstep = _backstep; } }; diff --git a/Indicators/README.md b/Indicators/README.md index ee7353588..439bfea2d 100644 --- a/Indicators/README.md +++ b/Indicators/README.md @@ -33,8 +33,8 @@ Example using a static call: Example usage: IndicatorParams iparams; - ADX_Params params(14, PRICE_HIGH); - Indi_ADX *adx = new Indi_ADX(params, iparams); + ADX_Params iparams(14, PRICE_HIGH); + Indi_ADX *adx = new Indi_ADX(iparams, iparams); Print("ADX: ", adx.GetValue(LINE_MAIN_ADX)); delete adx; @@ -60,8 +60,8 @@ Example using a static call: Example usage: IndicatorParams iparams; - ATR_Params params(14); - Indi_ATR *atr = new Indi_ATR(params, iparams); + ATR_Params iparams(14); + Indi_ATR *atr = new Indi_ATR(iparams, iparams); Print("ATR: ", atr.GetValue()); delete atr; @@ -74,8 +74,8 @@ Example using a static call: Example usage: IndicatorParams iparams; - Alligator_Params params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - Indi_Alligator *alligator = new Indi_Alligator(params, iparams); + Alligator_Params iparams(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); + Indi_Alligator *alligator = new Indi_Alligator(iparams, iparams); Print("Alligator: ", alligator.GetValue(LINE_JAW)); delete alligator; @@ -103,8 +103,8 @@ Example using a static call: Example usage: IndicatorParams iparams; - Bands_Params params(20, 2, 0, PRICE_LOW); - Indi_Bands *bands = new Indi_Bands(params, iparams); + Bands_Params iparams(20, 2, 0, PRICE_LOW); + Indi_Bands *bands = new Indi_Bands(iparams, iparams); Print("Bands: ", bands.GetValue(BAND_BASE)); delete bands; @@ -117,12 +117,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - BearsPower_Params params(13, PRICE_CLOSE); - Indi_BearsPower *bp = new Indi_BearsPower(params, iparams); + BearsPower_Params iparams(13, PRICE_CLOSE); + Indi_BearsPower *bp = new Indi_BearsPower(iparams, iparams); Print("BearsPower: ", bp.GetValue()); delete bp; -Example changing params: +Example changing iparams: bp.SetPeriod(bp.GetPeriod()+1); bp.SetAppliedPrice(PRICE_MEDIAN); @@ -136,12 +136,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - BullsPower_Params params(13, PRICE_CLOSE); - Indi_BullsPower *bp = new Indi_BullsPower(params, iparams); + BullsPower_Params iparams(13, PRICE_CLOSE); + Indi_BullsPower *bp = new Indi_BullsPower(iparams, iparams); Print("BullsPower: ", bp.GetValue()); delete bp; -Example changing params: +Example changing iparams: bp.SetPeriod(bp.GetPeriod()+1); bp.SetAppliedPrice(PRICE_MEDIAN); @@ -155,12 +155,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - CCI_Params params(14, PRICE_CLOSE); - Indi_CCI *cci = new Indi_CCI(params, iparams); + CCI_Params iparams(14, PRICE_CLOSE); + Indi_CCI *cci = new Indi_CCI(iparams, iparams); Print("CCI: ", cci.GetValue()); delete cci; -Example changing params: +Example changing iparams: cci.SetPeriod(cci.GetPeriod()+1); @@ -173,27 +173,27 @@ Example using a static call: Example usage: IndicatorParams iparams; - DeMarker_Params params; - params.period = 14; - Indi_DeMarker *dm = new Indi_DeMarker(params, iparams); + DeMarker_Params iparams; + iparams.period = 14; + Indi_DeMarker *dm = new Indi_DeMarker(iparams, iparams); Print("DeMarker: ", dm.GetValue()); delete dm; Example using a static call: - double dm_value = Indi_DeMarker::iDeMarker(_Symbol, PERIOD_CURRENT, params.period); + double dm_value = Indi_DeMarker::iDeMarker(_Symbol, PERIOD_CURRENT, iparams.period); ## Envelopes Example usage: IndicatorParams iparams; - Envelopes_Params params(13, 0, MODE_SMA, PRICE_CLOSE, 2); - Indi_Envelopes *env = new Indi_Envelopes(params, iparams); + Envelopes_Params iparams(13, 0, MODE_SMA, PRICE_CLOSE, 2); + Indi_Envelopes *env = new Indi_Envelopes(iparams, iparams); Print("Envelopes: ", env.GetValue(LINE_UPPER)); delete env; -Example changing params: +Example changing iparams: env.SetMAPeriod(env.GetMAPeriod()+1); env.SetMAMethod(MODE_SMA); @@ -210,12 +210,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - Force_Params params(13, MODE_SMA, PRICE_CLOSE); - Indi_Force *force = new Indi_Force(params, iparams); + Force_Params iparams(13, MODE_SMA, PRICE_CLOSE); + Indi_Force *force = new Indi_Force(iparams, iparams); Print("Force: ", force.GetValue()); delete force; -Example changing params: +Example changing iparams: force.SetPeriod(force.GetPeriod()+1); force.SetMAMethod(MODE_SMA); @@ -243,12 +243,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - Gator_Params params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - Indi_Gator *gator = new Indi_Gator(params, iparams); + Gator_Params iparams(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); + Indi_Gator *gator = new Indi_Gator(iparams, iparams); Print("Gator: ", gator.GetValue(LINE_JAW)); delete gator; -Example changing params: +Example changing iparams: gator.SetJawPeriod(gator.GetJawPeriod()+1); gator.SetJawShift(gator.GetJawShift()+1); @@ -279,12 +279,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - Ichimoku_Params params(9, 26, 52); - Indi_Ichimoku *ichimoku = new Indi_Ichimoku(params, iparams); + Ichimoku_Params iparams(9, 26, 52); + Indi_Ichimoku *ichimoku = new Indi_Ichimoku(iparams, iparams); Print("Ichimoku: ", ichimoku.GetValue(LINE_TENKANSEN)); delete ichimoku; -Example changing params: +Example changing iparams: ichimoku.SetTenkanSen(ichimoku.GetTenkanSen()+1); ichimoku.SetKijunSen(ichimoku.GetKijunSen()+1); @@ -299,12 +299,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - MA_Params params(13, 10, MODE_SMA, PRICE_CLOSE); - Indi_MA *ma = new Indi_MA(params, iparams); + MA_Params iparams(13, 10, MODE_SMA, PRICE_CLOSE); + Indi_MA *ma = new Indi_MA(iparams, iparams); Print("MA: ", ma.GetValue()); delete ma; -Example changing params: +Example changing iparams: ma.SetPeriod(ma.GetPeriod()+1); ma.SetMAShift(ma.GetMAShift()+1); @@ -320,12 +320,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - MACD_Params params(12, 26, 9, PRICE_CLOSE); - Indi_MACD *macd = new Indi_MACD(params, iparams); + MACD_Params iparams(12, 26, 9, PRICE_CLOSE); + Indi_MACD *macd = new Indi_MACD(iparams, iparams); Print("MACD: ", macd.GetValue(LINE_MAIN)); delete macd; -Example changing params: +Example changing iparams: macd.SetEmaFastPeriod(macd.GetEmaFastPeriod()+1); macd.SetEmaSlowPeriod(macd.GetEmaSlowPeriod()+1); @@ -341,13 +341,13 @@ Example using a static call: Example usage: IndicatorParams iparams; - MFI_Params params; - params.ma_period = 14; - params.applied_volume = VOLUME_TICK; // Used in MT5 only. - Indi_MFI *mfi = new Indi_MFI(params, iparams); + MFI_Params iparams; + iparams.ma_period = 14; + iparams.applied_volume = VOLUME_TICK; // Used in MT5 only. + Indi_MFI *mfi = new Indi_MFI(iparams, iparams); Print("MFI: ", mfi.GetValue()); -Example changing params: +Example changing iparams: mfi.SetPeriod(mfi.GetPeriod()+1); mfi.SetAppliedVolume(VOLUME_REAL); @@ -361,12 +361,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - Momentum_Params params(12, PRICE_CLOSE); - Indi_Momentum *mom = new Indi_Momentum(params, iparams); + Momentum_Params iparams(12, PRICE_CLOSE); + Indi_Momentum *mom = new Indi_Momentum(iparams, iparams); Print("Momentum: ", mom.GetValue()); delete mom; -Example changing params: +Example changing iparams: mom.SetPeriod(mom.GetPeriod()+1); mom.SetAppliedPrice(PRICE_MEDIAN); @@ -380,14 +380,14 @@ Example using a static call: Example usage: IndicatorParams iparams; - OBV_Params params; - params.applied_price = PRICE_CLOSE; // Used in MT4. - params.applied_volume = VOLUME_TICK; // Used in MT5. - Indi_OBV *obv = new Indi_OBV(params, iparams); + OBV_Params iparams; + iparams.applied_price = PRICE_CLOSE; // Used in MT4. + iparams.applied_volume = VOLUME_TICK; // Used in MT5. + Indi_OBV *obv = new Indi_OBV(iparams, iparams); Print("OBV: ", obv.GetValue()); delete obv; -Example changing params: +Example changing iparams: obv.SetAppliedPrice(PRICE_MEDIAN); obv.SetAppliedVolume(VOLUME_REAL); @@ -401,13 +401,13 @@ Example using a static call: Example usage: IndicatorParams iparams; - OsMA_Params params(12, 26, 9, PRICE_CLOSE); - params.applied_price = PRICE_CLOSE; - Indi_OsMA *osma = new Indi_OsMA(params, iparams); + OsMA_Params iparams(12, 26, 9, PRICE_CLOSE); + iparams.applied_price = PRICE_CLOSE; + Indi_OsMA *osma = new Indi_OsMA(iparams, iparams); Print("OsMA: ", osma.GetValue()); delete osma; -Example changing params: +Example changing iparams: osma.SetEmaFastPeriod(osma.GetEmaFastPeriod()+1); osma.SetEmaSlowPeriod(osma.GetEmaSlowPeriod()+1); @@ -423,12 +423,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - RSI_Params params(14, PRICE_CLOSE); - Indi_RSI *rsi = new Indi_RSI(params, iparams); + RSI_Params iparams(14, PRICE_CLOSE); + Indi_RSI *rsi = new Indi_RSI(iparams, iparams); Print("RSI: ", rsi.GetValue()); delete rsi; -Example changing params: +Example changing iparams: rsi.SetPeriod(rsi.GetPeriod()+1); rsi.SetAppliedPrice(PRICE_MEDIAN); @@ -442,12 +442,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - RVI_Params params(14); - Indi_RVI *rvi = new Indi_RVI(params, iparams); + RVI_Params iparams(14); + Indi_RVI *rvi = new Indi_RVI(iparams, iparams); Print("RVI: ", rvi.GetValue(LINE_MAIN)); delete rvi; -Example changing params: +Example changing iparams: rvi.SetPeriod(rvi.GetPeriod()+1); @@ -460,12 +460,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - SAR_Params params(0.02, 0.2); - Indi_SAR *sar = new Indi_SAR(params, iparams); + SAR_Params iparams(0.02, 0.2); + Indi_SAR *sar = new Indi_SAR(iparams, iparams); Print("SAR: ", sar.GetValue()); delete sar; -Example changing params: +Example changing iparams: sar.SetStep(sar.GetStep()*2); sar.SetMax(sar.GetMax()*2); @@ -479,12 +479,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - StdDev_Params params(13, 10, MODE_SMA, PRICE_CLOSE); - Indi_StdDev *sd = new Indi_StdDev(params, iparams); + StdDev_Params iparams(13, 10, MODE_SMA, PRICE_CLOSE); + Indi_StdDev *sd = new Indi_StdDev(iparams, iparams); Print("StdDev: ", sd.GetValue()); delete sd; -Example changing params: +Example changing iparams: sd.SetPeriod(sd.GetPeriod()+1); sd.SetMAShift(sd.GetMAShift()+1); @@ -500,12 +500,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - Stoch_Params params(5, 3, 3, MODE_SMMA, STO_LOWHIGH); - Indi_Stochastic *stoch = new Indi_Stochastic(params, iparams); + Stoch_Params iparams(5, 3, 3, MODE_SMMA, STO_LOWHIGH); + Indi_Stochastic *stoch = new Indi_Stochastic(iparams, iparams); Print("Stochastic: ", stoch.GetValue()); delete stoch; -Example changing params: +Example changing iparams: stoch.SetKPeriod(stoch.GetKPeriod()+1); stoch.SetDPeriod(stoch.GetDPeriod()+1); @@ -522,12 +522,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - WPR_Params params(14); - Indi_WPR *wpr = new Indi_WPR(params, iparams); + WPR_Params iparams(14); + Indi_WPR *wpr = new Indi_WPR(iparams, iparams); Print("WPR: ", wpr.GetValue()); delete wpr; -Example changing params: +Example changing iparams: wpr.SetPeriod(wpr.GetPeriod()+1); @@ -540,12 +540,12 @@ Example using a static call: Example usage: IndicatorParams iparams; - ZigZag_Params params(12, 5, 3); - Indi_ZigZag *zz = new Indi_ZigZag(params, iparams); + ZigZag_Params iparams(12, 5, 3); + Indi_ZigZag *zz = new Indi_ZigZag(iparams, iparams); Print("ZigZag: ", zz.GetValue()); delete zz; -Example changing params: +Example changing iparams: zz.SetDepth(zz.GetDepth()+1); zz.SetDeviation(zz.GetDeviation()+1); diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index a200b149d..faba5f773 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -40,16 +40,13 @@ struct MathParams : IndicatorParams { unsigned int shift_2; // Struct constructor. - void MathParams(ENUM_MATH_OP _op = MATH_OP_SUB, unsigned int _mode_1 = 0, unsigned int _mode_2 = 1, - unsigned int _shift_1 = 0, unsigned int _shift_2 = 0, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_SPECIAL_MATH; - max_modes = 1; + MathParams(ENUM_MATH_OP _op = MATH_OP_SUB, unsigned int _mode_1 = 0, unsigned int _mode_2 = 1, + unsigned int _shift_1 = 0, unsigned int _shift_2 = 0, int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + : IndicatorParams(INDI_SPECIAL_MATH, 1, TYPE_DOUBLE) { mode_1 = _mode_1; mode_2 = _mode_2; op_builtin = _op; op_mode = MATH_OP_MODE_BUILTIN; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetDataSourceType(IDATA_INDICATOR); shift = _shift; @@ -59,16 +56,14 @@ struct MathParams : IndicatorParams { }; // Struct constructor. - void MathParams(MathCustomOpFunction _op, unsigned int _mode_1 = 0, unsigned int _mode_2 = 1, - unsigned int _shift_1 = 0, unsigned int _shift_2 = 0, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - itype = INDI_SPECIAL_MATH; + MathParams(MathCustomOpFunction _op, unsigned int _mode_1 = 0, unsigned int _mode_2 = 1, unsigned int _shift_1 = 0, + unsigned int _shift_2 = 0, int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + : IndicatorParams(INDI_SPECIAL_MATH, 1, TYPE_DOUBLE) { max_modes = 1; mode_1 = _mode_1; mode_2 = _mode_2; op_fn = _op; op_mode = MATH_OP_MODE_CUSTOM_FUNCTION; - SetDataValueType(TYPE_DOUBLE); SetDataValueRange(IDATA_RANGE_MIXED); SetDataSourceType(IDATA_INDICATOR); shift = _shift; @@ -76,9 +71,8 @@ struct MathParams : IndicatorParams { shift_2 = _shift_2; tf = _tf; }; - - void MathParams(MathParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - this = _params; + MathParams(MathParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; tf = _tf; }; }; @@ -86,26 +80,23 @@ struct MathParams : IndicatorParams { /** * Implements the Volume Rate of Change indicator. */ -class Indi_Math : public Indicator { - protected: - MathParams params; - +class Indi_Math : public Indicator { public: /** * Class constructor. */ - Indi_Math(MathParams &_params) : Indicator((IndicatorParams)_params) { params = _params; }; - Indi_Math(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_SPECIAL_MATH, _tf) { params.tf = _tf; }; + Indi_Math(MathParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_Math(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_SPECIAL_MATH, _tf){}; /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual double GetValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; - switch (params.idstype) { + switch (iparams.idstype) { case IDATA_INDICATOR: - if (GetDataSource() == NULL) { + if (indi_src == NULL) { GetLogger().Error( "In order use custom indicator as a source, you need to select one using SetIndicatorData() method, " "which is a part of MathParams structure.", @@ -116,15 +107,15 @@ class Indi_Math : public Indicator { SetUserError(ERR_INVALID_PARAMETER); return _value; } - switch (params.op_mode) { + switch (iparams.op_mode) { case MATH_OP_MODE_BUILTIN: _value = Indi_Math::iMathOnIndicator( - GetDataSource(), Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), + indi_src, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), /*[*/ GetOpBuiltIn(), GetMode1(), GetMode2(), GetShift1(), GetShift2() /*]*/, 0, _shift, &this); break; case MATH_OP_MODE_CUSTOM_FUNCTION: _value = Indi_Math::iMathOnIndicator( - GetDataSource(), Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), + indi_src, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), /*[*/ GetOpFunction(), GetMode1(), GetMode2(), GetShift1(), GetShift2() /*]*/, 0, _shift, &this); break; } @@ -137,29 +128,6 @@ class Indi_Math : public Indicator { return _value; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(params.max_modes); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - for (int _mode = 0; _mode < (int)params.max_modes; _mode++) { - _entry.values[_mode] = GetValue(_mode, _shift); - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, !_entry.HasValue(NULL) && !_entry.HasValue(EMPTY_VALUE)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(params.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - } - return _entry; - } - /** * Returns the indicator's entry value. */ @@ -169,17 +137,17 @@ class Indi_Math : public Indicator { return _param; } - static double iMathOnIndicator(Indicator *_indi, string _symbol, ENUM_TIMEFRAMES _tf, ENUM_MATH_OP op, + static double iMathOnIndicator(IndicatorBase *_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, Indicator *_obj) { + unsigned int _shift_2, unsigned int _mode, int _shift, Indi_Math *_obj) { double _val_1 = _indi.GetValue(_shift_1, _mode_1); double _val_2 = _indi.GetValue(_shift_2, _mode_2); return Math::Op(op, _val_1, _val_2); } - static double iMathOnIndicator(Indicator *_indi, string _symbol, ENUM_TIMEFRAMES _tf, MathCustomOpFunction _op, + static double iMathOnIndicator(IndicatorBase *_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, Indicator *_obj) { + unsigned int _shift_2, unsigned int _mode, int _shift, Indi_Math *_obj) { double _val_1 = _indi.GetValue(_shift_1, _mode_1); double _val_2 = _indi.GetValue(_shift_2, _mode_2); return _op(_val_1, _val_2); @@ -190,32 +158,32 @@ class Indi_Math : public Indicator { /** * Get math operation. */ - ENUM_MATH_OP GetOpBuiltIn() { return params.op_builtin; } + ENUM_MATH_OP GetOpBuiltIn() { return iparams.op_builtin; } /** * Get math operation. */ - MathCustomOpFunction GetOpFunction() { return params.op_fn; } + MathCustomOpFunction GetOpFunction() { return iparams.op_fn; } /** * Get mode 1. */ - unsigned int GetMode1() { return params.mode_1; } + unsigned int GetMode1() { return iparams.mode_1; } /** * Get mode 2. */ - unsigned int GetMode2() { return params.mode_2; } + unsigned int GetMode2() { return iparams.mode_2; } /** * Get shift 1. */ - unsigned int GetShift1() { return params.shift_1; } + unsigned int GetShift1() { return iparams.shift_1; } /** * Get shift 2. */ - unsigned int GetShift2() { return params.shift_2; } + unsigned int GetShift2() { return iparams.shift_2; } /* Setters */ @@ -224,8 +192,8 @@ class Indi_Math : public Indicator { */ void SetOp(ENUM_MATH_OP _op) { istate.is_changed = true; - params.op_builtin = _op; - params.op_mode = MATH_OP_MODE_BUILTIN; + iparams.op_builtin = _op; + iparams.op_mode = MATH_OP_MODE_BUILTIN; } /** @@ -233,8 +201,8 @@ class Indi_Math : public Indicator { */ void SetOp(MathCustomOpFunction _op) { istate.is_changed = true; - params.op_fn = _op; - params.op_mode = MATH_OP_MODE_CUSTOM_FUNCTION; + iparams.op_fn = _op; + iparams.op_mode = MATH_OP_MODE_CUSTOM_FUNCTION; } /** @@ -242,7 +210,7 @@ class Indi_Math : public Indicator { */ void SetMode1(unsigned int _mode_1) { istate.is_changed = true; - params.mode_1 = _mode_1; + iparams.mode_1 = _mode_1; } /** @@ -250,7 +218,7 @@ class Indi_Math : public Indicator { */ void SetMode2(unsigned int _mode_2) { istate.is_changed = true; - params.mode_2 = _mode_2; + iparams.mode_2 = _mode_2; } /** @@ -258,7 +226,7 @@ class Indi_Math : public Indicator { */ void SetShift1(unsigned int _shift_1) { istate.is_changed = true; - params.shift_1 = _shift_1; + iparams.shift_1 = _shift_1; } /** @@ -266,7 +234,7 @@ class Indi_Math : public Indicator { */ void SetShift3(unsigned int _shift_2) { istate.is_changed = true; - params.shift_2 = _shift_2; + iparams.shift_2 = _shift_2; } /** diff --git a/Indicators/indicators.h b/Indicators/indicators.h index d6325d453..3257db5d4 100644 --- a/Indicators/indicators.h +++ b/Indicators/indicators.h @@ -32,10 +32,10 @@ #include "Indi_ADXW.mqh" #include "Indi_AMA.mqh" #include "Indi_AO.mqh" -#include "Indi_Alligator.mqh" -#include "Indi_AppliedPrice.mqh" #include "Indi_ASI.mqh" #include "Indi_ATR.mqh" +#include "Indi_Alligator.mqh" +#include "Indi_AppliedPrice.mqh" #include "Indi_BWMFI.mqh" #include "Indi_BWZT.mqh" #include "Indi_Bands.mqh" diff --git a/Indicators/tests/Indi_AppliedPrice.test.mq5 b/Indicators/tests/Indi_AppliedPrice.test.mq5 index df8173f45..e635ac3b6 100644 --- a/Indicators/tests/Indi_AppliedPrice.test.mq5 +++ b/Indicators/tests/Indi_AppliedPrice.test.mq5 @@ -22,20 +22,23 @@ // Includes. #include "../../Test.mqh" #include "../Indi_AppliedPrice.mqh" +#include "../Indi_Price.mqh" /** * @file * Test functionality of Indi_AppliedPrice indicator class. */ -Indi_AppliedPrice indi(PERIOD_CURRENT); +Indi_Price *indi_source_price = new Indi_Price(); +AppliedPriceParams indi_params(); +Ref indi = new Indi_AppliedPrice(indi_params, indi_source_price); /** * Implements Init event handler. */ int OnInit() { bool _result = true; - assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + assertTrueOrFail(indi.IsSet(), "Error on IsSet!"); // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); } @@ -50,7 +53,7 @@ void OnTick() { // Process ticks each minute. if (_tick_new.time % 3600 < _tick_last.time % 3600) { // Print indicator values every hour. - Print(indi.ToString()); + Print(indi.Ptr().ToString()); } } _tick_last = _tick_new; diff --git a/Indicators/tests/Indi_BWMFI.test.mq4 b/Indicators/tests/Indi_BWMFI.test.mq4 new file mode 100644 index 000000000..3db17f482 --- /dev/null +++ b/Indicators/tests/Indi_BWMFI.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_BWMFI indicator class. + */ + +#include "Indi_BWMFI.test.mq5" diff --git a/Indicators/tests/Indi_BWMFI.test.mq5 b/Indicators/tests/Indi_BWMFI.test.mq5 new file mode 100644 index 000000000..a5229b301 --- /dev/null +++ b/Indicators/tests/Indi_BWMFI.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_BWMFI.mqh" + +/** + * @file + * Test functionality of Indi_BWMFI indicator class. + */ + +Indi_BWMFI indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_BWZT.test.mq4 b/Indicators/tests/Indi_BWZT.test.mq4 new file mode 100644 index 000000000..63b312f58 --- /dev/null +++ b/Indicators/tests/Indi_BWZT.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_BWZT indicator class. + */ + +#include "Indi_BWZT.test.mq5" diff --git a/Indicators/tests/Indi_BWZT.test.mq5 b/Indicators/tests/Indi_BWZT.test.mq5 new file mode 100644 index 000000000..3f9737520 --- /dev/null +++ b/Indicators/tests/Indi_BWZT.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_BWZT.mqh" + +/** + * @file + * Test functionality of Indi_BWZT indicator class. + */ + +Indi_BWZT indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Bands.test.mq4 b/Indicators/tests/Indi_Bands.test.mq4 new file mode 100644 index 000000000..78e550018 --- /dev/null +++ b/Indicators/tests/Indi_Bands.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_Bands indicator class. + */ + +#include "Indi_Bands.test.mq5" diff --git a/Indicators/tests/Indi_Bands.test.mq5 b/Indicators/tests/Indi_Bands.test.mq5 new file mode 100644 index 000000000..0fba23043 --- /dev/null +++ b/Indicators/tests/Indi_Bands.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Bands.mqh" + +/** + * @file + * Test functionality of Indi_Bands indicator class. + */ + +Indi_Bands indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_BearsPower.test.mq4 b/Indicators/tests/Indi_BearsPower.test.mq4 new file mode 100644 index 000000000..8d43b3c60 --- /dev/null +++ b/Indicators/tests/Indi_BearsPower.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_BearsPower indicator class. + */ + +#include "Indi_BearsPower.test.mq5" diff --git a/Indicators/tests/Indi_BearsPower.test.mq5 b/Indicators/tests/Indi_BearsPower.test.mq5 new file mode 100644 index 000000000..d75d399b1 --- /dev/null +++ b/Indicators/tests/Indi_BearsPower.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_BearsPower.mqh" + +/** + * @file + * Test functionality of Indi_BearsPower indicator class. + */ + +Indi_BearsPower indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_BullsPower.test.mq4 b/Indicators/tests/Indi_BullsPower.test.mq4 new file mode 100644 index 000000000..d9fc05869 --- /dev/null +++ b/Indicators/tests/Indi_BullsPower.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_BullsPower indicator class. + */ + +#include "Indi_BullsPower.test.mq5" diff --git a/Indicators/tests/Indi_BullsPower.test.mq5 b/Indicators/tests/Indi_BullsPower.test.mq5 new file mode 100644 index 000000000..6daa8d462 --- /dev/null +++ b/Indicators/tests/Indi_BullsPower.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_BullsPower.mqh" + +/** + * @file + * Test functionality of Indi_BullsPower indicator class. + */ + +Indi_BullsPower indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_CCI.test.mq4 b/Indicators/tests/Indi_CCI.test.mq4 new file mode 100644 index 000000000..309271938 --- /dev/null +++ b/Indicators/tests/Indi_CCI.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_CCI indicator class. + */ + +#include "Indi_CCI.test.mq5" diff --git a/Indicators/tests/Indi_CCI.test.mq5 b/Indicators/tests/Indi_CCI.test.mq5 new file mode 100644 index 000000000..cf632abb0 --- /dev/null +++ b/Indicators/tests/Indi_CCI.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_CCI.mqh" + +/** + * @file + * Test functionality of Indi_CCI indicator class. + */ + +Indi_CCI indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_CHO.test.mq4 b/Indicators/tests/Indi_CHO.test.mq4 new file mode 100644 index 000000000..11acc3005 --- /dev/null +++ b/Indicators/tests/Indi_CHO.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_CHO indicator class. + */ + +#include "Indi_CHO.test.mq5" diff --git a/Indicators/tests/Indi_CHO.test.mq5 b/Indicators/tests/Indi_CHO.test.mq5 new file mode 100644 index 000000000..f02148a36 --- /dev/null +++ b/Indicators/tests/Indi_CHO.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_CHO.mqh" + +/** + * @file + * Test functionality of Indi_CHO indicator class. + */ + +Indi_CHO indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_CHV.test.mq4 b/Indicators/tests/Indi_CHV.test.mq4 new file mode 100644 index 000000000..e190dc77d --- /dev/null +++ b/Indicators/tests/Indi_CHV.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_CHV indicator class. + */ + +#include "Indi_CHV.test.mq5" diff --git a/Indicators/tests/Indi_CHV.test.mq5 b/Indicators/tests/Indi_CHV.test.mq5 new file mode 100644 index 000000000..6019bcad4 --- /dev/null +++ b/Indicators/tests/Indi_CHV.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_CHV.mqh" + +/** + * @file + * Test functionality of Indi_CHV indicator class. + */ + +Indi_CHV indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_ColorBars.test.mq4 b/Indicators/tests/Indi_ColorBars.test.mq4 new file mode 100644 index 000000000..0858213d2 --- /dev/null +++ b/Indicators/tests/Indi_ColorBars.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_ColorBars indicator class. + */ + +#include "Indi_ColorBars.test.mq5" diff --git a/Indicators/tests/Indi_ColorBars.test.mq5 b/Indicators/tests/Indi_ColorBars.test.mq5 new file mode 100644 index 000000000..6fb4ff8fc --- /dev/null +++ b/Indicators/tests/Indi_ColorBars.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_ColorBars.mqh" + +/** + * @file + * Test functionality of Indi_ColorBars indicator class. + */ + +Indi_ColorBars indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_ColorCandlesDaily.test.mq4 b/Indicators/tests/Indi_ColorCandlesDaily.test.mq4 new file mode 100644 index 000000000..d77adc574 --- /dev/null +++ b/Indicators/tests/Indi_ColorCandlesDaily.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_ColorCandlesDaily indicator class. + */ + +#include "Indi_ColorCandlesDaily.test.mq5" diff --git a/Indicators/tests/Indi_ColorCandlesDaily.test.mq5 b/Indicators/tests/Indi_ColorCandlesDaily.test.mq5 new file mode 100644 index 000000000..75aad77ab --- /dev/null +++ b/Indicators/tests/Indi_ColorCandlesDaily.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_ColorCandlesDaily.mqh" + +/** + * @file + * Test functionality of Indi_ColorCandlesDaily indicator class. + */ + +Indi_ColorCandlesDaily indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_ColorLine.test.mq4 b/Indicators/tests/Indi_ColorLine.test.mq4 new file mode 100644 index 000000000..0199b7560 --- /dev/null +++ b/Indicators/tests/Indi_ColorLine.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_ColorLine indicator class. + */ + +#include "Indi_ColorLine.test.mq5" diff --git a/Indicators/tests/Indi_ColorLine.test.mq5 b/Indicators/tests/Indi_ColorLine.test.mq5 new file mode 100644 index 000000000..3516f1d6b --- /dev/null +++ b/Indicators/tests/Indi_ColorLine.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_ColorLine.mqh" + +/** + * @file + * Test functionality of Indi_ColorLine indicator class. + */ + +Indi_ColorLine indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_CustomMovingAverage.test.mq4 b/Indicators/tests/Indi_CustomMovingAverage.test.mq4 new file mode 100644 index 000000000..b42e19e49 --- /dev/null +++ b/Indicators/tests/Indi_CustomMovingAverage.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_CustomMovingAverage indicator class. + */ + +#include "Indi_CustomMovingAverage.test.mq5" diff --git a/Indicators/tests/Indi_CustomMovingAverage.test.mq5 b/Indicators/tests/Indi_CustomMovingAverage.test.mq5 new file mode 100644 index 000000000..952d5ae9e --- /dev/null +++ b/Indicators/tests/Indi_CustomMovingAverage.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_CustomMovingAverage.mqh" + +/** + * @file + * Test functionality of Indi_CustomMovingAverage indicator class. + */ + +Indi_CustomMovingAverage indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_DEMA.test.mq4 b/Indicators/tests/Indi_DEMA.test.mq4 new file mode 100644 index 000000000..c2a168889 --- /dev/null +++ b/Indicators/tests/Indi_DEMA.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_DEMA indicator class. + */ + +#include "Indi_DEMA.test.mq5" diff --git a/Indicators/tests/Indi_DEMA.test.mq5 b/Indicators/tests/Indi_DEMA.test.mq5 new file mode 100644 index 000000000..b6b4fe929 --- /dev/null +++ b/Indicators/tests/Indi_DEMA.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_DEMA.mqh" + +/** + * @file + * Test functionality of Indi_DEMA indicator class. + */ + +Indi_DEMA indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_DeMarker.test.mq4 b/Indicators/tests/Indi_DeMarker.test.mq4 new file mode 100644 index 000000000..cc63b04c8 --- /dev/null +++ b/Indicators/tests/Indi_DeMarker.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_DeMarker indicator class. + */ + +#include "Indi_DeMarker.test.mq5" diff --git a/Indicators/tests/Indi_DeMarker.test.mq5 b/Indicators/tests/Indi_DeMarker.test.mq5 new file mode 100644 index 000000000..b6abf6db0 --- /dev/null +++ b/Indicators/tests/Indi_DeMarker.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_DeMarker.mqh" + +/** + * @file + * Test functionality of Indi_DeMarker indicator class. + */ + +Indi_DeMarker indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Demo.test.mq4 b/Indicators/tests/Indi_Demo.test.mq4 new file mode 100644 index 000000000..d5056995e --- /dev/null +++ b/Indicators/tests/Indi_Demo.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_Demo indicator class. + */ + +#include "Indi_Demo.test.mq5" diff --git a/Indicators/tests/Indi_Demo.test.mq5 b/Indicators/tests/Indi_Demo.test.mq5 new file mode 100644 index 000000000..368d72d2a --- /dev/null +++ b/Indicators/tests/Indi_Demo.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Demo.mqh" + +/** + * @file + * Test functionality of Indi_Demo indicator class. + */ + +Indi_Demo indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_DetrendedPrice.test.mq4 b/Indicators/tests/Indi_DetrendedPrice.test.mq4 new file mode 100644 index 000000000..297f2c81a --- /dev/null +++ b/Indicators/tests/Indi_DetrendedPrice.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_DetrendedPrice indicator class. + */ + +#include "Indi_DetrendedPrice.test.mq5" diff --git a/Indicators/tests/Indi_DetrendedPrice.test.mq5 b/Indicators/tests/Indi_DetrendedPrice.test.mq5 new file mode 100644 index 000000000..b40a1f9f8 --- /dev/null +++ b/Indicators/tests/Indi_DetrendedPrice.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_DetrendedPrice.mqh" + +/** + * @file + * Test functionality of Indi_DetrendedPrice indicator class. + */ + +Indi_DetrendedPrice indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Drawer.test.mq4 b/Indicators/tests/Indi_Drawer.test.mq4 new file mode 100644 index 000000000..32cf4a1e2 --- /dev/null +++ b/Indicators/tests/Indi_Drawer.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_Drawer indicator class. + */ + +#include "Indi_Drawer.test.mq5" diff --git a/Indicators/tests/Indi_Drawer.test.mq5 b/Indicators/tests/Indi_Drawer.test.mq5 new file mode 100644 index 000000000..178a25fe8 --- /dev/null +++ b/Indicators/tests/Indi_Drawer.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Drawer.mqh" + +/** + * @file + * Test functionality of Indi_Drawer indicator class. + */ + +Indi_Drawer indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Envelopes.test.mq4 b/Indicators/tests/Indi_Envelopes.test.mq4 new file mode 100644 index 000000000..af9885c8e --- /dev/null +++ b/Indicators/tests/Indi_Envelopes.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_Envelopes indicator class. + */ + +#include "Indi_Envelopes.test.mq5" diff --git a/Indicators/tests/Indi_Envelopes.test.mq5 b/Indicators/tests/Indi_Envelopes.test.mq5 new file mode 100644 index 000000000..ff468b16e --- /dev/null +++ b/Indicators/tests/Indi_Envelopes.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Envelopes.mqh" + +/** + * @file + * Test functionality of Indi_Envelopes indicator class. + */ + +Indi_Envelopes indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Force.test.mq4 b/Indicators/tests/Indi_Force.test.mq4 new file mode 100644 index 000000000..aefa93e28 --- /dev/null +++ b/Indicators/tests/Indi_Force.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_Force indicator class. + */ + +#include "Indi_Force.test.mq5" diff --git a/Indicators/tests/Indi_Force.test.mq5 b/Indicators/tests/Indi_Force.test.mq5 new file mode 100644 index 000000000..bfd0d97d7 --- /dev/null +++ b/Indicators/tests/Indi_Force.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Force.mqh" + +/** + * @file + * Test functionality of Indi_Force indicator class. + */ + +Indi_Force indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_FractalAdaptiveMA.test.mq4 b/Indicators/tests/Indi_FractalAdaptiveMA.test.mq4 new file mode 100644 index 000000000..1073b537d --- /dev/null +++ b/Indicators/tests/Indi_FractalAdaptiveMA.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_FractalAdaptiveMA indicator class. + */ + +#include "Indi_FractalAdaptiveMA.test.mq5" diff --git a/Indicators/tests/Indi_FractalAdaptiveMA.test.mq5 b/Indicators/tests/Indi_FractalAdaptiveMA.test.mq5 new file mode 100644 index 000000000..9b8555261 --- /dev/null +++ b/Indicators/tests/Indi_FractalAdaptiveMA.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_FractalAdaptiveMA.mqh" + +/** + * @file + * Test functionality of Indi_FractalAdaptiveMA indicator class. + */ + +Indi_FrAMA indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Fractals.test.mq4 b/Indicators/tests/Indi_Fractals.test.mq4 new file mode 100644 index 000000000..74575bfef --- /dev/null +++ b/Indicators/tests/Indi_Fractals.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_Fractals indicator class. + */ + +#include "Indi_Fractals.test.mq5" diff --git a/Indicators/tests/Indi_Fractals.test.mq5 b/Indicators/tests/Indi_Fractals.test.mq5 new file mode 100644 index 000000000..2a441ca5c --- /dev/null +++ b/Indicators/tests/Indi_Fractals.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Fractals.mqh" + +/** + * @file + * Test functionality of Indi_Fractals indicator class. + */ + +Indi_Fractals indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Gator.test.mq4 b/Indicators/tests/Indi_Gator.test.mq4 new file mode 100644 index 000000000..017e97229 --- /dev/null +++ b/Indicators/tests/Indi_Gator.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_Gator indicator class. + */ + +#include "Indi_Gator.test.mq5" diff --git a/Indicators/tests/Indi_Gator.test.mq5 b/Indicators/tests/Indi_Gator.test.mq5 new file mode 100644 index 000000000..325623c1f --- /dev/null +++ b/Indicators/tests/Indi_Gator.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Gator.mqh" + +/** + * @file + * Test functionality of Indi_Gator indicator class. + */ + +Indi_Gator indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_HeikenAshi.test.mq4 b/Indicators/tests/Indi_HeikenAshi.test.mq4 new file mode 100644 index 000000000..7412e5399 --- /dev/null +++ b/Indicators/tests/Indi_HeikenAshi.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_HeikenAshi indicator class. + */ + +#include "Indi_HeikenAshi.test.mq5" diff --git a/Indicators/tests/Indi_HeikenAshi.test.mq5 b/Indicators/tests/Indi_HeikenAshi.test.mq5 new file mode 100644 index 000000000..8f5dd357d --- /dev/null +++ b/Indicators/tests/Indi_HeikenAshi.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_HeikenAshi.mqh" + +/** + * @file + * Test functionality of Indi_HeikenAshi indicator class. + */ + +Indi_HeikenAshi indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Ichimoku.test.mq4 b/Indicators/tests/Indi_Ichimoku.test.mq4 new file mode 100644 index 000000000..942b84bd7 --- /dev/null +++ b/Indicators/tests/Indi_Ichimoku.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_Ichimoku indicator class. + */ + +#include "Indi_Ichimoku.test.mq5" diff --git a/Indicators/tests/Indi_Ichimoku.test.mq5 b/Indicators/tests/Indi_Ichimoku.test.mq5 new file mode 100644 index 000000000..8325c0b14 --- /dev/null +++ b/Indicators/tests/Indi_Ichimoku.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Ichimoku.mqh" + +/** + * @file + * Test functionality of Indi_Ichimoku indicator class. + */ + +Indi_Ichimoku indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Killzones.test.mq4 b/Indicators/tests/Indi_Killzones.test.mq4 new file mode 100644 index 000000000..12f792f2c --- /dev/null +++ b/Indicators/tests/Indi_Killzones.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_Killzones indicator class. + */ + +#include "Indi_Killzones.test.mq5" diff --git a/Indicators/tests/Indi_Killzones.test.mq5 b/Indicators/tests/Indi_Killzones.test.mq5 new file mode 100644 index 000000000..d925e3e0c --- /dev/null +++ b/Indicators/tests/Indi_Killzones.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Killzones.mqh" + +/** + * @file + * Test functionality of Indi_Killzones indicator class. + */ + +Indi_Killzones indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString(1)); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_MA.test.mq4 b/Indicators/tests/Indi_MA.test.mq4 new file mode 100644 index 000000000..89d4ee4b4 --- /dev/null +++ b/Indicators/tests/Indi_MA.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_MA indicator class. + */ + +#include "Indi_MA.test.mq5" diff --git a/Indicators/tests/Indi_MA.test.mq5 b/Indicators/tests/Indi_MA.test.mq5 new file mode 100644 index 000000000..8c84ef55e --- /dev/null +++ b/Indicators/tests/Indi_MA.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_MA.mqh" + +/** + * @file + * Test functionality of Indi_MA indicator class. + */ + +Indi_MA indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_MACD.test.mq4 b/Indicators/tests/Indi_MACD.test.mq4 new file mode 100644 index 000000000..e03f0a44b --- /dev/null +++ b/Indicators/tests/Indi_MACD.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_MACD indicator class. + */ + +#include "Indi_MACD.test.mq5" diff --git a/Indicators/tests/Indi_MACD.test.mq5 b/Indicators/tests/Indi_MACD.test.mq5 new file mode 100644 index 000000000..a8f664f1c --- /dev/null +++ b/Indicators/tests/Indi_MACD.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_MACD.mqh" + +/** + * @file + * Test functionality of Indi_MACD indicator class. + */ + +Indi_MACD indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_MFI.test.mq4 b/Indicators/tests/Indi_MFI.test.mq4 new file mode 100644 index 000000000..d6e3a1c9e --- /dev/null +++ b/Indicators/tests/Indi_MFI.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_MFI indicator class. + */ + +#include "Indi_MFI.test.mq5" diff --git a/Indicators/tests/Indi_MFI.test.mq5 b/Indicators/tests/Indi_MFI.test.mq5 new file mode 100644 index 000000000..812533deb --- /dev/null +++ b/Indicators/tests/Indi_MFI.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_MFI.mqh" + +/** + * @file + * Test functionality of Indi_MFI indicator class. + */ + +Indi_MFI indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_MassIndex.test.mq4 b/Indicators/tests/Indi_MassIndex.test.mq4 new file mode 100644 index 000000000..9a53fa65f --- /dev/null +++ b/Indicators/tests/Indi_MassIndex.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_MassIndex indicator class. + */ + +#include "Indi_MassIndex.test.mq5" diff --git a/Indicators/tests/Indi_MassIndex.test.mq5 b/Indicators/tests/Indi_MassIndex.test.mq5 new file mode 100644 index 000000000..6c9117aa3 --- /dev/null +++ b/Indicators/tests/Indi_MassIndex.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_MassIndex.mqh" + +/** + * @file + * Test functionality of Indi_MassIndex indicator class. + */ + +Indi_MassIndex indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Momentum.test.mq4 b/Indicators/tests/Indi_Momentum.test.mq4 new file mode 100644 index 000000000..31fb68c33 --- /dev/null +++ b/Indicators/tests/Indi_Momentum.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_Momentum indicator class. + */ + +#include "Indi_Momentum.test.mq5" diff --git a/Indicators/tests/Indi_Momentum.test.mq5 b/Indicators/tests/Indi_Momentum.test.mq5 new file mode 100644 index 000000000..0c916fa9e --- /dev/null +++ b/Indicators/tests/Indi_Momentum.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Momentum.mqh" + +/** + * @file + * Test functionality of Indi_Momentum indicator class. + */ + +Indi_Momentum indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_OBV.test.mq4 b/Indicators/tests/Indi_OBV.test.mq4 new file mode 100644 index 000000000..372045b77 --- /dev/null +++ b/Indicators/tests/Indi_OBV.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_OBV indicator class. + */ + +#include "Indi_OBV.test.mq5" diff --git a/Indicators/tests/Indi_OBV.test.mq5 b/Indicators/tests/Indi_OBV.test.mq5 new file mode 100644 index 000000000..ce78cee3a --- /dev/null +++ b/Indicators/tests/Indi_OBV.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_OBV.mqh" + +/** + * @file + * Test functionality of Indi_OBV indicator class. + */ + +Indi_OBV indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_OsMA.test.mq4 b/Indicators/tests/Indi_OsMA.test.mq4 new file mode 100644 index 000000000..476dfe415 --- /dev/null +++ b/Indicators/tests/Indi_OsMA.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_OsMA indicator class. + */ + +#include "Indi_OsMA.test.mq5" diff --git a/Indicators/tests/Indi_OsMA.test.mq5 b/Indicators/tests/Indi_OsMA.test.mq5 new file mode 100644 index 000000000..9139c108b --- /dev/null +++ b/Indicators/tests/Indi_OsMA.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_OsMA.mqh" + +/** + * @file + * Test functionality of Indi_OsMA indicator class. + */ + +Indi_OsMA indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Pattern.test.mq4 b/Indicators/tests/Indi_Pattern.test.mq4 new file mode 100644 index 000000000..155c7b60a --- /dev/null +++ b/Indicators/tests/Indi_Pattern.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_Pattern indicator class. + */ + +#include "Indi_Pattern.test.mq5" diff --git a/Indicators/tests/Indi_Pattern.test.mq5 b/Indicators/tests/Indi_Pattern.test.mq5 new file mode 100644 index 000000000..88fd982b7 --- /dev/null +++ b/Indicators/tests/Indi_Pattern.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Pattern.mqh" + +/** + * @file + * Test functionality of Indi_Pattern indicator class. + */ + +Indi_Pattern indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Price.test.mq4 b/Indicators/tests/Indi_Price.test.mq4 new file mode 100644 index 000000000..5f07803bc --- /dev/null +++ b/Indicators/tests/Indi_Price.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_Price indicator class. + */ + +#include "Indi_Price.test.mq5" diff --git a/Indicators/tests/Indi_Price.test.mq5 b/Indicators/tests/Indi_Price.test.mq5 new file mode 100644 index 000000000..c05b54743 --- /dev/null +++ b/Indicators/tests/Indi_Price.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Price.mqh" + +/** + * @file + * Test functionality of Indi_Price indicator class. + */ + +Indi_Price indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_PriceChannel.test.mq4 b/Indicators/tests/Indi_PriceChannel.test.mq4 new file mode 100644 index 000000000..23b54fa5e --- /dev/null +++ b/Indicators/tests/Indi_PriceChannel.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_PriceChannel indicator class. + */ + +#include "Indi_PriceChannel.test.mq5" diff --git a/Indicators/tests/Indi_PriceChannel.test.mq5 b/Indicators/tests/Indi_PriceChannel.test.mq5 new file mode 100644 index 000000000..46cdaf509 --- /dev/null +++ b/Indicators/tests/Indi_PriceChannel.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_PriceChannel.mqh" + +/** + * @file + * Test functionality of Indi_PriceChannel indicator class. + */ + +Indi_PriceChannel indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_PriceFeeder.test.mq4 b/Indicators/tests/Indi_PriceFeeder.test.mq4 new file mode 100644 index 000000000..6976c01ec --- /dev/null +++ b/Indicators/tests/Indi_PriceFeeder.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_PriceFeeder indicator class. + */ + +#include "Indi_PriceFeeder.test.mq5" diff --git a/Indicators/tests/Indi_PriceFeeder.test.mq5 b/Indicators/tests/Indi_PriceFeeder.test.mq5 new file mode 100644 index 000000000..c4626b0e6 --- /dev/null +++ b/Indicators/tests/Indi_PriceFeeder.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_PriceFeeder.mqh" + +/** + * @file + * Test functionality of Indi_PriceFeeder indicator class. + */ + +Indi_PriceFeeder indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_PriceVolumeTrend.test.mq4 b/Indicators/tests/Indi_PriceVolumeTrend.test.mq4 new file mode 100644 index 000000000..45a6e2c09 --- /dev/null +++ b/Indicators/tests/Indi_PriceVolumeTrend.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_PriceVolumeTrend indicator class. + */ + +#include "Indi_PriceVolumeTrend.test.mq5" diff --git a/Indicators/tests/Indi_PriceVolumeTrend.test.mq5 b/Indicators/tests/Indi_PriceVolumeTrend.test.mq5 new file mode 100644 index 000000000..5108b95e8 --- /dev/null +++ b/Indicators/tests/Indi_PriceVolumeTrend.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_PriceVolumeTrend.mqh" + +/** + * @file + * Test functionality of Indi_PriceVolumeTrend indicator class. + */ + +Indi_PriceVolumeTrend indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_RS.test.mq4 b/Indicators/tests/Indi_RS.test.mq4 new file mode 100644 index 000000000..5f191c9ea --- /dev/null +++ b/Indicators/tests/Indi_RS.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_RS indicator class. + */ + +#include "Indi_RS.test.mq5" diff --git a/Indicators/tests/Indi_RS.test.mq5 b/Indicators/tests/Indi_RS.test.mq5 new file mode 100644 index 000000000..cd78f2036 --- /dev/null +++ b/Indicators/tests/Indi_RS.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_RS.mqh" + +/** + * @file + * Test functionality of Indi_RS indicator class. + */ + +Indi_RS indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_RSI.test.mq4 b/Indicators/tests/Indi_RSI.test.mq4 new file mode 100644 index 000000000..b7f5e55d3 --- /dev/null +++ b/Indicators/tests/Indi_RSI.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_RSI indicator class. + */ + +#include "Indi_RSI.test.mq5" diff --git a/Indicators/tests/Indi_RSI.test.mq5 b/Indicators/tests/Indi_RSI.test.mq5 new file mode 100644 index 000000000..d40fd5e8b --- /dev/null +++ b/Indicators/tests/Indi_RSI.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_RSI.mqh" + +/** + * @file + * Test functionality of Indi_RSI indicator class. + */ + +Indi_RSI indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_RVI.test.mq4 b/Indicators/tests/Indi_RVI.test.mq4 new file mode 100644 index 000000000..cfd5e372f --- /dev/null +++ b/Indicators/tests/Indi_RVI.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_RVI indicator class. + */ + +#include "Indi_RVI.test.mq5" diff --git a/Indicators/tests/Indi_RVI.test.mq5 b/Indicators/tests/Indi_RVI.test.mq5 new file mode 100644 index 000000000..0cebe859b --- /dev/null +++ b/Indicators/tests/Indi_RVI.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_RVI.mqh" + +/** + * @file + * Test functionality of Indi_RVI indicator class. + */ + +Indi_RVI indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_RateOfChange.test.mq4 b/Indicators/tests/Indi_RateOfChange.test.mq4 new file mode 100644 index 000000000..6ca89fbef --- /dev/null +++ b/Indicators/tests/Indi_RateOfChange.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_RateOfChange indicator class. + */ + +#include "Indi_RateOfChange.test.mq5" diff --git a/Indicators/tests/Indi_RateOfChange.test.mq5 b/Indicators/tests/Indi_RateOfChange.test.mq5 new file mode 100644 index 000000000..e7cc7a024 --- /dev/null +++ b/Indicators/tests/Indi_RateOfChange.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_RateOfChange.mqh" + +/** + * @file + * Test functionality of Indi_RateOfChange indicator class. + */ + +Indi_RateOfChange indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_SAR.test.mq4 b/Indicators/tests/Indi_SAR.test.mq4 new file mode 100644 index 000000000..cb64f79b4 --- /dev/null +++ b/Indicators/tests/Indi_SAR.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_SAR indicator class. + */ + +#include "Indi_SAR.test.mq5" diff --git a/Indicators/tests/Indi_SAR.test.mq5 b/Indicators/tests/Indi_SAR.test.mq5 new file mode 100644 index 000000000..895fbd375 --- /dev/null +++ b/Indicators/tests/Indi_SAR.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_SAR.mqh" + +/** + * @file + * Test functionality of Indi_SAR indicator class. + */ + +Indi_SAR indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_StdDev.test.mq4 b/Indicators/tests/Indi_StdDev.test.mq4 new file mode 100644 index 000000000..e36c47034 --- /dev/null +++ b/Indicators/tests/Indi_StdDev.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_StdDev indicator class. + */ + +#include "Indi_StdDev.test.mq5" diff --git a/Indicators/tests/Indi_StdDev.test.mq5 b/Indicators/tests/Indi_StdDev.test.mq5 new file mode 100644 index 000000000..4929bf2b4 --- /dev/null +++ b/Indicators/tests/Indi_StdDev.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_StdDev.mqh" + +/** + * @file + * Test functionality of Indi_StdDev indicator class. + */ + +Indi_StdDev indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Stochastic.test.mq4 b/Indicators/tests/Indi_Stochastic.test.mq4 new file mode 100644 index 000000000..54658083e --- /dev/null +++ b/Indicators/tests/Indi_Stochastic.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_Stochastic indicator class. + */ + +#include "Indi_Stochastic.test.mq5" diff --git a/Indicators/tests/Indi_Stochastic.test.mq5 b/Indicators/tests/Indi_Stochastic.test.mq5 new file mode 100644 index 000000000..09e99ed27 --- /dev/null +++ b/Indicators/tests/Indi_Stochastic.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Stochastic.mqh" + +/** + * @file + * Test functionality of Indi_Stochastic indicator class. + */ + +Indi_Stochastic indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_TEMA.test.mq4 b/Indicators/tests/Indi_TEMA.test.mq4 new file mode 100644 index 000000000..41332b6a6 --- /dev/null +++ b/Indicators/tests/Indi_TEMA.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_TEMA indicator class. + */ + +#include "Indi_TEMA.test.mq5" diff --git a/Indicators/tests/Indi_TEMA.test.mq5 b/Indicators/tests/Indi_TEMA.test.mq5 new file mode 100644 index 000000000..30ab6b3cb --- /dev/null +++ b/Indicators/tests/Indi_TEMA.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_TEMA.mqh" + +/** + * @file + * Test functionality of Indi_TEMA indicator class. + */ + +Indi_TEMA indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_TRIX.test.mq4 b/Indicators/tests/Indi_TRIX.test.mq4 new file mode 100644 index 000000000..be5579c93 --- /dev/null +++ b/Indicators/tests/Indi_TRIX.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_TRIX indicator class. + */ + +#include "Indi_TRIX.test.mq5" diff --git a/Indicators/tests/Indi_TRIX.test.mq5 b/Indicators/tests/Indi_TRIX.test.mq5 new file mode 100644 index 000000000..d6b8d16fa --- /dev/null +++ b/Indicators/tests/Indi_TRIX.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_TRIX.mqh" + +/** + * @file + * Test functionality of Indi_TRIX indicator class. + */ + +Indi_TRIX indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_UltimateOscillator.test.mq4 b/Indicators/tests/Indi_UltimateOscillator.test.mq4 new file mode 100644 index 000000000..ec6d67e78 --- /dev/null +++ b/Indicators/tests/Indi_UltimateOscillator.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_UltimateOscillator indicator class. + */ + +#include "Indi_UltimateOscillator.test.mq5" diff --git a/Indicators/tests/Indi_UltimateOscillator.test.mq5 b/Indicators/tests/Indi_UltimateOscillator.test.mq5 new file mode 100644 index 000000000..44e2c2a37 --- /dev/null +++ b/Indicators/tests/Indi_UltimateOscillator.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_UltimateOscillator.mqh" + +/** + * @file + * Test functionality of Indi_UltimateOscillator indicator class. + */ + +Indi_UltimateOscillator indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_VIDYA.test.mq4 b/Indicators/tests/Indi_VIDYA.test.mq4 new file mode 100644 index 000000000..a222007f1 --- /dev/null +++ b/Indicators/tests/Indi_VIDYA.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_VIDYA indicator class. + */ + +#include "Indi_VIDYA.test.mq5" diff --git a/Indicators/tests/Indi_VIDYA.test.mq5 b/Indicators/tests/Indi_VIDYA.test.mq5 new file mode 100644 index 000000000..c94227252 --- /dev/null +++ b/Indicators/tests/Indi_VIDYA.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_VIDYA.mqh" + +/** + * @file + * Test functionality of Indi_VIDYA indicator class. + */ + +Indi_VIDYA indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_VROC.test.mq4 b/Indicators/tests/Indi_VROC.test.mq4 new file mode 100644 index 000000000..307567add --- /dev/null +++ b/Indicators/tests/Indi_VROC.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_VROC indicator class. + */ + +#include "Indi_VROC.test.mq5" diff --git a/Indicators/tests/Indi_VROC.test.mq5 b/Indicators/tests/Indi_VROC.test.mq5 new file mode 100644 index 000000000..fd0ce8036 --- /dev/null +++ b/Indicators/tests/Indi_VROC.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_VROC.mqh" + +/** + * @file + * Test functionality of Indi_VROC indicator class. + */ + +Indi_VROC indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_Volumes.test.mq4 b/Indicators/tests/Indi_Volumes.test.mq4 new file mode 100644 index 000000000..3b85b25ff --- /dev/null +++ b/Indicators/tests/Indi_Volumes.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_Volumes indicator class. + */ + +#include "Indi_Volumes.test.mq5" diff --git a/Indicators/tests/Indi_Volumes.test.mq5 b/Indicators/tests/Indi_Volumes.test.mq5 new file mode 100644 index 000000000..7ca0e369e --- /dev/null +++ b/Indicators/tests/Indi_Volumes.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_Volumes.mqh" + +/** + * @file + * Test functionality of Indi_Volumes indicator class. + */ + +Indi_Volumes indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_WPR.test.mq4 b/Indicators/tests/Indi_WPR.test.mq4 new file mode 100644 index 000000000..7e3e27097 --- /dev/null +++ b/Indicators/tests/Indi_WPR.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_WPR indicator class. + */ + +#include "Indi_WPR.test.mq5" diff --git a/Indicators/tests/Indi_WPR.test.mq5 b/Indicators/tests/Indi_WPR.test.mq5 new file mode 100644 index 000000000..ebc76e3cf --- /dev/null +++ b/Indicators/tests/Indi_WPR.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_WPR.mqh" + +/** + * @file + * Test functionality of Indi_WPR indicator class. + */ + +Indi_WPR indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_WilliamsAD.test.mq4 b/Indicators/tests/Indi_WilliamsAD.test.mq4 new file mode 100644 index 000000000..c3aa0468a --- /dev/null +++ b/Indicators/tests/Indi_WilliamsAD.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_WilliamsAD indicator class. + */ + +#include "Indi_WilliamsAD.test.mq5" diff --git a/Indicators/tests/Indi_WilliamsAD.test.mq5 b/Indicators/tests/Indi_WilliamsAD.test.mq5 new file mode 100644 index 000000000..a3840617a --- /dev/null +++ b/Indicators/tests/Indi_WilliamsAD.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_WilliamsAD.mqh" + +/** + * @file + * Test functionality of Indi_WilliamsAD indicator class. + */ + +Indi_WilliamsAD indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_ZigZag.test.mq4 b/Indicators/tests/Indi_ZigZag.test.mq4 new file mode 100644 index 000000000..dfe9dc22a --- /dev/null +++ b/Indicators/tests/Indi_ZigZag.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_ZigZag indicator class. + */ + +#include "Indi_ZigZag.test.mq5" diff --git a/Indicators/tests/Indi_ZigZag.test.mq5 b/Indicators/tests/Indi_ZigZag.test.mq5 new file mode 100644 index 000000000..2c2a7e7a9 --- /dev/null +++ b/Indicators/tests/Indi_ZigZag.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_ZigZag.mqh" + +/** + * @file + * Test functionality of Indi_ZigZag indicator class. + */ + +Indi_ZigZag indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Indicators/tests/Indi_ZigZagColor.test.mq4 b/Indicators/tests/Indi_ZigZagColor.test.mq4 new file mode 100644 index 000000000..750d34430 --- /dev/null +++ b/Indicators/tests/Indi_ZigZagColor.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_ZigZagColor indicator class. + */ + +#include "Indi_ZigZagColor.test.mq5" diff --git a/Indicators/tests/Indi_ZigZagColor.test.mq5 b/Indicators/tests/Indi_ZigZagColor.test.mq5 new file mode 100644 index 000000000..92b2b5b89 --- /dev/null +++ b/Indicators/tests/Indi_ZigZagColor.test.mq5 @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| 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 "../../Test.mqh" +#include "../Indi_ZigZagColor.mqh" + +/** + * @file + * Test functionality of Indi_ZigZagColor indicator class. + */ + +Indi_ZigZagColor indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + } + } + _tick_last = _tick_new; +} diff --git a/Order.mqh b/Order.mqh index e961061f7..7cbba164b 100644 --- a/Order.mqh +++ b/Order.mqh @@ -2581,9 +2581,9 @@ class Order : public SymbolInfo { /** * Process order conditions. */ - bool ProcessConditions() { + bool ProcessConditions(bool _refresh = false) { bool _result = true; - if (IsOpen() && ShouldCloseOrder()) { + if (IsOpen(_refresh) && ShouldCloseOrder()) { string _reason = "Close condition"; #ifdef __MQL__ // _reason += StringFormat(": %s", EnumToString(oparams.cond_close)); diff --git a/OrderQuery.h b/OrderQuery.h index e3cc6db4f..aede72e81 100644 --- a/OrderQuery.h +++ b/OrderQuery.h @@ -53,6 +53,9 @@ class OrderQuery : public Dynamic { /** * Calculates sum of order's value based on the property's enum. * + * @param + * _prop Order's property to sum by (e.g. ORDER_PROP_PROFIT). + * * @return * Returns sum of order's values. */ @@ -65,6 +68,24 @@ class OrderQuery : public Dynamic { return _sum; } + /** + * Calculates sum of order's value based on the property's enum with condition. + * + * @return + * Returns sum of order's values based on the condition. + */ + template + T CalcSumByPropWithCond(E _prop, ECT _prop_cond_type, ECV _prop_cond_value) { + T _sum = 0; + for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { + Order *_order = iter.Value().Ptr(); + if (_order.Get(_prop_cond_type) == _prop_cond_value) { + _sum += _order.Get(_prop); + } + } + return _sum; + } + /** * Find order by comparing property's value given the comparison operator. * @@ -111,6 +132,33 @@ class OrderQuery : public Dynamic { return _order_ref_found; } + /** + * Find property enum with the highest sum based on another property's enums. + * + * For example, you can find order's type which has the highest profit. + * + * @param + * _props Array of properties to group the sums by. + * _prop_sum Order's property to sum by (e.g. ORDER_PROP_PROFIT). + * + * @return + * Returns property enum having the highest sum. + */ + template + EP FindPropBySum(ARRAY_REF(EP, _props), ES _prop_sum, ECT _prop_sum_type, + STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP) _op = STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_GT)) { + EP _peak_type = _props[0]; + T _peak_sum = CalcSumByPropWithCond(_prop_sum, _prop_sum_type, _peak_type); + for (int _i = 1; _i < ArraySize(_props); _i++) { + T _sum = CalcSumByPropWithCond(_prop_sum, _prop_sum_type, _props[_i]); + if (Compare(_sum, _op, _peak_sum)) { + _peak_sum = _sum; + _peak_type = _props[_i]; + } + } + return _peak_type; + } + /** * Perform a comparison operation on two values. * diff --git a/Refs.mqh b/Refs.mqh index 1239e88ba..bc71b2138 100644 --- a/Refs.mqh +++ b/Refs.mqh @@ -129,7 +129,7 @@ class Dynamic { */ Dynamic() { #ifdef __MQL__ - if (CheckPointer(&this) == POINTER_DYNAMIC) { + if (CheckPointer(GetPointer(this)) == POINTER_DYNAMIC) { #else // For other languages we just assume that user knows what he does and creates all Dynamic instances on the heap. if (true) { diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index 9babdf989..98f90b93f 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -61,7 +61,7 @@ class HistoryValueStorage : public ValueStorage { */ HistoryValueStorage(string _symbol, ENUM_TIMEFRAMES _tf, bool _is_series = false) : symbol(_symbol), tf(_tf), is_series(_is_series) { - start_bar_time = ChartStatic::iTime(_symbol, _tf, INDICATOR_BUFFER_VALUE_STORAGE_HISTORY - 1); + start_bar_time = ChartStatic::iTime(_symbol, _tf, BarsFromStart() - 1); } /** @@ -79,22 +79,19 @@ class HistoryValueStorage : public ValueStorage { if (is_series) { return _shift; } else { - int _bars_from_start = BarsFromStart(); - return _bars_from_start - _shift; + return BarsFromStart() - _shift - 1; } } /** - * Number of bars passed from the start. + * Number of bars passed from the start. There will be a single bar at the start. */ - int BarsFromStart() const { - return (int)((ChartStatic::iTime(symbol, tf, 0) - start_bar_time) / (long)PeriodSeconds(tf)); - } + int BarsFromStart() const { return Bars(symbol, tf); } /** * Returns number of values available to fetch (size of the values buffer). */ - virtual int Size() const { return BarsFromStart() + 1; } + virtual int Size() const { return BarsFromStart(); } /** * Resizes storage to given size. diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 56f133d0c..4dc6aacb0 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -30,6 +30,9 @@ #pragma once #endif +// Forward declarations. +class IndicatorBase; + // Includes. #include "ValueStorage.history.h" @@ -39,7 +42,7 @@ template class IndicatorBufferValueStorage : public HistoryValueStorage { // Pointer to indicator to access data from. - Indicator *indicator; + IndicatorBase *indicator; // Mode of the target indicator. int mode; @@ -48,7 +51,7 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { /** * Constructor. */ - IndicatorBufferValueStorage(Indicator *_indi, int _mode = 0, bool _is_series = false) + IndicatorBufferValueStorage(IndicatorBase *_indi, int _mode = 0, bool _is_series = false) : indicator(_indi), mode(_mode), HistoryValueStorage(_indi.GetSymbol(), _indi.GetTf()) {} /** diff --git a/Storage/ValueStorage.volume.h b/Storage/ValueStorage.volume.h index 69644d53c..4eb51f188 100644 --- a/Storage/ValueStorage.volume.h +++ b/Storage/ValueStorage.volume.h @@ -58,5 +58,13 @@ class VolumeValueStorage : public HistoryValueStorage { /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - virtual long Fetch(int _shift) { return iVolume(symbol, tf, RealShift(_shift)); } + virtual long Fetch(int _shift) { + ResetLastError(); + long _volume = iVolume(symbol, tf, RealShift(_shift)); + if (_LastError != ERR_NO_ERROR) { + Print("Cannot fetch iVolume! Error: ", _LastError); + DebugBreak(); + } + return _volume; + } }; diff --git a/Strategy.enum.h b/Strategy.enum.h index c9c3b36b7..be20779b5 100644 --- a/Strategy.enum.h +++ b/Strategy.enum.h @@ -80,7 +80,8 @@ enum ENUM_STRATEGY_PARAM { STRAT_PARAM_PPM, // Signal profit method STRAT_PARAM_PSL, // Price stop level STRAT_PARAM_PSM, // Price stop method - STRAT_PARAM_SCF, // Signal close filter + STRAT_PARAM_SCFM, // Signal close filter method + STRAT_PARAM_SCFT, // Signal close filter time STRAT_PARAM_SCL, // Signal close level STRAT_PARAM_SCM, // Signal close method STRAT_PARAM_SHIFT, // Shift @@ -96,22 +97,6 @@ enum ENUM_STRATEGY_PARAM { FINAL_ENUM_STRATEGY_PARAM }; -/* Enumeration for strategy bitwise signal flags. */ -enum ENUM_STRATEGY_SIGNAL_FLAG { - STRAT_SIGNAL_NONE = 0 << 0, - STRAT_SIGNAL_CLOSE_BUY = 1 << 0, // Close signal for buy - STRAT_SIGNAL_CLOSE_BUY_PASS = 1 << 1, // Close signal for buy passed by filter - STRAT_SIGNAL_CLOSE_SELL = 1 << 2, // Close signal for sell - STRAT_SIGNAL_CLOSE_SELL_PASS = 1 << 3, // Close signal for sell passed by filter - STRAT_SIGNAL_OPEN_BUY = 1 << 4, // Open signal for buy - STRAT_SIGNAL_OPEN_BUY_PASS = 1 << 5, // Open signal for buy passed by filter - STRAT_SIGNAL_OPEN_SELL = 1 << 6, // Open signal for sell - STRAT_SIGNAL_OPEN_SELL_PASS = 1 << 7, // Open signal for sell passed by filter - STRAT_SIGNAL_PROCESSED = 1 << 8, // Signal proceed - STRAT_SIGNAL_TIME_PASS = 1 << 9, // Open signal passed by time filter - FINAL_ENUM_STRATEGY_SIGNAL_FLAG -}; - /* Enumeration for strategy periodical statistics. */ enum ENUM_STRATEGY_STATS_PERIOD { EA_STATS_DAILY, diff --git a/Strategy.mqh b/Strategy.mqh index 9e3ef9fa4..839b86425 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -93,13 +93,15 @@ class Strategy : public Object { Dict ddata; Dict fdata; Dict idata; + Dict indicators_unmanaged; // Indicators list (unmanaged). + DictStruct> indicators_managed; // Indicators list (managed). DictStruct tasks; Log logger; // Log instance. MqlTick last_tick; StgProcessResult sresult; Strategy *strat_sl, *strat_tp; // Strategy pointers for stop-loss and profit-take. - StrategySignal last_signals; // Last signals. Trade trade; // Trade instance. + // TradeSignalEntry last_signal; // Last signals. private: // Strategy statistics. @@ -142,71 +144,17 @@ class Strategy : public Object { Log *GetLogger() { return GetPointer(logger); } - /** - * Class copy constructor. - */ - /* - Strategy(const Strategy &_strat) { - // @todo - sparams = _strat.GetParams(); - // ... - } - */ - /** * Class deconstructor. */ - ~Strategy() { sparams.DeleteObjects(); } - - /* Processing methods */ - - /** - * Process strategy's signals. - * - * @param bool _should_open - * True if method should open the orders, otherwise only process the signals. - * @param bool _should_close - * True if method should close the orders, otherwise only process the signals. - * @param int _shift - * Bar shift. - * - * @return - * Returns StrategySignal struct. - */ - StrategySignal ProcessSignals(bool _trade_allowed = true, int _shift = -1) { - // float _bf = 1.0; - // float _ls = 0; - int _ss = _shift >= 0 ? _shift : sparams.shift; - StrategySignal _signal(THIS_PTR, trade.Get(CHART_PARAM_TF), - sparams.Get(STRAT_PARAM_WEIGHT)); - if (_trade_allowed) { - float _sol = sparams.Get(STRAT_PARAM_SOL); - int _sob = sparams.Get(STRAT_PARAM_SOB); - int _sofm = sparams.Get(STRAT_PARAM_SOFM); - int _soft = sparams.Get(STRAT_PARAM_SOFT); - int _som = sparams.Get(STRAT_PARAM_SOM); - // Process boost factor and lot size. - // sresult.SetBoostFactor(sparams.IsBoosted() ? SignalOpenBoost(ORDER_TYPE_BUY, _sob) : 1.0f); - // sresult.SetLotSize(sparams.GetLotSizeWithFactor()); - // Process open signals when trade is allowed. - _signal.SetSignal(STRAT_SIGNAL_OPEN_BUY, SignalOpen(ORDER_TYPE_BUY, _som, _sol, _ss)); - _signal.SetSignal(STRAT_SIGNAL_OPEN_BUY_PASS, SignalOpenFilterMethod(ORDER_TYPE_BUY, _sofm)); - _signal.SetSignal(STRAT_SIGNAL_OPEN_SELL, SignalOpen(ORDER_TYPE_SELL, _som, _sol, _ss)); - _signal.SetSignal(STRAT_SIGNAL_OPEN_SELL_PASS, SignalOpenFilterMethod(ORDER_TYPE_SELL, _sofm)); - _signal.SetSignal(STRAT_SIGNAL_TIME_PASS, SignalOpenFilterTime(_soft)); + ~Strategy() { + for (DictIterator iter = indicators_unmanaged.Begin(); iter.IsValid(); ++iter) { + delete iter.Value(); } - // Process close signals. - float _scl = sparams.Get(STRAT_PARAM_SCL); - int _scf = sparams.Get(STRAT_PARAM_SCF); - int _scm = sparams.Get(STRAT_PARAM_SCM); - _signal.SetSignal(STRAT_SIGNAL_CLOSE_BUY, SignalClose(ORDER_TYPE_BUY, _scm, _scl, _ss)); - _signal.SetSignal(STRAT_SIGNAL_CLOSE_BUY_PASS, SignalCloseFilter(ORDER_TYPE_BUY, _scf)); - _signal.SetSignal(STRAT_SIGNAL_CLOSE_SELL, SignalClose(ORDER_TYPE_SELL, _scm, _scl, _ss)); - _signal.SetSignal(STRAT_SIGNAL_CLOSE_SELL_PASS, SignalCloseFilter(ORDER_TYPE_SELL, _scf)); - last_signals = _signal; - return _signal; } + /* Processing methods */ + /** * Process strategy's signals and orders. * @@ -218,7 +166,6 @@ class Strategy : public Object { */ StgProcessResult Process(unsigned short _periods_started = DATETIME_NONE) { sresult.last_error = ERR_NO_ERROR; - last_signals = ProcessSignals(); if (_periods_started > 0) { ProcessTasks(); } @@ -294,20 +241,24 @@ class Strategy : public Object { /* Class getters */ - /** - * Returns access to Chart information. - */ - // Chart *GetChart() { return trade.GetChart(); } - /** * Returns handler to the strategy's indicator class. */ - Indicator *GetIndicator(int _id = 0) { return sparams.GetIndicator(_id); } + IndicatorBase *GetIndicator(int _id = 0) { + if (indicators_managed.KeyExists(_id)) { + return indicators_managed[_id].Ptr(); + } else if (indicators_unmanaged.KeyExists(_id)) { + return indicators_unmanaged[_id]; + } + + Alert("Missing indicator id ", _id); + return NULL; + } /** * Returns strategy's indicators. */ - DictStruct> GetIndicators() { return sparams.indicators_managed; } + DictStruct> GetIndicators() { return indicators_managed; } /* Struct getters */ @@ -353,11 +304,6 @@ class Strategy : public Object { return _entry; } - /** - * Get strategy's last signals. - */ - StrategySignal GetLastSignals() { return last_signals; } - /** * Gets pointer to strategy's stop-loss strategy. */ @@ -378,11 +324,6 @@ class Strategy : public Object { */ virtual long GetId() { return sparams.id; } - /** - * Get strategy's timeframe. - */ - // ENUM_TIMEFRAMES GetTf() { return trade.GetChart().GetTf(); } - /** * Get strategy's signal open method. */ @@ -569,6 +510,18 @@ class Strategy : public Object { void SetData(Dict *_fdata) { fdata = _fdata; } void SetData(Dict *_idata) { idata = _idata; } + /** + * Sets reference to indicator. + */ + void SetIndicator(IndicatorBase *_indi, int _id = 0, bool _managed = true) { + if (_managed) { + Ref _ref = _indi; + indicators_managed.Set(_id, _ref); + } else { + indicators_unmanaged.Set(_id, _indi); + } + } + /* Static setters */ /** @@ -1014,6 +967,7 @@ class Strategy : public Object { // Process on every minute. _val = _tick.time % 60 < last_tick.time % 60; _res = _method > 0 ? _res & _val : _res | _val; + last_tick = _tick; } if (METHOD(_method_abs, 1)) { // 2 // Process low and high ticks of a bar. @@ -1095,7 +1049,7 @@ class Strategy : public Object { */ virtual float SignalOpen(int _method = 0, float _level = 0.0f, int _shift = 0) { // @todo - return false; + return 0.0f; }; /** @@ -1127,6 +1081,25 @@ class Strategy : public Object { return _result; } + /** + * Checks strategy's trade's close signal time filter. + * + * @param + * _method - method to filter a closing trade (bitwise AND operation) + * + * @result bool + * Returns true if trade should be closed, otherwise false. + */ + virtual bool SignalCloseFilterTime(int _method = 0) { + bool _result = true; + if (_method != 0) { + MarketTimeForex _mtf(::TimeGMT()); + _result &= _mtf.CheckHours(_method); // 0-127 + _method = _method > 0 ? _method : !_method; // -127-127 + } + return _result; + } + /** * Checks strategy's trade's open signal time filter. * @@ -1134,7 +1107,7 @@ class Strategy : public Object { * _method - method to filter a trade (bitwise AND operation) * * @result bool - * Returns true when trade should be opened, otherwise false. + * Returns true if trade should be opened, otherwise false. */ virtual bool SignalOpenFilterTime(int _method = 0) { bool _result = true; @@ -1240,11 +1213,11 @@ class Strategy : public Object { int _count = (int)fmax(fabs(_level), fabs(_method)); int _direction = Order::OrderDirection(_cmd, _mode); Chart *_chart = trade.GetChart(); - Indicator *_indi = GetIndicator(); + IndicatorBase *_indi = GetIndicator(); StrategyPriceStop _psm(_method); _psm.SetChartParams(_chart.GetParams()); if (Object::IsValid(_indi)) { - int _ishift = fmax(0, _direction > 0 ? _indi.GetHighest(_bars) : _indi.GetLowest(_bars)); + int _ishift = 12; // @todo: Make it dynamic or as variable. float _value = _indi.GetValuePrice(_ishift, 0, _direction > 0 ? PRICE_HIGH : PRICE_LOW); _value = _value + (float)Math::ChangeByPct(fabs(_value - _chart.GetCloseOffer(0)), _level) * _direction; _psm.SetIndicatorPriceValue(_value); @@ -1297,8 +1270,6 @@ class Strategy : public Object { SerializerNodeType Serialize(Serializer &_s) { _s.PassStruct(THIS_REF, "strat-params", sparams); _s.PassStruct(THIS_REF, "strat-results", sresult, SERIALIZER_FIELD_FLAG_DYNAMIC); - _s.PassStruct(THIS_REF, "strat-signals", last_signals, - SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); return SerializerNodeObject; } }; diff --git a/Strategy.struct.h b/Strategy.struct.h index 3c41b81d6..2a4254a6b 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -37,47 +37,45 @@ #include "Task.struct.h" // Forward class declaration. -class Indicator; class Strategy; class Trade; /* Structure for strategy parameters. */ struct StgParams { // Strategy config parameters. - bool is_enabled; // State of the strategy (whether enabled or not). - bool is_suspended; // State of the strategy (whether suspended or not) - bool is_boosted; // State of the boost feature (to increase lot size). - float weight; // Weight of the strategy. - long order_close_time; // Order close time in mins (>0) or bars (<0). - float order_close_loss; // Order close loss (in pips). - float order_close_profit; // Order close profit (in pips). - int signal_open_method; // Signal open method. - float signal_open_level; // Signal open level. - int signal_open_filter_method; // Signal open filter method. - int signal_open_filter_time; // Signal open filter time. - int signal_open_boost; // Signal open boost method (for lot size increase). - int signal_close_method; // Signal close method. - float signal_close_level; // Signal close level. - int signal_close_filter; // Signal close filter method. - int price_profit_method; // Price profit method. - float price_profit_level; // Price profit level. - int price_stop_method; // Price stop method. - float price_stop_level; // Price stop level. - int tick_filter_method; // Tick filter. - float trend_threshold; // Trend strength threshold. - float lot_size; // Lot size to trade. - float lot_size_factor; // Lot size multiplier factor. - float max_risk; // Maximum risk to take (1.0 = normal, 2.0 = 2x). - float max_spread; // Maximum spread to trade (in pips). - int tp_max; // Hard limit on maximum take profit (in pips). - int sl_max; // Hard limit on maximum stop loss (in pips). - int type; // Strategy type (@see: ENUM_STRATEGY). - long id; // Unique identifier of the strategy. - datetime refresh_time; // Order refresh frequency (in sec). - short shift; // Shift (relative to the current bar, 0 - default) - ChartTf tf; // Main timeframe where strategy operates on. - DictStruct> indicators_managed; // Indicators list keyed by id. - Dict indicators_unmanaged; // Indicators list keyed by id. + bool is_enabled; // State of the strategy (whether enabled or not). + bool is_suspended; // State of the strategy (whether suspended or not) + bool is_boosted; // State of the boost feature (to increase lot size). + float weight; // Weight of the strategy. + long order_close_time; // Order close time in mins (>0) or bars (<0). + float order_close_loss; // Order close loss (in pips). + float order_close_profit; // Order close profit (in pips). + int signal_open_method; // Signal open method. + float signal_open_level; // Signal open level. + int signal_open_filter_method; // Signal open filter method. + int signal_open_filter_time; // Signal open filter time. + int signal_open_boost; // Signal open boost method (for lot size increase). + int signal_close_method; // Signal close method. + float signal_close_level; // Signal close level. + int signal_close_filter_method; // Signal close filter method. + int signal_close_filter_time; // Signal close filter method. + int price_profit_method; // Price profit method. + float price_profit_level; // Price profit level. + int price_stop_method; // Price stop method. + float price_stop_level; // Price stop level. + int tick_filter_method; // Tick filter. + float trend_threshold; // Trend strength threshold. + float lot_size; // Lot size to trade. + float lot_size_factor; // Lot size multiplier factor. + float max_risk; // Maximum risk to take (1.0 = normal, 2.0 = 2x). + float max_spread; // Maximum spread to trade (in pips). + int tp_max; // Hard limit on maximum take profit (in pips). + int sl_max; // Hard limit on maximum stop loss (in pips). + int type; // Strategy type (@see: ENUM_STRATEGY). + long id; // Unique identifier of the strategy. + datetime refresh_time; // Order refresh frequency (in sec). + short shift; // Shift (relative to the current bar, 0 - default) + ChartTf tf; // Main timeframe where strategy operates on. // Constructor. StgParams() : id(rand()), @@ -95,7 +93,8 @@ struct StgParams { signal_open_boost(0), signal_close_method(0), signal_close_level(0), - signal_close_filter(0), + signal_close_filter_method(0), + signal_close_filter_time(0), price_profit_method(0), price_profit_level(0), price_stop_method(0), @@ -106,6 +105,7 @@ struct StgParams { lot_size_factor(1.0), max_risk(1.0), max_spread(0.0), + shift(0), tp_max(0), sl_max(0), type(0), @@ -121,7 +121,7 @@ struct StgParams { signal_open_level(_sol), signal_open_boost(_sob), signal_close_method(_scm), - signal_close_filter(_scf), + signal_close_filter_method(_scf), signal_close_level(_scl), price_profit_method(_psm), price_profit_level(_psl), @@ -141,10 +141,7 @@ struct StgParams { sl_max(0), type(0), refresh_time(0) {} - StgParams(StgParams &_stg_params) { - DeleteObjects(); - this = _stg_params; - } + StgParams(StgParams &_stg_params) { this = _stg_params; } // Deconstructor. ~StgParams() {} @@ -184,8 +181,10 @@ struct StgParams { return (T)signal_open_filter_time; case STRAT_PARAM_SOB: return (T)signal_open_boost; - case STRAT_PARAM_SCF: - return (T)signal_close_filter; + case STRAT_PARAM_SCFM: + return (T)signal_close_filter_method; + case STRAT_PARAM_SCFT: + return (T)signal_close_filter_time; case STRAT_PARAM_SCM: return (T)signal_close_method; case STRAT_PARAM_SHIFT: @@ -206,20 +205,9 @@ struct StgParams { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } - bool HasIndicator(int _id = 0) { return GetIndicator(_id) != NULL; } bool IsBoosted() { return is_boosted; } bool IsEnabled() { return is_enabled; } bool IsSuspended() { return is_suspended; } - Indicator *GetIndicator(int _id = 0) { - if (indicators_managed.KeyExists(_id)) { - return indicators_managed[_id].Ptr(); - } else if (indicators_unmanaged.KeyExists(_id)) { - return indicators_unmanaged[_id]; - } - - Alert("Missing indicator id ", _id); - return NULL; - } // Setters. template void Set(ENUM_STRATEGY_PARAM _param, T _value) { @@ -275,8 +263,11 @@ struct StgParams { case STRAT_PARAM_SOB: // Signal open boost method signal_open_boost = (int)_value; return; - case STRAT_PARAM_SCF: // Signal close filter - signal_close_filter = (int)_value; + case STRAT_PARAM_SCFM: // Signal close filter method + signal_close_filter_method = (int)_value; + return; + case STRAT_PARAM_SCFT: // Signal close filter time + signal_close_filter_time = (int)_value; return; case STRAT_PARAM_SCM: // Signal close method signal_close_method = (int)_value; @@ -312,14 +303,6 @@ struct StgParams { } } void SetId(long _id) { id = _id; } - void SetIndicator(Indicator *_indi, int _id = 0, bool _managed = true) { - if (_managed) { - Ref _ref = _indi; - indicators_managed.Set(_id, _ref); - } else { - indicators_unmanaged.Set(_id, _indi); - } - } void SetStops(Strategy *_sl = NULL, Strategy *_tp = NULL) { // @todo: To remove. } @@ -334,11 +317,6 @@ struct StgParams { void Enabled(bool _is_enabled) { is_enabled = _is_enabled; }; void Suspended(bool _is_suspended) { is_suspended = _is_suspended; }; void Boost(bool _is_boosted) { is_boosted = _is_boosted; }; - void DeleteObjects() { - for (DictIterator iter = indicators_unmanaged.Begin(); iter.IsValid(); ++iter) { - delete iter.Value(); - } - } // Printers. string ToString() { // SerializerConverter _stub = SerializerConverter::MakeStubObject(SERIALIZER_FLAG_SKIP_HIDDEN); @@ -364,6 +342,8 @@ struct StgParams { s.Pass(THIS_REF, "soft", signal_open_filter_time); s.Pass(THIS_REF, "sob", signal_open_boost); s.Pass(THIS_REF, "scm", signal_close_method); + s.Pass(THIS_REF, "scfm", signal_close_filter_method); + s.Pass(THIS_REF, "scft", signal_close_filter_time); s.Pass(THIS_REF, "scl", signal_close_level); s.Pass(THIS_REF, "ppm", price_profit_method); s.Pass(THIS_REF, "ppl", price_profit_level); @@ -433,146 +413,6 @@ struct StgProcessResult { } }; -/* Structure for strategy's signals. */ -struct StrategySignal { - protected: - ENUM_TIMEFRAMES tf; // Timeframe. - float strength; // Signal strength. - float weight; // Signal weight. - unsigned int signals; // Store signals (@see: ENUM_STRATEGY_SIGNAL_FLAG). - Strategy *strat; - - public: - // Enumeration for strategy signal properties. - enum ENUM_STRATEGY_SIGNAL_PROP { - STRATEGY_SIGNAL_PROP_SIGNALS, - STRATEGY_SIGNAL_PROP_STRENGTH, - STRATEGY_SIGNAL_PROP_TF, - STRATEGY_SIGNAL_PROP_WEIGHT, - }; - // Enumeration for strategy signal types. - enum ENUM_STRATEGY_SIGNAL_TYPE { - STRAT_SIGNAL_SELL = -1, // Signal to sell. - STRAT_SIGNAL_NEUTRAL = 0, // Neutral signal. - STRAT_SIGNAL_BUY = 1, // Signal to buy. - }; - - /* Constructor */ - StrategySignal(Strategy *_strat = NULL, ENUM_TIMEFRAMES _tf = NULL, float _weight = 0.0f) - : signals(0), strat(_strat), tf(_tf), weight(_weight) {} - /* Getters */ - template - T Get(unsigned int _param) { - switch (_param) { - case STRATEGY_SIGNAL_PROP_SIGNALS: - return (T)signals; - case STRATEGY_SIGNAL_PROP_STRENGTH: - return (T)strength; - case STRATEGY_SIGNAL_PROP_TF: - return (T)tf; - case STRATEGY_SIGNAL_PROP_WEIGHT: - return (T)weight; - } - SetUserError(ERR_INVALID_PARAMETER); - return (T)WRONG_VALUE; - } - float GetSignalClose() { return float(int(ShouldClose(ORDER_TYPE_BUY)) - int(ShouldClose(ORDER_TYPE_SELL))); } - float GetSignalOpen() { return float(int(ShouldOpen(ORDER_TYPE_BUY)) - int(ShouldOpen(ORDER_TYPE_SELL))); } - Strategy *GetStrategy() { return strat; } - /* Setters */ - template - void Set(unsigned int _param, T _value) { - switch (_param) { - case STRATEGY_SIGNAL_PROP_SIGNALS: - signals = (unsigned int)_value; - return; - case STRATEGY_SIGNAL_PROP_STRENGTH: - strength = (float)_value; - return; - case STRATEGY_SIGNAL_PROP_TF: - tf = (ENUM_TIMEFRAMES)_value; - return; - case STRATEGY_SIGNAL_PROP_WEIGHT: - weight = (float)_value; - return; - } - SetUserError(ERR_INVALID_PARAMETER); - } - void SetStrategy(Strategy *_strat) { strat = _strat; } - /* Signal open and close methods */ - bool ShouldClose(ENUM_ORDER_TYPE _cmd) { - switch (_cmd) { - case ORDER_TYPE_BUY: - return CheckSignalsAll(STRAT_SIGNAL_CLOSE_BUY | STRAT_SIGNAL_CLOSE_BUY_PASS); - case ORDER_TYPE_SELL: - return CheckSignalsAll(STRAT_SIGNAL_CLOSE_SELL | STRAT_SIGNAL_CLOSE_SELL_PASS); - } - return false; - } - bool ShouldOpen(ENUM_ORDER_TYPE _cmd) { - switch (_cmd) { - case ORDER_TYPE_BUY: - return CheckSignalsAll(STRAT_SIGNAL_OPEN_BUY | STRAT_SIGNAL_OPEN_BUY_PASS | STRAT_SIGNAL_TIME_PASS); - case ORDER_TYPE_SELL: - return CheckSignalsAll(STRAT_SIGNAL_OPEN_SELL | STRAT_SIGNAL_OPEN_SELL_PASS | STRAT_SIGNAL_TIME_PASS); - } - return false; - } - /* Signal methods for bitwise operations */ - bool CheckSignals(unsigned int _flags) { return (signals & _flags) != 0; } - bool CheckSignalsAll(unsigned int _flags) { return (signals & _flags) == _flags; } - char GetCloseDirection() { - if (CheckSignals(STRAT_SIGNAL_CLOSE_BUY & ~STRAT_SIGNAL_CLOSE_SELL)) { - return 1; - } else if (CheckSignals(STRAT_SIGNAL_CLOSE_SELL & ~STRAT_SIGNAL_CLOSE_BUY)) { - return -1; - } - return 0; - } - char GetOpenDirection() { - if (CheckSignals(STRAT_SIGNAL_OPEN_BUY & ~STRAT_SIGNAL_OPEN_SELL)) { - return 1; - } else if (CheckSignals(STRAT_SIGNAL_OPEN_SELL & ~STRAT_SIGNAL_OPEN_BUY)) { - return -1; - } - return 0; - } - unsigned int GetSignals() { return signals; } - /* Setters */ - void AddSignals(unsigned int _flags) { signals |= _flags; } - void RemoveSignals(unsigned int _flags) { signals &= ~_flags; } - void SetSignal(ENUM_STRATEGY_SIGNAL_FLAG _flag, bool _value = true) { - if (_value) { - AddSignals(_flag); - } else { - RemoveSignals(_flag); - } - } - void SetSignals(unsigned int _flags) { signals = _flags; } - // Serializers. - SERIALIZER_EMPTY_STUB; - SerializerNodeType Serialize(Serializer &_s) { - _s.PassEnum(THIS_REF, "tf", tf); - _s.Pass(THIS_REF, "strenght", strength, SERIALIZER_FIELD_FLAG_DYNAMIC); - _s.Pass(THIS_REF, "weight", weight, SERIALIZER_FIELD_FLAG_DYNAMIC); - if (Object::IsValid(strat)) { - string _sname = strat.GetName(); - _s.Pass(THIS_REF, "strat", _sname); - } - int _size = sizeof(int) * 8; - for (int i = 0; i < _size; i++) { - int _value = CheckSignals(1 << i) ? 1 : 0; - _s.Pass(THIS_REF, (string)(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); - } - return SerializerNodeObject; - } - string ToString() { - // SerializerConverter _stub = SerializerConverter::MakeStubObject(SERIALIZER_FLAG_SKIP_HIDDEN); - return SerializerConverter::FromObject(THIS_REF, SERIALIZER_FLAG_SKIP_HIDDEN) - .ToString(SERIALIZER_JSON_NO_WHITESPACES); - } -}; - /* Struture for strategy statistics */ struct StgStats { uint orders_open; // Number of current opened orders. diff --git a/Trade/TradeSignal.h b/Trade/TradeSignal.h new file mode 100644 index 000000000..7a48524f5 --- /dev/null +++ b/Trade/TradeSignal.h @@ -0,0 +1,181 @@ +//+------------------------------------------------------------------+ +//| 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 "TradeSignal.struct.h" + +/** + * @file + * Implements TradeSignal class. + */ + +/** + * Class to store and manage a trading signal. + */ +class TradeSignal { + protected: + TradeSignalEntry signal; + + public: + /** + * Class constructor. + */ + TradeSignal() {} + TradeSignal(const TradeSignalEntry &_entry) : signal(_entry) {} + TradeSignal(const TradeSignal &_signal) : signal(_signal.GetSignal()) {} + + /* Getters */ + + /** + * Gets a signal flag state. + */ + bool Get(STRUCT_ENUM(TradeSignalEntry, ENUM_TRADE_SIGNAL_FLAG) _flag) { return signal.Get(_flag); } + + /** + * Gets a signal property. + */ + template + TV Get(STRUCT_ENUM(TradeSignalEntry, ENUM_TRADE_SIGNAL_PROP) _prop) { + return signal.Get(_prop); + } + + /** + * Gets a signal entry. + */ + TradeSignalEntry GetSignal() const { return signal; } + + /* Setters */ + + /** + * Sets a signal flag state. + */ + void Set(STRUCT_ENUM(TradeSignalEntry, ENUM_TRADE_SIGNAL_FLAG) _prop, bool _value) { signal.Set(_prop, _value); } + + /** + * Sets a signal property. + */ + template + void Set(STRUCT_ENUM(TradeSignalEntry, ENUM_TRADE_SIGNAL_PROP) _prop, TV _value) { + signal.Set(_prop, _value); + } + + /* Signal methods */ + + /** + * Check for signal to close a trade. + */ + bool ShouldClose(ENUM_ORDER_TYPE _cmd) { + switch (_cmd) { + case ORDER_TYPE_BUY: + return signal.CheckSignalsEqual(SIGNAL_CLOSE_BUY_SIGNAL, SIGNAL_CLOSE_BUY_MAIN); + case ORDER_TYPE_SELL: + return signal.CheckSignalsEqual(SIGNAL_CLOSE_SELL_SIGNAL, SIGNAL_CLOSE_SELL_MAIN); + default: + break; + } + return false; + } + + /** + * Check for signal to open a trade. + */ + bool ShouldOpen(ENUM_ORDER_TYPE _cmd) { + switch (_cmd) { + case ORDER_TYPE_BUY: + return signal.CheckSignalsEqual(SIGNAL_OPEN_BUY_SIGNAL, SIGNAL_OPEN_BUY_MAIN); + case ORDER_TYPE_SELL: + return signal.CheckSignalsEqual(SIGNAL_OPEN_SELL_SIGNAL, SIGNAL_OPEN_SELL_MAIN); + default: + break; + } + return false; + } + + /** + * Gets signal's strength to close. + * + * @return + * Returns strength of signal to close between -1 and 1. + * Returns 0 on a neutral signal or when signals are in conflict. + */ + float GetSignalClose() { return float(int(ShouldClose(ORDER_TYPE_BUY)) - int(ShouldClose(ORDER_TYPE_SELL))); } + + /** + * Gets signal's close direction. + * + * @return + * Returns +1 for upwards, -1 for downwards, or 0 for a neutral direction. + */ + char GetSignalCloseDirection() { + if (signal.CheckSignals(SIGNAL_CLOSE_UPWARDS)) { + return 1; + } else if (signal.CheckSignals(SIGNAL_CLOSE_DOWNWARDS)) { + return -1; + } + return 0; + } + + /** + * Gets signal's strength to open. + * + * @return + * Returns strength of signal to close between -1 and 1. + * Returns 0 on a neutral signal or when signals are in conflict. + */ + float GetSignalOpen() { return float(int(ShouldOpen(ORDER_TYPE_BUY)) - int(ShouldOpen(ORDER_TYPE_SELL))); } + + /** + * Gets signal's open direction. + * + * @return + * Returns +1 for upwards, -1 for downwards, or 0 for a neutral direction. + */ + char GetSignalOpenDirection() { + if (signal.CheckSignals(SIGNAL_OPEN_UPWARDS)) { + return 1; + } else if (signal.CheckSignals(SIGNAL_OPEN_DOWNWARDS)) { + return -1; + } + return 0; + } + + /* Serializers */ + + /** + * Serializes this class. + * + * @return + * Returns a JSON serialized instance. + */ + SerializerNodeType Serialize(Serializer &_s) { + _s.PassStruct(THIS_REF, "signal", signal); + return SerializerNodeObject; + } + + /** + * Converts this class into a string. + * + * @return + * Returns a JSON serialized signal. + */ + string ToString() { return signal.ToString(); } +}; diff --git a/Trade/TradeSignal.struct.h b/Trade/TradeSignal.struct.h new file mode 100644 index 000000000..f4b3a9c61 --- /dev/null +++ b/Trade/TradeSignal.struct.h @@ -0,0 +1,200 @@ +//+------------------------------------------------------------------+ +//| 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 TradeSignal's structs. + */ + +// Includes. +#include "../Serializer.mqh" +#include "../SerializerConverter.mqh" +#include "../SerializerJson.mqh" + +// Defines. +#define SIGNAL_CLOSE_BUY_FILTER STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_CLOSE_BUY_FILTER) +#define SIGNAL_CLOSE_BUY_MAIN STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_CLOSE_BUY_MAIN) +#define SIGNAL_CLOSE_BUY_SIGNAL STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_CLOSE_BUY_SIGNAL) +#define SIGNAL_CLOSE_DOWNWARDS STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_CLOSE_DOWNWARDS) +#define SIGNAL_CLOSE_SELL_FILTER STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_CLOSE_SELL_FILTER) +#define SIGNAL_CLOSE_SELL_MAIN STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_CLOSE_SELL_MAIN) +#define SIGNAL_CLOSE_SELL_SIGNAL STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_CLOSE_SELL_SIGNAL) +#define SIGNAL_CLOSE_TIME_FILTER STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_CLOSE_TIME_FILTER) +#define SIGNAL_CLOSE_UPWARDS STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_CLOSE_UPWARDS) +#define SIGNAL_OPEN_BUY_FILTER STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_OPEN_BUY_FILTER) +#define SIGNAL_OPEN_BUY_MAIN STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_OPEN_BUY_MAIN) +#define SIGNAL_OPEN_BUY_SIGNAL STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_OPEN_BUY_SIGNAL) +#define SIGNAL_OPEN_DOWNWARDS STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_OPEN_DOWNWARDS) +#define SIGNAL_OPEN_SELL_FILTER STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_OPEN_SELL_FILTER) +#define SIGNAL_OPEN_SELL_MAIN STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_OPEN_SELL_MAIN) +#define SIGNAL_OPEN_SELL_SIGNAL STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_OPEN_SELL_SIGNAL) +#define SIGNAL_OPEN_TIME_FILTER STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_OPEN_TIME_FILTER) +#define SIGNAL_OPEN_UPWARDS STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_OPEN_UPWARDS) + +// Structure for a trade signal. +struct TradeSignalEntry { + protected: + ENUM_TIMEFRAMES tf; // Timeframe. + float strength; // Signal strength. + float weight; // Signal weight. + long magic_id; // Magic identifier. + long timestamp; // Creation timestamp + unsigned int signals; // Store signals (@see: ENUM_TRADE_SIGNAL_FLAG). + + public: + /* Struct's enumerations */ + + // Enumeration for strategy bitwise signal flags. + enum ENUM_TRADE_SIGNAL_FLAG { + TRADE_SIGNAL_FLAG_NONE = 0 << 0, + TRADE_SIGNAL_FLAG_CLOSE_BUY_FILTER = 1 << 0, // Filter for close buy + TRADE_SIGNAL_FLAG_CLOSE_BUY_MAIN = 1 << 1, // Main signal for close buy + TRADE_SIGNAL_FLAG_CLOSE_SELL_FILTER = 1 << 2, // Filter for close sell + TRADE_SIGNAL_FLAG_CLOSE_SELL_MAIN = 1 << 3, // Main signal for close sell + TRADE_SIGNAL_FLAG_CLOSE_TIME_FILTER = 1 << 4, // Time filter to close + TRADE_SIGNAL_FLAG_EXPIRED = 1 << 5, // Signal expired + TRADE_SIGNAL_FLAG_OPEN_BUY_FILTER = 1 << 6, // Filter for close buy + TRADE_SIGNAL_FLAG_OPEN_BUY_MAIN = 1 << 7, // Main signal for close buy + TRADE_SIGNAL_FLAG_OPEN_SELL_FILTER = 1 << 8, // Filter for close sell + TRADE_SIGNAL_FLAG_OPEN_SELL_MAIN = 1 << 9, // Main signal for close sell + TRADE_SIGNAL_FLAG_OPEN_TIME_FILTER = 1 << 10, // Time filter to open + TRADE_SIGNAL_FLAG_PROCESSED = 1 << 11, // Signal proceed + // Pre-defined signal conditions. + TRADE_SIGNAL_FLAG_CLOSE_BUY_SIGNAL = + TRADE_SIGNAL_FLAG_CLOSE_BUY_MAIN ^ (TRADE_SIGNAL_FLAG_CLOSE_BUY_FILTER | TRADE_SIGNAL_FLAG_CLOSE_TIME_FILTER), + TRADE_SIGNAL_FLAG_CLOSE_SELL_SIGNAL = + TRADE_SIGNAL_FLAG_CLOSE_SELL_MAIN ^ (TRADE_SIGNAL_FLAG_CLOSE_SELL_FILTER | TRADE_SIGNAL_FLAG_CLOSE_TIME_FILTER), + TRADE_SIGNAL_FLAG_OPEN_BUY_SIGNAL = + TRADE_SIGNAL_FLAG_OPEN_BUY_MAIN ^ (TRADE_SIGNAL_FLAG_OPEN_BUY_FILTER | TRADE_SIGNAL_FLAG_OPEN_TIME_FILTER), + TRADE_SIGNAL_FLAG_OPEN_SELL_SIGNAL = + TRADE_SIGNAL_FLAG_OPEN_SELL_MAIN ^ (TRADE_SIGNAL_FLAG_OPEN_SELL_FILTER | TRADE_SIGNAL_FLAG_OPEN_TIME_FILTER), + // Pre-defined signal directions. + TRADE_SIGNAL_FLAG_CLOSE_DOWNWARDS = TRADE_SIGNAL_FLAG_CLOSE_SELL_MAIN & ~TRADE_SIGNAL_FLAG_CLOSE_BUY_MAIN, + TRADE_SIGNAL_FLAG_CLOSE_UPWARDS = TRADE_SIGNAL_FLAG_CLOSE_BUY_MAIN & ~TRADE_SIGNAL_FLAG_CLOSE_SELL_MAIN, + TRADE_SIGNAL_FLAG_OPEN_DOWNWARDS = TRADE_SIGNAL_FLAG_OPEN_SELL_MAIN & ~TRADE_SIGNAL_FLAG_OPEN_BUY_MAIN, + TRADE_SIGNAL_FLAG_OPEN_UPWARDS = TRADE_SIGNAL_FLAG_OPEN_BUY_MAIN & ~TRADE_SIGNAL_FLAG_OPEN_SELL_MAIN, + }; + + // Enumeration for strategy signal properties. + enum ENUM_TRADE_SIGNAL_PROP { + TRADE_SIGNAL_PROP_MAGIC_ID, + TRADE_SIGNAL_PROP_SIGNALS, + TRADE_SIGNAL_PROP_STRENGTH, + TRADE_SIGNAL_PROP_TF, + TRADE_SIGNAL_PROP_TIME, + TRADE_SIGNAL_PROP_WEIGHT, + }; + // Enumeration for strategy signal types. + enum ENUM_TRADE_SIGNAL_OP { + TRADE_SIGNAL_OP_SELL = -1, // Signal to sell. + TRADE_SIGNAL_OP_NEUTRAL = 0, // Neutral signal. + TRADE_SIGNAL_OP_BUY = 1, // Signal to buy. + }; + + /* Constructor */ + TradeSignalEntry(unsigned int _signals = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, long _magic_id = 0, + float _strength = 0.0f, float _weight = 0.0f, long _time = 0) + : magic_id(_magic_id), signals(_signals), strength(_strength), tf(_tf), timestamp(_time), weight(_weight) {} + TradeSignalEntry(const TradeSignalEntry &_entry) { this = _entry; } + /* Getters */ + template + T Get(STRUCT_ENUM(TradeSignalEntry, ENUM_TRADE_SIGNAL_PROP) _prop) { + switch (_prop) { + case TRADE_SIGNAL_PROP_MAGIC_ID: + return (T)magic_id; + case TRADE_SIGNAL_PROP_SIGNALS: + return (T)signals; + case TRADE_SIGNAL_PROP_STRENGTH: + return (T)strength; + case TRADE_SIGNAL_PROP_TF: + return (T)tf; + case TRADE_SIGNAL_PROP_TIME: + return (T)timestamp; + case TRADE_SIGNAL_PROP_WEIGHT: + return (T)weight; + } + SetUserError(ERR_INVALID_PARAMETER); + return (T)WRONG_VALUE; + } + bool Get(STRUCT_ENUM(TradeSignalEntry, ENUM_TRADE_SIGNAL_FLAG) _prop) { return CheckSignals(_prop); } + /* Setters */ + template + void Set(STRUCT_ENUM(TradeSignalEntry, ENUM_TRADE_SIGNAL_PROP) _prop, T _value) { + switch (_prop) { + case TRADE_SIGNAL_PROP_MAGIC_ID: + magic_id = (long)_value; + return; + case TRADE_SIGNAL_PROP_SIGNALS: + signals = (unsigned int)_value; + return; + case TRADE_SIGNAL_PROP_STRENGTH: + strength = (float)_value; + return; + case TRADE_SIGNAL_PROP_TF: + tf = (ENUM_TIMEFRAMES)_value; + return; + case TRADE_SIGNAL_PROP_TIME: + timestamp = (long)_value; + return; + case TRADE_SIGNAL_PROP_WEIGHT: + weight = (float)_value; + return; + } + SetUserError(ERR_INVALID_PARAMETER); + } + void Set(STRUCT_ENUM(TradeSignalEntry, ENUM_TRADE_SIGNAL_FLAG) _prop, bool _value) { SetSignal(_prop, _value); } + /* Signal methods for bitwise operations */ + bool CheckSignals(unsigned int _flags) { return (signals & _flags) != 0; } + bool CheckSignalsEqual(unsigned int _flags, unsigned int _value) { return (signals & _flags) == _value; } + bool CheckSignalsExact(unsigned int _flags) { return (signals & _flags) == _flags; } + unsigned int GetSignals() { return signals; } + /* Setters */ + void AddSignals(unsigned int _flags) { signals |= _flags; } + void RemoveSignals(unsigned int _flags) { signals &= ~_flags; } + void SetSignal(ENUM_TRADE_SIGNAL_FLAG _flag, bool _value = true) { + if (_value) { + AddSignals(_flag); + } else { + RemoveSignals(_flag); + } + } + void SetSignals(unsigned int _flags) { signals = _flags; } + // Serializers. + SERIALIZER_EMPTY_STUB; + SerializerNodeType Serialize(Serializer &_s) { + _s.PassEnum(THIS_REF, "tf", tf); + _s.Pass(THIS_REF, "timestamp", timestamp, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + _s.Pass(THIS_REF, "strength", strength, SERIALIZER_FIELD_FLAG_DYNAMIC); + _s.Pass(THIS_REF, "weight", weight, SERIALIZER_FIELD_FLAG_DYNAMIC); + int _size = sizeof(int) * 8; + for (int i = 0; i < _size; i++) { + int _value = CheckSignals(1 << i) ? 1 : 0; + _s.Pass(THIS_REF, (string)(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + } + return SerializerNodeObject; + } + string ToString() { + // SerializerConverter _stub = SerializerConverter::MakeStubObject(SERIALIZER_FLAG_SKIP_HIDDEN); + return SerializerConverter::FromObject(THIS_REF, SERIALIZER_FLAG_SKIP_HIDDEN) + .ToString(SERIALIZER_JSON_NO_WHITESPACES); + } +}; diff --git a/Trade/TradeSignalManager.h b/Trade/TradeSignalManager.h new file mode 100644 index 000000000..a421dd1fb --- /dev/null +++ b/Trade/TradeSignalManager.h @@ -0,0 +1,138 @@ +//+------------------------------------------------------------------+ +//| 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 + * Implements TradeSignalManager class. + */ + +// Includes. +#include "../DictObject.mqh" +#include "TradeSignal.h" + +/** + * Class to store and manage a trading signal. + */ +class TradeSignalManager : Dynamic { + protected: + DictObject signals_active; + DictObject signals_expired; + DictObject signals_processed; + + public: + /** + * Class constructor. + */ + TradeSignalManager() { + signals_active.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); + signals_expired.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); + signals_processed.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); + } + + /* Getters */ + + /** + * Gets an iterator instance. + * + */ + DictObjectIterator GetIterSignalsActive() { + DictObjectIterator _iter = signals_active.Begin(); + return _iter; + } + + /** + * Gets pointer to active signals. + * + */ + DictObject *GetSignalsActive() { return &signals_active; } + + /** + * Gets pointer to expired signals. + * + */ + DictObject *GetSignalsExpired() { return &signals_expired; } + + /** + * Gets pointer to processed signals. + * + */ + DictObject *GetSignalsProcessed() { return &signals_processed; } + + /* Setters */ + + /* Signal methods */ + + /** + * Adds new signal. + * + */ + void SignalAdd(TradeSignal &_signal) { signals_active.Push(_signal); } + + /** + * Refresh signals. + * + * Move already processed signals or expired to different list. + * + */ + void Refresh() { + for (DictObjectIterator iter = GetIterSignalsActive(); iter.IsValid(); ++iter) { + TradeSignal *_signal = iter.Value(); + if (_signal.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_PROCESSED))) { + signals_active.Unset(iter); + signals_processed.Push(_signal); + continue; + } + if (_signal.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_EXPIRED))) { + signals_active.Unset(iter); + signals_expired.Push(_signal); + continue; + } + } + } + + /* Serializers */ + + SERIALIZER_EMPTY_STUB; + + /** + * Serializes this class. + * + * @return + * Returns a JSON serialized instance. + */ + SerializerNodeType Serialize(Serializer &_s) { + _s.PassObject(THIS_REF, "signals_active", signals_active); + return SerializerNodeObject; + } + + /** + * Converts this class into a string. + * + * @return + * Returns a JSON serialized signal. + */ + string ToString() { + // SerializerConverter _stub = SerializerConverter::MakeStubObject(SERIALIZER_FLAG_SKIP_HIDDEN); + return SerializerConverter::FromObject(THIS_REF, SERIALIZER_FLAG_SKIP_HIDDEN) + .ToString(SERIALIZER_JSON_NO_WHITESPACES); + } +}; diff --git a/Trade/tests/TradeSignalManagerTest.mq4 b/Trade/tests/TradeSignalManagerTest.mq4 new file mode 100644 index 000000000..c199b1143 --- /dev/null +++ b/Trade/tests/TradeSignalManagerTest.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| 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 TradeSignalManager class. + */ + +// Includes. +#include "TradeSignalManagerTest.mq5" diff --git a/Trade/tests/TradeSignalManagerTest.mq5 b/Trade/tests/TradeSignalManagerTest.mq5 new file mode 100644 index 000000000..dd0bb64ed --- /dev/null +++ b/Trade/tests/TradeSignalManagerTest.mq5 @@ -0,0 +1,62 @@ +//+------------------------------------------------------------------+ +//| 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 TradeSignalManager class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../TradeSignalManager.h" + +// Test signals for processing. +bool TestSignalsProcessed() { + bool _result = true; + TradeSignalManager _tsm; + for (int i = 0; i < 10; i++) { + TradeSignalEntry _entry(i % 2 == 0 ? SIGNAL_OPEN_BUY_MAIN : SIGNAL_OPEN_SELL_MAIN); + TradeSignal _signal(_entry); + _tsm.SignalAdd(_signal); + } + _result &= _tsm.GetSignalsActive().Size() == 10; + Print(_tsm.ToString()); + for (DictObjectIterator iter = _tsm.GetIterSignalsActive(); iter.IsValid(); ++iter) { + TradeSignal *_signal = iter.Value(); + // Set signal as processed. + _signal.Set(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_PROCESSED), true); + } + _tsm.Refresh(); + _result &= _tsm.GetSignalsActive().Size() == 0; + _result &= _tsm.GetSignalsExpired().Size() == 0; + _result &= _tsm.GetSignalsProcessed().Size() == 10; + Print(_tsm.ToString()); + return _result; +} + +/** + * Implements OnInit(). + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(_result &= TestSignalsProcessed(), "Fail!"); + return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; +} diff --git a/Trade/tests/TradeSignalTest.mq4 b/Trade/tests/TradeSignalTest.mq4 new file mode 100644 index 000000000..8c80fd59a --- /dev/null +++ b/Trade/tests/TradeSignalTest.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| 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 TradeSignal class. + */ + +// Includes. +#include "TradeSignalTest.mq5" diff --git a/Trade/tests/TradeSignalTest.mq5 b/Trade/tests/TradeSignalTest.mq5 new file mode 100644 index 000000000..e1f18adb3 --- /dev/null +++ b/Trade/tests/TradeSignalTest.mq5 @@ -0,0 +1,342 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TradeSignal class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../TradeSignal.h" + +// Test signals to close buy trade with filters. +bool TestTradeSignalCloseBuyWithFilters() { + bool _result = true; + // 1st method. + TradeSignalEntry _entry1(SIGNAL_CLOSE_BUY_MAIN | SIGNAL_CLOSE_BUY_FILTER); + TradeSignal _signal1(_entry1); + _result &= !_signal1.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldClose(ORDER_TYPE_SELL); + // Do not close due to buy filter flag. + _result &= !_signal1.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal1.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 1.0f; + _result &= _signal1.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 0.0f; + Print(_signal1.ToString()); + // 2nd method. + TradeSignalEntry _entry2; + _entry2.Set(SIGNAL_CLOSE_BUY_MAIN, true); + _entry2.Set(SIGNAL_CLOSE_BUY_FILTER, true); + _entry2.Set(SIGNAL_CLOSE_TIME_FILTER, true); + TradeSignal _signal2(_entry2); + // Do not close due to buy and time filter flags. + _result &= !_signal2.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldClose(ORDER_TYPE_SELL); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal2.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 1.0f; + _result &= _signal2.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 0.0f; + Print(_signal2.ToString()); + return _result; +} + +// Test signals to close buy trade without filters. +bool TestTradeSignalCloseBuyWithoutFilters() { + bool _result = true; + // 1st method. + TradeSignalEntry _entry1(SIGNAL_CLOSE_BUY_MAIN); + TradeSignal _signal1(_entry1); + _result &= _signal1.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldClose(ORDER_TYPE_SELL); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal1.GetSignalClose() >= 0.5; + _result &= _signal1.GetSignalCloseDirection() == 1.0f; + _result &= _signal1.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 0.0f; + Print(_signal1.ToString()); + // 2nd method. + TradeSignalEntry _entry2; + _entry2.Set(SIGNAL_CLOSE_BUY_MAIN, true); + TradeSignal _signal2(_entry2); + _result &= _signal2.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldClose(ORDER_TYPE_SELL); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal2.GetSignalClose() >= 0.5f; + _result &= _signal1.GetSignalCloseDirection() == 1.0f; + _result &= _signal2.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 0.0f; + Print(_signal2.ToString()); + return _result; +} + +// Test signals to close sell trade with filters. +bool TestTradeSignalCloseSellWithFilters() { + bool _result = true; + // 1st method. + TradeSignalEntry _entry1(SIGNAL_CLOSE_SELL_MAIN | SIGNAL_CLOSE_SELL_FILTER); + TradeSignal _signal1(_entry1); + _result &= !_signal1.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldClose(ORDER_TYPE_SELL); + // Do not close due to sell filter flag. + _result &= !_signal1.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal1.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == -1.0f; + _result &= _signal1.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 0.0f; + Print(_signal1.ToString()); + // 2nd method. + TradeSignalEntry _entry2; + _entry2.Set(SIGNAL_CLOSE_SELL_MAIN, true); + _entry2.Set(SIGNAL_CLOSE_SELL_FILTER, true); + _entry2.Set(SIGNAL_CLOSE_TIME_FILTER, true); + TradeSignal _signal2(_entry2); + // Do not close due to sell and time filter flags. + _result &= !_signal2.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldClose(ORDER_TYPE_SELL); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal2.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == -1.0f; + _result &= _signal2.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 0.0f; + Print(_signal2.ToString()); + return _result; +} + +// Test signals to close sell trade without filters. +bool TestTradeSignalCloseSellWithoutFilters() { + bool _result = true; + // 1st method. + TradeSignalEntry _entry1(SIGNAL_CLOSE_SELL_MAIN); + TradeSignal _signal1(_entry1); + _result &= !_signal1.ShouldClose(ORDER_TYPE_BUY); + _result &= _signal1.ShouldClose(ORDER_TYPE_SELL); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal1.GetSignalClose() <= -0.5; + _result &= _signal1.GetSignalCloseDirection() == -1.0f; + _result &= _signal1.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 0.0f; + Print(_signal1.ToString()); + // 2nd method. + TradeSignalEntry _entry2; + _entry2.Set(SIGNAL_CLOSE_SELL_MAIN, true); + TradeSignal _signal2(_entry2); + _result &= !_signal2.ShouldClose(ORDER_TYPE_BUY); + _result &= _signal2.ShouldClose(ORDER_TYPE_SELL); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal2.GetSignalClose() <= -0.5; + _result &= _signal1.GetSignalCloseDirection() == -1.0f; + _result &= _signal2.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 0.0f; + Print(_signal2.ToString()); + return _result; +} + +// Test signals to open buy trade with filters. +bool TestTradeSignalOpenBuyWithFilters() { + bool _result = true; + // 1st method. + TradeSignalEntry _entry1(SIGNAL_OPEN_BUY_MAIN | SIGNAL_OPEN_BUY_FILTER); + TradeSignal _signal1(_entry1); + _result &= !_signal1.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldClose(ORDER_TYPE_SELL); + // Do not open due to buy filter flag. + _result &= !_signal1.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal1.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 0.0f; + _result &= _signal1.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 1.0f; + Print(_signal1.ToString()); + // 2nd method. + TradeSignalEntry _entry2; + _entry2.Set(SIGNAL_OPEN_BUY_MAIN, true); + _entry2.Set(SIGNAL_OPEN_BUY_FILTER, true); + _entry2.Set(SIGNAL_OPEN_TIME_FILTER, true); + TradeSignal _signal2(_entry2); + _result &= !_signal2.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldClose(ORDER_TYPE_SELL); + // Do not open due to buy and time filter flags. + _result &= !_signal2.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal2.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 0.0f; + _result &= _signal2.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 1.0f; + Print(_signal2.ToString()); + return _result; +} + +// Test signals to open buy trade without filters. +bool TestTradeSignalOpenBuyWithoutFilters() { + bool _result = true; + // 1st method. + TradeSignalEntry _entry1(SIGNAL_OPEN_BUY_MAIN); + TradeSignal _signal1(_entry1); + _result &= !_signal1.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldClose(ORDER_TYPE_SELL); + _result &= _signal1.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal1.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 0.0f; + _result &= _signal1.GetSignalOpen() >= 0.5; + _result &= _signal1.GetSignalOpenDirection() == 1.0f; + Print(_signal1.ToString()); + // 2nd method. + TradeSignalEntry _entry2; + _entry2.Set(SIGNAL_OPEN_BUY_MAIN, true); + TradeSignal _signal2(_entry2); + _result &= !_signal2.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldClose(ORDER_TYPE_SELL); + _result &= _signal2.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal2.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 0.0f; + _result &= _signal2.GetSignalOpen() >= 0.5f; + _result &= _signal1.GetSignalOpenDirection() == 1.0f; + Print(_signal2.ToString()); + return _result; +} + +// Test signals to open sell trade with filters. +bool TestTradeSignalOpenSellWithFilters() { + bool _result = true; + // 1st method. + TradeSignalEntry _entry1(SIGNAL_OPEN_SELL_MAIN | SIGNAL_OPEN_SELL_FILTER); + TradeSignal _signal1(_entry1); + _result &= !_signal1.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldClose(ORDER_TYPE_SELL); + // Do not open due to sell filter flag. + _result &= !_signal1.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal1.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 0.0f; + _result &= _signal1.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == -1.0f; + Print(_signal1.ToString()); + // 2nd method. + TradeSignalEntry _entry2; + _entry2.Set(SIGNAL_OPEN_SELL_MAIN, true); + _entry2.Set(SIGNAL_OPEN_SELL_FILTER, true); + _entry2.Set(SIGNAL_OPEN_TIME_FILTER, true); + TradeSignal _signal2(_entry2); + _result &= !_signal2.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldClose(ORDER_TYPE_SELL); + // Do not open due to sell and time filter flags. + _result &= !_signal2.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal2.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 0.0f; + _result &= _signal2.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == -1.0f; + Print(_signal2.ToString()); + return _result; +} + +// Test signals to open sell trade without filters. +bool TestTradeSignalOpenSellWithoutFilters() { + bool _result = true; + // 1st method. + TradeSignalEntry _entry1(SIGNAL_OPEN_SELL_MAIN); + TradeSignal _signal1(_entry1); + _result &= !_signal1.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldClose(ORDER_TYPE_SELL); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_BUY); + _result &= _signal1.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal1.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 0.0f; + _result &= _signal1.GetSignalOpen() <= -0.5; + _result &= _signal1.GetSignalOpenDirection() == -1.0f; + Print(_signal1.ToString()); + // 2nd method. + TradeSignalEntry _entry2; + _entry2.Set(SIGNAL_OPEN_SELL_MAIN, true); + TradeSignal _signal2(_entry2); + _result &= !_signal2.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldClose(ORDER_TYPE_SELL); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_BUY); + _result &= _signal2.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal2.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 0.0f; + _result &= _signal2.GetSignalOpen() <= -0.5; + _result &= _signal1.GetSignalOpenDirection() == -1.0f; + Print(_signal2.ToString()); + return _result; +} + +// Test empty signal. +bool TestTradeSignalNone() { + bool _result = true; + // 1st method. + TradeSignalEntry _entry1(SIGNAL_CLOSE_BUY_FILTER | SIGNAL_CLOSE_SELL_FILTER); + TradeSignal _signal1(_entry1); + _result &= !_signal1.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldClose(ORDER_TYPE_SELL); + // Do not close due to buy filter flag. + _result &= !_signal1.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal1.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal1.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 0.0f; + _result &= _signal1.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 0.0f; + Print(_signal1.ToString()); + // 2nd method. + TradeSignalEntry _entry2; + TradeSignal _signal2(_entry2); + // Do not close due to buy and time filter flags. + _result &= !_signal2.ShouldClose(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldClose(ORDER_TYPE_SELL); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_BUY); + _result &= !_signal2.ShouldOpen(ORDER_TYPE_SELL); + _result &= _signal2.GetSignalClose() == 0.0f; + _result &= _signal1.GetSignalCloseDirection() == 0.0f; + _result &= _signal2.GetSignalOpen() == 0.0f; + _result &= _signal1.GetSignalOpenDirection() == 0.0f; + Print(_signal2.ToString()); + return _result; +} + +/** + * Implements OnInit(). + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(TestTradeSignalCloseBuyWithFilters(), "Fail!"); + assertTrueOrFail(TestTradeSignalCloseBuyWithoutFilters(), "Fail!"); + assertTrueOrFail(TestTradeSignalCloseSellWithFilters(), "Fail!"); + assertTrueOrFail(TestTradeSignalCloseSellWithoutFilters(), "Fail!"); + assertTrueOrFail(TestTradeSignalOpenBuyWithFilters(), "Fail!"); + assertTrueOrFail(TestTradeSignalOpenBuyWithoutFilters(), "Fail!"); + assertTrueOrFail(TestTradeSignalOpenSellWithFilters(), "Fail!"); + assertTrueOrFail(TestTradeSignalOpenSellWithoutFilters(), "Fail!"); + assertTrueOrFail(TestTradeSignalNone(), "Fail!"); + return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; +} diff --git a/Util.h b/Util.h index 243b80752..89c1e866e 100644 --- a/Util.h +++ b/Util.h @@ -1,31 +1,42 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, 31337 Investments Ltd | +//| 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 . - * + * 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 * Utility methods. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "SerializerConversions.h" + +/** + * Utility methods. + */ class Util { + public: /** * Resizes native array and reserves space for further items by some fixed step. */ @@ -76,4 +87,82 @@ class Util { return false; } + + /** + * Creates string-based key using given variables. + */ + template + static string MakeKey(const A a) { + return SerializerConversions::ValueToString(a); + } + + /** + * Creates string-based key using given variables. + */ + template + static string MakeKey(const A _a, const B _b) { + return SeparatedMaybe(SerializerConversions::ValueToString(_a)) + SerializerConversions::ValueToString(_b); + } + + /** + * Creates string-based key using given variables. + */ + template + static string MakeKey(const A _a, const B _b, const C _c) { + return SeparatedMaybe(SerializerConversions::ValueToString(_a)) + + SeparatedMaybe(SerializerConversions::ValueToString(_b)) + SerializerConversions::ValueToString(_c); + } + + /** + * Creates string-based key using given variables. + */ + template + static string MakeKey(const A _a, const B _b, const C _c, const D _d) { + return SeparatedMaybe(SerializerConversions::ValueToString(_a)) + + SeparatedMaybe(SerializerConversions::ValueToString(_b)) + + SeparatedMaybe(SerializerConversions::ValueToString(_c)) + SerializerConversions::ValueToString(_d); + } + + /** + * Creates string-based key using given variables. + */ + template + static string MakeKey(const A _a, const B _b, const C _c, const D _d, const E _e) { + return SeparatedMaybe(SerializerConversions::ValueToString(_a)) + + SeparatedMaybe(SerializerConversions::ValueToString(_b)) + + SeparatedMaybe(SerializerConversions::ValueToString(_c)) + + SeparatedMaybe(SerializerConversions::ValueToString(_d)) + SerializerConversions::ValueToString(_e); + } + + /** + * Creates string-based key using given variables. + */ + template + static string MakeKey(const A _a, const B _b, const C _c, const D _d, const E _e, const F _f) { + return SeparatedMaybe(SerializerConversions::ValueToString(_a)) + + SeparatedMaybe(SerializerConversions::ValueToString(_b)) + + SeparatedMaybe(SerializerConversions::ValueToString(_c)) + + SeparatedMaybe(SerializerConversions::ValueToString(_d)) + + SeparatedMaybe(SerializerConversions::ValueToString(_e)) + SerializerConversions::ValueToString(_f); + } + + /** + * Creates string-based key using given variables. + */ + template + static string MakeKey(const A _a, const B _b, const C _c, const D _d, const E _e, const F _f, const G _g) { + return SeparatedMaybe(SerializerConversions::ValueToString(_a)) + + SeparatedMaybe(SerializerConversions::ValueToString(_b)) + + SeparatedMaybe(SerializerConversions::ValueToString(_c)) + + SeparatedMaybe(SerializerConversions::ValueToString(_d)) + + SeparatedMaybe(SerializerConversions::ValueToString(_e)) + + SeparatedMaybe(SerializerConversions::ValueToString(_f)) + SerializerConversions::ValueToString(_g); + } + + /** + * Creates string with separator if string was not empty. + */ + static string SeparatedMaybe(string _value, string _separator = "/") { + return _value == "" ? "" : (_value + _separator); + } }; diff --git a/tests/CompileIndicatorsTest.mq5 b/tests/CompileIndicatorsTest.mq5 index b772bc476..4d0b149bd 100644 --- a/tests/CompileIndicatorsTest.mq5 +++ b/tests/CompileIndicatorsTest.mq5 @@ -30,4 +30,4 @@ /** * Implements Init event handler. */ -int OnInit() { return (_LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); } +int OnInit() { return 0; } diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index f13ef9837..c9fd8436f 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -36,7 +36,7 @@ // Global variables. Chart *chart; -Dict indis; +Dict indis; int bar_processed; /** @@ -64,8 +64,8 @@ void OnTick() { if (chart.IsNewBar()) { bar_processed++; - for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { - Indicator *_indi = iter.Value(); + for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { + IndicatorBase *_indi = iter.Value(); _indi.OnTick(); IndicatorDataEntry _entry = _indi.GetEntry(); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)) && _entry.IsValid()) { @@ -81,7 +81,7 @@ void OnTick() { void OnDeinit(const int reason) { delete chart; - for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { + for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { delete iter.Value(); } } @@ -98,7 +98,7 @@ bool InitIndicators() { // Moving Average. MAParams ma_params(13, 10, MODE_SMA, PRICE_OPEN); - Indicator *indi_ma = new Indi_MA(ma_params); + IndicatorBase *indi_ma = new Indi_MA(ma_params); indis.Set(INDI_MA, indi_ma); // Relative Strength Index (RSI). @@ -109,38 +109,38 @@ bool InitIndicators() { // Demo/Dummy Indicator. DemoIndiParams demo_params; - Indicator *indi_demo = new Indi_Demo(demo_params); + IndicatorBase *indi_demo = new Indi_Demo(demo_params); indis.Set(INDI_DEMO, indi_demo); // Current Price (used by custom indicators) . PriceIndiParams price_params(); price_params.SetDraw(clrGreenYellow); - Indicator *indi_price = new Indi_Price(price_params); + IndicatorBase *indi_price = new Indi_Price(price_params); indis.Set(INDI_PRICE, indi_price); // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); - Indicator *indi_price_4_bands = new Indi_Price(price_params_4_bands); + IndicatorBase *indi_price_4_bands = new Indi_Price(price_params_4_bands); BandsParams bands_on_price_params(); bands_on_price_params.SetDraw(clrCadetBlue); - bands_on_price_params.SetDataSource(indi_price_4_bands, true, INDI_PRICE_MODE_OPEN); - indis.Set(INDI_BANDS_ON_PRICE, new Indi_Bands(bands_on_price_params)); + // bands_on_price_params.SetDataSource(indi_price_4_bands, true, INDI_PRICE_MODE_OPEN); + indis.Set(INDI_BANDS_ON_PRICE, new Indi_Bands(bands_on_price_params, indi_price_4_bands, true)); // Moving Average (MA) over Price indicator. PriceIndiParams price_params_4_ma(); - Indicator *indi_price_4_ma = new Indi_Price(price_params_4_ma); + IndicatorBase *indi_price_4_ma = new Indi_Price(price_params_4_ma); MAParams ma_on_price_params(); ma_on_price_params.SetDraw(clrYellowGreen); - ma_on_price_params.SetDataSource(indi_price_4_ma, true, INDI_PRICE_MODE_OPEN); + // ma_on_price_params.SetDataSource(indi_price_4_ma, true, INDI_PRICE_MODE_OPEN); ma_on_price_params.SetIndicatorType(INDI_MA_ON_PRICE); - Indicator *indi_ma_on_price = new Indi_MA(ma_on_price_params); + IndicatorBase *indi_ma_on_price = new Indi_MA(ma_on_price_params, indi_price_4_ma); indis.Set(INDI_MA_ON_PRICE, indi_ma_on_price); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); - Indicator *indi_price_4_rsi = new Indi_Price(price_params_4_rsi); + IndicatorBase *indi_price_4_rsi = new Indi_Price(price_params_4_rsi); RSIParams rsi_on_price_params(); - rsi_on_price_params.SetDataSource(indi_price_4_rsi, true, INDI_PRICE_MODE_OPEN); + // rsi_on_price_params.SetDataSource(indi_price_4_rsi, true, INDI_PRICE_MODE_OPEN); rsi_on_price_params.SetDraw(clrBisque, 1); indis.Set(INDI_RSI_ON_PRICE, indi_price_4_rsi); @@ -151,8 +151,8 @@ bool InitIndicators() { * Print indicators. */ bool PrintIndicators(string _prefix = "") { - for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { - Indicator *_indi = iter.Value(); + for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { + IndicatorBase *_indi = iter.Value(); MqlParam _value = _indi.GetEntryValue(); if (GetLastError() == ERR_INDICATOR_DATA_NOT_FOUND || GetLastError() == ERR_USER_ERROR_FIRST + ERR_USER_INVALID_BUFF_NUM) { diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 70169de92..c648ff30d 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -108,8 +108,8 @@ enum ENUM_CUSTOM_INDICATORS { INDI_SPECIAL_MATH_CUSTOM = FINAL_INDICATOR_TYPE_EN // Global variables. Chart *chart; -Dict indis; -Dict whitelisted_indis; +Dict indis; +Dict whitelisted_indis; Dict tested; int bar_processed; 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, @@ -124,6 +124,7 @@ int OnInit() { bool _result = true; // Initialize chart. chart = new Chart(); + Print("We have ", Bars(NULL, 0), " bars to analyze"); // Initialize indicators. _result &= InitIndicators(); Print("Indicators to test: ", indis.Size()); @@ -147,7 +148,7 @@ void OnTick() { if (indis.Size() == 0) { return; } - for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { + for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { if (whitelisted_indis.Size() == 0) { if (tested.GetByKey(iter.Key())) { // Indicator is already tested, skipping. @@ -159,7 +160,7 @@ void OnTick() { } } - Indicator *_indi = iter.Value(); + IndicatorBase *_indi = iter.Value(); _indi.OnTick(); IndicatorDataEntry _entry = _indi.GetEntry(); @@ -185,7 +186,7 @@ void OnDeinit(const int reason) { delete chart; - for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { + for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { delete iter.Value(); } @@ -225,7 +226,7 @@ bool InitIndicators() { // Bollinger Bands. BandsParams bands_params(20, 2, 0, PRICE_OPEN); - Indicator *indi_bands = new Indi_Bands(bands_params); + IndicatorBase *indi_bands = new Indi_Bands(bands_params); indis.Push(indi_bands); // Bollinger Bands over RSI. @@ -264,7 +265,7 @@ bool InitIndicators() { indis.Push(new Indi_Fractals()); // Fractal Adaptive Moving Average (FRAMA). - FrIndiAMAParams frama_params(); + IndiFrAMAParams frama_params(); indis.Push(new Indi_FrAMA(frama_params)); // Gator Oscillator. @@ -272,9 +273,7 @@ bool InitIndicators() { indis.Push(new Indi_Gator(gator_params)); // Heiken Ashi. -#ifdef __MQL5__ indis.Push(new Indi_HeikenAshi()); -#endif // Ichimoku Kinko Hyo. IchimokuParams ichi_params(9, 26, 52); @@ -282,17 +281,17 @@ bool InitIndicators() { // Moving Average. MAParams ma_params(13, 0, MODE_SMA, PRICE_OPEN); - Indicator *indi_ma = new Indi_MA(ma_params); + IndicatorBase *indi_ma = new Indi_MA(ma_params); indis.Push(indi_ma); // DEMA. DEMAParams dema_params(13, 2, PRICE_OPEN); - Indicator *indi_dema = new Indi_DEMA(dema_params); + IndicatorBase *indi_dema = new Indi_DEMA(dema_params); indis.Push(indi_dema); // MACD. MACDParams macd_params(12, 26, 9, PRICE_CLOSE); - Indicator *macd = new Indi_MACD(macd_params); + IndicatorBase *macd = new Indi_MACD(macd_params); indis.Push(macd); // Money Flow Index (MFI). @@ -332,12 +331,13 @@ bool InitIndicators() { indis.Push(new Indi_StdDev(stddev_params)); // Standard Deviation (StdDev). - Indicator *indi_price_for_stdev = new Indi_Price(PriceIndiParams()); + IndicatorBase *indi_price_for_stdev = new Indi_Price(PriceIndiParams()); StdDevParams stddev_on_price_params(); - stddev_on_price_params.SetDataSource(indi_price_for_stdev, true, PRICE_OPEN); stddev_on_price_params.SetDraw(clrBlue, 1); - indis.Push(new Indi_StdDev(stddev_on_price_params)); + Indi_StdDev *indi_stddev_on_price = new Indi_StdDev(stddev_on_price_params); + indi_stddev_on_price.SetDataSource(indi_price_for_stdev, true, PRICE_OPEN); + indis.Push(indi_stddev_on_price); // Stochastic Oscillator. StochParams stoch_params(5, 3, 3, MODE_SMMA, STO_LOWHIGH); @@ -359,85 +359,94 @@ bool InitIndicators() { // Current Price. PriceIndiParams price_params(); // price_params.SetDraw(clrAzure); - Indicator *indi_price = new Indi_Price(price_params); + IndicatorBase *indi_price = new Indi_Price(price_params); indis.Push(indi_price); // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); - Indicator *indi_price_4_bands = new Indi_Price(price_params_4_bands); + IndicatorBase *indi_price_4_bands = new Indi_Price(price_params_4_bands); BandsParams bands_on_price_params(); bands_on_price_params.SetDraw(clrCadetBlue); - bands_on_price_params.SetDataSource(indi_price_4_bands, true, INDI_PRICE_MODE_OPEN); - indis.Push(new Indi_Bands(bands_on_price_params)); + Indi_Bands *indi_bands_on_price = new Indi_Bands(bands_on_price_params); + indi_bands_on_price.SetDataSource(indi_price_4_bands, true, INDI_PRICE_MODE_OPEN); + indis.Push(indi_bands_on_price); // Standard Deviation (StdDev) over MA(SMA). // NOTE: If you set ma_shift parameter for MA, then StdDev will no longer // match built-in StdDev indicator (as it doesn't use ma_shift for averaging). MAParams ma_sma_params_for_stddev(); - Indicator *indi_ma_sma_for_stddev = new Indi_MA(ma_sma_params_for_stddev); + IndicatorBase *indi_ma_sma_for_stddev = new Indi_MA(ma_sma_params_for_stddev); StdDevParams stddev_params_on_ma_sma(13, 10); stddev_params_on_ma_sma.SetDraw(true, 1); - stddev_params_on_ma_sma.SetDataSource(indi_ma_sma_for_stddev, true, 0); - indis.Push(new Indi_StdDev(stddev_params_on_ma_sma)); + + Indi_StdDev *indi_stddev_on_ma_sma = new Indi_StdDev(stddev_params_on_ma_sma); + indi_stddev_on_ma_sma.SetDataSource(indi_ma_sma_for_stddev, true, 0); + indis.Push(indi_stddev_on_ma_sma); // Standard Deviation (StdDev) in SMA mode over Price. PriceIndiParams price_params_for_stddev_sma(); - Indicator *indi_price_for_stddev_sma = new Indi_Price(price_params_for_stddev_sma); + IndicatorBase *indi_price_for_stddev_sma = new Indi_Price(price_params_for_stddev_sma); StdDevParams stddev_sma_on_price_params(); stddev_sma_on_price_params.SetDraw(true, 1); - stddev_sma_on_price_params.SetDataSource(indi_price_for_stddev_sma, true, INDI_PRICE_MODE_OPEN); - indis.Push(new Indi_StdDev(stddev_sma_on_price_params)); + Indi_StdDev *indi_stddev_on_sma = new Indi_StdDev(stddev_sma_on_price_params); + indi_stddev_on_sma.SetDataSource(indi_price_for_stddev_sma, true, INDI_PRICE_MODE_OPEN); + indis.Push(indi_stddev_on_sma); // Moving Average (MA) over Price indicator. PriceIndiParams price_params_4_ma(); - Indicator *indi_price_4_ma = new Indi_Price(price_params_4_ma); + IndicatorBase *indi_price_4_ma = new Indi_Price(price_params_4_ma); MAParams ma_on_price_params(13, 0, MODE_SMA, PRICE_OPEN, 0); ma_on_price_params.SetDraw(clrYellowGreen); - ma_on_price_params.SetDataSource(indi_price_4_ma, true, INDI_PRICE_MODE_OPEN); ma_on_price_params.SetIndicatorType(INDI_MA_ON_PRICE); - indis.Push(new Indi_MA(ma_on_price_params)); + Indi_MA *indi_ma_on_price = new Indi_MA(ma_on_price_params); + indi_ma_on_price.SetDataSource(indi_price_4_ma, true, INDI_PRICE_MODE_OPEN); + indis.Push(indi_ma_on_price); // Commodity Channel Index (CCI) over Price indicator. PriceIndiParams price_params_4_cci(); - Indicator *indi_price_4_cci = new Indi_Price(price_params_4_cci); + IndicatorBase *indi_price_4_cci = new Indi_Price(price_params_4_cci); CCIParams cci_on_price_params(); cci_on_price_params.SetDraw(clrYellowGreen, 1); - cci_on_price_params.SetDataSource(indi_price_4_cci, true, INDI_PRICE_MODE_OPEN); - Indicator *indi_cci_on_price = new Indi_CCI(cci_on_price_params); + IndicatorBase *indi_cci_on_price = new Indi_CCI(cci_on_price_params); + indi_cci_on_price.SetDataSource(indi_price_4_cci, true, INDI_PRICE_MODE_OPEN); indis.Push(indi_cci_on_price); // Envelopes over Price indicator. PriceIndiParams price_params_4_envelopes(); - Indicator *indi_price_4_envelopes = new Indi_Price(price_params_4_envelopes); + IndicatorBase *indi_price_4_envelopes = new Indi_Price(price_params_4_envelopes); EnvelopesParams env_on_price_params(); - env_on_price_params.SetDataSource(indi_price_4_envelopes, true, INDI_PRICE_MODE_OPEN); env_on_price_params.SetDraw(clrBrown); - indis.Push(new Indi_Envelopes(env_on_price_params)); + Indi_Envelopes *indi_envelopes_on_price = new Indi_Envelopes(env_on_price_params); + indi_envelopes_on_price.SetDataSource(indi_price_4_envelopes, true, INDI_PRICE_MODE_OPEN); + indis.Push(indi_envelopes_on_price); // DEMA over Price indicator. PriceIndiParams price_params_4_dema(); - Indicator *indi_price_4_dema = new Indi_Price(price_params_4_dema); + IndicatorBase *indi_price_4_dema = new Indi_Price(price_params_4_dema); DEMAParams dema_on_price_params(13, 2, PRICE_OPEN); - dema_on_price_params.SetDataSource(indi_price_4_dema, true, INDI_PRICE_MODE_OPEN); dema_on_price_params.SetDraw(clrRed); - indis.Push(new Indi_DEMA(dema_on_price_params)); + Indi_DEMA *indi_dema_on_price = new Indi_DEMA(dema_on_price_params); + indi_dema_on_price.SetDataSource(indi_price_4_dema, true, INDI_PRICE_MODE_OPEN); + indis.Push(indi_dema_on_price); // Momentum over Price indicator. - Indicator *indi_price_4_momentum = new Indi_Price(); + IndicatorBase *indi_price_4_momentum = new Indi_Price(); MomentumParams mom_on_price_params(); - mom_on_price_params.SetDataSource(indi_price_4_momentum); mom_on_price_params.SetDraw(clrDarkCyan); - indis.Push(new Indi_Momentum(mom_on_price_params)); + Indi_Momentum *indi_momentum_on_price = new Indi_Momentum(mom_on_price_params); + indi_momentum_on_price.SetDataSource(indi_price_4_momentum, true, 0); + indis.Push(indi_momentum_on_price); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); - Indicator *indi_price_4_rsi = new Indi_Price(price_params_4_rsi); + IndicatorBase *indi_price_4_rsi = new Indi_Price(price_params_4_rsi); RSIParams rsi_on_price_params(); - rsi_on_price_params.SetDataSource(indi_price_4_rsi, true, INDI_PRICE_MODE_OPEN); rsi_on_price_params.SetDraw(clrBisque, 1); - indis.Push(new Indi_RSI(rsi_on_price_params)); + Indi_RSI *indi_rsi_on_price = new Indi_RSI(rsi_on_price_params); + indi_rsi_on_price.SetDataSource(indi_price_4_rsi, true, INDI_PRICE_MODE_OPEN); + indis.Push(indi_rsi_on_price); // Drawer (socket-based) indicator. DrawerParams drawer_params(14, /*unused*/ PRICE_OPEN); @@ -450,8 +459,9 @@ bool InitIndicators() { AppliedPriceParams applied_price_params(); applied_price_params.SetDraw(clrAquamarine, 0); PriceIndiParams applied_price_price_params; - applied_price_params.SetDataSource(new Indi_Price(applied_price_price_params), PRICE_TYPICAL); - indis.Push(new Indi_AppliedPrice(applied_price_params)); + Indi_AppliedPrice *indi_applied_price_on_price = new Indi_AppliedPrice(applied_price_params); + indi_applied_price_on_price.SetDataSource(new Indi_Price(applied_price_price_params), true, PRICE_TYPICAL); + indis.Push(indi_applied_price_on_price); // ADXW. ADXWParams adxw_params(14); @@ -479,9 +489,7 @@ bool InitIndicators() { // Color Line. ColorLineParams color_line_params(); -#ifdef __MQL5__ indis.Push(new Indi_ColorLine(color_line_params)); -#endif // Detrended Price Oscillator. DetrendedPriceParams detrended_params(); @@ -491,8 +499,8 @@ bool InitIndicators() { MassIndexParams mass_index_params(); indis.Push(new Indi_MassIndex(mass_index_params)); - // Price Channel. #ifdef __MQL5__ + // Price Channel. PriceChannelParams price_channel_params(); indis.Push(new Indi_PriceChannel(price_channel_params)); #endif @@ -503,9 +511,7 @@ bool InitIndicators() { // Bill Williams' Zone Trade. BWZTParams bwzt_params(); -#ifdef __MQL5__ indis.Push(new Indi_BWZT(bwzt_params)); -#endif // Rate of Change. RateOfChangeParams rate_of_change_params(); @@ -521,9 +527,7 @@ bool InitIndicators() { // Ultimate Oscillator. UltimateOscillatorParams ultimate_oscillator_params(); -#ifdef __MQL5__ indis.Push(new Indi_UltimateOscillator(ultimate_oscillator_params)); -#endif // VIDYA. VIDYAParams vidya_params(); @@ -531,9 +535,7 @@ bool InitIndicators() { // Volumes. VolumesParams volumes_params(); -#ifdef __MQL5__ indis.Push(new Indi_Volumes(volumes_params)); -#endif // Volume Rate of Change. VROCParams vol_rate_of_change_params(); @@ -543,31 +545,31 @@ bool InitIndicators() { WilliamsADParams williams_ad_params(); indis.Push(new Indi_WilliamsAD(williams_ad_params)); -// ZigZag Color. #ifdef __MQL5__ + // ZigZag Color. ZigZagColorParams zigzag_color_params(); indis.Push(new Indi_ZigZagColor(zigzag_color_params)); #endif -// Custom Moving Average. -#ifdef __MQL5__ + // Custom Moving Average. CustomMovingAverageParams cma_params(); indis.Push(new Indi_CustomMovingAverage(cma_params)); -#endif // Math (specialized indicator). MathParams math_params(MATH_OP_SUB, BAND_UPPER, BAND_LOWER, 0, 0); - math_params.SetDataSource(indi_bands, false, 0); math_params.SetDraw(clrBlue); math_params.SetName("Bands(UP - LO)"); - indis.Push(new Indi_Math(math_params)); + Indi_Math *indi_math_1 = new Indi_Math(math_params); + indi_math_1.SetDataSource(indi_bands, false, 0); + indis.Push(indi_math_1); // Math (specialized indicator) via custom math method. MathParams math_custom_params(MathCustomOp, BAND_UPPER, BAND_LOWER, 0, 0); - math_custom_params.SetDataSource(indi_bands, false, 0); math_custom_params.SetDraw(clrBeige); math_custom_params.SetName("Bands(Custom math fn)"); - indis.Push(new Indi_Math(math_custom_params)); + Indi_Math *indi_math_2 = new Indi_Math(math_custom_params); + indi_math_2.SetDataSource(indi_bands, false, 0); + indis.Push(indi_math_2); // RS (Math-based) indicator. RSParams rs_params(); @@ -586,7 +588,7 @@ bool InitIndicators() { indis.Push(new Indi_Candle(candle_params)); // Mark all as untested. - for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { + for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { tested.Set(iter.Key(), false); } @@ -602,13 +604,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) { + for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { if (whitelisted_indis.Size() != 0 && !whitelisted_indis.Contains(iter.Value())) { continue; } - Indicator *_indi = iter.Value(); - string _indi_name = _indi.GetName(); + IndicatorBase *_indi = iter.Value(); + string _indi_name = _indi.GetFullName(); MqlParam _value = _indi.GetEntryValue(); if (GetLastError() == ERR_INDICATOR_DATA_NOT_FOUND || GetLastError() == ERR_USER_ERROR_FIRST + ERR_USER_INVALID_BUFF_NUM) { diff --git a/tests/OrderQueryTest.mq5 b/tests/OrderQueryTest.mq5 index 64e88781c..8a4ada61b 100644 --- a/tests/OrderQueryTest.mq5 +++ b/tests/OrderQueryTest.mq5 @@ -36,6 +36,7 @@ bool Test01() { for (int i = -10; i <= 10; i++) { OrderData _odata; _odata.Set(ORDER_PROP_PROFIT, (float)i); + _odata.Set(ORDER_TYPE, i % 2 == 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL); Ref _order = new Order(_odata); orders.Push(_order); } @@ -71,6 +72,24 @@ bool Test01() { assertTrueOrReturnFalse(_order_profit_gt_2.Ptr().Get(ORDER_PROP_PROFIT) > 2, "Order with profit greater than 2 not found!"); + // Calculate profit sums (all, buys and sells). + float _order_profit_all = _oquery.CalcSumByProp(ORDER_PROP_PROFIT); + assertTrueOrReturnFalse(_order_profit_all == 0, "All profit should be 0!"); + float _order_profit_buy = + _oquery.CalcSumByPropWithCond( + ORDER_PROP_PROFIT, ORDER_TYPE, ORDER_TYPE_BUY); + float _order_profit_sell = + _oquery.CalcSumByPropWithCond( + ORDER_PROP_PROFIT, ORDER_TYPE, ORDER_TYPE_SELL); + assertTrueOrReturnFalse(_order_profit_buy == _order_profit_sell, "Profit of buys should equal profit of sells!"); + + // Find order type with the highest profit. + ENUM_ORDER_TYPE _order_types[] = {ORDER_TYPE_BUY, ORDER_TYPE_SELL}; + ENUM_ORDER_TYPE _order_type_highest_profit = + _oquery.FindPropBySum( + _order_types, ORDER_PROP_PROFIT, ORDER_TYPE); + assertTrueOrReturnFalse(_order_type_highest_profit == 0.0f, "Highest profitable order type incorrect!"); + //_order_profit_best.ToString(); // @todo //_order_profit_worst.ToString(); // @todo return _result; diff --git a/tests/StrategyTest-RSI.mq5 b/tests/StrategyTest-RSI.mq5 index 98d95da3d..65e908b17 100644 --- a/tests/StrategyTest-RSI.mq5 +++ b/tests/StrategyTest-RSI.mq5 @@ -41,14 +41,17 @@ class Stg_RSI : public Strategy { RSIParams _indi_params(12, PRICE_OPEN, 0); StgParams _stg_params; TradeParams _tparams; - _stg_params.SetIndicator(new Indi_RSI(_indi_params)); Strategy *_strat = new Stg_RSI(_stg_params, _tparams, _cparams, "RSI"); + _strat.SetIndicator(new Indi_RSI(_indi_params)); return _strat; } bool SignalOpen(ENUM_ORDER_TYPE _cmd, int _method = 0, float _level = 0.0f, int _shift = 0) { Indi_RSI *_indi = GetIndicator(); - return (_cmd == ORDER_TYPE_BUY && _indi[_shift][0] <= 20) || (_cmd == ORDER_TYPE_SELL && _indi[_shift][0] >= 80); + bool _result = _indi.GetFlag(INDI_ENTRY_FLAG_IS_VALID, _shift); + _result &= + (_cmd == ORDER_TYPE_BUY && _indi[_shift][0] <= 20) || (_cmd == ORDER_TYPE_SELL && _indi[_shift][0] >= 80); + return _result; } bool SignalClose(ENUM_ORDER_TYPE _cmd, int _method, float _level, int _shift) { @@ -57,10 +60,17 @@ class Stg_RSI : public Strategy { float PriceStop(ENUM_ORDER_TYPE _cmd, ENUM_ORDER_TYPE_VALUE _mode, int _method = 0, float _level = 0.0) { Indi_RSI *_indi = GetIndicator(); + RSIParams _iparams = _indi.GetParams();; double _trail = _level * Market().GetPipSize(); int _direction = Order::OrderDirection(_cmd, _mode); - return _direction > 0 ? (float)_indi.GetPrice(PRICE_HIGH, _indi.GetHighest(_indi.GetPeriod() * 2)) - : (float)_indi.GetPrice(PRICE_LOW, _indi.GetLowest(_indi.GetPeriod() * 2)); + return _direction > 0 ? (float)_indi.GetPrice(PRICE_HIGH, _indi.GetHighest(_iparams.GetPeriod() * 2)) + : (float)_indi.GetPrice(PRICE_LOW, _indi.GetLowest(_iparams.GetPeriod() * 2)); + } + + virtual void OnPeriod(unsigned int _periods = DATETIME_NONE) { + if ((_periods & DATETIME_HOUR) != 0) { + // New hour started. + } } }; @@ -105,26 +115,43 @@ int OnInit() { * Implements OnTick(). */ void OnTick() { - if (stg_rsi.TickFilter(SymbolInfoStatic::GetTick(_Symbol), 1)) { - StrategySignal _signal = stg_rsi.ProcessSignals(); - if (_signal.CheckSignals(STRAT_SIGNAL_OPEN_BUY)) { - assertTrueOrExit(_signal.GetOpenDirection() == 1, "Wrong order open direction!"); + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + if (stg_rsi.SignalOpen(ORDER_TYPE_BUY)) { MqlTradeRequest _request = trade.GetTradeOpenRequest(ORDER_TYPE_BUY, 0, stg_rsi.Get(STRAT_PARAM_ID), stg_rsi.GetName()); trade.RequestSend(_request); - } else if (_signal.CheckSignals(STRAT_SIGNAL_OPEN_SELL)) { - assertTrueOrExit(_signal.GetOpenDirection() == -1, "Wrong order open direction!"); + } else if (stg_rsi.SignalOpen(ORDER_TYPE_SELL)) { MqlTradeRequest _request = trade.GetTradeOpenRequest(ORDER_TYPE_SELL, 0, stg_rsi.Get(STRAT_PARAM_ID), stg_rsi.GetName()); trade.RequestSend(_request); - } else if (trade.Get(TRADE_STATE_ORDERS_ACTIVE)) { + } + if (trade.Get(TRADE_STATE_ORDERS_ACTIVE)) { + if (stg_rsi.SignalClose(ORDER_TYPE_BUY)) { + // Close signal for buy order. + trade.OrdersCloseViaProp2( + ORDER_MAGIC, stg_rsi.Get(STRAT_PARAM_ID), ORDER_TYPE, ORDER_TYPE_BUY, MATH_COND_EQ, + ORDER_REASON_CLOSED_BY_SIGNAL, stg_rsi.GetOrderCloseComment()); + } + if (stg_rsi.SignalClose(ORDER_TYPE_SELL)) { + trade.OrdersCloseViaProp2( + ORDER_MAGIC, stg_rsi.Get(STRAT_PARAM_ID), ORDER_TYPE, ORDER_TYPE_SELL, MATH_COND_EQ, + ORDER_REASON_CLOSED_BY_SIGNAL, stg_rsi.GetOrderCloseComment()); + } + } + if (_tick_new.time % 3600 < _tick_last.time % 3600) { stg_rsi.ProcessTasks(); + trade.UpdateStates(); + // Print strategy values every hour. + Print(stg_rsi.ToString()); } long _last_error = GetLastError(); if (_last_error > 0) { assertTrueOrExit(_last_error == ERR_NO_ERROR, StringFormat("Error occured! Code: %d", _last_error)); } } + _tick_last = _tick_new; } /** diff --git a/tests/StrategyTest.mq5 b/tests/StrategyTest.mq5 index 5282c63a3..d0c6efa10 100644 --- a/tests/StrategyTest.mq5 +++ b/tests/StrategyTest.mq5 @@ -112,8 +112,8 @@ int OnInit() { StgParams stg2_params; stg2_params.Enabled(false); stg2_params.Suspended(true); - stg2_params.SetIndicator(new Indi_Demo(iparams)); strat2 = new Stg2(stg2_params); + strat2.SetIndicator(new Indi_Demo(iparams)); strat2.SetName("Stg2"); assertTrueOrFail(strat2.GetName() == "Stg2", "Invalid Strategy name!"); assertTrueOrFail(strat2.IsValid(), "Fail on IsValid()!");