diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..5c48782df --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,26 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu +{ + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "L-I-V.mql-tools", + "ms-vscode.cpptools", + "vscodevim.vim" + ], + } + }, + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + "ghcr.io/devcontainers-contrib/features/actionlint:1": {}, + "ghcr.io/devcontainers-contrib/features/ansible:2": {}, + "ghcr.io/guiyomh/features/vim:0": {}, + "ghcr.io/jungaretti/features/make:1": {}, + "ghcr.io/prulloac/devcontainer-features/pre-commit:1": {}, + "ghcr.io/hspaans/devcontainer-features/ansible-lint:1": {} + }, + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/base:jammy", + "name": "EA31337" +} diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index ee997c3c7..f6efc2b35 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -1,6 +1,11 @@ --- name: Compile +env: + ARTIFACT_PREFIX: ${{ inputs.artifact_prefix || 'mt' }} + COMPILE_PATH: ${{ inputs.path || '*' }} + SKIP_INIT: ${{ inputs.skip_init || false }} + # yamllint disable-line rule:truthy on: pull_request: @@ -9,18 +14,85 @@ on: push: paths-ignore: - '**.md' + workflow_call: + inputs: + artifact_prefix: + default: mt + description: Artifact prefix. + required: false + type: string + path: + default: '*' + description: Path to compile. + required: false + type: string + skip_cleanup: + default: false + description: Skips a clean-up job. + required: false + type: boolean + skip_init: + default: true + description: Skips initialization of the platform. + required: false + type: boolean jobs: - Compile: + mt4: + name: Installs platform (4) + uses: EA31337/EA-Tester/.github/workflows/platform-linux.yml@dev + with: + artifact_name: ${{ inputs.artifact_prefix || 'mt' }}4 + artifact_overwrite: true + skip_cleanup: true + version: 4 + mt5: + name: Installs platform (5) + uses: EA31337/EA-Tester/.github/workflows/platform-linux.yml@dev + with: + artifact_name: ${{ inputs.artifact_prefix || 'mt' }}5 + artifact_overwrite: true + skip_cleanup: true + version: 5 + + compile: + name: Compile + needs: [mt4, mt5] runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: mt${{ matrix.version }} + path: .mt${{ matrix.version }} - name: Compile uses: fx31337/mql-compile-action@master with: - init-platform: true + init-platform: ${{ env.SKIP_INIT == 'false' }} + mt-path: .mt${{ matrix.version }} + path-ignore: .mt${{ matrix.version }} + path: '${{ env.COMPILE_PATH }}/**/*.mq${{ matrix.version }}' verbose: true - name: Print compiled files run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname' shell: powershell + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: files-ex${{ matrix.version }} + path: '**/*.ex[45]' + + strategy: + matrix: + version: [4, 5] + + cleanup: + if: inputs.skip_cleanup != true + name: Clean-up + needs: [compile] + runs-on: ubuntu-latest + steps: + - uses: geekyeggo/delete-artifact@v5 + with: + name: ${{ env.ARTIFACT_PREFIX }}* diff --git a/.github/workflows/test-account.yml b/.github/workflows/test-account.yml index 3ac99f1f5..c2a6cccbe 100644 --- a/.github/workflows/test-account.yml +++ b/.github/workflows/test-account.yml @@ -14,36 +14,21 @@ on: jobs: - Compile: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - name: Compile - uses: fx31337/mql-compile-action@master - with: - init-platform: true - path: 'Account/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' + compile: + name: Compile + uses: ./.github/workflows/compile.yml + with: + artifact_prefix: mt + path: Account + skip_cleanup: true Account-Tests-MQL4: defaults: run: shell: bash working-directory: Account/tests - needs: Compile + if: false + needs: compile runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/test-buffer.yml b/.github/workflows/test-buffer.yml new file mode 100644 index 000000000..140293213 --- /dev/null +++ b/.github/workflows/test-buffer.yml @@ -0,0 +1,46 @@ +--- +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: + name: Compile + uses: ./.github/workflows/compile.yml + with: + artifact_prefix: mt + path: Buffer + skip_cleanup: true + + Buffer-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Buffer/tests + if: false + 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-indicator.yml b/.github/workflows/test-indicator.yml new file mode 100644 index 000000000..4a89f6a28 --- /dev/null +++ b/.github/workflows/test-indicator.yml @@ -0,0 +1,52 @@ +--- +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: + name: Compile + uses: ./.github/workflows/compile.yml + with: + artifact_prefix: mt + path: Indicator + skip_cleanup: true + + Indicator-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Indicator/tests + if: false + 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-indicators-special.yml b/.github/workflows/test-indicators-special.yml index 6e3cfc6e0..4198d8d66 100644 --- a/.github/workflows/test-indicators-special.yml +++ b/.github/workflows/test-indicators-special.yml @@ -16,36 +16,21 @@ on: jobs: - Compile: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - name: Compile - uses: fx31337/mql-compile-action@master - with: - init-platform: true - path: 'Indicators/Special/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' + compile: + name: Compile + uses: ./.github/workflows/compile.yml + with: + artifact_prefix: mt + path: Indicators/Special + skip_cleanup: true Indicators-Tests-MQL4: defaults: run: shell: bash working-directory: Indicators/tests - needs: Compile + if: false + needs: compile runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/test-indicators-tick.yml b/.github/workflows/test-indicators-tick.yml index 25eabe43c..de3ca8db4 100644 --- a/.github/workflows/test-indicators-tick.yml +++ b/.github/workflows/test-indicators-tick.yml @@ -16,36 +16,21 @@ on: jobs: - Compile: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - name: Compile - uses: fx31337/mql-compile-action@master - with: - init-platform: true - path: 'Indicators/Tick/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' + compile: + name: Compile + uses: ./.github/workflows/compile.yml + with: + artifact_prefix: mt + path: Indicators/Tick + skip_cleanup: true Indicators-Tests-MQL4: defaults: run: shell: bash working-directory: Indicators/tests - needs: Compile + if: false + needs: compile runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/test-indicators.yml b/.github/workflows/test-indicators.yml index 081413a3d..0e10579d0 100644 --- a/.github/workflows/test-indicators.yml +++ b/.github/workflows/test-indicators.yml @@ -16,36 +16,21 @@ on: jobs: - Compile: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - name: Compile - uses: fx31337/mql-compile-action@master - with: - init-platform: true - path: 'Indicators/tests' - verbose: true - - name: Print compiled files - run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname' - shell: powershell - - name: Upload artifacts (MQL4) - uses: actions/upload-artifact@v2 - with: - name: files-ex4 - path: '**/*.ex4' - - name: Upload artifacts (MQL5) - uses: actions/upload-artifact@v2 - with: - name: files-ex5 - path: '**/*.ex5' + compile: + name: Compile + uses: ./.github/workflows/compile.yml + with: + artifact_prefix: mt + path: Indicators + skip_cleanup: true Indicators-Tests-MQL4: defaults: run: shell: bash working-directory: Indicators/tests - needs: Compile + if: false + needs: compile runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/test-tick.yml b/.github/workflows/test-tick.yml index 941fe371a..5e5770b60 100644 --- a/.github/workflows/test-tick.yml +++ b/.github/workflows/test-tick.yml @@ -14,35 +14,21 @@ on: jobs: - Compile: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - name: Compile - uses: fx31337/mql-compile-action@master - with: - path: 'Tick/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' + compile: + name: Compile + uses: ./.github/workflows/compile.yml + with: + artifact_prefix: mt + path: Tick + skip_cleanup: true Tick-Tests-MQL4: defaults: run: shell: bash working-directory: Tick/tests - needs: Compile + if: false + needs: compile runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/test-trade.yml b/.github/workflows/test-trade.yml index 4ab779efd..b5c83391a 100644 --- a/.github/workflows/test-trade.yml +++ b/.github/workflows/test-trade.yml @@ -14,36 +14,21 @@ on: jobs: - Compile: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - name: Compile - uses: fx31337/mql-compile-action@master - with: - init-platform: true - path: 'Trade/tests' - verbose: true - - name: Print compiled files - run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname' - shell: powershell - - name: Upload artifacts (MQL4) - uses: actions/upload-artifact@v2 - with: - name: files-ex4 - path: '**/*.ex4' - - name: Upload artifacts (MQL5) - uses: actions/upload-artifact@v2 - with: - name: files-ex5 - path: '**/*.ex5' + compile: + name: Compile + uses: ./.github/workflows/compile.yml + with: + artifact_prefix: mt + path: Trade + skip_cleanup: true Trade-Tests-MQL4: defaults: run: shell: bash working-directory: Trade/tests - needs: Compile + if: false + needs: compile runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ca02328a3..1094421a8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,35 +20,21 @@ on: jobs: - Compile: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - name: Compile - uses: fx31337/mql-compile-action@master - with: - mt-version: 4.0.0.1349 - 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' + compile: + name: Compile + uses: ./.github/workflows/compile.yml + with: + artifact_prefix: mt + skip_cleanup: true + skip_init: false Experts-MQL4: defaults: run: shell: bash working-directory: tests - needs: Compile + if: false + needs: compile runs-on: ubuntu-latest strategy: matrix: @@ -89,7 +75,7 @@ jobs: BtDays: 1-8 BtMonths: 1 BtYears: 2020 - MtVersion: 4.0.0.1349 + Version: 4 TestExpert: ${{ matrix.test }} timeout-minutes: 10 @@ -98,7 +84,8 @@ jobs: run: shell: bash working-directory: tests - needs: Compile + if: false + needs: compile runs-on: ubuntu-latest strategy: matrix: @@ -134,7 +121,8 @@ jobs: run: shell: bash working-directory: tests - needs: Compile + if: false + needs: compile runs-on: ubuntu-latest strategy: matrix: @@ -159,7 +147,8 @@ jobs: run: shell: bash working-directory: Trade/tests - needs: Compile + if: false + needs: compile runs-on: ubuntu-latest strategy: matrix: diff --git a/3D/Cube.h b/3D/Cube.h index 0bc9038ff..5ed20a8b9 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -77,8 +77,8 @@ class Cube : public Mesh { * Initializes graphics device-related things. */ virtual void Initialize(Device* _device) { - SetShaderVS(_device.VertexShader(ShaderCubeSourceVS, T::Layout)); - SetShaderPS(_device.PixelShader(ShaderCubeSourcePS)); + SetShaderVS(_device.CreateVertexShader(ShaderCubeSourceVS, T::Layout)); + SetShaderPS(_device.CreatePixelShader(ShaderCubeSourcePS)); } #endif }; diff --git a/3D/Device.h b/3D/Device.h index d7b64f94f..5124a22ac 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -138,20 +138,25 @@ class Device : public Dynamic { /** * Creates vertex shader to be used by current graphics device. */ - virtual Shader* VertexShader(string _source_code, const ShaderVertexLayout& _layout[], - string _entry_point = "main") = NULL; + virtual Shader* CreateVertexShader(string _source_code, const ShaderVertexLayout& _layout[], + string _entry_point = "main") = NULL; /** * Creates pixel shader to be used by current graphics device. */ - virtual Shader* PixelShader(string _source_code, string _entry_point = "main") = NULL; + virtual Shader* CreatePixelShader(string _source_code, string _entry_point = "main") = 0; + + /** + * Creates vertex buffer to be used by current graphics device. + */ + virtual VertexBuffer* CreateVertexBuffer() = 0; /** * Creates vertex buffer to be used by current graphics device. */ template - VertexBuffer* VertexBuffer(T& data[]) { - VertexBuffer* _buff = VertexBuffer(); + VertexBuffer* CreateVertexBuffer(T& data[]) { + VertexBuffer* _buff = CreateVertexBuffer(); // Unfortunately we can't make this method virtual. if (dynamic_cast(_buff) != NULL) { // MT5's DirectX. @@ -165,15 +170,10 @@ class Device : public Dynamic { return _buff; } - /** - * Creates vertex buffer to be used by current graphics device. - */ - virtual VertexBuffer* VertexBuffer() = NULL; - /** * Creates index buffer to be used by current graphics device. */ - virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) = NULL; + virtual IndexBuffer* CreateIndexBuffer(unsigned int& _indices[]) = 0; /** * Renders vertex buffer with optional point indices. @@ -183,7 +183,7 @@ class Device : public Dynamic { /** * Renders vertex buffer with optional point indices. */ - virtual void RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; + virtual void RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = 0; /** * Renders given mesh. @@ -233,6 +233,11 @@ class Device : public Dynamic { int Height() { return frontend.Ptr().Height(); } void SetCameraOrtho3D(float _pos_x = 0.0f, float _pos_y = 0.0f, float _pos_z = 0.0f) { + if (Width() <= 0 || Height() <= 0) { + Print("Cannot set 2D camera as width or height of the viewport is zero!"); + DebugBreak(); + return; + } DXMatrixOrthoLH(mtx_projection, 1.0f * _pos_z, 1.0f / Width() * Height() * _pos_z, -10000, 10000); } diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 7bb1c93b8..166a924ed 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -93,15 +93,11 @@ class MTDXDevice : public Device { } } - /** - * Creates index buffer to be used by current graphics device. - */ - IndexBuffer* IndexBuffer() { return NULL; } - /** * Creates vertex shader to be used by current graphics device. */ - virtual Shader* VertexShader(string _source_code, const ShaderVertexLayout& _layout[], string _entry_point = "main") { + Shader* CreateVertexShader(string _source_code, const ShaderVertexLayout& _layout[], + string _entry_point = "main") override { MTDXShader* _shader = new MTDXShader(&this); _shader.Create(SHADER_TYPE_VS, _source_code, _entry_point); _shader.SetDataLayout(_layout); @@ -111,7 +107,7 @@ class MTDXDevice : public Device { /** * Creates pixel shader to be used by current graphics device. */ - virtual Shader* PixelShader(string _source_code, string _entry_point = "main") { + Shader* CreatePixelShader(string _source_code, string _entry_point = "main") override { MTDXShader* _shader = new MTDXShader(&this); _shader.Create(SHADER_TYPE_PS, _source_code, _entry_point); return _shader; @@ -120,12 +116,12 @@ class MTDXDevice : public Device { /** * Creates vertex buffer to be used by current graphics device. */ - VertexBuffer* VertexBuffer() { return new MTDXVertexBuffer(&this); } + VertexBuffer* CreateVertexBuffer() override { return new MTDXVertexBuffer(&this); } /** * Creates index buffer to be used by current graphics device. */ - virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) { + IndexBuffer* CreateIndexBuffer(unsigned int& _indices[]) override { IndexBuffer* _buffer = new MTDXIndexBuffer(&this); _buffer.Fill(_indices); return _buffer; diff --git a/3D/Mesh.h b/3D/Mesh.h index 0ee82c0dc..c6eaf1f78 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -249,8 +249,8 @@ class Mesh : public Dynamic { Print("Indices: ", _s_indices); #endif - vbuff = _vbuff = _device.VertexBuffer(_vertices); - ibuff = _ibuff = _device.IndexBuffer(_indices); + vbuff = _vbuff = _device.CreateVertexBuffer(_vertices); + ibuff = _ibuff = _device.CreateIndexBuffer(_indices); return true; } }; diff --git a/Account.mqh b/Account.mqh index ec5bac686..49578410f 100644 --- a/Account.mqh +++ b/Account.mqh @@ -427,7 +427,10 @@ class Account { /** * Get current account drawdown in percent. */ - static double GetDrawdownInPct() { return (100 / AccountTotalBalance()) * (AccountTotalBalance() - AccountEquity()); } + static double GetDrawdownInPct() { + double _balance_total = AccountTotalBalance(); + return _balance_total != 0 ? (100 / AccountTotalBalance()) * (AccountTotalBalance() - AccountEquity()) : 0.0; + } /** * Get current account risk margin level. 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.mqh b/Array.mqh index 8ab6c020c..e07e0d0a2 100644 --- a/Array.mqh +++ b/Array.mqh @@ -753,12 +753,12 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) { } template - static void ArrayStore(ARRAY_REF(X, array), int index, X value, int reserve_size = 0) { - if (index >= ArraySize(array)) { - ArrayResize(array, MathMax(index + 1, ArraySize(array)), reserve_size); + static void ArrayStore(ARRAY_REF(X, array), int _idx, X value, int reserve_size = 0) { + if (_idx >= ArraySize(array)) { + ArrayResize(array, MathMax(_idx + 1, ArraySize(array)), reserve_size); } - array[index] = value; + array[_idx] = value; } }; 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..f8786e046 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) { @@ -378,23 +378,23 @@ class Chart : public Market { * * In case of error, check it via GetLastError(). */ - double GetPeakPrice(int bars, int mode, int index, ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT) { + double GetPeakPrice(int bars, int mode, int _idx, ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT) { int ibar = -1; // @todo: Add symbol parameter. double peak_price = GetOpen(0); switch (mode) { case MODE_HIGH: - ibar = ChartStatic::iHighest(symbol, timeframe, MODE_HIGH, bars, index); + ibar = ChartStatic::iHighest(symbol, timeframe, MODE_HIGH, bars, _idx); return ibar >= 0 ? GetHigh(timeframe, ibar) : false; case MODE_LOW: - ibar = ChartStatic::iLowest(symbol, timeframe, MODE_LOW, bars, index); + ibar = ChartStatic::iLowest(symbol, timeframe, MODE_LOW, bars, _idx); return ibar >= 0 ? GetLow(timeframe, ibar) : false; default: return false; } } - double GetPeakPrice(int bars, int mode = MODE_HIGH, int index = 0) { - return GetPeakPrice(bars, mode, index, Get(CHART_PARAM_TF)); + double GetPeakPrice(int bars, int mode = MODE_HIGH, int _idx = 0) { + return GetPeakPrice(bars, mode, _idx, Get(CHART_PARAM_TF)); } /** diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 49c7c88f3..70231bf47 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -32,6 +32,7 @@ // Includes. #include "Chart.enum.h" +#include "Serializer.mqh" /* Defines struct for chart timeframe. */ struct ChartTf { @@ -185,9 +186,9 @@ struct ChartTf { * @param * _tf ENUM_TIMEFRAMES_INDEX Specify timeframe index enum. */ - static ENUM_TIMEFRAMES const IndexToTf(ENUM_TIMEFRAMES_INDEX index) { + static ENUM_TIMEFRAMES const IndexToTf(ENUM_TIMEFRAMES_INDEX _idx) { // @todo: Convert it into a loop and using tf constant, see: TfToIndex(). - switch (index) { + switch (_idx) { case M1: return PERIOD_M1; // 1 minute. case M2: @@ -346,8 +347,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/Condition.mqh b/Condition.mqh index 915cbcd4e..862d20264 100644 --- a/Condition.mqh +++ b/Condition.mqh @@ -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.mqh b/Convert.mqh index 7d5f320c1..22352cfa2 100644 --- a/Convert.mqh +++ b/Convert.mqh @@ -298,8 +298,8 @@ class Convert { int i, j; len = StringLen(in); if (len % 4 != 0) len = len - len % 4; - int size = ArraySize(output); - if (size < len / 4) { + int _size = ArraySize(output); + if (_size < len / 4) { ArrayResize(output, len / 4); } for (i = 0, j = 0; j < len; i++, j += 4) { diff --git a/DictBase.mqh b/DictBase.mqh index daeaaae7a..6e80dd8ed 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -115,13 +115,13 @@ class DictBase { */ bool HasFlags(int flags) { return (_flags & flags) == flags; } - DictSlot* GetSlot(const unsigned int index) { - if (index >= GetSlotCount()) { + DictSlot* GetSlot(const unsigned int _idx) { + if (_idx >= GetSlotCount()) { // Index of out bounds. return NULL; } - return &_DictSlots_ref.DictSlots[index]; + return &_DictSlots_ref.DictSlots[_idx]; } /** diff --git a/Draw.mqh b/Draw.mqh index 350f89bf6..c915517eb 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -46,6 +46,9 @@ class Draw; bool ObjectCreate(string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { return Draw::ObjectCreate(0, _name, _otype, _swindow, _t1, _p1); } +bool ObjectCreate(string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, datetime _t2, double _p2) { + return Draw::ObjectCreate(0, _name, _otype, _swindow, _t1, _p1, _t2, _p2); +} bool ObjectDelete(string _name) { return Draw::ObjectDelete(_name); } bool ObjectSet(string _name, int _prop_id, double _value) { return Draw::ObjectSet(_name, _prop_id, _value); } int ObjectsTotal(int _type = EMPTY) { return Draw::ObjectsTotal(); } @@ -126,14 +129,14 @@ class Draw : public Chart { * @return * If successful, returns true, otherwise false. */ - static bool SetIndexLabel(int index, string text) { + static bool SetIndexLabel(int _idx, string text) { #ifdef __MQL4__ // https://docs.mql4.com/customind/setindexlabel - ::SetIndexLabel(index, text); + ::SetIndexLabel(_idx, text); return true; #else // https://www.mql5.com/en/docs/customind/plotindexsetstring - return PlotIndexSetString(index, PLOT_LABEL, text); + return PlotIndexSetString(_idx, PLOT_LABEL, text); #endif } @@ -141,19 +144,19 @@ class Draw : public Chart { * Sets the new type, style, width and color for a given indicator line. * */ - static void SetIndexStyle(int index, int type, int style = EMPTY, int width = EMPTY, color clr = CLR_NONE) { + static void SetIndexStyle(int _idx, int type, int style = EMPTY, int width = EMPTY, color clr = CLR_NONE) { #ifdef __MQL4__ // https://docs.mql4.com/customind/setindexstyle - ::SetIndexStyle(index, type, style, width, clr); + ::SetIndexStyle(_idx, type, style, width, clr); #else if (width != EMPTY) { - PlotIndexSetInteger(index, PLOT_LINE_WIDTH, width); + PlotIndexSetInteger(_idx, PLOT_LINE_WIDTH, width); } if (clr != CLR_NONE) { - PlotIndexSetInteger(index, PLOT_LINE_COLOR, clr); + PlotIndexSetInteger(_idx, PLOT_LINE_COLOR, clr); } - PlotIndexSetInteger(index, PLOT_DRAW_TYPE, type); - PlotIndexSetInteger(index, PLOT_LINE_STYLE, style); + PlotIndexSetInteger(_idx, PLOT_DRAW_TYPE, type); + PlotIndexSetInteger(_idx, PLOT_LINE_STYLE, style); #endif } @@ -299,9 +302,9 @@ class Draw : public Chart { /** * Draw a line given the price. */ - void ShowLine(string oname, double price, int colour = Yellow) { + void ShowLine(string oname, double price, int _colour = Yellow) { Draw::ObjectCreate(chart_id, oname, OBJ_HLINE, 0, GetBarTime(), price); - Draw::ObjectSet(oname, OBJPROP_COLOR, colour); + Draw::ObjectSet(oname, OBJPROP_COLOR, _colour); Draw::ObjectMove(oname, 0, GetBarTime(), price); } 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..63368f947 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); @@ -765,8 +765,21 @@ class EA { * Loads existing trades for the given strategy. */ bool StrategyLoadTrades(Strategy *_strat) { + bool _result = true; Trade *_trade = trade.GetByKey(_Symbol); - return _trade.OrdersLoadByMagic(_strat.Get(STRAT_PARAM_ID)); + // Load active trades. + _result &= _trade.OrdersLoadByMagic(_strat.Get(STRAT_PARAM_ID)); + // Load strategy-specific order parameters (e.g. conditions). + // This is a temporary workaround for GH-705. + // @todo: To move to Strategy class. + Ref _order; + for (DictStructIterator> iter = _trade.GetOrdersActive().Begin(); iter.IsValid(); ++iter) { + _order = iter.Value(); + if (_order.IsSet() && _order.Ptr().IsOpen()) { + _strat.OnOrderLoad(_order.Ptr()); + } + } + return _result; } /* Trade methods */ diff --git a/Indicator.define.h b/Indicator.define.h index d5056e91f..dc2d23d8a 100644 --- a/Indicator.define.h +++ b/Indicator.define.h @@ -25,6 +25,9 @@ * Includes Indicator's defines. */ +// Includes. +#include "Terminal.define.h" + #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once @@ -32,6 +35,7 @@ // Defines macros. #define COMMA , +#define SEMICOLON ; #define DUMMY #define ICUSTOM_DEF(SET_HANDLE, PARAMS) \ @@ -44,7 +48,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) { \ @@ -115,7 +119,7 @@ class DrawIndicator; _obj.SetHandle(_handle); \ } \ } \ - if (Terminal::IsVisualMode()) { \ + if (false && Terminal::IsVisualMode()) { \ /* To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), */ \ /* we check the number of calculated data only in visual mode. */ \ int _bars_calc = BarsCalculated(_handle); \ @@ -127,6 +131,7 @@ class DrawIndicator; } \ } \ if (CopyBuffer(_handle, MODE, SHIFT, 1, _res) < 0) { \ + Print(#NATIVE_METHOD_CALL, " = ", _res[0], ", LE = ", _LastError); \ return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; \ } \ return _res[0]; diff --git a/Indicator.enum.h b/Indicator.enum.h index 375064b34..8bf58e7b1 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -40,95 +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. */ +/* Defines type of source data for */ enum ENUM_IDATA_SOURCE_TYPE { IDATA_BUILTIN = 0, // Platform built-in IDATA_CHART, // Chart calculation @@ -150,7 +154,7 @@ enum ENUM_IDATA_VALUE_RANGE { 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 +176,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 +189,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 +231,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..58f6d3744 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -50,21 +50,45 @@ 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); +} +#endif + /** * Class to deal with indicators. */ template class Indicator : public IndicatorBase { protected: - // Structs. + DrawIndicator* draw; + BufferStruct idata; TS iparams; protected: /* Protected methods */ - /** - * It's called on class initialization. - */ bool Init() { ArrayResize(value_storages, iparams.GetMaxModes()); switch (iparams.GetDataSourceType()) { @@ -73,7 +97,7 @@ class Indicator : public IndicatorBase { case IDATA_ICUSTOM: break; case IDATA_INDICATOR: - if (!indi_src.IsSet()) { + if (indi_src.IsSet() == NULL) { // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); // SetDataSource(_indi_price, true, PRICE_OPEN); } @@ -82,6 +106,26 @@ class Indicator : public IndicatorBase { return InitDraw(); } + /** + * Initialize indicator data drawing on custom data. + */ + bool InitDraw() { + if (iparams.is_draw && !Object::IsValid(draw)) { + draw = new DrawIndicator(THIS_PTR); + draw.SetColorLine(iparams.indi_color); + } + return iparams.is_draw; + } + + /** + * Deinitialize drawing. + */ + void DeinitDraw() { + if (draw) { + delete draw; + } + } + public: /* Indicator enumerations */ @@ -103,22 +147,20 @@ class Indicator : public IndicatorBase { Indicator(const TS& _iparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) : IndicatorBase(_iparams.GetTf(), NULL) { iparams = _iparams; - SetName(_iparams.name != "" ? _iparams.name : EnumToString(iparams.itype)); if (_indi_src != NULL) { SetDataSource(_indi_src, _indi_mode); + iparams.SetDataSourceType(IDATA_INDICATOR); } Init(); } Indicator(const TS& _iparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorBase(_tf) { iparams = _iparams; - SetName(_iparams.name != "" ? _iparams.name : EnumToString(iparams.itype)); Init(); } Indicator(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "") : IndicatorBase(_tf) { iparams.SetIndicatorType(_itype); iparams.SetShift(_shift); - SetName(_name != "" ? _name : EnumToString(iparams.itype)); Init(); } @@ -127,41 +169,19 @@ class Indicator : public IndicatorBase { */ ~Indicator() { DeinitDraw(); } - /** - * Initialize indicator data drawing on custom data. - */ - bool InitDraw() { - if (iparams.is_draw && !Object::IsValid(draw)) { - draw = new DrawIndicator(THIS_PTR); - draw.SetColorLine(iparams.indi_color); - } - return iparams.is_draw; - } - - /* Deinit methods */ - - /** - * Deinitialize drawing. - */ - void DeinitDraw() { - if (draw) { - delete draw; - } - } - /* Getters */ /** * Gets an indicator property flag. */ - bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, int _shift = -1) { + bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, int _shift = 0) { IndicatorDataEntry _entry = GetEntry(_shift >= 0 ? _shift : iparams.GetShift()); return _entry.CheckFlag(_prop); } /* Buffer methods */ - virtual string CacheKey() { return GetName(); } + virtual string CacheKey() { return GetFullName(); } /** * Initializes a cached proxy between i*OnArray() methods and OnCalculate() @@ -392,17 +412,134 @@ class Indicator : public IndicatorBase { */ virtual IndicatorBase* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; } - /* Operator overloading methods */ + /* 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; + } /** - * Access indicator entry data using [] operator. + * 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. */ - IndicatorDataEntry operator[](int _shift) { return GetEntry(_shift); } - IndicatorDataEntry operator[](ENUM_INDICATOR_INDEX _shift) { return GetEntry(_shift); } - IndicatorDataEntry operator[](datetime _dt) { return idata[_dt]; } + 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 */ + /** + * Get pointer to data of indicator. + */ + BufferStruct* GetData() { return GetPointer(idata); } + /** * Returns the highest bar's index (shift). */ @@ -528,6 +665,34 @@ class Indicator : public IndicatorBase { return median; } + /** + * 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 currently selected data source doing validation. */ @@ -553,6 +718,17 @@ class Indicator : public IndicatorBase { _result = _source.Ptr(); } } + } else if (iparams.GetDataSourceType() == IDATA_INDICATOR) { + // User sets data source's mode to On-Indicator, but not set data source via SetDataSource()! + + // Requesting potential data source. + IndicatorBase* _ds = OnDataSourceRequest(); + + if (_ds != NULL) { + // Initializing with new data source. + SetDataSource(_ds); + iparams.SetDataSourceType(IDATA_INDICATOR); + } } ValidateDataSource(&this, _result); @@ -568,7 +744,17 @@ 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 (iparams.GetDataSourceId() != -1) { + return true; + } + + if (iparams.GetDataSourceType() == IDATA_INDICATOR && GetDataSourceRaw() == NULL && _try_initialize) { + SetDataSource(OnDataSourceRequest()); + } + + return GetDataSourceRaw() != NULL; + } /** * Gets indicator's params. @@ -603,22 +789,11 @@ class Indicator : public IndicatorBase { 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) : ""); } /** @@ -654,14 +829,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 +966,46 @@ 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) { + // 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); } - - 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(IndicatorBase* _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); + iparams.SetDataSource(-1, _input_mode); + indi_src.Ptr().OnBecomeDataSourceFor(THIS_PTR); } } @@ -915,6 +1063,19 @@ class Indicator : public IndicatorBase { return _result; } + /** + * Get full name of the indicator (with "over ..." part). + */ + string GetFullName() override { + return GetName() + "[" + IntegerToString(iparams.GetMaxModes()) + "]" + + (HasDataSource() ? (" (over " + GetDataSource().GetFullName() + ")") : ""); + } + + /** + * Get indicator type. + */ + ENUM_INDICATOR_TYPE GetType() override { return iparams.itype; } + /** * Update indicator. */ @@ -931,9 +1092,9 @@ 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)) { @@ -998,9 +1159,21 @@ 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) { + virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _timestamp = -1) { _entry.AddFlags(_entry.GetDataTypeFlags(iparams.GetDataValueType())); }; + /** + * 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.cache.h b/Indicator.struct.cache.h index 2c4df7097..9264f8e6e 100644 --- a/Indicator.struct.cache.h +++ b/Indicator.struct.cache.h @@ -123,16 +123,16 @@ class IndicatorCalculateCache : public Dynamic { * Returns existing or new cache as a child of current one. Useful when indicator uses other indicators and requires * unique caches for them. */ - IndicatorCalculateCache *GetSubCache(int index) { - if (index >= ArraySize(subcaches)) { - ArrayResize(subcaches, index + 1, 10); + IndicatorCalculateCache *GetSubCache(int _idx) { + if (_idx >= ArraySize(subcaches)) { + ArrayResize(subcaches, _idx + 1, 10); } - if (subcaches[index] == NULL) { - subcaches[index] = new IndicatorCalculateCache(); + if (subcaches[_idx] == NULL) { + subcaches[_idx] = new IndicatorCalculateCache(); } - return subcaches[index]; + return subcaches[_idx]; } /** diff --git a/Indicator.struct.h b/Indicator.struct.h index 99bc74b84..d9ecc205a 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -437,7 +437,7 @@ struct IndicatorParams { idstype(_idstype), idvrange(IDATA_RANGE_UNKNOWN), indi_data_source_id(-1), - indi_data_source_mode(0), + indi_data_source_mode(-1), itype(_itype), is_draw(false), indi_color(clrNONE), @@ -454,7 +454,7 @@ struct IndicatorParams { idstype(_idstype), idvrange(IDATA_RANGE_UNKNOWN), indi_data_source_id(-1), - indi_data_source_mode(0), + indi_data_source_mode(-1), is_draw(false), indi_color(clrNONE), draw_window(0) { diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h new file mode 100644 index 000000000..c0ff4637a --- /dev/null +++ b/Indicator/IndicatorCandle.h @@ -0,0 +1,266 @@ +//+------------------------------------------------------------------+ +//| 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 "../Indicator.mqh" +#include "../Candle.struct.h" + +// 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); + iparams.SetMaxModes(4); + } + + public: + /* Special methods */ + + /** + * Class constructor. + */ + IndicatorCandle(const TS& _icparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + : Indicator(_icparams, _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..84fe4b7c0 --- /dev/null +++ b/Indicator/IndicatorTf.h @@ -0,0 +1,85 @@ +//+------------------------------------------------------------------+ +//| 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 &_params) : IndicatorCandle(_params) { 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..e654dde70 --- /dev/null +++ b/Indicator/IndicatorTick.h @@ -0,0 +1,290 @@ +//+------------------------------------------------------------------+ +//| 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. + itparams.SetMaxModes(2); + } + + public: + /* Special methods */ + + /** + * Class constructor. + */ + IndicatorTick(const TS& _itparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + : Indicator(_itparams, _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); + } + + // No tick at given timestamp. Returning invalid entry. + IndicatorDataEntry _entry(itparams.GetMaxModes()); + GetEntryAlter(_entry, _timestamp); + + for (int i = 0; i < itparams.GetMaxModes(); ++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) { + _entry.AddFlags(_entry.GetDataTypeFlags(itparams.GetDataValueType())); + }; + + /** + * 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; + itparams.SetDataSource(-1, _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..45fce1acd --- /dev/null +++ b/Indicator/IndicatorTickOrCandleSource.h @@ -0,0 +1,99 @@ +//+------------------------------------------------------------------+ +//| 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, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + : Indicator(_iparams, _indi_src, _indi_mode) {} + IndicatorTickOrCandleSource(const TS& _iparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(_iparams, _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(IndicatorBase* _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. + */ + IndicatorBase* DataSourceRequestReturnDefault(int _applied_price) override { + // Returning real candle indicator. Thus way we can use SetAppliedPrice() and select Ask or Bid price. + IndicatorBase* _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..6e1734f4c --- /dev/null +++ b/Indicator/IndicatorTickSource.h @@ -0,0 +1,119 @@ +//+------------------------------------------------------------------+ +//| 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, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) + : Indicator(_iparams, _indi_src, _indi_mode) {} + IndicatorTickSource(const TS& _iparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : Indicator(_iparams, _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(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 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(IndicatorBase* _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..c9cb9d86f --- /dev/null +++ b/Indicator/tests/IndicatorTf.test.mq5 @@ -0,0 +1,112 @@ +//+------------------------------------------------------------------+ +//| 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. + * + * 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..683025176 --- /dev/null +++ b/Indicator/tests/classes/IndicatorTickDummy.h @@ -0,0 +1,71 @@ +//+------------------------------------------------------------------+ +//| 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, 2, TYPE_DOUBLE) {} +}; + +// 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) {} + + string GetName() override { return "IndicatorTickDummy"; } + + void OnBecomeDataSourceFor(IndicatorBase* _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..977c5cc48 --- /dev/null +++ b/Indicator/tests/classes/IndicatorTickReal.h @@ -0,0 +1,113 @@ +//+------------------------------------------------------------------+ +//| 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, 3, TYPE_DOUBLE) {} +}; + +// 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) {} + + string GetName() override { return "IndicatorTickReal"; } + + void OnBecomeDataSourceFor(IndicatorBase* _base_indi) override { + // Feeding base indicator with historic entries of this indicator. +#ifdef __debug__ + Print(GetFullName(), " became a data source for ", _base_indi.GetFullName()); +#endif + +#ifndef __MQL4__ + int _ticks_to_emit = 1000; + +#ifdef __debug_verbose__ + Print(_base_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! + _base_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..f8258b555 --- /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 "../../../IndicatorBase.h" +#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(IndicatorBase* _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..c0a4e3569 100644 --- a/IndicatorBase.h +++ b/IndicatorBase.h @@ -55,50 +55,11 @@ class Chart; #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. @@ -109,6 +70,9 @@ class IndicatorBase : public Chart { Ref indi_src; // // Indicator used as data source. int indi_src_mode; // Mode of source indicator IndicatorCalculateCache cache; + ARRAY(WeakRef, listeners); // List of indicators that listens for events from this one. + long last_tick_time; // Time of the last Tick() call. + int flags; // Flags such as INDI_FLAG_INDEXABLE_BY_SHIFT. public: /* Indicator enumerations */ @@ -128,35 +92,25 @@ class IndicatorBase : public Chart { /** * 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) { + IndicatorBase(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _symbol = NULL) : indi_src(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; } /** @@ -172,137 +126,35 @@ class IndicatorBase : public Chart { } } - /* Defines MQL backward compatible methods */ - - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(;, DUMMY); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(;, COMMA _a); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(;, COMMA _a COMMA _b); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, int _mode, - int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(;, COMMA _a COMMA _b COMMA _c); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, int _mode, - int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(;, COMMA _a COMMA _b COMMA _c COMMA _d); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, - int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(;, COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, - int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(;, COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, - G _g, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(;, COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, - G _g, H _h, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(;, COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h); -#endif - } - - template - double iCustom(int& _handle, string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, - G _g, H _h, I _i, int _mode, int _shift) { -#ifdef __MQL4__ - return ::iCustom(_symbol, _tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _mode, _shift); -#else // __MQL5__ - ICUSTOM_DEF(;, COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i); -#endif - } + /* Operator overloading methods */ - 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 + /** + * 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); } - 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 + /** + * 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); } - 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 - } + IndicatorDataEntry operator[](ENUM_INDICATOR_INDEX _index) { return GetEntry((int)_index); } /* Buffer methods */ @@ -452,17 +304,54 @@ class IndicatorBase : public Chart { */ IndicatorBase* GetDataSourceRaw() { return indi_src.Ptr(); } - /* Operator overloading methods */ + /** + * Returns given data source type. Used by i*OnIndicator methods if indicator's Calculate() uses other indicators. + */ + IndicatorBase* GetDataSource(ENUM_INDICATOR_TYPE _type) { + IndicatorBase* _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(), ", and timeframe ", GetTf(), "!"); + DebugBreak(); + } else { + indicators.Set((int)_type, _indi); + _result = _indi.Ptr(); + } + } + return _result; + } + + /** + * 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 IndicatorBase* 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; + } /** - * Access indicator entry data using [] operator. + * Creates default, tick based indicator for given applied price. */ - IndicatorDataEntry operator[](int _shift) { return GetEntry(_shift); } - IndicatorDataEntry operator[](ENUM_INDICATOR_INDEX _shift) { return GetEntry(_shift); } - IndicatorDataEntry operator[](datetime _dt) { return idata[_dt]; } + virtual IndicatorBase* DataSourceRequestReturnDefault(int _applied_price) { + DebugBreak(); + return NULL; + } /* Getters */ + /** + * Returns indicator's flags. + */ + int GetFlags() { return flags; } + /** * Returns buffers' cache. */ @@ -489,133 +378,12 @@ 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. @@ -624,36 +392,11 @@ class IndicatorBase : public Chart { int GetDataSourceMode() { return indi_src_mode; } - /** - * Gets indicator's symbol. - */ - string GetSymbol() { return Get(CHART_PARAM_SYMBOL); } - - /** - * Gets indicator's time-frame. - */ - ENUM_TIMEFRAMES GetTf() { return Get(CHART_PARAM_TF); } - - /** - * Gets indicator's signals. - * - * 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 +405,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). @@ -695,7 +438,7 @@ class IndicatorBase : public Chart { /** * Sets indicator data source. */ - virtual void SetDataSource(IndicatorBase* _indi, int _input_mode = 0) = NULL; + virtual void SetDataSource(IndicatorBase* _indi, int _input_mode = -1) = NULL; /** * Sets data source's input mode. @@ -719,90 +462,24 @@ class IndicatorBase : public Chart { */ void SetSymbol(string _symbol) { Set(CHART_PARAM_SYMBOL, _symbol); } - /* Conditions */ + /* Other methods */ /** - * Checks for indicator condition. - * - * @param ENUM_INDICATOR_CONDITION _cond - * Indicator condition. - * @param MqlParam[] _args - * Condition arguments. - * @return - * Returns true when the condition is met. + * Adds event listener. */ - 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); + void AddListener(IndicatorBase* _indi) { + WeakRef _ref = _indi; + ArrayPushObject(listeners, _ref); } /** - * 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. + * Removes event listener. */ - 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); + void RemoveListener(IndicatorBase* _indi) { + WeakRef _ref = _indi; + Util::ArrayRemoveFirst(listeners, _ref); } - /* Other methods */ - /** * Releases indicator's handle. * @@ -818,120 +495,98 @@ 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); + ValueStorage* GetValueStorage(int _mode = 0) { + if (_mode >= ArraySize(value_storages)) { + ArrayResize(value_storages, _mode + 1); + } - return true; + if (value_storages[_mode] == NULL) { + value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + } + return value_storages[_mode]; } /** - * 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; + * 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; + } + + 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; } - - 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; + 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; } - - --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). + * Checks whether indicator support given value storage type. */ - 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]; - } + virtual bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { return false; } template - T GetValue(int _shift = 0, int _mode = 0) { + T GetValue(int _mode = 0, int _index = 0) { T _out; - GetEntryValue(_shift, _mode).Get(_out); + GetEntryValue(_mode, _index).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); + bool GetValues(int _index, T& _out1, T& _out2) { + IndicatorDataEntry _entry = GetEntry(_index); _out1 = _entry.values[0]; _out2 = _entry.values[1]; bool _result = GetLastError() != 4401; @@ -940,8 +595,8 @@ class IndicatorBase : public Chart { } template - bool GetValues(int _shift, T& _out1, T& _out2, T& _out3) { - IndicatorDataEntry _entry = GetEntry(_shift); + 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]; @@ -951,8 +606,8 @@ class IndicatorBase : public Chart { } template - bool GetValues(int _shift, T& _out1, T& _out2, T& _out3, T& _out4) { - IndicatorDataEntry _entry = GetEntry(_shift); + 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]; @@ -962,6 +617,31 @@ class IndicatorBase : public Chart { return _result; } + 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(); + } + virtual void OnTick() {} /* Data representation methods */ @@ -971,7 +651,19 @@ class IndicatorBase : public Chart { /** * Returns the indicator's struct value. */ - virtual IndicatorDataEntry GetEntry(int _shift = -1) = NULL; + virtual IndicatorDataEntry GetEntry(int _index = 0) = 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; + } /** * Alters indicator's struct value. @@ -979,26 +671,65 @@ class IndicatorBase : public Chart { * 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; + 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 = -1) = NULL; + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 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() {} + + /** + * Called when data source emits new entry (historic or future one). + */ + virtual void OnDataSourceEntry(IndicatorDataEntry& entry){}; + + /** + * Called when indicator became a data source for other indicator. + */ + virtual void OnBecomeDataSourceFor(IndicatorBase* _base_indi){}; + + /** + * Called when user tries to set given data source. Could be used to check if indicator implements all required value + * storages. + */ + virtual bool OnValidateDataSource(IndicatorBase* _ds, string& _reason) { + _reason = "Indicator " + GetName() + " does not implement OnValidateDataSource()"; + return false; + } /** * 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. @@ -1021,8 +752,8 @@ class IndicatorBase : public Chart { /** * Returns the indicator's value in plain format. */ - virtual string ToString(int _shift = 0) { - IndicatorDataEntry _entry = GetEntry(_shift); + 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; @@ -1057,6 +788,150 @@ class IndicatorBase : public Chart { // Assuming all entries are calculated (even if have invalid values). return _bars; } + + /* Methods to get rid of */ + + /** + * Gets indicator's symbol. + */ + string GetSymbol() { return Get(CHART_PARAM_SYMBOL); } + + /** + * Gets indicator's time-frame. + */ + ENUM_TIMEFRAMES GetTf() { return Get(CHART_PARAM_TF); } + + /* 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 + } }; /** diff --git a/IndicatorLegacy.h b/IndicatorLegacy.h new file mode 100644 index 000000000..471e84676 --- /dev/null +++ b/IndicatorLegacy.h @@ -0,0 +1,484 @@ +/** + * @file + * Wrappers to be used by MQL4 code to allow calling MQL5's indicator functions like iMA() in MQL4. + */ + +#ifndef __MQL__ +#pragma once +#endif + +#ifdef INDICATOR_LEGACY_VERSION_MT4 +#define INDICATOR_LEGACY_VERSION_DEFINED +#endif + +#ifdef INDICATOR_LEGACY_VERSION_MT5 +#define INDICATOR_LEGACY_VERSION_DEFINED +#endif + +#ifndef INDICATOR_LEGACY_VERSION_DEFINED +#define INDICATOR_LEGACY_VERSION_MT5 +#define INDICATOR_LEGACY_VERSION_DEFINED +#endif + +#ifdef __MQL4__ + +#include +#include +#include +#include + +#ifdef INDICATOR_LEGACY_VERSION_MT5 + +/** + * Replacement for future OnCalculate(). Currently not used, but could be handy in the future. + */ +int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], + const double& high[], const double& low[], const double& close[], const long& tick_volume[], + const long& volume[], const int& spread[]) { + int _num_calculated = + OnCalculateMT5(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread); + + return _num_calculated; +} + +#define OnCalculate OnCalculateMT5 + +/** + * Wrapper class to be used by MQL4 code to allow calling MQL5's indicator functions like iMA() in MQL4. + */ +class IndicatorLegacy : public Dynamic { + // Handle to be used by BarsCalculated(), CopyBuffer() and so on. + int handle; + + // Name of the indicator. + string name; + + public: + /** + * Constructor. + */ + IndicatorLegacy(string _name) : name(_name) { handle = indis.Size(); } + + /** + * Returns indicator's handle. + */ + int GetHandle() { return handle; } + + /** + * Returns name of the indicator. + */ + string GetName() { return name; } + + /** + * Returns value for a given shift. + */ + virtual double GetValue(int _shift) = 0; + + /** + * Returns number of bars calculated for this indicator. + */ + int GetBarsCalculated() { + // @todo We probably need to replace it with some more specific check per indicator. + return Bars; + } + + // Dictionary of registered indicators (key -> indicator). + static DictStruct> indis; + + // Dictionary of registered indicators (handle -> indicator). + static DictStruct> indis_handles; + + /** + * Returns number of bars calculated for a given indicator's handle. + */ + static int GetBarsCalculated(int _handle) { + if (_handle < 0 || _handle >= (int)indis.Size()) { + Print("Error: Given handle index is out of bounds! Given handle index ", _handle, " and there is ", indis.Size(), + " handles available."); + DebugBreak(); + return 0; + } + + IndicatorLegacy* _indi = indis_handles[_handle].Ptr(); + return PTR_ATTRIB(_indi, GetBarsCalculated()); + } +}; + +DictStruct> IndicatorLegacy::indis; +DictStruct> IndicatorLegacy::indis_handles; + +/** + * MQL4 wrapper of MQL5's BarsCalculated(). + */ +int BarsCalculated(int _handle) { return IndicatorLegacy::GetBarsCalculated(_handle); } + +/** + * MQL4 wrapper of MQL5's CopyBuffer(). + */ +int CopyBuffer(int _handle, int _mode, int _start, int _count, double& _buffer[]) { + IndicatorLegacy* _indi = IndicatorLegacy::indis_handles[_handle].Ptr(); + + if (_mode != 0) { + Print("Only mode 0 is supported for ", PTR_ATTRIB(_indi, GetName()), + " legacy indicator as MQL4 supports only a single mode."); + DebugBreak(); + return 0; + } + + int _num_copied = 0; + int _buffer_size = ArraySize(_buffer); + + if (_buffer_size < _count) { + _buffer_size = ArrayResize(_buffer, _count); + } + + for (int i = 0; i < _count; ++i) { + double _value = PTR_ATTRIB(_indi, GetValue(_start + i)); + + if (_value == WRONG_VALUE) { + break; + } + + _buffer[_buffer_size - i - 1] = _value; + ++_num_copied; + } + + return _num_copied; +} + +/** + * Defines wrapper class and global iNAME() indicator function (e.g., iMA(), iATR()). + */ +// Print(#FN_NAME " key = ", _key); \ +#define DEFINE_LEGACY_INDICATOR(FN_NAME, BUILTIN_NAME, TYPED_PARAMS_COMMA, TYPED_PARAMS_NO_UDL_SEMICOLON, UNTYPED_PARAMS_COMMA_KEY, UNTYPED_PARAMS_COMMA_VALUES, ASSIGNMENTS_COMMA, UNTYPED_PARAMS_NO_UDL_COMMA_VALUES) \ +class BUILTIN_NAME##Legacy : public IndicatorLegacy { \ + TYPED_PARAMS_NO_UDL_SEMICOLON; \ +public: \ + BUILTIN_NAME##Legacy(string _name, TYPED_PARAMS_COMMA) : IndicatorLegacy(_name), ASSIGNMENTS_COMMA {} \ + virtual double GetValue(int _shift) { \ + double _value = ::BUILTIN_NAME(UNTYPED_PARAMS_NO_UDL_COMMA_VALUES, _shift); \ + if (false) Print(GetName(), "[-", _shift, "]: ", _value); \ + return _value; \ + } \ +}; \ +int FN_NAME(TYPED_PARAMS_COMMA) { \ + Ref _indi; \ + int _handle = INVALID_HANDLE; \ + string _key = Util::MakeKey(#FN_NAME, UNTYPED_PARAMS_COMMA_KEY); \ + if (IndicatorLegacy::indis.KeyExists(_key)) { \ + _indi = IndicatorLegacy::indis[_key]; \ + } \ + else { \ + _indi = new BUILTIN_NAME##Legacy(#BUILTIN_NAME, UNTYPED_PARAMS_COMMA_VALUES); \ + IndicatorLegacy::indis.Set(_key, _indi); \ + IndicatorLegacy::indis_handles.Set(PTR_ATTRIB(_indi.Ptr(), GetHandle()), _indi); \ + } \ + return PTR_ATTRIB(_indi.Ptr(), GetHandle()); \ +} + +/** + * 1-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_1(FN_NAME, INDI_NAME, T1, N1) \ + DEFINE_LEGACY_INDICATOR(INDI_NAME, T1 _##N1, T1 N1, _##N1, _##N1, N1(_##N1), N1); + +/** + * 2-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_2(FN_NAME, INDI_NAME, T1, N1, T2, N2) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2, T1 N1 SEMICOLON T2 N2, _##N1 COMMA _##N2, \ + _##N1 COMMA _##N2, N1(_##N1) COMMA N2(_##N2), N1 COMMA N2); + +/** + * 3-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_3(FN_NAME, INDI_NAME, T1, N1, T2, N2, T3, N3) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3, _##N1 COMMA _##N2 COMMA _##N3, \ + _##N1 COMMA _##N2 COMMA _##N3, N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3), \ + N1 COMMA N2 COMMA N3); + +/** + * 4-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_4(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4), N1 COMMA N2 COMMA N3 COMMA N4); + +/** + * 5-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_5(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5); + +/** + * 6-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_6(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6); + +/** + * 7-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_7(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR( \ + FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 _##N7, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 SEMICOLON T7 N7, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) COMMA N7(_##N7), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7); + +/** + * 8-parameter helper for DEFINE_LEGACY_INDICATOR. + */ +#define DEFINE_LEGACY_INDICATOR_8(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 \ + _##N7 COMMA T8 _##N8, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 \ + SEMICOLON T7 N7 SEMICOLON T8 N8, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) \ + COMMA N7(_##N7) COMMA N8(_##N8), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7 COMMA N8); + +/** + * Replacement for future StringConcatenate(). + */ +#define StringConcatenate StringConcatenateMT5 + +/** + * MQL4 wrapper of MQL5's StringConcatenate(). + */ +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j, K _k, L _l, + M _m) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k + (string)_l + (string)_m; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j, K _k, L _l) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k + (string)_l; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j, K _k) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e, F _f) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d, E _e) { + _result = (string)_a + (string)_b + (string)_c + (string)_d + (string)_e; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c, D _d) { + _result = (string)_a + (string)_b + (string)_c + (string)_d; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b, C _c) { + _result = (string)_a + (string)_b + (string)_c; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a, B _b) { + _result = (string)_a + (string)_b; + return StringLen(_result); +} +template +int StringConcatenateMT5(string& _result, A _a) { + _result = (string)_a; + return StringLen(_result); +} + +// ----- LEGACY INDICATOR DEFINITIONS + +// int iAC(string symbol, ENUM_TIMEFRAMES period); +DEFINE_LEGACY_INDICATOR_2(iAC, iAC, string, symbol, int, period); + +// int iAD(string symbol, ENUM_TIMEFRAMES period, ENUM_APPLIED_VOLUME applied_volume); +DEFINE_LEGACY_INDICATOR_2(iAD, iAD, string, symbol, int, period); + +// int iATR(string symbol, ENUM_TIMEFRAMES period, int ma_period); +DEFINE_LEGACY_INDICATOR_3(iATR, iATR, string, symbol, int, period, int, ma_period); + +// int iRSI(string symbol, ENUM_TIMEFRAMES period, int ma_period, int applied_price); +#define T1 string +#define N1 symbol +#define T2 int +#define N2 period +#define T3 int +#define N3 ma_period +#define T4 int +#define N4 applied_price +DEFINE_LEGACY_INDICATOR_4(iRSI, iRSI) +#undef T1 +#undef N1 +#undef T2 +#undef N2 +#undef T3 +#undef N3 +#undef T4 +#undef N4 +#undef T5 +#undef N5 +#undef T6 +#undef N6 + +// int iMA(string symbol, ENUM_TIMEFRAMES period, int ma_period, int ma_shift, ENUM_MA_METHOD ma_method, +#define T1 string +#define N1 symbol +#define T2 int +#define N2 period +#define T3 int +#define N3 ma_period +#define T4 int +#define N4 ma_shift +#define T5 int +#define N5 ma_method +#define T6 int +#define N6 applied_price +DEFINE_LEGACY_INDICATOR_6(iMA, iMA) +#undef T1 +#undef N1 +#undef T2 +#undef N2 +#undef T3 +#undef N3 +#undef T4 +#undef N4 +#undef T5 +#undef N5 +#undef T6 +#undef N6 + +#endif // INDICATOR_LEGACY_VERSION_MT5 +#endif // __MQL4__ + +#ifdef __MQL5__ +#ifdef INDICATOR_LEGACY_VERSION_MT4 + +/** + * Replacement for future StringConcatenate(). + */ +#define StringConcatenate StringConcatenateMT4 + +/** + * MQL5 wrapper of MQL4's StringConcatenate(). + */ +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j, K _k, L _l, + M _m) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k + (string)_l + (string)_m; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j, K _k, L _l) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k + (string)_l; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j, K _k) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j + (string)_k; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, J _j) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i + (string)_j; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h + + (string)_i; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g + (string)_h; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f, G _g) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f + (string)_g; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e, F _f) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e + (string)_f; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d, E _e) { + return (string)_a + (string)_b + (string)_c + (string)_d + (string)_e; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c, D _d) { + return (string)_a + (string)_b + (string)_c + (string)_d; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b, C _c) { + return (string)_a + (string)_b + (string)_c; +} +template +string StringConcatenateMT4(string& _result, A _a, B _b) { + return (string)_a + (string)_b; +} +template +string StringConcatenateMT4(string& _result, A _a) { + return (string)_a; +} + +#endif // INDICATOR_LEGACY_VERSION_MT4 +#endif // __MQL5__ diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index a9b94aea1..3171251f7 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" @@ -47,13 +47,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_Candle(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_CANDLE, _tf, _shift){}; /** * Alters indicator's struct value. @@ -66,7 +67,7 @@ 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]; @@ -93,10 +94,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..dc5bdc958 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" @@ -46,18 +46,19 @@ 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, IndicatorBase* _indi_src = NULL) : IndicatorTickOrCandleSource(_p, _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(); BarOHLC _ohlcs[8]; @@ -91,10 +92,10 @@ class Indi_Pattern : public Indicator { } 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); + _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 +113,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..1ce0404d3 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). @@ -54,13 +54,13 @@ struct IndiACParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_AC : public Indicator { +class Indi_AC : public IndicatorTickOrCandleSource { 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_AC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AC, _tf, _shift){}; /** * Returns the indicator value. @@ -105,7 +105,7 @@ 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) { diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index 31b21fec6..172eed9f5 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). @@ -48,13 +48,13 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_AD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AD, _tf, _shift) { iparams.SetTf(_tf); }; @@ -101,7 +101,7 @@ 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) { diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index 7a4c33d75..1a3883d14 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__ @@ -61,13 +61,13 @@ struct IndiADXParams : IndicatorParams { /** * Implements the Average Directional Movement Index indicator. */ -class Indi_ADX : public Indicator { +class Indi_ADX : public IndicatorTickOrCandleSource { 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_ADX(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_ADX, _tf, _shift) {} /** * Returns the indicator value. @@ -115,7 +115,7 @@ 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) { diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 2b7a1b644..b5b11d152 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" @@ -55,13 +55,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_ADXW(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_ADXW, _tf, _shift){}; /** * Built-in version of ADX Wilder. @@ -102,6 +103,16 @@ class Indi_ADXW : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of ADX Wilder. + */ + static double iADXWilderOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + int _mode = 0, int _shift = 0, IndicatorBase *_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,7 +226,7 @@ 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) { @@ -226,6 +237,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..e72de2fdc 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,14 +37,15 @@ 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) { + applied_price(_ap) { SetDataValueRange(IDATA_RANGE_PRICE); + // Defaulting to on-indicator mode (will use real ticks from platform via IndicatorTickReal). + SetDataSourceMode(IDATA_INDICATOR); SetShift(_shift); switch (idstype) { case IDATA_ICUSTOM: @@ -56,19 +58,22 @@ struct IndiAMAParams : IndicatorParams { 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, IndicatorBase *_indi_src = NULL, int _indi_mode = 0) + : IndicatorTickOrCandleSource(_p, _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. @@ -82,7 +87,7 @@ class Indi_AMA : public Indicator { #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 +115,20 @@ class Indi_AMA : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of AMA. + */ + static double iAMAOnIndicator(IndicatorBase *_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, IndicatorBase *_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 +177,10 @@ class Indi_AMA : public Indicator { CalculateInit(InpPeriodAMA, InpFastPeriodEMA, InpSlowPeriodEMA, InpShiftAMA, ExtFastSC, ExtSlowSC, ExtPeriodAMA, ExtSlowPeriodEMA, ExtFastPeriodEMA); + 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)); + } + int i; // Check for rates count. if (rates_total < ExtPeriodAMA + begin) return (0); @@ -199,7 +222,7 @@ 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) { @@ -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 IndicatorBase *OnDataSourceRequest() { return DataSourceRequestReturnDefault(GetAppliedPrice()); } + /* Getters */ /** diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index 2d1b1f8de..91b8e457c 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). @@ -51,13 +51,13 @@ struct IndiAOParams : IndicatorParams { /** * Implements the Awesome oscillator. */ -class Indi_AO : public Indicator { +class Indi_AO : public IndicatorTickOrCandleSource { 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_AO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_AO, _tf, _shift){}; /** * Returns the indicator value. @@ -103,7 +103,7 @@ 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) { diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index 2e0cf341b..cccfc3a2a 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. @@ -46,13 +46,13 @@ struct IndiASIParams : IndicatorParams { /** * Implements the Bill Williams' Accelerator/Decelerator oscillator. */ -class Indi_ASI : public Indicator { +class Indi_ASI : public IndicatorTickOrCandleSource { 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_ASI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_ASI, _tf, _shift){}; /** * Built-in version of ASI. @@ -84,6 +84,16 @@ class Indi_ASI : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of ASI. + */ + static double iASIOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, double _mpc, int _mode = 0, + int _shift = 0, IndicatorBase *_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,7 +165,7 @@ 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) { @@ -168,8 +178,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..6ddcbd8bc 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). @@ -52,13 +52,13 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_ATR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_ATR, _tf, _shift){}; /** * Returns the indicator value. @@ -103,7 +103,7 @@ 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) { diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index 3118ea4cb..af6799596 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). @@ -95,14 +95,15 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_Alligator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_ADX, _tf, _shift){}; /** * Returns the indicator value. @@ -162,7 +163,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__ diff --git a/Indicators/Indi_AppliedPrice.mqh b/Indicators/Indi_AppliedPrice.mqh index 379596331..28d43b785 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. @@ -44,7 +44,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()) { @@ -58,10 +58,11 @@ class Indi_AppliedPrice : public Indicator { * Class constructor. */ Indi_AppliedPrice(IndiAppliedPriceParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src) { + : IndicatorTickOrCandleSource(_p, _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(); }; @@ -74,7 +75,7 @@ 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) { diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index dcfd02fec..963490f84 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). @@ -62,14 +62,14 @@ struct IndiBWIndiMFIParams : IndicatorParams { /** * Implements the Market Facilitation Index by Bill Williams indicator. */ -class Indi_BWMFI : public Indicator { +class Indi_BWMFI : public IndicatorTickOrCandleSource { 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_BWMFI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_BWMFI, _tf, _shift) {} /** * Returns the indicator value. @@ -114,9 +114,11 @@ 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) { case IDATA_BUILTIN: _value = Indi_BWMFI::iBWMFI(GetSymbol(), GetTf(), _ishift, (ENUM_BWMFI_BUFFER)_mode, THIS_PTR); @@ -135,7 +137,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..5699beba3 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,11 +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) { + indi_ac = NULL; + indi_ao = NULL; SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\BW-ZoneTrade"); shift = _shift; @@ -58,13 +62,14 @@ struct IndiBWZTParams : IndicatorParams { /** * Implements the Bill Williams' Zone Trade. */ -class Indi_BWZT : public Indicator { +class Indi_BWZT : public IndicatorTickOrCandleSource { 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_BWZT(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_BWZT, _tf, _shift){}; /** * Built-in version of BWZT. @@ -102,6 +107,34 @@ class Indi_BWZT : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of BWZT. + */ + static double iBWZTOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode, int _shift, + IndicatorBase *_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 IndicatorBase *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. */ @@ -172,7 +205,7 @@ 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) { @@ -182,6 +215,9 @@ class Indi_BWZT : public Indicator { 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..56b4099fb 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" @@ -86,14 +86,14 @@ struct IndiBandsParams : IndicatorParams { /** * Implements the Bollinger Bands® indicator. */ -class Indi_Bands : public Indicator { +class Indi_Bands : public IndicatorTickSource { 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) {} + : IndicatorTickSource(_p, _indi_src, _mode) {} + Indi_Bands(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_BANDS, _tf, _shift) {} /** * Returns the indicator value. @@ -239,7 +239,7 @@ 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) { diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index e4f3ac5af..5ba1562a7 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). @@ -51,14 +51,15 @@ 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) {} + : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_BearsPower(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_BEARS, _tf, _shift) {} /** * Returns the indicator value. @@ -104,7 +105,7 @@ 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) { diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index 1baf044a9..d1d0491fb 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). @@ -51,14 +51,15 @@ 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) {} + : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_BullsPower(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_BULLS, _tf, _shift) {} /** * Returns the indicator value. @@ -104,7 +105,7 @@ 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) { diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index 210bb8ea6..43879b492 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" @@ -58,13 +58,13 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickSource(_p, _indi_src) {} + Indi_CCI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_CCI, _tf, _shift) {} /** * Returns the indicator value. @@ -145,7 +145,7 @@ 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) { diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index 1cf24699e..5366e2651 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" @@ -54,13 +54,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_CHO(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_CHAIKIN, _tf, _shift){}; /** * Built-in version of Chaikin Oscillator. @@ -73,7 +74,7 @@ class Indi_CHO : public Indicator { _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 +103,20 @@ class Indi_CHO : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Chaikin Oscillator. + */ + static double iChaikinOnIndicator(IndicatorBase *_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, IndicatorBase *_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,7 +181,7 @@ 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) { @@ -178,6 +193,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..145a03f59 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" @@ -55,13 +55,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_CHV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_CHAIKIN_V, _tf, _shift){}; /** * Built-in version of Chaikin Volatility. @@ -99,6 +100,19 @@ class Indi_CHV : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Chaikin Volatility. + */ + static double iCHVOnIndicator(IndicatorBase *_indi, 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) { + 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,7 +176,7 @@ 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) { @@ -174,6 +188,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..7927d1fe2 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. @@ -42,21 +42,22 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _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"); + INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_symbol, _tf, "Indi_ColorBars"); return iColorBarsOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, _mode, _shift, _cache); } @@ -82,6 +83,16 @@ class Indi_ColorBars : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Color Bars. + */ + static double iColorBarsOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, + int _shift = 0, IndicatorBase *_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,7 +124,7 @@ 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) { @@ -123,6 +134,9 @@ class Indi_ColorBars : public Indicator { 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..9348b8095 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. @@ -42,15 +42,15 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _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. @@ -82,6 +82,16 @@ class Indi_ColorCandlesDaily : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Color Candles Daily. + */ + static double iCCDOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, + int _shift = 0, IndicatorBase *_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,7 +120,7 @@ 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) { @@ -120,6 +130,10 @@ class Indi_ColorCandlesDaily : public Indicator { 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..64adcf9dc 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -22,14 +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 { + IndicatorBase *indi_ma; // Struct constructor. IndiColorLineParams(int _shift = 0) : IndicatorParams(INDI_COLOR_LINE, 2, TYPE_DOUBLE) { + indi_ma = NULL; SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\ColorLine"); shift = _shift; @@ -43,14 +45,15 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_ColorLine(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_COLOR_LINE, _tf, _shift){}; /** * "Built-in" version of Color Line. @@ -86,6 +89,30 @@ class Indi_ColorLine : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Color Line. + */ + static double iColorLineOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, + int _shift = 0, IndicatorBase *_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 IndicatorBase *FetchDataSource(ENUM_INDICATOR_TYPE _id) override { + switch (_id) { + case INDI_MA: + return iparams.indi_ma; + } + return NULL; + } + /** * OnCalculate() method for Color Line indicator. */ @@ -172,7 +199,7 @@ 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) { @@ -182,6 +209,9 @@ class Indi_ColorLine : public Indicator { 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..e172c2b69 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,7 +32,7 @@ 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) { + : IndicatorParams(INDI_CUSTOM_MOVING_AVG, 1, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); SetDataSourceType(IDATA_ICUSTOM); #ifdef __MQL5__ @@ -54,20 +54,20 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _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) { diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index 8f96593c4..ec5007d20 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" @@ -63,13 +63,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_DEMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_DEMA, _tf, _shift) {} /** * Updates the indicator value. @@ -108,44 +109,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, IndicatorBase *_indi, int indi_mode, + unsigned int ma_period, unsigned int ma_shift, int shift) { return iDEMAOnArray(_indi.GetValueStorage(indi_mode), 0, ma_period, ma_shift, shift, cache); } - 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); } - static int Calculate(const int rates_total, const int prev_calculated, const int begin, ValueStorage &price, - int InpPeriodEMA, ValueStorage &DemaBuffer, ValueStorage &Ema, - ValueStorage &EmaOfEma) { + /** + * On-indicator version of DEMA. + */ + static double iDEMAOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, int _ma_shift, + ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorBase *_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(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 +177,15 @@ 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) { 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..2e67aa4ea 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). @@ -50,14 +50,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_DeMarker(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_DEMARKER, _tf, _shift) {} /** * Returns the indicator value. @@ -102,7 +102,7 @@ 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) { diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index a5bf323d5..9fd756862 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" /** @@ -53,13 +53,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_Demo(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_DEMO, _tf, _shift){}; /** * Returns the indicator value. @@ -72,7 +73,7 @@ class Indi_Demo : 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 = 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..3f78bdddd 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" @@ -48,15 +48,15 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _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. @@ -65,14 +65,14 @@ class Indi_DetrendedPrice : public Indicator { int _shift = 0, IndicatorBase *_obj = NULL) { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_SHORT(_symbol, _tf, _ap, Util::MakeKey("Indi_DPO", _period, (int)_ap)); - return iDPOOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_SHORT, _period, _mode, _shift, _cache); + 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 +89,16 @@ class Indi_DetrendedPrice : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of DPO. + */ + static double iDPOOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorBase *_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,7 +126,7 @@ 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) { @@ -128,6 +138,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..893d62f65 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,7 +34,7 @@ struct IndicatorParams; /** * Implements the Relative Strength Index indicator. */ -class Indi_Drawer : public Indicator { +class Indi_Drawer : public IndicatorTickOrCandleSource { Redis redis; public: @@ -42,10 +42,11 @@ class Indi_Drawer : public Indicator { * Class constructor. */ Indi_Drawer(const IndiDrawerParams &_p, IndicatorBase *_indi_src = NULL) - : Indicator(_p, _indi_src), redis(true) { + : IndicatorTickOrCandleSource(_p, _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(); } @@ -172,7 +173,7 @@ class Indi_Drawer : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 4dedaa976..ecede2db4 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" @@ -76,14 +76,15 @@ struct IndiEnvelopesParams : IndicatorParams { /** * Implements the Envelopes indicator. */ -class Indi_Envelopes : public Indicator { +class Indi_Envelopes : public IndicatorTickOrCandleSource { 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) {} + : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_Envelopes(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_ENVELOPES, _tf, _shift) {} /** * Returns the indicator value. @@ -197,7 +198,7 @@ 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) { @@ -224,7 +225,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..661bdc6a4 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). @@ -65,14 +65,15 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_Force(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_FORCE, _tf, _shift) {} /** * Returns the indicator value. @@ -117,7 +118,7 @@ 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) { diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index 7640170c0..a0c69a60c 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. @@ -50,14 +50,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_FrAMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_FRAMA, _tf, _shift){}; /** * Built-in version of FrAMA. @@ -69,15 +69,15 @@ class Indi_FrAMA : public Indicator { #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 +95,17 @@ class Indi_FrAMA : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of FrAMA. + */ + static double iFrAMAOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, + int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, + IndicatorBase *_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,7 +145,7 @@ 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) { @@ -146,6 +157,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 16bafed00..cb1922ff1 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). @@ -48,14 +48,14 @@ struct IndiFractalsParams : IndicatorParams { /** * Implements the Fractals indicator. */ -class Indi_Fractals : public Indicator { +class Indi_Fractals : public IndicatorTickOrCandleSource { 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_Fractals(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_FRACTALS, _tf, _shift) {} /** * Returns the indicator value. @@ -102,7 +102,7 @@ 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) { @@ -121,7 +121,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..f87e8fc5a 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). @@ -103,13 +103,14 @@ struct IndiGatorParams : IndicatorParams { /** * Implements the Gator oscillator. */ -class Indi_Gator : public Indicator { +class Indi_Gator : public IndicatorTickOrCandleSource { 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_Gator(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_GATOR, _tf, _shift) {} /** * Returns the indicator value. @@ -169,7 +170,7 @@ 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) { @@ -195,7 +196,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..e3c3e33bc 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. @@ -68,14 +68,15 @@ struct IndiHeikenAshiParams : IndicatorParams { /** * Implements the Heiken-Ashi indicator. */ -class Indi_HeikenAshi : public Indicator { +class Indi_HeikenAshi : public IndicatorTickOrCandleSource { 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) {} + : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_HeikenAshi(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_HEIKENASHI, _tf, _shift) {} /** * Returns value for iHeikenAshi indicator. @@ -157,6 +158,16 @@ class Indi_HeikenAshi : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Heiken Ashi. + */ + static double iHeikenAshiOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, + int _shift = 0, IndicatorBase *_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,7 +206,7 @@ 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) { @@ -226,6 +237,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..e87290e9e 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). @@ -86,14 +86,14 @@ struct IndiIchimokuParams : IndicatorParams { /** * Implements the Ichimoku Kinko Hyo indicator. */ -class Indi_Ichimoku : public Indicator { +class Indi_Ichimoku : public IndicatorTickOrCandleSource { 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_Ichimoku(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_ICHIMOKU, _tf, _shift) {} /** * Returns the indicator value. @@ -142,7 +142,7 @@ 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) { @@ -163,7 +163,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..5fc584d03 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. @@ -91,7 +91,7 @@ struct Indi_Killzones_Time : MarketTimeForex { /** * Implements Pivot Detector. */ -class Indi_Killzones : public Indicator { +class Indi_Killzones : public IndicatorTickOrCandleSource { protected: Indi_Killzones_Time ikt; @@ -100,13 +100,14 @@ 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) {} + : IndicatorTickOrCandleSource(_p, _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(); diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index c2675a21a..cf6b14aed 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" @@ -74,13 +74,13 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickSource(_p, _indi_src) {} + Indi_MA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickSource(INDI_MA, _tf, _shift) {} /** * Returns the indicator value. @@ -141,11 +141,96 @@ class Indi_MA : public Indicator { #ifdef __MQL4__ return ::iMAOnArray(price, total, ma_period, ma_shift, ma_method, shift); #else - // We're reusing the same native array for each consecutive calculation. - NativeValueStorage *_array_storage = Singleton>::Get(); - _array_storage.SetData(price); - - return iMAOnArray((ValueStorage *)_array_storage, total, ma_period, ma_shift, ma_method, shift, cache); + if (cache != NULL) { + // We're reusing the same native array for each consecutive calculation. + NativeValueStorage *_array_storage = Singleton>::Get(); + _array_storage.SetData(price); + + return iMAOnArray((ValueStorage *)_array_storage, total, ma_period, ma_shift, ma_method, shift, cache); + } else { + double buf[], arr[], _result, pr, _array; + int pos, i, k, weight; + double sum, lsum; + if (total == 0) total = ArraySize(price); + if (total > 0 && total < ma_period) return (0); + if (shift > total - ma_period - ma_shift) return (0); + bool _was_series = ArrayGetAsSeries(price); + ArraySetAsSeries(price, true); + switch (ma_method) { + case MODE_SMA: + total = ArrayCopy(arr, price, 0, shift + ma_shift, ma_period); + if (ArrayResize(buf, total) < 0) return (0); + sum = 0; + pos = total - 1; + for (i = 1; i < ma_period; i++, pos--) sum += arr[pos]; + while (pos >= 0) { + sum += arr[pos]; + buf[pos] = sum / ma_period; + sum -= arr[pos + ma_period - 1]; + pos--; + } + _result = buf[0]; + break; + case MODE_EMA: + if (ArrayResize(buf, total) < 0) return (0); + pr = 2.0 / (ma_period + 1); + pos = total - 2; + while (pos >= 0) { + if (pos == total - 2) buf[pos + 1] = price[pos + 1]; + buf[pos] = price[pos] * pr + buf[pos + 1] * (1 - pr); + pos--; + } + _result = buf[0]; + break; + case MODE_SMMA: + if (ArrayResize(buf, total) < 0) return (0); + sum = 0; + pos = total - ma_period; + while (pos >= 0) { + if (pos == total - ma_period) { + for (i = 0, k = pos; i < ma_period; i++, k++) { + sum += price[k]; + buf[k] = 0; + } + } else + sum = buf[pos + 1] * (ma_period - 1) + price[pos]; + buf[pos] = sum / ma_period; + pos--; + } + _result = buf[0]; + break; + case MODE_LWMA: + if (ArrayResize(buf, total) < 0) return (0); + sum = 0.0; + lsum = 0.0; + weight = 0; + pos = total - 1; + for (i = 1; i <= ma_period; i++, pos--) { + _array = price[pos]; + sum += _array * i; + lsum += _array; + weight += i; + } + pos++; + i = pos + ma_period; + while (pos >= 0) { + buf[pos] = sum / weight; + if (pos == 0) break; + pos--; + i--; + _array = price[pos]; + sum = sum - lsum + _array * ma_period; + lsum -= price[i]; + lsum += _array; + } + _result = buf[0]; + break; + default: + _result = 0; + } + ArraySetAsSeries(price, _was_series); + return _result; + } #endif } @@ -627,7 +712,7 @@ 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) { @@ -663,6 +748,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..445c9d8dd 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). @@ -59,13 +59,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_MACD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_MACD, _tf, _shift) {} /** * Returns the indicator value. @@ -114,7 +115,7 @@ 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) { diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index acd15835b..f2ad316b1 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). @@ -51,13 +51,13 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _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. @@ -111,7 +111,7 @@ 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) { diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index 817b81cd8..b541f236e 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" @@ -50,14 +50,15 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_MassIndex(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_MASS_INDEX, _tf, _shift){}; /** * Built-in version of Mass Index. @@ -92,6 +93,19 @@ class Indi_MassIndex : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Mass Index. + */ + static double iMIOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + int _second_period, int _sum_period, int _mode = 0, int _shift = 0, + IndicatorBase *_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,7 +167,7 @@ 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) { @@ -165,6 +179,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..7dc6d01ea 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__ @@ -61,14 +61,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_Momentum(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_MOMENTUM, _tf, _shift) {} /** * Returns the indicator value. @@ -141,7 +141,7 @@ 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) { diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index 6efeeb242..dddc611e3 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). @@ -62,13 +62,13 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_OBV(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_OBV, _tf, _shift) {} /** * Returns the indicator value. @@ -118,7 +118,7 @@ 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) { diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index 9958bdf83..22520384c 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). @@ -58,13 +58,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_OsMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_OSMA, _tf, _shift) {} /** * Returns the indicator value. @@ -111,7 +112,7 @@ 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) { diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index fd4c7cf4d..75a737974 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -44,13 +44,14 @@ struct IndiPivotParams : IndicatorParams { /** * Implements Pivot Detector. */ -class Indi_Pivot : public Indicator { +class Indi_Pivot : public IndicatorTickOrCandleSource { 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, IndicatorBase* _indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_Pivot(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_PIVOT, _tf, _shift) { iparams.tf = _tf; }; @@ -62,7 +63,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); @@ -100,7 +101,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]; } @@ -148,10 +149,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..97fbe41d2 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "Indi_ZigZag.mqh" // Structs. @@ -43,17 +43,17 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _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. @@ -86,6 +86,16 @@ class Indi_PriceChannel : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Price Channel. + */ + static double iPriceChannelOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + int _mode = 0, int _shift = 0, IndicatorBase *_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,7 +116,7 @@ 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) { @@ -117,6 +127,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..9dfc075ea 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 { @@ -53,17 +53,18 @@ 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) { + : IndicatorTickOrCandleSource(_p, _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 +76,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(); diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index 17505eff1..9f4899142 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. @@ -45,15 +45,15 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _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. @@ -85,6 +85,16 @@ class Indi_PriceVolumeTrend : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Price Volume Trend. + */ + static double iPVTOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_VOLUME _av, + int _mode = 0, int _shift = 0, IndicatorBase *_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,7 +131,7 @@ 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) { @@ -133,6 +143,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..ef81af539 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" @@ -46,15 +46,17 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _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) { @@ -78,7 +80,7 @@ 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) { case IDATA_MATH: diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index c900e6680..c2fe083e1 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" @@ -33,9 +33,9 @@ #ifndef __MQL4__ // Defines global functions (for MQL4 backward compability). -double iRSI(string _symbol, int _tf, int _period, int _ap, int _shift) { +double iRSI(string _symbol, int _tf, int _period, ENUM_APPLIED_PRICE _ap, int _shift) { ResetLastError(); - return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); + return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, _ap, _shift); } double iRSIOnArray(double &_arr[], int _total, int _period, int _shift) { ResetLastError(); @@ -89,15 +89,15 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_RSI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_RSI, _tf, _shift) {} /** * Returns the indicator value. @@ -289,7 +289,7 @@ 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(); diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index 7256a4aa3..e19867e8a 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). @@ -50,13 +50,13 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_RVI(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_RVI, _tf, _shift) {} /** * Returns the indicator value. @@ -103,7 +103,7 @@ 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) { diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index 076f4798a..2f0d5b061 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. @@ -47,15 +47,15 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _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. @@ -88,6 +88,16 @@ class Indi_RateOfChange : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Rate of Change. + */ + static double iROCOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorBase *_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,7 +120,7 @@ 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) { @@ -122,6 +132,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..ba8d7c499 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). @@ -51,13 +51,13 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_SAR(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : IndicatorTickOrCandleSource(INDI_SAR, _tf, _shift) {} /** * Returns the indicator value. @@ -102,7 +102,7 @@ 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) { diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 46be6a1ac..aa2e77603 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" @@ -73,13 +73,13 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickSource(_p, _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. @@ -157,7 +157,8 @@ class Indi_StdDev : public Indicator { return MathSqrt(std_dev / period); } - static double iStdDevOnArray(double &array[], int total, int ma_period, int ma_shift, int ma_method, int shift) { + static double iStdDevOnArray(double &array[], int total, int ma_period, int ma_shift, ENUM_MA_METHOD ma_method, + int shift) { #ifdef __MQL4__ return ::iStdDevOnArray(array, total, ma_period, ma_shift, ma_method, shift); #endif @@ -226,7 +227,7 @@ 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) { diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index 722ac6120..f93c4cbce 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). @@ -62,13 +62,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _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. @@ -119,7 +120,7 @@ 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) { diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index 3cc9e949b..5954a9804 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" @@ -50,13 +50,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_TEMA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_TEMA, _tf, _shift){}; /** * Built-in version of TEMA. @@ -94,6 +95,18 @@ class Indi_TEMA : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of TEMA. + */ + static double iTEMAOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, + int _ma_shift, ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, + IndicatorBase *_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,7 +139,7 @@ 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) { @@ -138,6 +151,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..86caabb0d 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" @@ -49,13 +49,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_TRIX(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_TRIX, _tf, _shift){}; /** * Built-in version of TriX. @@ -93,6 +94,16 @@ class Indi_TRIX : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of TriX. + */ + static double iTriXOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _ma_period, + ENUM_APPLIED_PRICE _ap, int _mode = 0, int _shift = 0, IndicatorBase *_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,7 +138,7 @@ 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) { @@ -139,6 +150,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..98a7f9e1f 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; @@ -59,15 +62,15 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _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. @@ -113,6 +116,41 @@ class Indi_UltimateOscillator : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Ultimate Oscillator. + */ + static double iUOOnIndicator(IndicatorBase *_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, IndicatorBase *_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. + */ + IndicatorBase *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,7 +247,7 @@ 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) { @@ -225,6 +263,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..4e98a6254 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. @@ -53,13 +53,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_VIDYA(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_VIDYA, _tf, _shift){}; /** * Built-in version of iVIDyA. @@ -98,6 +99,19 @@ class Indi_VIDYA : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of VIDya indicator. + */ + static double iVIDyAOnIndicator(IndicatorBase *_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, + IndicatorBase *_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,7 +161,7 @@ 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) { @@ -162,6 +176,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..cacf2861c 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. @@ -47,13 +47,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_VROC(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_VROC, _tf, _shift){}; /** * Built-in version of VROC. @@ -65,7 +66,7 @@ class Indi_VROC : public Indicator { } /** - * 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 +86,16 @@ class Indi_VROC : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of VROC indicator. + */ + static double iVROCOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _period, + ENUM_APPLIED_VOLUME _av, int _mode = 0, int _shift = 0, IndicatorBase *_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,7 +141,7 @@ 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) { @@ -142,6 +153,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..c46671424 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. @@ -44,15 +44,16 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_Volumes(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_VOLUMES, _tf, _shift){}; /** * Built-in version of Volumes. @@ -84,6 +85,16 @@ class Indi_Volumes : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Volumes indicator. + */ + static double iVolumesOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, ENUM_APPLIED_VOLUME _av, + int _mode = 0, int _shift = 0, IndicatorBase *_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,7 +135,7 @@ 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) { @@ -135,6 +146,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..b202f3535 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). @@ -50,13 +50,13 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _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. @@ -101,7 +101,7 @@ 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) { diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index 754cff808..7e2bf94e4 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -22,7 +22,7 @@ // Includes. #include "../BufferStruct.mqh" -#include "../Indicator.mqh" +#include "../Indicator/IndicatorTickOrCandleSource.h" #include "../Storage/ValueStorage.all.h" // Structs. @@ -42,14 +42,15 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_WilliamsAD(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_WILLIAMS_AD, _tf, _shift){}; /** * Built-in version of Williams' AD. @@ -80,6 +81,16 @@ class Indi_WilliamsAD : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of Williams' AD. + */ + static double iWADOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _mode = 0, + int _shift = 0, IndicatorBase *_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,7 +135,7 @@ 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) { @@ -134,6 +145,9 @@ class Indi_WilliamsAD : public Indicator { 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..ec8147ee9 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. @@ -58,13 +58,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _indi_src) {} + Indi_ZigZag(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_ZIGZAG, _tf, _shift) {} /** * Returns value for ZigZag indicator. @@ -135,6 +136,18 @@ class Indi_ZigZag : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of ZigZag indicator. + */ + static double iZigZagOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _depth, + int _deviation, int _backstep, int _mode = 0, int _shift = 0, + IndicatorBase *_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 +347,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) { 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..6e8cf6d9a 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" @@ -52,14 +52,15 @@ 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){}; + : IndicatorTickOrCandleSource(_p, _indi_src){}; + Indi_ZigZagColor(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) + : IndicatorTickOrCandleSource(INDI_VROC, _tf, _shift){}; /** * Returns value for ZigZag Color indicator. @@ -96,6 +97,19 @@ class Indi_ZigZagColor : public Indicator { return _cache.GetTailValue(_mode, _shift); } + /** + * On-indicator version of ZigZag indicator. + */ + static double iZigZagColorOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, int _depth, + int _deviation, int _backstep, int _mode = 0, int _shift = 0, + IndicatorBase *_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 +282,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) { 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..c7f9cc25c 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. @@ -49,18 +49,19 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _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..b0cbcc6d3 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -22,7 +22,7 @@ // Includes. #include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" +#include "../../Indicator/IndicatorTickOrCandleSource.h" #include "../../Storage/Objects.h" // Structs. @@ -46,13 +46,14 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _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 +63,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 +87,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_Math.mqh b/Indicators/Special/Indi_Math.mqh index 033377c04..098b4fc3f 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 }; @@ -82,18 +82,19 @@ 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, IndicatorBase *_indi_src = NULL) : IndicatorTickOrCandleSource(_p, _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) { @@ -132,16 +133,16 @@ class Indi_Math : public Indicator { static double iMathOnIndicator(IndicatorBase *_indi, string _symbol, ENUM_TIMEFRAMES _tf, ENUM_MATH_OP op, unsigned int _mode_1, unsigned int _mode_2, unsigned int _shift_1, unsigned int _shift_2, unsigned int _mode, int _shift, 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, 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..9f03835b9 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -21,9 +21,7 @@ */ // Includes. -#include "../../BufferStruct.mqh" -#include "../../Indicator.mqh" -#include "../../Storage/Objects.h" +#include "../../Indicator/IndicatorTick.h" // Structs. struct IndiTickMtParams : IndicatorParams { @@ -31,6 +29,7 @@ struct IndiTickMtParams : IndicatorParams { // Struct constructor. IndiTickMtParams(string _symbol = NULL, int _shift = 0) : IndicatorParams(INDI_TICK, 3, TYPE_DOUBLE) { SetShift(_shift); + SetSymbol(_symbol); }; IndiTickMtParams(IndiTickMtParams &_params, ENUM_TIMEFRAMES _tf) { THIS_REF = _params; @@ -45,33 +44,51 @@ 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, IndicatorBase *_indi_src = NULL) + : IndicatorTick(_p, _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/Log.mqh b/Log.mqh index 9e7781d31..c5fa1cd1f 100644 --- a/Log.mqh +++ b/Log.mqh @@ -308,10 +308,10 @@ class Log : public Object { } bool DeleteByTimestamp(datetime timestamp) { - int size = ArraySize(data); - if (size > 0) { + int _size = ArraySize(data); + if (_size > 0) { int offset = 0; - for (int i = 0; i < size; i++) { + for (int i = 0; i < _size; i++) { if (data[i].timestamp == timestamp) { Erase(data, i); return true; diff --git a/MiniMatrix.h b/MiniMatrix.h index 3ceaaa5ab..716af79e4 100644 --- a/MiniMatrix.h +++ b/MiniMatrix.h @@ -43,13 +43,13 @@ class MiniMatrix2d { T Get(int _x, int _y) { return data[(size_x * _y) + _x]; } void Set(int _x, int _y, T _value) { - int index = (size_x * _y) + _x; + int _idx = (size_x * _y) + _x; - if (index < 0 || index >= (size_x * size_y)) { + if (_idx < 0 || _idx >= (size_x * size_y)) { Alert("Array out of range!"); } - data[index] = _value; + data[_idx] = _value; } int SizeX() { return size_x; } diff --git a/Object.mqh b/Object.mqh index 36f69ec28..64467c821 100644 --- a/Object.mqh +++ b/Object.mqh @@ -24,6 +24,10 @@ #ifndef OBJECT_MQH #define OBJECT_MQH +#ifdef __MQL4__ +#define nullptr NULL +#endif + // Includes. #include "Refs.mqh" #include "String.mqh" diff --git a/Order.mqh b/Order.mqh index 3ea5c20cb..be7803c3a 100644 --- a/Order.mqh +++ b/Order.mqh @@ -44,6 +44,7 @@ #include "Std.h" #include "String.mqh" #include "SymbolInfo.mqh" +#include "Terminal.define.h" /* Defines for backward compatibility. */ @@ -930,7 +931,7 @@ class Order : public SymbolInfo { _request.type_filling = GetOrderFilling(orequest.symbol); _request.position = odata.Get(ORDER_PROP_TICKET); _request.price = SymbolInfo::GetCloseOffer(orequest.type); - _request.volume = orequest.volume; + _request.volume = odata.Get(ORDER_VOLUME_CURRENT); Order::OrderSend(_request, oresult, oresult_check); if (oresult.retcode == TRADE_RETCODE_DONE) { // For now, sets the current time. @@ -1086,6 +1087,7 @@ class Order : public SymbolInfo { GetLogger().Warning(StringFormat("Failed to modify order (#%d/p:%g/sl:%g/tp:%g/code:%d).", odata.Get(ORDER_PROP_TICKET), _price, _sl, _tp, _last_error), __FUNCTION_LINE__, ToCSV()); + Refresh(ORDER_PRICE_CURRENT); Refresh(ORDER_SL); Refresh(ORDER_TP); // TODO: Refresh(ORDER_PRI) @@ -1101,6 +1103,7 @@ class Order : public SymbolInfo { __FUNCTION_LINE__, ToCSV()); } } + Refresh(); return _result; } @@ -1576,6 +1579,7 @@ class Order : public SymbolInfo { #endif // Update double values. _result &= Refresh(ORDER_PRICE_OPEN); + _result &= Refresh(ORDER_VOLUME_INITIAL); // Update string values. _result &= Refresh(ORDER_SYMBOL); _result &= Refresh(ORDER_COMMENT); @@ -1587,9 +1591,6 @@ class Order : public SymbolInfo { // _result &= Refresh(ORDER_STATE); // @fixme: Error 69539 // _result &= Refresh(ORDER_TYPE_TIME); // @fixme: Error 69539 // _result &= Refresh(ORDER_TYPE_FILLING); // @fixme: Error 69539 - // Update double values. - // _result &= Refresh(ORDER_VOLUME_INITIAL); // @fixme: false - // _result &= Refresh(ORDER_VOLUME_CURRENT); // @fixme: Error 69539 } // Updates whether order is open or closed. @@ -1603,6 +1604,7 @@ class Order : public SymbolInfo { _result &= Refresh(ORDER_PRICE_CURRENT); _result &= Refresh(ORDER_SL); _result &= Refresh(ORDER_TP); + _result &= Refresh(ORDER_VOLUME_CURRENT); } //} else if (IsPending()) // _result &= Refresh(ORDER_PRICE_STOPLIMIT); // @fixme: Error 69539 @@ -1792,6 +1794,9 @@ class Order : public SymbolInfo { case ORDER_VOLUME_CURRENT: _result = Order::OrderGetDouble(ORDER_VOLUME_CURRENT, _value); break; + case ORDER_VOLUME_INITIAL: + _result = Order::OrderGetDouble(ORDER_VOLUME_INITIAL, _value); + break; default: return false; } @@ -2133,10 +2138,10 @@ class Order : public SymbolInfo { #endif switch (property_id) { case ORDER_VOLUME_INITIAL: - _result = ::OrderLots(); // @fixit Are we sure? + _result = ::OrderLots(); break; case ORDER_VOLUME_CURRENT: - _result = ::OrderLots(); // @fixit Are we sure? + _result = ::OrderLots(); break; case ORDER_PRICE_OPEN: _result = ::OrderOpenPrice(); @@ -2540,9 +2545,7 @@ class Order : public SymbolInfo { case ORDER_VOLUME_INITIAL: return OrderGetValue(POSITION_VOLUME, _type, _out); case ORDER_VOLUME_CURRENT: - // @fixme - SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return OrderGetValue(POSITION_VOLUME, _type, _out); case ORDER_PRICE_OPEN: return OrderGetValue(POSITION_PRICE_OPEN, _type, _out); case ORDER_SL: diff --git a/Serializer.mqh b/Serializer.mqh index eabe14739..3cc513e78 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -171,7 +171,7 @@ class Serializer { /** * Returns child node for a given index or NULL. */ - SerializerNode* GetChild(unsigned int index) { return _node ? PTR_ATTRIB(_node, GetChild(index)) : NULL; } + SerializerNode* GetChild(unsigned int _idx) { return _node ? PTR_ATTRIB(_node, GetChild(_idx)) : NULL; } /** * Returns floating-point precision. diff --git a/SerializerJson.mqh b/SerializerJson.mqh index 6d7524140..82cb7bc98 100644 --- a/SerializerJson.mqh +++ b/SerializerJson.mqh @@ -326,9 +326,9 @@ class SerializerJson { return root; } - static SerializerNode* GracefulReturn(string error, unsigned int index, SerializerNode* root, + static SerializerNode* GracefulReturn(string error, unsigned int _idx, SerializerNode* root, SerializerNodeParam* key) { - Print(error + " at index ", index); + Print(error + " at index ", _idx); if (root != NULL) delete root; @@ -337,10 +337,10 @@ class SerializerJson { return NULL; } - static bool ExtractNumber(string& data, unsigned int index, string& number) { + static bool ExtractNumber(string& data, unsigned int _idx, string& number) { string str; - for (unsigned int i = index; i < (unsigned int)StringLen(data); ++i) { + for (unsigned int i = _idx; i < (unsigned int)StringLen(data); ++i) { #ifdef __MQL5__ unsigned short ch = StringGetCharacter(data, i); #else @@ -350,7 +350,7 @@ class SerializerJson { if (ch >= '0' && ch <= '9') { str += ShortToString(ch); } else if (ch == '.') { - if (i == index) { + if (i == _idx) { return false; } str += ShortToString(ch); @@ -364,12 +364,12 @@ class SerializerJson { return true; } - static string ExtractString(string& data, unsigned int index) { - for (unsigned int i = index; i < (unsigned int)StringLen(data); ++i) { + static string ExtractString(string& data, unsigned int _idx) { + for (unsigned int i = _idx; i < (unsigned int)StringLen(data); ++i) { unsigned short ch = StringGetCharacter(data, i); if (ch == '"') { - return StringSubstr(data, index, i - index); + return StringSubstr(data, _idx, i - _idx); } } diff --git a/SerializerNode.mqh b/SerializerNode.mqh index 143c79c0f..ef75ec19a 100644 --- a/SerializerNode.mqh +++ b/SerializerNode.mqh @@ -279,15 +279,15 @@ class SerializerNode { /** * Returns pointer to the child node at given index or NULL. */ - SerializerNode* GetChild(unsigned int index) { return index >= _numChildren ? NULL : _children[index]; } + SerializerNode* GetChild(unsigned int _idx) { return _idx >= _numChildren ? NULL : _children[_idx]; } /** * Removes child with given index. */ - void RemoveChild(unsigned int index) { - delete _children[index]; + void RemoveChild(unsigned int _idx) { + delete _children[_idx]; - for (unsigned int i = ArraySize(_children) - 2; i >= index; --i) { + for (unsigned int i = ArraySize(_children) - 2; i >= _idx; --i) { _children[i] = _children[i + 1]; } } 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..e363559b2 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -57,5 +57,5 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { /** * 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/Storage/ValueStorage.native.h b/Storage/ValueStorage.native.h index ea7ebb4ab..f13271087 100644 --- a/Storage/ValueStorage.native.h +++ b/Storage/ValueStorage.native.h @@ -34,6 +34,7 @@ template class NativeValueStorage : public ValueStorage { // Dynamic native array. C _values[]; + int _values_size; public: /** @@ -49,7 +50,16 @@ class NativeValueStorage : public ValueStorage { /** * Initializes array with given one. */ - void SetData(ARRAY_REF(C, _arr)) { ArrayCopy(_values, _arr); } + void SetData(ARRAY_REF(C, _arr)) { + bool _was_series = ArrayGetAsSeries(_arr); + ArraySetAsSeries(_arr, false); + ArraySetAsSeries(_values, false); + ArrayResize(_values, 0); + ArrayCopy(_values, _arr); + _values_size = ArraySize(_arr); + ArraySetAsSeries(_arr, _was_series); + ArraySetAsSeries(_values, _was_series); + } /** * Initializes storage with given value. @@ -60,7 +70,7 @@ class NativeValueStorage : public ValueStorage { * Fetches value from a given shift. Takes into consideration as-series flag. */ virtual C Fetch(int _shift) { - if (_shift < 0 || _shift >= ArraySize(_values)) { + if (_shift < 0 || _shift >= _values_size) { return (C)EMPTY_VALUE; // Print("Invalid buffer data index: ", _shift, ". Buffer size: ", ArraySize(_values)); // DebugBreak(); @@ -77,7 +87,7 @@ class NativeValueStorage : public ValueStorage { /** * Returns number of values available to fetch (size of the values buffer). */ - virtual int Size() const { return ArraySize(_values); } + virtual int Size() const { return _values_size; } /** * Resizes storage to given size. diff --git a/Strategy.mqh b/Strategy.mqh index 75007bce1..624ea4654 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -865,6 +865,51 @@ class Strategy : public Object { virtual void OnInit() { SetStops(GetPointer(this), GetPointer(this)); // trade.SetStrategy(&this); // @fixme + // Sets strategy's trade spread limit. + trade.Set(TRADE_PARAM_MAX_SPREAD, sparams.Get(STRAT_PARAM_MAX_SPREAD)); + // Load active trades. + if (Get(STRAT_PARAM_ID) > 0) { + trade.OrdersLoadByMagic(Get(STRAT_PARAM_ID)); + } + Ref _order; + for (DictStructIterator> iter = trade.GetOrdersActive().Begin(); iter.IsValid(); ++iter) { + _order = iter.Value(); + if (_order.IsSet() && _order.Ptr().IsOpen()) { + Strategy::OnOrderLoad(_order.Ptr()); + } + } + } + + /** + * Event on strategy's order load. + * + * @param + * _oparams Order parameters to update. + */ + virtual void OnOrderLoad(Order *_order) { + int _index = 0; + ENUM_TIMEFRAMES _stf = Get(STRAT_PARAM_TF); + unsigned int _stf_secs = ChartTf::TfToSeconds(_stf); + if (sparams.order_close_time != 0) { + long _close_time_arg = sparams.order_close_time > 0 ? sparams.order_close_time * 60 + : (int)round(-sparams.order_close_time * _stf_secs); + _order.Set(ORDER_PARAM_COND_CLOSE, ORDER_COND_LIFETIME_GT_ARG, _index); + _order.Set(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _close_time_arg, _index); + _index++; + } + if (sparams.order_close_loss != 0.0f) { + float _loss_limit = sparams.order_close_loss; + _order.Set(ORDER_PARAM_COND_CLOSE, ORDER_COND_IN_LOSS, _index); + _order.Set(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _loss_limit, _index); + _index++; + } + if (sparams.order_close_profit != 0.0f) { + float _profit_limit = sparams.order_close_profit; + _order.Set(ORDER_PARAM_COND_CLOSE, ORDER_COND_IN_PROFIT, _index); + _order.Set(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _profit_limit, _index); + _index++; + } + _order.Set(ORDER_PARAM_UPDATE_FREQ, _stf_secs); } /** @@ -1211,7 +1256,8 @@ class Strategy : public Object { _psm.SetChartParams(_chart.GetParams()); if (Object::IsValid(_indi)) { int _ishift = 12; // @todo: Make it dynamic or as variable. - float _value = _indi.GetValuePrice(_ishift, 0, _direction > 0 ? PRICE_HIGH : PRICE_LOW); + float _value = 0.0f; // @todo + //float _value = _indi.GetValuePrice(_ishift, 0, _direction > 0 ? PRICE_HIGH : PRICE_LOW); _value = _value + (float)Math::ChangeByPct(fabs(_value - _chart.GetCloseOffer(0)), _level) * _direction; _psm.SetIndicatorPriceValue(_value); /* diff --git a/SymbolInfo.struct.h b/SymbolInfo.struct.h index ba2dc565d..3e7b94bc8 100644 --- a/SymbolInfo.struct.h +++ b/SymbolInfo.struct.h @@ -32,7 +32,7 @@ // Includes. #include "ISerializable.h" -#include "MqlTick.h" +#include "Tick.struct.h" #include "SymbolInfo.struct.static.h" // Defines struct to store symbol data. diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index 11a1440b9..19c54c378 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -26,7 +26,7 @@ #endif #include "MQL5.mqh" -#include "MqlTick.h" +#include "Tick.struct.h" #include "Std.h" /** diff --git a/Terminal.define.h b/Terminal.define.h index d5105b86d..b68e5561c 100644 --- a/Terminal.define.h +++ b/Terminal.define.h @@ -31,7 +31,10 @@ // @docs // - https://docs.mql4.com/common/setusererror // - https://www.mql5.com/en/docs/common/SetUserError + +#ifndef __MQL5__ #define ERR_USER_ARRAY_IS_EMPTY 1 +#endif #define ERR_USER_INVALID_ARG 2 #define ERR_USER_INVALID_BUFF_NUM 3 #define ERR_USER_INVALID_HANDLE 4 diff --git a/MqlTick.h b/Tick.struct.h similarity index 72% rename from MqlTick.h rename to Tick.struct.h index 241e807b5..0d36f8095 100644 --- a/MqlTick.h +++ b/Tick.struct.h @@ -29,6 +29,29 @@ #pragma once #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) {} +}; + #ifndef __MQL__ /** * Structure for storing the latest prices of the symbol. diff --git a/Trade.enum.h b/Trade.enum.h index 0c4fa402d..38a52cb39 100644 --- a/Trade.enum.h +++ b/Trade.enum.h @@ -77,6 +77,7 @@ enum ENUM_TRADE_PARAM { TRADE_PARAM_BARS_MIN = 0, // Bars minimum TRADE_PARAM_LOT_SIZE, // Lot size TRADE_PARAM_MAGIC_NO, // Magic number + TRADE_PARAM_MAX_SPREAD, // Maximum spread TRADE_PARAM_ORDER_COMMENT, // Order comment TRADE_PARAM_RISK_MARGIN, // Risk margin TRADE_PARAM_SLIPPAGE, // Slippage diff --git a/Trade.mqh b/Trade.mqh index c55a92caa..bdd048743 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -196,7 +196,10 @@ class Trade { _request.symbol = GetChart().Get(CHART_PARAM_SYMBOL); _request.price = SymbolInfoStatic::GetOpenOffer(_request.symbol, _type); _request.type = _type; +#ifndef __MQL4__ + // Filling modes not supported under MQL4. _request.type_filling = Order::GetOrderFilling(_request.symbol); +#endif _request.volume = _volume > 0 ? _volume : tparams.Get(TRADE_PARAM_LOT_SIZE); _request.volume = NormalizeLots(fmax(_request.volume, SymbolInfoStatic::GetVolumeMin(_request.symbol))); return _request; @@ -842,8 +845,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); - return -1; + logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + continue; } } else { OrderMoveToHistory(_order.Ptr()); diff --git a/Trade.struct.h b/Trade.struct.h index 13ce9724a..226815833 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -40,6 +40,7 @@ struct TradeStats; /* Structure for trade parameters. */ struct TradeParams { float lot_size; // Default lot size. + float max_spread; // Maximum spread to trade (in pips). float risk_margin; // Maximum account margin to risk (in %). string order_comment; // Order comment. unsigned int limits_stats[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; @@ -72,6 +73,8 @@ struct TradeParams { return (T)lot_size; case TRADE_PARAM_MAGIC_NO: return (T)magic_no; + case TRADE_PARAM_MAX_SPREAD: + return (T)max_spread; case TRADE_PARAM_ORDER_COMMENT: return (T)order_comment; case TRADE_PARAM_RISK_MARGIN: @@ -130,6 +133,9 @@ struct TradeParams { case TRADE_PARAM_MAGIC_NO: magic_no = (unsigned long)_value; return; + case TRADE_PARAM_MAX_SPREAD: + max_spread = (float)_value; + return; case TRADE_PARAM_ORDER_COMMENT: order_comment = (string)_value; return; diff --git a/Util.h b/Util.h index 12ccb0c28..904fde211 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. */ diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 63390f3da..dd9ac7d5f 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -80,8 +80,8 @@ int OnInit() { gfx.Start(new MT5Frontend()); - Ref _shader_v = gfx.VertexShader(ShaderSourceVS, Vertex::Layout); - Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + Ref _shader_v = gfx.CreateVertexShader(ShaderSourceVS, Vertex::Layout); + Ref _shader_p = gfx.CreatePixelShader(ShaderSourcePS); Ref> _mesh = new Cube(1.0f, 1.0f, 1.0f); _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); 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..ada301677 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -25,7 +25,8 @@ */ // Defines. -//#define __debug__ // Enables debug. +// #define __debug__ // Enables debug. +// #define __debug_verbose__ // Forward declaration. struct DataParamEntry; @@ -83,6 +84,11 @@ 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(); + } + if (chart.IsNewBar()) { bar_processed++; if (indis.Size() == 0) { @@ -104,6 +110,7 @@ void OnTick() { IndicatorBase* _indi = iter.Value().Ptr(); _indi.OnTick(); 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()); @@ -321,7 +328,7 @@ bool InitIndicators() { 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); + indi_stddev_on_ma_sma.Ptr().SetDataSource(indi_ma_sma_for_stddev.Ptr()); indis.Push(indi_stddev_on_ma_sma.Ptr()); // Standard Deviation (StdDev) in SMA mode over Price. @@ -409,7 +416,18 @@ bool InitIndicators() { // AMA. 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"); + ama_params_orig.SetDataSourceType(IDATA_BUILTIN); + indis.Push(new Indi_AMA(ama_params_orig)); // Chaikin Oscillator. IndiCHOParams cho_params(); @@ -533,7 +551,7 @@ bool InitIndicators() { } // Push white-listed indicators here. - whitelisted_indis.Push(_indi_test); + // whitelisted_indis.Push(_indi_test); return GetLastError() == ERR_NO_ERROR; }