diff --git a/.github/workflows/cleanup.yml b/.github/workflows/cleanup.yml
new file mode 100644
index 000000000..cc033f27f
--- /dev/null
+++ b/.github/workflows/cleanup.yml
@@ -0,0 +1,23 @@
+---
+name: Clean-up
+
+# yamllint disable-line rule:truthy
+on:
+ workflow_call:
+ inputs:
+ artifact_prefix:
+ default: mt
+ description: Artifact prefix to clean up.
+ required: false
+ type: string
+
+jobs:
+
+ cleanup:
+ name: Clean-up
+ runs-on: ubuntu-latest
+ steps:
+ - uses: geekyeggo/delete-artifact@v5
+ with:
+ name: ${{ inputs.artifact_prefix }}*
+ timeout-minutes: 5
diff --git a/.github/workflows/compile-cpp.yml b/.github/workflows/compile-cpp.yml
new file mode 100644
index 000000000..085b4f3e0
--- /dev/null
+++ b/.github/workflows/compile-cpp.yml
@@ -0,0 +1,44 @@
+---
+name: Compile C++
+
+# yamllint disable-line rule:truthy
+on:
+ pull_request:
+ paths-ignore:
+ - '**.md'
+ push:
+ paths-ignore:
+ - '**.md'
+
+jobs:
+
+ FileList:
+ outputs:
+ filelist: ${{ steps.get-files.outputs.filelist }}
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set output with list of files
+ id: get-files
+ run: |
+ import glob, json, os
+ files = glob.glob("**/tests/*.cpp")
+ print("::set-output name=filelist::{}".format(json.dumps(files)))
+ shell: python
+ - name: Display output
+ run: echo ${{ steps.get-files.outputs.filelist }}
+
+ Compile:
+ runs-on: ubuntu-latest
+ needs: [FileList]
+ strategy:
+ matrix:
+ file: ${{ fromJson(needs.FileList.outputs.filelist) }}
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install compiler
+ uses: rlalik/setup-cpp-compiler@v1.1
+ with:
+ compiler: gcc-latest
+ - name: Compile ${{ matrix.file }}
+ run: g++ "${{ matrix.file }}"
diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml
index f6efc2b35..a5b9c6875 100644
--- a/.github/workflows/compile.yml
+++ b/.github/workflows/compile.yml
@@ -91,8 +91,4 @@ jobs:
if: inputs.skip_cleanup != true
name: Clean-up
needs: [compile]
- runs-on: ubuntu-latest
- steps:
- - uses: geekyeggo/delete-artifact@v5
- with:
- name: ${{ env.ARTIFACT_PREFIX }}*
+ uses: ./.github/workflows/cleanup.yml
diff --git a/.github/workflows/test-account.yml b/.github/workflows/test-account.yml
index c2a6cccbe..bc240f5d1 100644
--- a/.github/workflows/test-account.yml
+++ b/.github/workflows/test-account.yml
@@ -44,3 +44,8 @@ jobs:
with:
Script: ${{ matrix.test }}
timeout-minutes: 10
+
+ cleanup:
+ name: Clean-up
+ needs: [compile]
+ uses: ./.github/workflows/cleanup.yml
diff --git a/.github/workflows/test-buffer.yml b/.github/workflows/test-buffer.yml
index 140293213..82b627a14 100644
--- a/.github/workflows/test-buffer.yml
+++ b/.github/workflows/test-buffer.yml
@@ -44,3 +44,8 @@ jobs:
with:
Script: ${{ matrix.test }}
timeout-minutes: 10
+
+ cleanup:
+ name: Clean-up
+ needs: [compile]
+ uses: ./.github/workflows/cleanup.yml
diff --git a/.github/workflows/test-exchange.yml b/.github/workflows/test-exchange.yml
new file mode 100644
index 000000000..408fb5ed0
--- /dev/null
+++ b/.github/workflows/test-exchange.yml
@@ -0,0 +1,47 @@
+---
+name: Test Exchange
+
+# yamllint disable-line rule:truthy
+on:
+ pull_request:
+ paths:
+ - 'Exchange/**.h'
+ - 'Exchange/**.mq?'
+ - '.github/workflows/test-exchange.yml'
+ push:
+ paths:
+ - 'Exchange/**.h'
+ - 'Exchange/**.mq?'
+ - '.github/workflows/test-exchange.yml'
+
+jobs:
+
+ compile:
+ name: Compile
+ uses: ./.github/workflows/compile.yml
+ with:
+ artifact_prefix: mt
+ path: Exchange
+ skip_cleanup: true
+
+ Exchange-Tests-MQL4:
+ defaults:
+ run:
+ shell: bash
+ working-directory: Exchange/tests
+ if: false
+ needs: compile
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ test:
+ - Exchange.test
+ steps:
+ - uses: actions/download-artifact@v2
+ with:
+ name: files-ex4
+ - name: Run ${{ matrix.test }}
+ uses: fx31337/mql-tester-action@master
+ with:
+ Script: ${{ matrix.test }}
+ timeout-minutes: 10
diff --git a/.github/workflows/test-indicator.yml b/.github/workflows/test-indicator.yml
index 4a89f6a28..a3900e527 100644
--- a/.github/workflows/test-indicator.yml
+++ b/.github/workflows/test-indicator.yml
@@ -50,3 +50,8 @@ jobs:
BtYears: 2020
TestExpert: ${{ matrix.test }}
timeout-minutes: 10
+
+ cleanup:
+ name: Clean-up
+ needs: [compile]
+ uses: ./.github/workflows/cleanup.yml
diff --git a/.github/workflows/test-indicators-special.yml b/.github/workflows/test-indicators-special.yml
index 4198d8d66..50cbfe1f6 100644
--- a/.github/workflows/test-indicators-special.yml
+++ b/.github/workflows/test-indicators-special.yml
@@ -48,3 +48,8 @@ jobs:
BtYears: 2020
TestExpert: ${{ matrix.test }}
timeout-minutes: 10
+
+ cleanup:
+ name: Clean-up
+ needs: [compile]
+ uses: ./.github/workflows/cleanup.yml
diff --git a/.github/workflows/test-indicators-tick.yml b/.github/workflows/test-indicators-tick.yml
index de3ca8db4..516ade6ea 100644
--- a/.github/workflows/test-indicators-tick.yml
+++ b/.github/workflows/test-indicators-tick.yml
@@ -48,3 +48,8 @@ jobs:
BtYears: 2020
TestExpert: ${{ matrix.test }}
timeout-minutes: 10
+
+ cleanup:
+ name: Clean-up
+ needs: [compile]
+ uses: ./.github/workflows/cleanup.yml
diff --git a/.github/workflows/test-indicators.yml b/.github/workflows/test-indicators.yml
index 0e10579d0..ea3df37e8 100644
--- a/.github/workflows/test-indicators.yml
+++ b/.github/workflows/test-indicators.yml
@@ -113,3 +113,8 @@ jobs:
BtYears: 2020
TestExpert: ${{ matrix.test }}
timeout-minutes: 10
+
+ cleanup:
+ name: Clean-up
+ needs: [compile]
+ uses: ./.github/workflows/cleanup.yml
diff --git a/.github/workflows/test-tick.yml b/.github/workflows/test-tick.yml
index 5e5770b60..335a30a51 100644
--- a/.github/workflows/test-tick.yml
+++ b/.github/workflows/test-tick.yml
@@ -42,3 +42,8 @@ jobs:
uses: fx31337/mql-tester-action@master
with:
Script: ${{ matrix.test }}
+
+ cleanup:
+ name: Clean-up
+ needs: [compile]
+ uses: ./.github/workflows/cleanup.yml
diff --git a/.github/workflows/test-trade.yml b/.github/workflows/test-trade.yml
index b5c83391a..6c4dd0c95 100644
--- a/.github/workflows/test-trade.yml
+++ b/.github/workflows/test-trade.yml
@@ -44,3 +44,8 @@ jobs:
with:
Script: ${{ matrix.test }}
timeout-minutes: 10
+
+ cleanup:
+ name: Clean-up
+ needs: [compile]
+ uses: ./.github/workflows/cleanup.yml
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 1094421a8..a222d90a5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -47,7 +47,7 @@ jobs:
- CompileIndicatorsTest
- ConditionTest
- DatabaseTest
- - DrawIndicatorTest
+ # - DrawIndicatorTest
- EATest
- IndicatorDataTest
- IndicatorTest
@@ -163,3 +163,8 @@ jobs:
with:
Script: ${{ matrix.test }}
timeout-minutes: 10
+
+ cleanup:
+ name: Clean-up
+ needs: [compile]
+ uses: ./.github/workflows/cleanup.yml
diff --git a/Account.mqh b/Account.mqh
index 49578410f..8c0393ef4 100644
--- a/Account.mqh
+++ b/Account.mqh
@@ -30,6 +30,7 @@ class Account;
// Includes.
#include "Account/Account.define.h"
#include "Account/Account.enum.h"
+#include "Account/Account.extern.h"
#include "Account/Account.struct.h"
#include "Array.mqh"
#include "BufferStruct.mqh"
@@ -63,6 +64,11 @@ class Account {
*/
Account() : init_balance(CalcInitDeposit()), start_balance(GetBalance()), start_credit(GetCredit()) {}
+ /**
+ * Class copy constructor.
+ */
+ Account(const Account &_account) {}
+
/**
* Class deconstructor.
*/
diff --git a/Account/Account.extern.h b/Account/Account.extern.h
new file mode 100644
index 000000000..28aa8909d
--- /dev/null
+++ b/Account/Account.extern.h
@@ -0,0 +1,29 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2022, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Includes.
+#include "Account.enum.h"
+
+// Define external global functions.
+#ifndef __MQL__
+extern string AccountInfoString(ENUM_ACCOUNT_INFO_STRING property_id);
+#endif
diff --git a/Account/Account.struct.h b/Account/Account.struct.h
index 63c4ca53a..7f70c1498 100644
--- a/Account/Account.struct.h
+++ b/Account/Account.struct.h
@@ -36,6 +36,7 @@ class Serializer;
// Includes.
#include "../Serializer.mqh"
+#include "../Terminal.define.h"
// Struct for account entries.
struct AccountEntry {
diff --git a/Account/AccountBase.struct.h b/Account/AccountBase.struct.h
index 535d3cae7..f58e25e7f 100644
--- a/Account/AccountBase.struct.h
+++ b/Account/AccountBase.struct.h
@@ -36,6 +36,7 @@ class Serializer;
// Includes.
#include "../Serializer.mqh"
+#include "../Terminal.define.h"
// Struct for account entries.
struct AccountBaseEntry {
diff --git a/Account/AccountForex.struct.h b/Account/AccountForex.struct.h
index 9bf5c8901..64aacffa3 100644
--- a/Account/AccountForex.struct.h
+++ b/Account/AccountForex.struct.h
@@ -36,6 +36,7 @@ class Serializer;
// Includes.
#include "../Serializer.mqh"
+#include "../Terminal.define.h"
// Struct for account entries.
struct AccountForexEntry : public AccountBaseEntry {
diff --git a/Account/tests/Account.test.mq5 b/Account/tests/Account.test.mq5
index 6ed1a1263..a52e8c076 100644
--- a/Account/tests/Account.test.mq5
+++ b/Account/tests/Account.test.mq5
@@ -35,7 +35,7 @@ int OnInit() {
bool _result = true;
Account acc1;
// ...
- return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED;
+ return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED;
}
/**
diff --git a/Account/tests/AccountForex.test.mq5 b/Account/tests/AccountForex.test.mq5
index 826aa4235..fb10957ea 100644
--- a/Account/tests/AccountForex.test.mq5
+++ b/Account/tests/AccountForex.test.mq5
@@ -35,7 +35,7 @@ int OnInit() {
bool _result = true;
Account acc1;
// ...
- return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED;
+ return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED;
}
/**
diff --git a/Array.extern.h b/Array.extern.h
new file mode 100644
index 000000000..b09748d67
--- /dev/null
+++ b/Array.extern.h
@@ -0,0 +1,57 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2022, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Define external global functions.
+#ifndef __MQL__
+#pragma once
+
+template
+extern int ArraySize(const ARRAY_REF(T, _array));
+
+template
+extern constexpr int ArraySize(const T REF(_array)[size]);
+
+template
+extern int ArrayResize(ARRAY_REF(T, _array), int _new_size, int _reserve_size = 0);
+
+template
+extern bool ArraySetAsSeries(ARRAY_REF(T, _array), bool _flag);
+
+template
+extern int ArrayMaximum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY);
+
+template
+extern int ArrayMinimum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY);
+
+template
+extern int ArrayFree(const ARRAY_REF(T, _array));
+
+template
+extern int ArrayReverse(const ARRAY_REF(T, _array));
+
+template
+extern int ArrayInitialize(ARRAY_REF(T, array), char value);
+
+template
+extern int ArraySort(ARRAY_REF(T, array));
+
+#endif
diff --git a/Array.mqh b/Array.mqh
index e07e0d0a2..c844c8c4e 100644
--- a/Array.mqh
+++ b/Array.mqh
@@ -26,7 +26,12 @@
#endif
// Includes.
+#include "Array.extern.h"
+#include "Common.extern.h"
+#include "Convert.extern.h"
+#include "Math.extern.h"
#include "Std.h"
+#include "String.extern.h"
// Defines.
#ifndef MODE_ASCEND
@@ -529,7 +534,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) {
*/
template
void ArrayPrint(ARRAY_REF(T, _arr), // Printed array.
- int _digits = NULL, // Number of decimal places.
+ int _digits = 0, // Number of decimal places.
const string _dlm = NULL, // Separator of the structure field values.
long _start = 0, // First printed element index.
long _count = WHOLE_ARRAY, // Number of printed elements.
@@ -539,7 +544,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) {
#else
int i;
string output = "";
- for (i = _start; i < _count == WHOLE_ARRAY ? ArraySize(_arr) : _count; i++) {
+ for (i = _start; i < (_count == WHOLE_ARRAY ? ArraySize(_arr) : _count); i++) {
output += (string)_arr[i] + _dlm;
}
Print(output);
@@ -635,7 +640,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) {
* if error occured).
*/
template
- static int ArrayResizeFill(ARRAY_REF(X, array), int new_size, int reserve_size = 0, Y fill_value = EMPTY_VALUE) {
+ static int ArrayResizeFill(ARRAY_REF(X, array), int new_size, int reserve_size = 0, Y fill_value = NULL) {
const int old_size = ArrayRange(array, 0);
if (new_size <= old_size) return old_size;
@@ -686,7 +691,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) {
* - https://www.mql5.com/en/docs/array/arraymaximum
*/
template
- static int ArrayMinimum(const ARRAY_REF(X, _array), int _start = 0, int _count = WHOLE_ARRAY) {
+ static int ArrayMinimum(ARRAY_REF(X, _array), int _start = 0, int _count = WHOLE_ARRAY) {
#ifdef __MQL__
return ::ArrayMinimum(_array);
#else
@@ -719,7 +724,7 @@ static int GetLowestArrDoubleValue(double& arr[][], int key) {
* - https://www.mql5.com/en/docs/array/arraymaximum
*/
template
- static int ArrayMaximum(const ARRAY_REF(X, _array), int start = 0, int count = WHOLE_ARRAY) {
+ static int ArrayMaximum(ARRAY_REF(X, _array), int start = 0, int count = WHOLE_ARRAY) {
#ifdef __MQL__
return ::ArrayMaximum(_array);
#else
diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h
index 70231bf47..521ea3e6c 100644
--- a/Chart.struct.tf.h
+++ b/Chart.struct.tf.h
@@ -33,6 +33,7 @@
// Includes.
#include "Chart.enum.h"
#include "Serializer.mqh"
+#include "Terminal.define.h"
/* Defines struct for chart timeframe. */
struct ChartTf {
diff --git a/Common.define.h b/Common.define.h
new file mode 100644
index 000000000..09f7d754a
--- /dev/null
+++ b/Common.define.h
@@ -0,0 +1,35 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2022, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+/**
+ * @file
+ * Defines common defines.
+ */
+#ifndef __MQL__
+// Data types.
+#include
+typedef std::string string;
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+#endif
diff --git a/Common.extern.h b/Common.extern.h
new file mode 100644
index 000000000..2092a4c16
--- /dev/null
+++ b/Common.extern.h
@@ -0,0 +1,47 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2022, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Define external global functions.
+#ifndef __MQL__
+#pragma once
+#include "Chart.enum.h"
+#include "DateTime.enum.h"
+
+extern void DebugBreak();
+// Errors.
+extern void SetUserError(ushort user_error);
+// Exceptions.
+extern int NotImplementedException();
+// Print-related functions.
+template
+extern std::string StringFormat(const std::string& format, Args... args);
+
+template
+extern std::string PrintFormat(const std::string& format, Args... args);
+
+template
+extern void Print(Args... args);
+
+template
+extern void Alert(Args... args);
+
+#endif
diff --git a/Condition.mqh b/Condition.mqh
index 862d20264..9118becab 100644
--- a/Condition.mqh
+++ b/Condition.mqh
@@ -109,13 +109,13 @@ class Condition {
if (_entry.IsActive()) {
switch (_entry.next_statement) {
case COND_AND:
- _curr_result = _prev_result && this.Test(_entry);
+ _curr_result = _prev_result && this PTR_DEREF Test(_entry);
break;
case COND_OR:
- _curr_result = _prev_result || this.Test(_entry);
+ _curr_result = _prev_result || this PTR_DEREF Test(_entry);
break;
case COND_SEQ:
- _curr_result = this.Test(_entry);
+ _curr_result = this PTR_DEREF Test(_entry);
if (!_curr_result) {
// Do not check further conditions when the current condition is false.
return false;
diff --git a/Convert.extern.h b/Convert.extern.h
new file mode 100644
index 000000000..353a96b6b
--- /dev/null
+++ b/Convert.extern.h
@@ -0,0 +1,34 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2022, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Prevents processing this includes file for the second time.
+#ifndef __MQL__
+#pragma once
+#endif
+
+// Define external global functions.
+#ifndef __MQL__
+extern double NormalizeDouble(double value, int digits);
+extern string CharToString(uchar char_code);
+extern string DoubleToString(double value, int digits = 8);
+extern string ShortToString(ushort symbol_code);
+#endif
diff --git a/Convert.mqh b/Convert.mqh
index 22352cfa2..9c0fbae7e 100644
--- a/Convert.mqh
+++ b/Convert.mqh
@@ -24,11 +24,20 @@
#ifndef CONVERT_MQH
#define CONVERT_MQH
+// Prevents processing this includes file for the second time.
+#ifndef __MQL__
+#pragma once
+#endif
+
// Includes.
#include "Account/Account.enum.h"
+#include "Account/Account.extern.h"
#include "Array.mqh"
+#include "Convert.extern.h"
+#include "Math.extern.h"
#include "Order.enum.h"
#include "SymbolInfo.enum.h"
+#include "SymbolInfo.extern.h"
#include "SymbolInfo.struct.static.h"
/**
@@ -58,7 +67,7 @@ class Convert {
case ORDER_TYPE_BUY_STOP:
return ORDER_TYPE_BUY;
default:
- return (ENUM_ORDER_TYPE)WRONG_VALUE;
+ return InvalidEnumValue::value();
}
}
@@ -73,7 +82,7 @@ class Convert {
* Returns OP_BUY when value is positive, OP_SELL when negative, otherwise -1.
*/
static ENUM_ORDER_TYPE ValueToOp(int value) {
- return value == 0 ? (ENUM_ORDER_TYPE)-1 : (value > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL);
+ return value == 0 ? InvalidEnumValue::value() : (value > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL);
}
/**
@@ -87,13 +96,13 @@ class Convert {
* Returns OP_BUY when value is positive, OP_SELL when negative, otherwise -1.
*/
static ENUM_ORDER_TYPE ValueToOp(double value) {
- return value == 0 ? (ENUM_ORDER_TYPE)-1 : (value > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL);
+ return value == 0 ? InvalidEnumValue::value() : (value > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL);
}
/**
* Points per pip given digits after decimal point of a symbol price.
*/
- static uint PointsPerPip(uint digits) { return (uint)pow(10, digits - (digits < 4 ? 2 : 4)); }
+ static uint PointsPerPip(uint digits) { return (uint)pow((unsigned int)10, digits - (digits < 4 ? 2 : 4)); }
/**
* Returns number of points per pip.
@@ -172,19 +181,19 @@ class Convert {
switch (mode) {
case 0: // Forex.
// In currencies a tick is a point.
- return pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE);
+ return (double)pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE);
case 1: // CFD.
// In metals a Tick is still the smallest change, but is larger than a point.
// If price can change from 123.25 to 123.50,
// you have a TickSize of 0.25 and a point of 0.01. Pip has no meaning.
// @todo
- return pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE);
+ return (double)pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE);
case 2: // Futures.
// @todo
- return pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE);
+ return (double)pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE);
case 3: // CFD for indices.
// @todo
- return pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE);
+ return (double)pts * SymbolInfoStatic::SymbolInfoDouble(_symbol, SYMBOL_TRADE_TICK_SIZE);
}
return false;
}
@@ -243,7 +252,7 @@ class Convert {
/**
* Get the difference between two price values (in pips).
*/
- static double GetValueDiffInPips(double price1, double price2, bool abs = false, int digits = NULL,
+ static double GetValueDiffInPips(double price1, double price2, bool abs = false, int digits = 0,
string _symbol = NULL) {
digits = digits ? digits : (int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS);
return ValueToPips(abs ? fabs(price1 - price2) : (price1 - price2), digits);
@@ -263,7 +272,7 @@ class Convert {
else if (currency == "EUR")
sign = (unsigned char)0x80; // ANSI code.
else {
- sign = NULL;
+ sign = ' ';
prefix = false;
}
return prefix ? CharToString(sign) + DoubleToString(value, digits)
diff --git a/DateTime.extern.h b/DateTime.extern.h
new file mode 100644
index 000000000..87d156d81
--- /dev/null
+++ b/DateTime.extern.h
@@ -0,0 +1,79 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2022, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Includes.
+#include "DateTime.enum.h"
+
+/**
+ * @file
+ * Includes external declarations related to date and time.
+ */
+#ifndef __MQL__
+#pragma once
+// Forward declarations.
+struct MqlDateTime;
+
+/**
+ * MQL's "datetime" type.
+ */
+class datetime {
+ time_t dt;
+
+ public:
+ datetime();
+ datetime(const long& _time);
+ datetime(const int& _time);
+ bool operator==(const int& _time) const;
+ bool operator==(const datetime& _time) const;
+ bool operator<(const int& _time) const;
+ bool operator>(const int& _time) const;
+ bool operator<(const datetime& _time);
+ bool operator>(const datetime& _time);
+ operator long() const;
+};
+
+extern datetime TimeCurrent();
+extern datetime TimeCurrent(MqlDateTime& dt_struct);
+
+extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count,
+ ARRAY_REF(datetime, time_array));
+
+extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, datetime start_time, int count,
+ ARRAY_REF(datetime, time_array));
+
+extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, datetime start_time, datetime stop_time,
+ ARRAY_REF(datetime, time_array));
+
+extern datetime StructToTime(MqlDateTime& dt_struct);
+extern bool TimeToStruct(datetime dt, MqlDateTime& dt_struct);
+extern datetime TimeGMT();
+extern datetime TimeGMT(MqlDateTime& dt_struct);
+extern datetime TimeTradeServer();
+extern datetime TimeTradeServer(MqlDateTime& dt_struct);
+extern datetime StringToTime(const string& value);
+extern string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES);
+
+template
+extern datetime operator"" _D();
+
+#define DATETIME_LITERAL(STR) _D " ## STR ## "
+#endif
diff --git a/DateTime.mqh b/DateTime.mqh
index 49502d55f..fd26c7021 100644
--- a/DateTime.mqh
+++ b/DateTime.mqh
@@ -40,6 +40,7 @@ struct DataParamEntry;
#include "Array.mqh"
#include "Data.struct.h"
#include "DateTime.enum.h"
+#include "DateTime.extern.h"
#include "DateTime.struct.h"
#ifndef __MQL4__
@@ -113,9 +114,14 @@ class DateTime {
_result |= DATETIME_SECOND;
}
- if (dt_curr.GetValue(DATETIME_DAY | DATETIME_WEEK) != dt_last.GetValue(DATETIME_DAY | DATETIME_WEEK)) {
- // New week started.
- _result |= DATETIME_WEEK;
+ if (dt_curr.GetValue(DATETIME_DAY | DATETIME_WEEK) == 0) {
+ // It's the first day of the week (Sunday).
+ // Note that GetValue() for the above flags just returns value of GetDayOfWeek().
+ // @see https://docs.mql4.com/dateandtime/dayofweek
+ if (dt_curr.GetValue(DATETIME_DAY | DATETIME_WEEK) != dt_last.GetValue(DATETIME_DAY | DATETIME_WEEK)) {
+ // New week started.
+ _result |= DATETIME_WEEK;
+ }
}
#ifdef __debug__
diff --git a/Dict.enum.h b/Dict.enum.h
index 33887918c..080a50271 100644
--- a/Dict.enum.h
+++ b/Dict.enum.h
@@ -32,3 +32,24 @@
#define DICT_GROW_UP_PERCENT_DEFAULT 25
#define DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS 10
+
+/**
+ * Whether Dict operates in yet uknown mode, as dict or as list.
+ */
+enum DictMode { DictModeUnknown, DictModeDict, DictModeList };
+
+/**
+ * Reason of call to overflow listener.
+ */
+enum ENUM_DICT_OVERFLOW_REASON {
+ DICT_OVERFLOW_REASON_FULL,
+ DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS,
+};
+
+/**
+ * Dictionary flags.
+ */
+enum ENUM_DICT_FLAG {
+ DICT_FLAG_NONE = 0,
+ DICT_FLAG_FILL_HOLES_UNSORTED = 1,
+};
diff --git a/Dict.mqh b/Dict.mqh
index 26bd9705a..4a3b2ec04 100644
--- a/Dict.mqh
+++ b/Dict.mqh
@@ -28,6 +28,7 @@
#include "DictBase.mqh"
#include "Matrix.mqh"
#include "Serializer.mqh"
+#include "SerializerNodeIterator.mqh"
template
class DictIterator : public DictIteratorBase {
diff --git a/DictBase.mqh b/DictBase.mqh
index 6e80dd8ed..7993e1afc 100644
--- a/DictBase.mqh
+++ b/DictBase.mqh
@@ -31,27 +31,6 @@
#include "DictSlot.mqh"
#include "Serializer.mqh"
-/**
- * Whether Dict operates in yet uknown mode, as dict or as list.
- */
-enum DictMode { DictModeUnknown, DictModeDict, DictModeList };
-
-/**
- * Reason of call to overflow listener.
- */
-enum ENUM_DICT_OVERFLOW_REASON {
- DICT_OVERFLOW_REASON_FULL,
- DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS,
-};
-
-/**
- * Dictionary flags.
- */
-enum ENUM_DICT_FLAG {
- DICT_FLAG_NONE = 0,
- DICT_FLAG_FILL_HOLES_UNSORTED = 1,
-};
-
/**
* Dictionary overflow listener. arguments are:
* - ENUM_DICT_OVERFLOW_REASON overflow_reason
@@ -225,7 +204,7 @@ class DictBase {
if (_DictSlots_ref.DictSlots[position].IsUsed()) {
if (GetMode() == DictModeList) {
- _should_be_removed = position == (int)key;
+ _should_be_removed = position == (unsigned int)key;
} else {
_should_be_removed =
_DictSlots_ref.DictSlots[position].HasKey() && _DictSlots_ref.DictSlots[position].key == key;
@@ -274,7 +253,7 @@ class DictBase {
*/
void FillHoleUnsorted(int _hole_slot_idx) {
// After moving last element to fill the hole we
- if (_hole_slot_idx == Size() - 1) {
+ if ((unsigned int)_hole_slot_idx == Size() - 1) {
// We've just removed last element, thus don't need to do anything.
} else {
// Moving last slot into given one.
@@ -378,10 +357,10 @@ class DictBase {
* Specialization of hashing function.
*/
unsigned int Hash(const string& x) {
- unsigned char c[];
+ ARRAY(unsigned char, c);
unsigned int h = 0;
- if (x != NULL) {
+ if (!IsNull(x)) {
h = 5381;
int n = StringToCharArray(x, c);
for (int i = 0; i < n; i++) {
diff --git a/DictIteratorBase.mqh b/DictIteratorBase.mqh
index 16fafb8a8..329fc5cb8 100644
--- a/DictIteratorBase.mqh
+++ b/DictIteratorBase.mqh
@@ -60,7 +60,7 @@ class DictIteratorBase {
*/
DictIteratorBase(const DictIteratorBase& right)
: _dict(right._dict),
- _hash(right._dict ? right._dict.GetHash() : 0),
+ _hash(right._dict ? right._dict PTR_DEREF GetHash() : 0),
_slotIdx(right._slotIdx),
_index(right._index) {
_invalid_until_incremented = false;
@@ -75,24 +75,24 @@ class DictIteratorBase {
++_index;
_invalid_until_incremented = false;
- DictSlot* slot = _dict.GetSlot(_slotIdx);
+ DictSlot* slot = _dict PTR_DEREF GetSlot(_slotIdx);
// Iterating until we find valid, used slot.
- while (slot != NULL && !slot.IsUsed()) {
- slot = _dict.GetSlot(++_slotIdx);
+ while (slot != NULL && !slot PTR_DEREF IsUsed()) {
+ slot = _dict PTR_DEREF GetSlot(++_slotIdx);
}
- if (!slot || !slot.IsValid()) {
+ if (!slot || !slot PTR_DEREF IsValid()) {
// Invalidating iterator.
_dict = NULL;
}
}
- bool HasKey() { return _dict.GetSlot(_slotIdx).HasKey(); }
+ bool HasKey() { return _dict PTR_DEREF GetSlot(_slotIdx) PTR_DEREF HasKey(); }
K Key() {
CheckValidity();
- return _dict.GetMode() == DictModeList ? (K)_slotIdx : _dict.GetSlot(_slotIdx).key;
+ return PTR_ATTRIB(_dict, GetMode()) == DictModeList ? (K)_slotIdx : _dict PTR_DEREF GetSlot(_slotIdx) PTR_DEREF key;
}
string KeyAsString(bool includeQuotes = false) {
@@ -106,7 +106,7 @@ class DictIteratorBase {
V Value() {
CheckValidity();
- return _dict.GetSlot(_slotIdx).value;
+ return _dict PTR_DEREF GetSlot(_slotIdx) PTR_DEREF value;
}
void CheckValidity() {
@@ -121,15 +121,15 @@ class DictIteratorBase {
bool IsLast() {
if (!IsValid()) return true;
- if (_dict.GetMode() == DictModeUnknown || _dict.Size() == 0) {
+ if (_dict PTR_DEREF GetMode() == DictModeUnknown || _dict.Size() == 0) {
return false;
}
- if (_dict.GetMode() != DictModeList) {
+ if (_dict PTR_DEREF GetMode() != DictModeList) {
Alert("Dict iterator's IsLast() method may be used only when elements are added via Push() method.");
}
- return _index == _dict.Size() - 1;
+ return _index == _dict PTR_DEREF Size() - 1;
}
void ShiftPosition(int shift, bool invalid_until_incremented = false) {
diff --git a/DictObject.mqh b/DictObject.mqh
index 59ba0410a..fbfd681aa 100644
--- a/DictObject.mqh
+++ b/DictObject.mqh
@@ -27,6 +27,7 @@
#include "Convert.mqh"
#include "DictBase.mqh"
#include "Serializer.mqh"
+#include "SerializerNodeIterator.mqh"
template
class DictObjectIterator : public DictIteratorBase {
@@ -39,14 +40,14 @@ class DictObjectIterator : public DictIteratorBase {
/**
* Constructor.
*/
- DictObjectIterator(DictBase& dict, unsigned int slotIdx) : DictIteratorBase(dict, slotIdx) {}
+ DictObjectIterator(DictBase& dict, unsigned int slotIdx) : DictIteratorBase(dict, slotIdx) {}
/**
* Copy constructor.
*/
- DictObjectIterator(const DictObjectIterator& right) : DictIteratorBase(right) {}
+ DictObjectIterator(const DictObjectIterator& right) : DictIteratorBase(right) {}
- V* Value() { return &_dict.GetSlot(_slotIdx).value; }
+ V* Value() { return &(this PTR_DEREF _dict PTR_DEREF GetSlot(this PTR_DEREF _slotIdx) PTR_DEREF value); }
};
/**
@@ -71,37 +72,50 @@ class DictObject : public DictBase {
Clear();
Resize(right.GetSlotCount());
for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) {
- _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i];
+ this PTR_DEREF _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i];
}
- _DictSlots_ref._num_used = right._DictSlots_ref._num_used;
- _current_id = right._current_id;
- _mode = right._mode;
+ this PTR_DEREF _DictSlots_ref._num_used = right._DictSlots_ref._num_used;
+ this PTR_DEREF _current_id = right._current_id;
+ this PTR_DEREF _mode = right._mode;
+ }
+
+ DictObjectIterator Begin() {
+ // Searching for first item index.
+ for (unsigned int i = 0; i < (unsigned int)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots); ++i) {
+ if (this PTR_DEREF _DictSlots_ref.DictSlots[i].IsValid() && this PTR_DEREF _DictSlots_ref.DictSlots[i].IsUsed()) {
+ DictObjectIterator iter(THIS_REF, i);
+ return iter;
+ }
+ }
+ // No items found.
+ DictObjectIterator invalid;
+ return invalid;
}
void operator=(const DictObject& right) {
Clear();
Resize(right.GetSlotCount());
for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) {
- _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i];
+ this PTR_DEREF _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i];
}
- _DictSlots_ref._num_used = right._DictSlots_ref._num_used;
- _current_id = right._current_id;
- _mode = right._mode;
+ this PTR_DEREF _DictSlots_ref._num_used = right._DictSlots_ref._num_used;
+ this PTR_DEREF _current_id = right._current_id;
+ this PTR_DEREF _mode = right._mode;
}
void Clear() {
- for (unsigned int i = 0; i < (unsigned int)ArraySize(_DictSlots_ref.DictSlots); ++i) {
- _DictSlots_ref.DictSlots[i].SetFlags(0);
+ for (unsigned int i = 0; i < (unsigned int)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots); ++i) {
+ this PTR_DEREF _DictSlots_ref.DictSlots[i].SetFlags(0);
}
- _DictSlots_ref._num_used = 0;
+ this PTR_DEREF _DictSlots_ref._num_used = 0;
}
/**
* Inserts value using hashless key.
*/
bool Push(V& value) {
- if (!InsertInto(_DictSlots_ref, value)) return false;
+ if (!InsertInto(this PTR_DEREF _DictSlots_ref, value)) return false;
return true;
}
@@ -114,7 +128,7 @@ class DictObject : public DictBase {
* Inserts or replaces value for a given key.
*/
bool Set(K key, V& value) {
- if (!InsertInto(_DictSlots_ref, key, value, true)) return false;
+ if (!InsertInto(this PTR_DEREF _DictSlots_ref, key, value, true)) return false;
return true;
}
@@ -123,10 +137,10 @@ class DictObject : public DictBase {
unsigned int position;
- if (_mode == DictModeList)
- slot = GetSlot((unsigned int)key);
+ if (this PTR_DEREF _mode == DictModeList)
+ slot = this PTR_DEREF GetSlot((unsigned int)key);
else
- slot = GetSlotByKey(_DictSlots_ref, key, position);
+ slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, key, position);
if (slot == NULL || !slot.IsUsed()) return NULL;
@@ -138,7 +152,7 @@ class DictObject : public DictBase {
*/
V* GetByKey(const K _key) {
unsigned int position;
- DictSlot* slot = GetSlotByKey(_DictSlots_ref, _key, position);
+ DictSlot* slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, _key, position);
if (!slot) return NULL;
@@ -149,7 +163,7 @@ class DictObject : public DictBase {
* Returns value for a given position.
*/
V* GetByPos(unsigned int _position) {
- DictSlot* slot = GetSlotByPos(_DictSlots_ref, _position);
+ DictSlot* slot = this PTR_DEREF GetSlotByPos(this PTR_DEREF _DictSlots_ref, _position);
if (!slot) {
Alert("Invalid DictStruct position \"", _position, "\" (called by GetByPos()). Returning empty structure.");
@@ -163,10 +177,12 @@ class DictObject : public DictBase {
/**
* Checks whether dictionary contains given key => value pair.
*/
+#ifdef __MQL__
template <>
+#endif
bool Contains(const K key, const V& value) {
unsigned int position;
- DictSlot* slot = GetSlotByKey(_DictSlots_ref, key, position);
+ DictSlot* slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, key, position);
if (!slot) return false;
@@ -176,7 +192,9 @@ class DictObject : public DictBase {
/**
* Returns index of dictionary's value or -1 if value doesn't exist.
*/
+#ifdef __MQL__
template <>
+#endif
int IndexOf(V& value) {
for (DictIteratorBase i(Begin()); i.IsValid(); ++i) {
if (i.Value() == value) {
@@ -192,37 +210,37 @@ class DictObject : public DictBase {
* Inserts value into given array of DictSlots.
*/
bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) {
- if (_mode == DictModeUnknown)
- _mode = DictModeDict;
- else if (_mode != DictModeDict) {
+ if (this PTR_DEREF _mode == DictModeUnknown)
+ this PTR_DEREF _mode = DictModeDict;
+ else if (this PTR_DEREF _mode != DictModeDict) {
Alert("Warning: Dict already operates as a list, not a dictionary!");
return false;
}
unsigned int position;
- DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position);
+ DictSlot* keySlot = this PTR_DEREF GetSlotByKey(dictSlotsRef, key, position);
- if (keySlot == NULL && !IsGrowUpAllowed()) {
+ if (keySlot == NULL && !this PTR_DEREF IsGrowUpAllowed()) {
// Resize is prohibited.
return false;
}
// Will resize dict if there were performance problems before.
- if (allow_resize && IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) {
+ if (allow_resize && this PTR_DEREF IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) {
if (!GrowUp()) {
return false;
}
// We now have new positions of slots, so we have to take the corrent slot again.
- keySlot = GetSlotByKey(dictSlotsRef, key, position);
+ keySlot = this PTR_DEREF GetSlotByKey(dictSlotsRef, key, position);
}
if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) {
// No DictSlotsRef.DictSlots available.
- if (overflow_listener != NULL) {
- if (!overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) {
+ if (this PTR_DEREF overflow_listener != NULL) {
+ if (!this PTR_DEREF overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) {
// Overwriting slot pointed exactly by key's position in the hash table (we don't check for possible
// conflicts).
- keySlot = &dictSlotsRef.DictSlots[Hash(key) % ArraySize(dictSlotsRef.DictSlots)];
+ keySlot = &dictSlotsRef.DictSlots[this PTR_DEREF Hash(key) % ArraySize(dictSlotsRef.DictSlots)];
}
}
@@ -233,18 +251,20 @@ class DictObject : public DictBase {
}
if (keySlot == NULL) {
- position = Hash(key) % ArraySize(dictSlotsRef.DictSlots);
+ position = this PTR_DEREF Hash(key) % ArraySize(dictSlotsRef.DictSlots);
unsigned int _starting_position = position;
- int _num_conflicts = 0;
+ unsigned int _num_conflicts = 0;
bool _overwrite_slot = false;
// Searching for empty DictSlot or used one with the matching key. It skips used, hashless DictSlots.
while (dictSlotsRef.DictSlots[position].IsUsed() &&
(!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) {
- if (overflow_listener_max_conflicts != 0 && ++_num_conflicts == overflow_listener_max_conflicts) {
- if (overflow_listener != NULL) {
- if (!overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used, _num_conflicts)) {
+ if (this PTR_DEREF overflow_listener_max_conflicts != 0 &&
+ ++_num_conflicts == this PTR_DEREF overflow_listener_max_conflicts) {
+ if (this PTR_DEREF overflow_listener != NULL) {
+ if (!this PTR_DEREF overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used,
+ _num_conflicts)) {
// Overflow listener returned false so we won't search for further empty slot.
_overwrite_slot = true;
break;
@@ -282,9 +302,9 @@ class DictObject : public DictBase {
* Inserts hashless value into given array of DictSlots.
*/
bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) {
- if (_mode == DictModeUnknown)
- _mode = DictModeList;
- else if (_mode != DictModeList) {
+ if (this PTR_DEREF _mode == DictModeUnknown)
+ this PTR_DEREF _mode = DictModeList;
+ else if (this PTR_DEREF _mode != DictModeList) {
Alert("Warning: Dict already operates as a dictionary, not a list!");
DebugBreak();
return false;
@@ -295,7 +315,8 @@ class DictObject : public DictBase {
if (!GrowUp()) return false;
}
- unsigned int position = Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots);
+ unsigned int position =
+ this PTR_DEREF Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots);
// Searching for empty DictSlot.
while (dictSlotsRef.DictSlots[position].IsUsed()) {
@@ -315,14 +336,16 @@ class DictObject : public DictBase {
* Expands array of DictSlots by given percentage value.
*/
bool GrowUp(int percent = DICT_GROW_UP_PERCENT_DEFAULT) {
- return Resize(MathMax(10, (int)((float)ArraySize(_DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f))));
+ return Resize(MathMax(
+ 10, (int)((float)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f))));
}
/**
* Shrinks or expands array of DictSlots.
*/
bool Resize(int new_size) {
- if (new_size <= MathMin(_DictSlots_ref._num_used, ArraySize(_DictSlots_ref.DictSlots))) {
+ if (new_size <=
+ MathMin(this PTR_DEREF _DictSlots_ref._num_used, ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots))) {
// We already use minimum number of slots possible.
return true;
}
@@ -338,20 +361,21 @@ class DictObject : public DictBase {
}
// Copies entire array of DictSlots into new array of DictSlots. Hashes will be rehashed.
- for (i = 0; i < ArraySize(_DictSlots_ref.DictSlots); ++i) {
- if (!_DictSlots_ref.DictSlots[i].IsUsed()) continue;
+ for (i = 0; i < ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots); ++i) {
+ if (!this PTR_DEREF _DictSlots_ref.DictSlots[i].IsUsed()) continue;
- if (_DictSlots_ref.DictSlots[i].HasKey()) {
- if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].key, _DictSlots_ref.DictSlots[i].value, false))
+ if (this PTR_DEREF _DictSlots_ref.DictSlots[i].HasKey()) {
+ if (!InsertInto(new_DictSlots, this PTR_DEREF _DictSlots_ref.DictSlots[i].key,
+ this PTR_DEREF _DictSlots_ref.DictSlots[i].value, false))
return false;
} else {
- if (!InsertInto(new_DictSlots, _DictSlots_ref.DictSlots[i].value)) return false;
+ if (!InsertInto(new_DictSlots, this PTR_DEREF _DictSlots_ref.DictSlots[i].value)) return false;
}
}
// Freeing old DictSlots array.
- ArrayFree(_DictSlots_ref.DictSlots);
+ ArrayFree(this PTR_DEREF _DictSlots_ref.DictSlots);
- _DictSlots_ref = new_DictSlots;
+ this PTR_DEREF _DictSlots_ref = new_DictSlots;
return true;
}
@@ -362,10 +386,12 @@ class DictObject : public DictBase {
#endif
SerializerNodeType Serialize(Serializer& s) {
if (s.IsWriting()) {
- for (DictIteratorBase i(Begin()); i.IsValid(); ++i)
- s.PassObject(this, GetMode() == DictModeDict ? i.KeyAsString() : "", i.Value());
+ for (DictObjectIterator i(Begin()); i.IsValid(); ++i) {
+ V* _value = i.Value();
+ s.PassObject(THIS_REF, this PTR_DEREF GetMode() == DictModeDict ? i.KeyAsString() : "", PTR_TO_REF(_value));
+ }
- return (GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray;
+ return (this PTR_DEREF GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray;
} else {
if (s.IsArray()) {
unsigned int num_items = s.NumArrayItems();
@@ -394,9 +420,11 @@ class DictObject : public DictBase {
// Note that we're retrieving value by a key (as we are in an
// object!).
- Set(key, i.Struct(i.Key()));
+ V _prop = i.Struct(i.Key());
+ Set(key, _prop);
} else {
- Push(i.Struct());
+ V _prop = i.Struct();
+ Push(_prop);
}
}
return i.ParentNodeType();
@@ -407,7 +435,9 @@ class DictObject : public DictBase {
/**
* Initializes object with given number of elements. Could be skipped for non-containers.
*/
+#ifdef __MQL__
template <>
+#endif
void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {
V _child;
diff --git a/DictSlot.mqh b/DictSlot.mqh
index c64aa3eda..3c1fe29e1 100644
--- a/DictSlot.mqh
+++ b/DictSlot.mqh
@@ -52,7 +52,7 @@ class DictSlot {
void AddFlags(unsigned char flags) { _flags |= flags; }
- void RemoveFlags(unsigned char flags) { _flags &= ~flags; }
+ void RemoveFlags(unsigned char flags) { _flags &= (unsigned char)~flags; }
};
#endif
diff --git a/DictSlotsRef.h b/DictSlotsRef.h
index 140140c49..e5ae9ee58 100644
--- a/DictSlotsRef.h
+++ b/DictSlotsRef.h
@@ -38,7 +38,7 @@ class DictSlot;
template
struct DictSlotsRef {
- DictSlot DictSlots[];
+ ARRAY(DictSlot, DictSlots);
// Incremental index for dict operating in list mode.
int _list_index;
@@ -61,7 +61,7 @@ struct DictSlotsRef {
*/
void AddConflicts(int num) {
if (num != 0) {
- _avg_conflicts += float(num) / ++_num_conflicts;
+ _avg_conflicts += (float)num / (float)++_num_conflicts;
}
}
diff --git a/DictStruct.mqh b/DictStruct.mqh
index b4cb0d747..405dcee7a 100644
--- a/DictStruct.mqh
+++ b/DictStruct.mqh
@@ -31,6 +31,7 @@ class Log;
#include "DictBase.mqh"
#include "DictIteratorBase.mqh"
#include "Serializer.mqh"
+#include "SerializerNodeIterator.mqh"
// DictIterator could be used as DictStruct iterator.
#define DictStructIterator DictIteratorBase
diff --git a/EA.mqh b/EA.mqh
index 63368f947..0fb8a1051 100644
--- a/EA.mqh
+++ b/EA.mqh
@@ -343,6 +343,12 @@ class EA {
_strat.OnOrderOpen(_oparams);
// Send the request.
_result = _trade.RequestSend(_request, _oparams);
+ if (!_result) {
+ logger.Debug(
+ StringFormat("Error while sending a trade request! Entry: %s",
+ SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()),
+ __FUNCTION_LINE__, StringFormat("Code: %d, Msg: %s", _LastError, Terminal::GetErrorText(_LastError)));
+ }
return _result;
}
@@ -426,7 +432,7 @@ class EA {
if (eparams.CheckFlagDataStore(EA_DATA_STORE_INDICATOR)) {
for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) {
Strategy *_strati = iter.Value().Ptr();
- IndicatorBase *_indi = _strati.GetIndicator();
+ IndicatorData *_indi = _strati.GetIndicator();
if (_indi != NULL) {
ENUM_TIMEFRAMES _itf = _indi.GetParams().tf.GetTf();
IndicatorDataEntry _ientry = _indi.GetEntry();
@@ -485,7 +491,7 @@ class EA {
string _key_chart = "Chart";
_key_chart += StringFormat("-%d-%d", data_chart.GetMin(), data_chart.GetMax());
- SerializerConverter _stub = Serializer::MakeStubObject>(_serializer_flags);
+ SerializerConverter _stub = SerializerConverter::MakeStubObject>(_serializer_flags);
SerializerConverter _obj = SerializerConverter::FromObject(data_chart, _serializer_flags);
if ((_methods & EA_DATA_EXPORT_CSV) != 0) {
@@ -505,7 +511,8 @@ class EA {
_obj.Clean();
}
if (eparams.CheckFlagDataStore(EA_DATA_STORE_INDICATOR)) {
- SerializerConverter _stub = Serializer::MakeStubObject>(_serializer_flags);
+ SerializerConverter _stub =
+ SerializerConverter::MakeStubObject>(_serializer_flags);
/*
for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) {
@@ -540,7 +547,7 @@ class EA {
_stub.Clean();
}
if (eparams.CheckFlagDataStore(EA_DATA_STORE_STRATEGY)) {
- SerializerConverter _stub = Serializer::MakeStubObject>(_serializer_flags);
+ SerializerConverter _stub = SerializerConverter::MakeStubObject>(_serializer_flags);
/* @fixme
for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) {
@@ -570,7 +577,7 @@ class EA {
_stub.Clean();
}
if (eparams.CheckFlagDataStore(EA_DATA_STORE_SYMBOL)) {
- SerializerConverter _stub = Serializer::MakeStubObject>(_serializer_flags);
+ SerializerConverter _stub = SerializerConverter::MakeStubObject>(_serializer_flags);
SerializerConverter _obj = SerializerConverter::FromObject(data_symbol, _serializer_flags);
string _key_sym = "Symbol";
diff --git a/Exchange/Exchange.h b/Exchange/Exchange.h
new file mode 100644
index 000000000..85b9e9202
--- /dev/null
+++ b/Exchange/Exchange.h
@@ -0,0 +1,83 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+/**
+ * Exchange class.
+ */
+#ifndef EXCHANGE_H
+#define EXCHANGE_H
+
+// Includes.
+#include "../Account.mqh"
+#include "../DictObject.mqh"
+#include "../SymbolInfo.mqh"
+#include "../Trade.mqh"
+#include "Exchange.struct.h"
+
+class Exchange {
+ protected:
+ DictObject accounts;
+ DictObject symbols;
+ DictObject trades;
+ ExchangeParams eparams;
+
+ public:
+ /**
+ * Class constructor without parameters.
+ */
+ Exchange(){};
+
+ /**
+ * Class constructor with parameters.
+ */
+ Exchange(ExchangeParams &_eparams) : eparams(_eparams){};
+
+ /**
+ * Class deconstructor.
+ */
+ ~Exchange() {}
+
+ /* Adders */
+
+ /**
+ * Adds account to the list.
+ */
+ void AccountAdd(Account &_account, string _name) { accounts.Set(_name, _account); }
+
+ /**
+ * Adds symbol to the list.
+ */
+ void SymbolAdd(SymbolInfo &_sinfo, string _name) { symbols.Set(_name, _sinfo); }
+
+ /* Removers */
+
+ /**
+ * Removes account from the list.
+ */
+ void AccountRemove(string _name) { accounts.Unset(_name); }
+
+ /**
+ * Removes symbol from the list.
+ */
+ void SymbolRemove(string _name) { symbols.Unset(_name); }
+};
+#endif // EXCHANGE_H
diff --git a/Exchange/Exchange.struct.h b/Exchange/Exchange.struct.h
new file mode 100644
index 000000000..d63290d4f
--- /dev/null
+++ b/Exchange/Exchange.struct.h
@@ -0,0 +1,42 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+/**
+ * @file
+ * Includes Exchange's structs.
+ */
+
+#ifndef __MQL__
+// Allows the preprocessor to include a header file when it is needed.
+#pragma once
+#endif
+
+// Forward class declaration.
+class Exchange;
+
+/* Defines struct for Exchange parameters. */
+struct ExchangeParams {
+ // Constructors.
+ ExchangeParams() {}
+ ExchangeParams(const ExchangeParams &_eparams) {}
+ long id;
+};
diff --git a/Exchange/tests/Exchange.test.mq4 b/Exchange/tests/Exchange.test.mq4
new file mode 100644
index 000000000..2b3fdf2da
--- /dev/null
+++ b/Exchange/tests/Exchange.test.mq4
@@ -0,0 +1,28 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @file
+ * Test functionality of Exchange class.
+ */
+
+// Includes.
+#include "Exchange.test.mq5"
diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5
new file mode 100644
index 000000000..1c9d1c39b
--- /dev/null
+++ b/Exchange/tests/Exchange.test.mq5
@@ -0,0 +1,43 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2021, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @file
+ * Test functionality of Exchange class.
+ */
+
+// Includes.
+#include "../../Test.mqh"
+#include "../Exchange.h"
+
+// Test classes.
+class ExchangeDummy : public Exchange {};
+
+// Global variables.
+ExchangeDummy ex_dummy;
+
+/**
+ * Implements OnInit().
+ */
+int OnInit() {
+ bool _result = true;
+ return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED;
+}
diff --git a/File.define.h b/File.define.h
new file mode 100644
index 000000000..e932ab836
--- /dev/null
+++ b/File.define.h
@@ -0,0 +1,31 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2022, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Defines.
+#ifndef __MQL__
+// File constants to read the whole value of char, short or int type.
+#define CHAR_VALUE 1
+#define INT_VALUE 4
+#define SHORT_VALUE 2
+// Used for checking file handles (see FileOpen() and FileFindFirst()).
+#define INVALID_HANDLE -1
+#endif
diff --git a/File.extern.h b/File.extern.h
new file mode 100644
index 000000000..52e15849a
--- /dev/null
+++ b/File.extern.h
@@ -0,0 +1,36 @@
+//+------------------------------------------------------------------+
+//| EA31337 framework |
+//| Copyright 2016-2022, EA31337 Ltd |
+//| https://github.com/EA31337 |
+//+------------------------------------------------------------------+
+
+/*
+ * This file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Includes.
+#include "File.define.h"
+#include "Terminal.define.h"
+
+// Define external global functions.
+#ifndef __MQL__
+extern bool FileIsEnding(int file_handle);
+extern bool FileIsExist(const string file_name, int common_flag = 0);
+extern int FileClose(int file_handle);
+extern int FileOpen(string file_name, int open_flags, short delimiter = '\t', uint codepage = CP_ACP);
+extern int FileReadInteger(int file_handle, int size = INT_VALUE);
+extern string FileReadString(int file_handle, int length = -1);
+extern uint FileWriteString(int file_handle, const string text_string, int length = -1);
+#endif
diff --git a/File.mqh b/File.mqh
index 4fe3dcb6b..56c33bd57 100644
--- a/File.mqh
+++ b/File.mqh
@@ -30,7 +30,10 @@
*/
// Includes.
+#include "File.define.h"
+#include "File.extern.h"
#include "Terminal.define.h"
+#include "Terminal.extern.h"
#include "Terminal.enum.h"
#ifndef __MQL__
diff --git a/Indicator.define.h b/Indicator.define.h
index dc2d23d8a..74e3727fe 100644
--- a/Indicator.define.h
+++ b/Indicator.define.h
@@ -119,7 +119,7 @@ class DrawIndicator;
_obj.SetHandle(_handle); \
} \
} \
- if (false && Terminal::IsVisualMode()) { \
+ if (Terminal::IsVisualMode()) { \
/* To avoid error 4806 (ERR_INDICATOR_DATA_NOT_FOUND), */ \
/* we check the number of calculated data only in visual mode. */ \
int _bars_calc = BarsCalculated(_handle); \
diff --git a/Indicator.enum.h b/Indicator.enum.h
index 8bf58e7b1..bce168e60 100644
--- a/Indicator.enum.h
+++ b/Indicator.enum.h
@@ -132,28 +132,6 @@ enum ENUM_INDICATOR_TYPE {
FINAL_INDICATOR_TYPE_ENTRY
};
-/* Defines type of source data for */
-enum ENUM_IDATA_SOURCE_TYPE {
- IDATA_BUILTIN = 0, // Platform built-in
- IDATA_CHART, // Chart calculation
- IDATA_ICUSTOM, // iCustom: Custom indicator file
- IDATA_ICUSTOM_LEGACY, // iCustom: Custom, legacy, provided by MT indicator file
- IDATA_INDICATOR, // OnIndicator: Another indicator as a source of data
- IDATA_ONCALCULATE, // OnCalculate: Custom calculation function
- IDATA_MATH // Math-based indicator
-};
-
-/* Defines range value data type for indicator storage. */
-enum ENUM_IDATA_VALUE_RANGE {
- IDATA_RANGE_ARROW, // Value is non-zero on signal.
- IDATA_RANGE_BINARY, // E.g. 0 or 1.
- IDATA_RANGE_BITWISE, // Bitwise
- IDATA_RANGE_MIXED,
- IDATA_RANGE_PRICE, // Values represent price.
- IDATA_RANGE_RANGE, // E.g. 0 to 100.
- IDATA_RANGE_UNKNOWN
-};
-
// Indicator line identifiers used in ADX and ADXW
enum ENUM_INDI_ADX_LINE {
#ifdef __MQL4__
diff --git a/Indicator.mqh b/Indicator.mqh
index 58f6d3744..49670df3e 100644
--- a/Indicator.mqh
+++ b/Indicator.mqh
@@ -38,8 +38,7 @@ class Chart;
#include "Indicator.struct.cache.h"
#include "Indicator.struct.h"
#include "Indicator.struct.serialize.h"
-#include "Indicator.struct.signal.h"
-#include "IndicatorBase.h"
+#include "IndicatorData.mqh"
#include "Math.h"
#include "Object.mqh"
#include "Refs.mqh"
@@ -74,37 +73,32 @@ double iCustom5(string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C
ICUSTOM_DEF(_handlers.Set(_key, _handle),
COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i COMMA _j);
}
+template
+double iCustom5(string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i,
+ J _j, K _k, L _l, M _m, int _mode, int _shift) {
+ ResetLastError();
+ static Dict _handlers;
+ string _key = Util::MakeKey(_symbol, (string)_tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m);
+ int _handle = _handlers.GetByKey(_key);
+ ICUSTOM_DEF(_handlers.Set(_key, _handle), COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h
+ COMMA _i COMMA _j COMMA _k COMMA _l COMMA _m);
+}
#endif
/**
* Class to deal with indicators.
*/
template
-class Indicator : public IndicatorBase {
+class Indicator : public IndicatorData {
protected:
DrawIndicator* draw;
- BufferStruct idata;
TS iparams;
protected:
/* Protected methods */
- bool Init() {
- ArrayResize(value_storages, iparams.GetMaxModes());
- switch (iparams.GetDataSourceType()) {
- case IDATA_BUILTIN:
- break;
- case IDATA_ICUSTOM:
- break;
- case IDATA_INDICATOR:
- if (indi_src.IsSet() == NULL) {
- // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift());
- // SetDataSource(_indi_price, true, PRICE_OPEN);
- }
- break;
- }
- return InitDraw();
- }
+ bool Init() { return InitDraw(); }
/**
* Initialize indicator data drawing on custom data.
@@ -144,21 +138,19 @@ class Indicator : public IndicatorBase {
/**
* Class constructor.
*/
- Indicator(const TS& _iparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0)
- : IndicatorBase(_iparams.GetTf(), NULL) {
+ Indicator(const TS& _iparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL,
+ int _indi_mode = 0)
+ : IndicatorData(_idparams, _indi_src, _indi_mode) {
iparams = _iparams;
- 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) {
+ Indicator(const TS& _iparams, const IndicatorDataParams& _idparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT)
+ : IndicatorData(_idparams) {
iparams = _iparams;
Init();
}
Indicator(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "")
- : IndicatorBase(_tf) {
+ : IndicatorData(IndicatorDataParams::GetInstance()) {
iparams.SetIndicatorType(_itype);
iparams.SetShift(_shift);
Init();
@@ -172,11 +164,29 @@ class Indicator : public IndicatorBase {
/* Getters */
/**
- * Gets an indicator property flag.
+ * Gets a value from IndicatorDataParams struct.
+ */
+ template
+ T Get(STRUCT_ENUM_IDATA_PARAM _param) {
+ return idparams.Get(_param);
+ }
+
+ /**
+ * Gets a value from IndicatorState struct.
+ */
+ template
+ T Get(STRUCT_ENUM_INDICATOR_STATE_PROP _param) {
+ return istate.Get(_param);
+ }
+
+ /* Setters */
+
+ /**
+ * Sets the value for IndicatorDataParams struct.
*/
- bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, int _shift = 0) {
- IndicatorDataEntry _entry = GetEntry(_shift >= 0 ? _shift : iparams.GetShift());
- return _entry.CheckFlag(_prop);
+ template
+ void Set(STRUCT_ENUM_IDATA_PARAM _param, T _value) {
+ idparams.Set(_param, _value);
}
/* Buffer methods */
@@ -268,48 +278,6 @@ class Indicator : public IndicatorBase {
return GetIndicatorBuffers() > 0 && GetIndicatorBuffers() <= 512;
}
- /**
- * Gets indicator data from a buffer and copy into struct array.
- *
- * @return
- * Returns true of successful copy.
- * Returns false on invalid values.
- */
- bool CopyEntries(IndicatorDataEntry& _data[], int _count, int _start_shift = 0) {
- bool _is_valid = true;
- if (ArraySize(_data) < _count) {
- _is_valid &= ArrayResize(_data, _count) > 0;
- }
- for (int i = 0; i < _count; i++) {
- IndicatorDataEntry _entry = GetEntry(_start_shift + i);
- _is_valid &= _entry.IsValid();
- _data[i] = _entry;
- }
- return _is_valid;
- }
-
- /**
- * Gets indicator data from a buffer and copy into array of values.
- *
- * @return
- * Returns true of successful copy.
- * Returns false on invalid values.
- */
- template
- bool CopyValues(T& _data[], int _count, int _start_shift = 0, int _mode = 0) {
- bool _is_valid = true;
- if (ArraySize(_data) < _count) {
- _count = ArrayResize(_data, _count);
- _count = _count > 0 ? _count : ArraySize(_data);
- }
- for (int i = 0; i < _count; i++) {
- IndicatorDataEntry _entry = GetEntry(_start_shift + i);
- _is_valid &= _entry.IsValid();
- _data[i] = (T)_entry[_mode];
- }
- return _is_valid;
- }
-
/**
* CopyBuffer() method to be used on Indicator instance with ValueStorage buffer.
*
@@ -340,52 +308,6 @@ class Indicator : public IndicatorBase {
}
*/
- /**
- * Validates currently selected indicator used as data source.
- */
- void ValidateSelectedDataSource() {
- if (HasDataSource()) {
- ValidateDataSource(THIS_PTR, GetDataSourceRaw());
- }
- }
-
- /**
- * Loads and validates built-in indicators whose can be used as data source.
- */
- void ValidateDataSource(IndicatorBase* _target, IndicatorBase* _source) {
- if (_target == NULL) {
- Alert("Internal Error! _target is NULL in ", __FUNCTION_LINE__, ".");
- DebugBreak();
- return;
- }
-
- if (_source == NULL) {
- Alert("Error! You have to select source indicator's via SetDataSource().");
- DebugBreak();
- return;
- }
-
- if (!_target.IsDataSourceModeSelectable()) {
- // We don't validate source mode as it will use all modes.
- return;
- }
-
- if (_source.GetModeCount() > 1 && _target.GetDataSourceMode() == -1) {
- // Mode must be selected if source indicator has more that one mode.
- Alert("Warning! ", GetName(),
- " must select source indicator's mode via SetDataSourceMode(int). Defaulting to mode 0.");
- _target.SetDataSourceMode(0);
- DebugBreak();
- } else if (_source.GetModeCount() == 1 && _target.GetDataSourceMode() == -1) {
- _target.SetDataSourceMode(0);
- } else if (_target.GetDataSourceMode() < 0 || _target.GetDataSourceMode() > _source.GetModeCount()) {
- Alert("Error! ", _target.GetName(),
- " must select valid source indicator's mode via SetDataSourceMode(int) between 0 and ",
- _source.GetModeCount(), ".");
- DebugBreak();
- }
- }
-
/**
* Checks whether indicator have given mode index.
*
@@ -394,13 +316,13 @@ class Indicator : public IndicatorBase {
void ValidateDataSourceMode(int& _out_mode) {
if (_out_mode == -1) {
// First mode will be used by default, or, if selected indicator has more than one mode, error will happen.
- if (iparams.GetMaxModes() != 1) {
+ if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)) != 1) {
Alert("Error: ", GetName(), " must have exactly one possible mode in order to skip using SetDataSourceMode()!");
DebugBreak();
}
_out_mode = 0;
- } else if (_out_mode + 1 > (int)iparams.GetMaxModes()) {
- Alert("Error: ", GetName(), " have ", iparams.GetMaxModes(),
+ } else if (_out_mode + 1 > Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) {
+ Alert("Error: ", GetName(), " have ", Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)),
" mode(s) buy you tried to reference mode with index ", _out_mode,
"! Ensure that you properly set mode via SetDataSourceMode().");
DebugBreak();
@@ -412,302 +334,21 @@ class Indicator : public IndicatorBase {
*/
virtual IndicatorBase* FetchDataSource(ENUM_INDICATOR_TYPE _id) { return NULL; }
- /* 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 */
-
- /**
- * Get pointer to data of indicator.
- */
- BufferStruct* GetData() { return GetPointer(idata); }
-
- /**
- * Returns the highest bar's index (shift).
- */
- template
- int GetHighest(int count = WHOLE_ARRAY, int start_bar = 0) {
- int max_idx = -1;
- double max = -DBL_MAX;
- int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1);
-
- for (int shift = start_bar; shift <= last_bar; ++shift) {
- double value = GetEntry(shift).GetMax(GetModeCount());
- if (value > max) {
- max = value;
- max_idx = shift;
- }
- }
-
- return max_idx;
- }
-
- /**
- * Returns the lowest bar's index (shift).
- */
- template
- int GetLowest(int count = WHOLE_ARRAY, int start_bar = 0) {
- int min_idx = -1;
- double min = DBL_MAX;
- int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1);
-
- for (int shift = start_bar; shift <= last_bar; ++shift) {
- double value = GetEntry(shift).GetMin(GetModeCount());
- if (value < min) {
- min = value;
- min_idx = shift;
- }
- }
-
- return min_idx;
- }
-
- /**
- * Returns the highest value.
- */
- template
- double GetMax(int start_bar = 0, int count = WHOLE_ARRAY) {
- double max = NULL;
- int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1);
-
- for (int shift = start_bar; shift <= last_bar; ++shift) {
- double value = GetEntry(shift).GetMax(iparams.GetMaxModes());
- if (max == NULL || value > max) {
- max = value;
- }
- }
-
- return max;
- }
-
- /**
- * Returns the lowest value.
- */
- template
- double GetMin(int start_bar, int count = WHOLE_ARRAY) {
- double min = NULL;
- int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1);
-
- for (int shift = start_bar; shift <= last_bar; ++shift) {
- double value = GetEntry(shift).GetMin(iparams.GetMaxModes());
- if (min == NULL || value < min) {
- min = value;
- }
- }
-
- return min;
- }
-
- /**
- * Returns average value.
- */
- template
- double GetAvg(int start_bar, int count = WHOLE_ARRAY) {
- int num_values = 0;
- double sum = 0;
- int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1);
-
- for (int shift = start_bar; shift <= last_bar; ++shift) {
- double value_min = GetEntry(shift).GetMin(iparams.GetMaxModes());
- double value_max = GetEntry(shift).GetMax(iparams.GetMaxModes());
-
- sum += value_min + value_max;
- num_values += 2;
- }
-
- return sum / num_values;
- }
-
- /**
- * Returns median of values.
- */
- template
- double GetMed(int start_bar, int count = WHOLE_ARRAY) {
- double array[];
-
- int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1);
- int num_bars = last_bar - start_bar + 1;
- int index = 0;
-
- ArrayResize(array, num_bars);
-
- for (int shift = start_bar; shift <= last_bar; ++shift) {
- array[index++] = GetEntry(shift).GetAvg(iparams.GetMaxModes());
- }
-
- ArraySort(array);
- double median;
- int len = ArraySize(array);
- if (len % 2 == 0) {
- median = (array[len / 2] + array[(len / 2) - 1]) / 2;
- } else {
- median = array[len / 2];
- }
-
- return median;
- }
-
- /**
- * Returns 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.
*/
- IndicatorBase* GetDataSource() {
- IndicatorBase* _result = NULL;
+ IndicatorData* GetDataSource() {
+ IndicatorData* _result = NULL;
if (GetDataSourceRaw() != NULL) {
_result = GetDataSourceRaw();
- } else if (iparams.GetDataSourceId() != -1) {
- int _source_id = iparams.GetDataSourceId();
+ } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) {
+ int _source_id = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID));
if (indicators.KeyExists(_source_id)) {
_result = indicators[_source_id].Ptr();
} else {
- Ref _source = FetchDataSource((ENUM_INDICATOR_TYPE)_source_id);
+ Ref _source = FetchDataSource((ENUM_INDICATOR_TYPE)_source_id);
if (!_source.IsSet()) {
Alert(GetName(), " has no built-in source indicator ", _source_id);
@@ -718,16 +359,16 @@ class Indicator : public IndicatorBase {
_result = _source.Ptr();
}
}
- } else if (iparams.GetDataSourceType() == IDATA_INDICATOR) {
+ } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_INDICATOR) {
// User sets data source's mode to On-Indicator, but not set data source via SetDataSource()!
// Requesting potential data source.
- IndicatorBase* _ds = OnDataSourceRequest();
+ IndicatorData* _ds = OnDataSourceRequest();
if (_ds != NULL) {
// Initializing with new data source.
SetDataSource(_ds);
- iparams.SetDataSourceType(IDATA_INDICATOR);
+ Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR);
}
}
@@ -745,11 +386,12 @@ class Indicator : public IndicatorBase {
* Whether data source is selected.
*/
virtual bool HasDataSource(bool _try_initialize = false) {
- if (iparams.GetDataSourceId() != -1) {
+ if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) {
return true;
}
- if (iparams.GetDataSourceType() == IDATA_INDICATOR && GetDataSourceRaw() == NULL && _try_initialize) {
+ if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_INDICATOR &&
+ GetDataSourceRaw() == NULL && _try_initialize) {
SetDataSource(OnDataSourceRequest());
}
@@ -764,12 +406,17 @@ class Indicator : public IndicatorBase {
/**
* Gets indicator's symbol.
*/
- string GetSymbol() { return Get(CHART_PARAM_SYMBOL); }
+ // string GetSymbol() { return Get(CHART_PARAM_SYMBOL); }
/**
* Gets indicator's time-frame.
*/
- ENUM_TIMEFRAMES GetTf() { return Get(CHART_PARAM_TF); }
+ // ENUM_TIMEFRAMES GetTf() { return Get(CHART_PARAM_TF); }
+
+ /**
+ * Gets indicator's time-frame.
+ */
+ ENUM_TIMEFRAMES GetTf() { return iparams.tf.GetTf(); }
/**
* Gets indicator's signals.
@@ -785,7 +432,7 @@ class Indicator : public IndicatorBase {
return _signals;
}
// Returns signals.
- IndicatorSignal _signals(_data, iparams, cparams, _mode1, _mode2);
+ IndicatorSignal _signals(_data, idparams, cparams, _mode1, _mode2);
return _signals;
}
@@ -800,9 +447,10 @@ class Indicator : public IndicatorBase {
* Get more descriptive name of the indicator.
*/
string GetDescriptiveName() {
+ int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES));
string name = iparams.name + " (";
- switch (iparams.GetDataSourceType()) {
+ switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) {
case IDATA_BUILTIN:
name += "built-in, ";
break;
@@ -814,7 +462,7 @@ class Indicator : public IndicatorBase {
break;
}
- name += IntegerToString(iparams.GetMaxModes()) + (iparams.GetMaxModes() == 1 ? " mode" : " modes");
+ name += IntegerToString(_max_modes) + (_max_modes == 1 ? " mode" : " modes");
return name + ")";
}
@@ -970,9 +618,11 @@ class Indicator : public IndicatorBase {
Chart::OnTick();
if (iparams.is_draw) {
+ int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES));
// Print("Drawing ", GetName(), iparams.indi_data != NULL ? (" (over " + iparams.indi_data.GetName() + ")") : "");
- for (int i = 0; i < (int)iparams.GetMaxModes(); ++i)
- draw.DrawLineTo(GetName() + "_" + IntegerToString(i) + "_" + IntegerToString(iparams.GetDataSourceMode()),
+ for (int i = 0; i < _max_modes; ++i)
+ draw.DrawLineTo(GetName() + "_" + IntegerToString(i) + "_" +
+ Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE)),
GetBarTime(0), GetEntry(0)[i], iparams.draw_window);
}
}
@@ -980,7 +630,7 @@ class Indicator : public IndicatorBase {
/**
* Sets indicator data source.
*/
- void SetDataSource(IndicatorBase* _indi, int _input_mode = -1) override {
+ void SetDataSource(IndicatorData* _indi, int _input_mode = -1) override {
if (indi_src.IsSet()) {
if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT) &&
!bool(_indi.GetFlags() | INDI_FLAG_INDEXABLE_BY_SHIFT)) {
@@ -1004,7 +654,8 @@ class Indicator : public IndicatorBase {
indi_src = _indi;
if (_indi != NULL) {
indi_src.Ptr().AddListener(THIS_PTR);
- iparams.SetDataSource(-1, _input_mode);
+ Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID), -1);
+ Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE), _input_mode);
indi_src.Ptr().OnBecomeDataSourceFor(THIS_PTR);
}
}
@@ -1067,7 +718,7 @@ class Indicator : public IndicatorBase {
* Get full name of the indicator (with "over ..." part).
*/
string GetFullName() override {
- return GetName() + "[" + IntegerToString(iparams.GetMaxModes()) + "]" +
+ return GetName() + "[" + Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)) + "]" +
(HasDataSource() ? (" (over " + GetDataSource().GetFullName() + ")") : "");
}
@@ -1098,7 +749,8 @@ class Indicator : public IndicatorBase {
long _bar_time = GetBarTime(_ishift);
IndicatorDataEntry _entry = idata.GetByKey(_bar_time);
if (_bar_time > 0 && !_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) {
- _entry.Resize(iparams.GetMaxModes());
+ int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES));
+ _entry.Resize(_max_modes);
_entry.timestamp = GetBarTime(_ishift);
#ifndef __MQL4__
if (IndicatorBase::Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED))) {
@@ -1107,8 +759,8 @@ class Indicator : public IndicatorBase {
IndicatorBase::Set(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED), false);
}
#endif
- for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) {
- switch (iparams.GetDataValueType()) {
+ for (int _mode = 0; _mode < _max_modes; _mode++) {
+ switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE))) {
case TYPE_BOOL:
case TYPE_CHAR:
case TYPE_INT:
@@ -1160,8 +812,10 @@ class Indicator : public IndicatorBase {
* This method is called on GetEntry() right after values are set.
*/
virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _timestamp = -1) {
- _entry.AddFlags(_entry.GetDataTypeFlags(iparams.GetDataValueType()));
+ ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE));
+ _entry.AddFlags(_entry.GetDataTypeFlags(_dtype));
};
+
/**
* Returns the indicator's entry value for the given shift and mode.
*
diff --git a/Indicator.struct.h b/Indicator.struct.h
index d9ecc205a..7f90435ea 100644
--- a/Indicator.struct.h
+++ b/Indicator.struct.h
@@ -1,6 +1,6 @@
//+------------------------------------------------------------------+
//| EA31337 framework |
-//| Copyright 2016-2021, EA31337 Ltd |
+//| Copyright 2016-2022, EA31337 Ltd |
//| https://github.com/EA31337 |
//+------------------------------------------------------------------+
@@ -35,6 +35,9 @@ template
class Indicator;
struct ChartParams;
+// Defines.
+#define STRUCT_ENUM_INDICATOR_STATE_PROP STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP)
+
// Includes.
#include "Array.mqh"
#include "Chart.struct.tf.h"
@@ -45,379 +48,15 @@ struct ChartParams;
#include "SerializerNode.enum.h"
#include "Storage/ValueStorage.indicator.h"
-// Type-less value for IndicatorDataEntryValue structure.
-union IndicatorDataEntryTypelessValue {
- double vdbl;
- float vflt;
- int vint;
- long vlong;
-};
-
-// Type-aware value for IndicatorDataEntry class.
-struct IndicatorDataEntryValue {
- unsigned char flags;
- IndicatorDataEntryTypelessValue value;
-
- // Returns type of the value.
- ENUM_DATATYPE GetDataType() { return (ENUM_DATATYPE)((flags & 0xF0) >> 4); }
-
- // Sets type of the value.
- void SetDataType(ENUM_DATATYPE _type) {
- // Clearing type.
- flags &= 0x0F;
-
- // Setting type.
- flags |= (unsigned char)_type << 4;
- }
-
- // Union operators.
- template
- T operator*(const T _value) {
- return Get() * _value;
- }
- template
- T operator+(const T _value) {
- return Get() + _value;
- }
- template
- T operator-(const T _value) {
- return Get() - _value;
- }
- template
- T operator/(const T _value) {
- return Get() / _value;
- }
- template
- bool operator!=(const T _value) {
- return Get() != _value;
- }
- template
- bool operator<(const T _value) {
- return Get() < _value;
- }
- template
- bool operator<=(const T _value) {
- return Get() <= _value;
- }
- template
- bool operator==(const T _value) {
- return Get() == _value;
- }
- template
- bool operator>(const T _value) {
- return Get() > _value;
- }
- template
- bool operator>=(const T _value) {
- return Get() >= _value;
- }
- template
- void operator=(const T _value) {
- Set(_value);
- }
- // Checkers.
- template
- bool IsGt(T _value) {
- return Get() > _value;
- }
- template
- bool IsLt(T _value) {
- return Get() < _value;
- }
- // Getters.
- double GetDbl() { return value.vdbl; }
- float GetFloat() { return value.vflt; }
- int GetInt() { return value.vint; }
- long GetLong() { return value.vlong; }
- template
- void Get(T &_out) {
- _out = Get();
- }
- template
- T Get() {
- T _v;
- Get(_v);
- return _v;
- }
- void Get(double &_out) { _out = value.vdbl; }
- void Get(float &_out) { _out = value.vflt; }
- void Get(int &_out) { _out = value.vint; }
- void Get(unsigned int &_out) { _out = (unsigned int)value.vint; }
- void Get(long &_out) { _out = value.vlong; }
- void Get(unsigned long &_out) { _out = (unsigned long)value.vint; }
- // Setters.
- template
- void Set(T _value) {
- Set(_value);
- }
- void Set(double _value) {
- value.vdbl = _value;
- SetDataType(TYPE_DOUBLE);
- }
- void Set(float _value) {
- value.vflt = _value;
- SetDataType(TYPE_FLOAT);
- }
- void Set(int _value) {
- value.vint = _value;
- SetDataType(TYPE_INT);
- }
- void Set(unsigned int _value) {
- value.vint = (int)_value;
- SetDataType(TYPE_UINT);
- }
- void Set(long _value) {
- value.vlong = _value;
- SetDataType(TYPE_LONG);
- }
- void Set(unsigned long _value) {
- value.vlong = (long)_value;
- SetDataType(TYPE_ULONG);
- }
- // Serializers.
- // SERIALIZER_EMPTY_STUB
- SerializerNodeType Serialize(Serializer &_s);
- // To string
- template
- string ToString() {
- return (string)Get();
- }
-};
-
-/* Structure for indicator data entry. */
-struct IndicatorDataEntry {
- long timestamp; // Timestamp of the entry's bar.
- unsigned short flags; // Indicator entry flags.
- ARRAY(IndicatorDataEntryValue, values);
-
- // Constructors.
- IndicatorDataEntry(int _size = 1) : flags(INDI_ENTRY_FLAG_NONE), timestamp(0) { Resize(_size); }
- IndicatorDataEntry(IndicatorDataEntry &_entry) { THIS_REF = _entry; }
- int GetSize() { return ArraySize(values); }
- // Operator overloading methods.
- template
- T operator*(const T _value) {
- return values[0].Get() * _value;
- }
- template
- T operator+(const T _value) {
- return values[0].Get() + _value;
- }
- template
- T operator-(const T _value) {
- return values[0].Get() - _value;
- }
- template
- T operator/(const T _value) {
- return values[0].Get() / _value;
- }
- template
- T operator[](I _index) {
- return values[(int)_index].Get();
- }
- template <>
- double operator[](int _index) {
- if (_index >= ArraySize(values)) {
- return 0;
- }
- double _value;
- values[_index].Get(_value);
- return _value;
- }
- // Checkers.
- template
- bool HasValue(T _value) {
- bool _result = false;
- int _asize = ArraySize(values);
- T _value2;
- for (int i = 0; i < _asize; i++) {
- values[i].Get(_value2);
- if (_value == _value2) {
- _result = true;
- break;
- }
- }
- return _result;
- }
- template
- bool IsGe(T _value) {
- return GetMin() >= _value;
- }
- template
- bool IsGt(T _value) {
- return GetMin() > _value;
- }
- template
- bool IsLe(T _value) {
- return GetMax() <= _value;
- }
- template
- bool IsLt(T _value) {
- return GetMax() < _value;
- }
- template
- bool IsWithinRange(T _min, T _max) {
- return GetMin() >= _min && GetMax() <= _max;
- }
- // Getters.
- template
- void GetArray(ARRAY_REF(T, _out), int _size = 0) {
- int _asize = _size > 0 ? _size : ArraySize(_out);
- for (int i = 0; i < _asize; i++) {
- values[i].Get(_out[i]);
- }
- };
- template
- T GetAvg(int _size = 0) {
- int _asize = _size > 0 ? _size : ArraySize(values);
- T _avg = GetSum() / _asize;
- return _avg;
- };
- template
- T GetMin(int _size = 0) {
- int _asize = _size > 0 ? _size : ArraySize(values);
- int _index = 0;
- for (int i = 1; i < _asize; i++) {
- _index = values[i].Get() < values[_index].Get() ? i : _index;
- }
- return values[_index].Get();
- };
- template
- T GetMax(int _size = 0) {
- int _asize = _size > 0 ? _size : ArraySize(values);
- int _index = 0;
- for (int i = 1; i < _asize; i++) {
- _index = values[i].Get() > values[_index].Get() ? i : _index;
- }
- return values[_index].Get();
- };
- template
- T GetSum(int _size = 0) {
- int _asize = _size > 0 ? _size : ArraySize(values);
- T _sum = 0;
- for (int i = 1; i < _asize; i++) {
- _sum = +values[i].Get();
- }
- return _sum;
- };
- template
- T GetValue(int _index = 0) {
- return values[_index].Get();
- };
- template
- void GetValues(T &_out1, T &_out2) {
- values[0].Get(_out1);
- values[1].Get(_out2);
- };
- template
- void GetValues(T &_out1, T &_out2, T &_out3) {
- values[0].Get(_out1);
- values[1].Get(_out2);
- values[2].Get(_out3);
- };
- template
- void GetValues(T &_out1, T &_out2, T &_out3, T &_out4) {
- values[0].Get(_out1);
- values[1].Get(_out2);
- values[2].Get(_out3);
- values[3].Get(_out4);
- };
-
- // Getters.
- int GetDayOfYear() { return DateTimeStatic::DayOfYear(timestamp); }
- int GetMonth() { return DateTimeStatic::Month(timestamp); }
- int GetYear() { return DateTimeStatic::Year(timestamp); }
- long GetTime() { return timestamp; };
- ENUM_DATATYPE GetDataType(int _mode) { return values[_mode].GetDataType(); }
- ushort GetDataTypeFlags(ENUM_DATATYPE _dt) {
- switch (_dt) {
- case TYPE_BOOL:
- case TYPE_CHAR:
- SetUserError(ERR_INVALID_PARAMETER);
- break;
- case TYPE_INT:
- return INDI_ENTRY_FLAG_NONE;
- case TYPE_LONG:
- return INDI_ENTRY_FLAG_IS_DOUBLED;
- case TYPE_UINT:
- return INDI_ENTRY_FLAG_IS_UNSIGNED;
- case TYPE_ULONG:
- return INDI_ENTRY_FLAG_IS_UNSIGNED | INDI_ENTRY_FLAG_IS_DOUBLED;
- case TYPE_DOUBLE:
- return INDI_ENTRY_FLAG_IS_REAL | INDI_ENTRY_FLAG_IS_DOUBLED;
- case TYPE_FLOAT:
- return INDI_ENTRY_FLAG_IS_REAL;
- case TYPE_STRING:
- case TYPE_UCHAR:
- SetUserError(ERR_INVALID_PARAMETER);
- break;
- default:
- SetUserError(ERR_INVALID_PARAMETER);
- break;
- }
- SetUserError(ERR_INVALID_PARAMETER);
- return INDI_ENTRY_FLAG_NONE;
- }
- // Setters.
- bool Resize(int _size = 0) { return _size > 0 ? ArrayResize(values, _size) > 0 : true; }
- // Value flag methods for bitwise operations.
- bool CheckFlag(INDICATOR_ENTRY_FLAGS _prop) { return CheckFlags(_prop); }
- bool CheckFlags(unsigned short _flags) { return (flags & _flags) != 0; }
- bool CheckFlagsAll(unsigned short _flags) { return (flags & _flags) == _flags; }
- void AddFlags(unsigned short _flags) { flags |= _flags; }
- void RemoveFlags(unsigned short _flags) { flags &= ~_flags; }
- void SetFlag(INDICATOR_ENTRY_FLAGS _flag, bool _value) {
- if (_value) {
- AddFlags(_flag);
- } else {
- RemoveFlags(_flag);
- }
- }
- void SetFlags(unsigned short _flags) { flags = _flags; }
- unsigned short GetFlags() { return flags; }
- // Converters.
- // State checkers.
- bool IsValid() { return CheckFlags(INDI_ENTRY_FLAG_IS_VALID); }
- // Serializers.
- void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {
- ArrayResize(values, _n1);
- for (int i = 0; i < _n1; ++i) {
- values[i] = (int)1;
- }
- }
- SerializerNodeType Serialize(Serializer &_s);
- template
- string ToCSV() {
- int _asize = ArraySize(values);
- string _result = "";
- for (int i = 0; i < _asize; i++) {
- _result += StringFormat("%s%s", (string)values[i].Get(), i < _asize ? "," : "");
- }
- return _result;
- }
- template
- string ToString() {
- return ToCSV();
- }
-};
-
/* Structure for indicator parameters. */
struct IndicatorParams {
- public: // @todo: Change it to protected.
- string name; // Name of the indicator.
- int shift; // Shift (relative to the current bar, 0 - default).
- unsigned int max_buffers; // Max buffers to store.
- unsigned int max_modes; // Max supported indicator modes (values per entry).
- unsigned int max_params; // Max supported input params.
- ChartTf tf; // Chart's timeframe.
- ENUM_INDICATOR_TYPE itype; // Indicator type (e.g. INDI_RSI).
- ENUM_IDATA_SOURCE_TYPE idstype; // Indicator's data source type (e.g. IDATA_BUILTIN, IDATA_ICUSTOM).
- ENUM_IDATA_VALUE_RANGE idvrange; // Indicator's range value data type.
- // ENUM_IDATA_VALUE_TYPE idvtype; // Indicator's data value type (e.g. TDBL1, TDBL2, TINT1).
- ENUM_DATATYPE dtype; // Type of basic data to store values (DTYPE_DOUBLE, DTYPE_INT).
+ public: // @todo: Change it to protected.
+ string name; // Name of the indicator.
+ int shift; // Shift (relative to the current bar, 0 - default).
+ unsigned int max_params; // Max supported input params.
+ ChartTf tf; // Chart's timeframe.
+ ENUM_INDICATOR_TYPE itype; // Indicator type (e.g. INDI_RSI).
color indi_color; // Indicator color.
- int indi_data_source_id; // Id of the indicator to be used as data source.
- int indi_data_source_mode; // Mode used as input from data source.
ARRAY(DataParamEntry, input_params); // Indicator input params.
bool is_draw; // Draw active.
int draw_window; // Drawing window.
@@ -425,19 +64,16 @@ struct IndicatorParams {
public:
/* Special methods */
// Constructor.
- IndicatorParams(ENUM_INDICATOR_TYPE _itype = INDI_NONE, unsigned int _max_modes = 1,
- ENUM_DATATYPE _dtype = TYPE_DOUBLE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT,
- ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, string _name = "")
+ IndicatorParams(ENUM_INDICATOR_TYPE _itype = INDI_NONE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _name = "")
: custom_indi_name(""),
- dtype(_dtype),
name(_name),
shift(0),
- max_modes(_max_modes),
- max_buffers(10),
- idstype(_idstype),
- idvrange(IDATA_RANGE_UNKNOWN),
- indi_data_source_id(-1),
- indi_data_source_mode(-1),
+ // max_modes(_max_modes),
+ // max_buffers(10),
+ // idstype(_idstype),
+ // idvrange(IDATA_RANGE_UNKNOWN),
+ // indi_data_source_id(-1),
+ // indi_data_source_mode(-1),
itype(_itype),
is_draw(false),
indi_color(clrNONE),
@@ -445,16 +81,16 @@ struct IndicatorParams {
tf(_tf) {
Init();
};
- IndicatorParams(string _name, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN)
+ IndicatorParams(string _name)
: custom_indi_name(""),
name(_name),
shift(0),
- max_modes(1),
- max_buffers(10),
- idstype(_idstype),
- idvrange(IDATA_RANGE_UNKNOWN),
- indi_data_source_id(-1),
- indi_data_source_mode(-1),
+ // max_modes(1),
+ // max_buffers(10),
+ // idstype(_idstype),
+ // idvrange(IDATA_RANGE_UNKNOWN),
+ // indi_data_source_id(-1),
+ // indi_data_source_mode(-1),
is_draw(false),
indi_color(clrNONE),
draw_window(0) {
@@ -470,15 +106,10 @@ struct IndicatorParams {
void Init() {}
/* Getters */
string GetCustomIndicatorName() const { return custom_indi_name; }
- int GetDataSourceId() const { return indi_data_source_id; }
- int GetDataSourceMode() const { return indi_data_source_mode; }
color GetIndicatorColor() const { return indi_color; }
- int GetMaxModes() const { return (int)max_modes; }
int GetMaxParams() const { return (int)max_params; }
int GetShift() const { return shift; }
- ENUM_DATATYPE GetDataValueType() const { return dtype; }
- ENUM_IDATA_SOURCE_TYPE GetDataSourceType() const { return idstype; }
- ENUM_IDATA_VALUE_RANGE GetIDataValueRange() const { return idvrange; }
+ ENUM_INDICATOR_TYPE GetIndicatorType() { return itype; }
ENUM_TIMEFRAMES GetTf() const { return tf.GetTf(); }
template
T GetInputParam(int _index, T _default) const {
@@ -507,10 +138,6 @@ struct IndicatorParams {
}
/* Setters */
void SetCustomIndicatorName(string _name) { custom_indi_name = _name; }
- void SetDataSourceMode(int _mode) { indi_data_source_mode = _mode; }
- void SetDataSourceType(ENUM_IDATA_SOURCE_TYPE _idstype) { idstype = _idstype; }
- void SetDataValueRange(ENUM_IDATA_VALUE_RANGE _idvrange) { idvrange = _idvrange; }
- void SetDataValueType(ENUM_DATATYPE _dtype) { dtype = _dtype; }
void SetDraw(bool _draw = true, int _window = 0) {
is_draw = _draw;
draw_window = _window;
@@ -521,11 +148,6 @@ struct IndicatorParams {
draw_window = _window;
}
void SetIndicatorColor(color _clr) { indi_color = _clr; }
- void SetDataSource(int _id, int _input_mode = -1) {
- indi_data_source_id = _id;
- indi_data_source_mode = _input_mode;
- idstype = IDATA_INDICATOR;
- }
void SetIndicatorType(ENUM_INDICATOR_TYPE _itype) { itype = _itype; }
void SetInputParams(ARRAY_REF(DataParamEntry, _params)) {
int _asize = ArraySize(_params);
@@ -534,14 +156,12 @@ struct IndicatorParams {
input_params[i] = _params[i];
}
}
- void SetMaxModes(int _value) { max_modes = _value; }
void SetMaxParams(int _value) {
max_params = _value;
ArrayResize(input_params, max_params);
}
void SetName(string _name) { name = _name; };
void SetShift(int _shift) { shift = _shift; }
- void SetSize(int _size) { max_buffers = _size; };
void SetTf(ENUM_TIMEFRAMES _tf) { tf.SetTf(_tf); }
// Serializers.
// SERIALIZER_EMPTY_STUB;
@@ -551,14 +171,16 @@ struct IndicatorParams {
/* Structure for indicator state. */
struct IndicatorState {
+ public: // @todo: Change it to protected.
+ int handle; // Indicator handle (MQL5 only).
+ bool is_changed; // Set when params has been recently changed.
+ bool is_ready; // Set when indicator is ready (has valid values).
+ public:
enum ENUM_INDICATOR_STATE_PROP {
INDICATOR_STATE_PROP_HANDLE,
INDICATOR_STATE_PROP_IS_CHANGED,
INDICATOR_STATE_PROP_IS_READY,
};
- int handle; // Indicator handle (MQL5 only).
- bool is_changed; // Set when params has been recently changed.
- bool is_ready; // Set when indicator is ready (has valid values).
// Constructor.
IndicatorState() : handle(INVALID_HANDLE), is_changed(true), is_ready(false) {}
// Getters.
diff --git a/Indicator.struct.serialize.h b/Indicator.struct.serialize.h
index 98e262c60..e9a68a534 100644
--- a/Indicator.struct.serialize.h
+++ b/Indicator.struct.serialize.h
@@ -30,81 +30,16 @@
// Forward class declaration.
class Serializer;
-/* Method to serialize IndicatorDataEntry structure. */
-SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) {
- int _asize = ArraySize(values);
- _s.Pass(THIS_REF, "datetime", timestamp, SERIALIZER_FIELD_FLAG_DYNAMIC);
- _s.Pass(THIS_REF, "flags", flags, SERIALIZER_FIELD_FLAG_DYNAMIC);
- for (int i = 0; i < _asize; i++) {
- // _s.Pass(THIS_REF, (string)i, values[i], SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); // Can
- // this work? _s.Pass(THIS_REF, (string)i, GetEntry(i), SERIALIZER_FIELD_FLAG_DYNAMIC |
- // SERIALIZER_FIELD_FLAG_FEATURE); // Can this work?
-
- switch (values[i].GetDataType()) {
- case TYPE_DOUBLE:
- _s.Pass(THIS_REF, (string)i, values[i].value.vdbl,
- SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE);
- break;
- case TYPE_FLOAT:
- _s.Pass(THIS_REF, (string)i, values[i].value.vflt,
- SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE);
- break;
- case TYPE_INT:
- case TYPE_UINT:
- if (CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) {
- // Split for each bit and pass 0 or 1.
- for (int j = 0; j < sizeof(int) * 8; ++j) {
- int _value = (values[i].value.vint & (1 << j)) != 0;
- _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE);
- }
- } else {
- _s.Pass(THIS_REF, (string)i, values[i].value.vint,
- SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE);
- }
- break;
- case TYPE_LONG:
- case TYPE_ULONG:
- if (CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) {
- // Split for each bit and pass 0 or 1.
- /* @fixme: j, j already defined.
- for (int j = 0; j < sizeof(int) * 8; ++j) {
- int _value = (values[i].vlong & (1 << j)) != 0;
- _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE);
- }
- */
- SetUserError(ERR_INVALID_PARAMETER);
- } else {
- _s.Pass(THIS_REF, (string)i, values[i].value.vlong,
- SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE);
- }
- break;
- default:
- SetUserError(ERR_INVALID_PARAMETER);
- break;
- }
- }
- return SerializerNodeObject;
-}
-
-/* Method to serialize IndicatorDataEntry's IndicatorDataEntryValue union. */
-SerializerNodeType IndicatorDataEntryValue::Serialize(Serializer &_s) {
- _s.Pass(THIS_REF, "flags", flags);
- _s.Pass(THIS_REF, "vdbl", value.vdbl);
- _s.Pass(THIS_REF, "vflt", value.vflt);
- _s.Pass(THIS_REF, "vint", value.vint);
- _s.Pass(THIS_REF, "vlong", value.vlong);
- return SerializerNodeObject;
-};
-
/* Method to serialize IndicatorParams structure. */
SerializerNodeType IndicatorParams::Serialize(Serializer &s) {
s.Pass(THIS_REF, "name", name);
s.Pass(THIS_REF, "shift", shift);
- s.Pass(THIS_REF, "max_modes", max_modes);
- s.Pass(THIS_REF, "max_buffers", max_buffers);
+ // s.Pass(THIS_REF, "max_modes", max_modes);
+ // s.Pass(THIS_REF, "max_buffers", max_buffers);
s.PassEnum(THIS_REF, "itype", itype);
- s.PassEnum(THIS_REF, "idstype", idstype);
- s.PassEnum(THIS_REF, "dtype", dtype);
+ // s.PassEnum(THIS_REF, "idstype", idstype);
+ // s.PassEnum(THIS_REF, "dtype", dtype);
+
// s.PassObject(this, "indicator", indi_data); // @todo
// s.Pass(THIS_REF, "indi_data_ownership", indi_data_ownership);
s.Pass(THIS_REF, "indi_color", indi_color, SERIALIZER_FIELD_FLAG_HIDDEN);
diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h
index c0ff4637a..b5036d67e 100644
--- a/Indicator/IndicatorCandle.h
+++ b/Indicator/IndicatorCandle.h
@@ -31,8 +31,8 @@
// Includes.
#include "../Buffer/BufferCandle.h"
-#include "../Indicator.mqh"
#include "../Candle.struct.h"
+#include "../Indicator.mqh"
// Indicator modes.
enum ENUM_INDI_CANDLE_MODE {
@@ -67,7 +67,6 @@ class IndicatorCandle : public Indicator {
flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP;
icdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED);
icdata.SetOverflowListener(IndicatorCandleOverflowListener, 10);
- iparams.SetMaxModes(4);
}
public:
@@ -76,8 +75,9 @@ class IndicatorCandle : public Indicator {
/**
* Class constructor.
*/
- IndicatorCandle(const TS& _icparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0)
- : Indicator(_icparams, _indi_src, _indi_mode) {
+ IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL,
+ int _indi_mode = 0)
+ : Indicator(_icparams, _idparams, _indi_src, _indi_mode) {
Init();
}
IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0,
@@ -125,7 +125,8 @@ class IndicatorCandle : public Indicator {
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());
+ 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);
diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h
index 84fe4b7c0..fb0f714b9 100644
--- a/Indicator/IndicatorTf.h
+++ b/Indicator/IndicatorTf.h
@@ -79,7 +79,10 @@ class IndicatorTf : public IndicatorCandle {
/**
* Class constructor with parameters.
*/
- IndicatorTf(TFP &_params) : IndicatorCandle(_params) { Init(); }
+ IndicatorTf(TFP& _icparams, const IndicatorDataParams& _idparams)
+ : IndicatorCandle(_icparams, _idparams) {
+ Init();
+ }
};
#endif
diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h
index e654dde70..afb1075ea 100644
--- a/Indicator/IndicatorTick.h
+++ b/Indicator/IndicatorTick.h
@@ -66,7 +66,7 @@ class IndicatorTick : public Indicator {
itdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED);
itdata.SetOverflowListener(IndicatorTickOverflowListener, 10);
// Ask and Bid price.
- itparams.SetMaxModes(2);
+ Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2);
}
public:
@@ -75,8 +75,9 @@ class IndicatorTick : public Indicator {
/**
* Class constructor.
*/
- IndicatorTick(const TS& _itparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0)
- : Indicator(_itparams, _indi_src, _indi_mode) {
+ IndicatorTick(const TS& _itparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL,
+ int _indi_mode = 0)
+ : Indicator(_itparams, _idparams, _indi_src, _indi_mode) {
itparams = _itparams;
if (_indi_src != NULL) {
SetDataSource(_indi_src, _indi_mode);
@@ -153,12 +154,13 @@ class IndicatorTick : public Indicator {
TickAB _tick = itdata.GetByKey(_timestamp);
return TickToEntry(_timestamp, _tick);
}
+ int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES));
// No tick at given timestamp. Returning invalid entry.
- IndicatorDataEntry _entry(itparams.GetMaxModes());
+ IndicatorDataEntry _entry(_max_modes);
GetEntryAlter(_entry, _timestamp);
- for (int i = 0; i < itparams.GetMaxModes(); ++i) {
+ for (int i = 0; i < _max_modes; ++i) {
_entry.values[i] = (double)0;
}
@@ -173,7 +175,8 @@ class IndicatorTick : public Indicator {
* 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()));
+ ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE));
+ _entry.AddFlags(_entry.GetDataTypeFlags(_dtype));
};
/**
@@ -206,7 +209,8 @@ class IndicatorTick : public Indicator {
*/
void SetDataSource(IndicatorBase* _indi, int _input_mode = -1) {
indi_src = _indi;
- itparams.SetDataSource(-1, _input_mode);
+ Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID), -1);
+ Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE), _input_mode);
}
/* Virtual methods */
diff --git a/Indicator/IndicatorTickOrCandleSource.h b/Indicator/IndicatorTickOrCandleSource.h
index 45fce1acd..491766979 100644
--- a/Indicator/IndicatorTickOrCandleSource.h
+++ b/Indicator/IndicatorTickOrCandleSource.h
@@ -41,9 +41,12 @@ class IndicatorTickOrCandleSource : public Indicator {
/**
* 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(const TS& _iparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL,
+ int _indi_mode = 0)
+ : Indicator(_iparams, _idparams, _indi_src, _indi_mode) {}
+ IndicatorTickOrCandleSource(const TS& _iparams, const IndicatorDataParams& _idparams,
+ ENUM_TIMEFRAMES _tf = PERIOD_CURRENT)
+ : Indicator(_iparams, _idparams, _tf) {}
IndicatorTickOrCandleSource(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0,
string _name = "")
: Indicator(_itype, _tf, _shift, _name) {}
@@ -57,7 +60,7 @@ class IndicatorTickOrCandleSource : public Indicator {
* 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 {
+ bool OnValidateDataSource(IndicatorData* _ds, string& _reason) override {
// @todo Make use of this method.
return true;
}
@@ -72,9 +75,9 @@ class IndicatorTickOrCandleSource : public Indicator {
/**
* Creates default, tick based indicator for given applied price.
*/
- IndicatorBase* DataSourceRequestReturnDefault(int _applied_price) override {
+ IndicatorData* DataSourceRequestReturnDefault(int _applied_price) override {
// Returning real candle indicator. Thus way we can use SetAppliedPrice() and select Ask or Bid price.
- IndicatorBase* _indi;
+ IndicatorData* _indi;
switch (_applied_price) {
case PRICE_ASK:
diff --git a/Indicator/IndicatorTickSource.h b/Indicator/IndicatorTickSource.h
index 6e1734f4c..8b47180a5 100644
--- a/Indicator/IndicatorTickSource.h
+++ b/Indicator/IndicatorTickSource.h
@@ -37,9 +37,11 @@ class IndicatorTickSource : public Indicator {
/**
* 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(const TS& _iparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL,
+ int _indi_mode = 0)
+ : Indicator(_iparams, _idparams, _indi_src, _indi_mode) {}
+ IndicatorTickSource(const TS& _iparams, const IndicatorDataParams& _idparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT)
+ : Indicator(_iparams, _idparams, _tf) {}
IndicatorTickSource(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0,
string _name = "")
: Indicator(_itype, _tf, _shift, _name) {}
@@ -52,7 +54,7 @@ class IndicatorTickSource : public Indicator {
/**
* Sets indicator data source.
*/
- void SetDataSource(IndicatorBase* _indi, int _input_mode = -1) override {
+ void SetDataSource(IndicatorData* _indi, int _input_mode = -1) override {
if (_indi == NULL) {
// Just deselecting data source.
Indicator::SetDataSource(_indi, _input_mode);
@@ -112,7 +114,7 @@ class IndicatorTickSource : public Indicator {
* 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 {
+ bool OnValidateDataSource(IndicatorData* _ds, string& _reason) override {
// @todo Make use of this method.
return true;
}
diff --git a/Indicator/tests/IndicatorTf.test.mq5 b/Indicator/tests/IndicatorTf.test.mq5
index c9cb9d86f..d09b77905 100644
--- a/Indicator/tests/IndicatorTf.test.mq5
+++ b/Indicator/tests/IndicatorTf.test.mq5
@@ -1,6 +1,6 @@
//+------------------------------------------------------------------+
//| EA31337 framework |
-//| Copyright 2016-2021, EA31337 Ltd |
+//| Copyright 2016-2022, EA31337 Ltd |
//| https://github.com/EA31337 |
//+------------------------------------------------------------------+
diff --git a/Indicator/tests/classes/IndicatorTickDummy.h b/Indicator/tests/classes/IndicatorTickDummy.h
index 683025176..dcc473b88 100644
--- a/Indicator/tests/classes/IndicatorTickDummy.h
+++ b/Indicator/tests/classes/IndicatorTickDummy.h
@@ -35,18 +35,20 @@
// Params for dummy tick-based indicator.
struct IndicatorTickDummyParams : IndicatorParams {
- IndicatorTickDummyParams() : IndicatorParams(INDI_TICK, 2, TYPE_DOUBLE) {}
+ IndicatorTickDummyParams() : IndicatorParams(INDI_TICK) {}
};
// Dummy tick-based indicator.
class IndicatorTickDummy : public IndicatorTick {
public:
IndicatorTickDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "")
- : IndicatorTick(INDI_TICK, _tf, _shift, _name) {}
+ : IndicatorTick(INDI_TICK, _tf, _shift, _name) {
+ Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2);
+ }
string GetName() override { return "IndicatorTickDummy"; }
- void OnBecomeDataSourceFor(IndicatorBase* _base_indi) override {
+ void OnBecomeDataSourceFor(IndicatorData* _base_indi) override {
// Feeding base indicator with historic entries of this indicator.
Print(GetName(), " became a data source for ", _base_indi.GetName());
diff --git a/Indicator/tests/classes/IndicatorTickReal.h b/Indicator/tests/classes/IndicatorTickReal.h
index 977c5cc48..fc20d98c5 100644
--- a/Indicator/tests/classes/IndicatorTickReal.h
+++ b/Indicator/tests/classes/IndicatorTickReal.h
@@ -35,28 +35,30 @@
// Params for real tick-based indicator.
struct IndicatorTickRealParams : IndicatorParams {
- IndicatorTickRealParams() : IndicatorParams(INDI_TICK, 3, TYPE_DOUBLE) {}
+ IndicatorTickRealParams() : IndicatorParams(INDI_TICK) {}
};
// Real tick-based indicator.
class IndicatorTickReal : public IndicatorTick {
public:
IndicatorTickReal(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "")
- : IndicatorTick(INDI_TICK, _tf, _shift, _name) {}
+ : IndicatorTick(INDI_TICK, _tf, _shift, _name) {
+ Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 3);
+ }
string GetName() override { return "IndicatorTickReal"; }
- void OnBecomeDataSourceFor(IndicatorBase* _base_indi) override {
+ void OnBecomeDataSourceFor(IndicatorData* _indi) override {
// Feeding base indicator with historic entries of this indicator.
#ifdef __debug__
- Print(GetFullName(), " became a data source for ", _base_indi.GetFullName());
+ Print(GetFullName(), " became a data source for ", _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,
+ Print(_indi.GetFullName(), " will be now filled with ", _ticks_to_emit,
" historical entries generated by " + GetFullName());
#endif
@@ -82,7 +84,7 @@ class IndicatorTickReal : public IndicatorTick
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));
+ _indi.OnDataSourceEntry(TickToEntry(_ticks[i].time, _tick));
}
#endif
}
diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h
index f8258b555..1d1da2066 100644
--- a/Indicator/tests/classes/Indicators.h
+++ b/Indicator/tests/classes/Indicators.h
@@ -30,23 +30,23 @@
#endif
// Includes.
-#include "../../../IndicatorBase.h"
+#include "../../../IndicatorData.mqh"
#include "../../../Refs.mqh"
/**
* Helper class to store all indicators and call OnTick() on them.
*/
class Indicators {
- Ref _indis[];
+ Ref _indis[];
public:
void Add(IndicatorBase* _indi) {
- Ref _ref = _indi;
+ Ref _ref = _indi;
ArrayPushObject(_indis, _ref);
}
- void Remove(IndicatorBase* _indi) {
- Ref _ref = _indi;
+ void Remove(IndicatorData* _indi) {
+ Ref