diff --git a/.github/workflows/compile-cpp.yml b/.github/workflows/compile-cpp.yml new file mode 100644 index 000000000..085b4f3e0 --- /dev/null +++ b/.github/workflows/compile-cpp.yml @@ -0,0 +1,44 @@ +--- +name: Compile C++ + +# yamllint disable-line rule:truthy +on: + pull_request: + paths-ignore: + - '**.md' + push: + paths-ignore: + - '**.md' + +jobs: + + FileList: + outputs: + filelist: ${{ steps.get-files.outputs.filelist }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set output with list of files + id: get-files + run: | + import glob, json, os + files = glob.glob("**/tests/*.cpp") + print("::set-output name=filelist::{}".format(json.dumps(files))) + shell: python + - name: Display output + run: echo ${{ steps.get-files.outputs.filelist }} + + Compile: + runs-on: ubuntu-latest + needs: [FileList] + strategy: + matrix: + file: ${{ fromJson(needs.FileList.outputs.filelist) }} + steps: + - uses: actions/checkout@v2 + - name: Install compiler + uses: rlalik/setup-cpp-compiler@v1.1 + with: + compiler: gcc-latest + - name: Compile ${{ matrix.file }} + run: g++ "${{ matrix.file }}" diff --git a/.github/workflows/test-buffer.yml b/.github/workflows/test-buffer.yml new file mode 100644 index 000000000..bf23d92e7 --- /dev/null +++ b/.github/workflows/test-buffer.yml @@ -0,0 +1,61 @@ +--- +name: Test Buffer + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Buffer/**' + - '.github/workflows/test-buffer.yml' + push: + paths: + - 'Buffer/**' + - '.github/workflows/test-buffer.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: 'Buffer/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' + + Buffer-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Buffer/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - BufferCandle.test + - BufferTick.test + steps: + - uses: actions/download-artifact@v2 + with: + name: files-ex4 + - name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + Script: ${{ matrix.test }} + timeout-minutes: 10 diff --git a/.github/workflows/test-exchange.yml b/.github/workflows/test-exchange.yml new file mode 100644 index 000000000..b4c0ed3c9 --- /dev/null +++ b/.github/workflows/test-exchange.yml @@ -0,0 +1,62 @@ +--- +name: Test Exchange + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Exchange/**.h' + - 'Exchange/**.mq?' + - '.github/workflows/test-exchange.yml' + push: + paths: + - 'Exchange/**.h' + - 'Exchange/**.mq?' + - '.github/workflows/test-exchange.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: 'Exchange/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' + + Exchange-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Exchange/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - Exchange.test + steps: + - uses: actions/download-artifact@v2 + with: + name: files-ex4 + - name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + Script: ${{ matrix.test }} + timeout-minutes: 10 diff --git a/.github/workflows/test-indicator.yml b/.github/workflows/test-indicator.yml new file mode 100644 index 000000000..87b68aa41 --- /dev/null +++ b/.github/workflows/test-indicator.yml @@ -0,0 +1,67 @@ +--- +name: Test Indicator + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Indicator**' + - 'Indicator/**' + - '.github/workflows/test-indicator.yml' + push: + paths: + - 'Indicator**' + - 'Indicator/**' + - '.github/workflows/test-indicator.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: 'Indicator/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' + + Indicator-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Indicator/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - IndicatorCandle.test + - IndicatorTf.test + - IndicatorTick.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 }} + timeout-minutes: 10 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ca02328a3..5f4fe16e8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -61,7 +61,7 @@ jobs: - CompileIndicatorsTest - ConditionTest - DatabaseTest - - DrawIndicatorTest + # - DrawIndicatorTest - EATest - IndicatorDataTest - IndicatorTest diff --git a/Account.mqh b/Account.mqh index ec5bac686..bef93c4fe 100644 --- a/Account.mqh +++ b/Account.mqh @@ -30,6 +30,7 @@ class Account; // Includes. #include "Account/Account.define.h" #include "Account/Account.enum.h" +#include "Account/Account.extern.h" #include "Account/Account.struct.h" #include "Array.mqh" #include "BufferStruct.mqh" @@ -63,6 +64,11 @@ class Account { */ Account() : init_balance(CalcInitDeposit()), start_balance(GetBalance()), start_credit(GetCredit()) {} + /** + * Class copy constructor. + */ + Account(const Account &_account) {} + /** * Class deconstructor. */ diff --git a/Account/Account.extern.h b/Account/Account.extern.h new file mode 100644 index 000000000..28aa8909d --- /dev/null +++ b/Account/Account.extern.h @@ -0,0 +1,29 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Includes. +#include "Account.enum.h" + +// Define external global functions. +#ifndef __MQL__ +extern string AccountInfoString(ENUM_ACCOUNT_INFO_STRING property_id); +#endif diff --git a/Account/Account.struct.h b/Account/Account.struct.h index 63c4ca53a..7f70c1498 100644 --- a/Account/Account.struct.h +++ b/Account/Account.struct.h @@ -36,6 +36,7 @@ class Serializer; // Includes. #include "../Serializer.mqh" +#include "../Terminal.define.h" // Struct for account entries. struct AccountEntry { diff --git a/Account/AccountBase.struct.h b/Account/AccountBase.struct.h index 535d3cae7..f58e25e7f 100644 --- a/Account/AccountBase.struct.h +++ b/Account/AccountBase.struct.h @@ -36,6 +36,7 @@ class Serializer; // Includes. #include "../Serializer.mqh" +#include "../Terminal.define.h" // Struct for account entries. struct AccountBaseEntry { diff --git a/Account/AccountForex.struct.h b/Account/AccountForex.struct.h index 9bf5c8901..64aacffa3 100644 --- a/Account/AccountForex.struct.h +++ b/Account/AccountForex.struct.h @@ -36,6 +36,7 @@ class Serializer; // Includes. #include "../Serializer.mqh" +#include "../Terminal.define.h" // Struct for account entries. struct AccountForexEntry : public AccountBaseEntry { diff --git a/Account/tests/Account.test.mq5 b/Account/tests/Account.test.mq5 index 6ed1a1263..a52e8c076 100644 --- a/Account/tests/Account.test.mq5 +++ b/Account/tests/Account.test.mq5 @@ -35,7 +35,7 @@ int OnInit() { bool _result = true; Account acc1; // ... - return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; + return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; } /** diff --git a/Account/tests/AccountForex.test.mq5 b/Account/tests/AccountForex.test.mq5 index 826aa4235..fb10957ea 100644 --- a/Account/tests/AccountForex.test.mq5 +++ b/Account/tests/AccountForex.test.mq5 @@ -35,7 +35,7 @@ int OnInit() { bool _result = true; Account acc1; // ... - return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; + return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; } /** diff --git a/Action.mqh b/Action.mqh index c14fc5fea..65dc92f3b 100644 --- a/Action.mqh +++ b/Action.mqh @@ -139,14 +139,16 @@ class Action { break; #endif #ifdef INDICATOR_MQH - case ACTION_TYPE_INDICATOR: - if (Object::IsValid(_entry.obj)) { - _result = ((IndicatorBase *)_entry.obj).ExecuteAction((ENUM_INDICATOR_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; + /* + case ACTION_TYPE_INDICATOR: + if (Object::IsValid(_entry.obj)) { + _result = ((IndicatorBase *)_entry.obj).ExecuteAction((ENUM_INDICATOR_ACTION)_entry.action_id); + } else { + _result = false; + _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); + } + break; + */ #endif #ifdef STRATEGY_MQH case ACTION_TYPE_STRATEGY: diff --git a/Array.extern.h b/Array.extern.h new file mode 100644 index 000000000..b09748d67 --- /dev/null +++ b/Array.extern.h @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Define external global functions. +#ifndef __MQL__ +#pragma once + +template +extern int ArraySize(const ARRAY_REF(T, _array)); + +template +extern constexpr int ArraySize(const T REF(_array)[size]); + +template +extern int ArrayResize(ARRAY_REF(T, _array), int _new_size, int _reserve_size = 0); + +template +extern bool ArraySetAsSeries(ARRAY_REF(T, _array), bool _flag); + +template +extern int ArrayMaximum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY); + +template +extern int ArrayMinimum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY); + +template +extern int ArrayFree(const ARRAY_REF(T, _array)); + +template +extern int ArrayReverse(const ARRAY_REF(T, _array)); + +template +extern int ArrayInitialize(ARRAY_REF(T, array), char value); + +template +extern int ArraySort(ARRAY_REF(T, array)); + +#endif diff --git a/Array.mqh b/Array.mqh index 0a8a08635..d71b044d0 100644 --- a/Array.mqh +++ b/Array.mqh @@ -26,7 +26,12 @@ #endif // Includes. +#include "Array.extern.h" +#include "Common.extern.h" +#include "Convert.extern.h" +#include "Math.extern.h" #include "Std.h" +#include "String.extern.h" // Defines. #ifndef MODE_ASCEND @@ -529,7 +534,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { */ template void ArrayPrint(ARRAY_REF(T, _arr), // Printed array. - int _digits = NULL, // Number of decimal places. + int _digits = 0, // Number of decimal places. const string _dlm = NULL, // Separator of the structure field values. long _start = 0, // First printed element index. long _count = WHOLE_ARRAY, // Number of printed elements. @@ -539,7 +544,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { #else int i; string output = ""; - for (i = _start; i < _count == WHOLE_ARRAY ? ArraySize(_arr) : _count; i++) { + for (i = _start; i < (_count == WHOLE_ARRAY ? ArraySize(_arr) : _count); i++) { output += (string)_arr[i] + _dlm; } Print(output); @@ -635,7 +640,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { * if error occured). */ template - static int ArrayResizeFill(ARRAY_REF(X, array), int new_size, int reserve_size = 0, Y fill_value = EMPTY_VALUE) { + static int ArrayResizeFill(ARRAY_REF(X, array), int new_size, int reserve_size = 0, Y fill_value = NULL) { const int old_size = ArrayRange(array, 0); if (new_size <= old_size) return old_size; diff --git a/Buffer/BufferCandle.h b/Buffer/BufferCandle.h new file mode 100644 index 000000000..8401ee3f8 --- /dev/null +++ b/Buffer/BufferCandle.h @@ -0,0 +1,79 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Prevents processing this includes file for the second time. +#ifndef BUFFER_CANDLE_H +#define BUFFER_CANDLE_H + +// Includes. +#include "../BufferStruct.mqh" +#include "../Candle.struct.h" + +/** + * Class to store struct data. + */ +template +class BufferCandle : public BufferStruct> { + protected: + protected: + /* Protected methods */ + + /** + * Initialize class. + * + * Called on constructor. + */ + void Init() { SetOverflowListener(BufferCandleOverflowListener, 10); } + + public: + /* Constructors */ + + /** + * Constructor. + */ + BufferCandle() { Init(); } + BufferCandle(BufferCandle& _right) { + THIS_REF = _right; + Init(); + } + + /* Callback methods */ + + /** + * Function should return true if resize can be made, or false to overwrite current slot. + */ + static bool BufferCandleOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { + static int cache_limit = 86400; + switch (_reason) { + case DICT_OVERFLOW_REASON_FULL: + // We allow resize if dictionary size is less than 86400 slots. + return _size < cache_limit; + case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: + default: + // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. + break; + } + return false; + } +}; + +#endif // BUFFER_CANDLE_H diff --git a/Buffer/BufferTick.h b/Buffer/BufferTick.h new file mode 100644 index 000000000..d3eb35dab --- /dev/null +++ b/Buffer/BufferTick.h @@ -0,0 +1,169 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Prevents processing this includes file for the second time. +#ifndef BUFFER_TICK_H +#define BUFFER_TICK_H + +// Includes. +#include "../BufferStruct.mqh" +#include "../Chart.enum.h" +#include "../Storage/IValueStorage.h" +#include "../Tick.struct.h" + +template +class BufferTickValueStorage : ValueStorage { + // Poiner to buffer to take tick from. + BufferTick *buffer_tick; + + // PRICE_ASK or PRICE_BID. + int applied_price; + + public: + /** + * Constructor. + */ + BufferTickValueStorage(BufferTick *_buffer_tick, int _applied_price) + : buffer_tick(_buffer_tick), applied_price(_applied_price) {} + + /** + * Fetches value from a given shift. Takes into consideration as-series flag. + */ + TV Fetch(int _shift) override { + Print("BufferTickValueStorage: Fetching " + (applied_price == PRICE_ASK ? "Ask" : "Bid") + " price from shift ", + _shift); + return 0; + } + + /** + * Returns number of values available to fetch (size of the values buffer). + */ + int Size() const override { return (int)buffer_tick.Size(); } +}; + +/** + * Class to store struct data. + */ +template +class BufferTick : public BufferStruct> { + protected: + // Ask prices ValueStorage proxy. + BufferTickValueStorage *_vs_ask; + + // Bid prices ValueStorage proxy. + BufferTickValueStorage *_vs_bid; + + protected: + /* Protected methods */ + + /** + * Initialize class. + * + * Called on constructor. + */ + void Init() { + _vs_ask = NULL; + _vs_bid = NULL; + SetOverflowListener(BufferTickOverflowListener, 10); + } + + public: + /* Constructors */ + + /** + * Constructor. + */ + BufferTick() { Init(); } + BufferTick(BufferTick &_right) { + THIS_REF = _right; + Init(); + } + + /** + * Destructor. + */ + ~BufferTick() { + if (_vs_ask != NULL) { + delete _vs_ask; + } + if (_vs_bid != NULL) { + delete _vs_bid; + } + } + + /** + * Returns Ask prices ValueStorage proxy. + */ + BufferTickValueStorage *GetAskValueStorage() { + if (_vs_ask == NULL) { + _vs_ask = new BufferTickValueStorage(THIS_PTR, PRICE_ASK); + } + return _vs_ask; + } + + /** + * Returns Bid prices ValueStorage proxy. + */ + BufferTickValueStorage *GetBidValueStorage() { + if (_vs_bid == NULL) { + _vs_bid = new BufferTickValueStorage(THIS_PTR, PRICE_BID); + } + return _vs_bid; + } + + /* Grouping methods */ + + /** + * Group ticks by seconds. + */ + DictStruct>> GroupBySecs(uint _spc) { + // DictStruct>> _result; + // @todo: for each iter + // for (DictStructIterator>> iter(Begin()); iter.IsValid(); ++iter) { + // Load timestamp from key, TickAB from value + // foreach some timestamp mod % _spc - calculate shift + // _result.Push(_shift, TickAB) + // Convert to OHLC in upper method + return NULL; + } + + /* Callback methods */ + + /** + * Function should return true if resize can be made, or false to overwrite current slot. + */ + static bool BufferTickOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { + static int cache_limit = 86400; + switch (_reason) { + case DICT_OVERFLOW_REASON_FULL: + // We allow resize if dictionary size is less than 86400 slots. + return _size < cache_limit; + case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: + default: + // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. + break; + } + return false; + } +}; + +#endif // BUFFER_TICK_H diff --git a/Buffer/tests/BufferCandle.test.mq4 b/Buffer/tests/BufferCandle.test.mq4 new file mode 100644 index 000000000..fe6c0a00d --- /dev/null +++ b/Buffer/tests/BufferCandle.test.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 BufferCandle class. + */ + +// Includes. +#include "BufferCandle.test.mq5" diff --git a/Buffer/tests/BufferCandle.test.mq5 b/Buffer/tests/BufferCandle.test.mq5 new file mode 100644 index 000000000..ab76d8da8 --- /dev/null +++ b/Buffer/tests/BufferCandle.test.mq5 @@ -0,0 +1,59 @@ +//+------------------------------------------------------------------+ +//| 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 BufferCandle class. + */ + +// Includes +#include "../../Test.mqh" +#include "../BufferCandle.h" + +/** + * Implements OnInit(). + */ +int OnInit() { + BufferCandle buffer1; // 128 + CandleOHLC _ohlc_d; // 32 + CandleOHLC _ohlc_f; // 16 + CandleTOHLC _tohlc_d; // 32 + CandleTOHLC _tohlc_f; // 16 + // CandleEntry _centry_d; // 40 + // CandleEntry _centry_f; // 24 + Print("buffer1: ", sizeof(buffer1)); + Print("_ohlc_d: ", sizeof(_ohlc_d)); + Print("_ohlc_f: ", sizeof(_ohlc_f)); + Print("_tohlc_d: ", sizeof(_tohlc_d)); + Print("_tohlc_f: ", sizeof(_tohlc_f)); + // @todo + return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED); +} + +/** + * Implements OnTick(). + */ +void OnTick() {} + +/** + * Implements OnDeinit(). + */ +void OnDeinit(const int reason) {} diff --git a/Buffer/tests/BufferTick.test.mq4 b/Buffer/tests/BufferTick.test.mq4 new file mode 100644 index 000000000..5a45ef4fa --- /dev/null +++ b/Buffer/tests/BufferTick.test.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 BufferTick class. + */ + +// Includes. +#include "BufferTick.test.mq5" diff --git a/Buffer/tests/BufferTick.test.mq5 b/Buffer/tests/BufferTick.test.mq5 new file mode 100644 index 000000000..1daf2ea7b --- /dev/null +++ b/Buffer/tests/BufferTick.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 . + */ + +/** + * @file + * Test functionality of BufferTick class. + */ + +// Includes +#include "../../Test.mqh" +#include "../BufferTick.h" + +/** + * Implements OnInit(). + */ +int OnInit() { + MqlTick mql_tick; // 60 + TickAB _tick_ab_d; // 16 + TickAB _tick_ab_f; // 8 + TickTAB _tick_tab_d; // 24 + TickTAB _tick_tab_f; // 16 + Print("mql_tick: ", sizeof(mql_tick)); + Print("_tick_ab_d: ", sizeof(_tick_ab_d)); + Print("_tick_ab_f: ", sizeof(_tick_ab_f)); + Print("_tick_tab_d: ", sizeof(_tick_tab_d)); + Print("_tick_tab_f: ", sizeof(_tick_tab_f)); + // @todo + return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED); +} + +/** + * Implements OnTick(). + */ +void OnTick() {} + +/** + * Implements OnDeinit(). + */ +void OnDeinit(const int reason) {} diff --git a/Candle.struct.h b/Candle.struct.h new file mode 100644 index 000000000..4d4e03dfb --- /dev/null +++ b/Candle.struct.h @@ -0,0 +1,288 @@ +//+------------------------------------------------------------------+ +//| 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 Bar's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Forward class declaration. +class Serializer; + +// Includes. +#include "Bar.enum.h" +#include "Chart.enum.h" +#include "ISerializable.h" +#include "Serializer.enum.h" +#include "SerializerNode.enum.h" +#include "Std.h" + +/* Structure for storing OHLC values. */ +template +struct CandleOHLC +#ifndef __MQL__ + : public ISerializable +#endif +{ + T open, high, low, close; + + // Struct constructors. + CandleOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0) : open(_open), high(_high), low(_low), close(_close) {} + CandleOHLC(ARRAY_REF(T, _prices)) { + int _size = ArraySize(_prices); + close = _prices[0]; + open = _prices[_size - 1]; + high = fmax(close, open); + low = fmin(close, open); + for (int i = 0; i < _size; i++) { + high = fmax(high, _prices[i]); + low = fmin(low, _prices[i]); + } + } + // Struct methods. + // Getters + bool GetPivots(ENUM_PP_TYPE _type, T &_pp, T &_r1, T &_r2, T &_r3, T &_r4, T &_s1, T &_s2, T &_s3, T &_s4) { + T _range = GetRange(); + switch (_type) { + case PP_CAMARILLA: + // A set of eight very probable levels which resemble support and resistance values for a current trend. + _pp = GetPivot(); + _r1 = (T)(close + _range * 1.1 / 12); + _r2 = (T)(close + _range * 1.1 / 6); + _r3 = (T)(close + _range * 1.1 / 4); + _r4 = (T)(close + _range * 1.1 / 2); + _s1 = (T)(close - _range * 1.1 / 12); + _s2 = (T)(close - _range * 1.1 / 6); + _s3 = (T)(close - _range * 1.1 / 4); + _s4 = (T)(close - _range * 1.1 / 2); + break; + case PP_CLASSIC: + _pp = GetPivot(); + _r1 = (2 * _pp) - low; // R1 = (H - L) * 1.1 / 12 + C (1.0833) + _r2 = _pp + _range; // R2 = (H - L) * 1.1 / 6 + C (1.1666) + _r3 = _pp + _range * 2; // R3 = (H - L) * 1.1 / 4 + C (1.25) + _r4 = _pp + _range * 3; // R4 = (H - L) * 1.1 / 2 + C (1.5) + _s1 = (2 * _pp) - high; // S1 = C - (H - L) * 1.1 / 12 (1.0833) + _s2 = _pp - _range; // S2 = C - (H - L) * 1.1 / 6 (1.1666) + _s3 = _pp - _range * 2; // S3 = C - (H - L) * 1.1 / 4 (1.25) + _s4 = _pp - _range * 3; // S4 = C - (H - L) * 1.1 / 2 (1.5) + break; + case PP_FIBONACCI: + _pp = GetPivot(); + _r1 = (float)(_pp + 0.382 * _range); + _r2 = (float)(_pp + 0.618 * _range); + _r3 = _pp + _range; + _r4 = _r1 + _range; // ? + _s1 = (float)(_pp - 0.382 * _range); + _s2 = (float)(_pp - 0.618 * _range); + _s3 = _pp - _range; + _s4 = _s1 - _range; // ? + break; + case PP_FLOOR: + // Most basic and popular type of pivots used in Forex trading technical analysis. + _pp = GetPivot(); // Pivot (P) = (H + L + C) / 3 + _r1 = (2 * _pp) - low; // Resistance (R1) = (2 * P) - L + _r2 = _pp + _range; // R2 = P + H - L + _r3 = high + 2 * (_pp - low); // R3 = H + 2 * (P - L) + _r4 = _r3; + _s1 = (2 * _pp) - high; // Support (S1) = (2 * P) - H + _s2 = _pp - _range; // S2 = P - H + L + _s3 = low - 2 * (high - _pp); // S3 = L - 2 * (H - P) + _s4 = _s3; // ? + break; + case PP_TOM_DEMARK: + // Tom DeMark's pivot point (predicted lows and highs of the period). + _pp = GetPivotDeMark(); + _r1 = (2 * _pp) - low; // New High = X / 2 - L. + _r2 = _pp + _range; + _r3 = _r1 + _range; + _r4 = _r2 + _range; // ? + _s1 = (2 * _pp) - high; // New Low = X / 2 - H. + _s2 = _pp - _range; + _s3 = _s1 - _range; + _s4 = _s2 - _range; // ? + break; + case PP_WOODIE: + // Woodie's pivot point are giving more weight to the Close price of the previous period. + // They are similar to floor pivot points, but are calculated in a somewhat different way. + _pp = GetWeighted(); // Pivot (P) = (H + L + 2 * C) / 4 + _r1 = (2 * _pp) - low; // Resistance (R1) = (2 * P) - L + _r2 = _pp + _range; // R2 = P + H - L + _r3 = _r1 + _range; + _r4 = _r2 + _range; // ? + _s1 = (2 * _pp) - high; // Support (S1) = (2 * P) - H + _s2 = _pp - _range; // S2 = P - H + L + _s3 = _s1 - _range; + _s4 = _s2 - _range; // ? + break; + default: + break; + } + return _r4 > _r3 && _r3 > _r2 && _r2 > _r1 && _r1 > _pp && _pp > _s1 && _s1 > _s2 && _s2 > _s3 && _s3 > _s4; + } + T GetAppliedPrice(ENUM_APPLIED_PRICE _ap) const { return CandleOHLC::GetAppliedPrice(_ap, open, high, low, close); } + T GetBody() const { return close - open; } + T GetBodyAbs() const { return fabs(close - open); } + T GetBodyInPct(int _hundreds = 100) const { return GetRange() > 0 ? _hundreds / GetRange() * GetBodyAbs() : 0; } + T GetChangeInPct(int _hundreds = 100) const { return (close - open) / open * _hundreds; } + T GetClose() const { return close; } + T GetHigh() const { return high; } + T GetLow() const { return low; } + T GetMaxOC() const { return fmax(open, close); } + T GetMedian() const { return (high + low) / 2; } + T GetMinOC() const { return fmin(open, close); } + T GetOpen() const { return open; } + T GetPivot() const { return GetTypical(); } + T GetPivotDeMark() const { + // If Close < Open Then X = H + 2 * L + C + // If Close > Open Then X = 2 * H + L + C + // If Close = Open Then X = H + L + 2 * C + T _pp = open > close ? (high + (2 * low) + close) / 4 : ((2 * high) + low + close) / 4; + return open == close ? (high + low + (2 * close)) / 4 : _pp; + } + T GetPivotWithOpen() const { return (open + high + low + close) / 4; } + T GetPivotWithOpen(float _open) const { return (_open + high + low + close) / 4; } + T GetRange() const { return high - low; } + T GetRangeChangeInPct(int _hundreds = 100) const { return _hundreds - (_hundreds / open * fabs(open - GetRange())); } + T GetRangeInPips(float _ppp) const { return GetRange() / _ppp; } + T GetTypical() const { return (high + low + close) / 3; } + T GetWeighted() const { return (high + low + close + close) / 4; } + T GetWickMin() const { return fmin(GetWickLower(), GetWickUpper()); } + T GetWickLower() const { return GetMinOC() - low; } + T GetWickLowerInPct() const { return GetRange() > 0 ? 100 / GetRange() * GetWickLower() : 0; } + T GetWickMax() const { return fmax(GetWickLower(), GetWickUpper()); } + T GetWickSum() const { return GetWickLower() + GetWickUpper(); } + T GetWickUpper() const { return high - GetMaxOC(); } + T GetWickUpperInPct() const { return GetRange() > 0 ? 100 / GetRange() * GetWickUpper() : 0; } + short GetType() const { return IsBull() ? 1 : (IsBear() ? -1 : 0); } + void GetValues(ARRAY_REF(T, _out)) { + ArrayResize(_out, 4); + int _index = ArraySize(_out) - 4; + _out[_index++] = open; + _out[_index++] = high; + _out[_index++] = low; + _out[_index++] = close; + } + static T GetAppliedPrice(ENUM_APPLIED_PRICE _ap, T _o, T _h, T _l, T _c) { + switch (_ap) { + case PRICE_CLOSE: + return _c; + case PRICE_OPEN: + return _o; + case PRICE_HIGH: + return _h; + case PRICE_LOW: + return _l; + case PRICE_MEDIAN: + return (_h + _l) / 2; + case PRICE_TYPICAL: + return (_h + _l + _c) / 3; + case PRICE_WEIGHTED: + return (_h + _l + _c + _c) / 4; + default: + return _o; + } + } + // State checkers. + bool IsBear() const { return open > close; } + bool IsBull() const { return open < close; } + bool IsValid() const { return high >= low && fmin(open, close) > 0; } + // Serializers. + SerializerNodeType Serialize(Serializer &s); + // Converters. + string ToCSV() { return StringFormat("%g,%g,%g,%g", open, high, low, close); } +}; + +/* Structure for storing OHLC values with open and close timestamp. */ +template +struct CandleOCTOHLC : CandleOHLC { + long open_timestamp, close_timestamp; + + // Struct constructors. + CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, long _open_timestamp = -1, + long _close_timestamp = -1) + : CandleOHLC(_open, _high, _low, _close), open_timestamp(_open_timestamp), close_timestamp(_close_timestamp) {} + + // Updates OHLC values taking into consideration tick's timestamp. + void Update(long _timestamp, T _price) { + if (_timestamp < open_timestamp) { + open_timestamp = _timestamp; + open = _price; + } + if (_timestamp > close_timestamp) { + close_timestamp = _timestamp; + close = _price; + } + high = MathMax(high, _price); + low = MathMin(low, _price); + } + + // Returns timestamp of open price. + long GetOpenTimestamp() { return open_timestamp; } + + // Returns timestamp of close price. + long GetCloseTimestamp() { return close_timestamp; } +}; + +/* Structore for storing OHLC values with timestamp. */ +template +struct CandleTOHLC : CandleOHLC { + datetime time; + // Struct constructors. + CandleTOHLC(datetime _time = 0, T _open = 0, T _high = 0, T _low = 0, T _close = 0) + : time(_time), CandleOHLC(_open, _high, _low, _close) {} + // Getters. + datetime GetTime() { return time; } + // Serializers. + SerializerNodeType Serialize(Serializer &s); + // Converters. + string ToCSV() { return StringFormat("%d,%g,%g,%g,%g", time, open, high, low, close); } +}; + +#include "Serializer.mqh" + +/* Method to serialize CandleEntry structure. */ +template +SerializerNodeType CandleOHLC::Serialize(Serializer &s) { + // s.Pass(THIS_REF, "time", TimeToString(time)); + s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); + return SerializerNodeObject; +} + +/* Method to serialize CandleEntry structure. */ +template +SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { + s.Pass(THIS_REF, "time", time); + s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); + return SerializerNodeObject; +} diff --git a/Chart.enum.h b/Chart.enum.h index e7e68247c..5835ba3da 100644 --- a/Chart.enum.h +++ b/Chart.enum.h @@ -43,9 +43,14 @@ enum ENUM_APPLIED_PRICE { PRICE_MEDIAN, // Median price (H+L)/2 PRICE_TYPICAL, // Typical price, (H+L+C)/3 PRICE_WEIGHTED, // Weighted close price (H+L+C+C)/4 + FINAL_APPLIED_PRICE_ENTRY }; #endif +// Additional modes for applied price. +#define PRICE_ASK ((ENUM_APPLIED_PRICE)128) +#define PRICE_BID ((ENUM_APPLIED_PRICE)129) + // Defines enumeration for chart parameters. enum ENUM_CHART_PARAM { CHART_PARAM_NONE = 0, // None diff --git a/Chart.mqh b/Chart.mqh index ba63a7750..356b734db 100644 --- a/Chart.mqh +++ b/Chart.mqh @@ -224,7 +224,7 @@ class Chart : public Market { * @return * Returns ChartEntry struct. */ - ChartEntry GetEntry(unsigned int _shift = 0) { + ChartEntry GetEntry(int _shift = 0) { ChartEntry _chart_entry; BarOHLC _ohlc = GetOHLC(_shift); if (_ohlc.open > 0) { diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 49c7c88f3..625fa74ae 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -32,6 +32,8 @@ // Includes. #include "Chart.enum.h" +#include "Serializer.mqh" +#include "Terminal.define.h" /* Defines struct for chart timeframe. */ struct ChartTf { @@ -346,8 +348,6 @@ struct ChartTf { SerializerNodeType Serialize(Serializer& s); }; -#include "Serializer.mqh" - /* Method to serialize ChartTf structure. */ SerializerNodeType ChartTf::Serialize(Serializer& s) { s.PassEnum(THIS_REF, "tf", tf); diff --git a/Common.define.h b/Common.define.h new file mode 100644 index 000000000..09f7d754a --- /dev/null +++ b/Common.define.h @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Defines common defines. + */ +#ifndef __MQL__ +// Data types. +#include +typedef std::string string; +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned short ushort; +#endif diff --git a/Common.extern.h b/Common.extern.h new file mode 100644 index 000000000..2092a4c16 --- /dev/null +++ b/Common.extern.h @@ -0,0 +1,47 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Define external global functions. +#ifndef __MQL__ +#pragma once +#include "Chart.enum.h" +#include "DateTime.enum.h" + +extern void DebugBreak(); +// Errors. +extern void SetUserError(ushort user_error); +// Exceptions. +extern int NotImplementedException(); +// Print-related functions. +template +extern std::string StringFormat(const std::string& format, Args... args); + +template +extern std::string PrintFormat(const std::string& format, Args... args); + +template +extern void Print(Args... args); + +template +extern void Alert(Args... args); + +#endif diff --git a/Condition.mqh b/Condition.mqh index 915cbcd4e..9118becab 100644 --- a/Condition.mqh +++ b/Condition.mqh @@ -109,13 +109,13 @@ class Condition { if (_entry.IsActive()) { switch (_entry.next_statement) { case COND_AND: - _curr_result = _prev_result && this.Test(_entry); + _curr_result = _prev_result && this PTR_DEREF Test(_entry); break; case COND_OR: - _curr_result = _prev_result || this.Test(_entry); + _curr_result = _prev_result || this PTR_DEREF Test(_entry); break; case COND_SEQ: - _curr_result = this.Test(_entry); + _curr_result = this PTR_DEREF Test(_entry); if (!_curr_result) { // Do not check further conditions when the current condition is false. return false; @@ -165,15 +165,17 @@ class Condition { } break; #ifdef INDICATOR_MQH - case COND_TYPE_INDICATOR: - if (Object::IsValid(_entry.obj)) { - _result = ((IndicatorBase *)_entry.obj).CheckCondition((ENUM_INDICATOR_CONDITION)_entry.cond_id, _entry.args); - } else { - // Static method not supported. - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; + /* + case COND_TYPE_INDICATOR: + if (Object::IsValid(_entry.obj)) { + _result = ((IndicatorBase *)_entry.obj).CheckCondition((ENUM_INDICATOR_CONDITION)_entry.cond_id, + _entry.args); } else { + // Static method not supported. + _result = false; + _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); + } + break; + */ #endif case COND_TYPE_MARKET: if (Object::IsValid(_entry.obj)) { diff --git a/Convert.extern.h b/Convert.extern.h new file mode 100644 index 000000000..353a96b6b --- /dev/null +++ b/Convert.extern.h @@ -0,0 +1,34 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Prevents processing this includes file for the second time. +#ifndef __MQL__ +#pragma once +#endif + +// Define external global functions. +#ifndef __MQL__ +extern double NormalizeDouble(double value, int digits); +extern string CharToString(uchar char_code); +extern string DoubleToString(double value, int digits = 8); +extern string ShortToString(ushort symbol_code); +#endif diff --git a/Convert.mqh b/Convert.mqh index 7d5f320c1..010a358e4 100644 --- a/Convert.mqh +++ b/Convert.mqh @@ -24,11 +24,20 @@ #ifndef CONVERT_MQH #define CONVERT_MQH +// Prevents processing this includes file for the second time. +#ifndef __MQL__ +#pragma once +#endif + // Includes. #include "Account/Account.enum.h" +#include "Account/Account.extern.h" #include "Array.mqh" +#include "Convert.extern.h" +#include "Math.extern.h" #include "Order.enum.h" #include "SymbolInfo.enum.h" +#include "SymbolInfo.extern.h" #include "SymbolInfo.struct.static.h" /** @@ -58,7 +67,7 @@ class Convert { case ORDER_TYPE_BUY_STOP: return ORDER_TYPE_BUY; default: - return (ENUM_ORDER_TYPE)WRONG_VALUE; + return InvalidEnumValue::value(); } } @@ -73,7 +82,7 @@ class Convert { * Returns OP_BUY when value is positive, OP_SELL when negative, otherwise -1. */ static ENUM_ORDER_TYPE ValueToOp(int value) { - return value == 0 ? (ENUM_ORDER_TYPE)-1 : (value > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL); + return value == 0 ? InvalidEnumValue::value() : (value > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL); } /** @@ -87,13 +96,13 @@ class Convert { * Returns OP_BUY when value is positive, OP_SELL when negative, otherwise -1. */ static ENUM_ORDER_TYPE ValueToOp(double value) { - return value == 0 ? (ENUM_ORDER_TYPE)-1 : (value > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL); + return value == 0 ? InvalidEnumValue::value() : (value > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL); } /** * Points per pip given digits after decimal point of a symbol price. */ - static uint PointsPerPip(uint digits) { return (uint)pow(10, digits - (digits < 4 ? 2 : 4)); } + static uint PointsPerPip(uint digits) { return (uint)pow((unsigned int)10, digits - (digits < 4 ? 2 : 4)); } /** * Returns number of points per pip. @@ -172,19 +181,19 @@ class Convert { switch (mode) { case 0: // Forex. // In currencies a tick is a point. - return pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE); + return (double)pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE); case 1: // CFD. // In metals a Tick is still the smallest change, but is larger than a point. // If price can change from 123.25 to 123.50, // you have a TickSize of 0.25 and a point of 0.01. Pip has no meaning. // @todo - return pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE); + return (double)pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE); case 2: // Futures. // @todo - return pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE); + return (double)pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE); case 3: // CFD for indices. // @todo - return pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE); + return (double)pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE); } return false; } @@ -243,7 +252,7 @@ class Convert { /** * Get the difference between two price values (in pips). */ - static double GetValueDiffInPips(double price1, double price2, bool abs = false, int digits = NULL, + static double GetValueDiffInPips(double price1, double price2, bool abs = false, int digits = 0, string _symbol = NULL) { digits = digits ? digits : (int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS); return ValueToPips(abs ? fabs(price1 - price2) : (price1 - price2), digits); @@ -263,7 +272,7 @@ class Convert { else if (currency == "EUR") sign = (unsigned char)0x80; // ANSI code. else { - sign = NULL; + sign = ' '; prefix = false; } return prefix ? CharToString(sign) + DoubleToString(value, digits) diff --git a/DateTime.extern.h b/DateTime.extern.h new file mode 100644 index 000000000..87d156d81 --- /dev/null +++ b/DateTime.extern.h @@ -0,0 +1,79 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Includes. +#include "DateTime.enum.h" + +/** + * @file + * Includes external declarations related to date and time. + */ +#ifndef __MQL__ +#pragma once +// Forward declarations. +struct MqlDateTime; + +/** + * MQL's "datetime" type. + */ +class datetime { + time_t dt; + + public: + datetime(); + datetime(const long& _time); + datetime(const int& _time); + bool operator==(const int& _time) const; + bool operator==(const datetime& _time) const; + bool operator<(const int& _time) const; + bool operator>(const int& _time) const; + bool operator<(const datetime& _time); + bool operator>(const datetime& _time); + operator long() const; +}; + +extern datetime TimeCurrent(); +extern datetime TimeCurrent(MqlDateTime& dt_struct); + +extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(datetime, time_array)); + +extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, datetime start_time, int count, + ARRAY_REF(datetime, time_array)); + +extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, datetime start_time, datetime stop_time, + ARRAY_REF(datetime, time_array)); + +extern datetime StructToTime(MqlDateTime& dt_struct); +extern bool TimeToStruct(datetime dt, MqlDateTime& dt_struct); +extern datetime TimeGMT(); +extern datetime TimeGMT(MqlDateTime& dt_struct); +extern datetime TimeTradeServer(); +extern datetime TimeTradeServer(MqlDateTime& dt_struct); +extern datetime StringToTime(const string& value); +extern string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES); + +template +extern datetime operator"" _D(); + +#define DATETIME_LITERAL(STR) _D " ## STR ## " +#endif diff --git a/DateTime.mqh b/DateTime.mqh index 156c78831..fd26c7021 100644 --- a/DateTime.mqh +++ b/DateTime.mqh @@ -40,6 +40,7 @@ struct DataParamEntry; #include "Array.mqh" #include "Data.struct.h" #include "DateTime.enum.h" +#include "DateTime.extern.h" #include "DateTime.struct.h" #ifndef __MQL4__ diff --git a/Dict.enum.h b/Dict.enum.h index 33887918c..080a50271 100644 --- a/Dict.enum.h +++ b/Dict.enum.h @@ -32,3 +32,24 @@ #define DICT_GROW_UP_PERCENT_DEFAULT 25 #define DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS 10 + +/** + * Whether Dict operates in yet uknown mode, as dict or as list. + */ +enum DictMode { DictModeUnknown, DictModeDict, DictModeList }; + +/** + * Reason of call to overflow listener. + */ +enum ENUM_DICT_OVERFLOW_REASON { + DICT_OVERFLOW_REASON_FULL, + DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, +}; + +/** + * Dictionary flags. + */ +enum ENUM_DICT_FLAG { + DICT_FLAG_NONE = 0, + DICT_FLAG_FILL_HOLES_UNSORTED = 1, +}; diff --git a/Dict.mqh b/Dict.mqh index cd55d66ba..8da1f31e7 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -28,6 +28,7 @@ #include "DictBase.mqh" #include "Matrix.mqh" #include "Serializer.mqh" +#include "SerializerNodeIterator.mqh" template class DictIterator : public DictIteratorBase { diff --git a/DictBase.mqh b/DictBase.mqh index daeaaae7a..e7f0b8a75 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -31,27 +31,6 @@ #include "DictSlot.mqh" #include "Serializer.mqh" -/** - * Whether Dict operates in yet uknown mode, as dict or as list. - */ -enum DictMode { DictModeUnknown, DictModeDict, DictModeList }; - -/** - * Reason of call to overflow listener. - */ -enum ENUM_DICT_OVERFLOW_REASON { - DICT_OVERFLOW_REASON_FULL, - DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, -}; - -/** - * 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 @@ -225,7 +204,7 @@ class DictBase { if (_DictSlots_ref.DictSlots[position].IsUsed()) { if (GetMode() == DictModeList) { - _should_be_removed = position == (int)key; + _should_be_removed = position == (unsigned int)key; } else { _should_be_removed = _DictSlots_ref.DictSlots[position].HasKey() && _DictSlots_ref.DictSlots[position].key == key; @@ -274,7 +253,7 @@ class DictBase { */ void FillHoleUnsorted(int _hole_slot_idx) { // After moving last element to fill the hole we - if (_hole_slot_idx == Size() - 1) { + if ((unsigned int)_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. @@ -378,10 +357,10 @@ class DictBase { * Specialization of hashing function. */ unsigned int Hash(const string& x) { - unsigned char c[]; + ARRAY(unsigned char, c); unsigned int h = 0; - if (x != NULL) { + if (!IsNull(x)) { h = 5381; int n = StringToCharArray(x, c); for (int i = 0; i < n; i++) { diff --git a/DictIteratorBase.mqh b/DictIteratorBase.mqh index 16fafb8a8..329fc5cb8 100644 --- a/DictIteratorBase.mqh +++ b/DictIteratorBase.mqh @@ -60,7 +60,7 @@ class DictIteratorBase { */ DictIteratorBase(const DictIteratorBase& right) : _dict(right._dict), - _hash(right._dict ? right._dict.GetHash() : 0), + _hash(right._dict ? right._dict PTR_DEREF GetHash() : 0), _slotIdx(right._slotIdx), _index(right._index) { _invalid_until_incremented = false; @@ -75,24 +75,24 @@ class DictIteratorBase { ++_index; _invalid_until_incremented = false; - DictSlot* slot = _dict.GetSlot(_slotIdx); + DictSlot* slot = _dict PTR_DEREF GetSlot(_slotIdx); // Iterating until we find valid, used slot. - while (slot != NULL && !slot.IsUsed()) { - slot = _dict.GetSlot(++_slotIdx); + while (slot != NULL && !slot PTR_DEREF IsUsed()) { + slot = _dict PTR_DEREF GetSlot(++_slotIdx); } - if (!slot || !slot.IsValid()) { + if (!slot || !slot PTR_DEREF IsValid()) { // Invalidating iterator. _dict = NULL; } } - bool HasKey() { return _dict.GetSlot(_slotIdx).HasKey(); } + bool HasKey() { return _dict PTR_DEREF GetSlot(_slotIdx) PTR_DEREF HasKey(); } K Key() { CheckValidity(); - return _dict.GetMode() == DictModeList ? (K)_slotIdx : _dict.GetSlot(_slotIdx).key; + return PTR_ATTRIB(_dict, GetMode()) == DictModeList ? (K)_slotIdx : _dict PTR_DEREF GetSlot(_slotIdx) PTR_DEREF key; } string KeyAsString(bool includeQuotes = false) { @@ -106,7 +106,7 @@ class DictIteratorBase { V Value() { CheckValidity(); - return _dict.GetSlot(_slotIdx).value; + return _dict PTR_DEREF GetSlot(_slotIdx) PTR_DEREF value; } void CheckValidity() { @@ -121,15 +121,15 @@ class DictIteratorBase { bool IsLast() { if (!IsValid()) return true; - if (_dict.GetMode() == DictModeUnknown || _dict.Size() == 0) { + if (_dict PTR_DEREF GetMode() == DictModeUnknown || _dict.Size() == 0) { return false; } - if (_dict.GetMode() != DictModeList) { + if (_dict PTR_DEREF GetMode() != DictModeList) { Alert("Dict iterator's IsLast() method may be used only when elements are added via Push() method."); } - return _index == _dict.Size() - 1; + return _index == _dict PTR_DEREF Size() - 1; } void ShiftPosition(int shift, bool invalid_until_incremented = false) { diff --git a/DictObject.mqh b/DictObject.mqh index 8bcc9d412..fbfd681aa 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -27,6 +27,7 @@ #include "Convert.mqh" #include "DictBase.mqh" #include "Serializer.mqh" +#include "SerializerNodeIterator.mqh" template class DictObjectIterator : public DictIteratorBase { @@ -39,14 +40,14 @@ class DictObjectIterator : public DictIteratorBase { /** * Constructor. */ - DictObjectIterator(DictBase& dict, unsigned int slotIdx) : DictIteratorBase(dict, slotIdx) {} + DictObjectIterator(DictBase& dict, unsigned int slotIdx) : DictIteratorBase(dict, slotIdx) {} /** * Copy constructor. */ - DictObjectIterator(const DictObjectIterator& right) : DictIteratorBase(right) {} + DictObjectIterator(const DictObjectIterator& right) : DictIteratorBase(right) {} - V* Value() { return &_dict.GetSlot(_slotIdx).value; } + V* Value() { return &(this PTR_DEREF _dict PTR_DEREF GetSlot(this PTR_DEREF _slotIdx) PTR_DEREF value); } }; /** @@ -71,37 +72,50 @@ class DictObject : public DictBase { Clear(); Resize(right.GetSlotCount()); for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; + this PTR_DEREF _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; } - _DictSlots_ref._num_used = right._DictSlots_ref._num_used; - _current_id = right._current_id; - _mode = right._mode; + this PTR_DEREF _DictSlots_ref._num_used = right._DictSlots_ref._num_used; + this PTR_DEREF _current_id = right._current_id; + this PTR_DEREF _mode = right._mode; + } + + DictObjectIterator Begin() { + // Searching for first item index. + for (unsigned int i = 0; i < (unsigned int)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots); ++i) { + if (this PTR_DEREF _DictSlots_ref.DictSlots[i].IsValid() && this PTR_DEREF _DictSlots_ref.DictSlots[i].IsUsed()) { + DictObjectIterator iter(THIS_REF, i); + return iter; + } + } + // No items found. + DictObjectIterator invalid; + return invalid; } void operator=(const DictObject& right) { Clear(); Resize(right.GetSlotCount()); for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; + this PTR_DEREF _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; } - _DictSlots_ref._num_used = right._DictSlots_ref._num_used; - _current_id = right._current_id; - _mode = right._mode; + this PTR_DEREF _DictSlots_ref._num_used = right._DictSlots_ref._num_used; + this PTR_DEREF _current_id = right._current_id; + this PTR_DEREF _mode = right._mode; } void Clear() { - for (unsigned int i = 0; i < (unsigned int)ArraySize(_DictSlots_ref.DictSlots); ++i) { - _DictSlots_ref.DictSlots[i].SetFlags(0); + for (unsigned int i = 0; i < (unsigned int)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots); ++i) { + this PTR_DEREF _DictSlots_ref.DictSlots[i].SetFlags(0); } - _DictSlots_ref._num_used = 0; + this PTR_DEREF _DictSlots_ref._num_used = 0; } /** * Inserts value using hashless key. */ bool Push(V& value) { - if (!InsertInto(_DictSlots_ref, value)) return false; + if (!InsertInto(this PTR_DEREF _DictSlots_ref, value)) return false; return true; } @@ -114,7 +128,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, true)) return false; + if (!InsertInto(this PTR_DEREF _DictSlots_ref, key, value, true)) return false; return true; } @@ -123,10 +137,10 @@ class DictObject : public DictBase { unsigned int position; - if (_mode == DictModeList) - slot = GetSlot((unsigned int)key); + if (this PTR_DEREF _mode == DictModeList) + slot = this PTR_DEREF GetSlot((unsigned int)key); else - slot = GetSlotByKey(_DictSlots_ref, key, position); + slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, key, position); if (slot == NULL || !slot.IsUsed()) return NULL; @@ -138,7 +152,7 @@ class DictObject : public DictBase { */ V* GetByKey(const K _key) { unsigned int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, _key, position); + DictSlot* slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, _key, position); if (!slot) return NULL; @@ -149,7 +163,7 @@ class DictObject : public DictBase { * Returns value for a given position. */ V* GetByPos(unsigned int _position) { - DictSlot* slot = GetSlotByPos(_DictSlots_ref, _position); + DictSlot* slot = this PTR_DEREF GetSlotByPos(this PTR_DEREF _DictSlots_ref, _position); if (!slot) { Alert("Invalid DictStruct position \"", _position, "\" (called by GetByPos()). Returning empty structure."); @@ -163,10 +177,12 @@ class DictObject : public DictBase { /** * Checks whether dictionary contains given key => value pair. */ +#ifdef __MQL__ template <> +#endif bool Contains(const K key, const V& value) { unsigned int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, key, position); + DictSlot* slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, key, position); if (!slot) return false; @@ -176,7 +192,9 @@ class DictObject : public DictBase { /** * Returns index of dictionary's value or -1 if value doesn't exist. */ +#ifdef __MQL__ template <> +#endif int IndexOf(V& value) { for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { if (i.Value() == value) { @@ -192,37 +210,37 @@ class DictObject : public DictBase { * Inserts value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { - if (_mode == DictModeUnknown) - _mode = DictModeDict; - else if (_mode != DictModeDict) { + if (this PTR_DEREF _mode == DictModeUnknown) + this PTR_DEREF _mode = DictModeDict; + else if (this PTR_DEREF _mode != DictModeDict) { Alert("Warning: Dict already operates as a list, not a dictionary!"); return false; } unsigned int position; - DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); + DictSlot* keySlot = this PTR_DEREF GetSlotByKey(dictSlotsRef, key, position); - if (keySlot == NULL && !IsGrowUpAllowed()) { + if (keySlot == NULL && !this PTR_DEREF IsGrowUpAllowed()) { // Resize is prohibited. return false; } // Will resize dict if there were performance problems before. - if (allow_resize && IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (allow_resize && this PTR_DEREF IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { if (!GrowUp()) { return false; } // We now have new positions of slots, so we have to take the corrent slot again. - keySlot = GetSlotByKey(dictSlotsRef, key, position); + keySlot = this PTR_DEREF GetSlotByKey(dictSlotsRef, key, position); } if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { // No DictSlotsRef.DictSlots available. - if (overflow_listener != NULL) { - if (!overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { + if (this PTR_DEREF overflow_listener != NULL) { + if (!this PTR_DEREF overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { // Overwriting slot pointed exactly by key's position in the hash table (we don't check for possible // conflicts). - keySlot = &dictSlotsRef.DictSlots[Hash(key) % ArraySize(dictSlotsRef.DictSlots)]; + keySlot = &dictSlotsRef.DictSlots[this PTR_DEREF Hash(key) % ArraySize(dictSlotsRef.DictSlots)]; } } @@ -233,18 +251,20 @@ class DictObject : public DictBase { } if (keySlot == NULL) { - position = Hash(key) % ArraySize(dictSlotsRef.DictSlots); + position = this PTR_DEREF Hash(key) % ArraySize(dictSlotsRef.DictSlots); unsigned int _starting_position = position; - int _num_conflicts = 0; + unsigned int _num_conflicts = 0; bool _overwrite_slot = false; // Searching for empty DictSlot or used one with the matching key. It skips used, hashless DictSlots. while (dictSlotsRef.DictSlots[position].IsUsed() && (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { - if (overflow_listener_max_conflicts != 0 && ++_num_conflicts == overflow_listener_max_conflicts) { - if (overflow_listener != NULL) { - if (!overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used, _num_conflicts)) { + if (this PTR_DEREF overflow_listener_max_conflicts != 0 && + ++_num_conflicts == this PTR_DEREF overflow_listener_max_conflicts) { + if (this PTR_DEREF overflow_listener != NULL) { + if (!this PTR_DEREF overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used, + _num_conflicts)) { // Overflow listener returned false so we won't search for further empty slot. _overwrite_slot = true; break; @@ -282,9 +302,9 @@ class DictObject : public DictBase { * Inserts hashless value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { - if (_mode == DictModeUnknown) - _mode = DictModeList; - else if (_mode != DictModeList) { + if (this PTR_DEREF _mode == DictModeUnknown) + this PTR_DEREF _mode = DictModeList; + else if (this PTR_DEREF _mode != DictModeList) { Alert("Warning: Dict already operates as a dictionary, not a list!"); DebugBreak(); return false; @@ -295,7 +315,8 @@ class DictObject : public DictBase { if (!GrowUp()) return false; } - unsigned int position = Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); + unsigned int position = + this PTR_DEREF Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); // Searching for empty DictSlot. while (dictSlotsRef.DictSlots[position].IsUsed()) { @@ -315,14 +336,16 @@ class DictObject : public DictBase { * Expands array of DictSlots by given percentage value. */ bool GrowUp(int percent = DICT_GROW_UP_PERCENT_DEFAULT) { - return Resize(MathMax(10, (int)((float)ArraySize(_DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); + return Resize(MathMax( + 10, (int)((float)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } /** * Shrinks or expands array of DictSlots. */ bool Resize(int new_size) { - if (new_size <= MathMin(_DictSlots_ref._num_used, ArraySize(_DictSlots_ref.DictSlots))) { + if (new_size <= + MathMin(this PTR_DEREF _DictSlots_ref._num_used, ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots))) { // We already use minimum number of slots possible. return true; } @@ -338,31 +361,37 @@ class DictObject : public DictBase { } // Copies entire array of DictSlots into new array of DictSlots. Hashes will be rehashed. - for (i = 0; i < ArraySize(_DictSlots_ref.DictSlots); ++i) { - if (!_DictSlots_ref.DictSlots[i].IsUsed()) continue; + for (i = 0; i < ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots); ++i) { + if (!this PTR_DEREF _DictSlots_ref.DictSlots[i].IsUsed()) continue; - if (_DictSlots_ref.DictSlots[i].HasKey()) { - if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].key, _DictSlots_ref.DictSlots[i].value, false)) + if (this PTR_DEREF _DictSlots_ref.DictSlots[i].HasKey()) { + if (!InsertInto(new_DictSlots, this PTR_DEREF _DictSlots_ref.DictSlots[i].key, + this PTR_DEREF _DictSlots_ref.DictSlots[i].value, false)) return false; } else { - if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].value)) return false; + if (!InsertInto(new_DictSlots, this PTR_DEREF _DictSlots_ref.DictSlots[i].value)) return false; } } // Freeing old DictSlots array. - ArrayFree(_DictSlots_ref.DictSlots); + ArrayFree(this PTR_DEREF _DictSlots_ref.DictSlots); - _DictSlots_ref = new_DictSlots; + this PTR_DEREF _DictSlots_ref = new_DictSlots; return true; } + public: +#ifdef __MQL__ template <> +#endif SerializerNodeType Serialize(Serializer& s) { if (s.IsWriting()) { - for (DictIteratorBase i(Begin()); i.IsValid(); ++i) - s.PassObject(this, GetMode() == DictModeDict ? i.KeyAsString() : "", i.Value()); + for (DictObjectIterator i(Begin()); i.IsValid(); ++i) { + V* _value = i.Value(); + s.PassObject(THIS_REF, this PTR_DEREF GetMode() == DictModeDict ? i.KeyAsString() : "", PTR_TO_REF(_value)); + } - return (GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray; + return (this PTR_DEREF GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray; } else { if (s.IsArray()) { unsigned int num_items = s.NumArrayItems(); @@ -391,9 +420,11 @@ class DictObject : public DictBase { // Note that we're retrieving value by a key (as we are in an // object!). - Set(key, i.Struct(i.Key())); + V _prop = i.Struct(i.Key()); + Set(key, _prop); } else { - Push(i.Struct()); + V _prop = i.Struct(); + Push(_prop); } } return i.ParentNodeType(); @@ -404,7 +435,9 @@ class DictObject : public DictBase { /** * Initializes object with given number of elements. Could be skipped for non-containers. */ +#ifdef __MQL__ template <> +#endif void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) { V _child; diff --git a/DictSlot.mqh b/DictSlot.mqh index c64aa3eda..3c1fe29e1 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -52,7 +52,7 @@ class DictSlot { void AddFlags(unsigned char flags) { _flags |= flags; } - void RemoveFlags(unsigned char flags) { _flags &= ~flags; } + void RemoveFlags(unsigned char flags) { _flags &= (unsigned char)~flags; } }; #endif diff --git a/DictSlotsRef.h b/DictSlotsRef.h index 140140c49..e5ae9ee58 100644 --- a/DictSlotsRef.h +++ b/DictSlotsRef.h @@ -38,7 +38,7 @@ class DictSlot; template struct DictSlotsRef { - DictSlot DictSlots[]; + ARRAY(DictSlot, DictSlots); // Incremental index for dict operating in list mode. int _list_index; @@ -61,7 +61,7 @@ struct DictSlotsRef { */ void AddConflicts(int num) { if (num != 0) { - _avg_conflicts += float(num) / ++_num_conflicts; + _avg_conflicts += (float)num / (float)++_num_conflicts; } } diff --git a/DictStruct.mqh b/DictStruct.mqh index b4cb0d747..405dcee7a 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -31,6 +31,7 @@ class Log; #include "DictBase.mqh" #include "DictIteratorBase.mqh" #include "Serializer.mqh" +#include "SerializerNodeIterator.mqh" // DictIterator could be used as DictStruct iterator. #define DictStructIterator DictIteratorBase diff --git a/DrawIndicator.mqh b/DrawIndicator.mqh index 7017a81eb..2888b77cf 100644 --- a/DrawIndicator.mqh +++ b/DrawIndicator.mqh @@ -32,7 +32,6 @@ // Includes. #include "DictObject.mqh" #include "Draw.mqh" -#include "Indicator.mqh" #include "Object.mqh" // Forward declaration. diff --git a/EA.mqh b/EA.mqh index 69d39f812..8fba5ff06 100644 --- a/EA.mqh +++ b/EA.mqh @@ -149,7 +149,7 @@ class EA { * @return * Returns TradeSignalEntry struct. */ - TradeSignalEntry GetStrategySignalEntry(Strategy *_strat, bool _trade_allowed = true, int _shift = -1) { + TradeSignalEntry GetStrategySignalEntry(Strategy *_strat, bool _trade_allowed = true, int _shift = 0) { // float _bf = 1.0; float _scl = _strat.Get(STRAT_PARAM_SCL); float _sol = _strat.Get(STRAT_PARAM_SOL); @@ -426,7 +426,7 @@ class EA { if (eparams.CheckFlagDataStore(EA_DATA_STORE_INDICATOR)) { for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { Strategy *_strati = iter.Value().Ptr(); - IndicatorBase *_indi = _strati.GetIndicator(); + IndicatorData *_indi = _strati.GetIndicator(); if (_indi != NULL) { ENUM_TIMEFRAMES _itf = _indi.GetParams().tf.GetTf(); IndicatorDataEntry _ientry = _indi.GetEntry(); @@ -485,7 +485,7 @@ class EA { string _key_chart = "Chart"; _key_chart += StringFormat("-%d-%d", data_chart.GetMin(), data_chart.GetMax()); - SerializerConverter _stub = Serializer::MakeStubObject>(_serializer_flags); + SerializerConverter _stub = SerializerConverter::MakeStubObject>(_serializer_flags); SerializerConverter _obj = SerializerConverter::FromObject(data_chart, _serializer_flags); if ((_methods & EA_DATA_EXPORT_CSV) != 0) { @@ -505,7 +505,8 @@ class EA { _obj.Clean(); } if (eparams.CheckFlagDataStore(EA_DATA_STORE_INDICATOR)) { - SerializerConverter _stub = Serializer::MakeStubObject>(_serializer_flags); + SerializerConverter _stub = + SerializerConverter::MakeStubObject>(_serializer_flags); /* for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { @@ -540,7 +541,7 @@ class EA { _stub.Clean(); } if (eparams.CheckFlagDataStore(EA_DATA_STORE_STRATEGY)) { - SerializerConverter _stub = Serializer::MakeStubObject>(_serializer_flags); + SerializerConverter _stub = SerializerConverter::MakeStubObject>(_serializer_flags); /* @fixme for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { @@ -570,7 +571,7 @@ class EA { _stub.Clean(); } if (eparams.CheckFlagDataStore(EA_DATA_STORE_SYMBOL)) { - SerializerConverter _stub = Serializer::MakeStubObject>(_serializer_flags); + SerializerConverter _stub = SerializerConverter::MakeStubObject>(_serializer_flags); SerializerConverter _obj = SerializerConverter::FromObject(data_symbol, _serializer_flags); string _key_sym = "Symbol"; diff --git a/Exchange/Exchange.h b/Exchange/Exchange.h new file mode 100644 index 000000000..85b9e9202 --- /dev/null +++ b/Exchange/Exchange.h @@ -0,0 +1,83 @@ +//+------------------------------------------------------------------+ +//| 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 . + * + */ + +/** + * Exchange class. + */ +#ifndef EXCHANGE_H +#define EXCHANGE_H + +// Includes. +#include "../Account.mqh" +#include "../DictObject.mqh" +#include "../SymbolInfo.mqh" +#include "../Trade.mqh" +#include "Exchange.struct.h" + +class Exchange { + protected: + DictObject accounts; + DictObject symbols; + DictObject trades; + ExchangeParams eparams; + + public: + /** + * Class constructor without parameters. + */ + Exchange(){}; + + /** + * Class constructor with parameters. + */ + Exchange(ExchangeParams &_eparams) : eparams(_eparams){}; + + /** + * Class deconstructor. + */ + ~Exchange() {} + + /* Adders */ + + /** + * Adds account to the list. + */ + void AccountAdd(Account &_account, string _name) { accounts.Set(_name, _account); } + + /** + * Adds symbol to the list. + */ + void SymbolAdd(SymbolInfo &_sinfo, string _name) { symbols.Set(_name, _sinfo); } + + /* Removers */ + + /** + * Removes account from the list. + */ + void AccountRemove(string _name) { accounts.Unset(_name); } + + /** + * Removes symbol from the list. + */ + void SymbolRemove(string _name) { symbols.Unset(_name); } +}; +#endif // EXCHANGE_H diff --git a/Exchange/Exchange.struct.h b/Exchange/Exchange.struct.h new file mode 100644 index 000000000..d63290d4f --- /dev/null +++ b/Exchange/Exchange.struct.h @@ -0,0 +1,42 @@ +//+------------------------------------------------------------------+ +//| 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 Exchange's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Forward class declaration. +class Exchange; + +/* Defines struct for Exchange parameters. */ +struct ExchangeParams { + // Constructors. + ExchangeParams() {} + ExchangeParams(const ExchangeParams &_eparams) {} + long id; +}; diff --git a/Exchange/tests/Exchange.test.mq4 b/Exchange/tests/Exchange.test.mq4 new file mode 100644 index 000000000..2b3fdf2da --- /dev/null +++ b/Exchange/tests/Exchange.test.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 Exchange class. + */ + +// Includes. +#include "Exchange.test.mq5" diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 new file mode 100644 index 000000000..1c9d1c39b --- /dev/null +++ b/Exchange/tests/Exchange.test.mq5 @@ -0,0 +1,43 @@ +//+------------------------------------------------------------------+ +//| 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 Exchange class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../Exchange.h" + +// Test classes. +class ExchangeDummy : public Exchange {}; + +// Global variables. +ExchangeDummy ex_dummy; + +/** + * Implements OnInit(). + */ +int OnInit() { + bool _result = true; + return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; +} diff --git a/File.define.h b/File.define.h new file mode 100644 index 000000000..e932ab836 --- /dev/null +++ b/File.define.h @@ -0,0 +1,31 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Defines. +#ifndef __MQL__ +// File constants to read the whole value of char, short or int type. +#define CHAR_VALUE 1 +#define INT_VALUE 4 +#define SHORT_VALUE 2 +// Used for checking file handles (see FileOpen() and FileFindFirst()). +#define INVALID_HANDLE -1 +#endif diff --git a/File.extern.h b/File.extern.h new file mode 100644 index 000000000..52e15849a --- /dev/null +++ b/File.extern.h @@ -0,0 +1,36 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Includes. +#include "File.define.h" +#include "Terminal.define.h" + +// Define external global functions. +#ifndef __MQL__ +extern bool FileIsEnding(int file_handle); +extern bool FileIsExist(const string file_name, int common_flag = 0); +extern int FileClose(int file_handle); +extern int FileOpen(string file_name, int open_flags, short delimiter = '\t', uint codepage = CP_ACP); +extern int FileReadInteger(int file_handle, int size = INT_VALUE); +extern string FileReadString(int file_handle, int length = -1); +extern uint FileWriteString(int file_handle, const string text_string, int length = -1); +#endif diff --git a/File.mqh b/File.mqh index 4fe3dcb6b..56c33bd57 100644 --- a/File.mqh +++ b/File.mqh @@ -30,7 +30,10 @@ */ // Includes. +#include "File.define.h" +#include "File.extern.h" #include "Terminal.define.h" +#include "Terminal.extern.h" #include "Terminal.enum.h" #ifndef __MQL__ diff --git a/Indicator.define.h b/Indicator.define.h index d5056e91f..ab51a433d 100644 --- a/Indicator.define.h +++ b/Indicator.define.h @@ -44,7 +44,7 @@ SET_HANDLE; \ } \ if (Terminal::IsVisualMode()) { \ - int _bars_calc = BarsCalculated(_handle); \ + int _bars_calc = ::BarsCalculated(_handle); \ if (GetLastError() > 0) { \ return EMPTY_VALUE; \ } else if (_bars_calc <= 2) { \ diff --git a/Indicator.enum.h b/Indicator.enum.h index 375064b34..bce168e60 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -40,117 +40,99 @@ enum ENUM_INDICATOR_ACTION { FINAL_INDICATOR_ACTION_ENTRY }; -/* Define type of indicators. */ +/* Define type of */ enum ENUM_INDICATOR_TYPE { - INDI_NONE = 0, // (None) - INDI_AC, // Accelerator Oscillator - INDI_AD, // Accumulation/Distribution - INDI_ADX, // Average Directional Index - INDI_ADXW, // ADX by Welles Wilder - INDI_ALLIGATOR, // Alligator - INDI_AMA, // Adaptive Moving Average - INDI_APPLIED_PRICE, // Applied Price over OHLC Indicator - INDI_AO, // Awesome Oscillator - INDI_ASI, // Accumulation Swing Index - INDI_ATR, // Average True Range - INDI_BANDS, // Bollinger Bands - INDI_BANDS_ON_PRICE, // Bollinger Bands (on Price) - INDI_BEARS, // Bears Power - INDI_BULLS, // Bulls Power - INDI_BWMFI, // Market Facilitation Index - INDI_BWZT, // Bill Williams' Zone Trade - INDI_CANDLE, // Candle Pattern Detector - INDI_CCI, // Commodity Channel Index - INDI_CCI_ON_PRICE, // Commodity Channel Index (CCI) (on Price) - INDI_CHAIKIN, // Chaikin Oscillator - INDI_CHAIKIN_V, // Chaikin Volatility - INDI_COLOR_BARS, // Color Bars - INDI_COLOR_CANDLES_DAILY, // Color Candles Daily - INDI_COLOR_LINE, // Color Line - INDI_CUSTOM, // Custom indicator - INDI_CUSTOM_MOVING_AVG, // Custom Moving Average - INDI_DEMA, // Double Exponential Moving Average - INDI_DEMARKER, // DeMarker - INDI_DEMO, // Demo/Dummy Indicator - INDI_DETRENDED_PRICE, // Detrended Price Oscillator - INDI_DRAWER, // Drawer (Socket-based) Indicator - INDI_ENVELOPES, // Envelopes - INDI_ENVELOPES_ON_PRICE, // Evelopes (on Price) - INDI_FORCE, // Force Index - INDI_FRACTALS, // Fractals - INDI_FRAMA, // Fractal Adaptive Moving Average - 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). - INDI_MARKET_FI, // Market Facilitation Index - INDI_MASS_INDEX, // Mass Index - INDI_MFI, // Money Flow Index - INDI_MOMENTUM, // Momentum - INDI_MOMENTUM_ON_PRICE, // Momentum (on Price) - INDI_OBV, // On Balance Volume - INDI_OHLC, // OHLC (Open-High-Low-Close) - INDI_OSMA, // OsMA - INDI_PATTERN, // Pattern Detector - INDI_PIVOT, // Pivot Detector - INDI_PRICE, // Price - INDI_PRICE_CHANNEL, // Price Channel - INDI_PRICE_FEEDER, // Indicator which returns prices from custom array - INDI_PRICE_VOLUME_TREND, // Price and Volume Trend - INDI_RATE_OF_CHANGE, // Rate of Change - INDI_RS, // Indi_Math-based RSI indicator. - INDI_RSI, // Relative Strength Index - INDI_RSI_ON_PRICE, // Relative Strength Index (RSI) (on Price) - INDI_RVI, // Relative Vigor Index - INDI_SAR, // Parabolic SAR - INDI_SPECIAL_MATH, // Math operations over given indicator. - INDI_STDDEV, // Standard Deviation - INDI_STDDEV_ON_MA_SMA, // Standard Deviation on Moving Average in SMA mode - INDI_STDDEV_ON_PRICE, // Standard Deviation (on Price) - INDI_STDDEV_SMA_ON_PRICE, // Standard Deviation in SMA mode (on Price) - INDI_STOCHASTIC, // Stochastic Oscillator - INDI_SVE_BB, // SVE Bollinger Bands - INDI_TEMA, // Triple Exponential Moving Average - INDI_TICK, // Tick - INDI_TMA_TRUE, // Triangular Moving Average True - INDI_TRIX, // Triple Exponential Moving Averages Oscillator - INDI_ULTIMATE_OSCILLATOR, // Ultimate Oscillator - INDI_VIDYA, // Variable Index Dynamic Average - INDI_VOLUMES, // Volumes - INDI_VROC, // Volume Rate of Change - INDI_WILLIAMS_AD, // Larry Williams' Accumulation/Distribution - INDI_WPR, // Williams' Percent Range - INDI_ZIGZAG, // ZigZag - INDI_ZIGZAG_COLOR, // ZigZag Color + INDI_NONE = 0, // (None) + INDI_AC, // Accelerator Oscillator + INDI_AD, // Accumulation/Distribution + INDI_ADX, // Average Directional Index + INDI_ADXW, // ADX by Welles Wilder + INDI_ALLIGATOR, // Alligator + INDI_AMA, // Adaptive Moving Average + INDI_APPLIED_PRICE, // Applied Price over OHLC Indicator + INDI_AO, // Awesome Oscillator + INDI_ASI, // Accumulation Swing Index + INDI_ATR, // Average True Range + INDI_BANDS, // Bollinger Bands + INDI_BANDS_ON_PRICE, // Bollinger Bands (on Price) + INDI_BEARS, // Bears Power + INDI_BULLS, // Bulls Power + INDI_BWMFI, // Market Facilitation Index + INDI_BWZT, // Bill Williams' Zone Trade + INDI_CANDLE, // Candle Pattern Detector + INDI_CCI, // Commodity Channel Index + INDI_CCI_ON_PRICE, // Commodity Channel Index (CCI) (on Price) + INDI_CHAIKIN, // Chaikin Oscillator + INDI_CHAIKIN_V, // Chaikin Volatility + INDI_COLOR_BARS, // Color Bars + INDI_COLOR_CANDLES_DAILY, // Color Candles Daily + INDI_COLOR_LINE, // Color Line + INDI_CUSTOM, // Custom indicator + INDI_CUSTOM_MOVING_AVG, // Custom Moving Average + INDI_DEMA, // Double Exponential Moving Average + INDI_DEMARKER, // DeMarker + INDI_DEMO, // Demo/Dummy Indicator + INDI_DETRENDED_PRICE, // Detrended Price Oscillator + INDI_DRAWER, // Drawer (Socket-based) Indicator + INDI_ENVELOPES, // Envelopes + INDI_ENVELOPES_ON_PRICE, // Evelopes (on Price) + INDI_FORCE, // Force Index + INDI_FRACTALS, // Fractals + INDI_FRAMA, // Fractal Adaptive Moving Average + 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). + INDI_MARKET_FI, // Market Facilitation Index + INDI_MASS_INDEX, // Mass Index + INDI_MFI, // Money Flow Index + INDI_MOMENTUM, // Momentum + INDI_MOMENTUM_ON_PRICE, // Momentum (on Price) + INDI_OBV, // On Balance Volume + INDI_OHLC, // OHLC (Open-High-Low-Close) + INDI_OSMA, // OsMA + INDI_PATTERN, // Pattern Detector + INDI_PIVOT, // Pivot Detector + INDI_PRICE, // Price + INDI_PRICE_CHANNEL, // Price Channel + INDI_PRICE_FEEDER, // Indicator which returns prices from custom array + INDI_PRICE_VOLUME_TREND, // Price and Volume Trend + INDI_RATE_OF_CHANGE, // Rate of Change + INDI_RS, // Indi_Math-based RSI + INDI_RSI, // Relative Strength Index + INDI_RSI_ON_PRICE, // Relative Strength Index (RSI) (on Price) + INDI_RVI, // Relative Vigor Index + INDI_SAR, // Parabolic SAR + INDI_SPECIAL_MATH, // Math operations over given + INDI_STDDEV, // Standard Deviation + INDI_STDDEV_ON_MA_SMA, // Standard Deviation on Moving Average in SMA mode + INDI_STDDEV_ON_PRICE, // Standard Deviation (on Price) + INDI_STDDEV_SMA_ON_PRICE, // Standard Deviation in SMA mode (on Price) + INDI_STOCHASTIC, // Stochastic Oscillator + INDI_SVE_BB, // SVE Bollinger Bands + INDI_TEMA, // Triple Exponential Moving Average + INDI_TF, // Timeframe + INDI_TICK, // Tick + INDI_TMA_TRUE, // Triangular Moving Average True + INDI_TRIX, // Triple Exponential Moving Averages Oscillator + INDI_ULTIMATE_OSCILLATOR, // Ultimate Oscillator + INDI_ULTIMATE_OSCILLATOR_ATR_FAST, // Ultimate Oscillator's ATR, Fast + INDI_ULTIMATE_OSCILLATOR_ATR_MIDDLE, // Ultimate Oscillator's ATR, Middle + INDI_ULTIMATE_OSCILLATOR_ATR_SLOW, // Ultimate Oscillator's ATR, Slow + INDI_VIDYA, // Variable Index Dynamic Average + INDI_VOLUMES, // Volumes + INDI_VROC, // Volume Rate of Change + INDI_WILLIAMS_AD, // Larry Williams' Accumulation/Distribution + INDI_WPR, // Williams' Percent Range + INDI_ZIGZAG, // ZigZag + INDI_ZIGZAG_COLOR, // ZigZag Color FINAL_INDICATOR_TYPE_ENTRY }; -/* Defines type of source data for indicator. */ -enum ENUM_IDATA_SOURCE_TYPE { - IDATA_BUILTIN = 0, // Platform built-in - IDATA_CHART, // Chart calculation - IDATA_ICUSTOM, // iCustom: Custom indicator file - IDATA_ICUSTOM_LEGACY, // iCustom: Custom, legacy, provided by MT indicator file - IDATA_INDICATOR, // OnIndicator: Another indicator as a source of data - IDATA_ONCALCULATE, // OnCalculate: Custom calculation function - IDATA_MATH // Math-based indicator -}; - -/* Defines range value data type for indicator storage. */ -enum ENUM_IDATA_VALUE_RANGE { - IDATA_RANGE_ARROW, // Value is non-zero on signal. - IDATA_RANGE_BINARY, // E.g. 0 or 1. - IDATA_RANGE_BITWISE, // Bitwise - IDATA_RANGE_MIXED, - IDATA_RANGE_PRICE, // Values represent price. - IDATA_RANGE_RANGE, // E.g. 0 to 100. - IDATA_RANGE_UNKNOWN -}; - -// Indicator line identifiers used in ADX and ADXW indicators. +// Indicator line identifiers used in ADX and ADXW enum ENUM_INDI_ADX_LINE { #ifdef __MQL4__ LINE_MAIN_ADX = MODE_MAIN, // Base indicator line. @@ -172,7 +154,7 @@ enum ENUM_INDICATOR_INDEX { FINAL_ENUM_INDICATOR_INDEX = 3 // Should be the last one. Used to calculate the number of enum items. }; -/* Indicator line identifiers used in Envelopes and Fractals indicators. */ +/* Indicator line identifiers used in Envelopes and Fractals */ enum ENUM_LO_UP_LINE { #ifdef __MQL4__ LINE_UPPER = MODE_UPPER, // Upper line. @@ -185,7 +167,7 @@ enum ENUM_LO_UP_LINE { }; /** - * Indicator line identifiers used in MACD, RVI and Stochastic indicators. + * Indicator line identifiers used in MACD, RVI and Stochastic * * @see: * - https://docs.mql4.com/constants/indicatorconstants/lines @@ -227,3 +209,28 @@ enum INDICATOR_ENTRY_FLAGS { INDI_ENTRY_FLAG_IS_VALID = 1 << 6, INDI_ENTRY_FLAG_INSUFFICIENT_DATA = 1 << 7, // Entry has missing value for that shift and probably won't ever have. }; + +// Storage type for IndicatorBase::GetSpecificValueStorage(). +enum ENUM_INDI_VS_TYPE { + INDI_VS_TYPE_TIME, // Candle. + INDI_VS_TYPE_TICK_VOLUME, // Candle. + INDI_VS_TYPE_VOLUME, // Candle. + INDI_VS_TYPE_SPREAD, // Candle. + INDI_VS_TYPE_PRICE_OPEN, // Candle. + INDI_VS_TYPE_PRICE_HIGH, // Candle. + INDI_VS_TYPE_PRICE_LOW, // Candle. + INDI_VS_TYPE_PRICE_CLOSE, // Candle. + INDI_VS_TYPE_PRICE_MEDIAN, // Candle. + INDI_VS_TYPE_PRICE_TYPICAL, // Candle. + INDI_VS_TYPE_PRICE_WEIGHTED, // Candle. + INDI_VS_TYPE_PRICE_BID, // Tick. + INDI_VS_TYPE_PRICE_ASK, // Tick. +}; + +// Indicator flags. +enum ENUM_INDI_FLAGS { + INDI_FLAG_INDEXABLE_BY_SHIFT, // Indicator supports indexation by shift. + INDI_FLAG_INDEXABLE_BY_TIMESTAMP, // Indicator supports indexation by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT, // Source indicator must be indexable by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP // Source indicator must be indexable by timestamp. +}; diff --git a/Indicator.mqh b/Indicator.mqh index b5b0f3c6f..49670df3e 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -38,8 +38,7 @@ class Chart; #include "Indicator.struct.cache.h" #include "Indicator.struct.h" #include "Indicator.struct.serialize.h" -#include "Indicator.struct.signal.h" -#include "IndicatorBase.h" +#include "IndicatorData.mqh" #include "Math.h" #include "Object.mqh" #include "Refs.mqh" @@ -50,36 +49,75 @@ 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 + +#ifdef __MQL5__ +// Defines global functions (for MQL5 forward compatibility). +template +double iCustom5(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) { + ResetLastError(); + static Dict _handlers; + string _key = Util::MakeKey(_symbol, (string)_tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j); + int _handle = _handlers.GetByKey(_key); + ICUSTOM_DEF(_handlers.Set(_key, _handle), + COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i COMMA _j); +} +template +double iCustom5(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, L _l, M _m, int _mode, int _shift) { + ResetLastError(); + static Dict _handlers; + string _key = Util::MakeKey(_symbol, (string)_tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m); + int _handle = _handlers.GetByKey(_key); + ICUSTOM_DEF(_handlers.Set(_key, _handle), COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h + COMMA _i COMMA _j COMMA _k COMMA _l COMMA _m); +} +#endif + /** * Class to deal with indicators. */ template -class Indicator : public IndicatorBase { +class Indicator : public IndicatorData { protected: - // Structs. + DrawIndicator* draw; TS iparams; protected: /* Protected methods */ + bool Init() { return InitDraw(); } + /** - * It's called on class initialization. + * Initialize indicator data drawing on custom data. */ - bool Init() { - ArrayResize(value_storages, iparams.GetMaxModes()); - switch (iparams.GetDataSourceType()) { - case IDATA_BUILTIN: - break; - case IDATA_ICUSTOM: - break; - case IDATA_INDICATOR: - if (!indi_src.IsSet()) { - // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); - // SetDataSource(_indi_price, true, PRICE_OPEN); - } - break; + bool InitDraw() { + if (iparams.is_draw && !Object::IsValid(draw)) { + draw = new DrawIndicator(THIS_PTR); + draw.SetColorLine(iparams.indi_color); + } + return iparams.is_draw; + } + + /** + * Deinitialize drawing. + */ + void DeinitDraw() { + if (draw) { + delete draw; } - return InitDraw(); } public: @@ -100,25 +138,21 @@ class Indicator : public IndicatorBase { /** * Class constructor. */ - Indicator(const TS& _iparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) - : IndicatorBase(_iparams.GetTf(), NULL) { + Indicator(const TS& _iparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, + int _indi_mode = 0) + : IndicatorData(_idparams, _indi_src, _indi_mode) { iparams = _iparams; - SetName(_iparams.name != "" ? _iparams.name : EnumToString(iparams.itype)); - if (_indi_src != NULL) { - SetDataSource(_indi_src, _indi_mode); - } Init(); } - Indicator(const TS& _iparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorBase(_tf) { + Indicator(const TS& _iparams, const IndicatorDataParams& _idparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + : IndicatorData(_idparams) { iparams = _iparams; - SetName(_iparams.name != "" ? _iparams.name : EnumToString(iparams.itype)); Init(); } Indicator(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "") - : IndicatorBase(_tf) { + : IndicatorData(IndicatorDataParams::GetInstance()) { iparams.SetIndicatorType(_itype); iparams.SetShift(_shift); - SetName(_name != "" ? _name : EnumToString(iparams.itype)); Init(); } @@ -127,41 +161,37 @@ class Indicator : public IndicatorBase { */ ~Indicator() { DeinitDraw(); } + /* Getters */ + /** - * Initialize indicator data drawing on custom data. + * Gets a value from IndicatorDataParams struct. */ - bool InitDraw() { - if (iparams.is_draw && !Object::IsValid(draw)) { - draw = new DrawIndicator(THIS_PTR); - draw.SetColorLine(iparams.indi_color); - } - return iparams.is_draw; + template + T Get(STRUCT_ENUM_IDATA_PARAM _param) { + return idparams.Get(_param); } - /* Deinit methods */ - /** - * Deinitialize drawing. + * Gets a value from IndicatorState struct. */ - void DeinitDraw() { - if (draw) { - delete draw; - } + template + T Get(STRUCT_ENUM_INDICATOR_STATE_PROP _param) { + return istate.Get(_param); } - /* Getters */ + /* Setters */ /** - * Gets an indicator property flag. + * Sets the value for IndicatorDataParams struct. */ - bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, int _shift = -1) { - IndicatorDataEntry _entry = GetEntry(_shift >= 0 ? _shift : iparams.GetShift()); - return _entry.CheckFlag(_prop); + template + void Set(STRUCT_ENUM_IDATA_PARAM _param, T _value) { + idparams.Set(_param, _value); } /* Buffer methods */ - virtual string CacheKey() { return GetName(); } + virtual string CacheKey() { return GetFullName(); } /** * Initializes a cached proxy between i*OnArray() methods and OnCalculate() @@ -248,48 +278,6 @@ class Indicator : public IndicatorBase { return GetIndicatorBuffers() > 0 && GetIndicatorBuffers() <= 512; } - /** - * 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; - } - /** * CopyBuffer() method to be used on Indicator instance with ValueStorage buffer. * @@ -320,52 +308,6 @@ class Indicator : public IndicatorBase { } */ - /** - * 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. - */ - void ValidateDataSource(IndicatorBase* _target, IndicatorBase* _source) { - if (_target == NULL) { - Alert("Internal Error! _target is NULL in ", __FUNCTION_LINE__, "."); - DebugBreak(); - return; - } - - if (_source == NULL) { - Alert("Error! You have to select source indicator's via SetDataSource()."); - DebugBreak(); - return; - } - - if (!_target.IsDataSourceModeSelectable()) { - // We don't validate source mode as it will use all modes. - return; - } - - 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.SetDataSourceMode(0); - DebugBreak(); - } 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.GetModeCount(), "."); - DebugBreak(); - } - } - /** * Checks whether indicator have given mode index. * @@ -374,13 +316,13 @@ class Indicator : public IndicatorBase { 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.GetMaxModes() != 1) { + if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)) != 1) { Alert("Error: ", GetName(), " must have exactly one possible mode in order to skip using SetDataSourceMode()!"); DebugBreak(); } _out_mode = 0; - } else if (_out_mode + 1 > (int)iparams.GetMaxModes()) { - Alert("Error: ", GetName(), " have ", iparams.GetMaxModes(), + } else if (_out_mode + 1 > Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) { + Alert("Error: ", GetName(), " have ", Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)), " mode(s) buy you tried to reference mode with index ", _out_mode, "! Ensure that you properly set mode via SetDataSourceMode()."); DebugBreak(); @@ -392,157 +334,21 @@ class Indicator : public IndicatorBase { */ virtual IndicatorBase* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } - /* 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 the highest bar's index (shift). - */ - template - int GetHighest(int count = WHOLE_ARRAY, int start_bar = 0) { - int max_idx = -1; - double max = -DBL_MAX; - int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); - - for (int shift = start_bar; shift <= last_bar; ++shift) { - double value = GetEntry(shift).GetMax(GetModeCount()); - if (value > max) { - max = value; - max_idx = shift; - } - } - - return max_idx; - } - - /** - * Returns the lowest bar's index (shift). - */ - template - int GetLowest(int count = WHOLE_ARRAY, int start_bar = 0) { - int min_idx = -1; - double min = DBL_MAX; - int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); - - for (int shift = start_bar; shift <= last_bar; ++shift) { - double value = GetEntry(shift).GetMin(GetModeCount()); - if (value < min) { - min = value; - min_idx = shift; - } - } - - return min_idx; - } - - /** - * Returns the highest value. - */ - template - double GetMax(int start_bar = 0, int count = WHOLE_ARRAY) { - double max = NULL; - 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.GetMaxModes()); - if (max == NULL || value > max) { - max = value; - } - } - - return max; - } - - /** - * Returns the lowest value. - */ - template - double GetMin(int start_bar, int count = WHOLE_ARRAY) { - double min = NULL; - 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.GetMaxModes()); - if (min == NULL || value < min) { - min = value; - } - } - - return min; - } - - /** - * Returns average value. - */ - template - double GetAvg(int start_bar, int count = WHOLE_ARRAY) { - int num_values = 0; - double sum = 0; - 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.GetMaxModes()); - double value_max = GetEntry(shift).GetMax(iparams.GetMaxModes()); - - sum += value_min + value_max; - num_values += 2; - } - - return sum / num_values; - } - - /** - * Returns median of values. - */ - template - double GetMed(int start_bar, int count = WHOLE_ARRAY) { - double array[]; - - int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); - int num_bars = last_bar - start_bar + 1; - int index = 0; - - ArrayResize(array, num_bars); - - for (int shift = start_bar; shift <= last_bar; ++shift) { - array[index++] = GetEntry(shift).GetAvg(iparams.GetMaxModes()); - } - - ArraySort(array); - double median; - int len = ArraySize(array); - if (len % 2 == 0) { - median = (array[len / 2] + array[(len / 2) - 1]) / 2; - } else { - median = array[len / 2]; - } - - return median; - } - /** * Returns currently selected data source doing validation. */ - IndicatorBase* GetDataSource() { - IndicatorBase* _result = NULL; + IndicatorData* GetDataSource() { + IndicatorData* _result = NULL; if (GetDataSourceRaw() != NULL) { _result = GetDataSourceRaw(); - } else if (iparams.GetDataSourceId() != -1) { - int _source_id = iparams.GetDataSourceId(); + } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) { + int _source_id = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)); if (indicators.KeyExists(_source_id)) { _result = indicators[_source_id].Ptr(); } else { - Ref _source = FetchDataSource((ENUM_INDICATOR_TYPE)_source_id); + Ref _source = FetchDataSource((ENUM_INDICATOR_TYPE)_source_id); if (!_source.IsSet()) { Alert(GetName(), " has no built-in source indicator ", _source_id); @@ -553,6 +359,17 @@ class Indicator : public IndicatorBase { _result = _source.Ptr(); } } + } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_INDICATOR) { + // User sets data source's mode to On-Indicator, but not set data source via SetDataSource()! + + // Requesting potential data source. + IndicatorData* _ds = OnDataSourceRequest(); + + if (_ds != NULL) { + // Initializing with new data source. + SetDataSource(_ds); + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR); + } } ValidateDataSource(&this, _result); @@ -568,7 +385,18 @@ class Indicator : public IndicatorBase { /** * Whether data source is selected. */ - virtual bool HasDataSource() { return GetDataSourceRaw() != NULL || iparams.GetDataSourceId() != -1; } + virtual bool HasDataSource(bool _try_initialize = false) { + if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) { + return true; + } + + if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_INDICATOR && + GetDataSourceRaw() == NULL && _try_initialize) { + SetDataSource(OnDataSourceRequest()); + } + + return GetDataSourceRaw() != NULL; + } /** * Gets indicator's params. @@ -578,12 +406,17 @@ class Indicator : public IndicatorBase { /** * Gets indicator's symbol. */ - string GetSymbol() { return Get(CHART_PARAM_SYMBOL); } + // string GetSymbol() { return Get(CHART_PARAM_SYMBOL); } + + /** + * Gets indicator's time-frame. + */ + // ENUM_TIMEFRAMES GetTf() { return Get(CHART_PARAM_TF); } /** * Gets indicator's time-frame. */ - ENUM_TIMEFRAMES GetTf() { return Get(CHART_PARAM_TF); } + ENUM_TIMEFRAMES GetTf() { return iparams.tf.GetTf(); } /** * Gets indicator's signals. @@ -599,35 +432,25 @@ class Indicator : public IndicatorBase { return _signals; } // Returns signals. - IndicatorSignal _signals(_data, iparams, cparams, _mode1, _mode2); + IndicatorSignal _signals(_data, idparams, cparams, _mode1, _mode2); return _signals; } - /** - * Get pointer to data of indicator. - */ - BufferStruct* GetData() { return GetPointer(idata); } - /** * Get name of the indicator. */ - string GetName() { return iparams.name; } - - /** - * Get full name of the indicator (with "over ..." part). - */ - string GetFullName() { - return iparams.name + "[" + IntegerToString(iparams.GetMaxModes()) + "]" + - (HasDataSource() ? (" (over " + GetDataSource().GetFullName() + ")") : ""); + string GetName() override { + return "(" + EnumToString(GetType()) + ")" + (iparams.name != "" ? (" " + iparams.name) : ""); } /** * Get more descriptive name of the indicator. */ string GetDescriptiveName() { + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); string name = iparams.name + " ("; - switch (iparams.GetDataSourceType()) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: name += "built-in, "; break; @@ -639,7 +462,7 @@ class Indicator : public IndicatorBase { break; } - name += IntegerToString(iparams.GetMaxModes()) + (iparams.GetMaxModes() == 1 ? " mode" : " modes"); + name += IntegerToString(_max_modes) + (_max_modes == 1 ? " mode" : " modes"); return name + ")"; } @@ -654,14 +477,6 @@ class Indicator : public IndicatorBase { Chart::Set(_param, _value); } - /** - * Sets indicator data source. - */ - void SetDataSource(IndicatorBase* _indi, int _input_mode = 0) { - indi_src = _indi; - iparams.SetDataSource(-1, _input_mode); - } - /** * Sets name of the indicator. */ @@ -799,65 +614,49 @@ class Indicator : public IndicatorBase { 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. + void OnTick() override { + Chart::OnTick(); - ++out_shift; + if (iparams.is_draw) { + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); + // Print("Drawing ", GetName(), iparams.indi_data != NULL ? (" (over " + iparams.indi_data.GetName() + ")") : ""); + for (int i = 0; i < _max_modes; ++i) + draw.DrawLineTo(GetName() + "_" + IntegerToString(i) + "_" + + Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)), + GetBarTime(0), GetEntry(0)[i], iparams.draw_window); } - - 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). + * Sets indicator data source. */ - 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; + void SetDataSource(IndicatorData* _indi, int _input_mode = -1) override { + if (indi_src.IsSet()) { + if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT) && + !bool(_indi.GetFlags() | INDI_FLAG_INDEXABLE_BY_SHIFT)) { + Print(GetFullName(), ": Cannot set data source to ", _indi.GetFullName(), + ", because source indicator isn't indexable by shift!"); + DebugBreak(); + return; + } + if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP) && + !bool(_indi.GetFlags() | INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { + Print(GetFullName(), ": Cannot set data source to ", _indi.GetFullName(), + ", because source indicator isn't indexable by timestamp!"); + DebugBreak(); + return; + } } - --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; - } - - 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.GetMaxModes(); ++i) - draw.DrawLineTo(GetName() + "_" + IntegerToString(i) + "_" + IntegerToString(iparams.GetDataSourceMode()), - GetBarTime(0), GetEntry(0)[i], iparams.draw_window); + if (indi_src.IsSet() && indi_src.Ptr() != _indi) { + indi_src.Ptr().RemoveListener(THIS_PTR); + } + indi_src = _indi; + if (_indi != NULL) { + indi_src.Ptr().AddListener(THIS_PTR); + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID), -1); + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE), _input_mode); + indi_src.Ptr().OnBecomeDataSourceFor(THIS_PTR); } } @@ -915,6 +714,19 @@ class Indicator : public IndicatorBase { return _result; } + /** + * Get full name of the indicator (with "over ..." part). + */ + string GetFullName() override { + return GetName() + "[" + Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)) + "]" + + (HasDataSource() ? (" (over " + GetDataSource().GetFullName() + ")") : ""); + } + + /** + * Get indicator type. + */ + ENUM_INDICATOR_TYPE GetType() override { return iparams.itype; } + /** * Update indicator. */ @@ -931,13 +743,14 @@ class Indicator : public IndicatorBase { * @return * Returns IndicatorDataEntry struct filled with indicator values. */ - virtual IndicatorDataEntry GetEntry(int _shift = -1) { + IndicatorDataEntry GetEntry(int _index = -1) override { ResetLastError(); - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _ishift = _index >= 0 ? _index : iparams.GetShift(); long _bar_time = GetBarTime(_ishift); IndicatorDataEntry _entry = idata.GetByKey(_bar_time); if (_bar_time > 0 && !_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) { - _entry.Resize(iparams.GetMaxModes()); + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); + _entry.Resize(_max_modes); _entry.timestamp = GetBarTime(_ishift); #ifndef __MQL4__ if (IndicatorBase::Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED))) { @@ -946,8 +759,8 @@ class Indicator : public IndicatorBase { IndicatorBase::Set(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED), false); } #endif - for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) { - switch (iparams.GetDataValueType()) { + for (int _mode = 0; _mode < _max_modes; _mode++) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE))) { case TYPE_BOOL: case TYPE_CHAR: case TYPE_INT: @@ -998,9 +811,23 @@ class Indicator : public IndicatorBase { * This method allows user to modify the struct entry before it's added to cache. * This method is called on GetEntry() right after values are set. */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _shift = -1) { - _entry.AddFlags(_entry.GetDataTypeFlags(iparams.GetDataValueType())); + virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _timestamp = -1) { + ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE)); + _entry.AddFlags(_entry.GetDataTypeFlags(_dtype)); }; + + /** + * Returns the indicator's entry value for the given shift and mode. + * + * @see: DataParamEntry. + * + * @return + * Returns DataParamEntry struct filled with a single value. + */ + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) override { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + return GetEntry(_ishift)[_mode]; + } }; #endif diff --git a/Indicator.struct.h b/Indicator.struct.h index 99bc74b84..7f90435ea 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -35,6 +35,9 @@ template class Indicator; struct ChartParams; +// Defines. +#define STRUCT_ENUM_INDICATOR_STATE_PROP STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) + // Includes. #include "Array.mqh" #include "Chart.struct.tf.h" @@ -45,379 +48,15 @@ struct ChartParams; #include "SerializerNode.enum.h" #include "Storage/ValueStorage.indicator.h" -// Type-less value for IndicatorDataEntryValue structure. -union IndicatorDataEntryTypelessValue { - double vdbl; - float vflt; - int vint; - long vlong; -}; - -// Type-aware value for IndicatorDataEntry class. -struct IndicatorDataEntryValue { - unsigned char flags; - IndicatorDataEntryTypelessValue value; - - // Returns type of the value. - ENUM_DATATYPE GetDataType() { return (ENUM_DATATYPE)((flags & 0xF0) >> 4); } - - // Sets type of the value. - void SetDataType(ENUM_DATATYPE _type) { - // Clearing type. - flags &= 0x0F; - - // Setting type. - flags |= (unsigned char)_type << 4; - } - - // Union operators. - template - T operator*(const T _value) { - return Get() * _value; - } - template - T operator+(const T _value) { - return Get() + _value; - } - template - T operator-(const T _value) { - return Get() - _value; - } - template - T operator/(const T _value) { - return Get() / _value; - } - template - bool operator!=(const T _value) { - return Get() != _value; - } - template - bool operator<(const T _value) { - return Get() < _value; - } - template - bool operator<=(const T _value) { - return Get() <= _value; - } - template - bool operator==(const T _value) { - return Get() == _value; - } - template - bool operator>(const T _value) { - return Get() > _value; - } - template - bool operator>=(const T _value) { - return Get() >= _value; - } - template - void operator=(const T _value) { - Set(_value); - } - // Checkers. - template - bool IsGt(T _value) { - return Get() > _value; - } - template - bool IsLt(T _value) { - return Get() < _value; - } - // Getters. - double GetDbl() { return value.vdbl; } - float GetFloat() { return value.vflt; } - int GetInt() { return value.vint; } - long GetLong() { return value.vlong; } - template - void Get(T &_out) { - _out = Get(); - } - template - T Get() { - T _v; - Get(_v); - return _v; - } - void Get(double &_out) { _out = value.vdbl; } - void Get(float &_out) { _out = value.vflt; } - void Get(int &_out) { _out = value.vint; } - void Get(unsigned int &_out) { _out = (unsigned int)value.vint; } - void Get(long &_out) { _out = value.vlong; } - void Get(unsigned long &_out) { _out = (unsigned long)value.vint; } - // Setters. - template - void Set(T _value) { - Set(_value); - } - void Set(double _value) { - value.vdbl = _value; - SetDataType(TYPE_DOUBLE); - } - void Set(float _value) { - value.vflt = _value; - SetDataType(TYPE_FLOAT); - } - void Set(int _value) { - value.vint = _value; - SetDataType(TYPE_INT); - } - void Set(unsigned int _value) { - value.vint = (int)_value; - SetDataType(TYPE_UINT); - } - void Set(long _value) { - value.vlong = _value; - SetDataType(TYPE_LONG); - } - void Set(unsigned long _value) { - value.vlong = (long)_value; - SetDataType(TYPE_ULONG); - } - // Serializers. - // SERIALIZER_EMPTY_STUB - SerializerNodeType Serialize(Serializer &_s); - // To string - template - string ToString() { - return (string)Get(); - } -}; - -/* Structure for indicator data entry. */ -struct IndicatorDataEntry { - long timestamp; // Timestamp of the entry's bar. - unsigned short flags; // Indicator entry flags. - ARRAY(IndicatorDataEntryValue, values); - - // Constructors. - IndicatorDataEntry(int _size = 1) : flags(INDI_ENTRY_FLAG_NONE), timestamp(0) { Resize(_size); } - IndicatorDataEntry(IndicatorDataEntry &_entry) { THIS_REF = _entry; } - int GetSize() { return ArraySize(values); } - // Operator overloading methods. - template - T operator*(const T _value) { - return values[0].Get() * _value; - } - template - T operator+(const T _value) { - return values[0].Get() + _value; - } - template - T operator-(const T _value) { - return values[0].Get() - _value; - } - template - T operator/(const T _value) { - return values[0].Get() / _value; - } - template - T operator[](I _index) { - return values[(int)_index].Get(); - } - template <> - double operator[](int _index) { - if (_index >= ArraySize(values)) { - return 0; - } - double _value; - values[_index].Get(_value); - return _value; - } - // Checkers. - template - bool HasValue(T _value) { - bool _result = false; - int _asize = ArraySize(values); - T _value2; - for (int i = 0; i < _asize; i++) { - values[i].Get(_value2); - if (_value == _value2) { - _result = true; - break; - } - } - return _result; - } - template - bool IsGe(T _value) { - return GetMin() >= _value; - } - template - bool IsGt(T _value) { - return GetMin() > _value; - } - template - bool IsLe(T _value) { - return GetMax() <= _value; - } - template - bool IsLt(T _value) { - return GetMax() < _value; - } - template - bool IsWithinRange(T _min, T _max) { - return GetMin() >= _min && GetMax() <= _max; - } - // Getters. - template - void GetArray(ARRAY_REF(T, _out), int _size = 0) { - int _asize = _size > 0 ? _size : ArraySize(_out); - for (int i = 0; i < _asize; i++) { - values[i].Get(_out[i]); - } - }; - template - T GetAvg(int _size = 0) { - int _asize = _size > 0 ? _size : ArraySize(values); - T _avg = GetSum() / _asize; - return _avg; - }; - template - T GetMin(int _size = 0) { - int _asize = _size > 0 ? _size : ArraySize(values); - int _index = 0; - for (int i = 1; i < _asize; i++) { - _index = values[i].Get() < values[_index].Get() ? i : _index; - } - return values[_index].Get(); - }; - template - T GetMax(int _size = 0) { - int _asize = _size > 0 ? _size : ArraySize(values); - int _index = 0; - for (int i = 1; i < _asize; i++) { - _index = values[i].Get() > values[_index].Get() ? i : _index; - } - return values[_index].Get(); - }; - template - T GetSum(int _size = 0) { - int _asize = _size > 0 ? _size : ArraySize(values); - T _sum = 0; - for (int i = 1; i < _asize; i++) { - _sum = +values[i].Get(); - } - return _sum; - }; - template - T GetValue(int _index = 0) { - return values[_index].Get(); - }; - template - void GetValues(T &_out1, T &_out2) { - values[0].Get(_out1); - values[1].Get(_out2); - }; - template - void GetValues(T &_out1, T &_out2, T &_out3) { - values[0].Get(_out1); - values[1].Get(_out2); - values[2].Get(_out3); - }; - template - void GetValues(T &_out1, T &_out2, T &_out3, T &_out4) { - values[0].Get(_out1); - values[1].Get(_out2); - values[2].Get(_out3); - values[3].Get(_out4); - }; - - // Getters. - int GetDayOfYear() { return DateTimeStatic::DayOfYear(timestamp); } - int GetMonth() { return DateTimeStatic::Month(timestamp); } - int GetYear() { return DateTimeStatic::Year(timestamp); } - long GetTime() { return timestamp; }; - ENUM_DATATYPE GetDataType(int _mode) { return values[_mode].GetDataType(); } - ushort GetDataTypeFlags(ENUM_DATATYPE _dt) { - switch (_dt) { - case TYPE_BOOL: - case TYPE_CHAR: - SetUserError(ERR_INVALID_PARAMETER); - break; - case TYPE_INT: - return INDI_ENTRY_FLAG_NONE; - case TYPE_LONG: - return INDI_ENTRY_FLAG_IS_DOUBLED; - case TYPE_UINT: - return INDI_ENTRY_FLAG_IS_UNSIGNED; - case TYPE_ULONG: - return INDI_ENTRY_FLAG_IS_UNSIGNED | INDI_ENTRY_FLAG_IS_DOUBLED; - case TYPE_DOUBLE: - return INDI_ENTRY_FLAG_IS_REAL | INDI_ENTRY_FLAG_IS_DOUBLED; - case TYPE_FLOAT: - return INDI_ENTRY_FLAG_IS_REAL; - case TYPE_STRING: - case TYPE_UCHAR: - SetUserError(ERR_INVALID_PARAMETER); - break; - default: - SetUserError(ERR_INVALID_PARAMETER); - break; - } - SetUserError(ERR_INVALID_PARAMETER); - return INDI_ENTRY_FLAG_NONE; - } - // Setters. - bool Resize(int _size = 0) { return _size > 0 ? ArrayResize(values, _size) > 0 : true; } - // Value flag methods for bitwise operations. - bool CheckFlag(INDICATOR_ENTRY_FLAGS _prop) { return CheckFlags(_prop); } - bool CheckFlags(unsigned short _flags) { return (flags & _flags) != 0; } - bool CheckFlagsAll(unsigned short _flags) { return (flags & _flags) == _flags; } - void AddFlags(unsigned short _flags) { flags |= _flags; } - void RemoveFlags(unsigned short _flags) { flags &= ~_flags; } - void SetFlag(INDICATOR_ENTRY_FLAGS _flag, bool _value) { - if (_value) { - AddFlags(_flag); - } else { - RemoveFlags(_flag); - } - } - void SetFlags(unsigned short _flags) { flags = _flags; } - unsigned short GetFlags() { return flags; } - // Converters. - // State checkers. - bool IsValid() { return CheckFlags(INDI_ENTRY_FLAG_IS_VALID); } - // Serializers. - void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) { - ArrayResize(values, _n1); - for (int i = 0; i < _n1; ++i) { - values[i] = (int)1; - } - } - SerializerNodeType Serialize(Serializer &_s); - template - string ToCSV() { - int _asize = ArraySize(values); - string _result = ""; - for (int i = 0; i < _asize; i++) { - _result += StringFormat("%s%s", (string)values[i].Get(), i < _asize ? "," : ""); - } - return _result; - } - template - string ToString() { - return ToCSV(); - } -}; - /* 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. - unsigned int max_modes; // Max supported indicator modes (values per entry). - unsigned int max_params; // Max supported input params. - ChartTf tf; // Chart's timeframe. - ENUM_INDICATOR_TYPE itype; // Indicator type (e.g. INDI_RSI). - ENUM_IDATA_SOURCE_TYPE idstype; // Indicator's data source type (e.g. IDATA_BUILTIN, IDATA_ICUSTOM). - ENUM_IDATA_VALUE_RANGE idvrange; // Indicator's range value data type. - // ENUM_IDATA_VALUE_TYPE idvtype; // Indicator's data value type (e.g. TDBL1, TDBL2, TINT1). - ENUM_DATATYPE dtype; // Type of basic data to store values (DTYPE_DOUBLE, DTYPE_INT). + 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_params; // Max supported input params. + ChartTf tf; // Chart's timeframe. + ENUM_INDICATOR_TYPE itype; // Indicator type (e.g. INDI_RSI). color indi_color; // Indicator color. - 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. ARRAY(DataParamEntry, input_params); // Indicator input params. bool is_draw; // Draw active. int draw_window; // Drawing window. @@ -425,19 +64,16 @@ struct IndicatorParams { public: /* Special methods */ // Constructor. - IndicatorParams(ENUM_INDICATOR_TYPE _itype = INDI_NONE, unsigned int _max_modes = 1, - ENUM_DATATYPE _dtype = TYPE_DOUBLE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, - ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, string _name = "") + IndicatorParams(ENUM_INDICATOR_TYPE _itype = INDI_NONE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _name = "") : custom_indi_name(""), - dtype(_dtype), name(_name), shift(0), - max_modes(_max_modes), - max_buffers(10), - idstype(_idstype), - idvrange(IDATA_RANGE_UNKNOWN), - indi_data_source_id(-1), - indi_data_source_mode(0), + // max_modes(_max_modes), + // max_buffers(10), + // idstype(_idstype), + // idvrange(IDATA_RANGE_UNKNOWN), + // indi_data_source_id(-1), + // indi_data_source_mode(-1), itype(_itype), is_draw(false), indi_color(clrNONE), @@ -445,16 +81,16 @@ struct IndicatorParams { tf(_tf) { Init(); }; - IndicatorParams(string _name, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) + IndicatorParams(string _name) : custom_indi_name(""), name(_name), shift(0), - max_modes(1), - max_buffers(10), - idstype(_idstype), - idvrange(IDATA_RANGE_UNKNOWN), - indi_data_source_id(-1), - indi_data_source_mode(0), + // max_modes(1), + // max_buffers(10), + // idstype(_idstype), + // idvrange(IDATA_RANGE_UNKNOWN), + // indi_data_source_id(-1), + // indi_data_source_mode(-1), is_draw(false), indi_color(clrNONE), draw_window(0) { @@ -470,15 +106,10 @@ struct IndicatorParams { void Init() {} /* Getters */ 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_INDICATOR_TYPE GetIndicatorType() { return itype; } ENUM_TIMEFRAMES GetTf() const { return tf.GetTf(); } template T GetInputParam(int _index, T _default) const { @@ -507,10 +138,6 @@ struct IndicatorParams { } /* Setters */ void SetCustomIndicatorName(string _name) { custom_indi_name = _name; } - void SetDataSourceMode(int _mode) { indi_data_source_mode = _mode; } - void SetDataSourceType(ENUM_IDATA_SOURCE_TYPE _idstype) { idstype = _idstype; } - void SetDataValueRange(ENUM_IDATA_VALUE_RANGE _idvrange) { idvrange = _idvrange; } - void SetDataValueType(ENUM_DATATYPE _dtype) { dtype = _dtype; } void SetDraw(bool _draw = true, int _window = 0) { is_draw = _draw; draw_window = _window; @@ -521,11 +148,6 @@ struct IndicatorParams { draw_window = _window; } void SetIndicatorColor(color _clr) { indi_color = _clr; } - void SetDataSource(int _id, int _input_mode = -1) { - indi_data_source_id = _id; - indi_data_source_mode = _input_mode; - idstype = IDATA_INDICATOR; - } void SetIndicatorType(ENUM_INDICATOR_TYPE _itype) { itype = _itype; } void SetInputParams(ARRAY_REF(DataParamEntry, _params)) { int _asize = ArraySize(_params); @@ -534,14 +156,12 @@ struct IndicatorParams { input_params[i] = _params[i]; } } - void SetMaxModes(int _value) { max_modes = _value; } void SetMaxParams(int _value) { max_params = _value; ArrayResize(input_params, max_params); } void SetName(string _name) { name = _name; }; void SetShift(int _shift) { shift = _shift; } - void SetSize(int _size) { max_buffers = _size; }; void SetTf(ENUM_TIMEFRAMES _tf) { tf.SetTf(_tf); } // Serializers. // SERIALIZER_EMPTY_STUB; @@ -551,14 +171,16 @@ struct IndicatorParams { /* Structure for indicator state. */ struct IndicatorState { + public: // @todo: Change it to protected. + int handle; // Indicator handle (MQL5 only). + bool is_changed; // Set when params has been recently changed. + bool is_ready; // Set when indicator is ready (has valid values). + public: enum ENUM_INDICATOR_STATE_PROP { INDICATOR_STATE_PROP_HANDLE, INDICATOR_STATE_PROP_IS_CHANGED, INDICATOR_STATE_PROP_IS_READY, }; - int handle; // Indicator handle (MQL5 only). - bool is_changed; // Set when params has been recently changed. - bool is_ready; // Set when indicator is ready (has valid values). // Constructor. IndicatorState() : handle(INVALID_HANDLE), is_changed(true), is_ready(false) {} // Getters. diff --git a/Indicator.struct.serialize.h b/Indicator.struct.serialize.h index 98e262c60..e9a68a534 100644 --- a/Indicator.struct.serialize.h +++ b/Indicator.struct.serialize.h @@ -30,81 +30,16 @@ // Forward class declaration. class Serializer; -/* Method to serialize IndicatorDataEntry structure. */ -SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { - int _asize = ArraySize(values); - _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? - - switch (values[i].GetDataType()) { - case TYPE_DOUBLE: - _s.Pass(THIS_REF, (string)i, values[i].value.vdbl, - SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); - break; - case TYPE_FLOAT: - _s.Pass(THIS_REF, (string)i, values[i].value.vflt, - SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); - break; - case TYPE_INT: - case TYPE_UINT: - if (CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) { - // Split for each bit and pass 0 or 1. - for (int j = 0; j < sizeof(int) * 8; ++j) { - int _value = (values[i].value.vint & (1 << j)) != 0; - _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); - } - } else { - _s.Pass(THIS_REF, (string)i, values[i].value.vint, - SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); - } - break; - case TYPE_LONG: - case TYPE_ULONG: - if (CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) { - // Split for each bit and pass 0 or 1. - /* @fixme: j, j already defined. - for (int j = 0; j < sizeof(int) * 8; ++j) { - int _value = (values[i].vlong & (1 << j)) != 0; - _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); - } - */ - SetUserError(ERR_INVALID_PARAMETER); - } else { - _s.Pass(THIS_REF, (string)i, values[i].value.vlong, - SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); - } - break; - default: - SetUserError(ERR_INVALID_PARAMETER); - break; - } - } - return SerializerNodeObject; -} - -/* Method to serialize IndicatorDataEntry's IndicatorDataEntryValue union. */ -SerializerNodeType IndicatorDataEntryValue::Serialize(Serializer &_s) { - _s.Pass(THIS_REF, "flags", flags); - _s.Pass(THIS_REF, "vdbl", value.vdbl); - _s.Pass(THIS_REF, "vflt", value.vflt); - _s.Pass(THIS_REF, "vint", value.vint); - _s.Pass(THIS_REF, "vlong", value.vlong); - return SerializerNodeObject; -}; - /* Method to serialize IndicatorParams structure. */ SerializerNodeType IndicatorParams::Serialize(Serializer &s) { s.Pass(THIS_REF, "name", name); s.Pass(THIS_REF, "shift", shift); - s.Pass(THIS_REF, "max_modes", max_modes); - s.Pass(THIS_REF, "max_buffers", max_buffers); + // s.Pass(THIS_REF, "max_modes", max_modes); + // s.Pass(THIS_REF, "max_buffers", max_buffers); s.PassEnum(THIS_REF, "itype", itype); - s.PassEnum(THIS_REF, "idstype", idstype); - s.PassEnum(THIS_REF, "dtype", dtype); + // s.PassEnum(THIS_REF, "idstype", idstype); + // s.PassEnum(THIS_REF, "dtype", dtype); + // 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); diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h new file mode 100644 index 000000000..b5036d67e --- /dev/null +++ b/Indicator/IndicatorCandle.h @@ -0,0 +1,267 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Ignore processing of this file if already included. +#ifndef INDICATOR_CANDLE_H +#define INDICATOR_CANDLE_H + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Buffer/BufferCandle.h" +#include "../Candle.struct.h" +#include "../Indicator.mqh" + +// Indicator modes. +enum ENUM_INDI_CANDLE_MODE { + INDI_CANDLE_MODE_PRICE_OPEN, + INDI_CANDLE_MODE_PRICE_HIGH, + INDI_CANDLE_MODE_PRICE_LOW, + INDI_CANDLE_MODE_PRICE_CLOSE, + INDI_CANDLE_MODE_SPREAD, + INDI_CANDLE_MODE_TICK_VOLUME, + INDI_CANDLE_MODE_VOLUME, + FINAL_INDI_CANDLE_MODE_ENTRY, +}; + +/** + * Class to deal with candle indicators. + */ +template +class IndicatorCandle : public Indicator { + protected: + BufferCandle icdata; + + protected: + /* Protected methods */ + + /** + * Initialize class. + * + * Called on constructor. + */ + void Init() { + // Along with indexing by shift, we can also index via timestamp! + flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; + icdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); + icdata.SetOverflowListener(IndicatorCandleOverflowListener, 10); + } + + public: + /* Special methods */ + + /** + * Class constructor. + */ + IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, + int _indi_mode = 0) + : Indicator(_icparams, _idparams, _indi_src, _indi_mode) { + Init(); + } + IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, + string _name = "") + : Indicator(_itype, _tf, _shift, _name) { + Init(); + } + + /* Virtual method implementations */ + + /** + * Returns the indicator's data entry. + * + * @see: IndicatorDataEntry. + * + * @return + * Returns IndicatorDataEntry struct filled with indicator values. + */ + IndicatorDataEntry GetEntry(int _index = -1) override { + ResetLastError(); + unsigned int _ishift = _index >= 0 ? _index : iparams.GetShift(); + long _candle_time = CalcCandleTimestamp(GetBarTime(_ishift)); + long _curr_candle_time; + CandleOCTOHLC _candle; + + // Trying current and older shifts. + if (icdata.Size() > 0) { + int i = 0; + while (true) { + _curr_candle_time = CalcCandleTimestamp(GetBarTime(i++)); + + if (_curr_candle_time < icdata.GetMin()) { + // There is no older entries. + break; + } + + _candle = icdata.GetByKey(_curr_candle_time); + + if (_candle.IsValid()) { + break; + } + } + } + + if (!_candle.IsValid()) { + // Giving up. + DebugBreak(); + Print(GetFullName(), ": Missing candle after thorough search at shift ", _index, " (", TimeToString(_candle_time), + "). Lowest timestamp in history is ", icdata.GetMin()); + } + + return CandleToEntry(_candle_time, _candle); + } + + /** + * Function should return true if resize can be made, or false to overwrite current slot. + */ + static bool IndicatorCandleOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { + switch (_reason) { + case DICT_OVERFLOW_REASON_FULL: + // We allow resize if dictionary size is less than 86400 slots. + return _size < 86400; + case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: + default: + // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. + break; + } + return false; + } + + /** + * Sends historic entries to listening indicators. May be overriden. + */ + void EmitHistory() override { + for (DictStructIterator> iter(icdata.Begin()); iter.IsValid(); ++iter) { + IndicatorDataEntry _entry = CandleToEntry(iter.Key(), iter.Value()); + EmitEntry(_entry); + } + } + + /** + * Converts candle into indicator's data entry. + */ + IndicatorDataEntry CandleToEntry(long _timestamp, CandleOCTOHLC& _candle) { + IndicatorDataEntry _entry(4); + _entry.timestamp = _timestamp; + _entry.values[0] = _candle.open; + _entry.values[1] = _candle.high; + _entry.values[2] = _candle.low; + _entry.values[3] = _candle.close; + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, _candle.IsValid()); + return _entry; + } + + /** + * Adds tick's price to the matching candle and updates its OHLC values. + */ + void UpdateCandle(long _tick_timestamp, double _price) { + long _candle_timestamp = CalcCandleTimestamp(_tick_timestamp); + +#ifdef __debug_verbose__ + Print("Updating candle for ", GetFullName(), " at candle ", TimeToString(_candle_timestamp), " from tick at ", + TimeToString(_tick_timestamp)); +#endif + + CandleOCTOHLC _candle(_price, _price, _price, _price, _tick_timestamp, _tick_timestamp); + if (icdata.KeyExists(_candle_timestamp)) { + // Candle already exists. + _candle = icdata.GetByKey(_candle_timestamp); + _candle.Update(_tick_timestamp, _price); + } + + icdata.Add(_candle, _candle_timestamp); + } + + /** + * Calculates candle's timestamp from tick's timestamp. + */ + long CalcCandleTimestamp(long _tick_timestamp) { + return _tick_timestamp - _tick_timestamp % (iparams.GetSecsPerCandle()); + } + + /** + * Called when data source emits new entry (historic or future one). + */ + void OnDataSourceEntry(IndicatorDataEntry& entry) override { + // Updating candle from bid price. + UpdateCandle(entry.timestamp, entry[1]); + }; + + /** + * Returns value storage of given kind. + */ + IValueStorage* GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + switch (_type) { + case INDI_VS_TYPE_PRICE_OPEN: + return GetValueStorage(INDI_CANDLE_MODE_PRICE_OPEN); + case INDI_VS_TYPE_PRICE_HIGH: + return GetValueStorage(INDI_CANDLE_MODE_PRICE_HIGH); + case INDI_VS_TYPE_PRICE_LOW: + return GetValueStorage(INDI_CANDLE_MODE_PRICE_LOW); + case INDI_VS_TYPE_PRICE_CLOSE: + return GetValueStorage(INDI_CANDLE_MODE_PRICE_CLOSE); + case INDI_VS_TYPE_SPREAD: + return GetValueStorage(INDI_CANDLE_MODE_SPREAD); + case INDI_VS_TYPE_TICK_VOLUME: + return GetValueStorage(INDI_CANDLE_MODE_TICK_VOLUME); + case INDI_VS_TYPE_VOLUME: + return GetValueStorage(INDI_CANDLE_MODE_VOLUME); + default: + // Trying in parent class. + return Indicator::GetSpecificValueStorage(_type); + } + } + + /** + * Checks whether indicator support given value storage type. + */ + bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { + switch (_type) { + case INDI_VS_TYPE_PRICE_OPEN: + case INDI_VS_TYPE_PRICE_HIGH: + case INDI_VS_TYPE_PRICE_LOW: + case INDI_VS_TYPE_PRICE_CLOSE: + case INDI_VS_TYPE_SPREAD: + case INDI_VS_TYPE_TICK_VOLUME: + case INDI_VS_TYPE_VOLUME: + return true; + default: + // Trying in parent class. + return Indicator::HasSpecificValueStorage(_type); + } + } + + string CandlesToString() { + string _result; + for (DictStructIterator> iter(icdata.Begin()); iter.IsValid(); ++iter) { + IndicatorDataEntry _entry = CandleToEntry(iter.Key(), iter.Value()); + _result += IntegerToString(iter.Key()) + ": " + _entry.ToString() + "\n"; + } + return _result; + } + + /* Virtual methods */ +}; + +#endif diff --git a/Indicator/IndicatorCandleSource.h b/Indicator/IndicatorCandleSource.h new file mode 100644 index 000000000..2d721fb8a --- /dev/null +++ b/Indicator/IndicatorCandleSource.h @@ -0,0 +1,108 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Indicator.mqh" +#include "tests/classes/IndicatorTfDummy.h" +#include "tests/classes/IndicatorTickReal.h" + +/** + * Indicator to be used with IndicatorCandle as a data source. + */ +template +class IndicatorCandleSource : public Indicator { + public: + /** + * Class constructor. + */ + IndicatorCandleSource(const TS& _iparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + : Indicator(_iparams, _indi_src, _indi_mode) {} + IndicatorCandleSource(const TS& _iparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(_iparams, _tf) {} + IndicatorCandleSource(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, + string _name = "") + : Indicator(_itype, _tf, _shift, _name) {} + + /** + * Class deconstructor. + */ + ~IndicatorCandleSource() {} + + /** + * Sets indicator data source. + */ + void SetDataSource(IndicatorBase* _indi, int _input_mode = -1) override { + if (_indi == NULL) { + // Just deselecting data source. + Indicator::SetDataSource(_indi, _input_mode); + return; + } + + // We can only use data sources which supports all possible modes from IndicatorCandle. + bool _result = true; + + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_SPREAD); + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME); + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_VOLUME); + + if (!_result) { + Alert("Passed indicator ", _indi.GetFullName(), " does not define all required specific data storages!"); + DebugBreak(); + } + + Indicator::SetDataSource(_indi, _input_mode); + } + + /** + * Called when user tries to set given data source. Could be used to check if indicator implements all required value + * storages. + */ + bool OnValidateDataSource(IndicatorBase* _ds, string& _reason) override { + // @todo Make use of this method. + return true; + } + + /** + * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on + * some data source. + */ + IndicatorBase* OnDataSourceRequest() override { + // Defaulting to real platform ticks. + IndicatorBase* _indi_tick = + new IndicatorTickReal(GetSymbol(), GetTf(), "Ticker for Tf on IndicatorCandleSource-based indicator"); + + // Tf will work on real platform ticks. + IndicatorBase* _indi_tf = new IndicatorTfDummy(GetTf()); + _indi_tf.SetDataSource(_indi_tick); + + // Indicator will work on Tf, which will receive real platform ticks. + return _indi_tf; + } +}; diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h new file mode 100644 index 000000000..fb0f714b9 --- /dev/null +++ b/Indicator/IndicatorTf.h @@ -0,0 +1,88 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Ignore processing of this file if already included. +#ifndef INDICATOR_TF_H +#define INDICATOR_TF_H + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Chart.struct.tf.h" +#include "IndicatorCandle.h" +#include "IndicatorTf.struct.h" + +/** + * Class to deal with candle indicators. + */ +template +class IndicatorTf : public IndicatorCandle { + protected: + /* Protected methods */ + + /** + * Initialize class. + * + * Called on constructor. + */ + void Init() {} + + public: + /* Special methods */ + + /** + * Class constructor with timeframe enum. + */ + IndicatorTf(uint _spc) { + iparams.SetSecsPerCandle(_spc); + Init(); + } + + /** + * Class constructor with timeframe enum. + */ + IndicatorTf(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + iparams.SetSecsPerCandle(ChartTf::TfToSeconds(_tf)); + Init(); + } + + /** + * Class constructor with timeframe index. + */ + IndicatorTf(ENUM_TIMEFRAMES_INDEX _tfi = 0) { + iparams.SetSecsPerCandle(ChartTf::TfToSeconds(ChartTf::IndexToTf(_tfi))); + Init(); + } + + /** + * Class constructor with parameters. + */ + IndicatorTf(TFP& _icparams, const IndicatorDataParams& _idparams) + : IndicatorCandle(_icparams, _idparams) { + Init(); + } +}; + +#endif diff --git a/Indicator/IndicatorTf.struct.h b/Indicator/IndicatorTf.struct.h new file mode 100644 index 000000000..5feae87e4 --- /dev/null +++ b/Indicator/IndicatorTf.struct.h @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes IndicatorTf's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Indicator.struct.h" + +/* Structure for IndicatorTf class parameters. */ +struct IndicatorTfParams : IndicatorParams { + uint spc; // Seconds per candle. + // Struct constructor. + IndicatorTfParams(uint _spc = 60) : spc(_spc) {} + // Getters. + uint GetSecsPerCandle() { return spc; } + // Setters. + void SetSecsPerCandle(uint _spc) { spc = _spc; } + // Copy constructor. + IndicatorTfParams(const IndicatorTfParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + THIS_REF = _params; + if (_tf != PERIOD_CURRENT) { + tf.SetTf(_tf); + } + } +}; diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h new file mode 100644 index 000000000..afb1075ea --- /dev/null +++ b/Indicator/IndicatorTick.h @@ -0,0 +1,294 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Ignore processing of this file if already included. +#ifndef INDICATOR_TICK_H +#define INDICATOR_TICK_H + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Buffer/BufferTick.h" +#include "../Indicator.mqh" + +// Indicator modes. +enum ENUM_INDI_TICK_MODE { + INDI_TICK_MODE_PRICE_ASK, + INDI_TICK_MODE_PRICE_BID, + FINAL_INDI_TICK_MODE_ENTRY, +}; + +/** + * Class to deal with tick indicators. + */ +template +class IndicatorTick : public Indicator { + protected: + BufferTick itdata; + TS itparams; + + protected: + /* Protected methods */ + + /** + * Initialize class. + * + * Called on constructor. + */ + void Init() { + // We can't index by shift. + flags &= ~INDI_FLAG_INDEXABLE_BY_SHIFT; + // We can only index via timestamp. + flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; + + itdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); + itdata.SetOverflowListener(IndicatorTickOverflowListener, 10); + // Ask and Bid price. + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); + } + + public: + /* Special methods */ + + /** + * Class constructor. + */ + IndicatorTick(const TS& _itparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, + int _indi_mode = 0) + : Indicator(_itparams, _idparams, _indi_src, _indi_mode) { + itparams = _itparams; + if (_indi_src != NULL) { + SetDataSource(_indi_src, _indi_mode); + } + Init(); + } + IndicatorTick(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, + string _name = "") + : Indicator(_itype, _tf, _shift, _name) { + Init(); + } + + /** + * Returns value storage of given kind. + */ + IValueStorage* GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + switch (_type) { + case INDI_VS_TYPE_PRICE_ASK: + return (IValueStorage*)itdata.GetAskValueStorage(); + case INDI_VS_TYPE_PRICE_BID: + return (IValueStorage*)itdata.GetBidValueStorage(); + default: + // Trying in parent class. + return Indicator::GetSpecificValueStorage(_type); + } + } + + /** + * Checks whether indicator support given value storage type. + */ + virtual bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { + switch (_type) { + case INDI_VS_TYPE_PRICE_ASK: + case INDI_VS_TYPE_PRICE_BID: + return true; + } + + return Indicator::HasSpecificValueStorage(_type); + } + + /** + * Sends historic entries to listening indicators. May be overriden. + */ + void EmitHistory() override { + for (DictStructIterator> iter(itdata.Begin()); iter.IsValid(); ++iter) { + IndicatorDataEntry _entry = TickToEntry(iter.Key(), iter.Value()); + EmitEntry(_entry); + } + } + + /** + * @todo + */ + IndicatorDataEntry TickToEntry(long _timestamp, TickAB& _tick) { + IndicatorDataEntry _entry(2); + _entry.timestamp = _timestamp; + _entry.values[0] = _tick.ask; + _entry.values[1] = _tick.bid; + _entry.SetFlags(INDI_ENTRY_FLAG_IS_VALID); + return _entry; + } + + /** + * Returns the indicator's data entry. + * + * @see: IndicatorDataEntry. + * + * @return + * Returns IndicatorDataEntry struct filled with indicator values. + */ + IndicatorDataEntry GetEntry(int _timestamp = 0) override { + ResetLastError(); + if (itdata.KeyExists(_timestamp)) { + TickAB _tick = itdata.GetByKey(_timestamp); + return TickToEntry(_timestamp, _tick); + } + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); + + // No tick at given timestamp. Returning invalid entry. + IndicatorDataEntry _entry(_max_modes); + GetEntryAlter(_entry, _timestamp); + + for (int i = 0; i < _max_modes; ++i) { + _entry.values[i] = (double)0; + } + + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, false); + return _entry; + } + + /** + * Alters indicator's struct value. + * + * This method allows user to modify the struct entry before it's added to cache. + * This method is called on GetEntry() right after values are set. + */ + virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _timestamp = -1) { + ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE)); + _entry.AddFlags(_entry.GetDataTypeFlags(_dtype)); + }; + + /** + * Returns the indicator's entry value for the given shift and mode. + * + * @see: DataParamEntry. + * + * @return + * Returns DataParamEntry struct filled with a single value. + */ + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + int _ishift = _shift >= 0 ? _shift : itparams.GetShift(); + return GetEntry(_ishift)[_mode]; + } + + /* Setters */ + + /** + * Sets a tick struct with price values. + * + * @see: MqlTick. + */ + void SetTick(MqlTick& _mql_tick, long _timestamp = 0) { + TickAB _tick(_mql_tick); + itdata.Add(_tick, _timestamp); + } + + /** + * Sets indicator data source. + */ + void SetDataSource(IndicatorBase* _indi, int _input_mode = -1) { + indi_src = _indi; + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID), -1); + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE), _input_mode); + } + + /* Virtual methods */ + + /** + * Returns a tick struct with price values. + * + * @see: MqlTick. + * + * @return + * Returns MqlTick struct with prices of the symbol. + */ + virtual MqlTick GetTick(int _timestamp = 0) { + IndicatorDataEntry _entry = GetEntry(_timestamp); + MqlTick _tick; + _tick.time = (datetime)_entry.GetTime(); + _tick.bid = _entry[0]; + _tick.ask = _entry[1]; + return _tick; + } + + /** + * Checks if indicator entry is valid. + * + * @return + * Returns true if entry is valid (has valid values), otherwise false. + */ + virtual bool IsValidEntry(IndicatorDataEntry& _entry) { + bool _result = true; + _result &= _entry.timestamp > 0; + _result &= _entry.GetSize() > 0; + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_REAL)) { + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { + _result &= !_entry.HasValue(DBL_MAX); + _result &= !_entry.HasValue(NULL); + } else { + _result &= !_entry.HasValue(FLT_MAX); + _result &= !_entry.HasValue(NULL); + } + } else { + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED)) { + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { + _result &= !_entry.HasValue(ULONG_MAX); + _result &= !_entry.HasValue(NULL); + } else { + _result &= !_entry.HasValue(UINT_MAX); + _result &= !_entry.HasValue(NULL); + } + } else { + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { + _result &= !_entry.HasValue(LONG_MAX); + _result &= !_entry.HasValue(NULL); + } else { + _result &= !_entry.HasValue(INT_MAX); + _result &= !_entry.HasValue(NULL); + } + } + } + return _result; + } + + /* Callback methods */ + + /** + * Function should return true if resize can be made, or false to overwrite current slot. + */ + static bool IndicatorTickOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { + switch (_reason) { + case DICT_OVERFLOW_REASON_FULL: + // We allow resize if dictionary size is less than 86400 slots. + return _size < 86400; + case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: + default: + // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. + break; + } + return false; + } +}; + +#endif diff --git a/Indicator/IndicatorTickOrCandleSource.h b/Indicator/IndicatorTickOrCandleSource.h new file mode 100644 index 000000000..491766979 --- /dev/null +++ b/Indicator/IndicatorTickOrCandleSource.h @@ -0,0 +1,102 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Indicator.mqh" +#include "tests/classes/IndicatorTfDummy.h" +#include "tests/classes/IndicatorTickReal.h" + +/** + * Indicator to be used with IndicatorTick or IndicatorCandle as a data source. + * + * In order it to work with + */ +template +class IndicatorTickOrCandleSource : public Indicator { + public: + /** + * Class constructor. + */ + IndicatorTickOrCandleSource(const TS& _iparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, + int _indi_mode = 0) + : Indicator(_iparams, _idparams, _indi_src, _indi_mode) {} + IndicatorTickOrCandleSource(const TS& _iparams, const IndicatorDataParams& _idparams, + ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + : Indicator(_iparams, _idparams, _tf) {} + IndicatorTickOrCandleSource(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, + string _name = "") + : Indicator(_itype, _tf, _shift, _name) {} + + /** + * Class deconstructor. + */ + ~IndicatorTickOrCandleSource() {} + + /** + * Called when user tries to set given data source. Could be used to check if indicator implements all required value + * storages. + */ + bool OnValidateDataSource(IndicatorData* _ds, string& _reason) override { + // @todo Make use of this method. + return true; + } + + /** + * Called when data source emits new entry (historic or future one). + */ + void OnDataSourceEntry(IndicatorDataEntry& entry) override{ + // We do nothing. + }; + + /** + * Creates default, tick based indicator for given applied price. + */ + IndicatorData* DataSourceRequestReturnDefault(int _applied_price) override { + // Returning real candle indicator. Thus way we can use SetAppliedPrice() and select Ask or Bid price. + IndicatorData* _indi; + + switch (_applied_price) { + case PRICE_ASK: + case PRICE_BID: + case PRICE_OPEN: + case PRICE_HIGH: + case PRICE_LOW: + case PRICE_CLOSE: + case PRICE_MEDIAN: + case PRICE_TYPICAL: + case PRICE_WEIGHTED: + // @todo ASK/BID should return Tick indicator. Other APs should return Candle-over-Tick indicator. + _indi = new IndicatorTfDummy(GetTf()); + _indi.SetDataSource(new IndicatorTickReal(GetTf())); + return _indi; + } + + Print("Passed wrong value for applied price for ", GetFullName(), " indicator!"); + DebugBreak(); + return NULL; + } +}; diff --git a/Indicator/IndicatorTickSource.h b/Indicator/IndicatorTickSource.h new file mode 100644 index 000000000..8b47180a5 --- /dev/null +++ b/Indicator/IndicatorTickSource.h @@ -0,0 +1,121 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Indicator.mqh" + +/** + * Indicator to be used with IndicatorTick as a data source. + */ +template +class IndicatorTickSource : public Indicator { + public: + /** + * Class constructor. + */ + IndicatorTickSource(const TS& _iparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, + int _indi_mode = 0) + : Indicator(_iparams, _idparams, _indi_src, _indi_mode) {} + IndicatorTickSource(const TS& _iparams, const IndicatorDataParams& _idparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + : Indicator(_iparams, _idparams, _tf) {} + IndicatorTickSource(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, + string _name = "") + : Indicator(_itype, _tf, _shift, _name) {} + + /** + * Class deconstructor. + */ + ~IndicatorTickSource() {} + + /** + * Sets indicator data source. + */ + void SetDataSource(IndicatorData* _indi, int _input_mode = -1) override { + if (_indi == NULL) { + // Just deselecting data source. + Indicator::SetDataSource(_indi, _input_mode); + return; + } + + // We can only use data sources which supports all possible modes from IndicatorTick. + bool _result = true; + + if (_input_mode == -1) { + // Source mode which acts as an applied price wasn't selected, so we have to ensure that source is a Tick + // indicator. Valid only if implements bid or ask price. + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_BID) || + _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); + } else { + // Applied price selected. We will select source indicator only if it provides price buffer for given applied + // price. + switch (_input_mode) { + case PRICE_OPEN: + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); + break; + case PRICE_HIGH: + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); + break; + case PRICE_LOW: + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); + break; + case PRICE_CLOSE: + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); + break; + case PRICE_MEDIAN: + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_MEDIAN); + break; + case PRICE_TYPICAL: + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_TYPICAL); + break; + case PRICE_WEIGHTED: + _result &= _indi.HasSpecificValueStorage(INDI_VS_TYPE_PRICE_WEIGHTED); + break; + default: + Alert("Invalid input mode ", _input_mode, " for indicator ", _indi.GetFullName(), + ". Must be one one PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED)!"); + DebugBreak(); + } + } + + if (!_result) { + Alert("Passed indicator ", _indi.GetFullName(), + " does not provide required data storage(s)! Mode selected: ", _input_mode); + DebugBreak(); + } + + Indicator::SetDataSource(_indi, _input_mode); + } + + /** + * Called when user tries to set given data source. Could be used to check if indicator implements all required value + * storages. + */ + bool OnValidateDataSource(IndicatorData* _ds, string& _reason) override { + // @todo Make use of this method. + return true; + } +}; diff --git a/Indicator/README.md b/Indicator/README.md new file mode 100644 index 000000000..add1d2685 --- /dev/null +++ b/Indicator/README.md @@ -0,0 +1,54 @@ +# Indicator + +Indicator classes are intended for implementation of technical indicators. + +They can help with storing and accessing values and indicator parameters. + +## `IndicatorBase` + +An abstract class for all type of indicators (a base class). + +## `Indicator` + +An abstract class (subclass of `IndicatorBase`) to implement all type of indicators. + +It implements structure for storing input parameters +and buffer for accessing cached values by a given timestamp. + +## `IndicatorCandle` + +An abstract class (subclass of `IndicatorBase`) to implement candle indicators. + +It aims at managing prices by grouping them into OHLC chart candles. + +## `IndicatorRenko` + +(to be added) + +An abstract class (subclass of `IndicatorCandle`) to implement Renko indicators. + +It aims at managing prices by splitting them based solely on price movements. + +It can accept `IndicatorTick` as a data source. + +## `IndicatorTf` + +An abstract class (subclass of `IndicatorCandle`) +to implement timeframe indicators. + +It aims at storing prices by grouping them based on standardized time intervals +(e.g. M1, M2, M5). + +An instance has information about timeframe. + +Information about symbol can be accessed through the tick indicator. + +It can accept `IndicatorTick` as a data source. + +## `IndicatorTick` + +An abstract class (subclass of `IndicatorBase`) to implement tick indicators. + +It aims at managing bid and ask prices and can be used as data source. + +An instance has information about symbol, but it doesn't have timeframe. diff --git a/Indicator/tests/IndicatorCandle.test.mq4 b/Indicator/tests/IndicatorCandle.test.mq4 new file mode 100644 index 000000000..93a0098bb --- /dev/null +++ b/Indicator/tests/IndicatorCandle.test.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 IndicatorCandle class. + */ + +// Includes. +#include "IndicatorCandle.test.mq5" diff --git a/Indicator/tests/IndicatorCandle.test.mq5 b/Indicator/tests/IndicatorCandle.test.mq5 new file mode 100644 index 000000000..1d3f5c0d5 --- /dev/null +++ b/Indicator/tests/IndicatorCandle.test.mq5 @@ -0,0 +1,37 @@ +//+------------------------------------------------------------------+ +//| 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 IndicatorCandle class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../IndicatorCandle.h" + +/** + * Implements OnInit(). + */ +int OnInit() { + // @todo + return (INIT_SUCCEEDED); +} diff --git a/Indicator/tests/IndicatorTf.test.mq4 b/Indicator/tests/IndicatorTf.test.mq4 new file mode 100644 index 000000000..360408073 --- /dev/null +++ b/Indicator/tests/IndicatorTf.test.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 IndicatorTf class. + */ + +// Includes. +#include "IndicatorTf.test.mq5" diff --git a/Indicator/tests/IndicatorTf.test.mq5 b/Indicator/tests/IndicatorTf.test.mq5 new file mode 100644 index 000000000..d09b77905 --- /dev/null +++ b/Indicator/tests/IndicatorTf.test.mq5 @@ -0,0 +1,112 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of IndicatorTf class. + * + * Idea is to check if ticks from IndicatorTick will be properly grouped by given timespan/timeframe. + */ + +// Includes. +#include "../../Indicators/Indi_AMA.mqh" +#include "../../Test.mqh" +#include "../../Util.h" +#include "../IndicatorTf.h" +#include "../IndicatorTick.h" +#include "classes/IndicatorTfDummy.h" +#include "classes/IndicatorTickReal.h" +#include "classes/Indicators.h" + +Indicators indicators; +Ref indi_tick; +Ref indi_tf; +Ref indi_tf_orig_sim; +Ref indi_ama; +Ref indi_ama_orig; +Ref indi_ama_orig_sim; + +/** + * Implements OnInit(). + */ +int OnInit() { + indicators.Add(indi_tick = new IndicatorTickReal(PERIOD_CURRENT)); + + // 1-second candles. + // indicators.Add(indi_tf = new IndicatorTfDummy(1)); + + // 1:1 candles from platform using current timeframe. + indicators.Add(indi_tf_orig_sim = new IndicatorTfDummy(ChartTf::TfToSeconds(PERIOD_CURRENT))); + + // 1-second candles. + // indicators.Add(indi_ama = new Indi_AMA()); + + IndiAMAParams _ama_params; + _ama_params.applied_price = PRICE_OPEN; + + // AMA on platform candles. + indicators.Add(indi_ama_orig_sim = new Indi_AMA(_ama_params)); + + // Original built-in or OnCalculate()-based AMA indicator on platform OHLCs. + indicators.Add(indi_ama_orig = new Indi_AMA(_ama_params)); + + // Candles will be initialized from tick's history. + // indi_tf.Ptr().SetDataSource(indi_tick.Ptr()); + indi_tf_orig_sim.Ptr().SetDataSource(indi_tick.Ptr()); + + // AMA will work on the candle indicator. + // indi_ama.Ptr().SetDataSource(indi_tf.Ptr()); + + // AMA will work on the simulation of real candles. + indi_ama_orig_sim.Ptr().SetDataSource(indi_tf_orig_sim.Ptr()); + + // Checking if there are candles for last 100 ticks. + // Print(indi_tf.Ptr().GetName(), "'s historic candles (from 100 ticks):"); + // Print(indi_tf.Ptr().CandlesToString()); + return (INIT_SUCCEEDED); +} + +/** + * Implements OnTick(). + */ +void OnTick() { + string o = DoubleToStr(iOpen(_Symbol, PERIOD_CURRENT, 0), 5); + string h = DoubleToStr(iHigh(_Symbol, PERIOD_CURRENT, 0), 5); + string l = DoubleToStr(iLow(_Symbol, PERIOD_CURRENT, 0), 5); + string c = DoubleToStr(iClose(_Symbol, PERIOD_CURRENT, 0), 5); + string time = TimeToString(iTime(_Symbol, PERIOD_CURRENT, 0)); + + Util::Print("Tick: " + IntegerToString((long)iTime(_Symbol, PERIOD_CURRENT, 0)) + " (" + time + "), real = " + o + + ", " + h + ", " + l + ", " + c); + + indicators.Tick(); + + Util::Print(indicators.ToString(0)); +} + +/** + * Implements OnDeinit(). + */ +void OnDeinit(const int reason) { + // Printing all grouped candles. + Print(indi_tf_orig_sim.Ptr().GetName(), "'s all candles:"); + Print(indi_tf_orig_sim.Ptr().CandlesToString()); +} diff --git a/Indicator/tests/IndicatorTick.test.mq4 b/Indicator/tests/IndicatorTick.test.mq4 new file mode 100644 index 000000000..430e9d0e3 --- /dev/null +++ b/Indicator/tests/IndicatorTick.test.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 IndicatorTick class. + */ + +// Includes. +#include "IndicatorTick.test.mq5" diff --git a/Indicator/tests/IndicatorTick.test.mq5 b/Indicator/tests/IndicatorTick.test.mq5 new file mode 100644 index 000000000..67400dc41 --- /dev/null +++ b/Indicator/tests/IndicatorTick.test.mq5 @@ -0,0 +1,46 @@ +//+------------------------------------------------------------------+ +//| 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 IndicatorTick class. + */ + +// Includes. +#include "../../Test.mqh" +#include "classes/IndicatorTickDummy.h" + +/** + * Implements OnInit(). + */ +int OnInit() { + IndicatorTickDummy _indi_tick(PERIOD_CURRENT); + long _time = 1; + for (double _price = 0.1; _price <= 2.0; _price += 0.1) { + MqlTick _tick; + _tick.time = (datetime)_time++; + _tick.ask = _price; + _tick.bid = _price; + _indi_tick.SetTick(_tick, _tick.time); + } + // Print(_indi_tick.ToString()); + return (INIT_SUCCEEDED); +} diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h new file mode 100644 index 000000000..6680f07e0 --- /dev/null +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -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 + * Dummy candle-based indicator. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../../IndicatorTf.h" + +// Params for dummy candle-based indicator. +struct IndicatorTfDummyParams : IndicatorTfParams { + IndicatorTfDummyParams(uint _spc = 60) : IndicatorTfParams(_spc) {} +}; + +/** + * Dummy candle-based indicator. + */ +class IndicatorTfDummy : public IndicatorTf { + public: + IndicatorTfDummy(uint _spc) : IndicatorTf(_spc) {} + IndicatorTfDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTf(_tf) {} + IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi = 0) : IndicatorTf(_tfi) {} + + string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } + + void OnDataSourceEntry(IndicatorDataEntry& entry) override { + // When overriding OnDataSourceEntry() we have to remember to call parent + // method, because IndicatorCandle also need to invoke it in order to + // create/update matching candle. + IndicatorTf::OnDataSourceEntry(entry); + +#ifdef __debug_indicator__ + Print(GetFullName(), " got new tick at ", entry.timestamp, + " (" + TimeToString(entry.timestamp) + "): ", entry.ToString()); +#endif + } +}; diff --git a/Indicator/tests/classes/IndicatorTickDummy.h b/Indicator/tests/classes/IndicatorTickDummy.h new file mode 100644 index 000000000..dcc473b88 --- /dev/null +++ b/Indicator/tests/classes/IndicatorTickDummy.h @@ -0,0 +1,73 @@ +//+------------------------------------------------------------------+ +//| 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 + * Dummy candle-based indicator. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../../../Tick.struct.h" +#include "../../IndicatorTick.h" + +// Params for dummy tick-based indicator. +struct IndicatorTickDummyParams : IndicatorParams { + IndicatorTickDummyParams() : IndicatorParams(INDI_TICK) {} +}; + +// Dummy tick-based indicator. +class IndicatorTickDummy : public IndicatorTick { + public: + IndicatorTickDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "") + : IndicatorTick(INDI_TICK, _tf, _shift, _name) { + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); + } + + string GetName() override { return "IndicatorTickDummy"; } + + void OnBecomeDataSourceFor(IndicatorData* _base_indi) override { + // Feeding base indicator with historic entries of this indicator. + Print(GetName(), " became a data source for ", _base_indi.GetName()); + + TickAB _t1(1.0f, 1.01f); + TickAB _t2(1.5f, 1.51f); + TickAB _t3(2.0f, 2.01f); + TickAB _t4(3.0f, 3.01f); + TickAB _t5(4.0f, 4.01f); + TickAB _t6(4.1f, 4.11f); + TickAB _t7(4.2f, 4.21f); + TickAB _t8(4.8f, 4.81f); + + EmitEntry(TickToEntry(1000, _t1)); + EmitEntry(TickToEntry(1500, _t2)); + EmitEntry(TickToEntry(2000, _t3)); + EmitEntry(TickToEntry(3000, _t4)); + EmitEntry(TickToEntry(4000, _t5)); + EmitEntry(TickToEntry(4100, _t6)); + EmitEntry(TickToEntry(4200, _t7)); + EmitEntry(TickToEntry(4800, _t8)); + }; +}; diff --git a/Indicator/tests/classes/IndicatorTickReal.h b/Indicator/tests/classes/IndicatorTickReal.h new file mode 100644 index 000000000..fc20d98c5 --- /dev/null +++ b/Indicator/tests/classes/IndicatorTickReal.h @@ -0,0 +1,115 @@ +//+------------------------------------------------------------------+ +//| 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 + * Real tick-based indicator. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../../../Chart.struct.static.h" +#include "../../IndicatorTick.h" + +// Params for real tick-based indicator. +struct IndicatorTickRealParams : IndicatorParams { + IndicatorTickRealParams() : IndicatorParams(INDI_TICK) {} +}; + +// Real tick-based indicator. +class IndicatorTickReal : public IndicatorTick { + public: + IndicatorTickReal(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "") + : IndicatorTick(INDI_TICK, _tf, _shift, _name) { + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 3); + } + + string GetName() override { return "IndicatorTickReal"; } + + void OnBecomeDataSourceFor(IndicatorData* _indi) override { + // Feeding base indicator with historic entries of this indicator. +#ifdef __debug__ + Print(GetFullName(), " became a data source for ", _indi.GetFullName()); +#endif + +#ifndef __MQL4__ + int _ticks_to_emit = 1000; + +#ifdef __debug_verbose__ + Print(_indi.GetFullName(), " will be now filled with ", _ticks_to_emit, + " historical entries generated by " + GetFullName()); +#endif + + static MqlTick _ticks[]; + ArrayResize(_ticks, 0); + + int _tries = 10; + int _num_copied = -1; + + while (_tries-- > 0) { + _num_copied = CopyTicks(GetSymbol(), _ticks, COPY_TICKS_ALL); + + if (_num_copied == -1) { + Sleep(1000); + } else { + break; + } + } + + // Clearing possible error 4004. + ResetLastError(); + + for (int i = 0; i < _num_copied; ++i) { + TickAB _tick(_ticks[i].ask, _ticks[i].bid); + // We can't call EmitEntry() here, as tick would go to multiple sources at the same time! + _indi.OnDataSourceEntry(TickToEntry(_ticks[i].time, _tick)); + } +#endif + } + + void OnTick() override { +#ifdef __MQL4__ + // Refreshes Ask/Bid constants. + RefreshRates(); + double _ask = Ask; + double _bid = Bid; + long _time = TimeCurrent(); +#else + static MqlTick _ticks[]; + // Copying only the last tick. + int _num_copied = CopyTicks(GetSymbol(), _ticks, COPY_TICKS_INFO, 0, 1); + +#ifdef __debug_verbose__ + Print("TickReal: ", TimeToString(_ticks[0].time), " = ", _ticks[0].bid); +#endif + + double _ask = _ticks[0].ask; + double _bid = _ticks[0].bid; + long _time = _ticks[0].time; +#endif + TickAB _tick(_ask, _bid); + EmitEntry(TickToEntry(_time, _tick)); + } +}; diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h new file mode 100644 index 000000000..1d1da2066 --- /dev/null +++ b/Indicator/tests/classes/Indicators.h @@ -0,0 +1,73 @@ +//+------------------------------------------------------------------+ +//| 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 + * Helper class to store all indicators and call OnTick() on them. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../../../IndicatorData.mqh" +#include "../../../Refs.mqh" + +/** + * Helper class to store all indicators and call OnTick() on them. + */ +class Indicators { + Ref _indis[]; + + public: + void Add(IndicatorBase* _indi) { + Ref _ref = _indi; + ArrayPushObject(_indis, _ref); + } + + void Remove(IndicatorData* _indi) { + Ref _ref = _indi; + Util::ArrayRemoveFirst(_indis, _ref); + } + + /** + * Executes OnTick() on every added indicator. + */ + void Tick() { + for (int i = 0; i < ArraySize(_indis); ++i) { + _indis[i].Ptr().OnTick(); + } + } + + /** + * Prints indicators' values at the given shift. + */ + string ToString(int _shift = 0) { + string _result; + for (int i = 0; i < ArraySize(_indis); ++i) { + IndicatorDataEntry _entry = _indis[i].Ptr().GetEntry(_shift); + _result += _indis[i].Ptr().GetFullName() + " = " + _entry.ToString() + "\n"; + } + return _result; + } +}; diff --git a/IndicatorBase.h b/IndicatorBase.h index d883e49db..94b662314 100644 --- a/IndicatorBase.h +++ b/IndicatorBase.h @@ -44,71 +44,24 @@ class Chart; #include "Indicator.struct.cache.h" #include "Indicator.struct.h" #include "Indicator.struct.serialize.h" -#include "Indicator.struct.signal.h" #include "Object.mqh" #include "Refs.mqh" #include "Serializer.mqh" #include "SerializerCsv.mqh" #include "SerializerJson.mqh" -#include "Storage/ValueStorage.h" -#include "Storage/ValueStorage.indicator.h" -#include "Storage/ValueStorage.native.h" #include "Util.h" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compatibility). -bool IndicatorBuffers(int _count) { return Indicator::SetIndicatorBuffers(_count); } -int IndicatorCounted(int _value = 0) { - static int prev_calculated = 0; - // https://docs.mql4.com/customind/indicatorcounted - prev_calculated = _value > 0 ? _value : prev_calculated; - return prev_calculated; -} -#endif - -#ifdef __MQL5__ -// Defines global functions (for MQL5 forward compatibility). -template -double iCustom5(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) { - ResetLastError(); - static Dict _handlers; - string _key = Util::MakeKey(_symbol, (string)_tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j); - int _handle = _handlers.GetByKey(_key); - ICUSTOM_DEF(_handlers.Set(_key, _handle), - COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i COMMA _j); -} -template -double iCustom5(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, L _l, M _m, int _mode, int _shift) { - ResetLastError(); - static Dict _handlers; - string _key = Util::MakeKey(_symbol, (string)_tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j); - int _handle = _handlers.GetByKey(_key); - ICUSTOM_DEF(_handlers.Set(_key, _handle), COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h - COMMA _i COMMA _j COMMA _k COMMA _l COMMA _m); -} -#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. + int calc_start_bar; // Index of the first valid bar (from 0). bool indicator_builtin; - ARRAY(ValueStorage*, value_storages); - Ref indi_src; // // Indicator used as data source. - int indi_src_mode; // Mode of source indicator - IndicatorCalculateCache cache; + long last_tick_time; // Time of the last Tick() call. + int flags; // Flags such as INDI_FLAG_INDEXABLE_BY_SHIFT. public: /* Indicator enumerations */ @@ -125,184 +78,30 @@ class IndicatorBase : public Chart { /* Special methods */ - /** - * Class constructor. - */ - IndicatorBase() : indi_src(NULL) { - calc_start_bar = 0; - is_fed = false; - } - - /** - * Class constructor. - */ - IndicatorBase(ChartParams& _cparams) : indi_src(NULL), Chart(_cparams) { - calc_start_bar = 0; - is_fed = false; - } - /** * Class constructor. */ IndicatorBase(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _symbol = NULL) : Chart(_tf, _symbol) { + // By default, indicator is indexable only by shift and data source must be also indexable by shift. + flags = INDI_FLAG_INDEXABLE_BY_SHIFT | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT; calc_start_bar = 0; - is_fed = false; - indi_src = NULL; + last_tick_time = 0; } /** * Class constructor. */ IndicatorBase(ENUM_TIMEFRAMES_INDEX _tfi, string _symbol = NULL) : Chart(_tfi, _symbol) { + // By default, indicator is indexable only by shift and data source must be also indexable by shift. + flags = INDI_FLAG_INDEXABLE_BY_SHIFT | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT; calc_start_bar = 0; - is_fed = false; - indi_src = NULL; + last_tick_time = 0; } /** * 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 - } - - 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, L _l, M _m, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _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 - COMMA _l COMMA _m); -#endif - } + virtual ~IndicatorBase() { ReleaseHandle(); } /* Buffer methods */ @@ -379,94 +178,12 @@ class IndicatorBase : public Chart { } */ - /** - * 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.Ptr(); } - - /* 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. + * Returns indicator's flags. */ - IndicatorCalculateCache* GetCache() { return &cache; } + int GetFlags() { return flags; } /** * Gets an indicator's chart parameter value. @@ -480,7 +197,7 @@ class IndicatorBase : public Chart { * Gets an indicator's state property value. */ template - T Get(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop) { + T Get(STRUCT_ENUM_INDICATOR_STATE_PROP _prop) { return istate.Get(_prop); } @@ -489,171 +206,23 @@ class IndicatorBase : public Chart { */ 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; } + virtual bool HasDataSource(bool _try_initialize = false) { 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. */ @@ -662,7 +231,7 @@ class IndicatorBase : public Chart { /** * Get name of the indicator. */ - virtual string GetName() { return ""; } + virtual string GetName() { return EnumToString(GetType()); } /** * Get full name of the indicator (with "over ..." part). @@ -692,16 +261,6 @@ class IndicatorBase : public Chart { istate.Set(_prop, _value); } - /** - * Sets indicator data source. - */ - virtual void SetDataSource(IndicatorBase* _indi, int _input_mode = 0) = NULL; - - /** - * Sets data source's input mode. - */ - void SetDataSourceMode(int _mode) { indi_src_mode = _mode; } - /** * Sets name of the indicator. */ @@ -719,88 +278,6 @@ class IndicatorBase : public Chart { */ 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 */ /** @@ -818,187 +295,25 @@ class IndicatorBase : public Chart { istate.is_changed = true; } - /** - * Adds entry to the indicator's buffer. Invalid entry won't be added. - */ - bool AddEntry(IndicatorDataEntry& entry, int _shift = 0) { - if (!entry.IsValid()) return false; - - datetime timestamp = GetBarTime(_shift); - entry.timestamp = timestamp; - idata.Add(entry, timestamp); - - return true; - } - - /** - * 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]; - } - - template - T GetValue(int _shift = 0, int _mode = 0) { - T _out; - GetEntryValue(_shift, _mode).Get(_out); - return _out; - } - - /** - * 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 the indicator's struct value. - */ - virtual IndicatorDataEntry GetEntry(int _shift = -1) = NULL; - - /** - * Alters indicator's struct value. - * - * This method allows user to modify the struct entry before it's added to cache. - * This method is called on GetEntry() right after values are set. - */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _shift = -1) = NULL; - - /** - * Returns the indicator's entry value. - */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) = NULL; - /** * Returns indicator value for a given shift and mode. */ - // virtual double GetValue(int _shift = -1, int _mode = 0) = NULL; + // virtual double GetValue(int _shift = 0, int _mode = 0) = NULL; /** * Checks whether indicator has a valid value for a given shift. */ - virtual bool HasValidEntry(int _shift = 0) { + /* + virtual bool HasValidEntry(int _index = 0) { unsigned int position; - long bar_time = GetBarTime(_shift); + long bar_time = GetBarTime(_index); return bar_time > 0 && idata.KeyExists(bar_time, position) ? idata.GetByPos(position).IsValid() : false; } + */ /** * Returns stored data in human-readable format. @@ -1006,93 +321,139 @@ class IndicatorBase : public Chart { // virtual bool ToString() = NULL; // @fixme? /** - * Whether we can and have to select mode when specifying data source. + * Gets indicator's symbol. */ - virtual bool IsDataSourceModeSelectable() { return true; } + string GetSymbol() { return Get(CHART_PARAM_SYMBOL); } - /** - * Update indicator. - */ - virtual bool Update() { - // @todo - return false; - }; + /* Defines MQL backward compatible methods */ - /** - * 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 | SERIALIZER_FLAG_INCLUDE_FEATURE; - - IndicatorDataEntry _stub_entry; - _stub_entry.AddFlags(_entry.GetFlags()); - SerializerConverter _stub = SerializerConverter::MakeStubObject(_stub_entry, _serializer_flags, _entry.GetSize()); - return SerializerConverter::FromObject(_entry, _serializer_flags).ToString(0, &_stub); + 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 } - int GetBarsCalculated() { - int _bars = Bars(GetSymbol(), GetTf()); - - if (!is_fed) { - // Calculating start_bar. - for (; calc_start_bar < _bars; ++calc_start_bar) { - // Iterating from the oldest or previously iterated. - IndicatorDataEntry _entry = GetEntry(_bars - calc_start_bar - 1); - - if (_entry.IsValid()) { - // From this point we assume that future entries will be all valid. - is_fed = true; - return _bars - calc_start_bar; - } - } - } + 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 + } - if (!is_fed) { - Print("Can't find valid bars for ", GetFullName()); - return 0; - } + 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 + } - // Assuming all entries are calculated (even if have invalid values). - return _bars; + 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 } -}; -/** - * 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); + 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 + } - if (_buffer_size < _rates_total) { - _buffer_size = ArrayResize(_buffer, _rates_total); + 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 } - for (int i = _start; i < _count; ++i) { - IndicatorDataEntry _entry = _indi.GetEntry(i); + 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 + } - if (!_entry.IsValid()) { - break; - } + 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 + } - T _value = _entry.GetValue(_mode); + 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 + } - // Print(_value); + 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 + } - _buffer[_buffer_size - i - 1] = _value; - ++_num_copied; + 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 } - return _num_copied; -} + 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 + } -/** - * BarsCalculated()-compatible method to be used on Indicator instance. - */ -int BarsCalculated(IndicatorBase* _indi) { return _indi.GetBarsCalculated(); } + 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, L _l, M _m, int _mode, int _shift) { +#ifdef __MQL4__ + return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _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 + COMMA _l COMMA _m); +#endif + } +}; diff --git a/IndicatorData.enum.h b/IndicatorData.enum.h new file mode 100644 index 000000000..12193a557 --- /dev/null +++ b/IndicatorData.enum.h @@ -0,0 +1,54 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes IndicatorData's enums. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +/* Defines type of source data for */ +enum ENUM_IDATA_SOURCE_TYPE { + IDATA_BUILTIN = 0, // Platform built-in + IDATA_CHART, // Chart calculation + IDATA_ICUSTOM, // iCustom: Custom indicator file + IDATA_ICUSTOM_LEGACY, // iCustom: Custom, legacy, provided by MT indicator file + IDATA_INDICATOR, // OnIndicator: Another indicator as a source of data + IDATA_ONCALCULATE, // OnCalculate: Custom calculation function + IDATA_MATH // Math-based indicator +}; + +/* Defines range value data type for indicator storage. */ +enum ENUM_IDATA_VALUE_RANGE { + IDATA_RANGE_BINARY, // E.g. 0 or 1. + IDATA_RANGE_BITWISE, // Bitwise + IDATA_RANGE_MIXED, + IDATA_RANGE_PRICE, // Values represent price. + IDATA_RANGE_PRICE_DIFF, // Values represent price differences. + IDATA_RANGE_PRICE_ON_SIGNAL, // Values represent price on signal, otherwise zero. + IDATA_RANGE_RANGE, // E.g. 0 to 100. + IDATA_RANGE_UNKNOWN +}; diff --git a/IndicatorData.mqh b/IndicatorData.mqh index 242eb038a..0bc982946 100644 --- a/IndicatorData.mqh +++ b/IndicatorData.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -21,277 +21,938 @@ */ // Includes. -#include "Chart.mqh" -#include "Indicator.mqh" -#include "Log.mqh" - -#define TO_STRING_LIMIT_DEFAULT 3 -#define INDICATOR_BUFFERS_COUNT_MIN 1 -#define BUFFER_MAX_SIZE_DEFAULT 50 +#include "IndicatorBase.h" +#include "IndicatorData.enum.h" +#include "IndicatorData.struct.h" +#include "IndicatorData.struct.serialize.h" +#include "IndicatorData.struct.signal.h" +#include "Storage/ValueStorage.h" +#include "Storage/ValueStorage.indicator.h" +#include "Storage/ValueStorage.native.h" /** - * Class to store indicator value. + * Implements class to store indicator data. */ -class IndicatorValue { +class IndicatorData : public IndicatorBase { + protected: + // Class variables. + ARRAY(ValueStorage*, value_storages); + ARRAY(WeakRef, listeners); // List of indicators that listens for events from this one. + BufferStruct idata; + DictStruct> indicators; // Indicators list keyed by id. + IndicatorCalculateCache cache; + IndicatorDataParams idparams; // Indicator data params. + Ref indi_src; // Indicator used as data source. + + protected: + /* Protected methods */ + + bool Init() { + ArrayResize(value_storages, idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))); + if (indi_src.IsSet()) { + // SetDataSource(_indi_src, _indi_mode); + idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR); + } + switch (idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { + case IDATA_BUILTIN: + break; + case IDATA_ICUSTOM: + break; + case IDATA_INDICATOR: + if (indi_src.IsSet() == NULL) { + // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); + // SetDataSource(_indi_price, true, PRICE_OPEN); + } + break; + } + return true; + } + public: - datetime bt; // bar time - MqlParam value; // Contains value based on the data type (real, integer or string type). + /* Special methods */ + + /** + * Class constructor. + */ + IndicatorData(const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) + : idparams(_idparams), indi_src(_indi_src) {} + IndicatorData(const IndicatorDataParams& _idparams, ENUM_TIMEFRAMES _tf, string _symbol = NULL) + : idparams(_idparams), IndicatorBase(_tf, _symbol) {} - // double linked list attrs - IndicatorValue* prev; - IndicatorValue* next; + /** + * Class deconstructor. + */ + virtual ~IndicatorData() { + for (int i = 0; i < ArraySize(value_storages); ++i) { + if (value_storages[i] != NULL) { + delete value_storages[i]; + } + } + } - void IndicatorValue() : bt(NULL), prev(NULL), next(NULL) {} + /* Operator overloading methods */ - // double linked list methods - void Prev(IndicatorValue* p) { - if (CheckPointer(p) == POINTER_INVALID) return; - prev = p; - p.next = GetPointer(this); + /** + * Access indicator entry data using [] operator via shift. + */ + IndicatorDataEntry operator[](int _index) { + if (!bool(flags | INDI_FLAG_INDEXABLE_BY_SHIFT)) { + Print(GetFullName(), " is not indexable by shift!"); + DebugBreak(); + IndicatorDataEntry _default; + return _default; + } + return GetEntry(_index); } - void Next(IndicatorValue* p) { - if (CheckPointer(p) == POINTER_INVALID) return; - next = p; - p.prev = GetPointer(this); + + /** + * Access indicator entry data using [] operator via datetime. + */ + IndicatorDataEntry operator[](datetime _dt) { + if (!bool(flags | INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { + Print(GetFullName(), " is not indexable by timestamp!"); + DebugBreak(); + IndicatorDataEntry _default; + return _default; + } + return GetEntry(_dt); } -}; -/** - * Class to manage data buffer. - */ -class IndicatorBuffer { - protected: - int size; - int max_size; - IndicatorValue* _head; - IndicatorValue* _tail; + IndicatorDataEntry operator[](ENUM_INDICATOR_INDEX _index) { return GetEntry((int)_index); } - public: - IndicatorBuffer(int _max_size = BUFFER_MAX_SIZE_DEFAULT) : size(0), max_size(_max_size), _head(NULL), _tail(NULL) {} - ~IndicatorBuffer() { - IndicatorValue* it = NULL; - while (CheckPointer(_head) == POINTER_DYNAMIC) { - it = _head; - _head = _head.prev; - delete it; - } + /* Getters */ + + /** + * Gets a value from IndicatorDataParams struct. + */ + template + T Get(STRUCT_ENUM_IDATA_PARAM _param) { + return idparams.Get(_param); } - double GetDouble(datetime _bar_time) { - if (CheckPointer(_head) == POINTER_INVALID) return 0; + /** + * Gets an indicator's state property value. + */ + template + T Get(STRUCT_ENUM_INDICATOR_STATE_PROP _prop) { + return istate.Get(_prop); + } - IndicatorValue* _target = _head; - while (CheckPointer(_target) == POINTER_DYNAMIC && (_bar_time < _target.bt || _target.value.type != TYPE_DOUBLE)) { - _target = _target.prev; + /** + * Gets an indicator property flag. + */ + bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, int _shift = 0) { + IndicatorDataEntry _entry = GetEntry(_shift); + return _entry.CheckFlag(_prop); + } + + /** + * 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; + ENUM_IDATA_VALUE_RANGE _idvrange = + Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDVRANGE)); + if (_idvrange != IDATA_RANGE_PRICE) { + _price = (float)GetPrice(_ap, _shift); + } else if (_idvrange == 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; + } - if (CheckPointer(_target) == POINTER_INVALID) return 0; + /* State methods */ - if (_target.bt == _bar_time && _target.value.type == TYPE_DOUBLE) - return _target.value.double_value; - else - return 0; + /** + * 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)); } - int GetInt(datetime _bar_time) { - if (CheckPointer(_head) == POINTER_INVALID) return 0; + /** + * 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; + } - IndicatorValue* _target = _head; - while (CheckPointer(_target) == POINTER_DYNAMIC && (_bar_time < _target.bt || _target.value.type != TYPE_INT)) { - _target = _target.prev; + /** + * 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; + } - if (CheckPointer(_target) == POINTER_INVALID) return 0; + /** + * 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; + } - if (_target.bt == _bar_time && _target.value.type == TYPE_INT) - return (int)_target.value.integer_value; - else - return 0; + /* Getters */ + + /** + * Returns the highest bar's index (shift). + */ + template + int GetHighest(int count = WHOLE_ARRAY, int start_bar = 0) { + int max_idx = -1; + double max = -DBL_MAX; + int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); + + for (int shift = start_bar; shift <= last_bar; ++shift) { + double value = GetEntry(shift).GetMax(GetModeCount()); + if (value > max) { + max = value; + max_idx = shift; + } + } + + return max_idx; } - bool Add(double _value, datetime _bar_time, bool _force = false) { - IndicatorValue* new_value = new IndicatorValue(); - new_value.bt = _bar_time; - new_value.value.type = TYPE_DOUBLE; - new_value.value.double_value = _value; - return AddIndicatorValue(new_value, _force); + /** + * Returns the lowest bar's index (shift). + */ + template + int GetLowest(int count = WHOLE_ARRAY, int start_bar = 0) { + int min_idx = -1; + double min = DBL_MAX; + int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); + + for (int shift = start_bar; shift <= last_bar; ++shift) { + double value = GetEntry(shift).GetMin(GetModeCount()); + if (value < min) { + min = value; + min_idx = shift; + } + } + + return min_idx; } - bool Add(int _value, datetime _bar_time, bool _force = false) { - IndicatorValue* new_value = new IndicatorValue(); - new_value.bt = _bar_time; - new_value.value.type = TYPE_INT; - new_value.value.integer_value = _value; - return AddIndicatorValue(new_value, _force); + /** + * Returns the highest value. + */ + template + double GetMax(int start_bar = 0, int count = WHOLE_ARRAY) { + double max = NULL; + int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); + + for (int shift = start_bar; shift <= last_bar; ++shift) { + double value = GetEntry(shift).GetMax(_max_modes); + if (max == NULL || value > max) { + max = value; + } + } + + return max; } - bool AddIndicatorValue(IndicatorValue* _new_value, bool _force = false) { - if (CheckPointer(_new_value) == POINTER_INVALID) return false; + /** + * Returns the lowest value. + */ + template + double GetMin(int start_bar, int count = WHOLE_ARRAY) { + double min = NULL; + int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); + + for (int shift = start_bar; shift <= last_bar; ++shift) { + double value = GetEntry(shift).GetMin(_max_modes); + if (min == NULL || value < min) { + min = value; + } + } - // first node for empty linked list - if (CheckPointer(_head) == POINTER_INVALID) { - _head = _new_value; - _tail = _new_value; - size = 1; - return true; + return min; + } + + /** + * Returns average value. + */ + template + double GetAvg(int start_bar, int count = WHOLE_ARRAY) { + int num_values = 0; + double sum = 0; + int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); + + for (int shift = start_bar; shift <= last_bar; ++shift) { + double value_min = GetEntry(shift).GetMin(_max_modes); + double value_max = GetEntry(shift).GetMax(_max_modes); + + sum += value_min + value_max; + num_values += 2; } - // find insert position - IndicatorValue* insert_pos = _head; - while (CheckPointer(insert_pos) == POINTER_DYNAMIC && _new_value.bt <= insert_pos.bt) { - insert_pos = insert_pos.prev; + return sum / num_values; + } + + /** + * Returns median of values. + */ + template + double GetMed(int start_bar, int count = WHOLE_ARRAY) { + double array[]; + + int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); + int num_bars = last_bar - start_bar + 1; + int index = 0; + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); + + ArrayResize(array, num_bars); + + for (int shift = start_bar; shift <= last_bar; ++shift) { + array[index++] = GetEntry(shift).GetAvg(_max_modes); } - // find existed value node(match both bt and value.type), force replace or not - if (CheckPointer(insert_pos) == POINTER_DYNAMIC && _new_value.bt == insert_pos.bt && - _new_value.value.type == insert_pos.value.type) { - if (_force) { - insert_pos.value.integer_value = _new_value.value.integer_value; - insert_pos.value.double_value = _new_value.value.double_value; - insert_pos.value.string_value = _new_value.value.string_value; - return true; - } else - return false; + ArraySort(array); + double median; + int len = ArraySize(array); + if (len % 2 == 0) { + median = (array[len / 2] + array[(len / 2) - 1]) / 2; + } else { + median = array[len / 2]; } - // find insert pos at end of linked list - if (CheckPointer(insert_pos) == POINTER_INVALID) { - _tail.Prev(_new_value); - _tail = _new_value; + return median; + } + + /* Data methods */ + + /** + * 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; } - // find insert pos at begin of linked list - else if (insert_pos == _head) { - _head.Next(_new_value); - _head = _new_value; + for (int i = 0; i < _count; i++) { + IndicatorDataEntry _entry = GetEntry(_start_shift + i); + _is_valid &= _entry.IsValid(); + _data[i] = _entry; } - // find insert pos at normal place - else { - insert_pos.Next(_new_value); + 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); } - size++; + 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; + } + + /* Getters */ + + int GetBarsCalculated(ENUM_TIMEFRAMES _tf = NULL) { + int _bars = Bars(GetSymbol(), _tf); - // truncate data out of max_size - if (size > max_size) { - for (int i = 0; i < (max_size - size); i++) { - _tail = _tail.next; - delete _tail.prev; - size--; + if (!idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IS_FED))) { + // Calculating start_bar. + for (; calc_start_bar < _bars; ++calc_start_bar) { + // Iterating from the oldest or previously iterated. + IndicatorDataEntry _entry = GetEntry(_bars - calc_start_bar - 1); + + if (_entry.IsValid()) { + // From this point we assume that future entries will be all valid. + idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IS_FED), true); + return _bars - calc_start_bar; + } } } - return true; + if (!idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IS_FED))) { + Print("Can't find valid bars for ", GetFullName()); + return 0; + } + + // Assuming all entries are calculated (even if have invalid values). + return _bars; } - string ToString(uint _limit = TO_STRING_LIMIT_DEFAULT) { - string out = NULL; - IndicatorValue* it = _head; - uint i = 0; - while (CheckPointer(it) == POINTER_DYNAMIC && i < _limit) { - if (out != NULL) - // add comma - out = StringFormat("%s, ", out); - else - out = ""; - - switch (it.value.type) { - case TYPE_INT: - out = StringFormat("%s[%d]%d", out, i, it.value.integer_value); - break; - case TYPE_DOUBLE: { - string strfmt = StringFormat("%%s[%%d]%%.%df", _Digits); - out = StringFormat(strfmt, out, i, it.value.double_value); - break; - } + /** + * Returns buffers' cache. + */ + IndicatorCalculateCache* GetCache() { return &cache; } + + /** + * Get pointer to data of indicator. + */ + BufferStruct* GetData() { return GetPointer(idata); } + + /** + * Returns given data source type. Used by i*OnIndicator methods if indicator's Calculate() uses other indicators. + */ + IndicatorData* GetDataSource(ENUM_INDICATOR_TYPE _type) { + IndicatorData* _result = NULL; + if (indicators.KeyExists((int)_type)) { + _result = indicators[(int)_type].Ptr(); + } else { + Ref _indi = FetchDataSource(_type); + if (!_indi.IsSet()) { + Alert(GetFullName(), " does not define required indicator type ", EnumToString(_type), " for symbol ", + GetSymbol(), "!"); + DebugBreak(); + } else { + indicators.Set((int)_type, _indi); + _result = _indi.Ptr(); } - i++; - it = it.prev; } - if (out == "" || out == NULL) out = "[Empty]"; - return out; + return _result; } -}; -/** - * Implements class to store indicator data. - */ -class IndicatorData : public Chart { - protected: - // Struct variables. - IndicatorBuffer buffers[]; + // int GetDataSourceMode() { return indi_src_mode; } - string iname; + /** + * Returns currently selected data source without any validation. + */ + IndicatorBase* GetDataSourceRaw() { return indi_src.Ptr(); } - // Logging. - Ref indi_logger; + /** + * Returns values for a given shift. + * + * Note: Remember to check if shift exists by HasValidEntry(shift). + */ + template + bool GetValues(int _index, T& _out1, T& _out2) { + IndicatorDataEntry _entry = GetEntry(_index); + _out1 = _entry.values[0]; + _out2 = _entry.values[1]; + bool _result = GetLastError() != 4401; + ResetLastError(); + return _result; + } + + template + bool GetValues(int _index, T& _out1, T& _out2, T& _out3) { + IndicatorDataEntry _entry = GetEntry(_index); + _out1 = _entry.values[0]; + _out2 = _entry.values[1]; + _out3 = _entry.values[2]; + bool _result = GetLastError() != 4401; + ResetLastError(); + return _result; + } + + template + bool GetValues(int _index, T& _out1, T& _out2, T& _out3, T& _out4) { + IndicatorDataEntry _entry = GetEntry(_index); + _out1 = _entry.values[0]; + _out2 = _entry.values[1]; + _out3 = _entry.values[2]; + _out4 = _entry.values[3]; + bool _result = GetLastError() != 4401; + ResetLastError(); + return _result; + } - public: /** - * Class constructor. + * Provides built-in indicators whose can be used as data source. + */ + virtual IndicatorBase* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } + + /* Checkers */ + + /** + * Whether we can and have to select mode when specifying data source. + */ + virtual bool IsDataSourceModeSelectable() { return true; } + + /* Setters */ + + /** + * Adds event listener. */ - void IndicatorData(string _name = NULL, uint _max_buffer = INDICATOR_BUFFERS_COUNT_MIN) : iname(_name) { - _max_buffer = fmax(_max_buffer, INDICATOR_BUFFERS_COUNT_MIN); - ArrayResize(buffers, _max_buffer); + void AddListener(IndicatorData* _indi) { + WeakRef _ref = _indi; + ArrayPushObject(listeners, _ref); } /** - * Class deconstructor. + * Removes event listener. */ - void ~IndicatorData() {} + void RemoveListener(IndicatorData* _indi) { + WeakRef _ref = _indi; + Util::ArrayRemoveFirst(listeners, _ref); + } /** - * Store a new indicator value. + * Sets data source's input mode. */ - bool IsValidMode(uint _mode) { return _mode < (uint)ArraySize(buffers); } + // void SetDataSourceMode(int _mode) { indi_src_mode = _mode; } - bool Add(double _value, uint _mode = 0, uint _shift = CURR, bool _force = false) { - if (!IsValidMode(_mode)) return false; - return buffers[_mode].Add(_value, GetBarTime(_shift), _force); + /* Storage methods */ + + ValueStorage* GetValueStorage(int _mode = 0) { + if (_mode >= ArraySize(value_storages)) { + ArrayResize(value_storages, _mode + 1); + } + + if (value_storages[_mode] == NULL) { + value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + } + return value_storages[_mode]; } - bool Add(int _value, uint _mode = 0, uint _shift = CURR, bool _force = false) { - if (!IsValidMode(_mode)) return false; - return buffers[_mode].Add(_value, GetBarTime(_shift), _force); + /** + * Returns value storage of given kind. + */ + virtual IValueStorage* GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { + Print("Error: ", GetFullName(), " indicator has no storage type ", EnumToString(_type), "!"); + DebugBreak(); + return NULL; } - double GetDouble(uint _mode = 0, uint _shift = CURR) { - if (!IsValidMode(_mode)) return 0; - return buffers[_mode].GetDouble(GetBarTime(_shift)); + virtual IValueStorage* GetSpecificAppliedPriceValueStorage(ENUM_APPLIED_PRICE _ap) { + switch (_ap) { + case PRICE_ASK: + return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); + case PRICE_BID: + return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); + case PRICE_OPEN: + return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); + case PRICE_HIGH: + return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); + case PRICE_LOW: + return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); + case PRICE_CLOSE: + return GetSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); + case PRICE_MEDIAN: + case PRICE_TYPICAL: + case PRICE_WEIGHTED: + default: + Print("Error: Invalid applied price " + EnumToString(_ap) + + ", only PRICE_(OPEN|HIGH|LOW|CLOSE) are currently supported by " + "IndicatorBase::GetSpecificAppliedPriceValueStorage()!"); + DebugBreak(); + return NULL; + } } - int GetInt(uint _mode = 0, uint _shift = CURR) { - if (!IsValidMode(_mode)) return 0; - return buffers[_mode].GetInt(GetBarTime(_shift)); + virtual bool HasSpecificAppliedPriceValueStorage(ENUM_APPLIED_PRICE _ap) { + switch (_ap) { + case PRICE_ASK: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); + case PRICE_BID: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); + case PRICE_OPEN: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); + case PRICE_HIGH: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); + case PRICE_LOW: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); + case PRICE_CLOSE: + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); + case PRICE_MEDIAN: + case PRICE_TYPICAL: + case PRICE_WEIGHTED: + default: + Print("Error: Invalid applied price " + EnumToString(_ap) + + ", only PRICE_(OPEN|HIGH|LOW|CLOSE) are currently supported by " + "IndicatorBase::HasSpecificAppliedPriceValueStorage()!"); + DebugBreak(); + return false; + } } /** - * Get name of the indicator. + * Checks whether indicator support given value storage type. */ - string GetName() { return iname != NULL ? iname : "Custom"; } + virtual bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { return false; } + + /* Tick methods */ + + void Tick() { + long _current_time = TimeCurrent(); + + if (last_tick_time == _current_time) { + // We've already ticked. + return; + } + + last_tick_time = _current_time; + + // Checking and potentially initializing new data source. + if (HasDataSource(true) != NULL) { + // Ticking data source if not yet ticked. + GetDataSource().Tick(); + } + + // Also ticking all used indicators if they've not yet ticked. + for (DictStructIterator> iter = indicators.Begin(); iter.IsValid(); ++iter) { + iter.Value().Ptr().Tick(); + } + + // Overridable OnTick() method. + OnTick(); + } + + /* Validate methods */ /** - * Print stored data. + * Loads and validates built-in indicators whose can be used as data source. */ - string ToString(int mode = -1, uint _limit = TO_STRING_LIMIT_DEFAULT) { - string _out = StringFormat("%s DATA:\n", GetName()); - if (mode == -1) { // print all series - for (int m = 0; m < ArraySize(buffers); m++) { - _out = StringFormat("%s mode=%d %s\n", _out, m, buffers[m].ToString(_limit)); - } - } else if (mode < ArraySize(buffers)) { - _out = StringFormat("%s mode(%d) %s\n", _out, mode, buffers[mode].ToString(_limit)); - } else { - _out = StringFormat("%s [Err] mode(%d) is invalid", mode); + void ValidateDataSource(IndicatorData* _target, IndicatorData* _source) { + if (_target == NULL) { + Alert("Internal Error! _target is NULL in ", __FUNCTION_LINE__, "."); + DebugBreak(); + return; + } + + if (_source == NULL) { + Alert("Error! You have to select source indicator's via SetDataSource()."); + DebugBreak(); + return; + } + + if (!_target.IsDataSourceModeSelectable()) { + // We don't validate source mode as it will use all modes. + return; + } + + if (_source.GetModeCount() > 1 && + _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { + // Mode must be selected if source indicator has more that one mode. + Alert("Warning! ", GetName(), + " must select source indicator's mode via SetDataSourceMode(int). Defaulting to mode 0."); + _target.idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); + DebugBreak(); + } else if (_source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == 1 && + _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { + _target.idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); + } else if (_target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) < 0 || + _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) > + _source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) { + Alert("Error! ", _target.GetName(), + " must select valid source indicator's mode via SetDataSourceMode(int) between 0 and ", + _source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)), "."); + DebugBreak(); } + } + + /** + * Validates currently selected indicator used as data source. + */ + void ValidateSelectedDataSource() { + if (HasDataSource()) { + ValidateDataSource(THIS_PTR, GetDataSourceRaw()); + } + } + + /* Printers */ + + /** + * Returns the indicator's value in plain format. + */ + virtual string ToString(int _index = 0) { + IndicatorDataEntry _entry = GetEntry(_index); + int _serializer_flags = SERIALIZER_FLAG_SKIP_HIDDEN | SERIALIZER_FLAG_INCLUDE_DEFAULT | + SERIALIZER_FLAG_INCLUDE_DYNAMIC | SERIALIZER_FLAG_INCLUDE_FEATURE; + + IndicatorDataEntry _stub_entry; + _stub_entry.AddFlags(_entry.GetFlags()); + SerializerConverter _stub = SerializerConverter::MakeStubObject(_stub_entry, _serializer_flags, _entry.GetSize()); + return SerializerConverter::FromObject(_entry, _serializer_flags).ToString(0, &_stub); + } + + template + T GetValue(int _mode = 0, int _index = 0) { + T _out; + GetEntryValue(_mode, _index).Get(_out); return _out; } + /* Virtual methods */ + + /** + * Returns currently selected data source doing validation. + */ + virtual IndicatorData* GetDataSource() { return NULL; } + + /** + * Returns the indicator's struct value. + */ + virtual IndicatorDataEntry GetEntry(datetime _dt) { + Print(GetFullName(), + " must implement IndicatorDataEntry IndicatorBase::GetEntry(datetime _dt) in order to use GetEntry(datetime " + "_dt) or _indi[datetime] subscript operator!"); + DebugBreak(); + IndicatorDataEntry _default; + return _default; + } + + /** + * Returns the indicator's struct value. + */ + virtual IndicatorDataEntry GetEntry(int _index = 0) = NULL; + + /** + * Alters indicator's struct value. + * + * This method allows user to modify the struct entry before it's added to cache. + * This method is called on GetEntry() right after values are set. + */ + virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _index = -1) = NULL; + + // virtual ENUM_IDATA_VALUE_RANGE GetIDataValueRange() = NULL; + + /** + * Returns the indicator's entry value. + */ + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) = NULL; + + /** + * Gets indicator's signals. + * + * When indicator values are not valid, returns empty signals. + */ + virtual IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) = NULL; + + /** + * Sends entry to listening indicators. + */ + void EmitEntry(IndicatorDataEntry& entry) { + for (int i = 0; i < ArraySize(listeners); ++i) { + if (listeners[i].ObjectExists()) { + listeners[i].Ptr().OnDataSourceEntry(entry); + } + } + } + + /** + * Sends historic entries to listening indicators. May be overriden. + */ + virtual void EmitHistory() {} + /** - * Print stored data. + * Called when indicator became a data source for other indicator. */ - void PrintData(int mode = -1, uint _limit = TO_STRING_LIMIT_DEFAULT) { Print(ToString(mode, _limit)); } + virtual void OnBecomeDataSourceFor(IndicatorData* _base_indi){}; + + /** + * Called when data source emits new entry (historic or future one). + */ + virtual void OnDataSourceEntry(IndicatorDataEntry& entry){}; + + virtual void OnTick() {} + + /** + * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on + * some data source. + */ + virtual IndicatorData* OnDataSourceRequest() { + Print("In order to use IDATA_INDICATOR mode for indicator ", GetFullName(), + " without explicitly selecting an indicator, ", GetFullName(), + " must override OnDataSourceRequest() method and return new instance of data source to be used by default."); + DebugBreak(); + return NULL; + } + + /** + * Creates default, tick based indicator for given applied price. + */ + virtual IndicatorData* DataSourceRequestReturnDefault(int _applied_price) { + DebugBreak(); + return NULL; + } + + /** + * Called when user tries to set given data source. Could be used to check if indicator implements all required value + * storages. + */ + virtual bool OnValidateDataSource(IndicatorData* _ds, string& _reason) { + _reason = "Indicator " + GetName() + " does not implement OnValidateDataSource()"; + return false; + } + + /** + * Sets indicator data source. + */ + virtual void SetDataSource(IndicatorData* _indi, int _input_mode = -1) = NULL; /** * Update indicator. */ - bool Update() { return true; } + virtual bool Update() { + // @todo + return false; + }; + + /** + * Loads and validates built-in indicators whose can be used as data source. + */ + // virtual void ValidateDataSource(IndicatorData* _target, IndicatorData* _source) {} + + /** + * Checks whether indicator have given mode index. + * + * If given mode is -1 (default one) and indicator has exactly one mode, then mode index will be replaced by 0. + */ + virtual void ValidateDataSourceMode(int& _out_mode) {} }; + +/** + * BarsCalculated()-compatible method to be used on Indicator instance. + */ +int BarsCalculated(IndicatorData* _indi) { return _indi.GetBarsCalculated(); } + +/** + * 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(IndicatorData* _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); + + _buffer[_buffer_size - i - 1] = _value; + ++_num_copied; + } + + return _num_copied; +} diff --git a/IndicatorData.struct.h b/IndicatorData.struct.h new file mode 100644 index 000000000..b6f942eb4 --- /dev/null +++ b/IndicatorData.struct.h @@ -0,0 +1,503 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes IndicatorData's structs. + */ + +// Defines. +#define STRUCT_ENUM_IDATA_PARAM STRUCT_ENUM(IndicatorDataParams, ENUM_IDATA_PARAM) + +// Includes. +#include "SerializerNode.enum.h" + +// Type-less value for IndicatorDataEntryValue structure. +union IndicatorDataEntryTypelessValue { + double vdbl; + float vflt; + int vint; + long vlong; +}; + +// Type-aware value for IndicatorDataEntry class. +struct IndicatorDataEntryValue { + unsigned char flags; + IndicatorDataEntryTypelessValue value; + + // Returns type of the value. + ENUM_DATATYPE GetDataType() { return (ENUM_DATATYPE)((flags & 0xF0) >> 4); } + + // Sets type of the value. + void SetDataType(ENUM_DATATYPE _type) { + // Clearing type. + flags &= 0x0F; + + // Setting type. + flags |= (unsigned char)_type << 4; + } + + // Union operators. + template + T operator*(const T _value) { + return Get() * _value; + } + template + T operator+(const T _value) { + return Get() + _value; + } + template + T operator-(const T _value) { + return Get() - _value; + } + template + T operator/(const T _value) { + return Get() / _value; + } + template + bool operator!=(const T _value) { + return Get() != _value; + } + template + bool operator<(const T _value) { + return Get() < _value; + } + template + bool operator<=(const T _value) { + return Get() <= _value; + } + template + bool operator==(const T _value) { + return Get() == _value; + } + template + bool operator>(const T _value) { + return Get() > _value; + } + template + bool operator>=(const T _value) { + return Get() >= _value; + } + template + void operator=(const T _value) { + Set(_value); + } + // Checkers. + template + bool IsGt(T _value) { + return Get() > _value; + } + template + bool IsLt(T _value) { + return Get() < _value; + } + // Getters. + double GetDbl() { return value.vdbl; } + float GetFloat() { return value.vflt; } + int GetInt() { return value.vint; } + long GetLong() { return value.vlong; } + template + void Get(T &_out) { + _out = Get(); + } + template + T Get() { + T _v; + Get(_v); + return _v; + } + void Get(double &_out) { _out = value.vdbl; } + void Get(float &_out) { _out = value.vflt; } + void Get(int &_out) { _out = value.vint; } + void Get(unsigned int &_out) { _out = (unsigned int)value.vint; } + void Get(long &_out) { _out = value.vlong; } + void Get(unsigned long &_out) { _out = (unsigned long)value.vint; } + // Setters. + template + void Set(T _value) { + Set(_value); + } + void Set(double _value) { + value.vdbl = _value; + SetDataType(TYPE_DOUBLE); + } + void Set(float _value) { + value.vflt = _value; + SetDataType(TYPE_FLOAT); + } + void Set(int _value) { + value.vint = _value; + SetDataType(TYPE_INT); + } + void Set(unsigned int _value) { + value.vint = (int)_value; + SetDataType(TYPE_UINT); + } + void Set(long _value) { + value.vlong = _value; + SetDataType(TYPE_LONG); + } + void Set(unsigned long _value) { + value.vlong = (long)_value; + SetDataType(TYPE_ULONG); + } + // Serializers. + // SERIALIZER_EMPTY_STUB + SerializerNodeType Serialize(Serializer &_s); + // To string + template + string ToString() { + return (string)Get(); + } +}; + +/* Structure for indicator data entry. */ +struct IndicatorDataEntry { + long timestamp; // Timestamp of the entry's bar. + unsigned short flags; // Indicator entry flags. + ARRAY(IndicatorDataEntryValue, values); + + // Constructors. + IndicatorDataEntry(int _size = 1) : flags(INDI_ENTRY_FLAG_NONE), timestamp(0) { Resize(_size); } + IndicatorDataEntry(IndicatorDataEntry &_entry) { THIS_REF = _entry; } + int GetSize() { return ArraySize(values); } + // Operator overloading methods. + template + T operator*(const T _value) { + return values[0].Get() * _value; + } + template + T operator+(const T _value) { + return values[0].Get() + _value; + } + template + T operator-(const T _value) { + return values[0].Get() - _value; + } + template + T operator/(const T _value) { + return values[0].Get() / _value; + } + template + T operator[](I _index) { + return values[(int)_index].Get(); + } + template <> + double operator[](int _index) { + if (_index >= ArraySize(values)) { + return 0; + } + double _value; + values[_index].Get(_value); + return _value; + } + // Checkers. + template + bool HasValue(T _value) { + bool _result = false; + int _asize = ArraySize(values); + T _value2; + for (int i = 0; i < _asize; i++) { + values[i].Get(_value2); + if (_value == _value2) { + _result = true; + break; + } + } + return _result; + } + template + bool IsGe(T _value) { + return GetMin() >= _value; + } + template + bool IsGt(T _value) { + return GetMin() > _value; + } + template + bool IsLe(T _value) { + return GetMax() <= _value; + } + template + bool IsLt(T _value) { + return GetMax() < _value; + } + template + bool IsWithinRange(T _min, T _max) { + return GetMin() >= _min && GetMax() <= _max; + } + // Getters. + template + void GetArray(ARRAY_REF(T, _out), int _size = 0) { + int _asize = _size > 0 ? _size : ArraySize(_out); + for (int i = 0; i < _asize; i++) { + values[i].Get(_out[i]); + } + }; + template + T GetAvg(int _size = 0) { + int _asize = _size > 0 ? _size : ArraySize(values); + T _avg = GetSum() / _asize; + return _avg; + }; + template + T GetMin(int _size = 0) { + int _asize = _size > 0 ? _size : ArraySize(values); + int _index = 0; + for (int i = 1; i < _asize; i++) { + _index = values[i].Get() < values[_index].Get() ? i : _index; + } + return values[_index].Get(); + }; + template + T GetMax(int _size = 0) { + int _asize = _size > 0 ? _size : ArraySize(values); + int _index = 0; + for (int i = 1; i < _asize; i++) { + _index = values[i].Get() > values[_index].Get() ? i : _index; + } + return values[_index].Get(); + }; + template + T GetSum(int _size = 0) { + int _asize = _size > 0 ? _size : ArraySize(values); + T _sum = 0; + for (int i = 1; i < _asize; i++) { + _sum = +values[i].Get(); + } + return _sum; + }; + template + T GetValue(int _index = 0) { + return values[_index].Get(); + }; + template + void GetValues(T &_out1, T &_out2) { + values[0].Get(_out1); + values[1].Get(_out2); + }; + template + void GetValues(T &_out1, T &_out2, T &_out3) { + values[0].Get(_out1); + values[1].Get(_out2); + values[2].Get(_out3); + }; + template + void GetValues(T &_out1, T &_out2, T &_out3, T &_out4) { + values[0].Get(_out1); + values[1].Get(_out2); + values[2].Get(_out3); + values[3].Get(_out4); + }; + + // Getters. + int GetDayOfYear() { return DateTimeStatic::DayOfYear(timestamp); } + int GetMonth() { return DateTimeStatic::Month(timestamp); } + int GetYear() { return DateTimeStatic::Year(timestamp); } + long GetTime() { return timestamp; }; + ENUM_DATATYPE GetDataType(int _mode) { return values[_mode].GetDataType(); } + ushort GetDataTypeFlags(ENUM_DATATYPE _dt) { + switch (_dt) { + case TYPE_BOOL: + case TYPE_CHAR: + SetUserError(ERR_INVALID_PARAMETER); + break; + case TYPE_INT: + return INDI_ENTRY_FLAG_NONE; + case TYPE_LONG: + return INDI_ENTRY_FLAG_IS_DOUBLED; + case TYPE_UINT: + return INDI_ENTRY_FLAG_IS_UNSIGNED; + case TYPE_ULONG: + return INDI_ENTRY_FLAG_IS_UNSIGNED | INDI_ENTRY_FLAG_IS_DOUBLED; + case TYPE_DOUBLE: + return INDI_ENTRY_FLAG_IS_REAL | INDI_ENTRY_FLAG_IS_DOUBLED; + case TYPE_FLOAT: + return INDI_ENTRY_FLAG_IS_REAL; + case TYPE_STRING: + case TYPE_UCHAR: + SetUserError(ERR_INVALID_PARAMETER); + break; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return INDI_ENTRY_FLAG_NONE; + } + // Setters. + bool Resize(int _size = 0) { return _size > 0 ? ArrayResize(values, _size) > 0 : true; } + // Value flag methods for bitwise operations. + bool CheckFlag(INDICATOR_ENTRY_FLAGS _prop) { return CheckFlags(_prop); } + bool CheckFlags(unsigned short _flags) { return (flags & _flags) != 0; } + bool CheckFlagsAll(unsigned short _flags) { return (flags & _flags) == _flags; } + void AddFlags(unsigned short _flags) { flags |= _flags; } + void RemoveFlags(unsigned short _flags) { flags &= ~_flags; } + void SetFlag(INDICATOR_ENTRY_FLAGS _flag, bool _value) { + if (_value) { + AddFlags(_flag); + } else { + RemoveFlags(_flag); + } + } + void SetFlags(unsigned short _flags) { flags = _flags; } + unsigned short GetFlags() { return flags; } + // Converters. + // State checkers. + bool IsValid() { return CheckFlags(INDI_ENTRY_FLAG_IS_VALID); } + // Serializers. + void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) { + ArrayResize(values, _n1); + for (int i = 0; i < _n1; ++i) { + values[i] = (int)1; + } + } + SerializerNodeType Serialize(Serializer &_s); + template + string ToCSV() { + int _asize = ArraySize(values); + string _result = ""; + for (int i = 0; i < _asize; i++) { + _result += StringFormat("%s%s", (string)values[i].Get(), i < _asize ? "," : ""); + } + return _result; + } + template + string ToString() { + return ToCSV(); + } +}; + +/* Structure for indicator data parameters. */ +struct IndicatorDataParams { + protected: + /* Struct protected variables */ + bool is_fed; // Whether calc_start_bar is already calculated. + int data_src_mode; // Mode used as input from data source. + int src_id; // Id of the indicator to be used as data source. + int src_mode; // Mode of source indicator + unsigned int max_buffers; // Max buffers to store. + unsigned int max_modes; // Max supported indicator modes (values per entry). + ENUM_DATATYPE dtype; // Type of basic data to store values (DTYPE_DOUBLE, DTYPE_INT). + ENUM_IDATA_SOURCE_TYPE idstype; // Indicator's data source type (e.g. IDATA_BUILTIN, IDATA_ICUSTOM). + ENUM_IDATA_VALUE_RANGE idvrange; // Indicator's range value data type. + public: + /* Struct enumerations */ + enum ENUM_IDATA_PARAM { + IDATA_PARAM_IS_FED = 0, + IDATA_PARAM_DATA_SRC_MODE, + IDATA_PARAM_DTYPE, + IDATA_PARAM_IDSTYPE, + IDATA_PARAM_IDVRANGE, + IDATA_PARAM_MAX_BUFFERS, + IDATA_PARAM_MAX_MODES, + IDATA_PARAM_SRC_ID, + IDATA_PARAM_SRC_MODE, + }; + + public: + /* Special methods */ + // Constructor. + IndicatorDataParams(unsigned int _max_modes = 1, ENUM_DATATYPE _dtype = TYPE_DOUBLE, + ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + ENUM_IDATA_VALUE_RANGE _idvrange = IDATA_RANGE_UNKNOWN, int _data_src_mode = 0) + : data_src_mode(_data_src_mode), + dtype(_dtype), + max_modes(_max_modes), + max_buffers(10), + idstype(_idstype), + idvrange(_idvrange), + is_fed(false), + src_id(-1), + src_mode(-1){}; + // Copy constructor. + IndicatorDataParams(const IndicatorDataParams &_idp) { THIS_REF = _idp; } + // Deconstructor. + ~IndicatorDataParams(){}; + /* Getters */ + template + T Get(STRUCT_ENUM_IDATA_PARAM _param) { + switch (_param) { + case IDATA_PARAM_IS_FED: + return (T)is_fed; + case IDATA_PARAM_DATA_SRC_MODE: + return (T)data_src_mode; + case IDATA_PARAM_DTYPE: + return (T)dtype; + case IDATA_PARAM_IDSTYPE: + return (T)idstype; + case IDATA_PARAM_IDVRANGE: + return (T)idvrange; + case IDATA_PARAM_MAX_BUFFERS: + return (T)max_buffers; + case IDATA_PARAM_MAX_MODES: + return (T)max_modes; + case IDATA_PARAM_SRC_ID: + return (T)src_id; + case IDATA_PARAM_SRC_MODE: + return (T)src_mode; + } + SetUserError(ERR_INVALID_PARAMETER); + return (T)WRONG_VALUE; + } + static IndicatorDataParams GetInstance(unsigned int _max_modes = 1, ENUM_DATATYPE _dtype = TYPE_DOUBLE, + ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + ENUM_IDATA_VALUE_RANGE _idvrange = IDATA_RANGE_UNKNOWN, + int _data_src_mode = 0) { + IndicatorDataParams _instance(_max_modes, _dtype, _idstype, _idvrange, _data_src_mode); + return _instance; + } + /* Setters */ + template + void Set(STRUCT_ENUM_IDATA_PARAM _param, T _value) { + switch (_param) { + case IDATA_PARAM_IS_FED: + is_fed = (bool)_value; + return; + case IDATA_PARAM_DATA_SRC_MODE: + data_src_mode = (int)_value; + return; + case IDATA_PARAM_DTYPE: + dtype = (ENUM_DATATYPE)_value; + return; + case IDATA_PARAM_IDSTYPE: + idstype = (ENUM_IDATA_SOURCE_TYPE)_value; + return; + case IDATA_PARAM_IDVRANGE: + idvrange = (ENUM_IDATA_VALUE_RANGE)_value; + return; + case IDATA_PARAM_MAX_BUFFERS: + max_buffers = (unsigned int)_value; + return; + case IDATA_PARAM_MAX_MODES: + max_modes = (unsigned int)_value; + return; + case IDATA_PARAM_SRC_ID: + src_id = (int)_value; + return; + case IDATA_PARAM_SRC_MODE: + src_mode = (int)_value; + return; + } + SetUserError(ERR_INVALID_PARAMETER); + } +}; diff --git a/IndicatorData.struct.serialize.h b/IndicatorData.struct.serialize.h new file mode 100644 index 000000000..87020224e --- /dev/null +++ b/IndicatorData.struct.serialize.h @@ -0,0 +1,97 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes IndicatorData's struct serializers. + */ + +#include "Serializer.mqh" + +// Forward class declaration. +class Serializer; + +/* Method to serialize IndicatorDataEntry structure. */ +SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { + int _asize = ArraySize(values); + _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? + + switch (values[i].GetDataType()) { + case TYPE_DOUBLE: + _s.Pass(THIS_REF, (string)i, values[i].value.vdbl, + SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + break; + case TYPE_FLOAT: + _s.Pass(THIS_REF, (string)i, values[i].value.vflt, + SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + break; + case TYPE_INT: + case TYPE_UINT: + if (CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) { + // Split for each bit and pass 0 or 1. + for (int j = 0; j < sizeof(int) * 8; ++j) { + int _value = (values[i].value.vint & (1 << j)) != 0; + _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); + } + } else { + _s.Pass(THIS_REF, (string)i, values[i].value.vint, + SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + } + break; + case TYPE_LONG: + case TYPE_ULONG: + if (CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) { + // Split for each bit and pass 0 or 1. + /* @fixme: j, j already defined. + for (int j = 0; j < sizeof(int) * 8; ++j) { + int _value = (values[i].vlong & (1 << j)) != 0; + _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); + } + */ + SetUserError(ERR_INVALID_PARAMETER); + } else { + _s.Pass(THIS_REF, (string)i, values[i].value.vlong, + SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + } + break; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + } + return SerializerNodeObject; +} + +/* Method to serialize IndicatorDataEntry's IndicatorDataEntryValue union. */ +SerializerNodeType IndicatorDataEntryValue::Serialize(Serializer &_s) { + _s.Pass(THIS_REF, "flags", flags); + _s.Pass(THIS_REF, "vdbl", value.vdbl); + _s.Pass(THIS_REF, "vflt", value.vflt); + _s.Pass(THIS_REF, "vint", value.vint); + _s.Pass(THIS_REF, "vlong", value.vlong); + return SerializerNodeObject; +}; diff --git a/Indicator.struct.signal.h b/IndicatorData.struct.signal.h similarity index 94% rename from Indicator.struct.signal.h rename to IndicatorData.struct.signal.h index 954e02172..d865e4129 100644 --- a/Indicator.struct.signal.h +++ b/IndicatorData.struct.signal.h @@ -33,10 +33,12 @@ // Forward declaration. struct ChartParams; struct IndicatorDataEntry; +struct IndicatorDataParams; struct IndicatorParams; // Includes. -#include "Indicator.struct.h" +//#include "IndicatorData.enum.h" +//#include "Indicator.struct.h" /* Structure for indicator signals. */ struct IndicatorSignal { @@ -56,14 +58,14 @@ struct IndicatorSignal { // Constructors. IndicatorSignal(int _signals = 0) : signals(_signals) {} - IndicatorSignal(ARRAY_REF(IndicatorDataEntry, _data), IndicatorParams &_ip, ChartParams &_cp, int _m1 = 0, + IndicatorSignal(ARRAY_REF(IndicatorDataEntry, _data), IndicatorDataParams &_idp, ChartParams &_cp, int _m1 = 0, int _m2 = 0) : signals(0) { - CalcSignals(_data, _ip, _cp, _m1, _m2); + CalcSignals(_data, _idp, _cp, _m1, _m2); } // Main methods. // Calculate signal values. - void CalcSignals(ARRAY_REF(IndicatorDataEntry, _data), IndicatorParams &_ip, ChartParams &_cp, int _m1 = 0, + void CalcSignals(ARRAY_REF(IndicatorDataEntry, _data), IndicatorDataParams &_idp, ChartParams &_cp, int _m1 = 0, int _m2 = 0) { int _size = ArraySize(_data); // INDICATOR_SIGNAL_CROSSOVER @@ -88,7 +90,7 @@ struct IndicatorSignal { ((_price_w0 - _price_w1) < 0 && (_data[0][_m1] - _data[_size - 1][_m1]) > 0)); // INDICATOR_SIGNAL_GT_PRICE bool _v_gt_p = false; - if (_ip.GetIDataValueRange() == IDATA_RANGE_PRICE) { + if (_idp.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDVRANGE)) == IDATA_RANGE_PRICE) { _v_gt_p = _data[0][_m1] > _price_w0 || _data[0][_m2] > _price_w0; } else { // @todo diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index a9b94aea1..7e4a4f5d3 100644 --- a/Indicators/Bitwise/Indi_Candle.mqh +++ b/Indicators/Bitwise/Indi_Candle.mqh @@ -23,7 +23,7 @@ // Includes. #include "../../Bar.struct.h" #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/IndicatorTickOrCandleSource.h" #include "../../Pattern.struct.h" #include "../../Serializer.mqh" #include "../Price/Indi_Price.mqh" @@ -32,9 +32,7 @@ // Structs. struct CandleParams : IndicatorParams { // Struct constructor. - CandleParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorParams(INDI_CANDLE, 1, TYPE_INT) { - SetDataValueRange(IDATA_RANGE_RANGE); - SetDataSourceType(IDATA_BUILTIN); + CandleParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorParams(INDI_CANDLE) { shift = _shift; tf = _tf; }; @@ -47,13 +45,18 @@ struct CandleParams : IndicatorParams { /** * Implements Candle Pattern Detector. */ -class Indi_Candle : public Indicator { +class Indi_Candle : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_Candle(CandleParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_Candle(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_CANDLE, _tf, _shift){}; + Indi_Candle(CandleParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_INT, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src){}; + Indi_Candle(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_CANDLE, _tf, _shift){}; /** * Alters indicator's struct value. @@ -66,12 +69,12 @@ class Indi_Candle : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); BarOHLC _ohlcs[1]; - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // In this mode, price is fetched from chart. _ohlcs[0] = Chart::GetOHLC(_ishift); @@ -93,10 +96,10 @@ class Indi_Candle : public Indicator { break; } - _ohlcs[0].open = GetDataSource().GetValue(_ishift, PRICE_OPEN); - _ohlcs[0].high = GetDataSource().GetValue(_ishift, PRICE_HIGH); - _ohlcs[0].low = GetDataSource().GetValue(_ishift, PRICE_LOW); - _ohlcs[0].close = GetDataSource().GetValue(_ishift, PRICE_CLOSE); + _ohlcs[0].open = GetDataSource().GetValue(PRICE_OPEN, _ishift); + _ohlcs[0].high = GetDataSource().GetValue(PRICE_HIGH, _ishift); + _ohlcs[0].low = GetDataSource().GetValue(PRICE_LOW, _ishift); + _ohlcs[0].close = GetDataSource().GetValue(PRICE_CLOSE, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index f9e014ec0..cc223770c 100644 --- a/Indicators/Bitwise/Indi_Pattern.mqh +++ b/Indicators/Bitwise/Indi_Pattern.mqh @@ -23,7 +23,7 @@ // Includes. #include "../../Bar.struct.h" #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/IndicatorTickOrCandleSource.h" #include "../../Pattern.struct.h" #include "../../Serializer.mqh" #include "../Price/Indi_Price.mqh" @@ -32,11 +32,7 @@ // Structs. struct IndiPatternParams : IndicatorParams { // Struct constructor. - IndiPatternParams(int _shift = 0) : IndicatorParams(INDI_PATTERN, 5, TYPE_UINT) { - SetDataValueType(TYPE_UINT); - SetDataValueRange(IDATA_RANGE_BITWISE); - shift = _shift; - }; + IndiPatternParams(int _shift = 0) : IndicatorParams(INDI_PATTERN) { shift = _shift; }; IndiPatternParams(IndiPatternParams& _params, ENUM_TIMEFRAMES _tf) { THIS_REF = _params; tf = _tf; @@ -46,26 +42,32 @@ struct IndiPatternParams : IndicatorParams { /** * Implements Pattern Detector. */ -class Indi_Pattern : public Indicator { +class Indi_Pattern : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_Pattern(IndiPatternParams& _p, IndicatorBase* _indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_Pattern(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_PATTERN, _tf, _shift){}; + Indi_Pattern(IndiPatternParams& _p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData* _indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(5, TYPE_UINT, _idstype, IDATA_RANGE_BITWISE, _indi_src_mode), + _indi_src){}; + Indi_Pattern(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_PATTERN, _tf, _shift){}; /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int i; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); BarOHLC _ohlcs[8]; - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // In this mode, price is fetched from chart. - for (i = 0; i < iparams.GetMaxModes(); ++i) { + for (i = 0; i < _max_modes; ++i) { _ohlcs[i] = Chart::GetOHLC(_ishift + i); if (!_ohlcs[i].IsValid()) { // Return empty entry on invalid candles. @@ -90,11 +92,11 @@ class Indi_Pattern : public Indicator { return WRONG_VALUE; } - for (i = 0; i < iparams.GetMaxModes(); ++i) { - _ohlcs[i].open = GetDataSource().GetValue(_ishift + i, PRICE_OPEN); - _ohlcs[i].high = GetDataSource().GetValue(_ishift + i, PRICE_HIGH); - _ohlcs[i].low = GetDataSource().GetValue(_ishift + i, PRICE_LOW); - _ohlcs[i].close = GetDataSource().GetValue(_ishift + i, PRICE_CLOSE); + for (i = 0; i < _max_modes; ++i) { + _ohlcs[i].open = GetDataSource().GetValue(PRICE_OPEN, _ishift + i); + _ohlcs[i].high = GetDataSource().GetValue(PRICE_HIGH, _ishift + i); + _ohlcs[i].low = GetDataSource().GetValue(PRICE_LOW, _ishift + i); + _ohlcs[i].close = GetDataSource().GetValue(PRICE_CLOSE, _ishift + i); if (!_ohlcs[i].IsValid()) { // Return empty entry on invalid candles. return WRONG_VALUE; @@ -112,7 +114,7 @@ class Indi_Pattern : public Indicator { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _shift = -1) { + virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _shift = 0) { _entry.SetFlag(INDI_ENTRY_FLAG_IS_BITWISE, true); Indicator::GetEntryAlter(_entry); } diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index d63e97b3a..2d9e905f8 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -35,15 +35,9 @@ double iAC(string _symbol, int _tf, int _shift) { // Structs. struct IndiACParams : IndicatorParams { // Struct constructor. - IndiACParams(int _shift = 0) : IndicatorParams(INDI_AC, 1, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_MIXED); + IndiACParams(int _shift = 0) : IndicatorParams(INDI_AC) { SetCustomIndicatorName("Examples\\Accelerator"); shift = _shift; - switch (idstype) { - case IDATA_ICUSTOM: - SetMaxModes(2); - break; - } }; IndiACParams(IndiACParams &_params, ENUM_TIMEFRAMES _tf) { THIS_REF = _params; @@ -54,13 +48,35 @@ struct IndiACParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_AC : public Indicator { +class Indi_AC : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { + case IDATA_ICUSTOM: + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); + break; + } + } + public: /** * Class constructor. */ - Indi_AC(IndiACParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_AC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_AC, _tf, _shift){}; + Indi_AC(IndiACParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { + Init(); + }; + Indi_AC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AC, _tf, _shift) { + Init(); + }; /** * Returns the indicator value. @@ -70,11 +86,12 @@ 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, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iAC(_symbol, _tf, _shift); #else // __MQL5__ - int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; + int _handle = + Object::IsValid(_obj) ? _obj.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_HANDLE)) : NULL; double _res[]; if (_handle == NULL || _handle == INVALID_HANDLE) { if ((_handle = ::iAC(_symbol, _tf)) == INVALID_HANDLE) { @@ -105,10 +122,10 @@ class Indi_AC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { IndicatorDataEntryValue _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_AC::iAC(GetSymbol(), GetTf(), _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index 31b21fec6..279f380c4 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -34,8 +34,7 @@ double iAD(string _symbol, int _tf, int _shift) { // Structs. struct IndiADParams : IndicatorParams { // Struct constructor. - IndiADParams(int _shift = 0) : IndicatorParams(INDI_AD, 1, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_MIXED); + IndiADParams(int _shift = 0) : IndicatorParams(INDI_AD) { SetCustomIndicatorName("Examples\\AD"); shift = _shift; }; @@ -48,13 +47,18 @@ struct IndiADParams : IndicatorParams { /** * Implements the Accumulation/Distribution indicator. */ -class Indi_AD : public Indicator { +class Indi_AD : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_AD(IndiADParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_AD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_AD, _tf, _shift) { + Indi_AD(IndiADParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_AD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AD, _tf, _shift) { iparams.SetTf(_tf); }; @@ -66,7 +70,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, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iAD(_symbol, _tf, _shift); #else // __MQL5__ @@ -101,10 +105,10 @@ class Indi_AD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_AD::iAD(GetSymbol(), GetTf(), _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index 7a4c33d75..527749bc7 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "Price/Indi_Price.mqh" #ifndef __MQL4__ @@ -39,17 +39,11 @@ struct IndiADXParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructors. IndiADXParams(unsigned int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) - : period(_period), applied_price(_ap), IndicatorParams(INDI_ADX, FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE) { - SetDataSourceType(_idstype); - SetDataValueRange(IDATA_RANGE_RANGE); + ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + : period(_period), applied_price(_ap), IndicatorParams(INDI_ADX) { SetShift(_shift); - switch (idstype) { - case IDATA_ICUSTOM: - if (custom_indi_name == "") { - SetCustomIndicatorName("Examples\\ADX"); - } - break; + if (custom_indi_name == "") { + SetCustomIndicatorName("Examples\\ADX"); } }; IndiADXParams(IndiADXParams &_params, ENUM_TIMEFRAMES _tf) { @@ -61,13 +55,27 @@ struct IndiADXParams : IndicatorParams { /** * Implements the Average Directional Movement Index indicator. */ -class Indi_ADX : public Indicator { +class Indi_ADX : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + void Init() {} + public: /** * Class constructor. */ - Indi_ADX(IndiADXParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_ADX(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_ADX, _tf, _shift) {} + Indi_ADX(IndiADXParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_ADX(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_ADX, _tf, _shift) { + Init(); + } /** * Returns the indicator value. @@ -80,7 +88,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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iADX(_symbol, _tf, _period, _applied_price, _mode, _shift); #else // __MQL5__ @@ -115,10 +123,10 @@ class Indi_ADX : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_ADX::iADX(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _mode, _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 2b7a1b644..74f1c1f89 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.h" #include "../Storage/ValueStorage.price.h" #include "../Storage/ValueStorage.spread.h" @@ -37,13 +37,11 @@ struct IndiADXWParams : IndiADXParams { // Struct constructor. IndiADXWParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0, - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN) - : IndiADXParams(_period, _ap, _shift, _tf, _idstype) { + ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) + : IndiADXParams(_period, _ap, _shift, _tf) { itype = itype == INDI_NONE || itype == INDI_ADX ? INDI_ADXW : itype; - switch (idstype) { - case IDATA_ICUSTOM: - SetCustomIndicatorName("Examples\\ADXW"); - break; + if (custom_indi_name == "") { + SetCustomIndicatorName("Examples\\ADXW"); } }; IndiADXWParams(IndiADXWParams &_params, ENUM_TIMEFRAMES _tf) { @@ -55,19 +53,25 @@ struct IndiADXWParams : IndiADXParams { /** * Implements the Average Directional Movement Index indicator by Welles Wilder. */ -class Indi_ADXW : public Indicator { +class Indi_ADXW : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_ADXW(IndiADXWParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_ADXW(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_ADXW, _tf, _shift){}; + Indi_ADXW(IndiADXWParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_ADX_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src){}; + Indi_ADXW(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_ADXW, _tf, _shift){}; /** * 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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iADXWilder(_symbol, _tf, _ma_period), _mode, _shift); #else @@ -102,6 +106,16 @@ class Indi_ADXW : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of ADX Wilder. + */ + static double iADXWilderOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, Util::MakeKey("Indi_ADXW_ON_" + _indi.GetFullName(), _period)); + return iADXWilderOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, _shift, _cache); + } + /** * OnCalculate() method for ADXW indicator. */ @@ -215,10 +229,10 @@ class Indi_ADXW : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_ADXW::iADXWilder(GetSymbol(), GetTf(), GetPeriod(), _mode, _ishift, THIS_PTR); break; @@ -226,6 +240,10 @@ class Indi_ADXW : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, _mode, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_ADXW::iADXWilderOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod() /*]*/, _mode, + _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index 58a8bee10..fa0428199 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -22,7 +22,8 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" +#include "../Indicator/tests/classes/IndicatorTfDummy.h" #include "../Storage/ValueStorage.h" #include "../Storage/ValueStorage.price.h" #include "Price/Indi_Price.mqh" @@ -36,53 +37,54 @@ struct IndiAMAParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructor. 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_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) : period(_period), fast_period(_fast_period), slow_period(_slow_period), ama_shift(_ama_shift), - applied_price(_ap), - IndicatorParams(INDI_AMA, 1, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_PRICE); + applied_price(_ap) { + // Defaulting to on-indicator mode (will use real ticks from platform via IndicatorTickReal). SetShift(_shift); - switch (idstype) { - case IDATA_ICUSTOM: - if (custom_indi_name == "") { - SetCustomIndicatorName("Examples\\AMA"); - } - break; + if (custom_indi_name == "") { + SetCustomIndicatorName("Examples\\AMA"); } }; IndiAMAParams(IndiAMAParams &_params, ENUM_TIMEFRAMES _tf) { THIS_REF = _params; tf = _tf; - }; + } }; /** * Implements the AMA indicator. */ -class Indi_AMA : public Indicator { +class Indi_AMA : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_AMA(IndiAMAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_AMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_AMA, _tf, _shift){}; + Indi_AMA(IndiAMAParams &_p, int _indi_mode = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src, _indi_mode) { + iparams.SetIndicatorType(INDI_AMA); + }; + Indi_AMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AMA, _tf, _shift){}; /** * 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, - IndicatorBase *_obj = NULL) { + IndicatorData *_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); #else INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT( _symbol, _tf, _ap, - Util::MakeKey("INDI_AMA", _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, (int)_ap)); + Util::MakeKey("Indi_AMA", _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, (int)_ap)); return iAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, _mode, _shift, _cache); #endif @@ -110,6 +112,20 @@ class Indi_AMA : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of AMA. + */ + static double iAMAOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ama_period, + int _fast_ema_period, int _slow_ema_period, int _ama_shift, ENUM_APPLIED_PRICE _ap, + int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS_SPECIFIC( + _indi, _symbol, _tf, _ap, + Util::MakeKey("Indi_AMA_ON_" + _indi.GetFullName(), _ama_period, _fast_ema_period, _slow_ema_period, _ama_shift, + (int)_ap)); + return iAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ama_period, _fast_ema_period, _slow_ema_period, + _ama_shift, _mode, _shift, _cache); + } + /** * OnInit() method for AMA indicator. */ @@ -158,6 +174,13 @@ class Indi_AMA : public Indicator { CalculateInit(InpPeriodAMA, InpFastPeriodEMA, InpSlowPeriodEMA, InpShiftAMA, ExtFastSC, ExtSlowSC, ExtPeriodAMA, ExtSlowPeriodEMA, ExtFastPeriodEMA); +#ifdef __debug__ + for (int x = prev_calculated; x < rates_total; ++x) { + Print("price[", x, "] = ", price[x].Get(), + ", O = ", iOpen(Symbol(), PERIOD_CURRENT, Bars(Symbol(), PERIOD_CURRENT) - x - 1)); + } +#endif + int i; // Check for rates count. if (rates_total < ExtPeriodAMA + begin) return (0); @@ -199,10 +222,10 @@ class Indi_AMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_AMA::iAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), GetAMAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); @@ -213,8 +236,9 @@ class Indi_AMA : public Indicator { break; case IDATA_INDICATOR: - // @todo - SetUserError(ERR_INVALID_PARAMETER); + _value = Indi_AMA::iAMAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), + GetSlowPeriod(), GetAMAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, + THIS_PTR); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -222,6 +246,20 @@ class Indi_AMA : public Indicator { return _value; } + /** + * Called when data source emits new entry (historic or future one). + */ + void OnDataSourceEntry(IndicatorDataEntry &entry) override { + // Just to be able to make a breakpoint here. + int x = 4; + }; + + /** + * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on + * some data source. + */ + virtual IndicatorData *OnDataSourceRequest() { return DataSourceRequestReturnDefault(GetAppliedPrice()); } + /* Getters */ /** diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index 2d1b1f8de..783e48562 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -34,11 +34,7 @@ double iAO(string _symbol, int _tf, int _shift) { // Structs. struct IndiAOParams : IndicatorParams { // Struct constructor. - IndiAOParams(int _shift = 0) : IndicatorParams(INDI_AO, 2, TYPE_DOUBLE) { -#ifdef __MQL4__ - max_modes = 1; -#endif - SetDataValueRange(IDATA_RANGE_MIXED); + IndiAOParams(int _shift = 0) : IndicatorParams(INDI_AO) { SetCustomIndicatorName("Examples\\Awesome_Oscillator"); shift = _shift; }; @@ -51,13 +47,35 @@ struct IndiAOParams : IndicatorParams { /** * Implements the Awesome oscillator. */ -class Indi_AO : public Indicator { +class Indi_AO : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { +#ifdef __MQL4__ + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 1); +#else + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); +#endif + } + public: /** * Class constructor. */ - Indi_AO(IndiAOParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_AO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_AO, _tf, _shift){}; + Indi_AO(IndiAOParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { + Init(); + }; + Indi_AO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AO, _tf, _shift) { + Init(); + }; /** * Returns the indicator value. @@ -67,7 +85,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, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL4__ // Note: In MQL4 _mode is not supported. return ::iAO(_symbol, _tf, _shift); @@ -103,10 +121,10 @@ class Indi_AO : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_AO::iAO(GetSymbol(), GetTf(), _ishift, _mode, THIS_PTR); break; diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index 2e0cf341b..d520cfb5d 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. @@ -30,9 +30,7 @@ struct IndiASIParams : IndicatorParams { unsigned int period; double mpc; // Struct constructor. - IndiASIParams(double _mpc = 300.0, int _shift = 0) - : IndicatorParams(INDI_ASI, 1, TYPE_DOUBLE, PERIOD_CURRENT, IDATA_ONCALCULATE) { - SetDataValueRange(IDATA_RANGE_MIXED); + IndiASIParams(double _mpc = 300.0, int _shift = 0) : IndicatorParams(INDI_ASI, PERIOD_CURRENT) { SetCustomIndicatorName("Examples\\ASI"); mpc = _mpc; shift = _shift; @@ -46,19 +44,39 @@ struct IndiASIParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_ASI : public Indicator { +class Indi_ASI : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { + if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_BUILTIN) { + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_ONCALCULATE); + } + } + public: /** * Class constructor. */ - Indi_ASI(IndiASIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_ASI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_ASI, _tf, _shift){}; + Indi_ASI(IndiASIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_ONCALCULATE, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { + Init(); + }; + Indi_ASI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_ASI, _tf, _shift) { + Init(); + }; /** * Built-in version of ASI. */ static double iASI(string _symbol, ENUM_TIMEFRAMES _tf, double _mpc, int _mode = 0, int _shift = 0, - IndicatorBase *_obj = NULL) { + IndicatorData *_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); } @@ -84,6 +102,16 @@ class Indi_ASI : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of ASI. + */ + static double iASIOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, double _mpc, int _mode = 0, + int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, + Util::MakeKey("Indi_ASI_ON_" + _indi.GetFullName(), _mpc)); + return iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mpc, _mode, _shift, _cache); + } + /** * OnInit() method for ASI indicator. */ @@ -155,10 +183,10 @@ class Indi_ASI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetMaximumPriceChanging() /*]*/, 0, _ishift); @@ -168,8 +196,11 @@ class Indi_ASI : public Indicator { Util::MakeKey("Indi_ASI", GetMaximumPriceChanging())); _value = iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, GetMaximumPriceChanging(), _mode, _ishift, _cache); + } break; + case IDATA_INDICATOR: + _value = Indi_ASI::iASIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetMaximumPriceChanging() /*]*/, + _mode, _ishift, THIS_PTR); break; - } default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index 63a0e4889..37641e945 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -35,10 +35,8 @@ double iATR(string _symbol, int _tf, int _period, int _shift) { struct IndiATRParams : IndicatorParams { unsigned int period; // Struct constructors. - IndiATRParams(unsigned int _period = 14, int _shift = 0) - : period(_period), IndicatorParams(INDI_ATR, 1, TYPE_DOUBLE) { + IndiATRParams(unsigned int _period = 14, int _shift = 0) : period(_period), IndicatorParams(INDI_ATR) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ATR"); }; IndiATRParams(IndiATRParams &_params, ENUM_TIMEFRAMES _tf) { @@ -52,13 +50,17 @@ struct IndiATRParams : 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 IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_ATR(IndiATRParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_ATR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_ATR, _tf, _shift){}; + Indi_ATR(IndiATRParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_ATR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_ATR, _tf, _shift){}; /** * Returns the indicator value. @@ -68,7 +70,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, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iATR(_symbol, _tf, _period, _shift); #else // __MQL5__ @@ -103,10 +105,10 @@ class Indi_ATR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_ATR::iATR(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index 3118ea4cb..c2f1b7532 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -81,9 +81,8 @@ struct IndiAlligatorParams : IndicatorParams { lips_shift(_ls), ma_method(_mm), applied_price(_ap), - IndicatorParams(INDI_ALLIGATOR, FINAL_ALLIGATOR_LINE_ENTRY, TYPE_DOUBLE) { + IndicatorParams(INDI_ALLIGATOR) { shift = _shift; - SetDataValueRange(IDATA_RANGE_PRICE); SetCustomIndicatorName("Examples\\Alligator"); }; IndiAlligatorParams(IndiAlligatorParams &_params, ENUM_TIMEFRAMES _tf) { @@ -95,14 +94,18 @@ struct IndiAlligatorParams : IndicatorParams { /** * Implements the Alligator indicator. */ -class Indi_Alligator : public Indicator { +class Indi_Alligator : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_Alligator(IndiAlligatorParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_Alligator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_ADX, _tf, _shift){}; + Indi_Alligator(IndiAlligatorParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(FINAL_ALLIGATOR_LINE_ENTRY, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE), + _indi_src, _indi_src_mode) {} + Indi_Alligator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_ADX, _tf, _shift){}; /** * Returns the indicator value. @@ -125,7 +128,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, - IndicatorBase *_obj = NULL) { + IndicatorData *_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); @@ -162,7 +165,7 @@ class Indi_Alligator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); #ifdef __MQL4__ @@ -171,7 +174,7 @@ class Indi_Alligator : public Indicator { return GetEntryValue((ENUM_ALLIGATOR_LINE)1, _ishift); } #endif - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Alligator::iAlligator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), diff --git a/Indicators/Indi_AppliedPrice.mqh b/Indicators/Indi_AppliedPrice.mqh index 379596331..82a8399a9 100644 --- a/Indicators/Indi_AppliedPrice.mqh +++ b/Indicators/Indi_AppliedPrice.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "OHLC/Indi_OHLC.mqh" // Structs. @@ -30,9 +30,7 @@ struct IndiAppliedPriceParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructor. IndiAppliedPriceParams(ENUM_APPLIED_PRICE _applied_price = PRICE_OPEN, int _shift = 0) - : applied_price(_applied_price), IndicatorParams(INDI_APPLIED_PRICE, 1, TYPE_DOUBLE) { - SetDataSourceType(IDATA_INDICATOR); - SetDataValueRange(IDATA_RANGE_PRICE); + : applied_price(_applied_price), IndicatorParams(INDI_APPLIED_PRICE) { shift = _shift; }; IndiAppliedPriceParams(IndiAppliedPriceParams &_params, ENUM_TIMEFRAMES _tf) { @@ -44,7 +42,7 @@ struct IndiAppliedPriceParams : IndicatorParams { /** * Implements the "Applied Price over OHCL Indicator" indicator, e.g. over Indi_Price. */ -class Indi_AppliedPrice : public Indicator { +class Indi_AppliedPrice : public IndicatorTickOrCandleSource { protected: void OnInit() { if (!indi_src.IsSet()) { @@ -57,15 +55,19 @@ class Indi_AppliedPrice : public Indicator { /** * Class constructor. */ - Indi_AppliedPrice(IndiAppliedPriceParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) { + Indi_AppliedPrice(IndiAppliedPriceParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_INDICATOR, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { OnInit(); }; - Indi_AppliedPrice(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_PRICE, _tf, _shift) { + Indi_AppliedPrice(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_PRICE, _tf, _shift) { OnInit(); }; - static double iAppliedPriceOnIndicator(IndicatorBase *_indi, ENUM_APPLIED_PRICE _applied_price, int _shift = 0) { + static double iAppliedPriceOnIndicator(IndicatorData *_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]); @@ -74,15 +76,15 @@ class Indi_AppliedPrice : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_INDICATOR: if (HasDataSource()) { // Future validation of indi_src will check if we set mode for source indicator // (e.g. for applied price of Indi_Price). - iparams.SetDataSourceMode(GetAppliedPrice()); + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE), GetAppliedPrice()); _value = Indi_AppliedPrice::iAppliedPriceOnIndicator(GetDataSource(), GetAppliedPrice(), _ishift); } break; @@ -101,7 +103,7 @@ class Indi_AppliedPrice : public Indicator { */ virtual bool IsValidEntry(IndicatorDataEntry &_entry) { bool _is_valid = Indicator::IsValidEntry(_entry); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_INDICATOR: if (!HasDataSource()) { GetLogger().Error("Indi_AppliedPrice requires source indicator to be set via SetDataSource()!"); diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index dcfd02fec..a0c71f4f7 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -48,8 +48,7 @@ enum ENUM_MFI_COLOR { struct IndiBWIndiMFIParams : IndicatorParams { ENUM_APPLIED_VOLUME ap; // @todo // Struct constructors. - IndiBWIndiMFIParams(int _shift = 0) : IndicatorParams(INDI_BWMFI, FINAL_BWMFI_BUFFER_ENTRY, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_MIXED); + IndiBWIndiMFIParams(int _shift = 0) : IndicatorParams(INDI_BWMFI) { shift = _shift; SetCustomIndicatorName("Examples\\MarketFacilitationIndex"); }; @@ -62,14 +61,31 @@ struct IndiBWIndiMFIParams : IndicatorParams { /** * Implements the Market Facilitation Index by Bill Williams indicator. */ -class Indi_BWMFI : public Indicator { +class Indi_BWMFI : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_BWMFI_BUFFER_ENTRY); } + public: /** * Class constructor. */ - Indi_BWMFI(IndiBWIndiMFIParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_BWMFI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_BWMFI, _tf, _shift) {} + Indi_BWMFI(IndiBWIndiMFIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_BWMFI_BUFFER_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_BWMFI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_BWMFI, _tf, _shift) { + Init(); + } /** * Returns the indicator value. @@ -79,7 +95,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, IndicatorBase *_obj = NULL) { + ENUM_BWMFI_BUFFER _mode = BWMFI_BUFFER, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iBWMFI(_symbol, _tf, _shift); #else // __MQL5__ @@ -114,10 +130,12 @@ class Indi_BWMFI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = BWMFI_BUFFER, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = BWMFI_BUFFER, int _shift = 0) { + int _ishift = iparams.GetShift() + _shift; + double _value = EMPTY_VALUE; - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_BWMFI::iBWMFI(GetSymbol(), GetTf(), _ishift, (ENUM_BWMFI_BUFFER)_mode, THIS_PTR); break; @@ -135,7 +153,7 @@ class Indi_BWMFI : public Indicator { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = -1) { + virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { Indicator::GetEntryAlter(_entry); #ifdef __MQL4__ // @see: https://en.wikipedia.org/wiki/Market_facilitation_index diff --git a/Indicators/Indi_BWZT.mqh b/Indicators/Indi_BWZT.mqh index 65d7cb881..34a3f0df9 100644 --- a/Indicators/Indi_BWZT.mqh +++ b/Indicators/Indi_BWZT.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTf.h" #include "../Storage/ValueStorage.all.h" #include "Indi_AC.mqh" #include "Indi_AO.mqh" @@ -40,12 +40,15 @@ enum ENUM_INDI_BWZT_MODE { // Structs. struct IndiBWZTParams : IndicatorParams { + Ref indi_ac; + Ref indi_ao; unsigned int period; unsigned int second_period; unsigned int sum_period; // Struct constructor. - IndiBWZTParams(int _shift = 0) : IndicatorParams(INDI_BWZT, FINAL_INDI_BWZT_MODE_ENTRY, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_MIXED); + IndiBWZTParams(int _shift = 0) : IndicatorParams(INDI_BWZT) { + indi_ac = NULL; + indi_ao = NULL; SetCustomIndicatorName("Examples\\BW-ZoneTrade"); shift = _shift; }; @@ -58,18 +61,36 @@ struct IndiBWZTParams : IndicatorParams { /** * Implements the Bill Williams' Zone Trade. */ -class Indi_BWZT : public Indicator { +class Indi_BWZT : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_INDI_BWZT_MODE_ENTRY); } + public: /** * Class constructor. */ - Indi_BWZT(IndiBWZTParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_BWZT(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_BWZT, _tf, _shift){}; + Indi_BWZT(IndiBWZTParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_BWZT_MODE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { + Init(); + }; + Indi_BWZT(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_BWZT, _tf, _shift) { + Init(); + }; /** * Built-in version of BWZT. */ - static double iBWZT(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { + static double iBWZT(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_BWZT"); Indi_AC *_indi_ac = Indi_AC::GetCached(_symbol, _tf); @@ -102,6 +123,34 @@ class Indi_BWZT : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of BWZT. + */ + static double iBWZTOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode, int _shift, + IndicatorData *_obj) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, + Util::MakeKey("Indi_BWZT_ON_" + _indi.GetFullName())); + + Indi_AC *_indi_ac = _obj.GetDataSource(INDI_AC); + Indi_AO *_indi_ao = _obj.GetDataSource(INDI_AO); + + return iBWZTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache, _indi_ac, _indi_ao); + } + + /** + * Provides built-in indicators whose can be used as data source. + */ + virtual IndicatorData *FetchDataSource(ENUM_INDICATOR_TYPE _id) override { + switch (_id) { + case INDI_AC: + return iparams.indi_ac.Ptr(); + case INDI_AO: + return iparams.indi_ao.Ptr(); + } + + return NULL; + } + /** * OnCalculate() method for BWZT indicator. */ @@ -109,7 +158,7 @@ class Indi_BWZT : public Indicator { ValueStorage &ExtHBuffer, ValueStorage &ExtLBuffer, ValueStorage &ExtCBuffer, ValueStorage &ExtColorBuffer, ValueStorage &ExtAOBuffer, ValueStorage &ExtACBuffer, int DATA_LIMIT, - IndicatorBase *ExtACHandle, IndicatorBase *ExtAOHandle) { + IndicatorData *ExtACHandle, IndicatorData *ExtAOHandle) { if (rates_total < DATA_LIMIT) return (0); // Not all data may be calculated. int calculated = BarsCalculated(ExtACHandle); @@ -172,16 +221,19 @@ class Indi_BWZT : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_BWZT::iBWZT(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_BWZT::iBWZTOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); break; diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index cd46212f3..440158315 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "Indi_CCI.mqh" #include "Indi_Envelopes.mqh" #include "Indi_MA.mqh" @@ -68,13 +68,8 @@ struct IndiBandsParams : IndicatorParams { // Struct constructors. IndiBandsParams(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) { + : period(_period), deviation(_deviation), bshift(_bshift), applied_price(_ap), IndicatorParams(INDI_BANDS) { shift = _shift; - SetDataValueRange(IDATA_RANGE_PRICE); SetCustomIndicatorName("Examples\\BB"); }; IndiBandsParams(IndiBandsParams &_params, ENUM_TIMEFRAMES _tf) { @@ -86,14 +81,30 @@ struct IndiBandsParams : IndicatorParams { /** * Implements the Bollinger Bands® indicator. */ -class Indi_Bands : public Indicator { +class Indi_Bands : public IndicatorTickSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_BANDS_LINE_ENTRY); } + public: /** * Class constructor. */ - Indi_Bands(IndiBandsParams &_p, IndicatorBase *_indi_src = NULL, int _mode = 0) - : Indicator(_p, _indi_src, _mode) {} - Indi_Bands(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_BANDS, _tf, _shift) {} + Indi_Bands(IndiBandsParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickSource(_p, + IndicatorDataParams::GetInstance(FINAL_BANDS_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_Bands(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_BANDS, _tf, _shift) { + Init(); + } /** * Returns the indicator value. @@ -104,7 +115,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, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iBands(_symbol, _tf, _period, _deviation, _bands_shift, _applied_price, _mode, _shift); #else // __MQL5__ @@ -141,7 +152,7 @@ class Indi_Bands : public Indicator { * * When _applied_price is set to -1, method will */ - static double iBandsOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, + static double iBandsOnIndicator(IndicatorData *_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 @@ -156,7 +167,9 @@ class Indi_Bands : public Indicator { int current_shift = _shift + (i - _bands_shift); // Getting current indicator value. _indi_value_buffer[i - _bands_shift] = - _indi[i - _bands_shift].values[_target != NULL ? _target.GetDataSourceMode() : 0].Get(); + _indi[i - _bands_shift] + .values[_target != NULL ? _target.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)) : 0] + .Get(); } // Base band. @@ -239,10 +252,10 @@ class Indi_Bands : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = BAND_BASE, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = BAND_BASE, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Bands::iBands(GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, _ishift, THIS_PTR); @@ -271,7 +284,7 @@ class Indi_Bands : public Indicator { /** * Provides built-in indicators whose can be used as data source. */ - virtual IndicatorBase *FetchDataSource(ENUM_INDICATOR_TYPE _id) { + virtual IndicatorData *FetchDataSource(ENUM_INDICATOR_TYPE _id) { if (_id == INDI_BANDS) { IndiBandsParams bands_params(); return new Indi_Bands(bands_params); @@ -295,7 +308,7 @@ class Indi_Bands : public Indicator { return new Indi_StdDev(stddev_params); } - return IndicatorBase::FetchDataSource(_id); + return IndicatorData::FetchDataSource(_id); } /* Getters */ diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index e4f3ac5af..edaa5cdd6 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -37,9 +37,8 @@ struct IndiBearsPowerParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructors. IndiBearsPowerParams(unsigned int _period = 13, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) - : period(_period), applied_price(_ap), IndicatorParams(INDI_BEARS, 1, TYPE_DOUBLE) { + : period(_period), applied_price(_ap), IndicatorParams(INDI_BEARS) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Bears"); }; IndiBearsPowerParams(IndiBearsPowerParams &_params, ENUM_TIMEFRAMES _tf) { @@ -51,14 +50,18 @@ struct IndiBearsPowerParams : IndicatorParams { /** * Implements the Bears Power indicator. */ -class Indi_BearsPower : public Indicator { +class Indi_BearsPower : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_BearsPower(IndiBearsPowerParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_BearsPower(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_BEARS, _tf, _shift) {} + Indi_BearsPower(IndiBearsPowerParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_BearsPower(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_BEARS, _tf, _shift) {} /** * Returns the indicator value. @@ -69,7 +72,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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iBearsPower(_symbol, _tf, _period, _applied_price, _shift); #else // __MQL5__ @@ -104,10 +107,10 @@ class Indi_BearsPower : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = _value = iBearsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index 1baf044a9..dfbc27119 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -37,9 +37,8 @@ struct IndiBullsPowerParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // (MT5): not used // Struct constructor. IndiBullsPowerParams(unsigned int _period = 13, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) - : period(_period), applied_price(_ap), IndicatorParams(INDI_BULLS, 1, TYPE_DOUBLE) { + : period(_period), applied_price(_ap), IndicatorParams(INDI_BULLS) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Bulls"); }; IndiBullsPowerParams(IndiBullsPowerParams &_params, ENUM_TIMEFRAMES _tf) { @@ -51,14 +50,18 @@ struct IndiBullsPowerParams : IndicatorParams { /** * Implements the Bulls Power indicator. */ -class Indi_BullsPower : public Indicator { +class Indi_BullsPower : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_BullsPower(IndiBullsPowerParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_BullsPower(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_BULLS, _tf, _shift) {} + Indi_BullsPower(IndiBullsPowerParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_BullsPower(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_BULLS, _tf, _shift) {} /** * Returns the indicator value. @@ -69,7 +72,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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iBullsPower(_symbol, _tf, _period, _applied_price, _shift); #else // __MQL5__ @@ -104,10 +107,10 @@ class Indi_BullsPower : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = iBullsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index 210bb8ea6..57775a615 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickSource.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" #include "Price/Indi_Price.mqh" @@ -44,9 +44,8 @@ struct IndiCCIParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructors. IndiCCIParams(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) { + : period(_period), applied_price(_applied_price), IndicatorParams(INDI_CCI) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\CCI"); }; IndiCCIParams(IndiCCIParams &_params, ENUM_TIMEFRAMES _tf) { @@ -58,13 +57,17 @@ struct IndiCCIParams : IndicatorParams { /** * Implements the Commodity Channel Index indicator. */ -class Indi_CCI : public Indicator { +class Indi_CCI : public IndicatorTickSource { public: /** * Class constructor. */ - Indi_CCI(IndiCCIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_CCI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_CCI, _tf, _shift) {} + Indi_CCI(IndiCCIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_CCI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_CCI, _tf, _shift) {} /** * Returns the indicator value. @@ -74,7 +77,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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iCCI(_symbol, _tf, _period, _applied_price, _shift); #else // __MQL5__ @@ -82,7 +85,7 @@ class Indi_CCI : public Indicator { #endif } - static double iCCIOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, + static double iCCIOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, int _mode, int _shift = 0) { _indi.ValidateDataSourceMode(_mode); @@ -145,10 +148,10 @@ class Indi_CCI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); double _value = EMPTY_VALUE; - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_CCI::iCCI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift /* + iparams.shift*/, @@ -162,7 +165,8 @@ class Indi_CCI : public Indicator { ValidateSelectedDataSource(); // @fixit Somehow shift isn't used neither in MT4 nor MT5. - _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDataSourceMode(), + _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), + Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)), _ishift /* + iparams.shift*/); break; } diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index 1cf24699e..1e05734b0 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" #include "../Util.h" #include "Indi_MA.mqh" @@ -36,10 +36,9 @@ struct IndiCHOParams : IndicatorParams { // Struct constructor. IndiCHOParams(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) { + : IndicatorParams(INDI_CHAIKIN) { fast_ma = _fast_ma; input_volume = _input_volume; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\CHO"); shift = _shift; slow_ma = _slow_ma; @@ -54,26 +53,31 @@ struct IndiCHOParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_CHO : public Indicator { +class Indi_CHO : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_CHO(IndiCHOParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_CHO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_CHAIKIN, _tf, _shift){}; + Indi_CHO(IndiCHOParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_CHO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_CHAIKIN, _tf, _shift){}; /** * 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, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iChaikin(_symbol, _tf, _fast_ma_period, _slow_ma_period, _ma_method, _av), _mode, _shift); #else INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( - _symbol, _tf, Util::MakeKey("INDI_CHO", _fast_ma_period, _slow_ma_period, (int)_ma_method, (int)_av)); + _symbol, _tf, Util::MakeKey("Indi_CHO", _fast_ma_period, _slow_ma_period, (int)_ma_method, (int)_av)); return iChaikinOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _fast_ma_period, _slow_ma_period, _ma_method, _av, _mode, _shift, _cache); #endif @@ -102,6 +106,20 @@ class Indi_CHO : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Chaikin Oscillator. + */ + static double iChaikinOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _fast_ma_period, + int _slow_ma_period, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_VOLUME _av, + int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, + Util::MakeKey("Indi_CHO_ON_" + _indi.GetFullName(), _fast_ma_period, _slow_ma_period, (int)_ma_method, + (int)_av)); + return iChaikinOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _fast_ma_period, _slow_ma_period, _ma_method, _av, + _mode, _shift, _cache); + } + /** * OnCalculate() method for Chaikin Oscillator indicator. */ @@ -166,10 +184,10 @@ class Indi_CHO : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_CHO::iChaikin(GetSymbol(), GetTf(), /*[*/ GetSlowMA(), GetFastMA(), GetSmoothMethod(), GetInputVolume() /*]*/, _mode, _ishift, THIS_PTR); @@ -178,6 +196,10 @@ class Indi_CHO : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastMA(), GetSlowMA(), GetSmoothMethod(), GetInputVolume() /*]*/, 0, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_CHO::iChaikinOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetFastMA(), GetSlowMA(), + GetSmoothMethod(), GetInputVolume() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index d3f97fd42..9d514d3f7 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" #include "../Util.h" #include "Indi_MA.mqh" @@ -38,9 +38,8 @@ struct IndiCHVParams : IndicatorParams { // Struct constructor. IndiCHVParams(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) { + : IndicatorParams(INDI_CHAIKIN_V) { chv_period = _chv_period; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\CHV"); shift = _shift; smooth_method = _smooth_method; @@ -55,19 +54,24 @@ struct IndiCHVParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_CHV : public Indicator { +class Indi_CHV : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_CHV(IndiCHVParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_CHV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_CHAIKIN_V, _tf, _shift){}; + Indi_CHV(IndiCHVParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_CHV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_CHAIKIN_V, _tf, _shift){}; /** * 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, IndicatorBase *_obj = NULL) { + ENUM_CHV_SMOOTH_METHOD _smooth_method, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( _symbol, _tf, Util::MakeKey("Indi_CHV", _smooth_period, _chv_period, _smooth_method)); return iCHVOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _smooth_period, _chv_period, _smooth_method, _mode, @@ -99,6 +103,19 @@ class Indi_CHV : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Chaikin Volatility. + */ + static double iCHVOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _smooth_period, + int _chv_period, ENUM_CHV_SMOOTH_METHOD _smooth_method, int _mode = 0, int _shift = 0, + IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, + Util::MakeKey("Indi_CHV_ON_" + _indi.GetFullName(), _smooth_period, _chv_period, _smooth_method)); + return iCHVOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _smooth_period, _chv_period, _smooth_method, _mode, + _shift, _cache); + } + /** * OnInit() method for Chaikin Volatility indicator. */ @@ -162,10 +179,10 @@ class Indi_CHV : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_CHV::iCHV(GetSymbol(), GetTf(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _ishift, THIS_PTR); @@ -174,6 +191,10 @@ class Indi_CHV : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_CHV::iCHVOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetSmoothPeriod(), + GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index f89773c19..cb920a588 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -22,14 +22,13 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. struct IndiColorBarsParams : IndicatorParams { // Struct constructor. - IndiColorBarsParams(int _shift = 0) : IndicatorParams(INDI_COLOR_BARS, 5, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_MIXED); + IndiColorBarsParams(int _shift = 0) : IndicatorParams(INDI_COLOR_BARS) { SetCustomIndicatorName("Examples\\ColorBars"); shift = _shift; }; @@ -42,21 +41,25 @@ struct IndiColorBarsParams : IndicatorParams { /** * Implements Color Bars */ -class Indi_ColorBars : public Indicator { +class Indi_ColorBars : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_ColorBars(IndiColorBarsParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; - Indi_ColorBars(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_COLOR_BARS, _tf, _shift){}; + Indi_ColorBars(IndiColorBarsParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(5, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_ColorBars(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_COLOR_BARS, _tf, _shift){}; /** * "Built-in" version of Color Bars. */ 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"); + IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_ColorBars"); return iColorBarsOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -82,6 +85,16 @@ class Indi_ColorBars : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Color Bars. + */ + static double iColorBarsOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, + int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, + Util::MakeKey("Indi_ColorBars_ON_" + _indi.GetFullName())); + return iColorBarsOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); + } + /** * OnCalculate() method for Color Bars indicator. */ @@ -113,16 +126,19 @@ class Indi_ColorBars : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_ColorBars::iColorBars(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_ColorBars::iColorBarsOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); break; diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index b8c4b851c..e848eb6f0 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -22,14 +22,13 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. struct IndiColorCandlesDailyParams : IndicatorParams { // Struct constructor. - IndiColorCandlesDailyParams(int _shift = 0) : IndicatorParams(INDI_COLOR_CANDLES_DAILY, 5, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_MIXED); + IndiColorCandlesDailyParams(int _shift = 0) : IndicatorParams(INDI_COLOR_CANDLES_DAILY) { SetCustomIndicatorName("Examples\\ColorCandlesDaily"); shift = _shift; }; @@ -42,20 +41,23 @@ struct IndiColorCandlesDailyParams : IndicatorParams { /** * Implements Color Bars */ -class Indi_ColorCandlesDaily : public Indicator { +class Indi_ColorCandlesDaily : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_ColorCandlesDaily(IndiColorCandlesDailyParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; + Indi_ColorCandlesDaily(IndiColorCandlesDailyParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(5, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; Indi_ColorCandlesDaily(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : Indicator(INDI_COLOR_CANDLES_DAILY, _tf, _shift){}; + : IndicatorTickOrCandleSource(INDI_COLOR_CANDLES_DAILY, _tf, _shift){}; /** * "Built-in" version of Color Candles Daily. */ - static double iCCD(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { + static double iCCD(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_ColorCandlesDaily"); return iCCDOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -82,6 +84,16 @@ class Indi_ColorCandlesDaily : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Color Candles Daily. + */ + static double iCCDOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, + int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, Util::MakeKey("Indi_ColorCandlesDaily_ON_" + _indi.GetFullName())); + return iCCDOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); + } + /** * OnCalculate() method for Color Candles Daily indicator. */ @@ -110,16 +122,20 @@ class Indi_ColorCandlesDaily : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_ColorCandlesDaily::iCCD(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; + case IDATA_INDICATOR: + _value = + Indi_ColorCandlesDaily::iCCDOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index d3dd60ed7..a8f2b30bd 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -22,15 +22,16 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" #include "Indi_MA.mqh" // Structs. struct IndiColorLineParams : IndicatorParams { + IndicatorData *indi_ma; // Struct constructor. - IndiColorLineParams(int _shift = 0) : IndicatorParams(INDI_COLOR_LINE, 2, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_MIXED); + IndiColorLineParams(int _shift = 0) : IndicatorParams(INDI_COLOR_LINE) { + indi_ma = NULL; SetCustomIndicatorName("Examples\\ColorLine"); shift = _shift; }; @@ -43,20 +44,24 @@ struct IndiColorLineParams : IndicatorParams { /** * Implements Color Bars */ -class Indi_ColorLine : public Indicator { +class Indi_ColorLine : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_ColorLine(IndiColorLineParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; - Indi_ColorLine(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_COLOR_LINE, _tf, _shift){}; + Indi_ColorLine(IndiColorLineParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_ColorLine(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_COLOR_LINE, _tf, _shift){}; /** * "Built-in" version of Color Line. */ static double iColorLine(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_ColorLine"); Indi_MA *_indi_ma = Indi_MA::GetCached(_symbol, _tf, 10, 0, MODE_EMA, PRICE_CLOSE); @@ -68,7 +73,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, IndicatorBase *_indi_ma, + IndicatorCalculateCache *_cache, IndicatorData *_indi_ma, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -86,11 +91,35 @@ class Indi_ColorLine : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Color Line. + */ + static double iColorLineOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, + int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, + Util::MakeKey("Indi_ColorLine_ON_" + _indi.GetFullName())); + + Indi_MA *_indi_ma = _obj.GetDataSource(INDI_MA); + + return iColorLineOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache, _indi_ma); + } + + /** + * Provides built-in indicators whose can be used as data source. + */ + virtual IndicatorData *FetchDataSource(ENUM_INDICATOR_TYPE _id) override { + switch (_id) { + case INDI_MA: + return iparams.indi_ma; + } + return NULL; + } + /** * OnCalculate() method for Color Line indicator. */ static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &ExtColorLineBuffer, - ValueStorage &ExtColorsBuffer, IndicatorBase *ExtMAHandle) { + ValueStorage &ExtColorsBuffer, IndicatorData *ExtMAHandle) { static int ticks = 0, modified = 0; // Check data. int i, calculated = BarsCalculated(ExtMAHandle); @@ -172,16 +201,19 @@ class Indi_ColorLine : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_ColorLine::iColorLine(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_ColorLine::iColorLineOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_CustomMovingAverage.mqh b/Indicators/Indi_CustomMovingAverage.mqh index 7d83ee7dc..8e4b16e43 100644 --- a/Indicators/Indi_CustomMovingAverage.mqh +++ b/Indicators/Indi_CustomMovingAverage.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" // Structs. struct IndiCustomMovingAverageParams : IndicatorParams { @@ -32,14 +32,14 @@ struct IndiCustomMovingAverageParams : IndicatorParams { // Struct constructor. IndiCustomMovingAverageParams(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); - SetDataSourceType(IDATA_ICUSTOM); + : IndicatorParams(INDI_CUSTOM_MOVING_AVG) { + if (custom_indi_name == "") { #ifdef __MQL5__ - SetCustomIndicatorName("Examples\\Custom Moving Average"); + SetCustomIndicatorName("Examples\\Custom Moving Average"); #else - SetCustomIndicatorName("Custom Moving Averages"); + SetCustomIndicatorName("Custom Moving Averages"); #endif + } shift = _shift; smooth_method = _smooth_method; smooth_period = _smooth_period; @@ -54,23 +54,26 @@ struct IndiCustomMovingAverageParams : IndicatorParams { /** * Implements the Custom Moving Average indicator. */ -class Indi_CustomMovingAverage : public Indicator { +class Indi_CustomMovingAverage : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_CustomMovingAverage(IndiCustomMovingAverageParams& _p, IndicatorBase* _indi_src = NULL) - : Indicator(_p, _indi_src){}; + Indi_CustomMovingAverage(IndiCustomMovingAverageParams& _p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_ICUSTOM, + IndicatorData* _indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; Indi_CustomMovingAverage(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : Indicator(INDI_CUSTOM_MOVING_AVG, _tf, _shift){}; + : IndicatorTickOrCandleSource(INDI_CUSTOM_MOVING_AVG, _tf, _shift){}; /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), GetSmoothShift(), GetSmoothMethod() /*]*/, 0, _ishift); diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index 8f96593c4..75101e981 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -27,7 +27,7 @@ // Includes. #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Refs.mqh" #include "../Storage/Objects.h" #include "../Storage/ValueStorage.h" @@ -42,16 +42,11 @@ struct IndiDEIndiMAParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructors. IndiDEIndiMAParams(unsigned int _period = 14, int _ma_shift = 0, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) - : period(_period), ma_shift(_ma_shift), applied_price(_ap), IndicatorParams(INDI_DEMA, 1, TYPE_DOUBLE) { + : period(_period), ma_shift(_ma_shift), applied_price(_ap), IndicatorParams(INDI_DEMA) { SetCustomIndicatorName("Examples\\DEMA"); - SetDataValueRange(IDATA_RANGE_PRICE); SetShift(_shift); - switch (idstype) { - case IDATA_ICUSTOM: - if (custom_indi_name == "") { - SetCustomIndicatorName("Examples\\DEMA"); - } - break; + if (custom_indi_name == "") { + SetCustomIndicatorName("Examples\\DEMA"); } }; IndiDEIndiMAParams(IndiDEIndiMAParams &_params, ENUM_TIMEFRAMES _tf) { @@ -63,13 +58,18 @@ struct IndiDEIndiMAParams : IndicatorParams { /** * Implements the Moving Average indicator. */ -class Indi_DEMA : public Indicator { +class Indi_DEMA : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_DEMA(IndiDEIndiMAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_DEMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_DEMA, _tf, _shift) {} + Indi_DEMA(IndiDEIndiMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + Indi_DEMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_DEMA, _tf, _shift) {} /** * Updates the indicator value. @@ -78,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, IndicatorBase *_obj = NULL) { + ENUM_APPLIED_PRICE _applied_price, int _shift = 0, int _mode = 0, IndicatorData *_obj = NULL) { #ifdef __MQL5__ int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; double _res[]; @@ -108,44 +108,54 @@ class Indi_DEMA : public Indicator { #else Indi_Price *_indi_price = Indi_Price::GetCached(_symbol, _applied_price, _tf, _shift); // Note that _applied_price and Indi_Price mode indices are compatible. - return Indi_DEMA::iDEMAOnIndicator(_indi_price.GetCache(), _indi_price, 0, _period, _ma_shift, _shift); + return Indi_DEMA::iDEMAOnIndicatorSlow(_indi_price.GetCache(), _indi_price, 0, _period, _ma_shift, _shift); #endif } - static double iDEMAOnIndicator(IndicatorCalculateCache *cache, IndicatorBase *_indi, int indi_mode, - unsigned int ma_period, unsigned int ma_shift, int shift) { + static double iDEMAOnIndicatorSlow(IndicatorCalculateCache *cache, IndicatorData *_indi, int indi_mode, + unsigned int ma_period, unsigned int ma_shift, int shift) { return iDEMAOnArray(_indi.GetValueStorage(indi_mode), 0, ma_period, ma_shift, shift, cache); } - static double iDEMAOnArray(ValueStorage &price, int total, unsigned int ma_period, unsigned int ma_shift, - int shift, IndicatorCalculateCache *cache = NULL, bool recalculate = false) { - if (cache == NULL) { + static double iDEMAOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, unsigned int _ma_period, unsigned int _ma_shift, + int _mode, int _shift, IndicatorCalculateCache *_cache = NULL, + bool _recalculate = false) { + if (_cache == NULL) { Print("iDEMAOnArray() cannot yet work without cache object!"); DebugBreak(); return 0.0f; } - cache.SetPriceBuffer(price); + _cache.SetPriceBuffer(_price); - if (!cache.HasBuffers()) { - cache.AddBuffer>(3); // 3 buffers. + if (!_cache.HasBuffers()) { + _cache.AddBuffer>(3); // 3 buffers. } - if (recalculate) { + if (_recalculate) { // We don't want to continue calculations, but to recalculate previous one. - cache.ResetPrevCalculated(); + _cache.ResetPrevCalculated(); } - cache.SetPrevCalculated(Indi_DEMA::Calculate(cache.GetTotal(), cache.GetPrevCalculated(), 0, cache.GetPriceBuffer(), - ma_period, cache.GetBuffer(0), cache.GetBuffer(1), - cache.GetBuffer(2))); + _cache.SetPrevCalculated(Indi_DEMA::Calculate(INDICATOR_CALCULATE_GET_PARAMS_SHORT, _cache.GetBuffer(0), + _cache.GetBuffer(1), _cache.GetBuffer(2), + _ma_period)); + + return _cache.GetTailValue(0, _ma_shift + _shift); + } - return cache.GetTailValue(0, ma_shift + shift); + /** + * On-indicator version of DEMA. + */ + static double iDEMAOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, int _ma_shift, + ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( + _indi, _symbol, _tf, (int)_ap, Util::MakeKey("Indi_CHV_ON_" + _indi.GetFullName(), _period, _ma_shift)); + return iDEMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _ma_shift, _mode, _shift, _cache); } - static int Calculate(const int rates_total, const int prev_calculated, const int begin, ValueStorage &price, - int InpPeriodEMA, ValueStorage &DemaBuffer, ValueStorage &Ema, - ValueStorage &EmaOfEma) { + static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &DemaBuffer, + ValueStorage &Ema, ValueStorage &EmaOfEma, int InpPeriodEMA) { if (rates_total < 2 * InpPeriodEMA - 2) return (0); int start; @@ -166,16 +176,16 @@ class Indi_DEMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // We're getting DEMA from Price indicator. - _value = Indi_DEMA::iDEMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetAppliedPrice(), _ishift, _mode, - GetPointer(this)); + _value = Indi_DEMA::iDEMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetMAShift(), GetAppliedPrice() /*]*/, + _ishift, _mode, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /*[*/ GetPeriod(), GetMAShift(), @@ -183,8 +193,8 @@ class Indi_DEMA : public Indicator { break; case IDATA_INDICATOR: // Calculating DEMA value from specified indicator. - _value = Indi_DEMA::iDEMAOnIndicator(GetCache(), GetDataSource(), GetDataSourceMode(), GetPeriod(), - GetMAShift(), _ishift); + _value = Indi_DEMA::iDEMAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetMAShift(), + GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); break; } return _value; diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index 62e5869a0..d20b21dab 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -35,10 +35,8 @@ double iDeMarker(string _symbol, int _tf, int _period, int _shift) { struct IndiDeMarkerParams : IndicatorParams { unsigned int period; // Struct constructors. - IndiDeMarkerParams(unsigned int _period = 14, int _shift = 0) - : period(_period), IndicatorParams(INDI_DEMARKER, 1, TYPE_DOUBLE) { + IndiDeMarkerParams(unsigned int _period = 14, int _shift = 0) : period(_period), IndicatorParams(INDI_DEMARKER) { shift = _shift; - SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\DeMarker"); }; IndiDeMarkerParams(IndiDeMarkerParams &_params, ENUM_TIMEFRAMES _tf) { @@ -50,14 +48,18 @@ struct IndiDeMarkerParams : IndicatorParams { /** * Implements the DeMarker indicator. */ -class Indi_DeMarker : public Indicator { +class Indi_DeMarker : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_DeMarker(IndiDeMarkerParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_DeMarker(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_DEMARKER, _tf, _shift) {} + Indi_DeMarker(IndiDeMarkerParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + Indi_DeMarker(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_DEMARKER, _tf, _shift) {} /** * Returns the indicator value. @@ -67,7 +69,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, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iDeMarker(_symbol, _tf, _period, _shift); #else // __MQL5__ @@ -102,10 +104,10 @@ class Indi_DeMarker : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = _value = Indi_DeMarker::iDeMarker(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index a5bf323d5..7adc7080e 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "Price/Indi_Price.mqh" /** @@ -33,15 +33,10 @@ // Structs. struct IndiDemoParams : IndicatorParams { // Struct constructors. - IndiDemoParams(int _shift = 0) : IndicatorParams(INDI_DEMO, 1, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_MIXED); + IndiDemoParams(int _shift = 0) : IndicatorParams(INDI_DEMO) { SetShift(_shift); - switch (idstype) { - case IDATA_ICUSTOM: - if (custom_indi_name == "") { - SetCustomIndicatorName("Examples\\Demo"); - } - break; + if (custom_indi_name == "") { + SetCustomIndicatorName("Examples\\Demo"); } }; IndiDemoParams(IndiDemoParams &_params, ENUM_TIMEFRAMES _tf) { @@ -53,26 +48,31 @@ struct IndiDemoParams : IndicatorParams { /** * Demo/Dummy Indicator. */ -class Indi_Demo : public Indicator { +class Indi_Demo : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_Demo(IndiDemoParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_Demo(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_DEMO, _tf, _shift){}; + Indi_Demo(IndiDemoParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_Demo(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_DEMO, _tf, _shift){}; /** * Returns the indicator value. */ static double iDemo(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { return 0.1 + (0.1 * _obj.GetBarIndex()); } /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); double _value = Indi_Demo::iDemo(GetSymbol(), GetTf(), _ishift, THIS_PTR); if (iparams.is_draw) { diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index b8c4fe1cd..ab3195936 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.price.h" #include "Indi_MA.mqh" @@ -32,9 +32,8 @@ struct IndiDetrendedPriceParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructor. IndiDetrendedPriceParams(int _period = 12, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) - : IndicatorParams(INDI_DETRENDED_PRICE, 1, TYPE_DOUBLE) { + : IndicatorParams(INDI_DETRENDED_PRICE) { applied_price = _ap; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\DPO"); period = _period; shift = _shift; @@ -48,31 +47,34 @@ struct IndiDetrendedPriceParams : IndicatorParams { /** * Implements Detrended Price Oscillator. */ -class Indi_DetrendedPrice : public Indicator { +class Indi_DetrendedPrice : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_DetrendedPrice(IndiDetrendedPriceParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; + Indi_DetrendedPrice(IndiDetrendedPriceParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; Indi_DetrendedPrice(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : Indicator(INDI_DETRENDED_PRICE, _tf, _shift){}; + : IndicatorTickOrCandleSource(INDI_DETRENDED_PRICE, _tf, _shift){}; /** * 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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_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); + return iDPOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _ap, _mode, _shift, _cache); } /** * Calculates DPO on the array of values. */ - static double iDPOOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _period, int _mode, int _shift, - IndicatorCalculateCache *_cache, bool _recalculate = false) { + static double iDPOOnArray(INDICATOR_CALCULATE_PARAMS_SHORT, int _period, ENUM_APPLIED_PRICE _ap, int _mode, + int _shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_price); if (!_cache.HasBuffers()) { @@ -89,6 +91,16 @@ class Indi_DetrendedPrice : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of DPO. + */ + static double iDPOOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( + _indi, _symbol, _tf, _ap, Util::MakeKey("Indi_DPO_ON_" + _indi.GetFullName(), _period, (int)_ap)); + return iDPOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _ap, _mode, _shift, _cache); + } + /** * OnCalculate() method for DPO indicator. */ @@ -116,10 +128,10 @@ class Indi_DetrendedPrice : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_DetrendedPrice::iDPO(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); @@ -128,6 +140,10 @@ class Indi_DetrendedPrice : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_DetrendedPrice::iDPOOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), + GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index 4d64acd2d..f6ea7ecf7 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -26,7 +26,7 @@ struct IndicatorParams; // Includes. #include "../Action.mqh" #include "../DictStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Redis.mqh" #include "Indi_Drawer.struct.h" #include "Price/Indi_Price.mqh" @@ -34,18 +34,23 @@ struct IndicatorParams; /** * Implements the Relative Strength Index indicator. */ -class Indi_Drawer : public Indicator { +class Indi_Drawer : public IndicatorTickOrCandleSource { Redis redis; public: /** * Class constructor. */ - Indi_Drawer(const IndiDrawerParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src), redis(true) { + Indi_Drawer(const IndiDrawerParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(0, TYPE_DOUBLE, _idstype, IDATA_RANGE_UNKNOWN, _indi_src_mode), + _indi_src), + redis(true) { Init(); } - Indi_Drawer(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_DRAWER, _tf, _shift), redis(true) { + Indi_Drawer(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_DRAWER, _tf, _shift), redis(true) { Init(); } @@ -70,15 +75,16 @@ class Indi_Drawer : public Indicator { virtual bool ExecuteAction(ENUM_INDICATOR_ACTION _action, DataParamEntry &_args[]) { int num_args = ArraySize(_args), i; + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); IndicatorDataEntry entry(num_args - 1); // @fixit Not sure if we should enforce double. // entry.AddFlags(INDI_ENTRY_FLAG_IS_DOUBLE); if (_action == INDI_ACTION_SET_VALUE) { - iparams.SetMaxModes(num_args - 1); + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), num_args - 1); - if (num_args - 1 > iparams.GetMaxModes()) { + if (num_args - 1 > _max_modes) { GetLogger().Error( StringFormat("Too many data for buffers for action %s!", EnumToString(_action), __FUNCTION_LINE__)); return false; @@ -149,14 +155,14 @@ class Indi_Drawer : public Indicator { * - https://www.mql5.com/en/docs/indicators/irsi */ static double iDrawer(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { return 1.0; } /** * Performs drawing on data from other indicator. */ - static double iDrawerOnIndicator(IndicatorBase *_indi, Indi_Drawer *_obj, string _symbol = NULL, + static double iDrawerOnIndicator(IndicatorData *_indi, Indi_Drawer *_obj, string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) { // This method is not yet implemented. return 1.0; @@ -175,7 +181,7 @@ class Indi_Drawer : public Indicator { virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Drawer::iDrawer(GetSymbol(), GetTf(), _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_Drawer.struct.h b/Indicators/Indi_Drawer.struct.h index e868d110e..b9f5f8287 100644 --- a/Indicators/Indi_Drawer.struct.h +++ b/Indicators/Indi_Drawer.struct.h @@ -36,7 +36,7 @@ struct IndiDrawerParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; IndiDrawerParams(unsigned int _period = 10, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE) - : period(_period), applied_price(_ap), IndicatorParams(INDI_DRAWER, 0, TYPE_DOUBLE) { + : period(_period), applied_price(_ap), IndicatorParams(INDI_DRAWER) { // Fetching history data is not yet implemented. SetCustomIndicatorName("Examples\\Drawer"); }; diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 4dedaa976..431598d19 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/Singleton.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" @@ -58,13 +58,8 @@ struct IndiEnvelopesParams : IndicatorParams { 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 + IndicatorParams(INDI_ENVELOPES) { shift = _shift; - SetDataValueRange(IDATA_RANGE_PRICE); SetCustomIndicatorName("Examples\\Envelopes"); }; IndiEnvelopesParams(IndiEnvelopesParams &_params, ENUM_TIMEFRAMES _tf) { @@ -76,14 +71,37 @@ struct IndiEnvelopesParams : IndicatorParams { /** * Implements the Envelopes indicator. */ -class Indi_Envelopes : public Indicator { +class Indi_Envelopes : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { +#ifdef __MQL4__ + // There is extra LINE_MAIN in MQL4 for Envelopes. + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 3); +#else + Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); +#endif + } + public: /** * Class constructor. */ - Indi_Envelopes(IndiEnvelopesParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_Envelopes(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_ENVELOPES, _tf, _shift) {} + Indi_Envelopes(IndiEnvelopesParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_Envelopes(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_ENVELOPES, _tf, _shift) { + Init(); + }; /** * Returns the indicator value. @@ -96,7 +114,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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iEnvelopes(_symbol, _tf, _ma_period, _ma_method, _ma_shift, _ap, _deviation, _mode, _shift); #else // __MQL5__ @@ -137,7 +155,7 @@ class Indi_Envelopes : public Indicator { #endif } - static double iEnvelopesOnIndicator(IndicatorCalculateCache *_cache, IndicatorBase *_indi, string _symbol, + static double iEnvelopesOnIndicator(IndicatorCalculateCache *_cache, IndicatorData *_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 @@ -197,10 +215,10 @@ class Indi_Envelopes : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Envelopes::iEnvelopes(GetSymbol(), GetTf(), GetMAPeriod(), GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation(), _mode, _ishift, THIS_PTR); @@ -211,8 +229,9 @@ class Indi_Envelopes : public Indicator { break; case IDATA_INDICATOR: _value = Indi_Envelopes::iEnvelopesOnIndicator(GetCache(), GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), - GetMAMethod(), GetDataSourceMode(), GetMAShift(), GetDeviation(), - _mode, _ishift); + GetMAMethod(), + Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)), + GetMAShift(), GetDeviation(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -224,7 +243,7 @@ class Indi_Envelopes : public Indicator { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = -1) { + virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { Indicator::GetEntryAlter(_entry); #ifdef __MQL4__ // The LINE_MAIN only exists in MQL4 for Envelopes. diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index a61196e91..0880d6ee3 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -32,7 +32,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -51,9 +51,8 @@ struct IndiForceParams : IndicatorParams { // Struct constructors. IndiForceParams(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) { + : period(_period), ma_method(_ma_method), applied_price(_ap), IndicatorParams(INDI_FORCE) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Force_Index"); }; IndiForceParams(IndiForceParams &_params, ENUM_TIMEFRAMES _tf) { @@ -65,14 +64,19 @@ struct IndiForceParams : IndicatorParams { /** * Implements the Force Index indicator. */ -class Indi_Force : public Indicator { +class Indi_Force : public IndicatorTickOrCandleSource { protected: public: /** * Class constructor. */ - Indi_Force(IndiForceParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_Force(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_FORCE, _tf, _shift) {} + Indi_Force(IndiForceParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_Force(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_FORCE, _tf, _shift) {} /** * Returns the indicator value. @@ -82,7 +86,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, IndicatorBase *_obj = NULL) { + ENUM_APPLIED_PRICE _applied_price, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iForce(_symbol, _tf, _period, _ma_method, _applied_price, _shift); #else // __MQL5__ @@ -117,10 +121,10 @@ class Indi_Force : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Force::iForce(GetSymbol(), GetTf(), GetPeriod(), GetMAMethod(), GetAppliedPrice(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index 7640170c0..33a72fb83 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. @@ -33,9 +33,8 @@ struct IndiFrAIndiMAParams : IndicatorParams { // Struct constructor. IndiFrAIndiMAParams(int _period = 14, int _frama_shift = 0, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) - : IndicatorParams(INDI_FRAMA, 1, TYPE_DOUBLE) { + : IndicatorParams(INDI_FRAMA) { frama_shift = _frama_shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\FrAMA"); applied_price = _ap; period = _period; @@ -50,34 +49,38 @@ struct IndiFrAIndiMAParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_FrAMA : public Indicator { +class Indi_FrAMA : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_FrAMA(IndiFrAIndiMAParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; - Indi_FrAMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_FRAMA, _tf, _shift){}; + Indi_FrAMA(IndiFrAIndiMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_FrAMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_FRAMA, _tf, _shift){}; /** * 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, IndicatorBase *_obj = NULL) { + int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iFrAMA(_symbol, _tf, _ma_period, _ma_shift, _ap), _mode, _shift); #else INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_FrAMA", _ma_period, _ma_shift, (int)_ap)); - return iFrAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _ma_period, _ma_shift, _mode, _shift, _ap, _cache); + return iFrAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _ma_period, _ma_shift, _ap, _mode, _shift, _cache); #endif } /** * Calculates FrAMA on the array of values. */ - static double iFrAMAOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _ma_period, int _ma_shift, int _mode, int _shift, - ENUM_APPLIED_PRICE _ap, IndicatorCalculateCache *_cache, + static double iFrAMAOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _ma_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, + int _mode, int _shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); @@ -95,6 +98,17 @@ class Indi_FrAMA : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of FrAMA. + */ + static double iFrAMAOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, + int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, + IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, Util::MakeKey("Indi_AMA_ON_" + _indi.GetFullName(), _ma_period, _ma_shift, (int)_ap)); + return iFrAMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _ma_period, _ma_shift, _ap, _mode, _shift, _cache); + } + static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_LONG, ValueStorage &FrAmaBuffer, int InpPeriodFrAMA, int InpShift, ENUM_APPLIED_PRICE InpAppliedPrice) { if (rates_total < 2 * InpPeriodFrAMA) return (0); @@ -134,10 +148,10 @@ class Indi_FrAMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_FrAMA::iFrAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFRAMAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); @@ -146,6 +160,10 @@ class Indi_FrAMA : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetFRAMAShift() /*]*/, 0, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_FrAMA::iFrAMAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), + GetFRAMAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index a0a147a26..fecd71daf 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -34,8 +34,7 @@ double iFractals(string _symbol, int _tf, int _mode, int _shift) { // Structs. struct IndiFractalsParams : IndicatorParams { // Struct constructors. - IndiFractalsParams(int _shift = 0) : IndicatorParams(INDI_FRACTALS, FINAL_LO_UP_LINE_ENTRY, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_ARROW); + IndiFractalsParams(int _shift = 0) : IndicatorParams(INDI_FRACTALS) { SetCustomIndicatorName("Examples\\Fractals"); shift = _shift; }; @@ -48,14 +47,31 @@ struct IndiFractalsParams : IndicatorParams { /** * Implements the Fractals indicator. */ -class Indi_Fractals : public Indicator { +class Indi_Fractals : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_LO_UP_LINE_ENTRY); } + public: /** * Class constructor. */ - Indi_Fractals(IndiFractalsParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_Fractals(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_FRACTALS, _tf, _shift) {} + Indi_Fractals(IndiFractalsParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_LO_UP_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_Fractals(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_FRACTALS, _tf, _shift) { + Init(); + } /** * Returns the indicator value. @@ -67,7 +83,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 - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iFractals(_symbol, _tf, _mode, _shift); #else // __MQL5__ @@ -102,10 +118,10 @@ class Indi_Fractals : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = _value = Indi_Fractals::iFractals(GetSymbol(), GetTf(), (ENUM_LO_UP_LINE)_mode, _ishift, THIS_PTR); break; @@ -121,7 +137,7 @@ class Indi_Fractals : public Indicator { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = -1) { + virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { Indicator::GetEntryAlter(_entry); #ifdef __MQL4__ // In MT4 line identifiers starts from 1, so populating also at 0. diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index edf46e52a..dd0b06b7a 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -89,9 +89,8 @@ struct IndiGatorParams : IndicatorParams { lips_shift(_ls), ma_method(_mm), applied_price(_ap), - IndicatorParams(INDI_GATOR, FINAL_GATOR_LINE_HISTOGRAM_ENTRY, TYPE_DOUBLE) { + IndicatorParams(INDI_GATOR) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Gator"); }; IndiGatorParams(IndiGatorParams &_params, ENUM_TIMEFRAMES _tf) { @@ -103,13 +102,31 @@ struct IndiGatorParams : IndicatorParams { /** * Implements the Gator oscillator. */ -class Indi_Gator : public Indicator { +class Indi_Gator : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_GATOR_LINE_HISTOGRAM_ENTRY); } + public: /** * Class constructor. */ - Indi_Gator(IndiGatorParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_Gator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_GATOR, _tf, _shift) {} + Indi_Gator(IndiGatorParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_GATOR_LINE_HISTOGRAM_ENTRY, TYPE_DOUBLE, + _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_Gator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_GATOR, _tf, _shift) { + Init(); + } /** * Returns the indicator value. @@ -132,7 +149,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, - IndicatorBase *_obj = NULL) { + IndicatorData *_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); @@ -169,10 +186,10 @@ class Indi_Gator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Gator::iGator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice(), @@ -195,7 +212,7 @@ class Indi_Gator : public Indicator { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = -1) { + virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { Indicator::GetEntryAlter(_entry); #ifdef __MQL4__ // @todo: Can we calculate upper and lower histogram color in MT4? diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index be960bd21..637efb682 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Enums. @@ -50,13 +50,14 @@ enum ENUM_HA_MODE { // Structs. struct IndiHeikenAshiParams : IndicatorParams { // Struct constructors. - IndiHeikenAshiParams(int _shift = 0) : IndicatorParams(INDI_HEIKENASHI, FINAL_HA_MODE_ENTRY, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_MIXED); // @fixit It draws candles! + IndiHeikenAshiParams(int _shift = 0) : IndicatorParams(INDI_HEIKENASHI) { + if (custom_indi_name == "") { #ifdef __MQL4__ - SetCustomIndicatorName("Heiken Ashi"); + SetCustomIndicatorName("Heiken Ashi"); #else - SetCustomIndicatorName("Examples\\Heiken_Ashi"); + SetCustomIndicatorName("Examples\\Heiken_Ashi"); #endif + } shift = _shift; }; IndiHeikenAshiParams(IndiHeikenAshiParams &_params, ENUM_TIMEFRAMES _tf) { @@ -68,20 +69,37 @@ struct IndiHeikenAshiParams : IndicatorParams { /** * Implements the Heiken-Ashi indicator. */ -class Indi_HeikenAshi : public Indicator { +class Indi_HeikenAshi : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_HA_MODE_ENTRY); } + public: /** * Class constructor. */ - Indi_HeikenAshi(IndiHeikenAshiParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_HeikenAshi(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_HEIKENASHI, _tf, _shift) {} + Indi_HeikenAshi(IndiHeikenAshiParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_HA_MODE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_HeikenAshi(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_HEIKENASHI, _tf, _shift) { + Init(); + } /** * Returns value for iHeikenAshi indicator. */ static double iCustomLegacyHeikenAshi(string _symbol, ENUM_TIMEFRAMES _tf, string _name, int _mode, int _shift = 0, - IndicatorBase *_obj = NULL) { + IndicatorData *_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. @@ -157,6 +175,16 @@ class Indi_HeikenAshi : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Heiken Ashi. + */ + static double iHeikenAshiOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, + int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, + Util::MakeKey("Indi_HeikenAshi_ON_" + _indi.GetFullName())); + return iHeikenAshiOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); + } + /** * OnCalculate() method for Mass Index indicator. */ @@ -195,10 +223,10 @@ class Indi_HeikenAshi : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = HA_OPEN, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = HA_OPEN, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: #ifdef __MQL4__ // Converting MQL4's enum into MQL5 one, as OnCalculate uses further one. @@ -226,6 +254,10 @@ class Indi_HeikenAshi : public Indicator { _value = Indi_HeikenAshi::iCustomLegacyHeikenAshi(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift, THIS_PTR); break; + case IDATA_INDICATOR: + _value = + Indi_HeikenAshi::iHeikenAshiOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index 41450b753..16ceaab94 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -69,12 +69,8 @@ struct IndiIchimokuParams : IndicatorParams { unsigned int senkou_span_b; // Struct constructors. IndiIchimokuParams(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) { + : tenkan_sen(_ts), kijun_sen(_ks), senkou_span_b(_ss_b), IndicatorParams(INDI_ICHIMOKU) { shift = _shift; - SetDataValueRange(IDATA_RANGE_PRICE); // @fixit Not sure if not mixed. SetCustomIndicatorName("Examples\\Ichimoku"); }; IndiIchimokuParams(IndiIchimokuParams &_params, ENUM_TIMEFRAMES _tf) { @@ -86,14 +82,31 @@ struct IndiIchimokuParams : IndicatorParams { /** * Implements the Ichimoku Kinko Hyo indicator. */ -class Indi_Ichimoku : public Indicator { +class Indi_Ichimoku : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_ICHIMOKU_LINE_ENTRY); } + public: /** * Class constructor. */ - Indi_Ichimoku(IndiIchimokuParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_Ichimoku(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_ICHIMOKU, _tf, _shift) {} + Indi_Ichimoku(IndiIchimokuParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_ICHIMOKU_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_Ichimoku(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_ICHIMOKU, _tf, _shift) { + Init(); + } /** * Returns the indicator value. @@ -107,7 +120,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, IndicatorBase *_obj = NULL) { + int _mode, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iIchimoku(_symbol, _tf, _tenkan_sen, _kijun_sen, _senkou_span_b, _mode, _shift); #else // __MQL5__ @@ -142,10 +155,10 @@ class Indi_Ichimoku : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Ichimoku::iIchimoku(GetSymbol(), GetTf(), GetTenkanSen(), GetKijunSen(), GetSenkouSpanB(), _mode, _ishift, THIS_PTR); @@ -163,7 +176,7 @@ class Indi_Ichimoku : public Indicator { /** * Alters indicator's struct value. */ - virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = -1) { + virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { Indicator::GetEntryAlter(_entry); #ifdef __MQL4__ // In MQL4 value of LINE_TENKANSEN is 1 (not 0 as in MQL5), diff --git a/Indicators/Indi_Killzones.mqh b/Indicators/Indi_Killzones.mqh index 70016b6db..68cbbfb28 100644 --- a/Indicators/Indi_Killzones.mqh +++ b/Indicators/Indi_Killzones.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Market.struct.h" // Defines enumerations. @@ -49,10 +49,7 @@ enum ENUM_INDI_KILLZONES_MODE { 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); + IndiKillzonesParams(int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorParams(INDI_PIVOT) { SetShift(_shift); tf = _tf; }; @@ -91,7 +88,7 @@ struct Indi_Killzones_Time : MarketTimeForex { /** * Implements Pivot Detector. */ -class Indi_Killzones : public Indicator { +class Indi_Killzones : public IndicatorTickOrCandleSource { protected: Indi_Killzones_Time ikt; @@ -99,18 +96,23 @@ class Indi_Killzones : public Indicator { /** * Class constructor. */ - Indi_Killzones(IndiKillzonesParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_Killzones(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_KILLZONES, _tf, _shift) {} + Indi_Killzones(IndiKillzonesParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_CHART, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_KILLZONES_MODE_ENTRY, TYPE_FLOAT, + _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + Indi_Killzones(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_KILLZONES, _tf, _shift) {} /** * Returns the indicator's value. */ - IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { float _value = FLT_MAX; int _index = (int)_mode / 2; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // Builtin mode not supported. SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index c2675a21a..c52ef1332 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -27,7 +27,7 @@ // Includes. #include "../Dict.mqh" #include "../DictObject.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickSource.h" #include "../Refs.mqh" #include "../Storage/Singleton.h" #include "../Storage/ValueStorage.h" @@ -56,13 +56,8 @@ struct IndiMAParams : IndicatorParams { // Struct constructors. IndiMAParams(unsigned int _period = 13, int _ma_shift = 10, ENUM_MA_METHOD _ma_method = MODE_SMA, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : period(_period), - ma_shift(_ma_shift), - ma_method(_ma_method), - applied_array(_ap), - IndicatorParams(INDI_MA, 1, TYPE_DOUBLE) { + : period(_period), ma_shift(_ma_shift), ma_method(_ma_method), applied_array(_ap), IndicatorParams(INDI_MA) { shift = _shift; - SetDataValueRange(IDATA_RANGE_PRICE); SetCustomIndicatorName("Examples\\Moving Average"); }; IndiMAParams(IndiMAParams &_params, ENUM_TIMEFRAMES _tf) { @@ -74,13 +69,17 @@ struct IndiMAParams : IndicatorParams { /** * Implements the Moving Average indicator. */ -class Indi_MA : public Indicator { +class Indi_MA : public IndicatorTickSource { public: /** * Class constructor. */ - Indi_MA(IndiMAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_MA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_MA, _tf, _shift) {} + Indi_MA(IndiMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + Indi_MA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_MA, _tf, _shift) {} /** * Returns the indicator value. @@ -91,7 +90,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, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iMA(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_array, _shift); #else // __MQL5__ @@ -126,7 +125,7 @@ class Indi_MA : public Indicator { /** * Calculates MA on another indicator. */ - static double iMAOnIndicator(IndicatorCalculateCache *cache, IndicatorBase *_indi, int indi_mode, + static double iMAOnIndicator(IndicatorCalculateCache *cache, IndicatorData *_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) { @@ -627,10 +626,10 @@ class Indi_MA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_MA::iMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), _ishift, THIS_PTR); @@ -641,10 +640,12 @@ class Indi_MA : public Indicator { break; case IDATA_INDICATOR: // Calculating MA value from specified indicator. - _value = Indi_MA::iMAOnIndicator(GetCache(), GetDataSource(), GetDataSourceMode(), GetSymbol(), GetTf(), - GetPeriod(), GetMAShift(), GetMAMethod(), _ishift); + _value = Indi_MA::iMAOnIndicator(GetCache(), GetDataSource(), + Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)), GetSymbol(), + GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), _ishift); break; } + return _value; } @@ -663,6 +664,35 @@ class Indi_MA : public Indicator { return _ptr; } + /** + * Returns value storage of given kind. + */ + IValueStorage *GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + switch (_type) { + case INDI_VS_TYPE_PRICE_ASK: + case INDI_VS_TYPE_PRICE_BID: + // We're returning the same buffer for ask and bid price, as target indicator probably won't bother. + return GetValueStorage(0); + default: + // Trying in parent class. + return Indicator::GetSpecificValueStorage(_type); + } + } + + /** + * Checks whether indicator support given value storage type. + */ + bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + switch (_type) { + case INDI_VS_TYPE_PRICE_ASK: + case INDI_VS_TYPE_PRICE_BID: + return true; + default: + // Trying in parent class. + return Indicator::HasSpecificValueStorage(_type); + } + } + /* Getters */ /** diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index f5917f8bd..4d9518d64 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -45,9 +45,8 @@ struct IndiMACDParams : IndicatorParams { ema_slow_period(_esp), signal_period(_sp), applied_price(_ap), - IndicatorParams(INDI_MACD, FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE) { + IndicatorParams(INDI_MACD) { shift = _shift; - SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\MACD"); }; IndiMACDParams(IndiMACDParams &_params, ENUM_TIMEFRAMES _tf) { @@ -59,13 +58,19 @@ struct IndiMACDParams : IndicatorParams { /** * Implements the Moving Averages Convergence/Divergence indicator. */ -class Indi_MACD : public Indicator { +class Indi_MACD : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_MACD(IndiMACDParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_MACD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_MACD, _tf, _shift) {} + Indi_MACD(IndiMACDParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + Indi_MACD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_MACD, _tf, _shift) {} /** * Returns the indicator value. @@ -78,7 +83,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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iMACD(_symbol, _tf, _ema_fast_period, _ema_slow_period, _signal_period, _applied_price, _mode, _shift); #else // __MQL5__ @@ -114,10 +119,10 @@ class Indi_MACD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_MACD::iMACD(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice(), (ENUM_SIGNAL_LINE)_mode, _ishift, THIS_PTR); diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index acd15835b..2d8b4a800 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -37,9 +37,8 @@ struct IndiMFIParams : IndicatorParams { ENUM_APPLIED_VOLUME applied_volume; // Ignored in MT4. // Struct constructors. IndiMFIParams(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) { + : ma_period(_ma_period), applied_volume(_av), IndicatorParams(INDI_MFI) { shift = _shift; - SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\MFI"); }; IndiMFIParams(IndiMFIParams &_params, ENUM_TIMEFRAMES _tf) { @@ -51,13 +50,17 @@ struct IndiMFIParams : IndicatorParams { /** * Implements the Money Flow Index indicator. */ -class Indi_MFI : public Indicator { +class Indi_MFI : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_MFI(IndiMFIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_MFI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_MFI, _tf, _shift) {} + Indi_MFI(IndiMFIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + Indi_MFI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_MFI, _tf, _shift) {} /** * Calculates the Money Flow Index indicator and returns its value. @@ -67,7 +70,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, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iMFI(_symbol, _tf, _period, _shift); #else // __MQL5__ @@ -111,10 +114,10 @@ class Indi_MFI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: #ifdef __MQL4__ _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), _ishift); diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index 817b81cd8..dbd06b000 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" #include "Indi_MA.mqh" @@ -33,10 +33,9 @@ struct IndiMassIndexParams : IndicatorParams { int sum_period; // Struct constructor. IndiMassIndexParams(int _period = 9, int _second_period = 9, int _sum_period = 25, int _shift = 0) - : IndicatorParams(INDI_MASS_INDEX, 1, TYPE_DOUBLE) { + : IndicatorParams(INDI_MASS_INDEX) { period = _period; second_period = _second_period; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\MI"); shift = _shift; sum_period = _sum_period; @@ -50,20 +49,24 @@ struct IndiMassIndexParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_MassIndex : public Indicator { +class Indi_MassIndex : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_MassIndex(IndiMassIndexParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; - Indi_MassIndex(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_MASS_INDEX, _tf, _shift){}; + Indi_MassIndex(IndiMassIndexParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_MassIndex(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_MASS_INDEX, _tf, _shift){}; /** * 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, IndicatorBase *_obj = NULL) { + int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( _symbol, _tf, Util::MakeKey("Indi_MassIndex", _period, _second_period, _sum_period)); return iMIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _second_period, _sum_period, _mode, _shift, @@ -92,6 +95,19 @@ class Indi_MassIndex : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Mass Index. + */ + static double iMIOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + int _second_period, int _sum_period, int _mode = 0, int _shift = 0, + IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, + Util::MakeKey("Indi_MassIndex_ON_" + _indi.GetFullName(), _period, _second_period, _sum_period)); + return iMIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _second_period, _sum_period, _mode, _shift, + _cache); + } + /** * OnCalculate() method for Mass Index indicator. */ @@ -153,10 +169,10 @@ class Indi_MassIndex : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_MassIndex::iMI(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _ishift, THIS_PTR); @@ -165,6 +181,10 @@ class Indi_MassIndex : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_MassIndex::iMIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), + GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); break; diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 4671a6f3f..e228e8224 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -30,7 +30,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "Indi_PriceFeeder.mqh" #ifndef __MQL4__ @@ -47,9 +47,8 @@ struct IndiMomentumParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructors. IndiMomentumParams(unsigned int _period = 12, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : period(_period), applied_price(_ap), IndicatorParams(INDI_MOMENTUM, 1, TYPE_DOUBLE) { + : period(_period), applied_price(_ap), IndicatorParams(INDI_MOMENTUM) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Momentum"); }; IndiMomentumParams(IndiMomentumParams &_params, ENUM_TIMEFRAMES _tf) { @@ -61,14 +60,18 @@ struct IndiMomentumParams : IndicatorParams { /** * Implements the Momentum indicator. */ -class Indi_Momentum : public Indicator { +class Indi_Momentum : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_Momentum(IndiMomentumParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) {} - Indi_Momentum(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_MOMENTUM, _tf, _shift) {} + Indi_Momentum(IndiMomentumParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_Momentum(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_MOMENTUM, _tf, _shift) {} /** * Returns the indicator value. @@ -78,7 +81,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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iMomentum(_symbol, _tf, _period, _ap, _shift); #else // __MQL5__ @@ -110,7 +113,7 @@ class Indi_Momentum : public Indicator { #endif } - static double iMomentumOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, + static double iMomentumOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _period, int _mode, int _shift = 0) { double _indi_value_buffer[]; IndicatorDataEntry _entry(_indi.GetModeCount()); @@ -141,10 +144,10 @@ class Indi_Momentum : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_Momentum::iMomentum(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), iparams.shift + _ishift, @@ -159,7 +162,8 @@ class Indi_Momentum : public Indicator { // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), - GetDataSourceMode(), iparams.shift + _shift); + Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)), + iparams.shift + _shift); if (iparams.is_draw) { draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + _shift), _value, 1); } diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index 6efeeb242..7410d831a 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -36,21 +36,16 @@ struct IndiOBVParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // MT4 only. ENUM_APPLIED_VOLUME applied_volume; // MT5 only. // Struct constructors. - IndiOBVParams(int _shift = 0) : IndicatorParams(INDI_OBV, 1, TYPE_DOUBLE) { + IndiOBVParams(int _shift = 0) : IndicatorParams(INDI_OBV) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\OBV"); applied_price = PRICE_CLOSE; applied_volume = VOLUME_TICK; } - IndiOBVParams(ENUM_APPLIED_VOLUME _av, int _shift = 0) - : applied_volume(_av), IndicatorParams(INDI_OBV, 1, TYPE_DOUBLE) { - max_modes = 1; + IndiOBVParams(ENUM_APPLIED_VOLUME _av, int _shift = 0) : applied_volume(_av), IndicatorParams(INDI_OBV) { shift = _shift; }; - IndiOBVParams(ENUM_APPLIED_PRICE _ap, int _shift = 0) - : applied_price(_ap), IndicatorParams(INDI_OBV, 1, TYPE_DOUBLE) { - max_modes = 1; + IndiOBVParams(ENUM_APPLIED_PRICE _ap, int _shift = 0) : applied_price(_ap), IndicatorParams(INDI_OBV) { shift = _shift; }; IndiOBVParams(IndiOBVParams &_params, ENUM_TIMEFRAMES _tf) { @@ -62,13 +57,17 @@ struct IndiOBVParams : IndicatorParams { /** * Implements the On Balance Volume indicator. */ -class Indi_OBV : public Indicator { +class Indi_OBV : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_OBV(IndiOBVParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_OBV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_OBV, _tf, _shift) {} + Indi_OBV(IndiOBVParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_OBV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_OBV, _tf, _shift) {} /** * Returns the indicator value. @@ -83,7 +82,7 @@ class Indi_OBV : public Indicator { #else ENUM_APPLIED_VOLUME _applied = VOLUME_TICK, // MT5 only. #endif - int _shift = 0, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iOBV(_symbol, _tf, _applied, _shift); #else // __MQL5__ @@ -118,10 +117,10 @@ class Indi_OBV : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: #ifdef __MQL4__ _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedPrice(), _ishift); diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index 9958bdf83..0a81f2308 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -44,9 +44,8 @@ struct IndiOsMAParams : IndicatorParams { ema_slow_period(_esp), signal_period(_sp), applied_price(_ap), - IndicatorParams(INDI_OSMA, 1, TYPE_DOUBLE) { + IndicatorParams(INDI_OSMA) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\OsMA"); }; IndiOsMAParams(IndiOsMAParams &_params, ENUM_TIMEFRAMES _tf) { @@ -58,13 +57,18 @@ struct IndiOsMAParams : IndicatorParams { /** * Implements the Moving Average of Oscillator indicator. */ -class Indi_OsMA : public Indicator { +class Indi_OsMA : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_OsMA(IndiOsMAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_OsMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_OSMA, _tf, _shift) {} + Indi_OsMA(IndiOsMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_OsMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_OSMA, _tf, _shift) {} /** * Returns the indicator value. @@ -75,7 +79,7 @@ class Indi_OsMA : public Indicator { */ 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, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iOsMA(_symbol, _tf, _ema_fast_period, _ema_slow_period, _signal_period, _applied_price, _shift); #else // __MQL5__ @@ -111,10 +115,10 @@ class Indi_OsMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); double _value = EMPTY_VALUE; - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_OsMA::iOsMA(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice(), _ishift, THIS_PTR); diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index fd4c7cf4d..e9f98d642 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -30,9 +30,8 @@ struct IndiPivotParams : IndicatorParams { ENUM_PP_TYPE method; // Pivot point calculation method. // Struct constructor. - IndiPivotParams(ENUM_PP_TYPE _method = PP_CLASSIC, int _shift = 0) : IndicatorParams(INDI_PIVOT, 9, TYPE_FLOAT) { + IndiPivotParams(ENUM_PP_TYPE _method = PP_CLASSIC, int _shift = 0) : IndicatorParams(INDI_PIVOT) { method = _method; - SetDataValueRange(IDATA_RANGE_MIXED); shift = _shift; }; IndiPivotParams(IndiPivotParams& _params, ENUM_TIMEFRAMES _tf) { @@ -44,14 +43,30 @@ struct IndiPivotParams : IndicatorParams { /** * Implements Pivot Detector. */ -class Indi_Pivot : public Indicator { +class Indi_Pivot : public IndicatorTickOrCandleSource { + protected: + /* Protected methods */ + + /** + * Initialize. + */ + void Init() { Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 9); } + public: /** * Class constructor. */ - Indi_Pivot(IndiPivotParams& _p, IndicatorBase* _indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_Pivot(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_PIVOT, _tf, _shift) { + Indi_Pivot(IndiPivotParams& _p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData* _indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(9, TYPE_FLOAT, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) { + Init(); + }; + Indi_Pivot(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_PIVOT, _tf, _shift) { iparams.tf = _tf; + Init(); }; /** @@ -62,7 +77,7 @@ class Indi_Pivot : public Indicator { * @return * Returns IndicatorDataEntry struct filled with indicator values. */ - virtual IndicatorDataEntry GetEntry(int _shift = -1) { + virtual IndicatorDataEntry GetEntry(int _shift = 0) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); long _bar_time = GetBarTime(_ishift); IndicatorDataEntry _entry = idata.GetByKey(_bar_time); @@ -71,7 +86,7 @@ class Indi_Pivot : public Indicator { BarOHLC _ohlc = GetOHLC(_ishift); _entry.timestamp = GetBarTime(_ishift); if (_ohlc.IsValid()) { - _entry.Resize(iparams.GetMaxModes()); + _entry.Resize(Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))); _ohlc.GetPivots(GetMethod(), _entry.values[0].value.vflt, _entry.values[1].value.vflt, _entry.values[2].value.vflt, _entry.values[3].value.vflt, _entry.values[4].value.vflt, _entry.values[5].value.vflt, _entry.values[6].value.vflt, _entry.values[7].value.vflt, @@ -100,7 +115,7 @@ class Indi_Pivot : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); return GetEntry(_ishift)[_mode]; } @@ -110,7 +125,7 @@ class Indi_Pivot : public Indicator { */ virtual bool IsValidEntry(IndicatorDataEntry& _entry) { bool _is_valid = Indicator::IsValidEntry(_entry); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: break; case IDATA_INDICATOR: @@ -138,7 +153,7 @@ class Indi_Pivot : public Indicator { */ BarOHLC GetOHLC(int _shift = 0) { BarOHLC _ohlc; - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: // In this mode, price is fetched from chart. _ohlc = Chart::GetOHLC(_shift); @@ -148,10 +163,10 @@ class Indi_Pivot : public Indicator { // must have at least 4 buffers and define OHLC in the first 4 buffers. // Indi_Price is an example of such indicator. if (HasDataSource()) { - _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 = GetDataSource().GetValue(PRICE_OPEN, _shift); + _ohlc.high = GetDataSource().GetValue(PRICE_HIGH, _shift); + _ohlc.low = GetDataSource().GetValue(PRICE_LOW, _shift); + _ohlc.close = GetDataSource().GetValue(PRICE_CLOSE, _shift); } break; default: diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index 0afc2392e..4d9729599 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -22,17 +22,15 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "Indi_ZigZag.mqh" // Structs. struct IndiPriceChannelParams : IndicatorParams { unsigned int period; // Struct constructor. - IndiPriceChannelParams(unsigned int _period = 22, int _shift = 0) - : IndicatorParams(INDI_PRICE_CHANNEL, 3, TYPE_DOUBLE) { + IndiPriceChannelParams(unsigned int _period = 22, int _shift = 0) : IndicatorParams(INDI_PRICE_CHANNEL) { period = _period; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Price_Channel"); shift = _shift; }; @@ -43,23 +41,26 @@ struct IndiPriceChannelParams : IndicatorParams { }; /** - * Implements the Bill Williams' Accelerator/Decelerator oscillator. + * Implements Price Channel indicator. */ -class Indi_PriceChannel : public Indicator { +class Indi_PriceChannel : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_PriceChannel(IndiPriceChannelParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; + Indi_PriceChannel(IndiPriceChannelParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; Indi_PriceChannel(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : Indicator(INDI_PRICE_CHANNEL, _tf, _shift){}; + : IndicatorTickOrCandleSource(INDI_PRICE_CHANNEL, _tf, _shift){}; /** * Returns value for Price Channel indicator. */ static double iPriceChannel(string _symbol, ENUM_TIMEFRAMES _tf, int _period, int _mode = 0, int _shift = 0, - IndicatorBase *_obj = NULL) { + IndicatorData *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, Util::MakeKey("Indi_PriceChannel", _period)); return iPriceChannelOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, _shift, _cache); } @@ -86,6 +87,16 @@ class Indi_PriceChannel : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Price Channel. + */ + static double iPriceChannelOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, Util::MakeKey("Indi_PriceChannel_ON_" + _indi.GetFullName(), _period)); + return iPriceChannelOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _mode, _shift, _cache); + } + /** * OnCalculate() method for Price Channel indicator. */ @@ -106,10 +117,10 @@ class Indi_PriceChannel : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_PriceChannel::iPriceChannel(GetSymbol(), GetTf(), GetPeriod(), _mode, _ishift, THIS_PTR); break; @@ -117,6 +128,10 @@ class Indi_PriceChannel : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_PriceChannel::iPriceChannelOnIndicator(GetDataSource(), GetSymbol(), GetTf(), + /*[*/ GetPeriod() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index c1d286d88..0f0677de9 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" // Structs. struct IndiPriceFeederParams : IndicatorParams { @@ -32,15 +32,14 @@ struct IndiPriceFeederParams : IndicatorParams { /** * Struct constructor. */ - IndiPriceFeederParams(int _shift = 0) : IndicatorParams(INDI_PRICE_FEEDER, 1, TYPE_DOUBLE) { shift = _shift; } + IndiPriceFeederParams(int _shift = 0) : IndicatorParams(INDI_PRICE_FEEDER) { shift = _shift; } /** * Struct constructor. * * @todo Use more modes (full OHCL). */ - IndiPriceFeederParams(const double& _price_data[], int _total = 0) - : IndicatorParams(INDI_PRICE_FEEDER, 1, TYPE_DOUBLE) { + IndiPriceFeederParams(const double& _price_data[], int _total = 0) : IndicatorParams(INDI_PRICE_FEEDER) { tf = PERIOD_CURRENT; ArrayCopy(price_data, _price_data, 0, 0, _total == 0 ? WHOLE_ARRAY : _total); }; @@ -53,17 +52,21 @@ struct IndiPriceFeederParams : IndicatorParams { /** * Price Indicator. */ -class Indi_PriceFeeder : public Indicator { +class Indi_PriceFeeder : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_PriceFeeder(IndiPriceFeederParams& _p, IndicatorBase* _indi_src = NULL) - : Indicator(_p, _indi_src){}; - Indi_PriceFeeder(const double& _price_data[], int _total = 0) : Indicator(INDI_PRICE_FEEDER) { + Indi_PriceFeeder(IndiPriceFeederParams& _p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData* _indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + Indi_PriceFeeder(const double& _price_data[], int _total = 0) : IndicatorTickOrCandleSource(INDI_PRICE_FEEDER) { ArrayCopy(iparams.price_data, _price_data); }; - Indi_PriceFeeder(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_PRICE_FEEDER, _tf, _shift) {} + Indi_PriceFeeder(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_PRICE_FEEDER, _tf, _shift) {} void SetPrices(const double& _price_data[], int _total = 0) { iparams = IndiPriceFeederParams(_price_data, _total); } @@ -75,7 +78,7 @@ class Indi_PriceFeeder : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int data_size = ArraySize(iparams.price_data); int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); @@ -89,8 +92,9 @@ class Indi_PriceFeeder : public Indicator { Indicator::OnTick(); if (iparams.is_draw) { + int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); IndicatorDataEntry _entry = GetEntry(0); - for (int i = 0; i < (int)iparams.GetMaxModes(); ++i) { + for (int i = 0; i < _max_modes; ++i) { draw.DrawLineTo(GetName() + "_" + IntegerToString(i), GetBarTime(0), _entry.values[i].GetDbl()); } } diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index 17505eff1..41e642607 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. @@ -30,9 +30,8 @@ struct IndiPriceVolumeTrendParams : IndicatorParams { ENUM_APPLIED_VOLUME applied_volume; // Struct constructor. IndiPriceVolumeTrendParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0) - : IndicatorParams(INDI_PRICE_VOLUME_TREND, 1, TYPE_DOUBLE) { + : IndicatorParams(INDI_PRICE_VOLUME_TREND) { applied_volume = _applied_volume; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\PVT"); shift = _shift; }; @@ -45,21 +44,24 @@ struct IndiPriceVolumeTrendParams : IndicatorParams { /** * Implements the Price Volume Trend indicator. */ -class Indi_PriceVolumeTrend : public Indicator { +class Indi_PriceVolumeTrend : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_PriceVolumeTrend(IndiPriceVolumeTrendParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; + Indi_PriceVolumeTrend(IndiPriceVolumeTrendParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; Indi_PriceVolumeTrend(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : Indicator(INDI_PRICE_VOLUME_TREND, _tf, _shift){}; + : IndicatorTickOrCandleSource(INDI_PRICE_VOLUME_TREND, _tf, _shift){}; /** * 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, - IndicatorBase *_obj = NULL) { + IndicatorData *_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); } @@ -85,6 +87,16 @@ class Indi_PriceVolumeTrend : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Price Volume Trend. + */ + static double iPVTOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_VOLUME _av, + int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, Util::MakeKey("Indi_PVT_ON_" + _indi.GetFullName(), (int)_av)); + return iPVTOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _shift, _cache); + } + /** * OnCalculate() method for Price Volume Trend indicator. */ @@ -121,10 +133,10 @@ class Indi_PriceVolumeTrend : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_PriceVolumeTrend::iPVT(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); @@ -133,6 +145,10 @@ class Indi_PriceVolumeTrend : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetAppliedVolume() /*]*/, 0, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_PriceVolumeTrend::iPVTOnIndicator(GetDataSource(), GetSymbol(), GetTf(), + /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index 51c03ed8d..c564e6e6a 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "OHLC/Indi_OHLC.mqh" #include "Special/Indi_Math.mqh" @@ -30,11 +30,8 @@ struct IndiRSParams : IndicatorParams { ENUM_APPLIED_VOLUME applied_volume; // Struct constructor. - IndiRSParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0) - : IndicatorParams(INDI_RS, 2, TYPE_DOUBLE) { + IndiRSParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0) : IndicatorParams(INDI_RS) { applied_volume = _applied_volume; - SetDataValueRange(IDATA_RANGE_MIXED); - SetDataSourceType(IDATA_MATH); shift = _shift; }; IndiRSParams(IndiRSParams &_params, ENUM_TIMEFRAMES _tf) { @@ -46,18 +43,26 @@ struct IndiRSParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_RS : public Indicator { +class Indi_RS : public IndicatorTickOrCandleSource { DictStruct> imath; public: /** * Class constructor. */ - Indi_RS(IndiRSParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) { Init(); }; - Indi_RS(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_RS, _tf, _shift) { Init(); }; + Indi_RS(IndiRSParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_MATH, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_DIFF, _indi_src_mode), + _indi_src) { + Init(); + }; + Indi_RS(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_RS, _tf, _shift) { + Init(); + }; void Init() { - if (iparams.GetDataSourceType() == IDATA_MATH) { + if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_MATH) { IndiOHLCParams _iohlc_params(); // @todo Symbol should be already defined for a chart. // @todo If it's not, move initialization to GetValue()/GetEntry() method. @@ -78,9 +83,9 @@ class Indi_RS : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_MATH: return imath[_mode].Ptr().GetEntryValue(); break; diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index c900e6680..431d95470 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -22,7 +22,7 @@ // Includes. #include "../DictStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "Indi_Bands.mqh" #include "Indi_CCI.mqh" #include "Indi_Envelopes.mqh" @@ -51,10 +51,8 @@ struct IndiRSIParams : IndicatorParams { public: IndiRSIParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : applied_price(_ap), IndicatorParams(INDI_RSI, 1, TYPE_DOUBLE) { + : applied_price(_ap), IndicatorParams(INDI_RSI) { shift = _shift; - SetDataValueRange(IDATA_RANGE_RANGE); - // SetDataSourceType(IDATA_ICUSTOM); SetCustomIndicatorName("Examples\\RSI"); SetPeriod(_period); }; @@ -89,15 +87,19 @@ struct RSIGainLossData { /** * Implements the Relative Strength Index indicator. */ -class Indi_RSI : public Indicator { +class Indi_RSI : public IndicatorTickOrCandleSource { DictStruct aux_data; public: /** * Class constructor. */ - Indi_RSI(IndiRSIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_RSI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_RSI, _tf, _shift) {} + Indi_RSI(IndiRSIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + Indi_RSI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_RSI, _tf, _shift) {} /** * Returns the indicator value. @@ -107,7 +109,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, IndicatorBase *_obj = NULL) { + ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iRSI(_symbol, _tf, _period, _applied_price, _shift); #else // __MQL5__ @@ -119,7 +121,7 @@ class Indi_RSI : public Indicator { * Calculates non-SMMA version of RSI on another indicator (uses iRSIOnArray). */ template - static double iRSIOnArrayOnIndicator(IndicatorBase *_indi, string _symbol = NULL, + static double iRSIOnArrayOnIndicator(IndicatorData *_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) { @@ -153,7 +155,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(IndicatorBase *_indi, Indi_RSI *_obj, string _symbol = NULL, + static double iRSIOnIndicator(IndicatorData *_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); @@ -173,7 +175,7 @@ class Indi_RSI : public Indicator { RSIGainLossData last_data, new_data; unsigned int data_position; double diff; - int _mode = _obj.GetDataSourceMode(); + int _mode = _obj.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)); if (!_obj.aux_data.KeyExists(_bar_time_prev, data_position)) { // No previous SMMA-based average gain and loss. Calculating SMA-based ones. @@ -289,11 +291,11 @@ class Indi_RSI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; double _res[]; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_RSI::iRSI(GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), _ishift, THIS_PTR); @@ -314,7 +316,7 @@ class Indi_RSI : public Indicator { /** * Provides built-in indicators whose can be used as data source. */ - virtual IndicatorBase *FetchDataSource(ENUM_INDICATOR_TYPE _id) { + virtual IndicatorData *FetchDataSource(ENUM_INDICATOR_TYPE _id) { if (_id == INDI_BANDS) { IndiBandsParams bands_params; return new Indi_Bands(bands_params); @@ -338,6 +340,6 @@ class Indi_RSI : public Indicator { return new Indi_StdDev(stddev_params); } - return IndicatorBase::FetchDataSource(_id); + return IndicatorData::FetchDataSource(_id); } }; diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index 7256a4aa3..4b1458276 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -35,10 +35,8 @@ double iRVI(string _symbol, int _tf, int _period, int _mode, int _shift) { struct IndiRVIParams : IndicatorParams { unsigned int period; // Struct constructors. - IndiRVIParams(unsigned int _period = 10, int _shift = 0) - : period(_period), IndicatorParams(INDI_RVI, FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE) { + IndiRVIParams(unsigned int _period = 10, int _shift = 0) : period(_period), IndicatorParams(INDI_RVI) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\RVI"); }; IndiRVIParams(IndiRVIParams &_params, ENUM_TIMEFRAMES _tf) { @@ -50,13 +48,18 @@ struct IndiRVIParams : IndicatorParams { /** * Implements the Relative Vigor Index indicator. */ -class Indi_RVI : public Indicator { +class Indi_RVI : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_RVI(const IndiRVIParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_RVI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_RVI, _tf, _shift) {} + Indi_RVI(const IndiRVIParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_RVI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_RVI, _tf, _shift) {} /** * Returns the indicator value. @@ -68,7 +71,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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iRVI(_symbol, _tf, _period, _mode, _shift); #else // __MQL5__ @@ -103,10 +106,10 @@ class Indi_RVI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_RVI::iRVI(GetSymbol(), GetTf(), GetPeriod(), (ENUM_SIGNAL_LINE)_mode, _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index 076f4798a..a6c37dd26 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.price.h" // Structs. @@ -31,9 +31,8 @@ struct IndiRateOfChangeParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructor. IndiRateOfChangeParams(int _period = 12, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) - : IndicatorParams(INDI_RATE_OF_CHANGE, 1, TYPE_DOUBLE) { + : IndicatorParams(INDI_RATE_OF_CHANGE) { applied_price = _ap; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ROC"); period = _period; shift = _shift; @@ -47,21 +46,24 @@ struct IndiRateOfChangeParams : IndicatorParams { /** * Implements the Rate of Change indicator. */ -class Indi_RateOfChange : public Indicator { +class Indi_RateOfChange : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_RateOfChange(IndiRateOfChangeParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; + Indi_RateOfChange(IndiRateOfChangeParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; Indi_RateOfChange(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : Indicator(INDI_RATE_OF_CHANGE, _tf, _shift){}; + : IndicatorTickOrCandleSource(INDI_RATE_OF_CHANGE, _tf, _shift){}; /** * 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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_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); @@ -88,6 +90,16 @@ class Indi_RateOfChange : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Rate of Change. + */ + static double iROCOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( + _indi, _symbol, _tf, _ap, Util::MakeKey("Indi_RateOfChange_ON_" + _indi.GetFullName(), _period, (int)_ap)); + return iROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _mode, _shift, _cache); + } + /** * OnCalculate() method for Rate of Change indicator. */ @@ -110,10 +122,10 @@ class Indi_RateOfChange : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_RateOfChange::iROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); @@ -122,6 +134,10 @@ class Indi_RateOfChange : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_RateOfChange::iROCOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), + GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_SAR.mqh b/Indicators/Indi_SAR.mqh index f500fc007..c8a36e4c9 100644 --- a/Indicators/Indi_SAR.mqh +++ b/Indicators/Indi_SAR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -37,9 +37,8 @@ struct IndiSARParams : IndicatorParams { double max; // Struct constructors. IndiSARParams(double _step = 0.02, double _max = 0.2, int _shift = 0) - : step(_step), max(_max), IndicatorParams(INDI_SAR, 1, TYPE_DOUBLE) { + : step(_step), max(_max), IndicatorParams(INDI_SAR) { shift = _shift; - SetDataValueRange(IDATA_RANGE_PRICE); // @fixit It draws single dot for each bar! SetCustomIndicatorName("Examples\\ParabolicSAR"); }; IndiSARParams(IndiSARParams &_params, ENUM_TIMEFRAMES _tf) { @@ -51,13 +50,17 @@ struct IndiSARParams : IndicatorParams { /** * Implements the Parabolic Stop and Reverse system indicator. */ -class Indi_SAR : public Indicator { +class Indi_SAR : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_SAR(IndiSARParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_SAR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_SAR, _tf, _shift) {} + Indi_SAR(IndiSARParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) {} + Indi_SAR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_SAR, _tf, _shift) {} /** * Returns the indicator value. @@ -67,7 +70,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, IndicatorBase *_obj = NULL) { + double _max = 0.2, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iSAR(_symbol, _tf, _step, _max, _shift); #else // __MQL5__ @@ -102,10 +105,10 @@ class Indi_SAR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_SAR::iSAR(GetSymbol(), GetTf(), GetStep(), GetMax(), _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 46be6a1ac..17a7f250e 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -28,7 +28,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickSource.h" #include "../Storage/ObjectsCache.h" #include "Indi_MA.mqh" #include "Indi_PriceFeeder.mqh" @@ -59,9 +59,8 @@ struct IndiStdDevParams : IndicatorParams { ma_shift(_ma_shift), ma_method(_ma_method), applied_price(_ap), - IndicatorParams(INDI_STDDEV, 1, TYPE_DOUBLE) { + IndicatorParams(INDI_STDDEV) { shift = _shift; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\StdDev"); }; IndiStdDevParams(IndiStdDevParams &_params, ENUM_TIMEFRAMES _tf) { @@ -73,13 +72,17 @@ struct IndiStdDevParams : IndicatorParams { /** * Implements the Standard Deviation indicator. */ -class Indi_StdDev : public Indicator { +class Indi_StdDev : public IndicatorTickSource { public: /** * Class constructor. */ - Indi_StdDev(IndiStdDevParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_StdDev(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_STDDEV, _tf, _shift) {} + Indi_StdDev(IndiStdDevParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src) {} + Indi_StdDev(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_STDDEV, _tf, _shift) {} /** * Calculates the Standard Deviation indicator and returns its value. @@ -89,7 +92,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, IndicatorBase *_obj = NULL) { + ENUM_APPLIED_PRICE _applied_price, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iStdDev(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_price, _shift); #else // __MQL5__ @@ -124,13 +127,13 @@ class Indi_StdDev : public Indicator { /** * Note that this method operates on current price (set by _applied_price). */ - static double iStdDevOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, + static double iStdDevOnIndicator(IndicatorData *_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.GetDataSourceMode() : 0; + int _mode = _obj != NULL ? _obj.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)) : 0; ArrayResize(_indi_value_buffer, _ma_period); @@ -226,18 +229,17 @@ class Indi_StdDev : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_StdDev::iStdDev(GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - iparams.GetCustomIndicatorName(), /*[*/ GetMAPeriod(), GetMAShift(), GetMAMethod() /*]*/, 0, - _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetMAPeriod(), + GetMAShift(), GetMAMethod() /*]*/, 0, _ishift); break; case IDATA_INDICATOR: _value = Indi_StdDev::iStdDevOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index 722ac6120..3a5ec7444 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -48,9 +48,8 @@ struct IndiStochParams : IndicatorParams { slowing(_slowing), ma_method(_ma_method), price_field(_pf), - IndicatorParams(INDI_STOCHASTIC, FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE) { + IndicatorParams(INDI_STOCHASTIC) { shift = _shift; - SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\Stochastic"); }; IndiStochParams(IndiStochParams &_params, ENUM_TIMEFRAMES _tf) { @@ -62,13 +61,19 @@ struct IndiStochParams : IndicatorParams { /** * Implements the Stochastic Oscillator. */ -class Indi_Stochastic : public Indicator { +class Indi_Stochastic : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_Stochastic(IndiStochParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_Stochastic(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_STOCHASTIC, _tf, _shift) {} + Indi_Stochastic(IndiStochParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_SIGNAL_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + Indi_Stochastic(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_STOCHASTIC, _tf, _shift) {} /** * Calculates the Stochastic Oscillator and returns its value. @@ -83,7 +88,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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iStochastic(_symbol, _tf, _kperiod, _dperiod, _slowing, _ma_method, _price_field, _mode, _shift); #else // __MQL5__ @@ -119,10 +124,10 @@ class Indi_Stochastic : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Stochastic::iStochastic(GetSymbol(), GetTf(), GetKPeriod(), GetDPeriod(), GetSlowing(), GetMAMethod(), GetPriceField(), _mode, _ishift, THIS_PTR); diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index 3cc9e949b..73c71241c 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.price.h" #include "Indi_MA.mqh" @@ -33,9 +33,8 @@ struct IndiTEMAParams : IndicatorParams { ENUM_APPLIED_PRICE applied_price; // Struct constructor. IndiTEMAParams(int _period = 14, int _tema_shift = 0, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) - : IndicatorParams(INDI_TEMA, 1, TYPE_DOUBLE) { + : IndicatorParams(INDI_TEMA) { applied_price = _ap; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\TEMA"); period = _period; shift = _shift; @@ -50,13 +49,18 @@ struct IndiTEMAParams : IndicatorParams { /** * Implements the Triple Exponential Moving Average indicator. */ -class Indi_TEMA : public Indicator { +class Indi_TEMA : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_TEMA(IndiTEMAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_TEMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_TEMA, _tf, _shift){}; + Indi_TEMA(IndiTEMAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_TEMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_TEMA, _tf, _shift){}; /** * Built-in version of TEMA. @@ -94,6 +98,18 @@ class Indi_TEMA : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of TEMA. + */ + static double iTEMAOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, + int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, + IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( + _indi, _symbol, _tf, _ap, + Util::MakeKey("Indi_TEMA_ON_" + _indi.GetFullName(), _ma_period, _ma_shift, (int)_ap)); + return iTEMAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ma_period, _ma_shift, _mode, _shift, _cache); + } + /** * OnCalculate() method for TEMA indicator. * @@ -126,10 +142,10 @@ class Indi_TEMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_TEMA::iTEMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetTEMAShift(), GetAppliedPrice() /*]*/, 0, _ishift, THIS_PTR); @@ -138,6 +154,10 @@ class Indi_TEMA : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetTEMAShift() /*]*/, 0, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_TEMA::iTEMAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetTEMAShift(), + GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); break; diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index a8086bd27..c8be21d65 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.price.h" #include "Indi_MA.mqh" @@ -32,10 +32,8 @@ struct IndiTRIXParams : IndicatorParams { unsigned int tema_shift; ENUM_APPLIED_PRICE applied_price; // Struct constructor. - IndiTRIXParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) - : IndicatorParams(INDI_TRIX, 1, TYPE_DOUBLE) { + IndiTRIXParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_CLOSE, int _shift = 0) : IndicatorParams(INDI_TRIX) { applied_price = _ap; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\TRIX"); period = _period; shift = _shift; @@ -49,19 +47,24 @@ struct IndiTRIXParams : IndicatorParams { /** * Implements the Triple Exponential Average indicator. */ -class Indi_TRIX : public Indicator { +class Indi_TRIX : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_TRIX(IndiTRIXParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_TRIX(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_TRIX, _tf, _shift){}; + Indi_TRIX(IndiTRIXParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_TRIX(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_TRIX, _tf, _shift){}; /** * 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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iTriX(_symbol, _tf, _ma_period, _ap), _mode, _shift); #else @@ -93,6 +96,16 @@ class Indi_TRIX : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of TriX. + */ + static double iTriXOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, + ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( + _indi, _symbol, _tf, _ap, Util::MakeKey("Indi_TriX_ON_" + _indi.GetFullName(), _ma_period, (int)_ap)); + return iTriXOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _ma_period, _mode, _shift, _cache); + } + /** * OnCalculate() method for TriX indicator. */ @@ -127,10 +140,10 @@ class Indi_TRIX : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_TRIX::iTriX(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); @@ -139,6 +152,10 @@ class Indi_TRIX : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_TRIX::iTriXOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), + GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index 7788bd77b..906a79de3 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -22,13 +22,16 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" #include "Indi_ATR.mqh" #include "Indi_MA.mqh" // Structs. struct IndiUltimateOscillatorParams : IndicatorParams { + Ref indi_atr_fast; + Ref indi_atr_middle; + Ref indi_atr_slow; int fast_period; int middle_period; int slow_period; @@ -39,12 +42,11 @@ struct IndiUltimateOscillatorParams : IndicatorParams { // Struct constructor. IndiUltimateOscillatorParams(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) { + : IndicatorParams(INDI_ULTIMATE_OSCILLATOR) { fast_k = _fast_k; fast_period = _fast_period; middle_k = _middle_k; middle_period = _middle_period; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Ultimate_Oscillator"); shift = _shift; slow_k = _slow_k; @@ -59,30 +61,33 @@ struct IndiUltimateOscillatorParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_UltimateOscillator : public Indicator { +class Indi_UltimateOscillator : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_UltimateOscillator(IndiUltimateOscillatorParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; + Indi_UltimateOscillator(IndiUltimateOscillatorParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; Indi_UltimateOscillator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) - : Indicator(INDI_ULTIMATE_OSCILLATOR, _tf, _shift){}; + : IndicatorTickOrCandleSource(INDI_ULTIMATE_OSCILLATOR, _tf, _shift){}; /** * 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, - IndicatorBase *_obj = NULL) { + IndicatorData *_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)); - 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); + IndicatorData *_indi_atr_fast = Indi_ATR::GetCached(_symbol, _tf, _fast_period); + IndicatorData *_indi_atr_middle = Indi_ATR::GetCached(_symbol, _tf, _middle_period); + IndicatorData *_indi_atr_slow = Indi_ATR::GetCached(_symbol, _tf, _slow_period); 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); @@ -93,8 +98,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, IndicatorBase *_indi_atr_fast, - IndicatorBase *_indi_atr_middle, IndicatorBase *_indi_atr_slow, bool _recalculate = false) { + IndicatorCalculateCache *_cache, IndicatorData *_indi_atr_fast, + IndicatorData *_indi_atr_middle, IndicatorData *_indi_atr_slow, bool _recalculate = false) { _cache.SetPriceBuffer(_open, _high, _low, _close); if (!_cache.HasBuffers()) { @@ -113,6 +118,41 @@ class Indi_UltimateOscillator : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Ultimate Oscillator. + */ + static double iUOOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _fast_period, + int _middle_period, int _slow_period, int _fast_k, int _middle_k, int _slow_k, + int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, + Util::MakeKey("Indi_UltimateOscillator_ON_" + _indi.GetFullName(), _fast_period, _middle_period, _slow_period, + _fast_k, _middle_k, _slow_k)); + + // @fixit This won't work! Find a way to differentiate ATRs. + Indi_ATR *_indi_atr_fast = (Indi_ATR *)_indi.GetDataSource(INDI_ULTIMATE_OSCILLATOR_ATR_FAST); + Indi_ATR *_indi_atr_middle = (Indi_ATR *)_indi.GetDataSource(INDI_ULTIMATE_OSCILLATOR_ATR_MIDDLE); + Indi_ATR *_indi_atr_slow = (Indi_ATR *)_indi.GetDataSource(INDI_ULTIMATE_OSCILLATOR_ATR_SLOW); + + return iUOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _fast_period, _middle_period, _slow_period, _fast_k, + _middle_k, _slow_k, _mode, _shift, _cache, _indi_atr_fast, _indi_atr_middle, _indi_atr_slow); + } + + /** + * Provides built-in indicators whose can be used as data source. + */ + IndicatorData *FetchDataSource(ENUM_INDICATOR_TYPE _id) override { + switch (_id) { + case INDI_ULTIMATE_OSCILLATOR_ATR_FAST: + return iparams.indi_atr_fast.Ptr(); + case INDI_ULTIMATE_OSCILLATOR_ATR_MIDDLE: + return iparams.indi_atr_middle.Ptr(); + case INDI_ULTIMATE_OSCILLATOR_ATR_SLOW: + return iparams.indi_atr_slow.Ptr(); + } + return NULL; + } + /** * OnCalculate() method for Ultimate Oscillator. */ @@ -209,10 +249,10 @@ class Indi_UltimateOscillator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_UltimateOscillator::iUO(GetSymbol(), GetTf(), /*[*/ GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), GetMiddleK(), GetSlowK() /*]*/, _mode, @@ -225,6 +265,11 @@ class Indi_UltimateOscillator : public Indicator { /*]*/, 0, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_UltimateOscillator::iUOOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetFastPeriod(), + GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), GetMiddleK(), + GetSlowK() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index a5647974c..cf799aa28 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.price.h" // Structs. @@ -35,11 +35,10 @@ struct IndiVIDYAParams : IndicatorParams { // Struct constructor. IndiVIDYAParams(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) { + : IndicatorParams(INDI_VIDYA) { applied_price = _ap; cmo_period = _cmo_period; ma_period = _ma_period; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\VIDYA"); shift = _shift; vidya_shift = _vidya_shift; @@ -53,19 +52,24 @@ struct IndiVIDYAParams : IndicatorParams { /** * Implements the Variable Index Dynamic Average indicator. */ -class Indi_VIDYA : public Indicator { +class Indi_VIDYA : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_VIDYA(IndiVIDYAParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_VIDYA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_VIDYA, _tf, _shift){}; + Indi_VIDYA(IndiVIDYAParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_VIDYA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_VIDYA, _tf, _shift){}; /** * 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, IndicatorBase *_obj = NULL) { + ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iVIDyA(_symbol, _tf, _cmo_period, _ema_period, _ma_shift, _ap), _mode, _shift); #else @@ -98,6 +102,19 @@ class Indi_VIDYA : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of VIDya indicator. + */ + static double iVIDyAOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _cmo_period, + int _ema_period, int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, + IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS( + _indi, _symbol, _tf, _ap, + Util::MakeKey("Indi_VIDYA_ON_" + _indi.GetFullName(), _cmo_period, _ema_period, _ma_shift, (int)_ap)); + return iVIDyAOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _cmo_period, _ema_period, _ma_shift, _mode, _shift, + _cache); + } + /** * OnCalculate() method for VIDyA indicator. * @@ -147,10 +164,10 @@ class Indi_VIDYA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_VIDYA::iVIDyA(GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift(), GetAppliedPrice() /*]*/, 0, _ishift, THIS_PTR); @@ -162,6 +179,11 @@ class Indi_VIDYA : public Indicator { /*]*/, 0, _ishift); break; + case IDATA_INDICATOR: + _value = + Indi_VIDYA::iVIDyAOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), + GetVIDYAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index 2170fa831..98433c611 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. @@ -31,10 +31,9 @@ struct IndiVROCParams : IndicatorParams { ENUM_APPLIED_VOLUME applied_volume; // Struct constructor. IndiVROCParams(unsigned int _period = 25, ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0) - : IndicatorParams(INDI_VROC, 1, TYPE_DOUBLE) { + : IndicatorParams(INDI_VROC) { applied_volume = _applied_volume; period = _period; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\VROC"); shift = _shift; }; @@ -47,25 +46,30 @@ struct IndiVROCParams : IndicatorParams { /** * Implements the Volume Rate of Change indicator. */ -class Indi_VROC : public Indicator { +class Indi_VROC : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_VROC(IndiVROCParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_VROC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_VROC, _tf, _shift){}; + Indi_VROC(IndiVROCParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_VROC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_VROC, _tf, _shift){}; /** * 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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_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); } /** - * Calculates AMVROC on the array of values. + * Calculates VROC on the array of values. */ static double iVROCOnArray(INDICATOR_CALCULATE_PARAMS_LONG, int _period, ENUM_APPLIED_VOLUME _av, int _mode, int _shift, IndicatorCalculateCache *_cache, bool _recalculate = false) { @@ -85,6 +89,16 @@ class Indi_VROC : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of VROC indicator. + */ + static double iVROCOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, Util::MakeKey("Indi_VROC_ON_" + _indi.GetFullName(), _period, (int)_av)); + return iVROCOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _period, _av, _mode, _shift, _cache); + } + /** * OnCalculate() method for VROC indicator. */ @@ -130,10 +144,10 @@ class Indi_VROC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_VROC::iVROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); @@ -142,6 +156,10 @@ class Indi_VROC : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_VROC::iVROCOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetPeriod(), + GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index 786f9fbbe..46a12532c 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -22,19 +22,16 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. struct IndiVolumesParams : IndicatorParams { ENUM_APPLIED_VOLUME applied_volume; // Struct constructor. - IndiVolumesParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0) - : IndicatorParams(INDI_VOLUMES, 2, TYPE_DOUBLE) { + IndiVolumesParams(ENUM_APPLIED_VOLUME _applied_volume = VOLUME_TICK, int _shift = 0) : IndicatorParams(INDI_VOLUMES) { applied_volume = _applied_volume; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Volumes"); - SetDataSourceType(IDATA_BUILTIN); shift = _shift; }; IndiVolumesParams(IndiVolumesParams &_params, ENUM_TIMEFRAMES _tf) { @@ -44,21 +41,26 @@ struct IndiVolumesParams : IndicatorParams { }; /** - * Implements the Bill Williams' Accelerator/Decelerator oscillator. + * Implements the Volumes indicator. */ -class Indi_Volumes : public Indicator { +class Indi_Volumes : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_Volumes(IndiVolumesParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_Volumes(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_VOLUMES, _tf, _shift){}; + Indi_Volumes(IndiVolumesParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_Volumes(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_VOLUMES, _tf, _shift){}; /** * Built-in version of Volumes. */ static double iVolumes(string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0, - IndicatorBase *_obj = NULL) { + IndicatorData *_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); } @@ -84,6 +86,16 @@ class Indi_Volumes : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Volumes indicator. + */ + static double iVolumesOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_VOLUME _av, + int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, Util::MakeKey("Indi_Volumes_ON_" + _indi.GetFullName(), (int)_av)); + return iVolumesOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _av, _mode, _shift, _cache); + } + /** * OnCalculate() method for Volumes indicator. */ @@ -124,10 +136,10 @@ class Indi_Volumes : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_Volumes::iVolumes(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); break; @@ -135,6 +147,10 @@ class Indi_Volumes : public Indicator { _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_Volumes::iVolumesOnIndicator(GetDataSource(), GetSymbol(), GetTf(), + /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_WPR.mqh b/Indicators/Indi_WPR.mqh index 0e7a22bd1..f53c655ec 100644 --- a/Indicators/Indi_WPR.mqh +++ b/Indicators/Indi_WPR.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). @@ -35,10 +35,8 @@ double iWPR(string _symbol, int _tf, int _period, int _shift) { struct IndiWPRParams : IndicatorParams { unsigned int period; // Struct constructors. - IndiWPRParams(unsigned int _period = 14, int _shift = 0) - : period(_period), IndicatorParams(INDI_WPR, 1, TYPE_DOUBLE) { + IndiWPRParams(unsigned int _period = 14, int _shift = 0) : period(_period), IndicatorParams(INDI_WPR) { shift = _shift; - SetDataValueRange(IDATA_RANGE_RANGE); SetCustomIndicatorName("Examples\\WPR"); }; IndiWPRParams(IndiWPRParams &_params, ENUM_TIMEFRAMES _tf) { @@ -50,13 +48,17 @@ struct IndiWPRParams : IndicatorParams { /** * Implements the Larry Williams' Percent Range. */ -class Indi_WPR : public Indicator { +class Indi_WPR : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_WPR(IndiWPRParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_WPR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_WPR, _tf, _shift) {} + Indi_WPR(IndiWPRParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_RANGE, _indi_src_mode), + _indi_src) {} + Indi_WPR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_WPR, _tf, _shift) {} /** * Calculates the Larry Williams' Percent Range and returns its value. @@ -66,7 +68,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, IndicatorBase *_obj = NULL) { + int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iWPR(_symbol, _tf, _period, _shift); #else // __MQL5__ @@ -101,10 +103,10 @@ class Indi_WPR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_WPR::iWPR(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); break; diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index 754cff808..5a09d153c 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -22,14 +22,13 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. struct IndiWilliamsADParams : IndicatorParams { // Struct constructor. - IndiWilliamsADParams(int _shift = 0) : IndicatorParams(INDI_WILLIAMS_AD, 1, TYPE_DOUBLE) { - SetDataValueRange(IDATA_RANGE_MIXED); + IndiWilliamsADParams(int _shift = 0) : IndicatorParams(INDI_WILLIAMS_AD) { SetCustomIndicatorName("Examples\\W_AD"); shift = _shift; }; @@ -42,19 +41,23 @@ struct IndiWilliamsADParams : IndicatorParams { /** * Implements the Volume Rate of Change indicator. */ -class Indi_WilliamsAD : public Indicator { +class Indi_WilliamsAD : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_WilliamsAD(IndiWilliamsADParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; - Indi_WilliamsAD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_WILLIAMS_AD, _tf, _shift){}; + Indi_WilliamsAD(IndiWilliamsADParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_WilliamsAD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_WILLIAMS_AD, _tf, _shift){}; /** * Built-in version of Williams' AD. */ - static double iWAD(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { + static double iWAD(string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_WilliamsAD"); return iWADOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -80,6 +83,16 @@ class Indi_WilliamsAD : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Williams' AD. + */ + static double iWADOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, + int _shift = 0, IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(_indi, _symbol, _tf, + Util::MakeKey("Indi_WilliamsAD_ON_" + _indi.GetFullName())); + return iWADOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); + } + /** * OnCalculate() method for Williams' AD indicator. */ @@ -124,16 +137,19 @@ class Indi_WilliamsAD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_WilliamsAD::iWAD(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), 0, _ishift); break; + case IDATA_INDICATOR: + _value = Indi_WilliamsAD::iWADOnIndicator(GetDataSource(), GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); } diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index 64f7da7c9..ad6effa22 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -21,7 +21,7 @@ */ // Includes. -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Enums. @@ -35,13 +35,9 @@ struct IndiZigZagParams : IndicatorParams { unsigned int backstep; // Struct constructors. IndiZigZagParams(unsigned int _depth = 12, unsigned int _deviation = 5, unsigned int _backstep = 3, int _shift = 0) - : depth(_depth), - deviation(_deviation), - backstep(_backstep), - IndicatorParams(INDI_ZIGZAG, FINAL_ZIGZAG_LINE_ENTRY, TYPE_DOUBLE) { + : depth(_depth), deviation(_deviation), backstep(_backstep), IndicatorParams(INDI_ZIGZAG) { shift = _shift; SetCustomIndicatorName("Examples\\ZigZag"); - SetDataValueRange(IDATA_RANGE_PRICE); // @fixit Draws lines between lowest and highest prices! }; IndiZigZagParams(IndiZigZagParams &_params, ENUM_TIMEFRAMES _tf) { THIS_REF = _params; @@ -58,19 +54,25 @@ enum EnSearchMode { /** * Implements ZigZag indicator. */ -class Indi_ZigZag : public Indicator { +class Indi_ZigZag : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_ZigZag(IndiZigZagParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_ZigZag(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_ZIGZAG, _tf, _shift) {} + Indi_ZigZag(IndiZigZagParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_ZIGZAG_LINE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE_ON_SIGNAL), + _indi_src) {} + Indi_ZigZag(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_ZIGZAG, _tf, _shift) {} /** * 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, IndicatorBase *_obj = NULL) { + int _backstep, ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL5__ int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; double _res[]; @@ -135,6 +137,18 @@ class Indi_ZigZag : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of ZigZag indicator. + */ + static double iZigZagOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _depth, + int _deviation, int _backstep, int _mode = 0, int _shift = 0, + IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, Util::MakeKey("Indi_ZigZag_ON_" + _indi.GetFullName(), _depth, _deviation, _backstep)); + return iZigZagOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, _shift, + _cache); + } + /** * OnCalculate() method for ZigZag indicator. */ @@ -334,17 +348,22 @@ class Indi_ZigZag : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_ZigZag::iZigZag(GetSymbol(), GetTf(), GetDepth(), GetDeviation(), GetBackstep(), + _value = Indi_ZigZag::iZigZag(GetSymbol(), GetTf(), /*[*/ GetDepth(), GetDeviation(), GetBackstep() /*]*/, (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = Indi_ZigZag::iCustomZigZag(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), GetDepth(), - GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); + _value = + Indi_ZigZag::iCustomZigZag(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetDepth(), + GetDeviation(), GetBackstep() /*]*/, (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); + break; + case IDATA_INDICATOR: + _value = Indi_ZigZag::iZigZagOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetDepth(), + GetDeviation(), GetBackstep() /*]*/, _mode, _ishift, THIS_PTR); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 26489fd8f..4dd0303a4 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" #include "Indi_ZigZag.mqh" @@ -35,11 +35,10 @@ struct IndiZigZagColorParams : IndicatorParams { // Struct constructor. IndiZigZagColorParams(unsigned int _depth = 12, unsigned int _deviation = 5, unsigned int _backstep = 3, int _shift = 0) - : IndicatorParams(INDI_ZIGZAG_COLOR, 3, TYPE_DOUBLE) { + : IndicatorParams(INDI_ZIGZAG_COLOR) { backstep = _backstep; depth = _depth; deviation = _deviation; - SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ZigZagColor"); shift = _shift; }; @@ -52,20 +51,24 @@ struct IndiZigZagColorParams : IndicatorParams { /** * Implements the Volume Rate of Change indicator. */ -class Indi_ZigZagColor : public Indicator { +class Indi_ZigZagColor : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_ZigZagColor(IndiZigZagColorParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src){}; - Indi_ZigZagColor(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_VROC, _tf, _shift){}; + Indi_ZigZagColor(IndiZigZagColorParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), + _indi_src){}; + Indi_ZigZagColor(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_VROC, _tf, _shift){}; /** * Returns value for ZigZag Color indicator. */ static double iZigZagColor(string _symbol, ENUM_TIMEFRAMES _tf, int _depth, int _deviation, int _backstep, - ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0, IndicatorBase *_obj = NULL) { + ENUM_ZIGZAG_LINE _mode = 0, int _shift = 0, IndicatorData *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG( _symbol, _tf, Util::MakeKey("Indi_ZigZagColor", _depth, _deviation, _backstep)); return iZigZagColorOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, _shift, @@ -96,6 +99,19 @@ class Indi_ZigZagColor : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of ZigZag indicator. + */ + static double iZigZagColorOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _depth, + int _deviation, int _backstep, int _mode = 0, int _shift = 0, + IndicatorData *_obj = NULL) { + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS( + _indi, _symbol, _tf, + Util::MakeKey("Indi_ZigZagColor_ON_" + _indi.GetFullName(), _depth, _deviation, _backstep)); + return iZigZagColorOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _depth, _deviation, _backstep, _mode, _shift, + _cache); + } + /** * OnCalculate() method for ZigZag Color indicator. */ @@ -268,18 +284,23 @@ class Indi_ZigZagColor : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: - _value = Indi_ZigZagColor::iZigZagColor(GetSymbol(), GetTf(), GetDepth(), GetDeviation(), GetBackstep(), - (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); + _value = Indi_ZigZagColor::iZigZagColor(GetSymbol(), GetTf(), /*[*/ GetDepth(), GetDeviation(), + GetBackstep() /*]*/, (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetDepth(), GetDeviation(), GetBackstep() /*]*/, _mode, _ishift); break; + case IDATA_INDICATOR: + _value = + Indi_ZigZagColor::iZigZagColorOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetDepth(), + GetDeviation(), GetBackstep() /*]*/, _mode, _ishift, THIS_PTR); + break; default: SetUserError(ERR_INVALID_PARAMETER); break; diff --git a/Indicators/OHLC/Indi_OHLC.mqh b/Indicators/OHLC/Indi_OHLC.mqh index 7d7d26d93..21fa2319d 100644 --- a/Indicators/OHLC/Indi_OHLC.mqh +++ b/Indicators/OHLC/Indi_OHLC.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/IndicatorTickOrCandleSource.h" #include "../../Storage/Objects.h" // Enums. @@ -37,9 +37,7 @@ enum ENUM_INDI_OHLC_MODE { // Structs. struct IndiOHLCParams : IndicatorParams { // Struct constructor. - IndiOHLCParams(int _shift = 0) : IndicatorParams(INDI_OHLC, FINAL_INDI_OHLC_MODE_ENTRY, TYPE_DOUBLE) { - SetShift(_shift); - }; + IndiOHLCParams(int _shift = 0) : IndicatorParams(INDI_OHLC) { SetShift(_shift); }; IndiOHLCParams(IndiOHLCParams &_params, ENUM_TIMEFRAMES _tf) { THIS_REF = _params; tf = _tf; @@ -49,18 +47,24 @@ struct IndiOHLCParams : IndicatorParams { /** * OHLC Indicator. */ -class Indi_OHLC : public Indicator { +class Indi_OHLC : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_OHLC(IndiOHLCParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_OHLC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_PRICE, _tf, _shift){}; + Indi_OHLC(IndiOHLCParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource(_p, + IndicatorDataParams::GetInstance(FINAL_INDI_OHLC_MODE_ENTRY, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + Indi_OHLC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_PRICE, _tf, _shift){}; /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); ENUM_APPLIED_PRICE _ap = PRICE_OPEN; switch (_mode) { diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index 74cd43db8..e8a97a0c6 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -22,15 +22,14 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/IndicatorTickOrCandleSource.h" #include "../../Storage/Objects.h" // Structs. struct PriceIndiParams : IndicatorParams { ENUM_APPLIED_PRICE ap; // Struct constructor. - PriceIndiParams(ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) - : ap(_ap), IndicatorParams(INDI_PRICE, 1, TYPE_DOUBLE) { + PriceIndiParams(ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) : ap(_ap), IndicatorParams(INDI_PRICE) { SetShift(_shift); }; PriceIndiParams(PriceIndiParams &_params, ENUM_TIMEFRAMES _tf) { @@ -46,13 +45,18 @@ struct PriceIndiParams : IndicatorParams { /** * Price Indicator. */ -class Indi_Price : public Indicator { +class Indi_Price : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_Price(PriceIndiParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_Price(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_PRICE, _tf, _shift){}; + Indi_Price(PriceIndiParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src){}; + Indi_Price(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_PRICE, _tf, _shift){}; /** * Checks whether indicator has a valid value for a given shift. @@ -62,7 +66,7 @@ class Indi_Price : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); return ChartStatic::iPrice(iparams.GetAppliedPrice(), GetSymbol(), GetTf(), _ishift); } @@ -86,4 +90,54 @@ class Indi_Price : public Indicator { } return _indi_price; } + + /** + * Returns value storage of given kind. + */ + IValueStorage *GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + // Returning Price indicator which provides applied price in the only buffer #0. + switch (_type) { + case INDI_VS_TYPE_PRICE_ASK: // Tick. + case INDI_VS_TYPE_PRICE_BID: // Tick. + return GetCached(GetSymbol(), iparams.GetAppliedPrice(), GetTf(), iparams.GetShift()).GetValueStorage(0); + case INDI_VS_TYPE_PRICE_OPEN: // Candle. + return GetCached(GetSymbol(), PRICE_OPEN, GetTf(), iparams.GetShift()).GetValueStorage(0); + case INDI_VS_TYPE_PRICE_HIGH: // Candle. + return GetCached(GetSymbol(), PRICE_HIGH, GetTf(), iparams.GetShift()).GetValueStorage(0); + case INDI_VS_TYPE_PRICE_LOW: // Candle. + return GetCached(GetSymbol(), PRICE_LOW, GetTf(), iparams.GetShift()).GetValueStorage(0); + case INDI_VS_TYPE_PRICE_CLOSE: // Candle. + return GetCached(GetSymbol(), PRICE_CLOSE, GetTf(), iparams.GetShift()).GetValueStorage(0); + case INDI_VS_TYPE_PRICE_MEDIAN: // Candle. + return GetCached(GetSymbol(), PRICE_MEDIAN, GetTf(), iparams.GetShift()).GetValueStorage(0); + case INDI_VS_TYPE_PRICE_TYPICAL: // Candle. + return GetCached(GetSymbol(), PRICE_TYPICAL, GetTf(), iparams.GetShift()).GetValueStorage(0); + case INDI_VS_TYPE_PRICE_WEIGHTED: // Candle. + return GetCached(GetSymbol(), PRICE_WEIGHTED, GetTf(), iparams.GetShift()).GetValueStorage(0); + default: + // Trying in parent class. + return Indicator::GetSpecificValueStorage(_type); + } + } + + /** + * Checks whether indicator support given value storage type. + */ + bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + switch (_type) { + case INDI_VS_TYPE_PRICE_ASK: // Tick. + case INDI_VS_TYPE_PRICE_BID: // Tick. + case INDI_VS_TYPE_PRICE_OPEN: // Candle. + case INDI_VS_TYPE_PRICE_HIGH: // Candle. + case INDI_VS_TYPE_PRICE_LOW: // Candle. + case INDI_VS_TYPE_PRICE_CLOSE: // Candle. + case INDI_VS_TYPE_PRICE_MEDIAN: // Candle. + case INDI_VS_TYPE_PRICE_TYPICAL: // Candle. + case INDI_VS_TYPE_PRICE_WEIGHTED: // Candle. + return true; + default: + // Trying in parent class. + return Indicator::HasSpecificValueStorage(_type); + } + } }; diff --git a/Indicators/Special/Indi_Custom.mqh b/Indicators/Special/Indi_Custom.mqh index d35236289..c23a3c19f 100644 --- a/Indicators/Special/Indi_Custom.mqh +++ b/Indicators/Special/Indi_Custom.mqh @@ -33,7 +33,7 @@ #endif // Includes. -#include "../../Indicator.mqh" +#include "../../Indicator/IndicatorTickOrCandleSource.h" // Structs. @@ -41,9 +41,8 @@ struct IndiCustomParams : public IndicatorParams { DataParamEntry iargs[]; // Struct constructors. - IndiCustomParams(string _filepath = INDI_CUSTOM_PATH, int _shift = 0) : IndicatorParams(INDI_CUSTOM, 1, TYPE_DOUBLE) { + IndiCustomParams(string _filepath = INDI_CUSTOM_PATH, int _shift = 0) : IndicatorParams(INDI_CUSTOM) { custom_indi_name = _filepath; - SetDataSourceType(IDATA_ICUSTOM); } IndiCustomParams(IndiCustomParams &_params, ENUM_TIMEFRAMES _tf) { THIS_REF = _params; @@ -74,13 +73,18 @@ struct IndiCustomParams : public IndicatorParams { /** * Implements indicator class. */ -class Indi_Custom : public Indicator { +class Indi_Custom : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_Custom(IndiCustomParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src) {} - Indi_Custom(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(INDI_CUSTOM, _tf){}; + Indi_Custom(IndiCustomParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_ICUSTOM, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_UNKNOWN, _indi_src_mode), + _indi_src) {} + Indi_Custom(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_CUSTOM, _tf, _shift){}; /** * Returns the indicator's value. @@ -88,21 +92,20 @@ class Indi_Custom : public Indicator { IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_ICUSTOM: switch (iparams.GetParamsSize()) { case 0: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - iparams.custom_indi_name, _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, _mode, _ishift); break; case 1: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - iparams.custom_indi_name, iparams.GetParam(1).ToValue(), _mode, _ishift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, + iparams.GetParam(1).ToValue(), _mode, _ishift); break; case 2: - _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), - iparams.custom_indi_name, iparams.GetParam(1).ToValue(), - iparams.GetParam(2).ToValue(), _mode, _ishift); + _value = + iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, + iparams.GetParam(1).ToValue(), iparams.GetParam(2).ToValue(), _mode, _ishift); break; } break; diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index 033377c04..dcf43f01b 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/IndicatorTickOrCandleSource.h" #include "../../Math.enum.h" enum ENUM_MATH_OP_MODE { MATH_OP_MODE_BUILTIN, MATH_OP_MODE_CUSTOM_FUNCTION }; @@ -43,13 +43,11 @@ struct IndiMathParams : IndicatorParams { IndiMathParams(ENUM_MATH_OP _op = MATH_OP_SUB, unsigned int _mode_1 = 0, unsigned int _mode_2 = 1, unsigned int _shift_1 = 0, unsigned int _shift_2 = 0, int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) - : IndicatorParams(INDI_SPECIAL_MATH, 1, TYPE_DOUBLE) { + : IndicatorParams(INDI_SPECIAL_MATH) { mode_1 = _mode_1; mode_2 = _mode_2; op_builtin = _op; op_mode = MATH_OP_MODE_BUILTIN; - SetDataValueRange(IDATA_RANGE_MIXED); - SetDataSourceType(IDATA_INDICATOR); shift = _shift; shift_1 = _shift_1; shift_2 = _shift_2; @@ -60,14 +58,11 @@ struct IndiMathParams : IndicatorParams { IndiMathParams(MathCustomOpFunction _op, unsigned int _mode_1 = 0, unsigned int _mode_2 = 1, unsigned int _shift_1 = 0, unsigned int _shift_2 = 0, int _shift = 0, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) - : IndicatorParams(INDI_SPECIAL_MATH, 1, TYPE_DOUBLE) { - max_modes = 1; + : IndicatorParams(INDI_SPECIAL_MATH) { mode_1 = _mode_1; mode_2 = _mode_2; op_fn = _op; op_mode = MATH_OP_MODE_CUSTOM_FUNCTION; - SetDataValueRange(IDATA_RANGE_MIXED); - SetDataSourceType(IDATA_INDICATOR); shift = _shift; shift_1 = _shift_1; shift_2 = _shift_2; @@ -82,21 +77,26 @@ struct IndiMathParams : IndicatorParams { /** * Implements the Volume Rate of Change indicator. */ -class Indi_Math : public Indicator { +class Indi_Math : public IndicatorTickOrCandleSource { public: /** * Class constructor. */ - Indi_Math(IndiMathParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_Math(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_SPECIAL_MATH, _tf, _shift){}; + Indi_Math(IndiMathParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_INDICATOR, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTickOrCandleSource( + _p, IndicatorDataParams::GetInstance(1, TYPE_DOUBLE, _idstype, IDATA_RANGE_MIXED, _indi_src_mode), + _indi_src){}; + Indi_Math(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_SPECIAL_MATH, _tf, _shift){}; /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - switch (iparams.idstype) { + switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_INDICATOR: if (!indi_src.IsSet()) { GetLogger().Error( @@ -129,19 +129,19 @@ class Indi_Math : public Indicator { return _value; } - static double iMathOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, ENUM_MATH_OP op, + static double iMathOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, ENUM_MATH_OP op, unsigned int _mode_1, unsigned int _mode_2, unsigned int _shift_1, unsigned int _shift_2, unsigned int _mode, int _shift, Indi_Math *_obj) { - double _val_1 = _indi.GetValue(_shift_1, _mode_1); - double _val_2 = _indi.GetValue(_shift_2, _mode_2); + double _val_1 = _indi.GetValue(_mode_1, _shift_1); + double _val_2 = _indi.GetValue(_mode_2, _shift_2); return Math::Op(op, _val_1, _val_2); } - static double iMathOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, MathCustomOpFunction _op, + static double iMathOnIndicator(IndicatorData *_indi, string _symbol, ENUM_TIMEFRAMES _tf, MathCustomOpFunction _op, unsigned int _mode_1, unsigned int _mode_2, unsigned int _shift_1, unsigned int _shift_2, unsigned int _mode, int _shift, Indi_Math *_obj) { - double _val_1 = _indi.GetValue(_shift_1, _mode_1); - double _val_2 = _indi.GetValue(_shift_2, _mode_2); + double _val_1 = _indi.GetValue(_mode_1, _shift_1); + double _val_2 = _indi.GetValue(_mode_2, _shift_2); return _op(_val_1, _val_2); } diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index fd83cfdc7..8b1b39d4a 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -21,16 +21,15 @@ */ // Includes. -#include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" -#include "../../Storage/Objects.h" +#include "../../Indicator/IndicatorTick.h" // Structs. struct IndiTickMtParams : IndicatorParams { string symbol; // Struct constructor. - IndiTickMtParams(string _symbol = NULL, int _shift = 0) : IndicatorParams(INDI_TICK, 3, TYPE_DOUBLE) { + IndiTickMtParams(string _symbol = NULL, int _shift = 0) : IndicatorParams(INDI_TICK) { SetShift(_shift); + SetSymbol(_symbol); }; IndiTickMtParams(IndiTickMtParams &_params, ENUM_TIMEFRAMES _tf) { THIS_REF = _params; @@ -45,33 +44,53 @@ struct IndiTickMtParams : IndicatorParams { /** * Price Indicator. */ -class Indi_TickMt : public Indicator { +class Indi_TickMt : public IndicatorTick { + protected: + MqlTick tick; + public: /** * Class constructor. */ - Indi_TickMt(IndiTickMtParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; - Indi_TickMt(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_TICK, _tf, _shift){}; + Indi_TickMt(IndiTickMtParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : IndicatorTick(_p, IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype), + _indi_src){}; + Indi_TickMt(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "") + : IndicatorTick(INDI_TICK, _tf, _shift, _name) {} /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { - int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - MqlTick _tick = SymbolInfoStatic::GetTick(_Symbol); - switch (_mode) { - case 0: - return _tick.ask; - case 1: - return _tick.bid; - case 2: + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { + if (_shift == 0) { + // Fetch a current prices of a specified symbol. + tick = SymbolInfoStatic::GetTick(itparams.GetSymbol()); + switch (_mode) { + case 0: + return tick.ask; + case 1: + return tick.bid; + case 2: #ifdef __MQL4__ - return _tick.volume; + return tick.volume; #else - return _tick.volume_real; + return tick.volume_real; #endif + } + SetUserError(ERR_INVALID_PARAMETER); } - SetUserError(ERR_INVALID_PARAMETER); return DBL_MAX; } + + /** + * Alters indicator's struct value. + * + * This method allows user to modify the struct entry before it's added to cache. + * This method is called on GetEntry() right after values are set. + */ + virtual void GetEntryAlter(IndicatorDataEntry &_entry, int _shift = 0) { + IndicatorTick::GetEntryAlter(_entry, _shift); + _entry.timestamp = _entry.timestamp > 0 ? _entry.timestamp : tick.time; + }; }; diff --git a/Indicators/Tick/tests/Indi_TickMt.test.mq5 b/Indicators/Tick/tests/Indi_TickMt.test.mq5 index 4c9572767..e77d1ee23 100644 --- a/Indicators/Tick/tests/Indi_TickMt.test.mq5 +++ b/Indicators/Tick/tests/Indi_TickMt.test.mq5 @@ -36,7 +36,6 @@ Indi_TickMt indi(PERIOD_CURRENT); 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); } @@ -45,7 +44,7 @@ int OnInit() { */ void OnTick() { static MqlTick _tick_last; - MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + MqlTick _tick_new = indi.GetTick(); if (_tick_new.time % 60 < _tick_last.time % 60) { // Process ticks each minute. if (_tick_new.time % 3600 < _tick_last.time % 3600) { diff --git a/MQL4.mqh b/MQL4.mqh index 42901ff73..b3e5c850c 100644 --- a/MQL4.mqh +++ b/MQL4.mqh @@ -155,29 +155,30 @@ class MT4HISTORY { const datetime LastTimeCurrent = ::TimeCurrent(); - if ((!MT4HISTORY::IsTester) && (LastTimeCurrent >= this.LastInitTime + DAY)) { - this.LastTime = 0; + if ((!MT4HISTORY::IsTester) && (LastTimeCurrent >= this PTR_DEREF LastInitTime + DAY)) { + this PTR_DEREF LastTime = 0; - this.LastTotalOrders = 0; - this.LastTotalDeals = 0; + this PTR_DEREF LastTotalOrders = 0; + this PTR_DEREF LastTotalDeals = 0; - this.Amount = 0; + this PTR_DEREF Amount = 0; - ::ArrayResize(this.Tickets, this.Amount, RESERVE_SIZE); + ::ArrayResize(this PTR_DEREF Tickets, this PTR_DEREF Amount, RESERVE_SIZE); - this.LastInitTime = LastTimeCurrent; + this PTR_DEREF LastInitTime = LastTimeCurrent; } - if (::HistorySelect(this.LastTime, ::MathMax(LastTimeCurrent, this.LastTime) + DAY)) // Daily stock. + if (::HistorySelect(this PTR_DEREF LastTime, + ::MathMax(LastTimeCurrent, this PTR_DEREF LastTime) + DAY)) // Daily stock. { const int TotalOrders = ::HistoryOrdersTotal(); const int TotalDeals = ::HistoryDealsTotal(); - Res = ((TotalOrders != this.LastTotalOrders) || (TotalDeals != this.LastTotalDeals)); + Res = ((TotalOrders != this PTR_DEREF LastTotalOrders) || (TotalDeals != this PTR_DEREF LastTotalDeals)); if (Res) { - int iOrder = MT4HISTORY::GetNextPosMT4Order(this.LastTotalOrders); - int iDeal = MT4HISTORY::GetNextPosMT4Deal(this.LastTotalDeals); + int iOrder = MT4HISTORY::GetNextPosMT4Order(this PTR_DEREF LastTotalOrders); + int iDeal = MT4HISTORY::GetNextPosMT4Deal(this PTR_DEREF LastTotalDeals); long TimeOrder = (iOrder < TotalOrders) ? ::HistoryOrderGetInteger(::HistoryOrderGetTicket(iOrder), ORDER_TIME_DONE /*_MSC*/) @@ -188,9 +189,9 @@ class MT4HISTORY { while ((iDeal < TotalDeals) || (iOrder < TotalOrders)) if (TimeOrder < TimeDeal) { - this.Amount = ::ArrayResize(this.Tickets, this.Amount + 1, RESERVE_SIZE); + this PTR_DEREF Amount = ::ArrayResize(this PTR_DEREF Tickets, this PTR_DEREF Amount + 1, RESERVE_SIZE); - this.Tickets[this.Amount - 1] = -(long)::HistoryOrderGetTicket(iOrder); + this PTR_DEREF Tickets[this PTR_DEREF Amount - 1] = -(long)::HistoryOrderGetTicket(iOrder); iOrder = MT4HISTORY::GetNextPosMT4Order(iOrder + 1); @@ -198,9 +199,9 @@ class MT4HISTORY { ? ::HistoryOrderGetInteger(::HistoryOrderGetTicket(iOrder), ORDER_TIME_DONE /*_MSC*/) : LONG_MAX; // ORDER_TIME_DONE_MSC returns zero in the tester (build 1470). } else { - this.Amount = ::ArrayResize(this.Tickets, this.Amount + 1, RESERVE_SIZE); + this PTR_DEREF Amount = ::ArrayResize(this PTR_DEREF Tickets, this PTR_DEREF Amount + 1, RESERVE_SIZE); - this.Tickets[this.Amount - 1] = (long)::HistoryDealGetTicket(iDeal); + this PTR_DEREF Tickets[this PTR_DEREF Amount - 1] = (long)::HistoryDealGetTicket(iDeal); iDeal = MT4HISTORY::GetNextPosMT4Deal(iDeal + 1); @@ -216,19 +217,19 @@ class MT4HISTORY { const long MaxTime = ::MathMax(TimeOrder, TimeDeal); - this.LastTotalOrders = 0; - this.LastTotalDeals = 0; + this PTR_DEREF LastTotalOrders = 0; + this PTR_DEREF LastTotalDeals = 0; if (LastTimeCurrent - HISTORY_PAUSE > MaxTime) - this.LastTime = LastTimeCurrent - HISTORY_PAUSE; + this PTR_DEREF LastTime = LastTimeCurrent - HISTORY_PAUSE; else { - this.LastTime = (datetime)MaxTime; + this PTR_DEREF LastTime = (datetime)MaxTime; if (TimeOrder == MaxTime) for (int i = TotalOrders - 1; i >= 0; i--) { if (TimeOrder > ::HistoryOrderGetInteger(::HistoryOrderGetTicket(i), ORDER_TIME_DONE /*_MSC*/)) break; - this.LastTotalOrders++; + this PTR_DEREF LastTotalOrders++; } if (TimeDeal == MaxTime) @@ -236,14 +237,14 @@ class MT4HISTORY { if (TimeDeal != ::HistoryDealGetInteger(::HistoryDealGetTicket(TotalDeals - 1), DEAL_TIME /*_MSC*/)) break; - this.LastTotalDeals++; + this PTR_DEREF LastTotalDeals++; } } - } else if (LastTimeCurrent - HISTORY_PAUSE > this.LastTime) { - this.LastTime = LastTimeCurrent - HISTORY_PAUSE; + } else if (LastTimeCurrent - HISTORY_PAUSE > this PTR_DEREF LastTime) { + this PTR_DEREF LastTime = LastTimeCurrent - HISTORY_PAUSE; - this.LastTotalOrders = 0; - this.LastTotalDeals = 0; + this PTR_DEREF LastTotalOrders = 0; + this PTR_DEREF LastTotalDeals = 0; } } @@ -264,26 +265,26 @@ class MT4HISTORY { } MT4HISTORY(void) : Amount(0), LastTime(0), LastTotalDeals(0), LastTotalOrders(0), LastInitTime(0) { - ::ArrayResize(this.Tickets, this.Amount, RESERVE_SIZE); + ::ArrayResize(this PTR_DEREF Tickets, this PTR_DEREF Amount, RESERVE_SIZE); - this.RefreshHistory(); + this PTR_DEREF RefreshHistory(); } int GetAmount(void) { - this.RefreshHistory(); + this PTR_DEREF RefreshHistory(); - return ((int)this.Amount); + return ((int)this PTR_DEREF Amount); } long operator[](const uint Pos) { long Res = 0; - if (Pos >= this.Amount) { - this.RefreshHistory(); + if (Pos >= this PTR_DEREF Amount) { + this PTR_DEREF RefreshHistory(); - if (Pos < this.Amount) Res = this.Tickets[Pos]; + if (Pos < this PTR_DEREF Amount) Res = this PTR_DEREF Tickets[Pos]; } else - Res = this.Tickets[Pos]; + Res = this PTR_DEREF Tickets[Pos]; return (Res); } @@ -325,16 +326,19 @@ struct MT4_ORDER { string ToString(void) const { static const string Types[] = {"buy", "sell", "buy limit", "sell limit", "buy stop", "sell stop", "balance"}; - const int digits = (int)::SymbolInfoInteger(this.Symbol, SYMBOL_DIGITS); - - return ("#" + (string)this.Ticket + " " + (string)this.OpenTime + " " + - ((this.Type < ::ArraySize(Types)) ? Types[this.Type] : "unknown") + " " + ::DoubleToString(this.Lots, 2) + - " " + this.Symbol + " " + ::DoubleToString(this.OpenPrice, digits) + " " + - ::DoubleToString(this.StopLoss, digits) + " " + ::DoubleToString(this.TakeProfit, digits) + " " + - ((this.CloseTime > 0) ? ((string)this.CloseTime + " ") : "") + ::DoubleToString(this.ClosePrice, digits) + - " " + ::DoubleToString(this.Commission, 2) + " " + ::DoubleToString(this.Swap, 2) + " " + - ::DoubleToString(this.Profit, 2) + " " + ((this.Comment == "") ? "" : (this.Comment + " ")) + - (string)this.MagicNumber + (((this.Expiration > 0) ? (" expiration " + (string)this.Expiration) : ""))); + const int digits = (int)::SymbolInfoInteger(this PTR_DEREF Symbol, SYMBOL_DIGITS); + + return ( + "#" + (string)this PTR_DEREF Ticket + " " + (string)this PTR_DEREF OpenTime + " " + + ((this PTR_DEREF Type < ::ArraySize(Types)) ? Types[this PTR_DEREF Type] : "unknown") + " " + + ::DoubleToString(this PTR_DEREF Lots, 2) + " " + this PTR_DEREF Symbol + " " + + ::DoubleToString(this PTR_DEREF OpenPrice, digits) + " " + ::DoubleToString(this PTR_DEREF StopLoss, digits) + + " " + ::DoubleToString(this PTR_DEREF TakeProfit, digits) + " " + + ((this PTR_DEREF CloseTime > 0) ? ((string)this PTR_DEREF CloseTime + " ") : "") + + ::DoubleToString(this PTR_DEREF ClosePrice, digits) + " " + ::DoubleToString(this PTR_DEREF Commission, 2) + + " " + ::DoubleToString(this PTR_DEREF Swap, 2) + " " + ::DoubleToString(this PTR_DEREF Profit, 2) + " " + + ((this PTR_DEREF Comment == "") ? "" : (this PTR_DEREF Comment + " ")) + (string)this PTR_DEREF MagicNumber + + (((this PTR_DEREF Expiration > 0) ? (" expiration " + (string)this PTR_DEREF Expiration) : ""))); } }; diff --git a/MQL5.mqh b/MQL5.mqh index e230f6f61..584a74fd2 100644 --- a/MQL5.mqh +++ b/MQL5.mqh @@ -307,92 +307,4 @@ #define ERR_USER_ERROR_FIRST 65536 // User defined errors start with this code. #endif -/** - * MQL5 wrapper to work in MQL4. - */ -class MQL5 { - - public: - // Enums. - #ifdef __MQL4__ - // Trading operations. - enum ENUM_TRADE_REQUEST_ACTIONS { - // @see: https://www.mql5.com/en/docs/constants/tradingconstants/enum_trade_request_actions - TRADE_ACTION_DEAL, // Place a trade order for an immediate execution with the specified parameters (market order). - TRADE_ACTION_PENDING, // Place a trade order for the execution under specified conditions (pending order). - TRADE_ACTION_SLTP, // Modify Stop Loss and Take Profit values of an opened position. - TRADE_ACTION_MODIFY, // Modify the parameters of the order placed previously. - TRADE_ACTION_REMOVE, // Delete the pending order placed previously. - TRADE_ACTION_CLOSE_BY // Close a position by an opposite one. - }; - // Fill Policy. - enum ENUM_SYMBOL_FILLING { - // @see: https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties - SYMBOL_FILLING_FOK = 1, // A deal can be executed only with the specified volume. - SYMBOL_FILLING_IOC = 2 // Trader agrees to execute a deal with the volume maximally available in the market. - }; - enum ENUM_ORDER_TYPE_FILLING { - // @see: https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties - ORDER_FILLING_FOK, // An order can be filled only in the specified amount. - ORDER_FILLING_IOC, // A trader agrees to execute a deal with the volume maximally available in the market. - ORDER_FILLING_RETURN // In case of partial filling a market or limit order with remaining volume is not canceled but processed further. - }; - enum ENUM_ORDER_TYPE_TIME { - // @see: https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties - ORDER_TIME_GTC, // Good till cancel order. - ORDER_TIME_DAY, // Good till current trade day order. - ORDER_TIME_SPECIFIED, // Good till expired order. - ORDER_TIME_SPECIFIED_DAY // The order will be effective till 23:59:59 of the specified day. - }; - // An order status that describes its state. - enum ENUM_ORDER_STATE { - ORDER_STATE_STARTED, // Order checked, but not yet accepted by broker - ORDER_STATE_PLACED, // Order accepted - ORDER_STATE_CANCELED, // Order canceled by client - ORDER_STATE_PARTIAL, // Order partially executed - ORDER_STATE_FILLED, // Order fully executed - ORDER_STATE_REJECTED, // Order rejected - ORDER_STATE_EXPIRED, // Order expired - ORDER_STATE_REQUEST_ADD, // Order is being registered (placing to the trading system) - ORDER_STATE_REQUEST_MODIFY, // Order is being modified (changing its parameters) - ORDER_STATE_REQUEST_CANCEL // Order is being deleted (deleting from the trading system) - }; - #endif - - #ifdef __MQL4__ - // @see: https://www.mql5.com/en/docs/constants/structures/mqltraderequest - struct MqlTradeRequest { - ENUM_TRADE_REQUEST_ACTIONS action; // Trade operation type. - ulong magic; // Expert Advisor ID (magic number). - ulong order; // Order ticket. - string symbol; // Trade symbol. - double volume; // Requested volume for a deal in lots. - double price; // Price. - double stoplimit; // StopLimit level of the order. - double sl; // Stop Loss level of the order. - double tp; // Take Profit level of the order. - ulong deviation; // Maximal possible deviation from the requested price. - ENUM_ORDER_TYPE type; // Order type. - ENUM_ORDER_TYPE_FILLING type_filling; // Order execution type. - ENUM_ORDER_TYPE_TIME type_time; // Order expiration type. - datetime expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type. - string comment; // Order comment. - ulong position; // Position ticket. - ulong position_by; // The ticket of an opposite position. - }; - // @see: https://www.mql5.com/en/docs/constants/structures/mqltraderesult - struct MqlTradeResult { - uint retcode; // Operation return code. - ulong deal; // Deal ticket, if it is performed. - ulong order; // Order ticket, if it is placed. - double volume; // Deal volume, confirmed by broker. - double price; // Deal price, confirmed by broker. - double bid; // Current Bid price. - double ask; // Current Ask price. - string comment; // Broker comment to operation (by default it is filled by description of trade server return code). - uint request_id; // Request ID set by the terminal during the dispatch. - uint retcode_external; // Return code of an external trading system. - }; - #endif -}; #endif // MQL5_MQH diff --git a/Mail.mqh b/Mail.mqh index 9ff20a1b1..f41078561 100644 --- a/Mail.mqh +++ b/Mail.mqh @@ -44,10 +44,10 @@ class Mail { * Constructor. */ Mail(string _subject_prefix = "Trading Info: ") { - this.string_dlm = " "; - this.string_nl = "
\n"; - this.subject_execute_order = __FILE__; - this.subject_prefix = _subject_prefix; + this PTR_DEREF string_dlm = " "; + this PTR_DEREF string_nl = "
\n"; + this PTR_DEREF subject_execute_order = __FILE__; + this PTR_DEREF subject_prefix = _subject_prefix; } /* Getters */ @@ -55,12 +55,12 @@ class Mail { /** * Gets subject prefix. */ - string GetMailSubjectPrefix() { return this.subject_prefix; } + string GetMailSubjectPrefix() { return this PTR_DEREF subject_prefix; } /** * Gets subject on execute order. */ - string GetMailSubjectExecuteOrder() { return this.subject_execute_order; } + string GetMailSubjectExecuteOrder() { return this PTR_DEREF subject_execute_order; } /** * Get content of e-mail for executing order. @@ -87,41 +87,45 @@ class Mail { /** * Gets string delimiter. */ - string GetStringDlm() { return this.string_dlm; } + string GetStringDlm() { return this PTR_DEREF string_dlm; } /** * Gets string new line separator. */ - string GetStringNl() { return this.string_nl; } + string GetStringNl() { return this PTR_DEREF string_nl; } /** * Get subject of e-mail for executing order. * * Note: Order needs to be selected before calling this function. */ - string GetSubjectExecuteOrder() { return GetMailSubjectPrefix() + this.string_dlm + GetMailSubjectExecuteOrder(); } + string GetSubjectExecuteOrder() { + return GetMailSubjectPrefix() + this PTR_DEREF string_dlm + GetMailSubjectExecuteOrder(); + } /* Setters */ /** * Sets subject prefix. */ - void SetSubjectPrefix(string _subject_prefix) { this.subject_prefix = _subject_prefix; } + void SetSubjectPrefix(string _subject_prefix) { this PTR_DEREF subject_prefix = _subject_prefix; } /** * Sets subject on execute order. */ - void SetSubjectExecuteOrder(string _subject_execute_order) { this.subject_execute_order = _subject_execute_order; } + void SetSubjectExecuteOrder(string _subject_execute_order) { + this PTR_DEREF subject_execute_order = _subject_execute_order; + } /** * Sets string delimiter. */ - void SetStringDlm(string _dlm) { this.string_dlm = _dlm; } + void SetStringDlm(string _dlm) { this PTR_DEREF string_dlm = _dlm; } /** * Sets string new line separator. */ - void SetStringNl(string _nl) { this.string_nl = _nl; } + void SetStringNl(string _nl) { this PTR_DEREF string_nl = _nl; } /* Mailing methods */ diff --git a/Math.define.h b/Math.define.h index 82ac071dd..8e519a71f 100644 --- a/Math.define.h +++ b/Math.define.h @@ -36,3 +36,25 @@ #define fmin4(_v1, _v2, _v3, _v4) fmin(fmin(fmin(_v1, _v2), _v3), _v4) #define fmin5(_v1, _v2, _v3, _v4, _v5) fmin(fmin(fmin(fmin(_v1, _v2), _v3), _v4), _v5) #define fmin6(_v1, _v2, _v3, _v4, _v5, _v6) fmin(fmin(fmin(fmin(fmin(_v1, _v2), _v3), _v4), _v5), _v6) + +#ifdef __cplusplus +#include + +#define CHAR_MIN std::numeric_limits::min() +#define CHAR_MAX std::numeric_limits::max() +#define UCHAR_MAX std::numeric_limits::max() +#define SHORT_MAX std::numeric_limits::max() +#define SHORT_MIN std::numeric_limits::min() +#define USHORT_MAX std::numeric_limits::max() +#define INT_MIN std::numeric_limits::min() +#define INT_MAX std::numeric_limits::max() +#define UINT_MAX std::numeric_limits::max() +#define LONG_MIN std::numeric_limits::min() +#define LONG_MAX std::numeric_limits::max() +#define ULONG_MAX std::numeric_limits::max() +#define FLT_MIN std::numeric_limits::min() +#define FLT_MAX std::numeric_limits::max() +#define DBL_MIN std::numeric_limits::min() +#define DBL_MAX std::numeric_limits::max() + +#endif diff --git a/Math.extern.h b/Math.extern.h new file mode 100644 index 000000000..4dce9bfe7 --- /dev/null +++ b/Math.extern.h @@ -0,0 +1,49 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Define external global functions. +#ifndef __MQL__ +template +extern T MathAbs(T value); +template +extern T fabs(T value); +template +extern T pow(T base, T exponent); +template +extern T MathPow(T base, T exponent); +template +extern T round(T value); +template +extern T MathRound(T value); +template +extern T fmax(T value1, T value2); +template +extern T MathMax(T value1, T value2); +template +extern T fmin(T value1, T value2); +template +extern T MathMin(T value1, T value2); +template +extern T MathLog10(T value1); +template +extern T log10(T value); +#endif diff --git a/Math.h b/Math.h index 4edd25801..691837b31 100644 --- a/Math.h +++ b/Math.h @@ -30,6 +30,7 @@ #include "Indicator.struct.h" #include "Math.define.h" #include "Math.enum.h" +#include "Math.extern.h" #include "Math.struct.h" /** diff --git a/Matrix.mqh b/Matrix.mqh index 069588d7f..59f3eef39 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -1494,8 +1494,9 @@ class Matrix { return NULL; } - if (_weights != NULL && _weights.GetDimensions() > this.GetDimensions()) { - Print("MeanAbsolute(): Shape ", Repr(), ": Weights must be a tensor level <= ", this.GetDimensions(), "!"); + if (_weights != NULL && _weights.GetDimensions() > this PTR_DEREF GetDimensions()) { + Print("MeanAbsolute(): Shape ", Repr(), ": Weights must be a tensor level <= ", this PTR_DEREF GetDimensions(), + "!"); return NULL; } diff --git a/Object.enum.h b/Object.enum.h new file mode 100644 index 000000000..68d22f513 --- /dev/null +++ b/Object.enum.h @@ -0,0 +1,38 @@ +//+------------------------------------------------------------------+ +//| EA31337 - multi-strategy advanced trading robot. | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes enumerations used for objects. + */ + +#ifndef __MQLBUILD__ +// Used for checking the type of the object pointer. +// @docs +// - https://docs.mql4.com/constants/namedconstants/enum_pointer_type +// - https://www.mql5.com/en/docs/constants/namedconstants/enum_pointer_type +enum ENUM_POINTER_TYPE { + POINTER_INVALID, // Incorrect pointer. + POINTER_DYNAMIC, // Pointer of the object created by the new() operator. + POINTER_AUTOMATIC // Pointer of any objects created automatically (not using new()). +}; +#endif diff --git a/Object.extern.h b/Object.extern.h new file mode 100644 index 000000000..f8b97dbd8 --- /dev/null +++ b/Object.extern.h @@ -0,0 +1,29 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes external declarations related to objects. + */ +#ifndef __MQL__ +extern void *GetPointer(void *anyobject); +#endif diff --git a/Object.mqh b/Object.mqh index 36f69ec28..d0dd1fadb 100644 --- a/Object.mqh +++ b/Object.mqh @@ -25,146 +25,114 @@ #define OBJECT_MQH // Includes. +#include "Object.enum.h" +#include "Object.extern.h" #include "Refs.mqh" +#include "Refs.struct.h" #include "String.mqh" -#ifndef __MQLBUILD__ -// Used for checking the type of the object pointer. -// @docs -// - https://docs.mql4.com/constants/namedconstants/enum_pointer_type -// - https://www.mql5.com/en/docs/constants/namedconstants/enum_pointer_type -enum ENUM_POINTER_TYPE { - POINTER_INVALID, // Incorrect pointer. - POINTER_DYNAMIC, // Pointer of the object created by the new() operator. - POINTER_AUTOMATIC // Pointer of any objects created automatically (not using new()). -}; -#endif - /** * Class to deal with objects. */ class Object : public Dynamic { - - protected: - - void *obj; - long id; - - public: - - /** - * Class constructor. - */ - Object() - : id(rand()), obj(THIS_PTR) - { - } - Object(void *_obj, long _id = __LINE__) { - obj = _obj; - id = _id; - } - - /* Getters */ - - /** - * Get ID of the object. - */ - virtual long GetId() { - return id; - } - - /* Setters */ - - /** - * Set ID of the object. - */ - void SetId(long _id) { - id = _id; - } - - /** - * Get the object handler. - */ - static void *Get(void *_obj) { - return Object::IsValid(_obj) ? _obj : NULL; - } - void *Get() { - return IsValid(obj) ? obj : NULL; - } - - /** - * Check whether pointer is valid. - * @docs: https://docs.mql4.com/constants/namedconstants/enum_pointer_type - */ - static bool IsValid(void *_obj) { - #ifdef __MQL__ - return CheckPointer(_obj) != POINTER_INVALID; - #else - return _obj != nullptr; - #endif - } - bool IsValid() { - return IsValid(obj); - } - - /** - * Check whether pointer is dynamic. - * @docs: https://docs.mql4.com/constants/namedconstants/enum_pointer_type - */ - static bool IsDynamic(void *_obj) { - #ifdef __MQL__ - return CheckPointer(_obj) == POINTER_DYNAMIC; - #else - // In C++ we can't check it. - // @fixme We should fire a warning here so user won't use this method anymore. - return true; - #endif - } - bool IsDynamic() { - return IsDynamic(obj); - } - - /** - * Returns text representation of the object. - */ - virtual const string ToString() { - return StringFormat("[Object #%04x]", GetPointer(this)); - } - - /** - * Returns text representation of the object. - */ - virtual const string ToJSON() { - return StringFormat("{ \"type\": \"%s\" }", typename(this)); - } - - /** - * Safely delete the object. - */ - static void Delete(void *_obj) { - #ifdef __MQL__ - if (CheckPointer(_obj) == POINTER_DYNAMIC) { - #else - if (true) { - #endif - delete _obj; - } - } - void Delete() { - Delete(obj); + protected: + void *obj; + long id; + + public: + /** + * Class constructor. + */ + Object() : obj(THIS_PTR), id(rand()) {} + Object(void *_obj, long _id = __LINE__) { + obj = _obj; + id = _id; + } + + /* Getters */ + + /** + * Get ID of the object. + */ + virtual long GetId() { return id; } + + /* Setters */ + + /** + * Set ID of the object. + */ + void SetId(long _id) { id = _id; } + + /** + * Get the object handler. + */ + static void *Get(void *_obj) { return Object::IsValid(_obj) ? _obj : NULL; } + void *Get() { return IsValid(obj) ? obj : NULL; } + + /** + * Check whether pointer is valid. + * @docs: https://docs.mql4.com/constants/namedconstants/enum_pointer_type + */ + static bool IsValid(void *_obj) { +#ifdef __MQL__ + return CheckPointer(_obj) != POINTER_INVALID; +#else + return _obj != nullptr; +#endif + } + bool IsValid() { return IsValid(obj); } + + /** + * Check whether pointer is dynamic. + * @docs: https://docs.mql4.com/constants/namedconstants/enum_pointer_type + */ + static bool IsDynamic(void *_obj) { +#ifdef __MQL__ + return CheckPointer(_obj) == POINTER_DYNAMIC; +#else + // In C++ we can't check it. + // @fixme We should fire a warning here so user won't use this method anymore. + return true; +#endif + } + bool IsDynamic() { return IsDynamic(obj); } + + /** + * Returns text representation of the object. + */ + virtual const string ToString() { return StringFormat("[Object #%04x]", GetPointer(this)); } + + /** + * Returns text representation of the object. + */ + virtual const string ToJSON() { return StringFormat("{ \"type\": \"%s\" }", typename(this)); } + + /** + * Safely delete the object. + */ + template + static void Delete(T *_obj) { +#ifdef __cplusplus + static_assert(!std::is_same::value, + "Please avoid deleting void* pointers as no destructor will be called!"); +#endif +#ifdef __MQL__ + if (CheckPointer(_obj) == POINTER_DYNAMIC) { +#else + if (true) { +#endif + delete _obj; } + } - /* Virtual methods */ - - /** - * Weight of the object. - */ - virtual double GetWeight() { - return 0; - }; + /* Virtual methods */ + /** + * Weight of the object. + */ + virtual double GetWeight() { return 0; }; }; // Initialize static global variables. -//Object *Object::list = { 0 }; -#endif // OBJECT_MQH +// Object *Object::list = { 0 }; +#endif // OBJECT_MQH diff --git a/Order.enum.h b/Order.enum.h index 385aebb30..c6489a73d 100644 --- a/Order.enum.h +++ b/Order.enum.h @@ -114,6 +114,33 @@ enum ENUM_ORDER_REASON { ORDER_REASON_TP, // The order was placed as a result of Take Profit activation. ORDER_REASON_WEB, // The order was placed from a web platform. }; +// An order status that describes its state. +enum ENUM_ORDER_STATE { + ORDER_STATE_STARTED, // Order checked, but not yet accepted by broker + ORDER_STATE_PLACED, // Order accepted + ORDER_STATE_CANCELED, // Order canceled by client + ORDER_STATE_PARTIAL, // Order partially executed + ORDER_STATE_FILLED, // Order fully executed + ORDER_STATE_REJECTED, // Order rejected + ORDER_STATE_EXPIRED, // Order expired + ORDER_STATE_REQUEST_ADD, // Order is being registered (placing to the trading system) + ORDER_STATE_REQUEST_MODIFY, // Order is being modified (changing its parameters) + ORDER_STATE_REQUEST_CANCEL // Order is being deleted (deleting from the trading system) +}; +enum ENUM_ORDER_TYPE_FILLING { + // @see: https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties + ORDER_FILLING_FOK, // An order can be filled only in the specified amount. + ORDER_FILLING_IOC, // A trader agrees to execute a deal with the volume maximally available in the market. + ORDER_FILLING_RETURN // In case of partial filling a market or limit order with remaining volume is not canceled but + // processed further. +}; +enum ENUM_ORDER_TYPE_TIME { + // @see: https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties + ORDER_TIME_GTC, // Good till cancel order. + ORDER_TIME_DAY, // Good till current trade day order. + ORDER_TIME_SPECIFIED, // Good till expired order. + ORDER_TIME_SPECIFIED_DAY // The order will be effective till 23:59:59 of the specified day. +}; #endif #ifndef __MQ4__ @@ -294,4 +321,15 @@ enum ENUM_POSITION_TYPE { POSITION_TYPE_BUY, // Buy position. POSITION_TYPE_SELL // Sell position. }; + +// Trading operations. +enum ENUM_TRADE_REQUEST_ACTIONS { + // @see: https://www.mql5.com/en/docs/constants/tradingconstants/enum_trade_request_actions + TRADE_ACTION_DEAL, // Place a trade order for an immediate execution with the specified parameters (market order). + TRADE_ACTION_PENDING, // Place a trade order for the execution under specified conditions (pending order). + TRADE_ACTION_SLTP, // Modify Stop Loss and Take Profit values of an opened position. + TRADE_ACTION_MODIFY, // Modify the parameters of the order placed previously. + TRADE_ACTION_REMOVE, // Delete the pending order placed previously. + TRADE_ACTION_CLOSE_BY // Close a position by an opposite one. +}; #endif diff --git a/Order.mqh b/Order.mqh index 466d81b7e..32fae5441 100644 --- a/Order.mqh +++ b/Order.mqh @@ -39,7 +39,7 @@ #include "Order.define.h" #include "Order.enum.h" #include "Order.struct.h" -#include "Serializer.mqh" +#include "SerializerConverter.mqh" #include "SerializerJson.mqh" #include "Std.h" #include "String.mqh" @@ -2735,7 +2735,7 @@ class Order : public SymbolInfo { * Returns order details in text. */ string const ToString() { - SerializerConverter stub(Serializer::MakeStubObject(SERIALIZER_FLAG_SKIP_HIDDEN)); + SerializerConverter stub(SerializerConverter::MakeStubObject(SERIALIZER_FLAG_SKIP_HIDDEN)); return SerializerConverter::FromObject(THIS_REF, SERIALIZER_FLAG_SKIP_HIDDEN) .ToString(SERIALIZER_FLAG_SKIP_HIDDEN, &stub); } diff --git a/Order.struct.h b/Order.struct.h index d2bda532e..dfc4792d2 100644 --- a/Order.struct.h +++ b/Order.struct.h @@ -54,6 +54,41 @@ struct MqlTradeCheckResult { double margin_level; // Margin level. string comment; // Comment to the reply code (description of the error). }; + +// @see: https://www.mql5.com/en/docs/constants/structures/mqltraderequest +struct MqlTradeRequest { + ENUM_TRADE_REQUEST_ACTIONS action; // Trade operation type. + ulong magic; // Expert Advisor ID (magic number). + ulong order; // Order ticket. + string symbol; // Trade symbol. + double volume; // Requested volume for a deal in lots. + double price; // Price. + double stoplimit; // StopLimit level of the order. + double sl; // Stop Loss level of the order. + double tp; // Take Profit level of the order. + ulong deviation; // Maximal possible deviation from the requested price. + ENUM_ORDER_TYPE type; // Order type. + ENUM_ORDER_TYPE_FILLING type_filling; // Order execution type. + ENUM_ORDER_TYPE_TIME type_time; // Order expiration type. + datetime expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type. + string comment; // Order comment. + ulong position; // Position ticket. + ulong position_by; // The ticket of an opposite position. +}; + +// @see: https://www.mql5.com/en/docs/constants/structures/mqltraderesult +struct MqlTradeResult { + uint retcode; // Operation return code. + ulong deal; // Deal ticket, if it is performed. + ulong order; // Order ticket, if it is placed. + double volume; // Deal volume, confirmed by broker. + double price; // Deal price, confirmed by broker. + double bid; // Current Bid price. + double ask; // Current Ask price. + string comment; // Broker comment to operation (by default it is filled by description of trade server return code). + uint request_id; // Request ID set by the terminal during the dispatch. + uint retcode_external; // Return code of an external trading system. +}; #endif /** diff --git a/Orders.mqh b/Orders.mqh index 57afd15a5..b245450c4 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -550,9 +550,9 @@ class Orders { double GetRealizedPL() const { double profit = 0; for (int i = 0; i <= numberOrders; ++i) { - if (this.orders[i].getOrderType() == ORDER_FINAL) { + if (this PTR_DEREF orders[i].getOrderType() == ORDER_FINAL) { // @todo - // profit += this.orders[i].getOrderProfit(); + // profit += this PTR_DEREF orders[i].getOrderProfit(); } } return profit; @@ -569,8 +569,8 @@ class Orders { double GetUnrealizedPL() const { double profit = 0; for (int i = 0; i <= numberOrders; ++i) { - if (this.orders[i].getOrderType() != ORDER_FINAL) { - profit += this.orders[i].getOrderProfit(); + if (this PTR_DEREF orders[i].getOrderType() != ORDER_FINAL) { + profit += this PTR_DEREF orders[i].getOrderProfit(); } } return profit; @@ -579,7 +579,7 @@ class Orders { double GetTotalEquity() const { double profit = 0; for (int i = 0; i <= numberOrders; ++i) { - profit += this.orders[i].GetOrderProfit(); + profit += this PTR_DEREF orders[i].GetOrderProfit(); } return profit; } @@ -587,7 +587,7 @@ class Orders { double GetTotalCommission() const { double commission = 0; for (int i = 0; i <= numberOrders; ++i) { - commission += this.orders[i].GetOrderCommission(); + commission += this PTR_DEREF orders[i].GetOrderCommission(); } return commission; } @@ -595,7 +595,7 @@ class Orders { double GetTotalSwap() const { double swap = 0; for (int i = 0; i <= numberOrders; ++i) { - swap += this.orders[i].GetOrderSwap(); + swap += this PTR_DEREF orders[i].GetOrderSwap(); } return swap; } diff --git a/Pattern.struct.h b/Pattern.struct.h index 2297c7c51..83422f4a6 100644 --- a/Pattern.struct.h +++ b/Pattern.struct.h @@ -32,8 +32,8 @@ // Includes. #include "Bar.struct.h" -#include "Pattern.enum.h" #include "Math.define.h" +#include "Pattern.enum.h" // Defines structure for bitwise pattern values. struct PatternBitwise { diff --git a/Refs.mqh b/Refs.mqh index bc71b2138..07b530ff4 100644 --- a/Refs.mqh +++ b/Refs.mqh @@ -25,7 +25,7 @@ #define REFS_MQH // Includes. -#include "Refs.struct.h" +#include "Refs.rc.h" #include "Std.h" /** @@ -66,54 +66,6 @@ // Forward class declaration. class Dynamic; -class ReferenceCounter { - public: - /** - * Number of weak references to target object. - */ - unsigned int num_weak_refs; - - /** - * Number of strong references to target object. - */ - unsigned int num_strong_refs; - - /** - * Target object pointer. - */ - Dynamic* ptr_object; - - /** - * Whether object has been deleted (but still have weak references). - */ - bool deleted; - - /** - * Constructor. - */ - ReferenceCounter() { - num_weak_refs = 0; - num_strong_refs = 0; - ptr_object = NULL; - deleted = false; - } - - string Debug() { return StringFormat("%d: %d strong, %d weak", ptr_object, num_strong_refs, num_weak_refs); } - - /** - * ReferenceCounter class allocator. - */ - static ReferenceCounter* alloc(); -}; - -/** - * ReferenceCounter class allocator. - */ -ReferenceCounter* ReferenceCounter::alloc() { - // @todo Enhance with linked-list object reuse. - return new ReferenceCounter(); -} - /** * Base class for reference-counted objects. */ diff --git a/Refs.rc.h b/Refs.rc.h new file mode 100644 index 000000000..c24c32b0f --- /dev/null +++ b/Refs.rc.h @@ -0,0 +1,82 @@ +//+------------------------------------------------------------------+ +//| 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 Refs' ReferenceCounter struct. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Forward declarations. +class Dynamic; + +class ReferenceCounter { + public: + /** + * Number of weak references to target object. + */ + unsigned int num_weak_refs; + + /** + * Number of strong references to target object. + */ + unsigned int num_strong_refs; + + /** + * Target object pointer. + */ + Dynamic* ptr_object; + + /** + * Whether object has been deleted (but still have weak references). + */ + bool deleted; + + /** + * Constructor. + */ + ReferenceCounter() { + num_weak_refs = 0; + num_strong_refs = 0; + ptr_object = NULL; + deleted = false; + } + + string Debug() { return StringFormat("%d: %d strong, %d weak", ptr_object, num_strong_refs, num_weak_refs); } + + /** + * ReferenceCounter class allocator. + */ + static ReferenceCounter* alloc(); +}; + +/** + * ReferenceCounter class allocator. + */ +ReferenceCounter* ReferenceCounter::alloc() { + // @todo Enhance with linked-list object reuse. + return new ReferenceCounter(); +} diff --git a/Refs.struct.h b/Refs.struct.h index 60ad53306..c63b4322f 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -30,9 +30,12 @@ #pragma once #endif +// Includes. +#include "Refs.rc.h" +#include "Std.h" + +class Dynamic; // Forward class declaration. -class Refs; -class ReferenceCounter; template struct WeakRef; @@ -140,19 +143,19 @@ struct Ref { ptr_object = NULL; return; } - if (ptr_object.ptr_ref_counter == NULL) { + if (PTR_ATTRIB(ptr_object, ptr_ref_counter) == NULL) { // Object is not reference counted. Maybe a stack-based one? return; } // Dropping strong reference. - if (!--ptr_object.ptr_ref_counter.num_strong_refs) { + if (!--PTR_ATTRIB2(ptr_object, ptr_ref_counter, num_strong_refs)) { #ifdef __debug_ref__ Print(ptr_object.ptr_ref_counter.Debug()); #endif // No more strong references. - if (!ptr_object.ptr_ref_counter.num_weak_refs) { - if (CheckPointer(ptr_object.ptr_ref_counter) == POINTER_INVALID) { + if (!PTR_ATTRIB2(ptr_object, ptr_ref_counter, num_weak_refs)) { + if (CheckPointer(PTR_ATTRIB(ptr_object, ptr_ref_counter)) == POINTER_INVALID) { // Serious problem. #ifndef __MQL4__ // Bug: Avoid calling in MQL4 due to 'global initialization failed' error. @@ -162,11 +165,11 @@ struct Ref { } // Also no more weak references. - delete ptr_object.ptr_ref_counter; - ptr_object.ptr_ref_counter = NULL; + delete PTR_ATTRIB(ptr_object, ptr_ref_counter); + PTR_ATTRIB(ptr_object, ptr_ref_counter) = NULL; } else { // Object becomes deleted, but there are some weak references. - ptr_object.ptr_ref_counter.deleted = true; + PTR_ATTRIB(PTR_ATTRIB(ptr_object, ptr_ref_counter), deleted) = true; } // Avoiding delete loop for cyclic references. @@ -182,7 +185,7 @@ struct Ref { } // Avoiding double deletion in Dynamic's destructor. - ptr_object.ptr_ref_counter = NULL; + PTR_ATTRIB(ptr_object, ptr_ref_counter) = NULL; ptr_object = NULL; #ifdef __debug__ @@ -210,11 +213,11 @@ struct Ref { ptr_object = _ptr; if (ptr_object != NULL) { - if (CheckPointer(ptr_object) == POINTER_INVALID || ptr_object.ptr_ref_counter == NULL) { + if (CheckPointer(ptr_object) == POINTER_INVALID || PTR_ATTRIB(ptr_object, ptr_ref_counter) == NULL) { // Double check the pointer for invalid references. Can happen very rarely. return Ptr(); } - ++ptr_object.ptr_ref_counter.num_strong_refs; + ++PTR_ATTRIB(PTR_ATTRIB(ptr_object, ptr_ref_counter), num_strong_refs); #ifdef __debug_ref__ Print(ptr_object.ptr_ref_counter.Debug()); #endif @@ -276,15 +279,15 @@ struct WeakRef { */ ~WeakRef() { Unset(); } - bool ObjectExists() { return ptr_ref_counter != NULL && !ptr_ref_counter.deleted; } + bool ObjectExists() { return ptr_ref_counter != NULL && !PTR_ATTRIB(ptr_ref_counter, deleted); } - X* Ptr() { return ObjectExists() ? (X*)ptr_ref_counter.ptr_object : NULL; } + X* Ptr() { return ObjectExists() ? (X*)PTR_ATTRIB(ptr_ref_counter, ptr_object) : NULL; } /** * Makes a strong reference to the given object. */ X* operator=(X* _ptr) { - if (ptr_ref_counter == (_ptr == NULL ? NULL : _ptr.ptr_ref_counter)) { + if (ptr_ref_counter == (_ptr == NULL ? NULL : PTR_ATTRIB(_ptr, ptr_ref_counter))) { // Assigning the same object or the same NULL. return Ptr(); } @@ -296,20 +299,19 @@ struct WeakRef { return Ptr(); } - if (_ptr.ptr_ref_counter.deleted) { + if (PTR_ATTRIB2(_ptr, ptr_ref_counter, deleted)) { // Assigning already deleted object. ptr_ref_counter = NULL; return Ptr(); } - ptr_ref_counter = _ptr.ptr_ref_counter; + ptr_ref_counter = PTR_ATTRIB(_ptr, ptr_ref_counter); #ifdef __debug_ref__ Print(ptr_ref_counter.Debug()); #endif - ++ptr_ref_counter.num_weak_refs; - + ++PTR_ATTRIB(ptr_ref_counter, num_weak_refs); return Ptr(); } @@ -340,25 +342,27 @@ struct WeakRef { void Unset() { if (ptr_ref_counter != NULL) { // Dropping weak reference. - if (!--ptr_ref_counter.num_weak_refs) { + if (!--PTR_ATTRIB(ptr_ref_counter, num_weak_refs)) { // No more weak references. #ifdef __debug_ref__ Print(ptr_ref_counter.Debug()); #endif - if (!ptr_ref_counter.num_strong_refs) { + if (!PTR_ATTRIB(ptr_ref_counter, num_strong_refs)) { // There are also no strong references. ReferenceCounter* stored_ptr_ref_counter = ptr_ref_counter; - if (!ptr_ref_counter.deleted) { + if (!ptr_ref_counter PTR_DEREF deleted) { // It is safe to delete object and reference counter object. // Avoiding double deletion in Dynamic's destructor. - ptr_ref_counter.ptr_object.ptr_ref_counter = NULL; + ptr_ref_counter PTR_DEREF ptr_object PTR_DEREF ptr_ref_counter = NULL; #ifdef __debug_ref__ Print("Refs: Deleting object ", ptr_ref_counter.ptr_object); #endif - if (CheckPointer(ptr_ref_counter.ptr_object) == POINTER_INVALID) { +#ifdef __MQL__ + // We can't check pointer validity in C++ (other than check for NULL). + if (CheckPointer(ptr_ref_counter PTR_DEREF ptr_object) == POINTER_INVALID) { // Serious problem. #ifndef __MQL4__ // Bug: Avoid calling in MQL4 due to 'global initialization failed' error. @@ -366,10 +370,12 @@ struct WeakRef { #endif return; } - - delete ptr_ref_counter.ptr_object; +#endif + delete ptr_ref_counter PTR_DEREF ptr_object; } +#ifdef __MQL__ + // We can't check pointer validity in C++ (other than check for NULL). if (CheckPointer(stored_ptr_ref_counter) == POINTER_INVALID) { // Serious problem. #ifndef __MQL4__ @@ -378,6 +384,7 @@ struct WeakRef { #endif return; } +#endif delete stored_ptr_ref_counter; } diff --git a/Serializer.mqh b/Serializer.mqh index eabe14739..e761be724 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -28,13 +28,16 @@ #include "Convert.mqh" #include "Serializer.define.h" #include "Serializer.enum.h" -#include "SerializerConverter.mqh" #include "SerializerNode.mqh" -#include "SerializerNodeIterator.mqh" #include "SerializerNodeParam.mqh" +#include "Terminal.define.h" #define SERIALIZER_DEFAULT_FP_PRECISION 8 +// Forward declarations. +template +class SerializerIterator; + class Serializer { protected: SerializerNode* _node; @@ -72,7 +75,7 @@ class Serializer { template SerializerIterator Begin() { - SerializerIterator iter(&this, _node); + SerializerIterator iter(THIS_PTR, _node); return iter; } @@ -200,9 +203,9 @@ class Serializer { value.Serialize(this); fp_precision = SERIALIZER_DEFAULT_FP_PRECISION; - SerializerNode* obj = _node.GetChild(_node.NumChildren() - 1); + SerializerNode* obj = _node PTR_DEREF GetChild(PTR_ATTRIB(_node, NumChildren()) - 1); - obj.SetKey(name); + obj PTR_DEREF SetKey(name); } else { _single_value_name = name; value.Serialize(this); @@ -345,7 +348,7 @@ class Serializer { if (si.HasKey()) { // Should not happen. } else { - _node = parent.GetChild(si.Index()); + _node = parent PTR_DEREF GetChild(si.Index()); array[si.Index()] = si.Struct(); } } @@ -429,7 +432,8 @@ class Serializer { Convert::StringToType(PTR_ATTRIB(PTR_ATTRIB(child, GetValueParam()), _string), value); break; default: - Print("Error: Wrong param type ", EnumToString(paramType), "!"); + Print("Error: Wrong param type!"); + SetUserError(ERR_INVALID_PARAMETER); DebugBreak(); } @@ -440,19 +444,6 @@ class Serializer { return NULL; } - - template - static SerializerConverter MakeStubObject(int _serializer_flags = SERIALIZER_FLAG_INCLUDE_ALL, int _n1 = 1, - int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) { - if (_serializer_flags == 0) { - // Avoiding flags misuse. - _serializer_flags = SERIALIZER_FLAG_INCLUDE_ALL; - } - - X stub; - stub.SerializeStub(_n1, _n2, _n3, _n4, _n5); - return SerializerConverter::FromObject(stub, _serializer_flags); - } }; #endif // End: SERIALIZER_MQH diff --git a/SerializerConversions.h b/SerializerConversions.h index 6dbdb1a73..4f5454a5e 100644 --- a/SerializerConversions.h +++ b/SerializerConversions.h @@ -30,6 +30,8 @@ #pragma once #endif +#include "Convert.extern.h" +#include "DateTime.extern.h" #include "Object.mqh" #include "Refs.struct.h" diff --git a/SerializerConverter.mqh b/SerializerConverter.mqh index 89f615609..c92bd14c2 100644 --- a/SerializerConverter.mqh +++ b/SerializerConverter.mqh @@ -23,6 +23,7 @@ // Prevents processing this includes file for the second time. #ifndef SERIALIZER_CONVERTER_MQH #define SERIALIZER_CONVERTER_MQH +#include "SerializerDict.mqh" // Forward declarations. class SerializerNode; @@ -30,6 +31,7 @@ class SerializerNode; // Includes. #include "File.mqh" #include "Serializer.enum.h" +#include "Serializer.mqh" #include "SerializerNode.mqh" class SerializerConverter { @@ -52,7 +54,7 @@ class SerializerConverter { return ""; } - return root_node.ToString(_json_flags); + return root_node PTR_DEREF ToString(_json_flags); } template @@ -118,7 +120,7 @@ class SerializerConverter { template string ToString(unsigned int stringify_flags = 0, void* stringify_aux_arg = NULL) { - string result = ((R*)NULL).Stringify(root_node, stringify_flags, stringify_aux_arg); + string result = ((R*)NULL)PTR_DEREF Stringify(root_node, stringify_flags, stringify_aux_arg); if ((_serializer_flags & SERIALIZER_FLAG_REUSE_OBJECT) == 0) { Clean(); } diff --git a/SerializerDict.mqh b/SerializerDict.mqh index 68ebde3fc..ddef3e957 100644 --- a/SerializerDict.mqh +++ b/SerializerDict.mqh @@ -33,16 +33,16 @@ class SerializerDict { public: template static void Extract(SerializerNode* _root, D& _dict, unsigned int extractor_flags = 0) { - if (_root.IsContainer()) { - for (unsigned int _data_entry_idx = 0; _data_entry_idx < _root.NumChildren(); ++_data_entry_idx) { - Extract(_root.GetChild(_data_entry_idx), _dict, extractor_flags); + if (_root PTR_DEREF IsContainer()) { + for (unsigned int _data_entry_idx = 0; _data_entry_idx < _root PTR_DEREF NumChildren(); ++_data_entry_idx) { + Extract(_root PTR_DEREF GetChild(_data_entry_idx), _dict, extractor_flags); } } else { - SerializerNodeParam* _value_param = _root.GetValueParam(); + SerializerNodeParam* _value_param = _root PTR_DEREF GetValueParam(); V _aux = (V)NULL; - _dict.Push(_value_param.ConvertTo(_aux)); + _dict.Push(_value_param PTR_DEREF ConvertTo(_aux)); } } }; diff --git a/SerializerJson.mqh b/SerializerJson.mqh index 6d7524140..1e87e3481 100644 --- a/SerializerJson.mqh +++ b/SerializerJson.mqh @@ -29,6 +29,7 @@ #include "Object.mqh" #include "Serializer.mqh" #include "SerializerNode.mqh" +#include "String.extern.h" class Log; @@ -64,10 +65,12 @@ class SerializerJson { repr += ident; - if (PTR_ATTRIB(_node, GetKeyParam()) != NULL && PTR_ATTRIB(PTR_ATTRIB(_node, GetKeyParam()), AsString(false, false)) != "") + if (PTR_ATTRIB(_node, GetKeyParam()) != NULL && + PTR_ATTRIB(PTR_ATTRIB(_node, GetKeyParam()), AsString(false, false)) != "") repr += PTR_ATTRIB(PTR_ATTRIB(_node, GetKeyParam()), AsString(false, true)) + ":" + (trimWhitespaces ? "" : " "); - if (PTR_ATTRIB(_node, GetValueParam()) != NULL) repr += PTR_ATTRIB(PTR_ATTRIB(_node, GetValueParam()), AsString(false, true)); + if (PTR_ATTRIB(_node, GetValueParam()) != NULL) + repr += PTR_ATTRIB(PTR_ATTRIB(_node, GetValueParam()), AsString(false, true)); switch (PTR_ATTRIB(_node, GetType())) { case SerializerNodeObject: @@ -76,6 +79,12 @@ class SerializerJson { case SerializerNodeArray: repr += string("[") + (trimWhitespaces ? "" : "\n"); break; + case SerializerNodeUnknown: + case SerializerNodeValue: + case SerializerNodeObjectProperty: + case SerializerNodeArrayItem: + break; + default:; } if (PTR_ATTRIB(_node, HasChildren())) { @@ -91,6 +100,11 @@ class SerializerJson { case SerializerNodeArray: repr += ident + "]"; break; + case SerializerNodeUnknown: + case SerializerNodeValue: + case SerializerNodeObjectProperty: + case SerializerNodeArrayItem: + default:; } if (!PTR_ATTRIB(_node, IsLast())) repr += ","; @@ -115,9 +129,7 @@ class SerializerJson { return false; } - Serializer serializer(node, JsonUnserialize); - - if (logger != NULL) serializer.Logger().Link(logger); + Serializer serializer(node, Unserialize); // We don't use result. We parse data as it is. obj.Serialize(serializer); @@ -126,11 +138,10 @@ class SerializerJson { } static SerializerNode* Parse(string data, unsigned int converter_flags = 0) { - SerializerNodeType type; if (StringGetCharacter(data, 0) == '{') - type = SerializerNodeObject; + ; else if (StringGetCharacter(data, 0) == '[') - type = SerializerNodeArray; + ; else { return GracefulReturn("Failed to parse JSON. It must start with either \"{\" or \"[\".", 0, NULL, NULL); } @@ -141,7 +152,6 @@ class SerializerJson { string extracted; - bool isOuterScope = true; bool expectingKey = false; bool expectingValue = false; bool expectingSemicolon = false; @@ -177,9 +187,10 @@ class SerializerJson { expectingKey = false; expectingSemicolon = true; } else if (expectingValue) { - PTR_ATTRIB(current, AddChild(new SerializerNode( - PTR_ATTRIB(current, GetType()) == SerializerNodeObject ? SerializerNodeObjectProperty : SerializerNodeArrayItem, - current, key, SerializerNodeParam::FromString(extracted)))); + PTR_ATTRIB(current, AddChild(new SerializerNode(PTR_ATTRIB(current, GetType()) == SerializerNodeObject + ? SerializerNodeObjectProperty + : SerializerNodeArrayItem, + current, key, SerializerNodeParam::FromString(extracted)))); #ifdef __debug__ Print("SerializerJson: Value \"" + extracted + "\" for key " + @@ -216,7 +227,6 @@ class SerializerJson { current = node; - isOuterScope = false; expectingValue = false; expectingKey = ch2 != '}'; key = NULL; @@ -250,7 +260,6 @@ class SerializerJson { current = node; expectingValue = ch2 != ']'; - isOuterScope = false; key = NULL; } else if (ch == ']') { #ifdef __debug__ @@ -279,9 +288,10 @@ class SerializerJson { (key != NULL ? ("\"" + key.ToString() + "\"") : "")); #endif - PTR_ATTRIB(current, AddChild(new SerializerNode( - PTR_ATTRIB(current, GetType()) == SerializerNodeObject ? SerializerNodeObjectProperty : SerializerNodeArrayItem, current, - key, value))); + PTR_ATTRIB(current, AddChild(new SerializerNode(PTR_ATTRIB(current, GetType()) == SerializerNodeObject + ? SerializerNodeObjectProperty + : SerializerNodeArrayItem, + current, key, value))); expectingValue = false; // Skipping value. @@ -302,9 +312,10 @@ class SerializerJson { // Skipping value. i += ch == 't' ? 3 : 4; - PTR_ATTRIB(current, AddChild(new SerializerNode( - PTR_ATTRIB(current, GetType()) == SerializerNodeObject ? SerializerNodeObjectProperty : SerializerNodeArrayItem, current, - key, value))); + PTR_ATTRIB(current, AddChild(new SerializerNode(PTR_ATTRIB(current, GetType()) == SerializerNodeObject + ? SerializerNodeObjectProperty + : SerializerNodeArrayItem, + current, key, value))); expectingValue = false; // We don't want to delete it twice. @@ -341,7 +352,7 @@ class SerializerJson { string str; for (unsigned int i = index; i < (unsigned int)StringLen(data); ++i) { -#ifdef __MQL5__ +#ifndef __MQL4__ unsigned short ch = StringGetCharacter(data, i); #else unsigned short ch = StringGetChar(data, i); diff --git a/SerializerNode.mqh b/SerializerNode.mqh index 143c79c0f..27fbd2307 100644 --- a/SerializerNode.mqh +++ b/SerializerNode.mqh @@ -25,8 +25,10 @@ #define JSON_NODE_MQH // Includes. +#include "Math.extern.h" #include "SerializerNode.enum.h" #include "SerializerNodeParam.mqh" +#include "Terminal.define.h" class SerializerNode { protected: @@ -137,7 +139,8 @@ class SerializerNode { _result += StringLen(PTR_ATTRIB(_value, _string)) + 1; break; default: - Print("Error: Wrong value type ", EnumToString(GetType()), "!"); + Print("Error: Wrong value type!"); + SetUserError(ERR_INVALID_PARAMETER); DebugBreak(); } } @@ -260,7 +263,7 @@ class SerializerNode { * Adds child to this node. */ void AddChild(SerializerNode* child) { - if (_numChildren == ArraySize(_children)) ArrayResize(_children, _numChildren + 10); + if (_numChildren == (unsigned int)ArraySize(_children)) ArrayResize(_children, _numChildren + 10); PTR_ATTRIB(child, _index) = (int)_numChildren; _children[_numChildren++] = child; @@ -329,6 +332,11 @@ class SerializerNode { case SerializerNodeArray: repr += string("[") + (trimWhitespaces ? "" : "\n"); break; + case SerializerNodeUnknown: + case SerializerNodeValue: + case SerializerNodeObjectProperty: + case SerializerNodeArrayItem: + default:; } if (HasChildren()) { @@ -344,6 +352,11 @@ class SerializerNode { case SerializerNodeArray: repr += ident + "]"; break; + case SerializerNodeUnknown: + case SerializerNodeValue: + case SerializerNodeObjectProperty: + case SerializerNodeArrayItem: + default:; } if (!IsLast()) repr += ","; diff --git a/SerializerNodeIterator.mqh b/SerializerNodeIterator.mqh index 3a1f0f00f..57acc5265 100644 --- a/SerializerNodeIterator.mqh +++ b/SerializerNodeIterator.mqh @@ -24,6 +24,7 @@ #ifndef JSON_ITERATOR_MQH #define JSON_ITERATOR_MQH +#include "Serializer.mqh" #include "SerializerNode.mqh" class SerializerNode; @@ -54,8 +55,7 @@ class SerializerNodeIterator { /** * Returns current node or NULL. */ - SerializerNode* Node() { return !IsValid() ? NULL : PTR_ATTRIB(_collection, GetChild(_index)); - } + SerializerNode* Node() { return !IsValid() ? NULL : PTR_ATTRIB(_collection, GetChild(_index)); } /** * Returns current node index. @@ -70,25 +70,23 @@ class SerializerNodeIterator { /** * Checks whether iterator is still valid. */ - bool IsValid() { return _index < PTR_ATTRIB(_collection, NumChildren()); - } + bool IsValid() { return _index < PTR_ATTRIB(_collection, NumChildren()); } /** * Returns current's child key or empty string. */ - const string Key() { return !IsValid() ? "" : PTR_ATTRIB(PTR_ATTRIB(_collection, GetChild(_index)), Key()); - } + const string Key() { return !IsValid() ? "" : PTR_ATTRIB(PTR_ATTRIB(_collection, GetChild(_index)), Key()); } /** * Checks whether current child has key. */ - bool HasKey() { return !IsValid() ? false : PTR_ATTRIB(PTR_ATTRIB(_collection, GetChild(_index)), HasKey()); - } + bool HasKey() { return !IsValid() ? false : PTR_ATTRIB(PTR_ATTRIB(_collection, GetChild(_index)), HasKey()); } /** * Checks whether current child is a container. */ - bool IsContainer() { return !IsValid() ? false : PTR_ATTRIB(PTR_ATTRIB(_collection, GetChild(_index)), IsContainer()); + bool IsContainer() { + return !IsValid() ? false : PTR_ATTRIB(PTR_ATTRIB(_collection, GetChild(_index)), IsContainer()); } }; @@ -114,17 +112,21 @@ class SerializerIterator : public SerializerNodeIterator { /** * Returns next value or value by given key. */ +#ifdef __MQL__ template <> +#endif X Value(string key = "") { X value; - _serializer.Pass(_serializer, key, value); + _serializer PTR_DEREF Pass(PTR_TO_REF(_serializer), key, value); return value; } /** * Returns next object or object by given key. */ +#ifdef __MQL__ template <> +#endif X Object(string key = "") { return Struct(key); } @@ -132,14 +134,16 @@ class SerializerIterator : public SerializerNodeIterator { /** * Returns next structure or structure by given key. */ +#ifdef __MQL__ template <> +#endif X Struct(string key = "") { X value; - _serializer.PassStruct(_serializer, key, value); + _serializer PTR_DEREF PassStruct(PTR_TO_REF(_serializer), key, value); return value; } - SerializerNodeType ParentNodeType() { return _collection.GetType(); } + SerializerNodeType ParentNodeType() { return _collection PTR_DEREF GetType(); } }; #endif diff --git a/Std.h b/Std.h index 1b7d70ab2..cd268432c 100644 --- a/Std.h +++ b/Std.h @@ -23,6 +23,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once +#include "Math.define.h" #endif // Data types. @@ -31,13 +32,6 @@ #include #include #include - -// Data types. -typedef std::string string; -typedef unsigned int uint; -typedef unsigned long datetime; -typedef unsigned long ulong; -typedef unsigned short ushort; #endif #ifdef __MQL__ @@ -50,13 +44,17 @@ typedef unsigned short ushort; #ifdef __MQL__ #define THIS_PTR (&this) #define THIS_REF this +#define PTR_DEREF . #define PTR_ATTRIB(O, A) O.A +#define PTR_ATTRIB2(O, A, B) O.A.B #define PTR_TO_REF(PTR) PTR #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE* NAME = PTR #else #define THIS_PTR (this) #define THIS_REF (*this) +#define PTR_DEREF -> #define PTR_ATTRIB(O, A) O->A +#define PTR_ATTRIB2(O, A, B) O->A->B #define PTR_TO_REF(PTR) (*PTR) #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE& NAME = PTR #endif @@ -69,6 +67,7 @@ typedef unsigned short ushort; #endif // Arrays and references to arrays. +#define _COMMA , #ifdef __MQL__ #define ARRAY_DECLARATION_BRACKETS [] #else @@ -157,7 +156,7 @@ class _cpp_array { /** * Returns number of elements in the array. */ - int size() const { return m_data.size(); } + int size() const { return (int)m_data.size(); } /** * Checks whether @@ -191,11 +190,6 @@ class color { }; #endif -// GetPointer(ptr). -#ifndef __MQL__ -unsigned int GetPointer(void* _ptr) { return (unsigned int)_ptr; } -#endif - // MQL defines. #ifndef __MQL__ #define WHOLE_ARRAY -1 // For processing the entire array. @@ -210,6 +204,12 @@ unsigned int GetPointer(void* _ptr) { return (unsigned int)_ptr; } const char* cstring_from(const std::string& _value) { return _value.c_str(); } #endif +#ifdef __cplusplus +using std::string; +#endif + +bool IsNull(const string& str) { return str == ""; } + /** * Referencing struct's enum. * @@ -223,224 +223,6 @@ const char* cstring_from(const std::string& _value) { return _value.c_str(); } #endif #ifndef __MQL__ -/** - * @file - * Includes MQL-compatible enumerations. - */ -enum ENUM_TRADE_REQUEST_ACTIONS { - // @see: https://www.mql5.com/en/docs/constants/tradingconstants/enum_trade_request_actions - TRADE_ACTION_DEAL, // Place a trade order for an immediate execution with the specified parameters (market order). - TRADE_ACTION_PENDING, // Place a trade order for the execution under specified conditions (pending order). - TRADE_ACTION_SLTP, // Modify Stop Loss and Take Profit values of an opened position. - TRADE_ACTION_MODIFY, // Modify the parameters of the order placed previously. - TRADE_ACTION_REMOVE, // Delete the pending order placed previously. - TRADE_ACTION_CLOSE_BY // Close a position by an opposite one. -}; -// Fill Policy. -enum ENUM_SYMBOL_FILLING { - // @see: https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties - SYMBOL_FILLING_FOK = 1, // A deal can be executed only with the specified volume. - SYMBOL_FILLING_IOC = 2 // Trader agrees to execute a deal with the volume maximally available in the market. -}; -enum ENUM_ORDER_TYPE_FILLING { - // @see: https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties - ORDER_FILLING_FOK, // An order can be filled only in the specified amount. - ORDER_FILLING_IOC, // A trader agrees to execute a deal with the volume maximally available in the market. - ORDER_FILLING_RETURN // In case of partial filling a market or limit order with remaining volume is not canceled but - // processed further. -}; -enum ENUM_ORDER_TYPE_TIME { - // @see: https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties - ORDER_TIME_GTC, // Good till cancel order. - ORDER_TIME_DAY, // Good till current trade day order. - ORDER_TIME_SPECIFIED, // Good till expired order. - ORDER_TIME_SPECIFIED_DAY // The order will be effective till 23:59:59 of the specified day. -}; -// An order status that describes its state. -enum ENUM_ORDER_STATE { - ORDER_STATE_STARTED, // Order checked, but not yet accepted by broker - ORDER_STATE_PLACED, // Order accepted - ORDER_STATE_CANCELED, // Order canceled by client - ORDER_STATE_PARTIAL, // Order partially executed - ORDER_STATE_FILLED, // Order fully executed - ORDER_STATE_REJECTED, // Order rejected - ORDER_STATE_EXPIRED, // Order expired - ORDER_STATE_REQUEST_ADD, // Order is being registered (placing to the trading system) - ORDER_STATE_REQUEST_MODIFY, // Order is being modified (changing its parameters) - ORDER_STATE_REQUEST_CANCEL // Order is being deleted (deleting from the trading system) -}; - -// @see: https://www.mql5.com/en/docs/constants/structures/mqltraderequest -struct MqlTradeRequest { - ENUM_TRADE_REQUEST_ACTIONS action; // Trade operation type. - ulong magic; // Expert Advisor ID (magic number). - ulong order; // Order ticket. - string symbol; // Trade symbol. - double volume; // Requested volume for a deal in lots. - double price; // Price. - double stoplimit; // StopLimit level of the order. - double sl; // Stop Loss level of the order. - double tp; // Take Profit level of the order. - ulong deviation; // Maximal possible deviation from the requested price. - ENUM_ORDER_TYPE type; // Order type. - ENUM_ORDER_TYPE_FILLING type_filling; // Order execution type. - ENUM_ORDER_TYPE_TIME type_time; // Order expiration type. - datetime expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type. - string comment; // Order comment. - ulong position; // Position ticket. - ulong position_by; // The ticket of an opposite position. -}; -// @see: https://www.mql5.com/en/docs/constants/structures/mqltraderesult -struct MqlTradeResult { - uint retcode; // Operation return code. - ulong deal; // Deal ticket, if it is performed. - ulong order; // Order ticket, if it is placed. - double volume; // Deal volume, confirmed by broker. - double price; // Deal price, confirmed by broker. - double bid; // Current Bid price. - double ask; // Current Ask price. - string comment; // Broker comment to operation (by default it is filled by description of trade server return code). - uint request_id; // Request ID set by the terminal during the dispatch. - uint retcode_external; // Return code of an external trading system. -}; - -#define ERR_USER_ERROR_FIRST 65536 // User defined errors start with this code. - -#define AliceBlue 0xFFF8F0 -#define AntiqueWhite 0xD7EBFA -#define Aqua 0xFFFF00 -#define Aquamarine 0xD4FF7F -#define Beige 0xDCF5F5 -#define Bisque 0xC4E4FF -#define Black 0x000000 -#define BlanchedAlmond 0xCDEBFF -#define Blue 0xFF0000 -#define BlueViolet 0xE22B8A -#define Brown 0x2A2AA5 -#define BurlyWood 0x87B8DE -#define CadetBlue 0xA09E5F -#define Chartreuse 0x00FF7F -#define Chocolate 0x1E69D2 -#define Coral 0x507FFF -#define CornflowerBlue 0xED9564 -#define Cornsilk 0xDCF8FF -#define Crimson 0x3C14DC -#define DarkBlue 0x8B0000 -#define DarkGoldenrod 0x0B86B8 -#define DarkGray 0xA9A9A9 -#define DarkGreen 0x006400 -#define DarkKhaki 0x6BB7BD -#define DarkOliveGreen 0x2F6B55 -#define DarkOrange 0x008CFF -#define DarkOrchid 0xCC3299 -#define DarkSalmon 0x7A96E9 -#define DarkSeaGreen 0x8BBC8F -#define DarkSlateBlue 0x8B3D48 -#define DarkSlateGray 0x4F4F2F -#define DarkTurquoise 0xD1CE00 -#define DarkViolet 0xD30094 -#define DeepPink 0x9314FF -#define DeepSkyBlue 0xFFBF00 -#define DimGray 0x696969 -#define DodgerBlue 0xFF901E -#define FireBrick 0x2222B2 -#define ForestGreen 0x228B22 -#define Gainsboro 0xDCDCDC -#define Gold 0x00D7FF -#define Goldenrod 0x20A5DA -#define Gray 0x808080 -#define Green 0x008000 -#define GreenYellow 0x2FFFAD -#define Honeydew 0xF0FFF0 -#define HotPink 0xB469FF -#define IndianRed 0x5C5CCD -#define Indigo 0x82004B -#define Ivory 0xF0FFFF -#define Khaki 0x8CE6F0 -#define Lavender 0xFAE6E6 -#define LavenderBlush 0xF5F0FF -#define LawnGreen 0x00FC7C -#define LemonChiffon 0xCDFAFF -#define LightBlue 0xE6D8AD -#define LightCoral 0x8080F0 -#define LightCyan 0xFFFFE0 -#define LightGoldenrod 0xD2FAFA -#define LightGray 0xD3D3D3 -#define LightGreen 0x90EE90 -#define LightPink 0xC1B6FF -#define LightSalmon 0x7AA0FF -#define LightSeaGreen 0xAAB220 -#define LightSkyBlue 0xFACE87 -#define LightSlateGray 0x998877 -#define LightSteelBlue 0xDEC4B0 -#define LightYellow 0xE0FFFF -#define Lime 0x00FF00 -#define LimeGreen 0x32CD32 -#define Linen 0xE6F0FA -#define Magenta 0xFF00FF -#define Maroon 0x000080 -#define MediumAquamarine 0xAACD66 -#define MediumBlue 0xCD0000 -#define MediumOrchid 0xD355BA -#define MediumPurple 0xDB7093 -#define MediumSeaGreen 0x71B33C -#define MediumSlateBlue 0xEE687B -#define MediumSpringGreen 0x9AFA00 -#define MediumTurquoise 0xCCD148 -#define MediumVioletRed 0x8515C7 -#define MidnightBlue 0x701919 -#define MintCream 0xFAFFF5 -#define MistyRose 0xE1E4FF -#define Moccasin 0xB5E4FF -#define NavajoWhite 0xADDEFF -#define Navy 0x800000 -#define OldLace 0xE6F5FD -#define Olive 0x008080 -#define OliveDrab 0x238E6B -#define Orange 0x00A5FF -#define OrangeRed 0x0045FF -#define Orchid 0xD670DA -#define PaleGoldenrod 0xAAE8EE -#define PaleGreen 0x98FB98 -#define PaleTurquoise 0xEEEEAF -#define PaleVioletRed 0x9370DB -#define PapayaWhip 0xD5EFFF -#define PeachPuff 0xB9DAFF -#define Peru 0x3F85CD -#define Pink 0xCBC0FF -#define Plum 0xDDA0DD -#define PowderBlue 0xE6E0B0 -#define Purple 0x800080 -#define Red 0x0000FF -#define RosyBrown 0x8F8FBC -#define RoyalBlue 0xE16941 -#define SaddleBrown 0x13458B -#define Salmon 0x7280FA -#define SandyBrown 0x60A4F4 -#define SeaGreen 0x578B2E -#define Seashell 0xEEF5FF -#define Sienna 0x2D52A0 -#define Silver 0xC0C0C0 -#define SkyBlue 0xEBCE87 -#define SlateBlue 0xCD5A6A -#define SlateGray 0x908070 -#define Snow 0xFAFAFF -#define SpringGreen 0x7FFF00 -#define SteelBlue 0xB48246 -#define Tan 0x8CB4D2 -#define Teal 0x808000 -#define Thistle 0xD8BFD8 -#define Tomato 0x4763FF -#define Turquoise 0xD0E040 -#define Violet 0xEE82EE -#define Wheat 0xB3DEF5 -#define White 0xFFFFFF -#define WhiteSmoke 0xF5F5F5 -#define Yellow 0x00FFFF -#define YellowGreen 0x32CD9A -#define clrNONE -1 -#define CLR_NONE -1 - // Additional enum values for ENUM_SYMBOL_INFO_DOUBLE #define SYMBOL_MARGIN_LIMIT ((ENUM_SYMBOL_INFO_DOUBLE)46) #define SYMBOL_MARGIN_MAINTENANCE ((ENUM_SYMBOL_INFO_DOUBLE)43) @@ -448,44 +230,14 @@ struct MqlTradeResult { #define SYMBOL_MARGIN_SHORT ((ENUM_SYMBOL_INFO_DOUBLE)45) #define SYMBOL_MARGIN_STOP ((ENUM_SYMBOL_INFO_DOUBLE)47) #define SYMBOL_MARGIN_STOPLIMIT ((ENUM_SYMBOL_INFO_DOUBLE)48) - -#define TRADE_RETCODE_REQUOTE 10004 // Requote -#define TRADE_RETCODE_REJECT 10006 // Request rejected -#define TRADE_RETCODE_CANCEL 10007 // Request canceled by trader -#define TRADE_RETCODE_PLACED 10008 // Order placed -#define TRADE_RETCODE_DONE 10009 // Request completed -#define TRADE_RETCODE_DONE_PARTIAL 10010 // Only part of the request was completed -#define TRADE_RETCODE_ERROR 10011 // Request processing error -#define TRADE_RETCODE_TIMEOUT 10012 // Request canceled by timeout -#define TRADE_RETCODE_INVALID 10013 // Invalid request -#define TRADE_RETCODE_INVALID_VOLUME 10014 // Invalid volume in the request -#define TRADE_RETCODE_INVALID_PRICE 10015 // Invalid price in the request -#define TRADE_RETCODE_INVALID_STOPS 10016 // Invalid stops in the request -#define TRADE_RETCODE_TRADE_DISABLED 10017 // Trade is disabled -#define TRADE_RETCODE_MARKET_CLOSED 10018 // Market is closed -#define TRADE_RETCODE_NO_MONEY 10019 // There is not enough money to complete the request -#define TRADE_RETCODE_PRICE_CHANGED 10020 // Prices changed -#define TRADE_RETCODE_PRICE_OFF 10021 // There are no quotes to process the request -#define TRADE_RETCODE_INVALID_EXPIRATION 10022 // Invalid order expiration date in the request -#define TRADE_RETCODE_ORDER_CHANGED 10023 // Order state changed -#define TRADE_RETCODE_TOO_MANY_REQUESTS 10024 // Too frequent requests -#define TRADE_RETCODE_NO_CHANGES 10025 // No changes in request -#define TRADE_RETCODE_SERVER_DISABLES_AT 10026 // Autotrading disabled by server -#define TRADE_RETCODE_CLIENT_DISABLES_AT 10027 // Autotrading disabled by client terminal -#define TRADE_RETCODE_LOCKED 10028 // Request locked for processing -#define TRADE_RETCODE_FROZEN 10029 // Order or position frozen -#define TRADE_RETCODE_INVALID_FILL 10030 // Invalid order filling type -#define TRADE_RETCODE_CONNECTION 10031 // No connection with the trade server -#define TRADE_RETCODE_ONLY_REAL 10032 // Operation is allowed only for live accounts -#define TRADE_RETCODE_LIMIT_ORDERS 10033 // The number of pending orders has reached the limit -#define TRADE_RETCODE_LIMIT_VOLUME 10034 // The volume of orders and positions for the symbol has reached the limit -#define TRADE_RETCODE_INVALID_ORDER 10035 // Incorrect or prohibited order type -#define TRADE_RETCODE_POSITION_CLOSED 10036 // Position with the specified POSITION_IDENTIFIER has already been closed -#define TRADE_RETCODE_INVALID_CLOSE_VOLUME 10038 // A close volume exceeds the current position volume -#define TRADE_RETCODE_CLOSE_ORDER_EXIST 10039 // A close order already exists. -#define TRADE_RETCODE_LIMIT_POSITIONS 10040 // The number of open positions can be limited (e.g. Netting, Hedging). #endif +template +class InvalidEnumValue { + public: + static T value() { return (T)INT_MAX; } +}; + #ifndef __MQL__ // Converter of NULL_VALUE into expected type. e.g., "int x = NULL_VALUE" will end up with "x = 0". struct _NULL_VALUE { diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index cf9105c30..3b019ba0e 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -87,6 +87,34 @@ enum ENUM_IPEAK { IPEAK_LOWEST, IPEAK_HIGHEST }; ValueStorage *_price = PriceValueStorage::GetInstance(SYMBOL, TF, APPLIED_PRICE); \ INDICATOR_CALCULATE_POPULATE_CACHE(SYMBOL, TF, KEY) +#define INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS(INDI, SYMBOL, TF, APPLIED_PRICE, KEY) \ + ValueStorage *_price = INDI.GetValueStorage(APPLIED_PRICE); \ + INDICATOR_CALCULATE_POPULATE_CACHE(SYMBOL, TF, KEY) + +#define INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT_DS_SPECIFIC(INDI, SYMBOL, TF, APPLIED_PRICE, KEY) \ + ValueStorage *_price; \ + if (_indi.HasSpecificAppliedPriceValueStorage(APPLIED_PRICE)) { \ + _price = INDI.GetSpecificAppliedPriceValueStorage(APPLIED_PRICE); \ + } else { \ + Print("Source indicator ", INDI.GetFullName(), \ + " cannot be used as it doesn't provide a single buffer to be used by target indicator! You may try to set " \ + "applied price/data source mode and try again."); \ + DebugBreak(); \ + } \ + \ + INDICATOR_CALCULATE_POPULATE_CACHE(SYMBOL, TF, KEY) + +#define INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG_DS(INDI, SYMBOL, TF, KEY) \ + ValueStorage *_time = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_TIME); \ + ValueStorage *_tick_volume = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME); \ + ValueStorage *_volume = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_VOLUME); \ + ValueStorage *_spread = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_SPREAD); \ + ValueStorage *_price_open = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_PRICE_OPEN); \ + ValueStorage *_price_high = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_PRICE_HIGH); \ + ValueStorage *_price_low = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_PRICE_LOW); \ + ValueStorage *_price_close = (ValueStorage *)INDI.GetSpecificValueStorage(INDI_VS_TYPE_PRICE_CLOSE); \ + INDICATOR_CALCULATE_POPULATE_CACHE(SYMBOL, TF, KEY) + #define INDICATOR_CALCULATE_POPULATED_PARAMS_LONG \ _time, _price_open, _price_high, _price_low, _price_close, _tick_volume, _volume, _spread diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index 4dc6aacb0..6744660e6 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -31,7 +31,7 @@ #endif // Forward declarations. -class IndicatorBase; +class IndicatorData; // Includes. #include "ValueStorage.history.h" @@ -42,7 +42,7 @@ class IndicatorBase; template class IndicatorBufferValueStorage : public HistoryValueStorage { // Pointer to indicator to access data from. - IndicatorBase *indicator; + IndicatorData *indicator; // Mode of the target indicator. int mode; @@ -51,11 +51,11 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { /** * Constructor. */ - IndicatorBufferValueStorage(IndicatorBase *_indi, int _mode = 0, bool _is_series = false) - : indicator(_indi), mode(_mode), HistoryValueStorage(_indi.GetSymbol(), _indi.GetTf()) {} + IndicatorBufferValueStorage(IndicatorData *_indi, int _mode = 0, ENUM_TIMEFRAMES _tf = NULL, bool _is_series = false) + : indicator(_indi), mode(_mode), HistoryValueStorage(_indi.GetSymbol(), _tf) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. */ - virtual C Fetch(int _shift) { return indicator.GetValue(RealShift(_shift), mode); } + virtual C Fetch(int _shift) { return indicator.GetValue(mode, RealShift(_shift)); } }; diff --git a/Strategy.mqh b/Strategy.mqh index 6b38f4784..898f6c012 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -1206,7 +1206,7 @@ class Strategy : public Object { int _count = (int)fmax(fabs(_level), fabs(_method)); int _direction = Order::OrderDirection(_cmd, _mode); Chart *_chart = trade.GetChart(); - IndicatorBase *_indi = GetIndicators().Begin().Value().Ptr(); + IndicatorData *_indi = GetIndicators().Begin().Value().Ptr(); StrategyPriceStop _psm(_method); _psm.SetChartParams(_chart.GetParams()); if (Object::IsValid(_indi)) { diff --git a/String.extern.h b/String.extern.h new file mode 100644 index 000000000..04f359fef --- /dev/null +++ b/String.extern.h @@ -0,0 +1,42 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Prevents processing this includes file for the second time. +#ifndef __MQL__ +#pragma once +#include "Terminal.define.h" +#endif + +// Define external global functions. +#ifndef __MQL__ +extern double StringToDouble(string value); +extern int StringFind(string string_value, string match_substring, int start_pos = 0); +extern int StringLen(string string_value); +extern int StringSplit(const string& string_value, const unsigned short separator, ARRAY_REF(string, result)); +extern long StringToInteger(string value); +extern string IntegerToString(long number, int str_len = 0, ushort fill_symbol = ' '); +extern string StringFormat(string format, ...); +extern string StringSubstr(string string_value, int start_pos, int length = -1); +extern ushort StringGetCharacter(string string_value, int pos); +int StringToCharArray(string text_string, ARRAY_REF(uchar, array), int start = 0, int count = -1, + uint codepage = CP_ACP); +#endif diff --git a/String.mqh b/String.mqh index 3acccfd30..ab240c4db 100644 --- a/String.mqh +++ b/String.mqh @@ -25,7 +25,9 @@ #define STRING_MQH // Includes. +#include "Array.extern.h" #include "Std.h" +#include "String.extern.h" // Defines. #define NL "\n" // New line: 0x0A (MQL file functions auto-convert 0x0A to 0x0D0A). diff --git a/SymbolInfo.define.h b/SymbolInfo.define.h index 68ef4c107..960369f2d 100644 --- a/SymbolInfo.define.h +++ b/SymbolInfo.define.h @@ -32,3 +32,13 @@ #define Point _Point #define Digits _Digits #endif + +#ifndef __MQL__ +// Additional enum values for ENUM_SYMBOL_INFO_DOUBLE +#define SYMBOL_MARGIN_LIMIT ((ENUM_SYMBOL_INFO_DOUBLE)46) +#define SYMBOL_MARGIN_MAINTENANCE ((ENUM_SYMBOL_INFO_DOUBLE)43) +#define SYMBOL_MARGIN_LONG ((ENUM_SYMBOL_INFO_DOUBLE)44) +#define SYMBOL_MARGIN_SHORT ((ENUM_SYMBOL_INFO_DOUBLE)45) +#define SYMBOL_MARGIN_STOP ((ENUM_SYMBOL_INFO_DOUBLE)47) +#define SYMBOL_MARGIN_STOPLIMIT ((ENUM_SYMBOL_INFO_DOUBLE)48) +#endif diff --git a/SymbolInfo.enum.h b/SymbolInfo.enum.h index 59a3ffdfc..43b625853 100644 --- a/SymbolInfo.enum.h +++ b/SymbolInfo.enum.h @@ -31,6 +31,13 @@ #endif #ifndef __MQL5__ +// Fill Policy. +enum ENUM_SYMBOL_FILLING { + // @see: https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties + SYMBOL_FILLING_FOK = 1, // A deal can be executed only with the specified volume. + SYMBOL_FILLING_IOC = 2 // Trader agrees to execute a deal with the volume maximally available in the market. +}; + // Methods of swap calculation at position transfer. // @see: https://www.mql5.com/en/docs/constants/environment_state/marketinfoconstants#enum_symbol_swap_mode enum ENUM_SYMBOL_SWAP_MODE { diff --git a/SymbolInfo.extern.h b/SymbolInfo.extern.h new file mode 100644 index 000000000..801c47fb1 --- /dev/null +++ b/SymbolInfo.extern.h @@ -0,0 +1,37 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Includes. +#include "Order.enum.h" +#include "SymbolInfo.enum.h" +#include "Tick.struct.h" + +// Define external global functions. +#ifndef __MQL__ +extern long SymbolInfoInteger(string name, ENUM_SYMBOL_INFO_INTEGER prop_id); +extern bool SymbolInfoMarginRate(string name, ENUM_ORDER_TYPE order_type, double &initial_margin_rate, + double &maintenance_margin_rate); +extern bool SymbolInfoTick(string symbol, MqlTick &tick); + +// Define external global variables. +extern string _Symbol; +#endif diff --git a/SymbolInfo.mqh b/SymbolInfo.mqh index 226ace580..92377deb6 100644 --- a/SymbolInfo.mqh +++ b/SymbolInfo.mqh @@ -31,6 +31,7 @@ class SymbolInfo; #include "SymbolInfo.define.h" #include "SymbolInfo.enum.h" #include "SymbolInfo.enum.symbols.h" +#include "SymbolInfo.extern.h" #include "SymbolInfo.struct.h" #include "SymbolInfo.struct.static.h" @@ -58,7 +59,7 @@ class SymbolInfo : public Object { public: /** - * Implements class constructor with a parameter. + * Class constructor given a symbol string. */ SymbolInfo(string _symbol = NULL) : symbol(_symbol), pip_size(GetPipSize()), symbol_digits(GetDigits()) { Select(); @@ -73,6 +74,16 @@ class SymbolInfo : public Object { } } + /** + * Class constructor with symbol properties. + */ + SymbolInfo(const SymbolInfoProp &_sip) : sprops(_sip) {} + + /** + * Class copy constructor. + */ + SymbolInfo(const SymbolInfo &_si) : s_entry(_si.s_entry), sprops(_si.sprops) {} + ~SymbolInfo() {} /** diff --git a/SymbolInfo.struct.h b/SymbolInfo.struct.h index ba2dc565d..731a2562a 100644 --- a/SymbolInfo.struct.h +++ b/SymbolInfo.struct.h @@ -32,8 +32,9 @@ // Includes. #include "ISerializable.h" -#include "MqlTick.h" +#include "Std.h" #include "SymbolInfo.struct.static.h" +#include "Tick.struct.h" // Defines struct to store symbol data. struct SymbolInfoEntry @@ -46,7 +47,7 @@ struct SymbolInfoEntry double last; // Price of the last deal. double spread; // Current spread. unsigned long volume; // Volume for the current last price. - // Constructor. + // Constructors. SymbolInfoEntry() : bid(0), ask(0), last(0), spread(0), volume(0) {} SymbolInfoEntry(const MqlTick& _tick, const string _symbol = "") { bid = _tick.bid; @@ -55,6 +56,8 @@ struct SymbolInfoEntry volume = _tick.volume; spread = (unsigned int)round((ask - bid) * pow(10, SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS))); } + // Copy constructor. + SymbolInfoEntry(const SymbolInfoEntry& _sie) { this = _sie; } // Getters string ToCSV() { return StringFormat("%g,%g,%g,%g,%d", bid, ask, last, spread, volume); } // Serializers. @@ -72,6 +75,9 @@ struct SymbolInfoProp { unsigned int pip_digits; // Pip digits (precision). unsigned int pts_per_pip; // Points per pip. unsigned int vol_digits; // Volume digits. + // Constructors. + SymbolInfoProp() {} + SymbolInfoProp(const SymbolInfoProp& _sip) {} // Serializers. void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} SerializerNodeType Serialize(Serializer& _s); diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index 11a1440b9..be343fb7b 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -26,8 +26,9 @@ #endif #include "MQL5.mqh" -#include "MqlTick.h" +#include "Order.enum.h" #include "Std.h" +#include "Tick.struct.h" /** * Struct to provide symbol information. @@ -135,9 +136,8 @@ struct SymbolInfoStatic { * */ static unsigned int GetPointsPerPip(string _symbol) { - // To be used to replace Point for trade parameters calculations. - // See: https://www.mql5.com/en/forum/124692 - return (unsigned int)pow(10, SymbolInfoStatic::GetDigits(_symbol) - SymbolInfoStatic::GetPipDigits(_symbol)); + return (unsigned int)pow((unsigned int)10, + SymbolInfoStatic::GetDigits(_symbol) - SymbolInfoStatic::GetPipDigits(_symbol)); } /** @@ -263,7 +263,7 @@ struct SymbolInfoStatic { * Get real spread based on the ask and bid price (in points). */ static unsigned int GetRealSpread(double _bid, double _ask, unsigned int _digits) { - return (unsigned int)round((_ask - _bid) * pow(10, _digits)); + return (unsigned int)round((_ask - _bid) * pow((unsigned int)10, _digits)); } static unsigned int GetRealSpread(string _symbol) { return GetRealSpread(SymbolInfoStatic::GetBid(_symbol), SymbolInfoStatic::GetAsk(_symbol), diff --git a/Terminal.define.h b/Terminal.define.h index d5105b86d..129089236 100644 --- a/Terminal.define.h +++ b/Terminal.define.h @@ -27,6 +27,154 @@ /* Defines */ +// Codepages. +// @see: https://www.mql5.com/en/docs/constants/io_constants/codepageusage +#define CP_ACP 0 // The current Windows ANSI code page. +#define CP_OEMCP 1 // The current system OEM code page. +#define CP_MACCP 2 // The current system Macintosh code page. +#define CP_THREAD_ACP 3 // The Windows ANSI code page for the current thread. +#define CP_SYMBOL 42 // Symbol code page +#define CP_UTF7 65000 // UTF-7 code page. +#define CP_UTF8 65001 // UTF-8 code page. + +// Colors. +#define AliceBlue 0xFFF8F0 +#define AntiqueWhite 0xD7EBFA +#define Aqua 0xFFFF00 +#define Aquamarine 0xD4FF7F +#define Beige 0xDCF5F5 +#define Bisque 0xC4E4FF +#define Black 0x000000 +#define BlanchedAlmond 0xCDEBFF +#define Blue 0xFF0000 +#define BlueViolet 0xE22B8A +#define Brown 0x2A2AA5 +#define BurlyWood 0x87B8DE +#define CadetBlue 0xA09E5F +#define Chartreuse 0x00FF7F +#define Chocolate 0x1E69D2 +#define Coral 0x507FFF +#define CornflowerBlue 0xED9564 +#define Cornsilk 0xDCF8FF +#define Crimson 0x3C14DC +#define DarkBlue 0x8B0000 +#define DarkGoldenrod 0x0B86B8 +#define DarkGray 0xA9A9A9 +#define DarkGreen 0x006400 +#define DarkKhaki 0x6BB7BD +#define DarkOliveGreen 0x2F6B55 +#define DarkOrange 0x008CFF +#define DarkOrchid 0xCC3299 +#define DarkSalmon 0x7A96E9 +#define DarkSlateBlue 0x8B3D48 +#define DarkSlateGray 0x4F4F2F +#define DarkTurquoise 0xD1CE00 +#define DarkViolet 0xD30094 +#define DeepPink 0x9314FF +#define DeepSkyBlue 0xFFBF00 +#define DimGray 0x696969 +#define DodgerBlue 0xFF901E +#define FireBrick 0x2222B2 +#define ForestGreen 0x228B22 +#define Gainsboro 0xDCDCDC +#define Gold 0x00D7FF +#define Goldenrod 0x20A5DA +#define Gray 0x808080 +#define Green 0x008000 +#define GreenYellow 0x2FFFAD +#define Honeydew 0xF0FFF0 +#define HotPink 0xB469FF +#define IndianRed 0x5C5CCD +#define Indigo 0x82004B +#define Ivory 0xF0FFFF +#define Khaki 0x8CE6F0 +#define Lavender 0xFAE6E6 +#define LavenderBlush 0xF5F0FF +#define LawnGreen 0x00FC7C +#define LemonChiffon 0xCDFAFF +#define LightBlue 0xE6D8AD +#define LightCoral 0x8080F0 +#define LightCyan 0xFFFFE0 +#define LightGoldenrod 0xD2FAFA +#define LightGray 0xD3D3D3 +#define LightGreen 0x90EE90 +#define LightPink 0xC1B6FF +#define LightSalmon 0x7AA0FF +#define LightSeaGreen 0xAAB220 +#define LightSkyBlue 0xFACE87 +#define LightSlateGray 0x998877 +#define LightSteelBlue 0xDEC4B0 +#define LightYellow 0xE0FFFF +#define Lime 0x00FF00 +#define LimeGreen 0x32CD32 +#define Linen 0xE6F0FA +#define Magenta 0xFF00FF +#define Maroon 0x000080 +#define MediumAquamarine 0xAACD66 +#define MediumBlue 0xCD0000 +#define MediumOrchid 0xD355BA +#define MediumPurple 0xDB7093 +#define MediumSeaGreen 0x71B33C +#define MediumSlateBlue 0xEE687B +#define MediumSpringGreen 0x9AFA00 +#define MediumTurquoise 0xCCD148 +#define MediumVioletRed 0x8515C7 +#define MidnightBlue 0x701919 +#define MintCream 0xFAFFF5 +#define MistyRose 0xE1E4FF +#define Moccasin 0xB5E4FF +#define NavajoWhite 0xADDEFF +#define Navy 0x800000 +#define OldLace 0xE6F5FD +#define Olive 0x008080 +#define OliveDrab 0x238E6B +#define Orange 0x00A5FF +#define OrangeRed 0x0045FF +#define Orchid 0xD670DA +#define PaleGoldenrod 0xAAE8EE +#define PaleGreen 0x98FB98 +#define PaleTurquoise 0xEEEEAF +#define PaleVioletRed 0x9370DB +#define PapayaWhip 0xD5EFFF +#define PeachPuff 0xB9DAFF +#define Peru 0x3F85CD +#define Pink 0xCBC0FF +#define Plum 0xDDA0DD +#define PowderBlue 0xE6E0B0 +#define Purple 0x800080 +#define Red 0x0000FF +#define RosyBrown 0x8F8FBC +#define RoyalBlue 0xE16941 +#define SaddleBrown 0x13458B +#define Salmon 0x7280FA +#define SandyBrown 0x60A4F4 +#define SeaGreen 0x578B2E +#define Seashell 0xEEF5FF +#define Sienna 0x2D52A0 +#define Silver 0xC0C0C0 +#define SkyBlue 0xEBCE87 +#define SlateBlue 0xCD5A6A +#define SlateGray 0x908070 +#define Snow 0xFAFAFF +#define SpringGreen 0x7FFF00 +#define SteelBlue 0xB48246 +#define Tan 0x8CB4D2 +#define Teal 0x808000 +#define Thistle 0xD8BFD8 +#define Tomato 0x4763FF +#define Turquoise 0xD0E040 +#define Violet 0xEE82EE +#define Wheat 0xB3DEF5 +#define White 0xFFFFFF +#define WhiteSmoke 0xF5F5F5 +#define Yellow 0x00FFFF +#define YellowGreen 0x32CD9A +#ifndef __MQL__ +#define clrNONE -1 +#define CLR_NONE -1 +#define DarkSeaGreen 0x8BBC8F +#endif + // Custom user errors. // @docs // - https://docs.mql4.com/common/setusererror @@ -37,6 +185,7 @@ #define ERR_USER_INVALID_HANDLE 4 #define ERR_USER_ITEM_NOT_FOUND 5 #define ERR_USER_NOT_SUPPORTED 6 +#define ERR_USER_ERROR_FIRST 65536 // User defined errors start with this code. // Return codes of the trade server. #define ERR_NO_ERROR 0 @@ -72,6 +221,46 @@ #define ERR_TRADE_HEDGE_PROHIBITED 149 #define ERR_TRADE_PROHIBITED_BY_FIFO 150 +#ifndef __MQL__ +// Return Codes of the Trade Server. +// @see: https://www.mql5.com/en/docs/constants/errorswarnings/enum_trade_return_codes +#define TRADE_RETCODE_REQUOTE 10004 // Requote +#define TRADE_RETCODE_REJECT 10006 // Request rejected +#define TRADE_RETCODE_CANCEL 10007 // Request canceled by trader +#define TRADE_RETCODE_PLACED 10008 // Order placed +#define TRADE_RETCODE_DONE 10009 // Request completed +#define TRADE_RETCODE_DONE_PARTIAL 10010 // Only part of the request was completed +#define TRADE_RETCODE_ERROR 10011 // Request processing error +#define TRADE_RETCODE_TIMEOUT 10012 // Request canceled by timeout +#define TRADE_RETCODE_INVALID 10013 // Invalid request +#define TRADE_RETCODE_INVALID_VOLUME 10014 // Invalid volume in the request +#define TRADE_RETCODE_INVALID_PRICE 10015 // Invalid price in the request +#define TRADE_RETCODE_INVALID_STOPS 10016 // Invalid stops in the request +#define TRADE_RETCODE_TRADE_DISABLED 10017 // Trade is disabled +#define TRADE_RETCODE_MARKET_CLOSED 10018 // Market is closed +#define TRADE_RETCODE_NO_MONEY 10019 // There is not enough money to complete the request +#define TRADE_RETCODE_PRICE_CHANGED 10020 // Prices changed +#define TRADE_RETCODE_PRICE_OFF 10021 // There are no quotes to process the request +#define TRADE_RETCODE_INVALID_EXPIRATION 10022 // Invalid order expiration date in the request +#define TRADE_RETCODE_ORDER_CHANGED 10023 // Order state changed +#define TRADE_RETCODE_TOO_MANY_REQUESTS 10024 // Too frequent requests +#define TRADE_RETCODE_NO_CHANGES 10025 // No changes in request +#define TRADE_RETCODE_SERVER_DISABLES_AT 10026 // Autotrading disabled by server +#define TRADE_RETCODE_CLIENT_DISABLES_AT 10027 // Autotrading disabled by client terminal +#define TRADE_RETCODE_LOCKED 10028 // Request locked for processing +#define TRADE_RETCODE_FROZEN 10029 // Order or position frozen +#define TRADE_RETCODE_INVALID_FILL 10030 // Invalid order filling type +#define TRADE_RETCODE_CONNECTION 10031 // No connection with the trade server +#define TRADE_RETCODE_ONLY_REAL 10032 // Operation is allowed only for live accounts +#define TRADE_RETCODE_LIMIT_ORDERS 10033 // The number of pending orders has reached the limit +#define TRADE_RETCODE_LIMIT_VOLUME 10034 // The volume of orders and positions for the symbol has reached the limit +#define TRADE_RETCODE_INVALID_ORDER 10035 // Incorrect or prohibited order type +#define TRADE_RETCODE_POSITION_CLOSED 10036 // Position with the specified POSITION_IDENTIFIER has already been closed +#define TRADE_RETCODE_INVALID_CLOSE_VOLUME 10038 // A close volume exceeds the current position volume +#define TRADE_RETCODE_CLOSE_ORDER_EXIST 10039 // A close order already exists. +#define TRADE_RETCODE_LIMIT_POSITIONS 10040 // The number of open positions can be limited (e.g. Netting, Hedging). +#endif + // Missing error handling constants in MQL4. // @see: https://docs.mql4.com/constants/errorswarnings/errorcodes // @see: https://www.mql5.com/en/docs/constants/errorswarnings diff --git a/Terminal.extern.h b/Terminal.extern.h new file mode 100644 index 000000000..65582439f --- /dev/null +++ b/Terminal.extern.h @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Define external global functions. +#ifndef __MQL__ +extern int GetLastError(); +extern string TerminalInfoString(int property_id); +extern void ResetLastError(); +#endif diff --git a/Terminal.mqh b/Terminal.mqh index d408480a3..77aa28d13 100644 --- a/Terminal.mqh +++ b/Terminal.mqh @@ -43,6 +43,7 @@ class Terminal; #include "Refs.mqh" #include "String.mqh" #include "Terminal.define.h" +#include "Terminal.extern.h" #include "Terminal.enum.h" #include "Terminal.struct.h" diff --git a/MqlTick.h b/Tick.struct.h similarity index 71% rename from MqlTick.h rename to Tick.struct.h index 241e807b5..dbb226a4f 100644 --- a/MqlTick.h +++ b/Tick.struct.h @@ -29,6 +29,9 @@ #pragma once #endif +// Includes. +#include "DateTime.extern.h" + #ifndef __MQL__ /** * Structure for storing the latest prices of the symbol. @@ -46,3 +49,26 @@ struct MqlTick { unsigned long volume; // Volume for the current last price. }; #endif + +/** + * Structure for storing ask and bid prices of the symbol. + */ +template +struct TickAB { + T ask; // Current Ask price. + T bid; // Current Bid price. + // Struct constructors. + TickAB(T _ask = 0, T _bid = 0) : ask(_ask), bid(_bid) {} + TickAB(MqlTick &_tick) : ask((T)_tick.ask), bid((T)_tick.bid) {} +}; + +/** + * Structure for storing ask and bid prices of the symbol. + */ +template +struct TickTAB : TickAB { + datetime time; // Time of the last prices update. + // Struct constructors. + TickTAB(datetime _time = 0, T _ask = 0, T _bid = 0) : time(_time), TickAB(_ask, _bid) {} + TickTAB(MqlTick &_tick) : time(_tick.time), TickAB(_tick) {} +}; diff --git a/Tick/tests/TickManager.test.mq5 b/Tick/tests/TickManager.test.mq5 index a2b36637a..1c54f9b2a 100644 --- a/Tick/tests/TickManager.test.mq5 +++ b/Tick/tests/TickManager.test.mq5 @@ -36,7 +36,7 @@ TickManager tm; int OnInit() { bool _result = true; // ... - return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; + return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; } /** diff --git a/Ticker.mqh b/Ticker.mqh index 0e56e424d..a02bccd5c 100644 --- a/Ticker.mqh +++ b/Ticker.mqh @@ -145,7 +145,7 @@ class Ticker { return true; } bool Add() { - MqlTick _tick = this.symbol.GetTick(); + MqlTick _tick = this PTR_DEREF symbol.GetTick(); return Add(_tick); } @@ -172,8 +172,8 @@ class Ticker { FileWrite(_handle, "Datatime", "Bid", "Ask", "Volume"); for (int i = 0; i < index; i++) { if (data[i].time > 0) { - FileWrite(_handle, DateTimeStatic::TimeToStr(data[i].time, TIME_DATE | TIME_MINUTES | TIME_SECONDS), data[i].bid, - data[i].ask, data[i].volume); + FileWrite(_handle, DateTimeStatic::TimeToStr(data[i].time, TIME_DATE | TIME_MINUTES | TIME_SECONDS), + data[i].bid, data[i].ask, data[i].volume); total_saved++; } } diff --git a/Timer.mqh b/Timer.mqh index e772306d7..986556b08 100644 --- a/Timer.mqh +++ b/Timer.mqh @@ -28,140 +28,115 @@ * Class to provide functions to deal with the timer. */ class Timer : public Object { - - protected: - - // Variables. - string name; - int index; - uint data[]; - uint start, end; - ulong max; - - public: - - /** - * Class constructor. - */ - Timer(string _name = "") : index(-1), name(_name) { }; - - /* Main methods */ - - /** - * Start the timer. - */ - void Start() { - start = GetTickCount(); - } - - /** - * Stop the timer. - */ - Timer *Stop() { - end = GetTickCount(); - ArrayResize(this.data, ++this.index + 1, 10000); - data[this.index] = fabs(this.end - this.start); - max = fmax(data[this.index], this.max); - return GetPointer(this); - } - - /* Misc */ - - /** - * Print the current timer times. - */ - Timer *PrintSummary() { - Print(ToString()); - return GetPointer(this); - } - - /** - * Print the current timer times when maximum value is reached. - */ - Timer *PrintOnMax(ulong _min = 1) { - return - data[index] > _min && data[this.index] >= this.max - ? PrintSummary() - : GetPointer(this); - } - - /* Getters */ - - /** - * Stop the timer. - */ - uint GetTime(uint _index) { - return data[_index]; + protected: + // Variables. + string name; + int index; + uint data[]; + uint start, end; + ulong max; + + public: + /** + * Class constructor. + */ + Timer(string _name = "") : index(-1), name(_name){}; + + /* Main methods */ + + /** + * Start the timer. + */ + void Start() { start = GetTickCount(); } + + /** + * Stop the timer. + */ + Timer *Stop() { + end = GetTickCount(); + ArrayResize(this PTR_DEREF data, ++this PTR_DEREF index + 1, 10000); + data[this PTR_DEREF index] = fabs(this PTR_DEREF end - this PTR_DEREF start); + max = fmax(data[this PTR_DEREF index], this PTR_DEREF max); + return GetPointer(this); + } + + /* Misc */ + + /** + * Print the current timer times. + */ + Timer *PrintSummary() { + Print(ToString()); + return GetPointer(this); + } + + /** + * Print the current timer times when maximum value is reached. + */ + Timer *PrintOnMax(ulong _min = 1) { + return data[index] > _min && data[this PTR_DEREF index] >= this PTR_DEREF max ? PrintSummary() : GetPointer(this); + } + + /* Getters */ + + /** + * Stop the timer. + */ + uint GetTime(uint _index) { return data[_index]; } + uint GetTime() { return GetTickCount() - this PTR_DEREF start; } + + /** + * Returns timer name. + */ + string GetName() { return this PTR_DEREF name; } + + /** + * Get the sum of all values. + */ + ulong GetSum() { + uint _size = ArraySize(this PTR_DEREF data); + ulong _sum = 0; + for (uint _i = 0; _i < _size; _i++) { + _sum += data[_i]; } - uint GetTime() { - return GetTickCount() - this.start; + return _sum; + } + + /** + * Get the median of all values. + */ + uint GetMedian() { + if (this PTR_DEREF index >= 0) { + ArraySort(this PTR_DEREF data); } - - /** - * Returns timer name. - */ - string GetName() { - return this.name; - } - - /** - * Get the sum of all values. - */ - ulong GetSum() { - uint _size = ArraySize(this.data); - ulong _sum = 0; - for (uint _i = 0; _i < _size; _i++) { - _sum += data[_i]; - } - return _sum; - } - - /** - * Get the median of all values. - */ - uint GetMedian() { - if (this.index >= 0) { - ArraySort(this.data); - } - return this.index >= 0 ? this.data[this.index / 2] : 0; - } - - /** - * Get the minimum time value. - */ - uint GetMin() { - return this.index >= 0 ? this.data[ArrayMinimum(this.data)] : 0; - } - - /** - * Get the maximal time value. - */ - uint GetMax() { - int _index = this.index >= 0 ? ArrayMaximum(this.data) : -1; - return _index >= 0 ? data[_index] : 0; - } - - /* Inherited methods */ - - /** - * Print timer times. - */ - virtual const string ToString() { - return StringFormat("%s(%d)=%d-%dms,med=%dms,sum=%dms", - GetName(), - ArraySize(this.data), - GetMin(), - GetMax(), - GetMedian(), - GetSum() - ); - } - - /** - * Returns weight of the object. - */ - virtual double GetWeight() { - return (double) GetSum(); - } - + return this PTR_DEREF index >= 0 ? this PTR_DEREF data[this PTR_DEREF index / 2] : 0; + } + + /** + * Get the minimum time value. + */ + uint GetMin() { return this PTR_DEREF index >= 0 ? this PTR_DEREF data[ArrayMinimum(this PTR_DEREF data)] : 0; } + + /** + * Get the maximal time value. + */ + uint GetMax() { + int _index = this PTR_DEREF index >= 0 ? ArrayMaximum(this PTR_DEREF data) : -1; + return _index >= 0 ? data[_index] : 0; + } + + /* Inherited methods */ + + /** + * Print timer times. + */ + virtual const string ToString() { + return StringFormat("%s(%d)=%d-%dms,med=%dms,sum=%dms", GetName(), ArraySize(this PTR_DEREF data), GetMin(), + GetMax(), GetMedian(), GetSum()); + } + + /** + * Returns weight of the object. + */ + virtual double GetWeight() { return (double)GetSum(); } }; diff --git a/Trade/TradeSignal.struct.h b/Trade/TradeSignal.struct.h index 77918c1fd..5b8221cce 100644 --- a/Trade/TradeSignal.struct.h +++ b/Trade/TradeSignal.struct.h @@ -26,7 +26,7 @@ */ // Includes. -#include "../Serializer.mqh" +#include "../Chart.enum.h" #include "../SerializerConverter.mqh" #include "../SerializerJson.mqh" @@ -53,12 +53,12 @@ // 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). + float strength; // Signal strength. + ENUM_TIMEFRAMES tf; // Timeframe. + long timestamp; // Creation timestamp + float weight; // Signal weight. public: /* Struct's enumerations */ @@ -115,7 +115,7 @@ struct TradeSignalEntry { 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; } + TradeSignalEntry(const TradeSignalEntry &_entry) { THIS_REF = _entry; } /* Getters */ template T Get(STRUCT_ENUM(TradeSignalEntry, ENUM_TRADE_SIGNAL_PROP) _prop) { @@ -134,7 +134,7 @@ struct TradeSignalEntry { return (T)weight; } SetUserError(ERR_INVALID_PARAMETER); - return (T)WRONG_VALUE; + return (T)NULL; } bool Get(STRUCT_ENUM(TradeSignalEntry, ENUM_TRADE_SIGNAL_FLAG) _prop) { return CheckSignals(_prop); } /* Setters */ @@ -189,7 +189,7 @@ struct TradeSignalEntry { 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); + _s.Pass(THIS_REF, IntegerToString(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } return SerializerNodeObject; } diff --git a/Trade/TradeSignalManager.h b/Trade/TradeSignalManager.h index e3e9060a1..87dd5c017 100644 --- a/Trade/TradeSignalManager.h +++ b/Trade/TradeSignalManager.h @@ -124,14 +124,14 @@ class TradeSignalManager : Dynamic { void Refresh() { for (DictObjectIterator iter = GetIterSignalsActive(); iter.IsValid(); ++iter) { TradeSignal *_signal = iter.Value(); - if (_signal.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_PROCESSED))) { + if (_signal PTR_DEREF Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_PROCESSED))) { signals_active.Unset(iter); - signals_processed.Push(_signal); + signals_processed.Push(PTR_TO_REF(_signal)); continue; } - if (_signal.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_EXPIRED))) { + if (_signal PTR_DEREF Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_FLAG_EXPIRED))) { signals_active.Unset(iter); - signals_expired.Push(_signal); + signals_expired.Push(PTR_TO_REF(_signal)); continue; } } diff --git a/Trade/TradeSignalManager.struct.h b/Trade/TradeSignalManager.struct.h index 7e492a21d..d4be49393 100644 --- a/Trade/TradeSignalManager.struct.h +++ b/Trade/TradeSignalManager.struct.h @@ -34,8 +34,8 @@ */ struct TradeSignalManagerParams { protected: - long last_check; // Last check. short freq; // Signal process refresh frequency (in sec). + long last_check; // Last check. public: /* Struct's enumerations */ @@ -67,7 +67,7 @@ struct TradeSignalManagerParams { return (T)last_check; } SetUserError(ERR_INVALID_PARAMETER); - return (T)WRONG_VALUE; + return (T)NULL; } /* Setters */ diff --git a/Trade/tests/TradeSignal.test.cpp b/Trade/tests/TradeSignal.test.cpp new file mode 100644 index 000000000..696ec4422 --- /dev/null +++ b/Trade/tests/TradeSignal.test.cpp @@ -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 + * Test C++ compilation of TradeSignal class. + */ + +// Includes. +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" +#include "../TradeSignal.h" + +int main(int argc, char **argv) {} diff --git a/Trade/tests/TradeSignalManager.test.cpp b/Trade/tests/TradeSignalManager.test.cpp new file mode 100644 index 000000000..7ca976d9f --- /dev/null +++ b/Trade/tests/TradeSignalManager.test.cpp @@ -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 + * Test C++ compilation of TradeSignalManager class. + */ + +// Includes. +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" +#include "../TradeSignalManager.h" + +int main(int argc, char **argv) {} diff --git a/Util.h b/Util.h index 12ccb0c28..a4a012cda 100644 --- a/Util.h +++ b/Util.h @@ -65,6 +65,36 @@ class Util { return _result; } + /** + * Removes value from the array. + */ + template + static bool ArrayRemove(T& _array[], int index) { + if (index < 0 || index >= ArraySize(_array)) { + // Index out of array bounds. + return false; + } + for (int i = index; i < ArraySize(_array) - 1; ++i) { + _array[i] = _array[i + 1]; + } + Util::ArrayResize(_array, ArraySize(_array) - 1); + return true; + } + + /** + * Removes value from the array. + */ + template + static bool ArrayRemoveFirst(T& _array[], T& value) { + for (int i = 0; i < ArraySize(_array); ++i) { + if (_array[i] == value) { + Util::ArrayRemove(_array, i); + return true; + } + } + return false; + } + template static T Print(T& _array[]) { string _result; @@ -74,6 +104,21 @@ class Util { return _result; } + /** + * Splits prints by newlines on MT4. + */ + static void Print(string _value) { +#ifdef __MQL4__ + string _segments[]; + StringSplit(_value, '\n', _segments); + for (int i = 0; i < ArraySize(_segments); ++i) { + ::Print(_segments[i]); + } +#else + ::Print(_value); +#endif + } + /** * Checks whether array has given value. */ @@ -259,6 +304,65 @@ class Util { SerializerConversions::ValueToString(_l) + SerializerConversions::ValueToString(_m); } + /** + * 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, const H _h, + const I _i, const J _j, const K _k, const L _l, const M _m, const N _n) { + 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) + + SerializerConversions::ValueToString(_h) + SerializerConversions::ValueToString(_i) + + SerializerConversions::ValueToString(_j) + SerializerConversions::ValueToString(_k) + + SerializerConversions::ValueToString(_l) + SerializerConversions::ValueToString(_m) + + SerializerConversions::ValueToString(_n); + } + + /** + * 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, const H _h, + const I _i, const J _j, const K _k, const L _l, const M _m, const N _n, const O _o) { + 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) + + SerializerConversions::ValueToString(_h) + SerializerConversions::ValueToString(_i) + + SerializerConversions::ValueToString(_j) + SerializerConversions::ValueToString(_k) + + SerializerConversions::ValueToString(_l) + SerializerConversions::ValueToString(_m) + + SerializerConversions::ValueToString(_n) + SerializerConversions::ValueToString(_o); + } + + /** + * 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, const H _h, + const I _i, const J _j, const K _k, const L _l, const M _m, const N _n, const O _o, + const P _p) { + 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) + + SerializerConversions::ValueToString(_h) + SerializerConversions::ValueToString(_i) + + SerializerConversions::ValueToString(_j) + SerializerConversions::ValueToString(_k) + + SerializerConversions::ValueToString(_l) + SerializerConversions::ValueToString(_m) + + SerializerConversions::ValueToString(_n) + SerializerConversions::ValueToString(_o) + + SerializerConversions::ValueToString(_p); + } + /** * Creates string with separator if string was not empty. */ diff --git a/tests/BufferStructTest.mq5 b/tests/BufferStructTest.mq5 index a55ed6baa..f5881fb70 100644 --- a/tests/BufferStructTest.mq5 +++ b/tests/BufferStructTest.mq5 @@ -28,6 +28,7 @@ #include "../BufferStruct.mqh" #include "../Data.define.h" #include "../Data.struct.h" +#include "../SerializerConverter.mqh" #include "../SerializerJSON.mqh" #include "../Std.h" #include "../Test.mqh" diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index dea9802e4..ef6ceeab7 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -62,6 +62,7 @@ #include "../ISerializable.h" #include "../Indicator.define.h" #include "../Indicator.mqh" +#include "../IndicatorBase.h" #include "../IndicatorData.mqh" #include "../Inet.mqh" #include "../Log.mqh" diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index 0ec2fc83b..2770d7db5 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -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) { - IndicatorBase *_indi = iter.Value(); + for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { + IndicatorData *_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. IndiMAParams ma_params(13, 10, MODE_SMA, PRICE_OPEN); - IndicatorBase *indi_ma = new Indi_MA(ma_params); + IndicatorData *indi_ma = new Indi_MA(ma_params); indis.Set(INDI_MA, indi_ma); // Relative Strength Index (RSI). @@ -109,40 +109,40 @@ bool InitIndicators() { // Demo/Dummy Indicator. IndiDemoParams demo_params; - IndicatorBase *indi_demo = new Indi_Demo(demo_params); + IndicatorData *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); - IndicatorBase *indi_price = new Indi_Price(price_params); + IndicatorData *indi_price = new Indi_Price(price_params); indis.Set(INDI_PRICE, indi_price); + /* @fixme: Array out of range. // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); - IndicatorBase *indi_price_4_bands = new Indi_Price(price_params_4_bands); + IndicatorData *indi_price_4_bands = new Indi_Price(price_params_4_bands); IndiBandsParams bands_on_price_params(); bands_on_price_params.SetDraw(clrCadetBlue); - // bands_on_price_params.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)); + indis.Set(INDI_BANDS_ON_PRICE, new Indi_Bands(bands_on_price_params, IDATA_INDICATOR, indi_price_4_bands)); // Moving Average (MA) over Price indicator. PriceIndiParams price_params_4_ma(); - IndicatorBase *indi_price_4_ma = new Indi_Price(price_params_4_ma); + IndicatorData *indi_price_4_ma = new Indi_Price(price_params_4_ma); IndiMAParams ma_on_price_params(); ma_on_price_params.SetDraw(clrYellowGreen); - // ma_on_price_params.SetDataSource(indi_price_4_ma, true, INDI_PRICE_MODE_OPEN); ma_on_price_params.SetIndicatorType(INDI_MA_ON_PRICE); - IndicatorBase *indi_ma_on_price = new Indi_MA(ma_on_price_params, indi_price_4_ma); + IndicatorData *indi_ma_on_price = new Indi_MA(ma_on_price_params, IDATA_INDICATOR, indi_price_4_ma); indis.Set(INDI_MA_ON_PRICE, indi_ma_on_price); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); - IndicatorBase *indi_price_4_rsi = new Indi_Price(price_params_4_rsi); + IndicatorData *indi_price_4_rsi = new Indi_Price(price_params_4_rsi); IndiRSIParams 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.Set(INDI_RSI_ON_PRICE, indi_price_4_rsi); + IndicatorBase *indi_rsi_on_price = new Indi_RSI(rsi_on_price_params, IDATA_INDICATOR, indi_price_4_rsi); + indis.Set(INDI_RSI_ON_PRICE, indi_rsi_on_price); + */ return _LastError == ERR_NO_ERROR; } @@ -152,8 +152,8 @@ bool InitIndicators() { */ bool PrintIndicators(string _prefix = "") { ResetLastError(); - for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { - IndicatorBase *_indi = iter.Value(); + for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { + IndicatorData *_indi = iter.Value(); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString()); } diff --git a/tests/IndicatorBaseTest.mq4 b/tests/IndicatorBaseTest.mq4 new file mode 100644 index 000000000..167dec35e --- /dev/null +++ b/tests/IndicatorBaseTest.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of IndicatorBase class. + */ + +// Includes. +#include "IndicatorBaseTest.mq5" diff --git a/tests/IndicatorBaseTest.mq5 b/tests/IndicatorBaseTest.mq5 new file mode 100644 index 000000000..8ca89f936 --- /dev/null +++ b/tests/IndicatorBaseTest.mq5 @@ -0,0 +1,37 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of IndicatorBase class. + */ + +// Includes. +#include "../IndicatorBase.h" +#include "../Test.mqh" + +/** + * Implements OnInit(). + */ +int OnInit() { + // @todo + return (INIT_SUCCEEDED); +} diff --git a/tests/IndicatorDataTest.mq4 b/tests/IndicatorDataTest.mq4 index dd6581caa..ec907afe1 100644 --- a/tests/IndicatorDataTest.mq4 +++ b/tests/IndicatorDataTest.mq4 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -25,184 +25,4 @@ */ // Includes. -#include "../IndicatorData.mqh" - -// User inputs. -#ifdef __input__ input #endif string __MA_Parameters__ = "-- Settings for the Moving Average indicator --"; // >>> MA <<< -#ifdef __input__ input #endif int MA_Period_Fast = 14; // Period Fast -#ifdef __input__ input #endif int MA_Period_Medium = 20; // Period Medium -#ifdef __input__ input #endif int MA_Period_Slow = 48; // Period Slow -#ifdef __input__ input #endif double MA_Period_Ratio = 1.0; // Period ratio between timeframes (0.5-1.5) -#ifdef __input__ input #endif int MA_Shift = 0; // Shift -#ifdef __input__ input #endif int MA_Shift_Fast = 0; // Shift Fast (+1) -#ifdef __input__ input #endif int MA_Shift_Medium = 0; // Shift Medium (+1) -#ifdef __input__ input #endif int MA_Shift_Slow = 1; // Shift Slow (+1) -#ifdef __input__ input #endif int MA_Shift_Far = 4; // Shift Far (+2) -#ifdef __input__ input #endif ENUM_MA_METHOD MA_Method = 1; // MA Method -#ifdef __input__ input #endif ENUM_APPLIED_PRICE MA_Applied_Price = 3; // Applied Price - -class I_MA : public IndicatorData { - protected: - // Indicator Buffers. - enum ENUM_MA_MODE { - MODE_MA_FAST = 0, - MODE_MA_MEDIUM = 1, - MODE_MA_SLOW = 2, - MAX_OF_ENUM_MA_MODE // Buffers count - }; - - public: - /** - * Class constructor. - */ - void I_MA() : IndicatorData("Custom MA Indicator", MAX_OF_ENUM_MA_MODE) {} - - /** - * Returns the indicator value. - * - * @docs - * - https://docs.mql4.com/indicators/ima - * - https://www.mql5.com/en/docs/indicators/ima - */ - static double iMA(string _symbol, ENUM_TIMEFRAMES _tf, uint _ma_period, int _ma_shift, - ENUM_MA_METHOD _ma_method, // (MT4/MT5): MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA - ENUM_APPLIED_PRICE _applied_price, // (MT4/MT5): PRICE_CLOSE, PRICE_OPEN, PRICE_HIGH, PRICE_LOW, - // PRICE_MEDIAN, PRICE_TYPICAL, PRICE_WEIGHTED - int _shift = 0) { -#ifdef __MQL4__ - return ::iMA(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_price, _shift); -#else // __MQL5__ - double _res[]; - int _handle = ::iMA(_symbol, _tf, _ma_period, _ma_shift, _ma_method, _applied_price); - return CopyBuffer(_handle, 0, _shift, 1, _res) > 0 ? _res[0] : EMPTY_VALUE; -#endif - } - double iMA(uint _ma_period, int _ma_shift, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_PRICE _applied_price, - int _shift = 0) { - double _value = iMA(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), _ma_period, _ma_shift, - _ma_method, _applied_price, _shift); - return _value; - } - - /** - * Get period value from settings. - */ - int GetPeriod(ENUM_MA_MODE _ma_type) { - switch (_ma_type) { - default: - case MODE_MA_FAST: - return MA_Period_Fast; - case MODE_MA_MEDIUM: - return MA_Period_Medium; - case MODE_MA_SLOW: - return MA_Period_Slow; - } - } - - /** - * Get shift value from settings. - */ - int GetShift(ENUM_MA_MODE _ma_type) { - switch (_ma_type) { - default: - case MODE_MA_FAST: - return MA_Shift_Fast; - case MODE_MA_MEDIUM: - return MA_Shift_Medium; - case MODE_MA_SLOW: - return MA_Shift_Slow; - } - } - - /** - * Get method value from settings. - */ - ENUM_MA_METHOD GetMethod(ENUM_MA_MODE _ma_type) { - switch (_ma_type) { - default: - case MODE_MA_FAST: - return MA_Method; - case MODE_MA_MEDIUM: - return MA_Method; - case MODE_MA_SLOW: - return MA_Method; - } - } - - /** - * Get applied price value from settings. - */ - ENUM_APPLIED_PRICE GetAppliedPrice(ENUM_MA_MODE _ma_type) { - switch (_ma_type) { - default: - case MODE_MA_FAST: - return MA_Applied_Price; - case MODE_MA_MEDIUM: - return MA_Applied_Price; - case MODE_MA_SLOW: - return MA_Applied_Price; - } - } - - /** - * Calculates the Moving Average indicator. - */ - bool Update(int shift = CURR) { - bool _res = true; - double _ma_value; - for (ENUM_MA_MODE mode = 0; mode <= MODE_MA_SLOW; mode++) { - _ma_value = iMA(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), GetPeriod(mode), - GetShift(mode), GetMethod(mode), GetAppliedPrice(mode), shift); - _res &= Add(_ma_value, mode, shift); - } - return _res; - } -}; - -////////////////////////////////////////////////////////////////////////// -// create a custom mt4 indicator to show values on mt4 chart -////////////////////////////////////////////////////////////////////////// - -#property indicator_chart_window -#property indicator_buffers MAX_OF_ENUM_MA_MODE - -double FastMa[]; -double MediumMa[]; -double SlowMa[]; - -I_MA myMa; - -/** - * Implements OnInit(). - */ -int OnInit() { - IndicatorBuffers(MAX_OF_ENUM_MA_MODE); - SetIndexBuffer(MODE_MA_FAST, FastMa); - SetIndexBuffer(MODE_MA_MEDIUM, MediumMa); - SetIndexBuffer(MODE_MA_SLOW, SlowMa); - - SetIndexStyle(MODE_MA_FAST, DRAW_LINE, STYLE_SOLID, 1, clrRed); - SetIndexStyle(MODE_MA_MEDIUM, DRAW_LINE, STYLE_SOLID, 1, clrGreen); - SetIndexStyle(MODE_MA_SLOW, DRAW_LINE, STYLE_SOLID, 1, clrGreen); - return (INIT_SUCCEEDED); -} - -int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], - const double &high[], const double &low[], const double &close[], const long &tick_volume[], - const long &volume[], const int &spread[]) { - uint start_at = GetTickCount(); - - int oldest_bar = rates_total - prev_calculated - 1; - for (int i = oldest_bar; i >= 0; i--) { - bool ok = myMa.Update(i); - if (!ok) continue; - - FastMa[i] = myMa.GetDouble(MODE_MA_FAST, i); - MediumMa[i] = myMa.GetDouble(MODE_MA_MEDIUM, i); - SlowMa[i] = myMa.GetDouble(MODE_MA_SLOW, i); - } - - PrintFormat("elapse %dms", GetTickCount() - start_at); - - return (rates_total); -} +#include "IndicatorDataTest.mq5" diff --git a/tests/IndicatorDataTest.mq5 b/tests/IndicatorDataTest.mq5 new file mode 100644 index 000000000..bd6a17c11 --- /dev/null +++ b/tests/IndicatorDataTest.mq5 @@ -0,0 +1,37 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of IndicatorData class. + */ + +// Includes. +#include "../IndicatorData.mqh" +#include "../Test.mqh" + +/** + * Implements OnInit(). + */ +int OnInit() { + // @todo + return (INIT_SUCCEEDED); +} diff --git a/tests/IndicatorTest.mq5 b/tests/IndicatorTest.mq5 index fde4800ce..79b70758c 100644 --- a/tests/IndicatorTest.mq5 +++ b/tests/IndicatorTest.mq5 @@ -45,14 +45,14 @@ int OnInit() { entry.integer_value = 1; for (uint i = 0; i < in.GetBufferSize() * 2; i++) { in.AddValue(entry); - Print("Index ", i, ": Curr: ", in.GetValue(0).integer_value, "; Prev: ", in.GetValue(1).integer_value); - assertTrueOrFail(in.GetValue(0).integer_value == entry.integer_value, + Print("Index ", i, ": Curr: ", in.GetValue(0, 0).integer_value, "; Prev: ", in.GetValue(0, 1).integer_value); + assertTrueOrFail(in.GetValue(0, 0).integer_value == entry.integer_value, StringFormat("Wrong latest value (%d <> %d)!", - in.GetValue(0).integer_value, + in.GetValue(0, 0).integer_value, entry.integer_value)); - assertTrueOrFail(in.GetValue(1).integer_value == entry.integer_value - 1, + assertTrueOrFail(in.GetValue(0, 1).integer_value == entry.integer_value - 1, StringFormat("Wrong previous value (%d <> %d)!", - in.GetValue(1).integer_value, + in.GetValue(0, 1).integer_value, entry.integer_value - 1)); entry.integer_value++; } diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 3a36f05da..6ec22c545 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -25,7 +25,8 @@ */ // Defines. -//#define __debug__ // Enables debug. +// #define __debug__ // Enables debug. +// #define __debug_verbose__ // Forward declaration. struct DataParamEntry; @@ -45,15 +46,15 @@ enum ENUM_CUSTOM_INDICATORS { INDI_SPECIAL_MATH_CUSTOM = FINAL_INDICATOR_TYPE_EN // Global variables. Chart* chart; -DictStruct> indis; -DictStruct> whitelisted_indis; +DictStruct> indis; +DictStruct> 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, 1.240, 1.234, 1.245, 1.265, 1.274, 1.285, 1.295, 1.300, 1.312, 1.315, 1.320, 1.325, 1.335, 1.342, 1.348, 1.352, 1.357, 1.359, 1.422, 1.430, 1.435}; Ref _indi_drawer; -Ref _indi_test; +Ref _indi_test; /** * Implements Init event handler. @@ -83,13 +84,18 @@ int OnInit() { void OnTick() { chart.OnTick(); + // All indicators should execute its OnTick() method for every platform tick. + for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + // iter.Value().Ptr().Tick(); // @fixme + } + if (chart.IsNewBar()) { bar_processed++; if (indis.Size() == 0) { return; } - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { if (whitelisted_indis.Size() == 0) { if (tested.GetByKey(iter.Key())) { // Indicator is already tested, skipping. @@ -101,9 +107,10 @@ void OnTick() { } } - IndicatorBase* _indi = iter.Value().Ptr(); - _indi.OnTick(); + IndicatorData* _indi = iter.Value().Ptr(); + // _indi.OnTick(); // @fixme IndicatorDataEntry _entry(_indi.GetEntry()); + if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { if (_entry.IsValid()) { PrintFormat("%s: bar %d: %s", _indi.GetFullName(), bar_processed, _indi.ToString()); @@ -157,7 +164,8 @@ bool InitIndicators() { indis.Push(new Indi_AO()); // Accumulation Swing Index (ASI). - indis.Push(new Indi_ASI()); + IndiASIParams _asi_params; + indis.Push(new Indi_ASI(_asi_params)); // Average True Range (ATR). IndiATRParams atr_params(14); @@ -165,13 +173,15 @@ bool InitIndicators() { // Bollinger Bands. IndiBandsParams bands_params(20, 2, 0, PRICE_OPEN); - Ref indi_bands = new Indi_Bands(bands_params); + Ref indi_bands = new Indi_Bands(bands_params); indis.Push(indi_bands); // Bollinger Bands over RSI. + /* @todo: Convert into new syntax. IndiBandsParams bands_over_rsi_params(20, 2, 0, PRICE_OPEN); - bands_over_rsi_params.SetDataSource(INDI_RSI); + // bands_over_rsi_params.SetDataSource(INDI_RSI); indis.Push(new Indi_Bands(bands_over_rsi_params)); + */ // Bears Power. IndiBearsPowerParams bears_params(13, PRICE_CLOSE); @@ -213,7 +223,8 @@ bool InitIndicators() { indis.Push(new Indi_Gator(gator_params)); // Heiken Ashi. - indis.Push(new Indi_HeikenAshi()); + IndiHeikenAshiParams _ha_params(); + indis.Push(new Indi_HeikenAshi(_ha_params)); // Ichimoku Kinko Hyo. IndiIchimokuParams ichi_params(9, 26, 52); @@ -221,17 +232,17 @@ bool InitIndicators() { // Moving Average. IndiMAParams ma_params(13, 0, MODE_SMA, PRICE_OPEN); - Ref indi_ma = new Indi_MA(ma_params); + Ref indi_ma = new Indi_MA(ma_params); indis.Push(indi_ma); // DEMA. IndiDEIndiMAParams dema_params(13, 2, PRICE_OPEN); - Ref indi_dema = new Indi_DEMA(dema_params); + Ref indi_dema = new Indi_DEMA(dema_params); indis.Push(indi_dema); // MACD. IndiMACDParams macd_params(12, 26, 9, PRICE_CLOSE); - Ref macd = new Indi_MACD(macd_params); + Ref macd = new Indi_MACD(macd_params); indis.Push(macd); // Money Flow Index (MFI). @@ -254,9 +265,11 @@ bool InitIndicators() { indis.Push(new Indi_RSI(rsi_params)); // Relative Strength Index (RSI). + /* @todo: Convert into new syntax. IndiRSIParams rsi_over_blt_stddev_params(); - rsi_over_blt_stddev_params.SetDataSource(INDI_STDDEV); + // rsi_over_blt_stddev_params.SetDataSource(INDI_STDDEV); indis.Push(new Indi_RSI(rsi_over_blt_stddev_params)); + */ // Relative Vigor Index (RVI). IndiRVIParams rvi_params(14); @@ -271,12 +284,11 @@ bool InitIndicators() { indis.Push(new Indi_StdDev(stddev_params)); // Standard Deviation (StdDev). - Ref indi_price_for_stdev = new Indi_Price(PriceIndiParams()); + Ref indi_price_for_stdev = new Indi_Price(PriceIndiParams()); IndiStdDevParams stddev_on_price_params(); stddev_on_price_params.SetDraw(clrBlue, 1); - Ref indi_stddev_on_price = new Indi_StdDev(stddev_on_price_params); - indi_stddev_on_price.Ptr().SetDataSource(indi_price_for_stdev.Ptr(), PRICE_OPEN); + Ref indi_stddev_on_price = new Indi_StdDev(stddev_on_price_params, IDATA_BUILTIN, indi_price_for_stdev.Ptr()); indis.Push(indi_stddev_on_price.Ptr()); // Stochastic Oscillator. @@ -299,108 +311,99 @@ bool InitIndicators() { // Current Price. PriceIndiParams price_params(); // price_params.SetDraw(clrAzure); - Ref indi_price = new Indi_Price(price_params); + Ref indi_price = new Indi_Price(price_params); indis.Push(indi_price); // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); - Ref indi_price_4_bands = new Indi_Price(price_params_4_bands); + Ref indi_price_4_bands = new Indi_Price(price_params_4_bands); IndiBandsParams bands_on_price_params(); bands_on_price_params.SetDraw(clrCadetBlue); - Ref indi_bands_on_price = new Indi_Bands(bands_on_price_params); - indi_bands_on_price.Ptr().SetDataSource(indi_price_4_bands.Ptr()); + Ref indi_bands_on_price = new Indi_Bands(bands_on_price_params, IDATA_BUILTIN, indi_price_4_bands.Ptr()); indis.Push(indi_bands_on_price.Ptr()); // 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). IndiMAParams ma_sma_params_for_stddev(); - Ref indi_ma_sma_for_stddev = new Indi_MA(ma_sma_params_for_stddev); + Ref indi_ma_sma_for_stddev = new Indi_MA(ma_sma_params_for_stddev); IndiStdDevParams stddev_params_on_ma_sma(13, 10); stddev_params_on_ma_sma.SetDraw(true, 1); - Ref indi_stddev_on_ma_sma = new Indi_StdDev(stddev_params_on_ma_sma); - indi_stddev_on_ma_sma.Ptr().SetDataSource(indi_ma_sma_for_stddev.Ptr(), 0); + Ref indi_stddev_on_ma_sma = new Indi_StdDev(stddev_params_on_ma_sma, IDATA_BUILTIN, indi_ma_sma_for_stddev.Ptr()); indis.Push(indi_stddev_on_ma_sma.Ptr()); // Standard Deviation (StdDev) in SMA mode over Price. PriceIndiParams price_params_for_stddev_sma(); - Ref indi_price_for_stddev_sma = new Indi_Price(price_params_for_stddev_sma); + Ref indi_price_for_stddev_sma = new Indi_Price(price_params_for_stddev_sma); IndiStdDevParams stddev_sma_on_price_params(); stddev_sma_on_price_params.SetDraw(true, 1); - Ref indi_stddev_on_sma = new Indi_StdDev(stddev_sma_on_price_params); - indi_stddev_on_sma.Ptr().SetDataSource(indi_price_for_stddev_sma.Ptr()); + Ref indi_stddev_on_sma = new Indi_StdDev(stddev_sma_on_price_params, IDATA_BUILTIN, indi_price_for_stddev_sma.Ptr()); indis.Push(indi_stddev_on_sma.Ptr()); // Moving Average (MA) over Price indicator. PriceIndiParams price_params_4_ma(); - Ref indi_price_4_ma = new Indi_Price(price_params_4_ma); + Ref indi_price_4_ma = new Indi_Price(price_params_4_ma); IndiMAParams ma_on_price_params(13, 0, MODE_SMA, PRICE_OPEN, 0); ma_on_price_params.SetDraw(clrYellowGreen); ma_on_price_params.SetIndicatorType(INDI_MA_ON_PRICE); - Ref indi_ma_on_price = new Indi_MA(ma_on_price_params); - indi_ma_on_price.Ptr().SetDataSource(indi_price_4_ma.Ptr()); + Ref indi_ma_on_price = new Indi_MA(ma_on_price_params, IDATA_BUILTIN, indi_price_4_ma.Ptr()); indis.Push(indi_ma_on_price.Ptr()); // Commodity Channel Index (CCI) over Price indicator. PriceIndiParams price_params_4_cci(); - Ref indi_price_4_cci = new Indi_Price(price_params_4_cci); + Ref indi_price_4_cci = new Indi_Price(price_params_4_cci); IndiCCIParams cci_on_price_params(); cci_on_price_params.SetDraw(clrYellowGreen, 1); - Ref indi_cci_on_price = new Indi_CCI(cci_on_price_params); - indi_cci_on_price.Ptr().SetDataSource(indi_price_4_cci.Ptr()); + Ref indi_cci_on_price = new Indi_CCI(cci_on_price_params, IDATA_BUILTIN, indi_price_4_cci.Ptr()); indis.Push(indi_cci_on_price.Ptr()); // Envelopes over Price indicator. PriceIndiParams price_params_4_envelopes(); - Ref indi_price_4_envelopes = new Indi_Price(price_params_4_envelopes); + Ref indi_price_4_envelopes = new Indi_Price(price_params_4_envelopes); IndiEnvelopesParams env_on_price_params(); env_on_price_params.SetDraw(clrBrown); - Ref indi_envelopes_on_price = new Indi_Envelopes(env_on_price_params); - indi_envelopes_on_price.Ptr().SetDataSource(indi_price_4_envelopes.Ptr()); + Ref indi_envelopes_on_price = new Indi_Envelopes(env_on_price_params, IDATA_BUILTIN, indi_price_4_envelopes.Ptr()); indis.Push(indi_envelopes_on_price.Ptr()); // DEMA over Price indicator. PriceIndiParams price_params_4_dema(); - Ref indi_price_4_dema = new Indi_Price(price_params_4_dema); + Ref indi_price_4_dema = new Indi_Price(price_params_4_dema); IndiDEIndiMAParams dema_on_price_params(13, 2, PRICE_OPEN); dema_on_price_params.SetDraw(clrRed); - Ref indi_dema_on_price = new Indi_DEMA(dema_on_price_params); - indi_dema_on_price.Ptr().SetDataSource(indi_price_4_dema.Ptr()); + Ref indi_dema_on_price = new Indi_DEMA(dema_on_price_params, IDATA_BUILTIN, indi_price_4_dema.Ptr()); indis.Push(indi_dema_on_price.Ptr()); // Momentum over Price indicator. - Ref indi_price_4_momentum = new Indi_Price(); + Ref indi_price_4_momentum = new Indi_Price(); IndiMomentumParams mom_on_price_params(); mom_on_price_params.SetDraw(clrDarkCyan); - Ref indi_momentum_on_price = new Indi_Momentum(mom_on_price_params); - indi_momentum_on_price.Ptr().SetDataSource(indi_price_4_momentum.Ptr(), 0); + Ref indi_momentum_on_price = new Indi_Momentum(mom_on_price_params, IDATA_BUILTIN, indi_price_4_momentum.Ptr()); indis.Push(indi_momentum_on_price.Ptr()); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); - Ref indi_price_4_rsi = new Indi_Price(price_params_4_rsi); + Ref indi_price_4_rsi = new Indi_Price(price_params_4_rsi); IndiRSIParams rsi_on_price_params(); rsi_on_price_params.SetDraw(clrBisque, 1); - Ref indi_rsi_on_price = new Indi_RSI(rsi_on_price_params); - indi_rsi_on_price.Ptr().SetDataSource(indi_price_4_rsi.Ptr()); + Ref indi_rsi_on_price = new Indi_RSI(rsi_on_price_params, IDATA_BUILTIN, indi_price_4_rsi.Ptr()); indis.Push(indi_rsi_on_price.Ptr()); +#ifndef __MQL4__ // @fixme: Fix it for MQL4. // Drawer (socket-based) indicator over RSI over Price. IndiDrawerParams drawer_params(14, /*unused*/ PRICE_OPEN); drawer_params.SetDraw(clrBisque, 0); - Ref indi_drawer_on_rsi = new Indi_Drawer(drawer_params); - indi_drawer_on_rsi.Ptr().SetDataSource(indi_rsi_on_price.Ptr(), PRICE_OPEN); + Ref indi_drawer_on_rsi = new Indi_Drawer(drawer_params, IDATA_BUILTIN, indi_rsi_on_price.Ptr()); indis.Push(indi_drawer_on_rsi.Ptr()); +#endif // Applied Price over OHCL indicator. IndiAppliedPriceParams applied_price_params(); applied_price_params.SetDraw(clrAquamarine, 0); - IndiOHLCParams applied_price_ohlc_params; - Ref indi_applied_price_on_price = new Indi_AppliedPrice(applied_price_params); - indi_applied_price_on_price.Ptr().SetDataSource(new Indi_OHLC(applied_price_ohlc_params), PRICE_TYPICAL); + IndiOHLCParams applied_price_ohlc_params(PRICE_TYPICAL); + Ref indi_applied_price_on_price = new Indi_AppliedPrice(applied_price_params, IDATA_INDICATOR, new Indi_OHLC(applied_price_ohlc_params)); indis.Push(indi_applied_price_on_price.Ptr()); // ADXW. @@ -408,8 +411,20 @@ bool InitIndicators() { indis.Push(new Indi_ADXW(adxw_params)); // AMA. + /* @fixme IndiAMAParams ama_params(); - indis.Push(new Indi_AMA(ama_params)); + // Will use Candle indicator by default. + // However, in that case we need to specifiy applied price (excluding ASK and BID). + ama_params.SetDataSourceType(IDATA_INDICATOR); + Indi_AMA* _indi_ama = new Indi_AMA(ama_params); + _indi_ama.SetAppliedPrice(PRICE_OPEN); + indis.Push(_indi_ama); + */ + + // Original AMA. + IndiAMAParams ama_params_orig(); + ama_params_orig.SetName("Original AMA to compare"); + indis.Push(new Indi_AMA(ama_params_orig)); // Chaikin Oscillator. IndiCHOParams cho_params(); @@ -499,16 +514,14 @@ bool InitIndicators() { IndiMathParams math_params(MATH_OP_SUB, BAND_UPPER, BAND_LOWER, 0, 0); math_params.SetDraw(clrBlue); math_params.SetName("Bands(UP - LO)"); - Ref indi_math_1 = new Indi_Math(math_params); - indi_math_1.Ptr().SetDataSource(indi_bands.Ptr(), 0); + Ref indi_math_1 = new Indi_Math(math_params, IDATA_INDICATOR, indi_bands.Ptr()); indis.Push(indi_math_1.Ptr()); // Math (specialized indicator) via custom math method. IndiMathParams math_custom_params(MathCustomOp, BAND_UPPER, BAND_LOWER, 0, 0); math_custom_params.SetDraw(clrBeige); math_custom_params.SetName("Bands(Custom math fn)"); - Ref indi_math_2 = new Indi_Math(math_custom_params); - indi_math_2.Ptr().SetDataSource(indi_bands.Ptr(), 0); + Ref indi_math_2 = new Indi_Math(math_custom_params, IDATA_INDICATOR, indi_bands.Ptr()); indis.Push(indi_math_2.Ptr()); // RS (Math-based) indicator. @@ -528,12 +541,12 @@ 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); } // Push white-listed indicators here. - whitelisted_indis.Push(_indi_test); + // whitelisted_indis.Push(_indi_test); return GetLastError() == ERR_NO_ERROR; } @@ -544,12 +557,12 @@ 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; } - IndicatorBase* _indi = iter.Value().Ptr(); + IndicatorData* _indi = iter.Value().Ptr(); if (_indi.GetModeCount() == 0) { // Indicator has no modes. diff --git a/tests/SerializerTest.mq5 b/tests/SerializerTest.mq5 index 5f10e70e5..fb619c193 100644 --- a/tests/SerializerTest.mq5 +++ b/tests/SerializerTest.mq5 @@ -246,7 +246,7 @@ int OnInit() { SerializerConverter::FromObject(configs1).ToFile("configs.json"); - SerializerConverter stub3(Serializer::MakeStubObject>(0, 1, configs1[0].Size())); + SerializerConverter stub3(SerializerConverter::MakeStubObject>(0, 1, configs1[0].Size())); SerializerConverter::FromObject(configs1).ToFile("configs.csv", SERIALIZER_CSV_INCLUDE_TITLES, &stub3); string configs1_json = SerializerConverter::FromObject(configs1).ToString(); @@ -284,7 +284,7 @@ int OnInit() { string configs2_imported = SerializerConverter::FromObject(configs2).ToString(); Print("configs2 imported: ", configs2_imported); - SerializerConverter stub4(Serializer::MakeStubObject>(0, 1, 6)); + SerializerConverter stub4(SerializerConverter::MakeStubObject>(0, 1, 6)); SerializerConverter::FromObject(entries_map) .ToFile("configs_key.csv", SERIALIZER_CSV_INCLUDE_TITLES_TREE | SERIALIZER_CSV_INCLUDE_KEY, &stub4);