diff --git a/.github/workflows/test-buffer.yml b/.github/workflows/test-buffer.yml
new file mode 100644
index 000000000..bf23d92e7
--- /dev/null
+++ b/.github/workflows/test-buffer.yml
@@ -0,0 +1,61 @@
+---
+name: Test Buffer
+
+# yamllint disable-line rule:truthy
+on:
+ pull_request:
+ paths:
+ - 'Buffer/**'
+ - '.github/workflows/test-buffer.yml'
+ push:
+ paths:
+ - 'Buffer/**'
+ - '.github/workflows/test-buffer.yml'
+
+jobs:
+
+ Compile:
+ runs-on: windows-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Compile
+ uses: fx31337/mql-compile-action@master
+ with:
+ init-platform: true
+ path: 'Buffer/tests'
+ verbose: true
+ - name: Print compiled files
+ run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname'
+ shell: powershell
+ - name: Upload artifacts (MQL4)
+ uses: actions/upload-artifact@v2
+ with:
+ name: files-ex4
+ path: '**/*.ex4'
+ - name: Upload artifacts (MQL5)
+ uses: actions/upload-artifact@v2
+ with:
+ name: files-ex5
+ path: '**/*.ex5'
+
+ Buffer-Tests-MQL4:
+ defaults:
+ run:
+ shell: bash
+ working-directory: Buffer/tests
+ needs: Compile
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ test:
+ - BufferCandle.test
+ - BufferTick.test
+ steps:
+ - uses: actions/download-artifact@v2
+ with:
+ name: files-ex4
+ - name: Run ${{ matrix.test }}
+ uses: fx31337/mql-tester-action@master
+ with:
+ Script: ${{ matrix.test }}
+ timeout-minutes: 10
diff --git a/.github/workflows/test-indicator.yml b/.github/workflows/test-indicator.yml
new file mode 100644
index 000000000..87b68aa41
--- /dev/null
+++ b/.github/workflows/test-indicator.yml
@@ -0,0 +1,67 @@
+---
+name: Test Indicator
+
+# yamllint disable-line rule:truthy
+on:
+ pull_request:
+ paths:
+ - 'Indicator**'
+ - 'Indicator/**'
+ - '.github/workflows/test-indicator.yml'
+ push:
+ paths:
+ - 'Indicator**'
+ - 'Indicator/**'
+ - '.github/workflows/test-indicator.yml'
+
+jobs:
+
+ Compile:
+ runs-on: windows-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Compile
+ uses: fx31337/mql-compile-action@master
+ with:
+ init-platform: true
+ path: 'Indicator/tests'
+ verbose: true
+ - name: Print compiled files
+ run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname'
+ shell: powershell
+ - name: Upload artifacts (MQL4)
+ uses: actions/upload-artifact@v2
+ with:
+ name: files-ex4
+ path: '**/*.ex4'
+ - name: Upload artifacts (MQL5)
+ uses: actions/upload-artifact@v2
+ with:
+ name: files-ex5
+ path: '**/*.ex5'
+
+ Indicator-Tests-MQL4:
+ defaults:
+ run:
+ shell: bash
+ working-directory: Indicator/tests
+ needs: Compile
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ test:
+ - IndicatorCandle.test
+ - IndicatorTf.test
+ - IndicatorTick.test
+ steps:
+ - uses: actions/download-artifact@v2
+ with:
+ name: files-ex4
+ - name: Run ${{ matrix.test }}
+ uses: fx31337/mql-tester-action@master
+ with:
+ BtDays: 4-8
+ BtMonths: 1
+ BtYears: 2020
+ TestExpert: ${{ matrix.test }}
+ timeout-minutes: 10
diff --git a/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/Buffer/BufferCandle.h b/Buffer/BufferCandle.h
new file mode 100644
index 000000000..8401ee3f8
--- /dev/null
+++ b/Buffer/BufferCandle.h
@@ -0,0 +1,79 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Prevents processing this includes file for the second time.
+#ifndef BUFFER_CANDLE_H
+#define BUFFER_CANDLE_H
+
+// Includes.
+#include "../BufferStruct.mqh"
+#include "../Candle.struct.h"
+
+/**
+ * Class to store struct data.
+ */
+template
+class BufferCandle : public BufferStruct> {
+ protected:
+ protected:
+ /* Protected methods */
+
+ /**
+ * Initialize class.
+ *
+ * Called on constructor.
+ */
+ void Init() { SetOverflowListener(BufferCandleOverflowListener, 10); }
+
+ public:
+ /* Constructors */
+
+ /**
+ * Constructor.
+ */
+ BufferCandle() { Init(); }
+ BufferCandle(BufferCandle& _right) {
+ THIS_REF = _right;
+ Init();
+ }
+
+ /* Callback methods */
+
+ /**
+ * Function should return true if resize can be made, or false to overwrite current slot.
+ */
+ static bool BufferCandleOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) {
+ static int cache_limit = 86400;
+ switch (_reason) {
+ case DICT_OVERFLOW_REASON_FULL:
+ // We allow resize if dictionary size is less than 86400 slots.
+ return _size < cache_limit;
+ case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS:
+ default:
+ // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused.
+ break;
+ }
+ return false;
+ }
+};
+
+#endif // BUFFER_CANDLE_H
diff --git a/Buffer/BufferTick.h b/Buffer/BufferTick.h
new file mode 100644
index 000000000..d3eb35dab
--- /dev/null
+++ b/Buffer/BufferTick.h
@@ -0,0 +1,169 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Prevents processing this includes file for the second time.
+#ifndef BUFFER_TICK_H
+#define BUFFER_TICK_H
+
+// Includes.
+#include "../BufferStruct.mqh"
+#include "../Chart.enum.h"
+#include "../Storage/IValueStorage.h"
+#include "../Tick.struct.h"
+
+template
+class BufferTickValueStorage : ValueStorage {
+ // Poiner to buffer to take tick from.
+ BufferTick *buffer_tick;
+
+ // PRICE_ASK or PRICE_BID.
+ int applied_price;
+
+ public:
+ /**
+ * Constructor.
+ */
+ BufferTickValueStorage(BufferTick *_buffer_tick, int _applied_price)
+ : buffer_tick(_buffer_tick), applied_price(_applied_price) {}
+
+ /**
+ * Fetches value from a given shift. Takes into consideration as-series flag.
+ */
+ TV Fetch(int _shift) override {
+ Print("BufferTickValueStorage: Fetching " + (applied_price == PRICE_ASK ? "Ask" : "Bid") + " price from shift ",
+ _shift);
+ return 0;
+ }
+
+ /**
+ * Returns number of values available to fetch (size of the values buffer).
+ */
+ int Size() const override { return (int)buffer_tick.Size(); }
+};
+
+/**
+ * Class to store struct data.
+ */
+template
+class BufferTick : public BufferStruct> {
+ protected:
+ // Ask prices ValueStorage proxy.
+ BufferTickValueStorage *_vs_ask;
+
+ // Bid prices ValueStorage proxy.
+ BufferTickValueStorage *_vs_bid;
+
+ protected:
+ /* Protected methods */
+
+ /**
+ * Initialize class.
+ *
+ * Called on constructor.
+ */
+ void Init() {
+ _vs_ask = NULL;
+ _vs_bid = NULL;
+ SetOverflowListener(BufferTickOverflowListener, 10);
+ }
+
+ public:
+ /* Constructors */
+
+ /**
+ * Constructor.
+ */
+ BufferTick() { Init(); }
+ BufferTick(BufferTick &_right) {
+ THIS_REF = _right;
+ Init();
+ }
+
+ /**
+ * Destructor.
+ */
+ ~BufferTick() {
+ if (_vs_ask != NULL) {
+ delete _vs_ask;
+ }
+ if (_vs_bid != NULL) {
+ delete _vs_bid;
+ }
+ }
+
+ /**
+ * Returns Ask prices ValueStorage proxy.
+ */
+ BufferTickValueStorage *GetAskValueStorage() {
+ if (_vs_ask == NULL) {
+ _vs_ask = new BufferTickValueStorage(THIS_PTR, PRICE_ASK);
+ }
+ return _vs_ask;
+ }
+
+ /**
+ * Returns Bid prices ValueStorage proxy.
+ */
+ BufferTickValueStorage *GetBidValueStorage() {
+ if (_vs_bid == NULL) {
+ _vs_bid = new BufferTickValueStorage(THIS_PTR, PRICE_BID);
+ }
+ return _vs_bid;
+ }
+
+ /* Grouping methods */
+
+ /**
+ * Group ticks by seconds.
+ */
+ DictStruct>> GroupBySecs(uint _spc) {
+ // DictStruct>> _result;
+ // @todo: for each iter
+ // for (DictStructIterator>> iter(Begin()); iter.IsValid(); ++iter) {
+ // Load timestamp from key, TickAB from value
+ // foreach some timestamp mod % _spc - calculate shift
+ // _result.Push(_shift, TickAB)
+ // Convert to OHLC in upper method
+ return NULL;
+ }
+
+ /* Callback methods */
+
+ /**
+ * Function should return true if resize can be made, or false to overwrite current slot.
+ */
+ static bool BufferTickOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) {
+ static int cache_limit = 86400;
+ switch (_reason) {
+ case DICT_OVERFLOW_REASON_FULL:
+ // We allow resize if dictionary size is less than 86400 slots.
+ return _size < cache_limit;
+ case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS:
+ default:
+ // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused.
+ break;
+ }
+ return false;
+ }
+};
+
+#endif // BUFFER_TICK_H
diff --git a/Buffer/tests/BufferCandle.test.mq4 b/Buffer/tests/BufferCandle.test.mq4
new file mode 100644
index 000000000..fe6c0a00d
--- /dev/null
+++ b/Buffer/tests/BufferCandle.test.mq4
@@ -0,0 +1,28 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @file
+ * Test functionality of BufferCandle class.
+ */
+
+// Includes.
+#include "BufferCandle.test.mq5"
diff --git a/Buffer/tests/BufferCandle.test.mq5 b/Buffer/tests/BufferCandle.test.mq5
new file mode 100644
index 000000000..ab76d8da8
--- /dev/null
+++ b/Buffer/tests/BufferCandle.test.mq5
@@ -0,0 +1,59 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @file
+ * Test functionality of BufferCandle class.
+ */
+
+// Includes
+#include "../../Test.mqh"
+#include "../BufferCandle.h"
+
+/**
+ * Implements OnInit().
+ */
+int OnInit() {
+ BufferCandle buffer1; // 128
+ CandleOHLC _ohlc_d; // 32
+ CandleOHLC _ohlc_f; // 16
+ CandleTOHLC _tohlc_d; // 32
+ CandleTOHLC _tohlc_f; // 16
+ // CandleEntry _centry_d; // 40
+ // CandleEntry _centry_f; // 24
+ Print("buffer1: ", sizeof(buffer1));
+ Print("_ohlc_d: ", sizeof(_ohlc_d));
+ Print("_ohlc_f: ", sizeof(_ohlc_f));
+ Print("_tohlc_d: ", sizeof(_tohlc_d));
+ Print("_tohlc_f: ", sizeof(_tohlc_f));
+ // @todo
+ return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED);
+}
+
+/**
+ * Implements OnTick().
+ */
+void OnTick() {}
+
+/**
+ * Implements OnDeinit().
+ */
+void OnDeinit(const int reason) {}
diff --git a/Buffer/tests/BufferTick.test.mq4 b/Buffer/tests/BufferTick.test.mq4
new file mode 100644
index 000000000..5a45ef4fa
--- /dev/null
+++ b/Buffer/tests/BufferTick.test.mq4
@@ -0,0 +1,28 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @file
+ * Test functionality of BufferTick class.
+ */
+
+// Includes.
+#include "BufferTick.test.mq5"
diff --git a/Buffer/tests/BufferTick.test.mq5 b/Buffer/tests/BufferTick.test.mq5
new file mode 100644
index 000000000..1daf2ea7b
--- /dev/null
+++ b/Buffer/tests/BufferTick.test.mq5
@@ -0,0 +1,57 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @file
+ * Test functionality of BufferTick class.
+ */
+
+// Includes
+#include "../../Test.mqh"
+#include "../BufferTick.h"
+
+/**
+ * Implements OnInit().
+ */
+int OnInit() {
+ MqlTick mql_tick; // 60
+ TickAB _tick_ab_d; // 16
+ TickAB _tick_ab_f; // 8
+ TickTAB _tick_tab_d; // 24
+ TickTAB _tick_tab_f; // 16
+ Print("mql_tick: ", sizeof(mql_tick));
+ Print("_tick_ab_d: ", sizeof(_tick_ab_d));
+ Print("_tick_ab_f: ", sizeof(_tick_ab_f));
+ Print("_tick_tab_d: ", sizeof(_tick_tab_d));
+ Print("_tick_tab_f: ", sizeof(_tick_tab_f));
+ // @todo
+ return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED);
+}
+
+/**
+ * Implements OnTick().
+ */
+void OnTick() {}
+
+/**
+ * Implements OnDeinit().
+ */
+void OnDeinit(const int reason) {}
diff --git a/Candle.struct.h b/Candle.struct.h
new file mode 100644
index 000000000..4d4e03dfb
--- /dev/null
+++ b/Candle.struct.h
@@ -0,0 +1,288 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+/**
+ * @file
+ * Includes Bar's structs.
+ */
+
+#ifndef __MQL__
+// Allows the preprocessor to include a header file when it is needed.
+#pragma once
+#endif
+
+// Forward class declaration.
+class Serializer;
+
+// Includes.
+#include "Bar.enum.h"
+#include "Chart.enum.h"
+#include "ISerializable.h"
+#include "Serializer.enum.h"
+#include "SerializerNode.enum.h"
+#include "Std.h"
+
+/* Structure for storing OHLC values. */
+template
+struct CandleOHLC
+#ifndef __MQL__
+ : public ISerializable
+#endif
+{
+ T open, high, low, close;
+
+ // Struct constructors.
+ CandleOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0) : open(_open), high(_high), low(_low), close(_close) {}
+ CandleOHLC(ARRAY_REF(T, _prices)) {
+ int _size = ArraySize(_prices);
+ close = _prices[0];
+ open = _prices[_size - 1];
+ high = fmax(close, open);
+ low = fmin(close, open);
+ for (int i = 0; i < _size; i++) {
+ high = fmax(high, _prices[i]);
+ low = fmin(low, _prices[i]);
+ }
+ }
+ // Struct methods.
+ // Getters
+ bool GetPivots(ENUM_PP_TYPE _type, T &_pp, T &_r1, T &_r2, T &_r3, T &_r4, T &_s1, T &_s2, T &_s3, T &_s4) {
+ T _range = GetRange();
+ switch (_type) {
+ case PP_CAMARILLA:
+ // A set of eight very probable levels which resemble support and resistance values for a current trend.
+ _pp = GetPivot();
+ _r1 = (T)(close + _range * 1.1 / 12);
+ _r2 = (T)(close + _range * 1.1 / 6);
+ _r3 = (T)(close + _range * 1.1 / 4);
+ _r4 = (T)(close + _range * 1.1 / 2);
+ _s1 = (T)(close - _range * 1.1 / 12);
+ _s2 = (T)(close - _range * 1.1 / 6);
+ _s3 = (T)(close - _range * 1.1 / 4);
+ _s4 = (T)(close - _range * 1.1 / 2);
+ break;
+ case PP_CLASSIC:
+ _pp = GetPivot();
+ _r1 = (2 * _pp) - low; // R1 = (H - L) * 1.1 / 12 + C (1.0833)
+ _r2 = _pp + _range; // R2 = (H - L) * 1.1 / 6 + C (1.1666)
+ _r3 = _pp + _range * 2; // R3 = (H - L) * 1.1 / 4 + C (1.25)
+ _r4 = _pp + _range * 3; // R4 = (H - L) * 1.1 / 2 + C (1.5)
+ _s1 = (2 * _pp) - high; // S1 = C - (H - L) * 1.1 / 12 (1.0833)
+ _s2 = _pp - _range; // S2 = C - (H - L) * 1.1 / 6 (1.1666)
+ _s3 = _pp - _range * 2; // S3 = C - (H - L) * 1.1 / 4 (1.25)
+ _s4 = _pp - _range * 3; // S4 = C - (H - L) * 1.1 / 2 (1.5)
+ break;
+ case PP_FIBONACCI:
+ _pp = GetPivot();
+ _r1 = (float)(_pp + 0.382 * _range);
+ _r2 = (float)(_pp + 0.618 * _range);
+ _r3 = _pp + _range;
+ _r4 = _r1 + _range; // ?
+ _s1 = (float)(_pp - 0.382 * _range);
+ _s2 = (float)(_pp - 0.618 * _range);
+ _s3 = _pp - _range;
+ _s4 = _s1 - _range; // ?
+ break;
+ case PP_FLOOR:
+ // Most basic and popular type of pivots used in Forex trading technical analysis.
+ _pp = GetPivot(); // Pivot (P) = (H + L + C) / 3
+ _r1 = (2 * _pp) - low; // Resistance (R1) = (2 * P) - L
+ _r2 = _pp + _range; // R2 = P + H - L
+ _r3 = high + 2 * (_pp - low); // R3 = H + 2 * (P - L)
+ _r4 = _r3;
+ _s1 = (2 * _pp) - high; // Support (S1) = (2 * P) - H
+ _s2 = _pp - _range; // S2 = P - H + L
+ _s3 = low - 2 * (high - _pp); // S3 = L - 2 * (H - P)
+ _s4 = _s3; // ?
+ break;
+ case PP_TOM_DEMARK:
+ // Tom DeMark's pivot point (predicted lows and highs of the period).
+ _pp = GetPivotDeMark();
+ _r1 = (2 * _pp) - low; // New High = X / 2 - L.
+ _r2 = _pp + _range;
+ _r3 = _r1 + _range;
+ _r4 = _r2 + _range; // ?
+ _s1 = (2 * _pp) - high; // New Low = X / 2 - H.
+ _s2 = _pp - _range;
+ _s3 = _s1 - _range;
+ _s4 = _s2 - _range; // ?
+ break;
+ case PP_WOODIE:
+ // Woodie's pivot point are giving more weight to the Close price of the previous period.
+ // They are similar to floor pivot points, but are calculated in a somewhat different way.
+ _pp = GetWeighted(); // Pivot (P) = (H + L + 2 * C) / 4
+ _r1 = (2 * _pp) - low; // Resistance (R1) = (2 * P) - L
+ _r2 = _pp + _range; // R2 = P + H - L
+ _r3 = _r1 + _range;
+ _r4 = _r2 + _range; // ?
+ _s1 = (2 * _pp) - high; // Support (S1) = (2 * P) - H
+ _s2 = _pp - _range; // S2 = P - H + L
+ _s3 = _s1 - _range;
+ _s4 = _s2 - _range; // ?
+ break;
+ default:
+ break;
+ }
+ return _r4 > _r3 && _r3 > _r2 && _r2 > _r1 && _r1 > _pp && _pp > _s1 && _s1 > _s2 && _s2 > _s3 && _s3 > _s4;
+ }
+ T GetAppliedPrice(ENUM_APPLIED_PRICE _ap) const { return CandleOHLC::GetAppliedPrice(_ap, open, high, low, close); }
+ T GetBody() const { return close - open; }
+ T GetBodyAbs() const { return fabs(close - open); }
+ T GetBodyInPct(int _hundreds = 100) const { return GetRange() > 0 ? _hundreds / GetRange() * GetBodyAbs() : 0; }
+ T GetChangeInPct(int _hundreds = 100) const { return (close - open) / open * _hundreds; }
+ T GetClose() const { return close; }
+ T GetHigh() const { return high; }
+ T GetLow() const { return low; }
+ T GetMaxOC() const { return fmax(open, close); }
+ T GetMedian() const { return (high + low) / 2; }
+ T GetMinOC() const { return fmin(open, close); }
+ T GetOpen() const { return open; }
+ T GetPivot() const { return GetTypical(); }
+ T GetPivotDeMark() const {
+ // If Close < Open Then X = H + 2 * L + C
+ // If Close > Open Then X = 2 * H + L + C
+ // If Close = Open Then X = H + L + 2 * C
+ T _pp = open > close ? (high + (2 * low) + close) / 4 : ((2 * high) + low + close) / 4;
+ return open == close ? (high + low + (2 * close)) / 4 : _pp;
+ }
+ T GetPivotWithOpen() const { return (open + high + low + close) / 4; }
+ T GetPivotWithOpen(float _open) const { return (_open + high + low + close) / 4; }
+ T GetRange() const { return high - low; }
+ T GetRangeChangeInPct(int _hundreds = 100) const { return _hundreds - (_hundreds / open * fabs(open - GetRange())); }
+ T GetRangeInPips(float _ppp) const { return GetRange() / _ppp; }
+ T GetTypical() const { return (high + low + close) / 3; }
+ T GetWeighted() const { return (high + low + close + close) / 4; }
+ T GetWickMin() const { return fmin(GetWickLower(), GetWickUpper()); }
+ T GetWickLower() const { return GetMinOC() - low; }
+ T GetWickLowerInPct() const { return GetRange() > 0 ? 100 / GetRange() * GetWickLower() : 0; }
+ T GetWickMax() const { return fmax(GetWickLower(), GetWickUpper()); }
+ T GetWickSum() const { return GetWickLower() + GetWickUpper(); }
+ T GetWickUpper() const { return high - GetMaxOC(); }
+ T GetWickUpperInPct() const { return GetRange() > 0 ? 100 / GetRange() * GetWickUpper() : 0; }
+ short GetType() const { return IsBull() ? 1 : (IsBear() ? -1 : 0); }
+ void GetValues(ARRAY_REF(T, _out)) {
+ ArrayResize(_out, 4);
+ int _index = ArraySize(_out) - 4;
+ _out[_index++] = open;
+ _out[_index++] = high;
+ _out[_index++] = low;
+ _out[_index++] = close;
+ }
+ static T GetAppliedPrice(ENUM_APPLIED_PRICE _ap, T _o, T _h, T _l, T _c) {
+ switch (_ap) {
+ case PRICE_CLOSE:
+ return _c;
+ case PRICE_OPEN:
+ return _o;
+ case PRICE_HIGH:
+ return _h;
+ case PRICE_LOW:
+ return _l;
+ case PRICE_MEDIAN:
+ return (_h + _l) / 2;
+ case PRICE_TYPICAL:
+ return (_h + _l + _c) / 3;
+ case PRICE_WEIGHTED:
+ return (_h + _l + _c + _c) / 4;
+ default:
+ return _o;
+ }
+ }
+ // State checkers.
+ bool IsBear() const { return open > close; }
+ bool IsBull() const { return open < close; }
+ bool IsValid() const { return high >= low && fmin(open, close) > 0; }
+ // Serializers.
+ SerializerNodeType Serialize(Serializer &s);
+ // Converters.
+ string ToCSV() { return StringFormat("%g,%g,%g,%g", open, high, low, close); }
+};
+
+/* Structure for storing OHLC values with open and close timestamp. */
+template
+struct CandleOCTOHLC : CandleOHLC {
+ long open_timestamp, close_timestamp;
+
+ // Struct constructors.
+ CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, long _open_timestamp = -1,
+ long _close_timestamp = -1)
+ : CandleOHLC(_open, _high, _low, _close), open_timestamp(_open_timestamp), close_timestamp(_close_timestamp) {}
+
+ // Updates OHLC values taking into consideration tick's timestamp.
+ void Update(long _timestamp, T _price) {
+ if (_timestamp < open_timestamp) {
+ open_timestamp = _timestamp;
+ open = _price;
+ }
+ if (_timestamp > close_timestamp) {
+ close_timestamp = _timestamp;
+ close = _price;
+ }
+ high = MathMax(high, _price);
+ low = MathMin(low, _price);
+ }
+
+ // Returns timestamp of open price.
+ long GetOpenTimestamp() { return open_timestamp; }
+
+ // Returns timestamp of close price.
+ long GetCloseTimestamp() { return close_timestamp; }
+};
+
+/* Structore for storing OHLC values with timestamp. */
+template
+struct CandleTOHLC : CandleOHLC {
+ datetime time;
+ // Struct constructors.
+ CandleTOHLC(datetime _time = 0, T _open = 0, T _high = 0, T _low = 0, T _close = 0)
+ : time(_time), CandleOHLC(_open, _high, _low, _close) {}
+ // Getters.
+ datetime GetTime() { return time; }
+ // Serializers.
+ SerializerNodeType Serialize(Serializer &s);
+ // Converters.
+ string ToCSV() { return StringFormat("%d,%g,%g,%g,%g", time, open, high, low, close); }
+};
+
+#include "Serializer.mqh"
+
+/* Method to serialize CandleEntry structure. */
+template
+SerializerNodeType CandleOHLC::Serialize(Serializer &s) {
+ // s.Pass(THIS_REF, "time", TimeToString(time));
+ s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC);
+ s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC);
+ s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC);
+ s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC);
+ return SerializerNodeObject;
+}
+
+/* Method to serialize CandleEntry structure. */
+template
+SerializerNodeType CandleTOHLC::Serialize(Serializer &s) {
+ s.Pass(THIS_REF, "time", time);
+ s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC);
+ s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC);
+ s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC);
+ s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC);
+ return SerializerNodeObject;
+}
diff --git a/Chart.enum.h b/Chart.enum.h
index e7e68247c..5835ba3da 100644
--- a/Chart.enum.h
+++ b/Chart.enum.h
@@ -43,9 +43,14 @@ enum ENUM_APPLIED_PRICE {
PRICE_MEDIAN, // Median price (H+L)/2
PRICE_TYPICAL, // Typical price, (H+L+C)/3
PRICE_WEIGHTED, // Weighted close price (H+L+C+C)/4
+ FINAL_APPLIED_PRICE_ENTRY
};
#endif
+// Additional modes for applied price.
+#define PRICE_ASK ((ENUM_APPLIED_PRICE)128)
+#define PRICE_BID ((ENUM_APPLIED_PRICE)129)
+
// Defines enumeration for chart parameters.
enum ENUM_CHART_PARAM {
CHART_PARAM_NONE = 0, // None
diff --git a/Chart.mqh b/Chart.mqh
index ba63a7750..356b734db 100644
--- a/Chart.mqh
+++ b/Chart.mqh
@@ -224,7 +224,7 @@ class Chart : public Market {
* @return
* Returns ChartEntry struct.
*/
- ChartEntry GetEntry(unsigned int _shift = 0) {
+ ChartEntry GetEntry(int _shift = 0) {
ChartEntry _chart_entry;
BarOHLC _ohlc = GetOHLC(_shift);
if (_ohlc.open > 0) {
diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h
index 49c7c88f3..7074f67e8 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 {
@@ -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/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..55b6f4130 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);
diff --git a/Indicator.define.h b/Indicator.define.h
index d5056e91f..ab51a433d 100644
--- a/Indicator.define.h
+++ b/Indicator.define.h
@@ -44,7 +44,7 @@
SET_HANDLE; \
} \
if (Terminal::IsVisualMode()) { \
- int _bars_calc = BarsCalculated(_handle); \
+ int _bars_calc = ::BarsCalculated(_handle); \
if (GetLastError() > 0) { \
return EMPTY_VALUE; \
} else if (_bars_calc <= 2) { \
diff --git a/Indicator.enum.h b/Indicator.enum.h
index 375064b34..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.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..478b4c4c2 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).
@@ -684,18 +427,10 @@ class IndicatorBase : public Chart {
Chart::Set(_param, _value);
}
- /**
- * Sets an indicator's state property value.
- */
- template
- void Set(STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) _prop, T _value) {
- istate.Set(_prop, _value);
- }
-
/**
* Sets 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,89 +454,23 @@ 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);
+ void RemoveListener(IndicatorBase* _indi) {
+ WeakRef _ref = _indi;
+ Util::ArrayRemoveFirst(listeners, _ref);
}
- bool ExecuteAction(ENUM_INDICATOR_ACTION _action, long _arg1) {
- ARRAY(DataParamEntry, _args);
- DataParamEntry _param1 = _arg1;
- ArrayPushObject(_args, _param1);
- _args[0].integer_value = _arg1;
- return ExecuteAction(_action, _args);
- }
-
- /* Other methods */
/**
* Releases indicator's handle.
@@ -818,120 +487,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 +587,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 +598,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 +609,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 +643,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 +663,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 +744,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 +780,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/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