diff --git a/.clang-format b/.clang-format index 3442bc765..d64b4533c 100644 --- a/.clang-format +++ b/.clang-format @@ -2,3 +2,4 @@ Language: Cpp BasedOnStyle: Google ColumnLimit: 120 +IndentPPDirectives: BeforeHash diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..9e7ce8e04 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,108 @@ +--- +Checks: |- + *, + -altera-id-dependent-backward-branch, + -altera-struct-pack-align, + -altera-unroll-loops, + -bugprone-branch-clone, + -bugprone-copy-constructor-init, + -bugprone-easily-swappable-parameters, + -bugprone-integer-division, + -bugprone-macro-parentheses, + -bugprone-narrowing-conversions, + -bugprone-redundant-branch-condition, + -bugprone-reserved-identifier, + -bugprone-string-constructor, + -bugprone-unhandled-self-assignment, + -cert-dcl37-c, + -cert-dcl51-cpp, + -cert-msc30-c, + -cert-msc50-cpp, + -cert-oop54-cpp, + -cert-oop54-cpp, + -clang-diagnostic-error, + -concurrency-mt-unsafe, + -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-avoid-non-const-global-variables, + -cppcoreguidelines-c-copy-assignment-signature, + -cppcoreguidelines-init-variables, + -cppcoreguidelines-macro-usage, + -cppcoreguidelines-narrowing-conversions, + -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-owning-memory, + -cppcoreguidelines-prefer-member-initializer, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-type-member-init, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-pro-type-vararg, + -cppcoreguidelines-special-member-functions, + -fuchsia-default-arguments-calls, + -fuchsia-default-arguments-declarations, + -fuchsia-overloaded-operator, + -fuchsia-trailing-return, + -google-explicit-constructor, + -google-global-names-in-headers, + -google-readability-braces-around-statements, + -google-readability-casting, + -google-runtime-int, + -hicpp-avoid-c-arrays, + -hicpp-braces-around-statements, + -hicpp-braces-around-statements, + -hicpp-exception-baseclass, + -hicpp-explicit-conversions, + -hicpp-member-init, + -hicpp-multiway-paths-covered, + -hicpp-named-parameter, + -hicpp-no-array-decay, + -hicpp-signed-bitwise,, + -hicpp-special-member-functions, + -hicpp-uppercase-literal-suffix, + -hicpp-use-auto, + -hicpp-use-equals-default, + -hicpp-use-nullptr, + -hicpp-vararg, + -llvm-else-after-return, + -llvm-header-guard,, + -llvmlibc-callee-namespace, + -llvmlibc-implementation-in-namespace,, + -llvmlibc-restrict-system-libc-headers, + -misc-definitions-in-headers, + -misc-no-recursion, + -misc-non-private-member-variables-in-classes, + -misc-non-private-member-variables-in-classes, + -misc-unconventional-assign-operator, + -misc-unused-parameters,, + -modernize-avoid-c-arrays, + -modernize-raw-string-literal, + -modernize-redundant-void-arg, + -modernize-use-auto, + -modernize-use-default-member-init, + -modernize-use-equals-default, + -modernize-use-nullptr, + -modernize-use-nullptr, + -modernize-use-trailing-return-type, + -modernize-use-using, + -performance-unnecessary-value-param, + -readability-avoid-const-params-in-decls, + -readability-braces-around-statements, + -readability-braces-around-statements, + -readability-const-return-type, + -readability-container-size-empty, + -readability-convert-member-functions-to-static, + -readability-delete-null-pointer, + -readability-else-after-return, + -readability-identifier-length, + -readability-implicit-bool-conversion, + -readability-isolate-declaration, + -readability-magic-numbers, + -readability-make-member-function-const, + -readability-named-parameter, + -readability-redundant-access-specifiers, + -readability-redundant-declaration, + -readability-redundant-string-init, + -readability-simplify-boolean-expr, + -readability-uppercase-literal-suffix, +FormatStyle: file +HeaderFilterRegex: '.*' +WarningsAsErrors: '' diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..3712cbb64 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,9 @@ +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.238.1/containers/ubuntu/.devcontainer/base.Dockerfile + +# [Choice] Ubuntu version (use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon): ubuntu-22.04, ubuntu-20.04, ubuntu-18.04 +ARG VARIANT="jammy" +FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} + +# [Optional] Uncomment this section to install additional OS packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 44cb575cc..84285b19d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,14 +1,25 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu { + + // "build": { + // "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick an Ubuntu version: jammy / ubuntu-22.04, focal / ubuntu-20.04, bionic /ubuntu-18.04 + // Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon. + // "args": { "VARIANT": "ubuntu-22.04" } + // }, + // Configure tool-specific properties. "customizations": { "vscode": { "extensions": [ "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack", + "nicholishen.mql-over-cpp", "vscodevim.vim", "DavidAnson.vscode-markdownlint", - "EA31337.vscode-mql-tools" + "EA31337.vscode-mql-tools", + "xaver.clang-format" ], } }, @@ -23,7 +34,17 @@ // "ghcr.io/maks1ms/devcontainers-features/wine:0": {}, "ghcr.io/devcontainers-contrib/features/node-asdf:0": {} }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile "image": "mcr.microsoft.com/devcontainers/base:jammy", "name": "EA31337" + + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode", } diff --git a/.github/workflows/compile-cpp.yml b/.github/workflows/compile-cpp.yml index 60d4612b8..1aecc1521 100644 --- a/.github/workflows/compile-cpp.yml +++ b/.github/workflows/compile-cpp.yml @@ -13,7 +13,6 @@ on: jobs: FileList: - if: ${{ false }} # @fixme outputs: filelist: ${{ steps.get-files.outputs.filelist }} runs-on: ubuntu-latest @@ -30,7 +29,6 @@ jobs: run: echo ${{ steps.get-files.outputs.filelist }} Compile: - if: ${{ false }} # @fixme runs-on: ubuntu-latest needs: [FileList] strategy: @@ -45,9 +43,11 @@ jobs: with: compiler: gcc-latest - name: Compile ${{ matrix.file }} via emcc - run: emcc "${{ matrix.file }}" + if: always() + run: > + emcc -s WASM=1 -s ENVIRONMENT=node -s EXIT_RUNTIME=0 -s NO_EXIT_RUNTIME=1 -s ASSERTIONS=1 -Wall -s + MODULARIZE=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 --bind -s EXPORTED_FUNCTIONS="[]" -g -std=c++17 + "${{ matrix.file }}" - name: Compile ${{ matrix.file }} via g++ - run: g++ -c "${{ matrix.file }}" - - if: failure() - # Force success. - run: exit 0 + if: always() + run: g++ -g -std=c++17 -c "${{ matrix.file }}" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ff0153775..2b2c96d05 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,6 +39,7 @@ jobs: strategy: matrix: test: + - AccountTest - BufferStructTest - BufferTest - ChartTest @@ -59,6 +60,7 @@ jobs: - SummaryReportTest - TickerTest - TradeTest + max-parallel: 4 steps: - uses: actions/download-artifact@v2 with: @@ -72,6 +74,7 @@ jobs: Version: 4 TestExpert: ${{ matrix.test }} RunOnError: show_logs 200 + if: always() timeout-minutes: 10 Scripts-MQL4: @@ -100,6 +103,7 @@ jobs: - TerminalTest - TimerTest - ValueStorageTest + max-parallel: 4 steps: - uses: actions/download-artifact@v2 with: @@ -108,6 +112,7 @@ jobs: uses: fx31337/mql-tester-action@master with: Script: ${{ matrix.test }} + if: always() timeout-minutes: 10 Scripts-MQL4-Ignore: @@ -134,6 +139,7 @@ jobs: with: Script: ${{ matrix.test }} RunOnFail: "exit 0" + if: always() timeout-minutes: 10 Trade-Tests-MQL4: @@ -156,6 +162,7 @@ jobs: uses: fx31337/mql-tester-action@master with: Script: ${{ matrix.test }} + if: always() timeout-minutes: 10 cleanup: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f9e1999f3..a99a55cc2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,6 +2,11 @@ exclude: '\.md$' repos: + # - repo: https://github.com/pre-commit/mirrors-clang-format + # rev: v14.0.6 + # hooks: + # - id: clang-format + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.0.1 hooks: diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index af9a319f0..4df50d599 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -25,6 +25,7 @@ * 3D chart candles renderer. */ +#include "../Chart.define.h" #include "Chart3DType.h" #include "Cube.h" #include "Device.h" diff --git a/3D/Mesh.h b/3D/Mesh.h index 05c10e3c3..95cbf8ce3 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -45,8 +45,13 @@ struct PointEntry { T point; long key; + // Default constructor. PointEntry() {} + // Copy constructor. + PointEntry(const PointEntry& r) : point(r.point), key(r.key) {} + + // Constructor. PointEntry(const T& _point) { point = _point; key = MakeKey(_point.Position.x, _point.Position.y, _point.Position.z); diff --git a/3D/Vertex.h b/3D/Vertex.h index 8466fa312..f9b84851e 100644 --- a/3D/Vertex.h +++ b/3D/Vertex.h @@ -8,11 +8,18 @@ struct Vertex { DXVector3 Normal; DXColor Color; - Vertex() { - Color.r = 1.0f; - Color.g = 1.0f; - Color.b = 1.0f; - Color.a = 1.0f; + // Default constructor. + Vertex(float r = 1, float g = 1, float b = 1, float a = 1) { + Color.r = r; + Color.g = g; + Color.b = b; + Color.a = a; + } + + Vertex(const Vertex &r) { + Position = r.Position; + Normal = r.Normal; + Color = r.Color; } static const ShaderVertexLayout Layout[3]; diff --git a/Account/Account.struct.h b/Account/Account.struct.h index eaa8d466c..8a33fe210 100644 --- a/Account/Account.struct.h +++ b/Account/Account.struct.h @@ -28,7 +28,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#include "../Serializer.enum.h" +#include "../Serializer/Serializer.enum.h" #endif // Forward class declaration. @@ -48,6 +48,21 @@ struct AccountEntry { double margin_used; double margin_free; double margin_avail; + + // Default constructor. + AccountEntry() {} + + // Constructor. + AccountEntry(const AccountEntry& r) + : dtime(r.dtime), + balance(r.balance), + credit(r.credit), + equity(r.equity), + profit(r.profit), + margin_used(r.margin_used), + margin_free(r.margin_free), + margin_avail(r.margin_avail) {} + // Serializers. void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} SerializerNodeType Serialize(Serializer& _s) { diff --git a/Account/AccountBase.struct.h b/Account/AccountBase.struct.h index 14d0773b4..50641290f 100644 --- a/Account/AccountBase.struct.h +++ b/Account/AccountBase.struct.h @@ -28,7 +28,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#include "../Serializer.enum.h" +#include "../Serializer/Serializer.enum.h" #endif // Forward class declaration. @@ -36,6 +36,7 @@ class Serializer; // Includes. #include "../Serializer/Serializer.h" +#include "../Std.h" #include "../Terminal.define.h" // Struct for account entries. diff --git a/Account/AccountMt.h b/Account/AccountMt.h index a444f1084..b0ff5decd 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -37,6 +37,7 @@ class AccountMt; #include "../Orders.mqh" #include "../Serializer/Serializer.h" #include "../SymbolInfo.mqh" +#include "../Task/TaskCondition.enum.h" #include "../Trade.struct.h" #include "Account.define.h" #include "Account.enum.h" @@ -284,7 +285,7 @@ class AccountMt : public AccountBase { return ::AccountFreeMarginMode(); #else // @todo: Not implemented yet. - return NULL; + return NULL_VALUE; #endif } static double GetAccountFreeMarginMode() { return AccountMt::AccountFreeMarginMode(); } @@ -470,7 +471,7 @@ class AccountMt : public AccountBase { */ bool IsFreeMargin(ENUM_ORDER_TYPE _cmd, double size_of_lot, string _symbol = NULL) { bool _res = true; - double margin = AccountFreeMarginCheck(_symbol, _cmd, size_of_lot); + // double margin = AccountFreeMarginCheck(_symbol, _cmd, size_of_lot); if (GetLastError() == 134 /* NOT_ENOUGH_MONEY */) _res = false; return (_res); } @@ -614,13 +615,14 @@ class AccountMt : public AccountBase { /** * Returns text info about the account. */ - string ToString() { + string const ToString() { return StringFormat( "Type: %s, Server/Company/Name: %s/%s/%s, Currency: %s, Balance: %g, Credit: %g, Equity: %g, Profit: %g, " "Margin Used/Free/Avail: %g(%.1f%%)/%g/%g, Orders limit: %g: Leverage: 1:%d, StopOut Level: %d (Mode: %d)", - GetType(), GetServerName(), GetCompanyName(), GetAccountName(), GetCurrency(), GetBalance(), GetCredit(), - GetEquity(), GetProfit(), GetMarginUsed(), GetMarginUsedInPct(), GetMarginFree(), GetMarginAvail(), - GetLimitOrders(), GetLeverage(), GetStopoutLevel(), GetStopoutMode()); + C_STR(GetType()), C_STR(GetServerName()), C_STR(GetCompanyName()), C_STR(GetAccountName()), + C_STR(GetCurrency()), GetBalance(), GetCredit(), GetEquity(), GetProfit(), GetMarginUsed(), + GetMarginUsedInPct(), GetMarginFree(), GetMarginAvail(), GetLimitOrders(), GetLeverage(), GetStopoutLevel(), + GetStopoutMode()); } /** diff --git a/Array.extern.h b/Array.extern.h index bfdaf7f2f..fcedddc15 100644 --- a/Array.extern.h +++ b/Array.extern.h @@ -24,36 +24,71 @@ #ifndef __MQL__ #pragma once +#include "Common.extern.h" #include "Std.h" +#include "String.extern.h" template -extern int ArraySize(const ARRAY_REF(T, _array)); +int ArraySize(const ARRAY_REF(T, _array)) { + return _array.size(); +} template -extern constexpr int ArraySize(const T REF(_array)[size]); +constexpr int ArraySize(const T REF(_array)[size]) { + return size; +} template -extern int ArrayResize(ARRAY_REF(T, _array), int _new_size, int _reserve_size = 0); +int ArrayResize(ARRAY_REF(T, _array), int _new_size, int _reserve_size = 0) { + _array.resize(_new_size, _reserve_size); + return _new_size; +} template -extern bool ArraySetAsSeries(ARRAY_REF(T, _array), bool _flag); +bool ArraySetAsSeries(ARRAY_REF(T, _array), bool _flag) { + _array.setIsSeries(_flag); + return true; +} template -extern int ArrayMaximum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY); +bool ArrayGetAsSeries(ARRAY_REF(T, _array)) { + return _array.getIsSeries(); +} template -extern int ArrayMinimum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY); +int ArrayMaximum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} template -extern int ArrayFree(const ARRAY_REF(T, _array)); +int ArrayMinimum(const ARRAY_REF(T, _array), int _start = 0, unsigned int _count = WHOLE_ARRAY) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} template -extern int ArrayReverse(const ARRAY_REF(T, _array)); +int ArrayFree(ARRAY_REF(T, _array)) { + _array.resize(0, 0); + return 0; +} template -extern int ArrayInitialize(ARRAY_REF(T, array), char value); +bool ArrayReverse(ARRAY_REF(T, _array)) { + _array.reverse(); + return true; +} template -extern int ArraySort(ARRAY_REF(T, array)); +extern int ArrayInitialize(ARRAY_REF(T, array), char value) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +template +extern int ArraySort(ARRAY_REF(T, array)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} #endif diff --git a/Bar.struct.h b/Bar.struct.h index b66f4e50a..3b9074271 100644 --- a/Bar.struct.h +++ b/Bar.struct.h @@ -51,15 +51,15 @@ struct BarOHLC datetime time; double open, high, low, close; // Struct constructor. - BarOHLC() : open(0), high(0), low(0), close(0), time(0){}; + BarOHLC() : time(0), open(0), high(0), low(0), close(0){}; BarOHLC(double _open, double _high, double _low, double _close, datetime _time = 0) : time(_time), open(_open), high(_high), low(_low), close(_close) { - if (_time == 0) { + if (_time == (datetime)0) { _time = TimeCurrent(); } } BarOHLC(ARRAY_REF(double, _prices), datetime _time = 0) : time(_time) { - _time = _time == 0 ? TimeCurrent() : _time; + _time = _time == (datetime)0 ? TimeCurrent() : _time; int _size = ArraySize(_prices); close = _prices[0]; open = _prices[_size - 1]; @@ -261,5 +261,5 @@ struct BarEntry { s.PassStruct(THIS_REF, "ohlc", ohlc, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } - string ToCSV() { return StringFormat("%s", ohlc.ToCSV()); } + string ToCSV() { return StringFormat("%s", C_STR(ohlc.ToCSV())); } }; diff --git a/Buffer/BufferTick.h b/Buffer/BufferTick.h index 7ae8d7e17..de986565a 100644 --- a/Buffer/BufferTick.h +++ b/Buffer/BufferTick.h @@ -30,6 +30,10 @@ #include "../Storage/IValueStorage.h" #include "../Tick/Tick.struct.h" +// Forward declarations. +template +class BufferTick; + // TV = Type of price stored by BufferTick. RV = Type of property to be retrieved from BufferTick. template class BufferTickValueStorage : ValueStorage { @@ -71,7 +75,7 @@ class BufferTickValueStorage : ValueStorage { /** * Returns number of values available to fetch (size of the values buffer). */ - int Size() override { return (int)buffer_tick.Size(); } + int Size() override { return (int)THIS_ATTR buffer_tick.Size(); } }; /** @@ -109,7 +113,7 @@ class BufferTick : public BufferStruct> { _vs_spread = NULL; _vs_volume = NULL; _vs_tick_volume = NULL; - SetOverflowListener(BufferStructOverflowListener, 10); + THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } public: diff --git a/BufferFXT.mqh b/BufferFXT.mqh index 71d7a5d28..5cd0c72ba 100644 --- a/BufferFXT.mqh +++ b/BufferFXT.mqh @@ -73,6 +73,20 @@ struct BufferFXTEntry { int flag; // Flag to launch an expert (0 - bar will be modified, but the expert will not be launched). public: + // Default constructor + BufferFXTEntry() {} + + // Copy constructor + BufferFXTEntry(const BufferFXTEntry &r) + : otm(r.otm), + open(r.open), + high(r.high), + low(r.low), + close(r.close), + volume(r.volume), + ctm(r.ctm), + flag(r.flag) {} + bool operator==(const BufferFXTEntry &_s) { // @fixme return false; diff --git a/BufferStruct.mqh b/BufferStruct.mqh index 80c0253fd..20c60eae2 100644 --- a/BufferStruct.mqh +++ b/BufferStruct.mqh @@ -63,18 +63,18 @@ class BufferStruct : public DictStruct { /** * Constructor. */ - BufferStruct() : max(INT_MIN), min(INT_MAX) { SetOverflowListener(BufferStructOverflowListener, 10); } - BufferStruct(BufferStruct& _right) : max(INT_MIN), min(INT_MAX) { + BufferStruct() : min(INT_MAX), max(INT_MIN) { THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } + BufferStruct(const BufferStruct& _right) : min(INT_MAX), max(INT_MIN) { this = _right; - SetOverflowListener(BufferStructOverflowListener, 10); + THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10); } /** * Adds new value. */ void Add(TStruct& _value, long _dt = 0) { - _dt = _dt > 0 ? _dt : TimeCurrent(); - if (Set(_dt, _value)) { + _dt = _dt > 0 ? _dt : (long)TimeCurrent(); + if (THIS_ATTR Set(_dt, _value)) { min = _dt < min ? _dt : min; max = _dt > max ? _dt : max; } @@ -87,7 +87,7 @@ class BufferStruct : public DictStruct { min = INT_MAX; max = INT_MIN; if (_dt > 0) { - for (DictStructIterator iter(Begin()); iter.IsValid(); ++iter) { + for (DictStructIterator iter(THIS_ATTR Begin()); iter.IsValid(); ++iter) { long _time = iter.Key(); if (_older && _time < _dt) { Unset(iter.Key()); diff --git a/Candle.struct.h b/Candle.struct.h index ebbe5b3ce..74e9c9bab 100644 --- a/Candle.struct.h +++ b/Candle.struct.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Forward class declaration. @@ -236,10 +236,10 @@ struct CandleOCTOHLC : CandleOHLC { // Number of ticks which formed the candle. Also known as volume. int volume; - // Struct constructors. + // Struct constructor. CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, int _start_time = -1, int _length = 0, long _open_timestamp_ms = -1, long _close_timestamp_ms = -1, int _volume = 0) - : CandleOHLC(_open, _high, _low, _close), + : CandleOHLC(_open, _high, _low, _close), is_complete(true), start_time(_start_time), length(_length), @@ -251,17 +251,30 @@ struct CandleOCTOHLC : CandleOHLC { } } + // Struct constructor. + CandleOCTOHLC(const CandleOCTOHLC &r) { THIS_REF = r; } + + // Virtual destructor. Required because of Emscripted warning, despite structure has no virtual methods: + // warning: destructor called on non-final 'CandleOCTOHLC' that has virtual functions but non-virtual + // destructor [-Wdelete-non-abstract-non-virtual-dtor] +#ifndef __MQL__ + virtual ~CandleOCTOHLC() {} +#endif + /** - * Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price. + * Initializes candle with a given start time, length in seconds, first tick's timestamp and its price. */ void Init(int _start_time, int _length, long _timestamp_ms = -1, T _price = 0) { + if (_start_time < 0) { + Print("Error!"); + } is_complete = false; start_time = _start_time; length = _length; open_timestamp_ms = _timestamp_ms; close_timestamp_ms = _timestamp_ms; volume = _price != 0 ? 1 : 0; - open = high = low = close = _price; + THIS_ATTR open = THIS_ATTR high = THIS_ATTR low = THIS_ATTR close = _price; } /** @@ -269,7 +282,16 @@ struct CandleOCTOHLC : CandleOHLC { */ void Update(long _timestamp_ms, T _price) { if (!ContainsTimeMs(_timestamp_ms)) { - Print("Error: Cannot update candle. Given time doesn't fit in candle's time-frame!"); + Print("Error: Cannot update candle. Given time doesn't fit in candle's time-frame! Given time ", _timestamp_ms, + ", but candle range is ", (long)start_time * 1000, " - ", (long)(start_time + length) * 1000, "."); + long _ms; + if (_timestamp_ms < (long)start_time * 1000) { + _ms = (long)start_time * 1000 - _timestamp_ms; + Print("Looks like given time is ", _ms, " ms (", (double)_ms / 1000, " s) before the candle starts."); + } else { + _ms = _timestamp_ms - (long)(start_time + length) * 1000; + Print("Looks like given time is ", _ms, " ms (", (double)_ms / 1000, "s) after the candle ends."); + } DebugBreak(); } @@ -277,19 +299,20 @@ struct CandleOCTOHLC : CandleOHLC { if (_is_init || _timestamp_ms < open_timestamp_ms) { open_timestamp_ms = _timestamp_ms; - open = _price; + THIS_ATTR open = _price; + start_time = int(_timestamp_ms / 1000); } if (_is_init || _timestamp_ms > close_timestamp_ms) { close_timestamp_ms = _timestamp_ms; - close = _price; + THIS_ATTR close = _price; } if (_is_init) { - high = _price; - low = _price; + THIS_ATTR high = _price; + THIS_ATTR low = _price; } else { - high = MathMax(high, _price); - low = MathMin(low, _price); + THIS_ATTR high = MathMax(THIS_ATTR high, _price); + THIS_ATTR low = MathMin(THIS_ATTR low, _price); } // Increasing candle's volume. ++volume; @@ -334,8 +357,8 @@ struct CandleOCTOHLC : CandleOHLC { * Returns text representation of candle. */ string ToString() { - return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", open, high, low, close, - is_complete ? "Complete" : "Incomplete", + return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", THIS_ATTR open, THIS_ATTR high, THIS_ATTR low, + THIS_ATTR close, is_complete ? "Complete" : "Incomplete", TimeToString(open_timestamp_ms, TIME_DATE | TIME_MINUTES | TIME_SECONDS), TimeToString(close_timestamp_ms, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); } @@ -349,18 +372,24 @@ struct CandleTOHLC : CandleOHLC { datetime time; // Struct constructors. CandleTOHLC(datetime _time = 0, T _open = 0, T _high = 0, T _low = 0, T _close = 0) - : time(_time), CandleOHLC(_open, _high, _low, _close) {} + : time(_time), CandleOHLC(_open, _high, _low, _close) {} // Getters. datetime GetTime() { return time; } // Serializers. SerializerNodeType Serialize(Serializer &s); // Converters. - string ToCSV() { return StringFormat("%d,%g,%g,%g,%g", time, open, high, low, close); } + string ToCSV() { + return StringFormat("%d,%g,%g,%g,%g", time, THIS_ATTR open, THIS_ATTR high, THIS_ATTR low, THIS_ATTR close); + } }; /* Method to serialize CandleEntry structure. */ template +#ifdef __MQL__ SerializerNodeType CandleOHLC::Serialize(Serializer &s) { +#else +SerializerNodeType CandleOHLC::Serialize(Serializer &s) { +#endif // s.Pass(THIS_REF, "time", TimeToString(time)); s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); @@ -371,25 +400,33 @@ SerializerNodeType CandleOHLC::Serialize(Serializer &s) { /* Method to serialize CandleEntry structure. */ template +#ifdef __MQL__ SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { +#else +SerializerNodeType CandleTOHLC::Serialize(Serializer &s) { +#endif s.Pass(THIS_REF, "time", time); - s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "open", THIS_ATTR open, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "high", THIS_ATTR high, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "low", THIS_ATTR low, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close", THIS_ATTR close, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } /* Method to serialize CandleEntry structure. */ template +#ifdef __MQL__ SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { +#else +SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) { +#endif s.Pass(THIS_REF, "is_complete", is_complete, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "open_timestamp_ms", open_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "close_timestamp_ms", close_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC); - s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "open", THIS_ATTR open, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "high", THIS_ATTR high, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "low", THIS_ATTR low, SERIALIZER_FIELD_FLAG_DYNAMIC); + s.Pass(THIS_REF, "close", THIS_ATTR close, SERIALIZER_FIELD_FLAG_DYNAMIC); s.Pass(THIS_REF, "volume", volume, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; } diff --git a/Chart.enum.h b/Chart.enum.h index 0aef076f9..3e6af773f 100644 --- a/Chart.enum.h +++ b/Chart.enum.h @@ -126,8 +126,52 @@ enum ENUM_TIMEFRAMES { PERIOD_MN1 = 43200 // 1 month. }; +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(ENUM_TIMEFRAMES) { + emscripten::enum_("timeframes") + .value("CURRENT", PERIOD_CURRENT) + .value("M1", PERIOD_M1) + .value("M2", PERIOD_M2) + .value("M3", PERIOD_M3) + .value("M3", PERIOD_M3) + .value("M5", PERIOD_M5) + .value("M6", PERIOD_M6) + .value("M10", PERIOD_M10) + .value("M12", PERIOD_M12) + .value("M15", PERIOD_M15) + .value("M20", PERIOD_M20) + .value("M30", PERIOD_M30) + .value("H1", PERIOD_H1) + .value("H3", PERIOD_H3) + .value("H4", PERIOD_H4) + .value("H6", PERIOD_H6) + .value("H8", PERIOD_H8) + .value("H12", PERIOD_H12) + .value("D1", PERIOD_D1) + .value("W1", PERIOD_W1) + .value("MN1", PERIOD_MN1); +} + +EMSCRIPTEN_BINDINGS(ENUM_APPLIED_PRICE) { + emscripten::enum_("ap") + .value("open", PRICE_OPEN) + .value("high", PRICE_HIGH) + .value("low", PRICE_LOW) + .value("median", PRICE_MEDIAN) + .value("typical", PRICE_TYPICAL) + .value("weighted", PRICE_WEIGHTED); +} + #endif +#endif + +// Non-TF based period. Used e.g., by Renko indicator. +#define PERIOD_TF_IRREGULAR ((ENUM_TIMEFRAMES)-1) + // Define type of periods. // @see: https://docs.mql4.com/constants/chartconstants/enum_timeframes #define TFS 21 diff --git a/Chart.struct.h b/Chart.struct.h index b0fa365f6..bb17302ba 100644 --- a/Chart.struct.h +++ b/Chart.struct.h @@ -51,6 +51,7 @@ struct ChartEntry { // Constructors. ChartEntry() {} ChartEntry(const BarEntry& _bar) { SetBar(_bar); } + ChartEntry(const ChartEntry& _r) { SetBar(_r.bar); } // Getters. BarEntry GetBar() { return bar; } string ToCSV() { return StringFormat("%s", bar.ToCSV()); } diff --git a/Chart.struct.static.h b/Chart.struct.static.h index 83bc8561c..2e7f8d65b 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -25,9 +25,15 @@ * Includes Chart's static structs. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. #include "Chart.define.h" #include "Chart.symboltf.h" +#include "Platform.extern.h" #include "Terminal.define.h" /* Defines struct for chart static methods. */ @@ -69,7 +75,7 @@ struct ChartStatic { } return _bar_shift; #else // __MQL5__ - if (_time < 0) return (-1); + if (_time == (datetime)0) return (-1); ARRAY(datetime, arr); datetime _time0; // ENUM_TIMEFRAMES _tf = MQL4::TFMigrate(_tf); @@ -145,7 +151,7 @@ struct ChartStatic { if (_start < 0) return (-1); _count = (_count <= 0 ? ChartStatic::iBars(_symbol_tf.Symbol(), _symbol_tf.Tf()) : _count); ARRAY(double, arr_d); - ARRAY(long, arr_l); + ARRAY(int64, arr_l); ARRAY(datetime, arr_dt); ArraySetAsSeries(arr_d, true); switch (_type) { @@ -202,7 +208,7 @@ struct ChartStatic { if (_start < 0) return (-1); _count = (_count <= 0 ? iBars(_symbol, _tf) : _count); ARRAY(double, arr_d); - ARRAY(long, arr_l); + ARRAY(int64, arr_l); ARRAY(datetime, arr_dt); ArraySetAsSeries(arr_d, true); switch (_type) { @@ -287,6 +293,8 @@ struct ChartStatic { ChartStatic::iClose(_symbol, _tf, _shift) + ChartStatic::iClose(_symbol, _tf, _shift)) / 4; break; + default: + break; // FINAL_APPLIED_PRICE_ENTRY. } return _result; } @@ -322,7 +330,7 @@ struct ChartStatic { } return _volume; #else // __MQL5__ - ARRAY(long, _arr); + ARRAY(int64, _arr); ArraySetAsSeries(_arr, true); return (_shift >= 0 && CopyTickVolume(_symbol, _tf, _shift, 1, _arr) > 0) ? _arr[0] : 0; #endif @@ -347,7 +355,7 @@ struct ChartStatic { // ENUM_TIMEFRAMES _tf = MQL4::TFMigrate(_tf); // @todo: Improves performance by caching values. - datetime _time = (_shift >= 0 && ::CopyTime(_symbol, _tf, _shift, 1, _arr) > 0) ? _arr[0] : 0; + datetime _time = (_shift >= 0 && ::CopyTime(_symbol, _tf, _shift, 1, _arr) > 0) ? _arr[0] : (datetime)0; if (_LastError != ERR_NO_ERROR) { Print("Error: ", _LastError, " while doing CopyTime() in ChartStatic::GetBarTime(", _symbol, ", ", diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 0d8c4710f..0acc2d8f5 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -28,7 +28,7 @@ #ifndef __MQL__ // Allows the preprocessor to include a header file when it is needed. #pragma once -#include "Platform.h" +#include "Platform.extern.h" #endif // Forward declarations. @@ -49,7 +49,7 @@ struct ChartTf { public: // Constructors. ChartTf(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : tf(_tf), tfi(ChartTf::TfToIndex(_tf)){}; - ChartTf(ENUM_TIMEFRAMES_INDEX _tfi) : tfi(_tfi), tf(ChartTf::IndexToTf(_tfi)){}; + ChartTf(ENUM_TIMEFRAMES_INDEX _tfi) : tf(ChartTf::IndexToTf(_tfi)), tfi(_tfi){}; ChartTf(const ChartTf& _ctf) : tf(_ctf.tf), tfi(_ctf.tfi){}; // Struct operators. @@ -186,6 +186,78 @@ struct ChartTf { return PERIOD_CURRENT; } + /** + * Convert timeframe period to miliseconds. + * + * @param + * _tf ENUM_TIMEFRAMES Specify timeframe enum. + */ + static int64 TfToMs(const ENUM_TIMEFRAMES _tf) { return (int64)TfToSeconds(_tf) * 1000; } + + /** + * Convert timeframe period to seconds. + * + * @param + * _tf ENUM_TIMEFRAMES Specify timeframe enum. + */ + static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { + switch (_tf) { + case PERIOD_CURRENT: +#ifdef __MQL__ + return ::PeriodSeconds(_tf); +#else + RUNTIME_ERROR("PeriodSeconds(PERIOD_CURRENT) is not implemented! Returning 0."); + return 0; +#endif + case PERIOD_M1: // 1 minute. + return 60; + case PERIOD_M2: // 2 minutes (non-standard). + return 60 * 2; + case PERIOD_M3: // 3 minutes (non-standard). + return 60 * 3; + case PERIOD_M4: // 4 minutes (non-standard). + return 60 * 4; + case PERIOD_M5: // 5 minutes. + return 60 * 5; + case PERIOD_M6: // 6 minutes (non-standard). + return 60 * 6; + case PERIOD_M10: // 10 minutes (non-standard). + return 60 * 10; + case PERIOD_M12: // 12 minutes (non-standard). + return 60 * 12; + case PERIOD_M15: // 15 minutes. + return 60 * 15; + case PERIOD_M20: // 20 minutes (non-standard). + return 60 * 20; + case PERIOD_M30: // 30 minutes. + return 60 * 30; + case PERIOD_H1: // 1 hour. + return 60 * 60; + case PERIOD_H2: // 2 hours (non-standard). + return 60 * 60 * 2; + case PERIOD_H3: // 3 hours (non-standard). + return 60 * 60 * 3; + case PERIOD_H4: // 4 hours. + return 60 * 60 * 4; + case PERIOD_H6: // 6 hours (non-standard). + return 60 * 60 * 6; + case PERIOD_H8: // 8 hours (non-standard). + return 60 * 60 * 8; + case PERIOD_H12: // 12 hours (non-standard). + return 60 * 60 * 12; + case PERIOD_D1: // Daily. + return 60 * 60 * 24; + case PERIOD_W1: // Weekly. + return 60 * 60 * 24 * 7; + case PERIOD_MN1: // Monthly. + return 60 * 60 * 24 * 30; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return 0; + } + /** * Convert period to proper chart timeframe value. * @@ -274,14 +346,6 @@ struct ChartTf { */ static double TfToMinutes(const ENUM_TIMEFRAMES _tf) { return ChartTf::TfToSeconds(_tf) / 60; } - /** - * Convert timeframe period to seconds. - * - * @param - * _tf ENUM_TIMEFRAMES Specify timeframe enum. - */ - static unsigned int TfToSeconds(const ENUM_TIMEFRAMES _tf) { return ::PeriodSeconds(_tf); } - /** * Returns text representation of the timeframe constant. * diff --git a/Common.extern.h b/Common.extern.h index 379ec718d..34fc0cde6 100644 --- a/Common.extern.h +++ b/Common.extern.h @@ -23,25 +23,28 @@ // Define external global functions. #ifndef __MQL__ #pragma once +#include +#include + #include "Chart.enum.h" #include "DateTime.enum.h" +#include "Terminal.define.h" + +void DebugBreak() { +#ifdef _MSC_VER + // @see https://learn.microsoft.com/en-us/cpp/intrinsics/debugbreak?view=msvc-170 + __debugbreak(); +#else + raise(SIGTRAP); +#endif +} + +int _LastError = 0; -extern void DebugBreak(); // Errors. -extern void SetUserError(unsigned short user_error); +void SetUserError(unsigned short user_error) { _LastError = ERR_USER_ERROR_FIRST + 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/Convert.basic.h b/Convert.basic.h index 3725a9e13..05ee81dcc 100644 --- a/Convert.basic.h +++ b/Convert.basic.h @@ -104,6 +104,13 @@ class ConvertBasic { #endif } + template + static X StringTo(string _value) { + X _out = {}; + StringToType(_value, _out); + return _out; + } + static void BoolToType(bool _value, bool& _out) { _out = _value; } static void BoolToType(bool _value, char& _out) { _out = (char)_value; } static void BoolToType(bool _value, unsigned char& _out) { _out = (unsigned char)_value; } @@ -119,6 +126,13 @@ class ConvertBasic { static void BoolToType(bool _value, color& _out) { _out = 0; } static void BoolToType(bool _value, datetime& _out) {} + template + static X BoolTo(bool _value) { + X _out; + BoolToType(_value, _out); + return _out; + } + static void LongToType(long _value, bool& _out) { _out = (bool)_value; } static void LongToType(long _value, char& _out) { _out = (char)_value; } static void LongToType(long _value, unsigned char& _out) { _out = (unsigned char)_value; } @@ -134,6 +148,13 @@ class ConvertBasic { static void LongToType(long _value, color& _out) { _out = 0; } static void LongToType(long _value, datetime& _out) {} + template + static X LongTo(long _value) { + X _out; + LongToType(_value, _out); + return _out; + } + static void DoubleToType(double _value, bool& _out) { _out = (bool)_value; } static void DoubleToType(double _value, char& _out) { _out = (char)_value; } static void DoubleToType(double _value, unsigned char& _out) { _out = (unsigned char)_value; } @@ -148,4 +169,11 @@ class ConvertBasic { static void DoubleToType(double _value, string& _out) { _out = _value ? "1" : "0"; } static void DoubleToType(double _value, color& _out) { _out = 0; } static void DoubleToType(double _value, datetime& _out) {} + + template + static X DoubleTo(double _value) { + X _out; + DoubleToType(_value, _out); + return _out; + } }; diff --git a/Convert.extern.h b/Convert.extern.h index b08e80d86..753f0156a 100644 --- a/Convert.extern.h +++ b/Convert.extern.h @@ -23,12 +23,29 @@ // Prevents processing this includes file for the second time. #ifndef __MQL__ #pragma once -#endif + +// Includes. +#include +#include // Define external global functions. -#ifndef __MQL__ -extern double NormalizeDouble(double value, int digits); -extern string CharToString(unsigned char char_code); -extern string DoubleToString(double value, int digits = 8); -extern string ShortToString(unsigned short symbol_code); +double NormalizeDouble(double value, int digits) { return std::round(value / digits) * digits; } + +string CharToString(unsigned char char_code) { + std::stringstream ss; + ss << char_code; + return ss.str(); +} + +string DoubleToString(double value, int digits = 8) { + std::stringstream ss; + ss << std::setprecision(digits) << value; + return ss.str(); +} + +string ShortToString(unsigned short symbol_code) { + std::stringstream ss; + ss << (char)symbol_code; + return ss.str(); +} #endif diff --git a/Convert.mqh b/Convert.mqh index 29831f9ab..29cee521a 100644 --- a/Convert.mqh +++ b/Convert.mqh @@ -34,6 +34,8 @@ #include "Account/Account.extern.h" #include "Array.mqh" #include "Convert.extern.h" +#include "DateTime.extern.h" +#include "DateTime.mqh" #include "Math.extern.h" #include "Order.enum.h" #include "SymbolInfo.enum.h" diff --git a/Data.struct.h b/Data.struct.h index 6b6d84415..38aac559f 100644 --- a/Data.struct.h +++ b/Data.struct.h @@ -129,8 +129,42 @@ struct DataParamEntry : public MqlParam { string_value = _string_value; } DataParamEntry(const DataParamEntry &_r) { ASSIGN_TO_THIS(MqlParam, _r); } + + DataParamEntry(bool _value) { + type = TYPE_BOOL; + integer_value = _value; + } + DataParamEntry(const datetime _value) { + type = TYPE_DATETIME; + integer_value = _value; + } + DataParamEntry(double _value) { + type = TYPE_DOUBLE; + double_value = _value; + } + DataParamEntry(int _value) { + type = TYPE_INT; + integer_value = _value; + } + DataParamEntry(const string _value) { + type = TYPE_STRING; + string_value = _value; + } + DataParamEntry(unsigned int _value) { + type = TYPE_UINT; + integer_value = _value; + } + DataParamEntry(long _value) { + type = TYPE_LONG; + integer_value = _value; + } + DataParamEntry(unsigned long _value) { + type = TYPE_ULONG; + integer_value = (long)_value; + } + // Struct operators. - void operator=(const bool _value) { + void operator=(bool _value) { type = TYPE_BOOL; integer_value = _value; } @@ -138,11 +172,11 @@ struct DataParamEntry : public MqlParam { type = TYPE_DATETIME; integer_value = _value; } - void operator=(const double _value) { + void operator=(double _value) { type = TYPE_DOUBLE; double_value = _value; } - void operator=(const int _value) { + void operator=(int _value) { type = TYPE_INT; integer_value = _value; } @@ -150,15 +184,19 @@ struct DataParamEntry : public MqlParam { type = TYPE_STRING; string_value = _value; } - void operator=(const unsigned int _value) { + void operator=(unsigned int _value) { type = TYPE_UINT; integer_value = _value; } - template - void operator=(const T _value) { - type = TYPE_INT; - integer_value = (int)_value; + void operator=(long _value) { + type = TYPE_LONG; + integer_value = _value; + } + void operator=(unsigned long _value) { + type = TYPE_ULONG; + integer_value = (long)_value; } + bool operator==(const DataParamEntry &_s) { return type == _s.type && double_value == _s.double_value && integer_value == _s.integer_value && string_value == _s.string_value; diff --git a/Database.mqh b/Database.mqh index ed4024489..3fe4d6386 100644 --- a/Database.mqh +++ b/Database.mqh @@ -74,6 +74,21 @@ struct DatabaseTableColumnEntry { // State methods. bool IsKey() { return bool(flags & DATABASE_COLUMN_FLAG_IS_KEY); } bool IsNull() { return bool(flags & DATABASE_COLUMN_FLAG_IS_NULL); } + + DatabaseTableColumnEntry() {} + DatabaseTableColumnEntry(const string _name, const ENUM_DATATYPE _type, unsigned short _flags = 0, + unsigned short _char_size = 0) { + name = _name; + type = _type; + flags = _flags; + char_size = _char_size; + } + DatabaseTableColumnEntry(const DatabaseTableColumnEntry &r) { + name = r.name; + type = r.type; + flags = r.flags; + char_size = r.char_size; + } }; struct DatabaseTableSchema { DictStruct columns; @@ -84,6 +99,7 @@ struct DatabaseTableSchema { columns.Push(_columns[i]); } } + DatabaseTableSchema(const DatabaseTableSchema &r) { columns = r.columns; } // Methods. bool AddColumn(DatabaseTableColumnEntry &column) { return columns.Push(column); } }; @@ -93,18 +109,17 @@ struct DbSymbolInfoEntry : public SymbolInfoEntry { DatabaseTableSchema schema; // Constructors. DbSymbolInfoEntry() { DefineSchema(); } + DbSymbolInfoEntry(const DbSymbolInfoEntry &r) { schema = r.schema; } DbSymbolInfoEntry(const MqlTick &_tick, const string _symbol = NULL) : SymbolInfoEntry(_tick, _symbol) { DefineSchema(); } // Methods. void DefineSchema() { - DatabaseTableColumnEntry _columns[] = { - {"bid", TYPE_DOUBLE}, {"ask", TYPE_DOUBLE}, {"last", TYPE_DOUBLE}, - {"spread", TYPE_DOUBLE}, {"volume", TYPE_INT}, - }; - for (int i = 0; i < ArraySize(_columns); i++) { - schema.columns.Push(_columns[i]); - } + schema.columns.Push(DatabaseTableColumnEntry("bid", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("ask", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("last", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("spread", TYPE_DOUBLE)); + schema.columns.Push(DatabaseTableColumnEntry("volume", TYPE_INT)); } }; #endif diff --git a/DateTime.entry.h b/DateTime.entry.h new file mode 100644 index 000000000..539ec5a45 --- /dev/null +++ b/DateTime.entry.h @@ -0,0 +1,172 @@ +//+------------------------------------------------------------------+ +//| 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 DateTime's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "DateTime.static.h" +#include "PlatformTime.h" +#include "Std.h" + +struct DateTimeEntry : MqlDateTime { + int week_of_year; + // Struct constructors. + DateTimeEntry() { Set(); } + DateTimeEntry(datetime _dt) { Set(_dt); } + DateTimeEntry(MqlDateTime& _dt) { + Set(_dt); +#ifndef __MQL__ + throw NotImplementedException(); +#endif + } + // Getters. + int GetDayOfMonth() { return day; } + int GetDayOfWeek() { + // Returns the zero-based day of week. + // (0-Sunday, 1-Monday, ... , 6-Saturday). + return day_of_week; + } + int GetDayOfYear() { return day_of_year + 1; } // Zero-based day of year (1st Jan = 0). + int GetHour() { return hour; } + int GetMinute() { return min; } + int GetMonth() { return mon; } + int GetSeconds() { return sec; } + // int GetWeekOfYear() { return week_of_year; } // @todo + int GetValue(ENUM_DATETIME_UNIT _unit) { + int _result = -1; + switch (_unit) { + case DATETIME_SECOND: + return GetSeconds(); + case DATETIME_MINUTE: + return GetMinute(); + case DATETIME_HOUR: + return GetHour(); + case DATETIME_DAY: + return GetDayOfMonth(); + case DATETIME_WEEK: + return -1; // return WeekOfYear(); // @todo + case DATETIME_MONTH: + return GetMonth(); + case DATETIME_YEAR: + return GetYear(); + default: + break; + } + return _result; + } + unsigned int GetValue(unsigned int _unit) { + if ((_unit & (DATETIME_DAY | DATETIME_WEEK)) != 0) { + return GetDayOfWeek(); + } else if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { + return GetDayOfMonth(); + } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { + return GetDayOfYear(); + } + return GetValue((ENUM_DATETIME_UNIT)_unit); + } + int GetYear() { return year; } + datetime GetTimestamp() { return StructToTime(THIS_REF); } + // Setters. + void Set() { + TimeToStruct(PlatformTime::CurrentTimestamp(), THIS_REF); + // @fixit Should also set day of week. + } + void SetGMT() { + TimeToStruct(::TimeGMT(), THIS_REF); + // @fixit Should also set day of week. + } + // Set date and time. + void Set(datetime _time) { + TimeToStruct(_time, THIS_REF); + // @fixit Should also set day of week. + } + // Set date and time. + void Set(MqlDateTime& _time) { + THIS_REF = _time; + // @fixit Should also set day of week. + } + void SetDayOfMonth(int _value) { + day = _value; + day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. + day_of_year = DateTimeStatic::DayOfYear(); // Zero-based day of year. + } + void SetDayOfYear(int _value) { + day_of_year = _value - 1; // Sets zero-based day of year. + day = DateTimeStatic::Month(); // Sets day of month (1..31). + day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. + } + void SetHour(int _value) { hour = _value; } + void SetMinute(int _value) { min = _value; } + void SetMonth(int _value) { mon = _value; } + void SetSeconds(int _value) { sec = _value; } + void SetWeekOfYear(int _value) { + week_of_year = _value; + // day = @todo; + // day_of_week = @todo; + // day_of_year = @todo; + } + void SetValue(ENUM_DATETIME_UNIT _unit, int _value) { + switch (_unit) { + case DATETIME_SECOND: + SetSeconds(_value); + break; + case DATETIME_MINUTE: + SetMinute(_value); + break; + case DATETIME_HOUR: + SetHour(_value); + break; + case DATETIME_DAY: + SetDayOfMonth(_value); + break; + case DATETIME_WEEK: + SetWeekOfYear(_value); + break; + case DATETIME_MONTH: + SetMonth(_value); + break; + case DATETIME_YEAR: + SetYear(_value); + break; + default: + break; + } + } + void SetValue(unsigned short _unit, int _value) { + if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { + SetDayOfMonth(_value); + } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { + SetDayOfYear(_value); + } else { + SetValue((ENUM_DATETIME_UNIT)_unit, _value); + } + } + void SetYear(int _value) { year = _value; } +}; diff --git a/DateTime.extern.h b/DateTime.extern.h index a1dbea297..68c1dc9f6 100644 --- a/DateTime.extern.h +++ b/DateTime.extern.h @@ -29,6 +29,7 @@ // Includes. #include + #include "DateTime.enum.h" #include "String.mqh" @@ -42,21 +43,18 @@ 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; + datetime() { dt = 0; } + datetime(const int64& _time) { dt = _time; } + // datetime(const int& _time); + bool operator==(const int _time) const = delete; + bool operator==(const datetime& _time) const { return dt == _time; } + bool operator<(const int _time) const = delete; + bool operator>(const int _time) const = delete; + bool operator<(const datetime& _time) const { return dt < _time; } + bool operator>(const datetime& _time) const { return dt > _time; } + operator int64() const { return dt; } }; -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)); @@ -76,7 +74,8 @@ extern datetime StringToTime(const string& value); extern string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES); template -extern datetime operator"" _D(); +datetime operator"" _D(); #define DATETIME_LITERAL(STR) _D " ## STR ## " + #endif diff --git a/DateTime.mqh b/DateTime.mqh index 4bbe8fe10..a1cbca946 100644 --- a/DateTime.mqh +++ b/DateTime.mqh @@ -39,9 +39,12 @@ struct DataParamEntry; // Includes class enum and structs. #include "Array.mqh" #include "Data.struct.h" +#include "DateTime.entry.h" #include "DateTime.enum.h" #include "DateTime.extern.h" +#include "DateTime.static.h" #include "DateTime.struct.h" +#include "PlatformTime.h" #ifndef __MQL4__ // Defines global functions (for MQL4 backward compatibility). @@ -61,7 +64,7 @@ class DateTime { /** * Class constructor. */ - DateTime() { TimeToStruct(TimeCurrent(), dt_curr); } + DateTime() { TimeToStruct(PlatformTime::CurrentTimestamp(), dt_curr); } DateTime(DateTime &r) : dt_curr(r.dt_curr), dt_last(r.dt_last) {} DateTime(DateTimeEntry &_dt) { dt_curr = _dt; } DateTime(MqlDateTime &_dt) { dt_curr = _dt; } @@ -126,8 +129,8 @@ class DateTime { } #ifdef __debug_verbose__ - string _passed = - "time now " + (string)dt_curr.GetTimestamp() + ", time last " + (string)dt_last.GetTimestamp() + " "; + string _passed = "time now " + TimeToString(dt_curr.GetTimestamp()) + ", time last " + + TimeToString(dt_last.GetTimestamp()) + " "; if (_update) { _passed += "updating time "; @@ -198,7 +201,7 @@ class DateTime { /** * Updates datetime to the current one. */ - void Update() { dt_curr.Set(TimeCurrent()); } + void Update() { dt_curr.Set(PlatformTime::CurrentTimestamp()); } /* Conditions */ @@ -238,4 +241,16 @@ class DateTime { return DateTime::CheckCondition(_cond, _args); } }; + +#ifndef __MQL__ + +datetime TimeCurrent() { return PlatformTime::CurrentTimestamp(); } + +datetime TimeCurrent(MqlDateTime &dt_struct) { + dt_struct = PlatformTime::CurrentTime(); + return PlatformTime::CurrentTimestamp(); +} + +#endif + #endif // DATETIME_MQH diff --git a/DateTime.static.h b/DateTime.static.h new file mode 100644 index 000000000..c2ca188d8 --- /dev/null +++ b/DateTime.static.h @@ -0,0 +1,206 @@ +//+------------------------------------------------------------------+ +//| 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 DateTime's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "PlatformTime.h" + +/* + * Struct to provide static date and time methods. + */ +struct DateTimeStatic { + /** + * Returns the current day of the month (e.g. the day of month of the last known server time). + */ + static int Day(datetime dt = 0) { + if (dt == (datetime)0) { + dt = (datetime)PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::TimeDay(dt); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.day; +#endif + } + + /** + * Returns the current zero-based day of the week of the last known server time. + */ + static int DayOfWeek(datetime dt = 0) { + if (dt == (datetime)0) { + dt = (datetime)PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::DayOfWeek(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.day_of_week; +#endif + } + + /** + * Returns the current day of the year (e.g. the day of year of the last known server time). + */ + static int DayOfYear(datetime dt = 0) { + if (dt == (datetime)0) { + dt = (datetime)PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::DayOfYear(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.day_of_year + 1; +#endif + } + + /** + * Returns the hour of the last known server time by the moment of the program start. + */ + static int Hour(datetime dt = 0) { + if (dt == (datetime)0) { + dt = (datetime)PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Hour(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.hour; +#endif + } + + /** + * Check whether market is within peak hours. + */ + static bool IsPeakHour() { + MqlDateTime dt; + TimeToStruct(::TimeGMT(), dt); + return dt.hour >= 8 && dt.hour <= 16; + } + + /** + * Returns the current minute of the last known server time by the moment of the program start. + */ + static int Minute(datetime dt = 0) { + if (dt == (datetime)0) { + dt = (datetime)PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Minute(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.min; +#endif + } + + /** + * Returns the current month as number (e.g. the number of month of the last known server time). + */ + static int Month(datetime dt = 0) { + if (dt == (datetime)0) { + dt = (datetime)PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Month(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.mon; +#endif + } + + /** + * Returns the amount of seconds elapsed from the beginning of the current minute of the last known server time. + */ + static int Seconds(datetime dt = 0) { + if (dt == (datetime)0) { + dt = (datetime)PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Seconds(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.sec; +#endif + } + + /** + * Converts a time stamp into a string of "yyyy.mm.dd hh:mi" format. + */ + static string TimeToStr(datetime value, int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { +#ifdef __MQL4__ + return ::TimeToStr(value, mode); +#else // __MQL5__ + // #define TimeToStr(value, mode) DateTime::TimeToStr(value, mode) + return ::TimeToString(value, mode); +#endif + } + static string TimeToStr(int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { + return TimeToStr(PlatformTime::CurrentTimestamp(), mode); + } + + /** + * Returns the current time of the trade server. + */ + static datetime TimeTradeServer() { +#ifdef __MQL4__ + // Unlike MQL5 TimeTradeServer(), + // TimeCurrent() returns the last known server time. + return ::TimeCurrent(); +#else + // The calculation of the time value is performed in the client terminal + // and depends on the time settings of your computer. + return ::TimeTradeServer(); +#endif + } + + /** + * Returns the current year (e.g. the year of the last known server time). + */ + static int Year(datetime dt = 0) { + if (dt == (datetime)0) { + dt = (datetime)PlatformTime::CurrentTimestamp(); + } +#ifdef __MQL4__ + return ::Year(); +#else + MqlDateTime _dt; + TimeToStruct(dt, _dt); + return _dt.year; +#endif + } +}; diff --git a/DateTime.struct.h b/DateTime.struct.h index bd641db9e..cb44b9325 100644 --- a/DateTime.struct.h +++ b/DateTime.struct.h @@ -56,368 +56,3 @@ struct MqlDateTime { int day_of_year; // Zero-based day number of the year (1st Jan = 0). }; #endif - -/* - * Struct to provide static date and time methods. - */ -struct DateTimeStatic { - /** - * Returns the current day of the month (e.g. the day of month of the last known server time). - */ - static int Day(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::TimeDay(dt); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.day; -#endif - } - - /** - * Returns the current zero-based day of the week of the last known server time. - */ - static int DayOfWeek(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::DayOfWeek(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.day_of_week; -#endif - } - - /** - * Returns the current day of the year (e.g. the day of year of the last known server time). - */ - static int DayOfYear(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::DayOfYear(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.day_of_year + 1; -#endif - } - - /** - * Returns the hour of the last known server time by the moment of the program start. - */ - static int Hour(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Hour(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.hour; -#endif - } - - /** - * Check whether market is within peak hours. - */ - static bool IsPeakHour() { - MqlDateTime dt; - TimeToStruct(::TimeGMT(), dt); - return dt.hour >= 8 && dt.hour <= 16; - } - - /** - * Returns the current minute of the last known server time by the moment of the program start. - */ - static int Minute(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Minute(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.min; -#endif - } - - /** - * Returns the current month as number (e.g. the number of month of the last known server time). - */ - static int Month(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Month(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.mon; -#endif - } - - /** - * Returns the amount of seconds elapsed from the beginning of the current minute of the last known server time. - */ - static int Seconds(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Seconds(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.sec; -#endif - } - - /** - * Converts a time stamp into a string of "yyyy.mm.dd hh:mi" format. - */ - static string TimeToStr(datetime value, int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { -#ifdef __MQL4__ - return ::TimeToStr(value, mode); -#else // __MQL5__ - // #define TimeToStr(value, mode) DateTime::TimeToStr(value, mode) - return ::TimeToString(value, mode); -#endif - } - static string TimeToStr(int mode = TIME_DATE | TIME_MINUTES | TIME_SECONDS) { return TimeToStr(TimeCurrent(), mode); } - - /** - * Returns the current time of the trade server. - */ - static datetime TimeTradeServer() { -#ifdef __MQL4__ - // Unlike MQL5 TimeTradeServer(), - // TimeCurrent() returns the last known server time. - return ::TimeCurrent(); -#else - // The calculation of the time value is performed in the client terminal - // and depends on the time settings of your computer. - return ::TimeTradeServer(); -#endif - } - - /** - * Returns the current year (e.g. the year of the last known server time). - */ - static int Year(datetime dt = 0) { - if (dt == 0) { - dt = TimeCurrent(); - } -#ifdef __MQL4__ - return ::Year(); -#else - MqlDateTime _dt; - TimeToStruct(dt, _dt); - return _dt.year; -#endif - } -}; - -struct DateTimeEntry : public MqlDateTime { - int week_of_year; - // Struct constructors. - DateTimeEntry() { Set(); } - DateTimeEntry(datetime _dt) { Set(_dt); } - DateTimeEntry(int _year, int _mon, int _day, int _hour = 0, int _min = 0, int _sec = 0) { - year = _year; - mon = _mon; - day = _day; - hour = _hour; - min = _min; - sec = _sec; - Recalculate(); - } - DateTimeEntry(MqlDateTime& _dt) { - Set(_dt); - // In MqlDateTime, 1st Jan is assigned the number value of zero. - day_of_year = day_of_year + 1; -#ifndef __MQL__ - throw NotImplementedException(); -#endif - } - // Getters. - int GetDayOfMonth() { return day; } - int GetDayOfWeek(bool _recalc = true) { - // Returns the zero-based day of week. - // (0-Sunday, 1-Monday, ... , 6-Saturday). - if (!_recalc) { - return day_of_week; - } - // Calculates day of the week using the Tomohiko Sakamoto Algorithm. - // @see: https://iq.opengenus.org/tomohiko-sakamoto-algorithm/ - // @see: https://stackoverflow.com/a/64923433/55075 - int _days[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; - int _year = mon < 3 ? year - 1 : year; - day_of_week = (_year + _year / 4 - _year / 100 + _year / 400 + _days[mon - 1] + day) % 7; - return day_of_week; - } - // Gets day of the year. - int GetDayOfYear(bool _recalc = false) { - if (!_recalc) { - return day_of_year; - } - int _days_to_month[2][12] = { - {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, - {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}, - }; - // @see: https://stackoverflow.com/a/19111202/55075 - day_of_year = _days_to_month[IsLeapYear() ? 1 : 0][mon - 1] + day; - return day_of_year; - } - // Calculates the week of the year based on the day of the year. - // @see: https://stackoverflow.com/a/274913/55075 - int GetWeekOfYear(bool _recalc = false) { - if (!_recalc) { - return week_of_year; - } - if (day == 1 && mon == 1) { - return 1; - } - int doy = GetDayOfYear(); - int dow = GetDayOfWeek(); - DateTimeEntry _dte(year, 1, 1); - int dow1j = _dte.GetDayOfWeek(); - week_of_year = (doy + 6) / 7; - // Adjust for being after Saturday of 1st week. - week_of_year = dow < dow1j ? week_of_year + 1 : week_of_year; - return week_of_year; - } - int GetHour() { return hour; } - int GetMinute() { return min; } - int GetMonth() { return mon; } - int GetSeconds() { return sec; } - // int GetWeekOfYear() { return week_of_year; } // @todo - int GetValue(ENUM_DATETIME_UNIT _unit) { - int _result = -1; - switch (_unit) { - case DATETIME_SECOND: - return GetSeconds(); - case DATETIME_MINUTE: - return GetMinute(); - case DATETIME_HOUR: - return GetHour(); - case DATETIME_DAY: - return GetDayOfMonth(); - case DATETIME_WEEK: - return -1; // return WeekOfYear(); // @todo - case DATETIME_MONTH: - return GetMonth(); - case DATETIME_YEAR: - return GetYear(); - default: - break; - } - return _result; - } - unsigned int GetValue(unsigned int _unit) { - if ((_unit & (DATETIME_DAY | DATETIME_WEEK)) != 0) { - return GetDayOfWeek(); - } else if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { - return GetDayOfMonth(); - } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { - return GetDayOfYear(); - } else if ((_unit & (DATETIME_WEEK | DATETIME_YEAR)) != 0) { - return GetWeekOfYear(); - } - return GetValue((ENUM_DATETIME_UNIT)_unit); - } - int GetYear() { return year; } - datetime GetTimestamp() { return StructToTime(THIS_REF); } - bool IsLeapYear() { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } - // Recalculate - void Recalculate() { - day_of_week = GetDayOfWeek(true); - day_of_year = GetDayOfYear(true); - week_of_year = GetWeekOfYear(true); - } - // Setters. - void Set() { - TimeToStruct(::TimeCurrent(), THIS_REF); - Recalculate(); - } - void SetGMT() { - TimeToStruct(::TimeGMT(), THIS_REF); - Recalculate(); - } - // Set date and time. - void Set(datetime _time) { - TimeToStruct(_time, THIS_REF); - Recalculate(); - } - // Set date and time. - void Set(MqlDateTime& _time) { - THIS_REF = _time; - Recalculate(); - } - void SetDayOfMonth(int _value) { - day = _value; - day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. - day_of_year = DateTimeStatic::DayOfYear(); // Zero-based day of year. - } - void SetDayOfYear(int _value) { - day_of_year = _value - 1; // Sets zero-based day of year. - day = DateTimeStatic::Month(); // Sets day of month (1..31). - day_of_week = DateTimeStatic::DayOfWeek(); // Zero-based day of week. - } - void SetHour(int _value) { hour = _value; } - void SetMinute(int _value) { min = _value; } - void SetMonth(int _value) { mon = _value; } - void SetSeconds(int _value) { sec = _value; } - void SetWeekOfYear(int _value) { - week_of_year = _value; - // day = @todo; - // day_of_week = @todo; - // day_of_year = @todo; - } - void SetValue(ENUM_DATETIME_UNIT _unit, int _value) { - switch (_unit) { - case DATETIME_SECOND: - SetSeconds(_value); - break; - case DATETIME_MINUTE: - SetMinute(_value); - break; - case DATETIME_HOUR: - SetHour(_value); - break; - case DATETIME_DAY: - SetDayOfMonth(_value); - break; - case DATETIME_WEEK: - SetWeekOfYear(_value); - break; - case DATETIME_MONTH: - SetMonth(_value); - break; - case DATETIME_YEAR: - SetYear(_value); - break; - default: - break; - } - } - void SetValue(unsigned short _unit, int _value) { - if ((_unit & (DATETIME_DAY | DATETIME_MONTH)) != 0) { - SetDayOfMonth(_value); - } else if ((_unit & (DATETIME_DAY | DATETIME_YEAR)) != 0) { - SetDayOfYear(_value); - } else { - SetValue((ENUM_DATETIME_UNIT)_unit, _value); - } - } - void SetYear(int _value) { year = _value; } -}; diff --git a/Deal.enum.h b/Deal.enum.h index a94fbb415..fa7cb4a19 100644 --- a/Deal.enum.h +++ b/Deal.enum.h @@ -26,6 +26,10 @@ */ #ifndef __MQL__ + +// Allows the preprocessor to include a header file when it is needed. +#pragma once + enum ENUM_DEAL_TYPE { DEAL_TYPE_BUY, DEAL_TYPE_SELL, diff --git a/Dict.enum.h b/Dict.enum.h index 99474def2..c746f87e3 100644 --- a/Dict.enum.h +++ b/Dict.enum.h @@ -26,12 +26,12 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif -#define DICT_GROW_UP_PERCENT_DEFAULT 25 -#define DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS 10 +#define DICT_GROW_UP_PERCENT_DEFAULT 100 +#define DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS 20 /** * Whether Dict operates in yet uknown mode, as dict or as list. diff --git a/Dict.mqh b/Dict.mqh index 5c8099c5a..f123cf539 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -26,6 +26,7 @@ #include "Convert.basic.h" #include "DictBase.mqh" +#include "DictIteratorBase.mqh" #include "Matrix.mqh" #include "Serializer/Serializer.h" #include "Serializer/SerializerNodeIterator.h" @@ -41,12 +42,12 @@ class DictIterator : public DictIteratorBase { /** * Constructor. */ - DictIterator(DictBase& dict, unsigned int slotIdx) : DictIteratorBase(dict, slotIdx) {} + DictIterator(DictBase& dict, unsigned int slotIdx) : DictIteratorBase(dict, slotIdx) {} /** * Copy constructor. */ - DictIterator(const DictIterator& right) : DictIteratorBase(right) {} + DictIterator(const DictIterator& right) : DictIteratorBase(right) {} }; /** @@ -70,37 +71,39 @@ class Dict : 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_ATTR _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_ATTR _DictSlots_ref._num_used = right._DictSlots_ref._num_used; + THIS_ATTR _current_id = right._current_id; + THIS_ATTR _mode = right._mode; } void operator=(const Dict& 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_ATTR _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_ATTR _DictSlots_ref._num_used = right._DictSlots_ref._num_used; + THIS_ATTR _current_id = right._current_id; + THIS_ATTR _mode = right._mode; } void Clear() { - for (unsigned int i = 0; i < (unsigned int)ArraySize(_DictSlots_ref.DictSlots); ++i) { - if (_DictSlots_ref.DictSlots[i].IsUsed()) _DictSlots_ref.DictSlots[i].SetFlags(0); + _DictSlots_ref = new DictSlotsRef(); + + for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { + if (THIS_ATTR _DictSlots_ref.DictSlots[i].IsUsed()) THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); } - _DictSlots_ref._num_used = 0; + THIS_ATTR _DictSlots_ref._num_used = 0; } /** * Inserts value using hashless key. */ bool Push(V value) { - if (!InsertInto(_DictSlots_ref, value)) return false; + if (!InsertInto(THIS_ATTR _DictSlots_ref, value)) return false; return true; } @@ -113,19 +116,19 @@ class Dict : 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_ATTR _DictSlots_ref, key, value, true)) return false; return true; } V operator[](K key) { - if (_mode == DictModeList) return GetSlot((unsigned int)key).value; + if (THIS_ATTR _mode == DictModeList) return THIS_ATTR GetSlot((unsigned int)key).value; int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, key, position); + DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); if (!slot) return (V)NULL; - return slot.value; + return slot PTR_DEREF value; } /** @@ -136,20 +139,20 @@ class Dict : public DictBase { */ V GetByKey(const K _key, V _default = NULL) { unsigned int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, _key, position); + DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); if (!slot) { return _default; } - return slot.value; + return slot PTR_DEREF value; } /** * Returns value for a given position. */ V GetByPos(unsigned int _position) { - DictSlot* slot = GetSlotByPos(_DictSlots_ref, _position); + DictSlot* slot = GetSlotByPos(THIS_ATTR _DictSlots_ref, _position); if (!slot) { Alert("Invalid DictStruct position \"", _position, "\" (called by GetByPos()). Returning empty structure."); @@ -158,28 +161,32 @@ class Dict : public DictBase { return _empty; } - return slot.value; + return slot PTR_DEREF value; } /** * 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_ATTR _DictSlots_ref, key, position); if (!slot) return false; - return slot.value == value; + return slot PTR_DEREF value == value; } /** * 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) { + for (DictIteratorBase i(THIS_ATTR Begin()); i.IsValid(); ++i) { if (i.Value() == value) { return (int)i.Index(); } @@ -192,7 +199,7 @@ class Dict : public DictBase { * Checks whether dictionary contains given value. */ bool Contains(const V value) { - for (DictIterator i = Begin(); i.IsValid(); ++i) { + for (DictIterator i = THIS_ATTR Begin(); i.IsValid(); ++i) { if (i.Value() == value) { return true; } @@ -205,7 +212,7 @@ class Dict : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V value, bool allow_resize) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, const K key, V value, bool allow_resize) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeDict; else if (THIS_ATTR _mode != DictModeDict) { @@ -232,7 +239,7 @@ class Dict : public DictBase { if ((_is_full || !_is_performant) && allow_resize) { // We have to resize the dict as it is either full or have perfomance problems due to massive number of conflicts // when inserting new values. - if (overflow_listener == NULL) { + if (THIS_ATTR overflow_listener == NULL) { // There is no overflow listener so we can freely grow up the dict. if (!GrowUp()) { // Can't resize the dict. Error happened. @@ -240,8 +247,9 @@ class Dict : public DictBase { } } else { // Overflow listener will decide if we can grow up the dict. - if (overflow_listener(_is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, - dictSlotsRef._num_used, 0)) { + if (THIS_ATTR overflow_listener( + _is_full ? DICT_LISTENER_FULL_CAN_RESIZE : DICT_LISTENER_NOT_PERFORMANT_CAN_RESIZE, + dictSlotsRef._num_used, 0)) { // We can freely grow up the dict. if (!GrowUp()) { // Can't resize the dict. Error happened. @@ -268,11 +276,12 @@ class Dict : public DictBase { (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { ++_num_conflicts; - if (overflow_listener != NULL) { + if (THIS_ATTR overflow_listener != NULL) { // We had to skip slot as it is already occupied. Now we are checking if // there is too many conflicts/skips and thus we can overwrite slot in // the starting position. - if (overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, _num_conflicts)) { + if (THIS_ATTR overflow_listener(DICT_LISTENER_CONFLICTS_CAN_OVERWRITE, dictSlotsRef._num_used, + _num_conflicts)) { // Looks like dict is working as buffer and we can overwrite slot in the starting position. position = _starting_position; break; @@ -308,10 +317,10 @@ class Dict : 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) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, V value) { + if (THIS_ATTR _mode == DictModeUnknown) + THIS_ATTR _mode = DictModeList; + else if (THIS_ATTR _mode != DictModeList) { Alert("Warning: Dict already operates as a dictionary, not a list!"); DebugBreak(); return false; @@ -322,7 +331,7 @@ class Dict : public DictBase { if (!GrowUp()) return false; } - unsigned int position = Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); + unsigned int position = THIS_ATTR Hash((unsigned int)dictSlotsRef._list_index) % ArraySize(dictSlotsRef.DictSlots); // Searching for empty DictSlot. while (dictSlotsRef.DictSlots[position].IsUsed()) { @@ -342,19 +351,32 @@ class Dict : 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_ATTR _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } + public: + /** + * Ensures that there is at least given number of slots in dict. + */ + bool Reserve(int _size) { + if (_size <= ArraySize(THIS_ATTR _DictSlots_ref.DictSlots)) { + return true; + } + return Resize(_size); + } + + protected: /** * 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_ATTR _DictSlots_ref._num_used, ArraySize(THIS_ATTR _DictSlots_ref.DictSlots))) { // We already use minimum number of slots possible. return true; } - DictSlotsRef new_DictSlots; + DictSlotsRef* new_DictSlots = new DictSlotsRef(); if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) return false; @@ -367,20 +389,23 @@ class Dict : public DictBase { new_DictSlots._num_used = 0; // Copies entire array of DictSlots into new array of DictSlots. Hashes will be rehashed. - for (i = 0; i < ArraySize(_DictSlots_ref.DictSlots); ++i) { - if (!_DictSlots_ref.DictSlots[i].IsUsed()) continue; + for (i = 0; i < ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { + if (!THIS_ATTR _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_ATTR _DictSlots_ref.DictSlots[i].HasKey()) { + if (!InsertInto(new_DictSlots, THIS_ATTR _DictSlots_ref.DictSlots[i].key, + THIS_ATTR _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_ATTR _DictSlots_ref.DictSlots[i].value)) return false; } } // Freeing old DictSlots array. - ArrayFree(_DictSlots_ref.DictSlots); + ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots); + + delete THIS_ATTR _DictSlots_ref; - _DictSlots_ref = new_DictSlots; + THIS_ATTR _DictSlots_ref = new_DictSlots; return true; } @@ -391,12 +416,12 @@ class Dict : public DictBase { #endif SerializerNodeType Serialize(Serializer& s) { if (s.IsWriting()) { - for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + for (DictIteratorBase i(THIS_ATTR Begin()); i.IsValid(); ++i) { V value = i.Value(); - s.Pass(THIS_REF, GetMode() == DictModeDict ? i.KeyAsString() : "", value); + s.Pass(THIS_REF, THIS_ATTR GetMode() == DictModeDict ? i.KeyAsString() : "", value); } - return (GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray; + return (THIS_ATTR GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray; } else { SerializerIterator i; @@ -432,9 +457,9 @@ class Dict : public DictBase { */ template Matrix* ToMatrix() { - Matrix* result = new Matrix(Size()); + Matrix* result = new Matrix(THIS_ATTR Size()); - for (DictIterator i = Begin(); i.IsValid(); ++i) result[i.Index()] = (X)i.Value(); + for (DictIterator i = THIS_ATTR Begin(); i.IsValid(); ++i) result[i.Index()] = (X)i.Value(); return result; } diff --git a/DictBase.mqh b/DictBase.mqh index 269f9ddd2..187191f2d 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -61,12 +61,14 @@ class DictBase { _current_id = 0; _mode = DictModeUnknown; _flags = 0; + overflow_listener = nullptr; + _DictSlots_ref = new DictSlotsRef(); } /** * Destructor. */ - ~DictBase() {} + ~DictBase() { delete _DictSlots_ref; } DictIteratorBase Begin() { // Searching for first item index. @@ -105,7 +107,7 @@ class DictBase { /** * Returns slot by key. */ - DictSlot* GetSlotByKey(DictSlotsRef& dictSlotsRef, const K _key, unsigned int& position) { + DictSlot* GetSlotByKey(DictSlotsRef*& dictSlotsRef, const K _key, unsigned int& position) { unsigned int numSlots = ArraySize(dictSlotsRef.DictSlots); if (numSlots == 0) return NULL; @@ -136,7 +138,7 @@ class DictBase { /** * Returns slot by position. */ - DictSlot* GetSlotByPos(DictSlotsRef& dictSlotsRef, const unsigned int position) { + DictSlot* GetSlotByPos(DictSlotsRef*& dictSlotsRef, const unsigned int position) { return dictSlotsRef.DictSlots[position].IsUsed() ? &dictSlotsRef.DictSlots[position] : NULL; } @@ -186,7 +188,15 @@ class DictBase { if (GetMode() == DictModeList) { // In list mode value index is the slot index. - position = (int)key; +#ifndef __MQL__ + if constexpr (std::is_same::value) { +#endif + position = (int)key; +#ifndef __MQL__ + } else { + RUNTIME_ERROR("List mode for a dict could only work if Dict's key type is an integer!"); + } +#endif } else { position = Hash(key) % ArraySize(_DictSlots_ref.DictSlots); } @@ -203,7 +213,15 @@ class DictBase { if (_DictSlots_ref.DictSlots[position].IsUsed()) { if (GetMode() == DictModeList) { - _should_be_removed = position == (unsigned int)key; +#ifndef __MQL__ + if constexpr (std::is_same::value) { +#endif + _should_be_removed = position == (unsigned int)key; +#ifndef __MQL__ + } else { + RUNTIME_ERROR("List mode for a dict could only work if Dict's key type is an integer!"); + } +#endif } else { _should_be_removed = _DictSlots_ref.DictSlots[position].HasKey() && _DictSlots_ref.DictSlots[position].key == key; @@ -318,9 +336,9 @@ class DictBase { protected: /** - * Array of DictSlots. + * Pointer to array of DictSlots. */ - DictSlotsRef _DictSlots_ref; + DictSlotsRef* _DictSlots_ref; DictOverflowListener overflow_listener; unsigned int overflow_listener_max_conflicts; @@ -361,17 +379,50 @@ class DictBase { /** * Specialization of hashing function. */ - unsigned int Hash(unsigned int x) { return x; } + unsigned int Hash(float x) { return (unsigned int)((unsigned long)x * 10000 % 10000); } /** * Specialization of hashing function. */ - unsigned int Hash(int x) { return (unsigned int)x; } + unsigned int Hash(int value) { + value ^= (value >> 8); + value ^= (value << 3); + value ^= (value >> 9); + value ^= (value >> 4); + value ^= (value << 6); + value ^= (value >> 14); + return value; + } /** * Specialization of hashing function. */ - unsigned int Hash(float x) { return (unsigned int)((unsigned long)x * 10000 % 10000); } + unsigned int Hash(unsigned int value) { return Hash((int)value); } + + /** + * Specialization of hashing function. + */ + unsigned int Hash(long value) { + value ^= (value >> 33); + value ^= (value << 21); + value ^= (value >> 17); + + // Step 2: Combine upper and lower 32 bits to form a 32-bit hash + long hash = (int)(value ^ (value >> 32)); + + // Step 3: Further bit manipulation to spread the bits + hash ^= (hash >> 16); + hash *= 0x85ebca6b; // A large prime number + hash ^= (hash >> 13); + hash *= 0xc2b2ae35; // Another large prime number + hash ^= (hash >> 16); + return int(value >> 32); + } + + /** + * Specialization of hashing function. + */ + unsigned int Hash(unsigned long value) { return Hash((unsigned long)value); } }; #endif diff --git a/DictObject.mqh b/DictObject.mqh index 84f556bcf..63db36d87 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -21,8 +21,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif #include "Convert.basic.h" @@ -105,6 +105,8 @@ class DictObject : public DictBase { } void Clear() { + _DictSlots_ref = new DictSlotsRef(); + 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); } @@ -153,7 +155,7 @@ class DictObject : public DictBase { */ V* GetByKey(const K _key) { unsigned int position; - DictSlot* slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, _key, position); + DictSlot* slot = THIS_ATTR GetSlotByKey(this PTR_DEREF _DictSlots_ref, _key, position); if (!slot) return NULL; @@ -210,7 +212,7 @@ class DictObject : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, const K key, V& value, bool allow_resize) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeDict; else if (THIS_ATTR _mode != DictModeDict) { @@ -315,7 +317,7 @@ class DictObject : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, V& value) { if (this PTR_DEREF _mode == DictModeUnknown) this PTR_DEREF _mode = DictModeList; else if (this PTR_DEREF _mode != DictModeList) { @@ -354,6 +356,18 @@ class DictObject : public DictBase { 10, (int)((float)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } + public: + /** + * Ensures that there is at least given number of slots in dict. + */ + bool Reserve(int _size) { + if (_size <= ArraySize(THIS_ATTR _DictSlots_ref.DictSlots)) { + return true; + } + return Resize(_size); + } + + protected: /** * Shrinks or expands array of DictSlots. */ @@ -364,7 +378,7 @@ class DictObject : public DictBase { return true; } - DictSlotsRef new_DictSlots; + DictSlotsRef* new_DictSlots = new DictSlotsRef(); int i; @@ -389,7 +403,9 @@ class DictObject : public DictBase { // Freeing old DictSlots array. ArrayFree(this PTR_DEREF _DictSlots_ref.DictSlots); - this PTR_DEREF _DictSlots_ref = new_DictSlots; + delete THIS_ATTR _DictSlots_ref; + + THIS_ATTR _DictSlots_ref = new_DictSlots; return true; } diff --git a/DictSlot.mqh b/DictSlot.mqh index 3cbd4a473..06d31650d 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,6 +40,12 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} + //#ifdef __MQL__ + // DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key), value(r.value) {} + //#else + DictSlot(const DictSlot& r) : _flags(r._flags), key(r.key) { value = r.value; } + //#endif + bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } bool HasKey() { return bool(_flags & DICT_SLOT_HAS_KEY); } diff --git a/DictSlotsRef.h b/DictSlotsRef.h index ff90c8b17..32da49a6e 100644 --- a/DictSlotsRef.h +++ b/DictSlotsRef.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -42,7 +42,8 @@ template class DictSlot; template -struct DictSlotsRef { +class DictSlotsRef { + public: ARRAY(DictSlot, DictSlots); // Incremental index for dict operating in list mode. @@ -61,14 +62,13 @@ struct DictSlotsRef { _avg_conflicts = 0; } - void operator=(DictSlotsRef& r) { - Util::ArrayCopy(DictSlots, r.DictSlots); - _list_index = r._list_index; - _num_used = r._num_used; - _num_conflicts = r._num_conflicts; - _avg_conflicts = r._avg_conflicts; - } + private: + /** + * Private assignment operator to avoid invalid copying. + */ + void operator=(DictSlotsRef& r) {} + public: /** * Adds given number of conflicts for an insert action, so we can store average number of conflicts. */ diff --git a/DictStruct.mqh b/DictStruct.mqh index b7bb1a173..5b5c6e1c9 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -22,7 +22,7 @@ // Prevents processing this includes file for the second time. #ifndef __MQL__ -#pragma once + #pragma once #endif // Includes. @@ -89,18 +89,10 @@ class DictStruct : public DictBase { THIS_ATTR _mode = right._mode; } - void operator=(DictStruct& right) { - Clear(); - Resize(right.GetSlotCount()); - for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - THIS_ATTR _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; - } - THIS_ATTR _DictSlots_ref._num_used = right._DictSlots_ref._num_used; - THIS_ATTR _current_id = right._current_id; - THIS_ATTR _mode = right._mode; - } - void Clear() { + delete _DictSlots_ref; + _DictSlots_ref = new DictSlotsRef(); + for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); } @@ -134,19 +126,6 @@ class DictStruct : public DictBase { */ bool operator+=(V& value) { return Push(value); } -/** - * Inserts value using hashless key. - */ -#ifdef __MQL__ - template <> -#endif - bool Push(Dynamic* value) { - V ptr = value; - - if (!InsertInto(THIS_ATTR _DictSlots_ref, ptr)) return false; - return true; - } - /** * Inserts or replaces value for a given key. */ @@ -161,12 +140,12 @@ class DictStruct : public DictBase { V operator[](K key) { DictSlot* slot; - int position; + unsigned int position; if (THIS_ATTR _mode == DictModeList) slot = THIS_ATTR GetSlot((unsigned int)key); else - slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); + slot = THIS_ATTR GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); if (slot == NULL || !slot PTR_DEREF IsUsed()) { Alert("Invalid DictStruct key \"", key, "\" (called by [] operator). Returning empty structure."); @@ -183,7 +162,7 @@ class DictStruct : public DictBase { */ V GetByKey(const K _key) { unsigned int position; - DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); + DictSlot* slot = THIS_ATTR GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); if (!slot) { static V _empty; @@ -280,7 +259,7 @@ class DictStruct : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, const K key, V& value, bool allow_resize) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeDict; else if (THIS_ATTR _mode != DictModeDict) { @@ -385,7 +364,7 @@ class DictStruct : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, V& value) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeList; else if (THIS_ATTR _mode != DictModeList) { @@ -422,6 +401,18 @@ class DictStruct : public DictBase { MathMax(10, (int)((float)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } + public: + /** + * Ensures that there is at least given number of slots in dict. + */ + bool Reserve(int _size) { + if (_size <= ArraySize(THIS_ATTR _DictSlots_ref.DictSlots)) { + return true; + } + return Resize(_size); + } + + protected: /** * Shrinks or expands array of DictSlots. */ @@ -431,9 +422,11 @@ class DictStruct : public DictBase { return true; } - DictSlotsRef new_DictSlots; + DictSlotsRef* new_DictSlots = new DictSlotsRef(); - if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) return false; + if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) { + return false; + } int i; @@ -454,7 +447,9 @@ class DictStruct : public DictBase { } } // Freeing old DictSlots array. - ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots); + ArrayFree(THIS_ATTR _DictSlots_ref PTR_DEREF DictSlots); + + delete THIS_ATTR _DictSlots_ref; THIS_ATTR _DictSlots_ref = new_DictSlots; diff --git a/Draw.mqh b/Draw.mqh index 0e5168a01..1074333cd 100644 --- a/Draw.mqh +++ b/Draw.mqh @@ -302,7 +302,7 @@ class Draw : public Object { /** * Draw a line given the price. */ - void ShowLine(string oname, double price, int colour = Yellow) { + void ShowLine(string oname, double price, int _colour = Yellow) { /** @TODO Draw::ObjectCreate(chart_id, oname, OBJ_HLINE, 0, GetBarTime(), price); Draw::ObjectSet(oname, OBJPROP_COLOR, _colour); diff --git a/DrawIndicator.mqh b/DrawIndicator.mqh index d3448a795..d9bc1da44 100644 --- a/DrawIndicator.mqh +++ b/DrawIndicator.mqh @@ -48,7 +48,7 @@ class DrawPoint { } // Special methods. DrawPoint(const DrawPoint& r) : time(r.time), value(r.value) {} - DrawPoint(datetime _time = NULL, double _value = 0) : time(_time), value(_value) {} + DrawPoint(datetime _time = 0, double _value = 0) : time(_time), value(_value) {} }; class DrawIndicator { @@ -124,15 +124,16 @@ class DrawIndicator { } if (!last_points.KeyExists(_name)) { - last_points.Set(_name, DrawPoint(_time, _value)); + DrawPoint _point(_time, _value); + last_points.Set(_name, _point); } else { DrawPoint* last_point = last_points.GetByKey(_name); - draw.TLine(_name + "_" + IntegerToString(_time), last_point.value, _value, last_point.time, _time, color_line, - false, _window); + draw PTR_DEREF TLine(_name + "_" + IntegerToString(_time), last_point PTR_DEREF value, _value, + last_point PTR_DEREF time, _time, color_line, false, _window); - last_point.time = _time; - last_point.value = _value; + last_point PTR_DEREF time = _time; + last_point PTR_DEREF value = _value; } } }; diff --git a/EA.mqh b/EA.mqh index 3d7bdb6d4..16cccca33 100644 --- a/EA.mqh +++ b/EA.mqh @@ -30,8 +30,8 @@ #define EA_MQH // Includes. -#include "Chart.mqh" #include "./Chart.struct.static.h" +#include "Chart.mqh" #include "Data.struct.h" #include "Dict.mqh" #include "DictObject.mqh" @@ -114,12 +114,12 @@ class EA : public Taskable { Init(); // Initialize a trade instance for the current chart and symbol. Ref _source = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); - TradeParams _tparams(0, 1.0f, 0, eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + TradeParams _tparams(0, 1.0f, 0, (ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); Trade _trade(_tparams, _source.Ptr()); trade.Set(_Symbol, _trade); logger.Link(_trade.GetLogger()); - logger.SetLevel(eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); - //_trade.GetLogger().SetLevel(eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + logger.SetLevel((ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + //_trade.GetLogger().SetLevel((ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); } /** @@ -409,11 +409,11 @@ class EA : public Taskable { _strat.OnOrderOpen(_oparams); // Send the request. _result = _trade.RequestSend(_request, _oparams); - if (!_result) { // && _strade.IsTradeRecommended( - 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))); + if (!_result) { // && _strade.IsTradeRecommended( + 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))); if (_trade.IsTradeRecommended()) { logger.Debug( StringFormat("Error while sending a trade request! Entry: %s", @@ -421,7 +421,8 @@ class EA : public Taskable { __FUNCTION_LINE__, StringFormat("Code: %d, Msg: %s", _LastError, Terminal::GetErrorText(_LastError))); } #ifdef __debug_ea__ - Print(__FUNCTION_LINE__ + "(): " + SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()); + Print(__FUNCTION_LINE__ + + "(): " + SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()); #endif } return _result; @@ -766,8 +767,8 @@ class EA : public Taskable { Ref _strat = ((SClass *)NULL).Init(_tf, THIS_PTR); _strat.Ptr().Set(STRAT_PARAM_ID, _magic_no); _strat.Ptr().Set(TRADE_PARAM_MAGIC_NO, _magic_no); - _strat.Ptr().Set(STRAT_PARAM_LOG_LEVEL, - eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); + _strat.Ptr().Set(STRAT_PARAM_LOG_LEVEL, + (ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); _strat.Ptr().Set(STRAT_PARAM_TF, _tf); _strat.Ptr().Set(STRAT_PARAM_TYPE, _type); _strat.Ptr().OnInit(); diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 index 498c0c791..aff8fa3f9 100644 --- a/Exchange/tests/Exchange.test.mq5 +++ b/Exchange/tests/Exchange.test.mq5 @@ -96,8 +96,8 @@ bool TestExchange01() { exchange REF_DEREF SymbolAdd(symbol02.Ptr(), "Symbol02"); // Attach instances of dummy trades. - Ref trade01 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT)); - Ref trade02 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT)); + Ref trade01 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, (ENUM_TIMEFRAMES)Period())); + Ref trade02 = new TradeDummy(Platform::FetchDefaultCandleIndicator(_Symbol, (ENUM_TIMEFRAMES)Period())); exchange REF_DEREF TradeAdd(trade01.Ptr(), "Trade01"); exchange REF_DEREF TradeAdd(trade02.Ptr(), "Trade02"); diff --git a/File.define.h b/File.define.h index 95ce7939d..d95eb025b 100644 --- a/File.define.h +++ b/File.define.h @@ -19,13 +19,46 @@ * along with this program. If not, see . * */ - // Defines. #ifndef __MQL__ +#pragma once + // 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 + +enum ENUM_FILE_PROPERTY_INTEGER { + FILE_EXISTS, + FILE_CREATE_DATE, + FILE_MODIFY_DATE, + FILE_ACCESS_DATE, + FILE_SIZE, + FILE_POSITION, + FILE_END, + FILE_LINE_END, + FILE_IS_COMMON, + FILE_IS_TEXT, + FILE_IS_BINARY, + FILE_IS_CSV, + FILE_IS_ANSI, + FILE_IS_READABLE, + FILE_IS_WRITABLE, +}; +enum ENUM_FILE_OPEN_FLAGS { + FILE_READ = 1, + FILE_WRITE = 2, + FILE_BIN = 4, + FILE_CSV = 8, + FILE_TXT = 16, + FILE_ANSI = 32, + FILE_UNICODE = 64, + FILE_SHARE_READ = 128, + FILE_SHARE_WRITE = 256, + FILE_REWRITE = 512, + FILE_COMMON = 4096, +}; + #endif diff --git a/File.extern.h b/File.extern.h index fcb89a897..fa4ff6204 100644 --- a/File.extern.h +++ b/File.extern.h @@ -22,15 +22,37 @@ // Includes. #include "File.define.h" +#include "Storage/MemoryFileSystem.h" +#include "String.extern.h" #include "Terminal.define.h" // Define external global functions. #ifndef __MQL__ +#pragma once + +MemoryFileSystem _memfs; + 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', unsigned int codepage = CP_ACP); + +void FileClose(int file_handle) { _memfs.FileClose(file_handle); } + +int FileOpen(string file_name, int open_flags, short delimiter = '\t', unsigned int codepage = CP_ACP) { + return _memfs.FileOpen(file_name, open_flags, delimiter, codepage); +} + extern int FileReadInteger(int file_handle, int size = INT_VALUE); + extern string FileReadString(int file_handle, int length = -1); -extern unsigned int FileWriteString(int file_handle, const string text_string, int length = -1); + +unsigned int FileWriteString(int file_handle, const string text_string, int length = -1) { + return _memfs.FileWrite(file_handle, text_string); +} + +template +unsigned int FileWrite(int file_handle, Arg&& arg, Args&&... args) { + return _memfs.FileWrite(file_handle, arg, args...); +} + #endif diff --git a/File.mqh b/File.mqh index 900ce7a31..dc27741af 100644 --- a/File.mqh +++ b/File.mqh @@ -29,6 +29,11 @@ * - Files with which file operations are conducted means cannot be outside the file sandbox. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. #include "File.define.h" #include "File.extern.h" @@ -37,39 +42,6 @@ #include "Terminal.enum.h" #include "Terminal.extern.h" -#ifndef __MQL__ -enum ENUM_FILE_PROPERTY_INTEGER { - FILE_EXISTS, - FILE_CREATE_DATE, - FILE_MODIFY_DATE, - FILE_ACCESS_DATE, - FILE_SIZE, - FILE_POSITION, - FILE_END, - FILE_LINE_END, - FILE_IS_COMMON, - FILE_IS_TEXT, - FILE_IS_BINARY, - FILE_IS_CSV, - FILE_IS_ANSI, - FILE_IS_READABLE, - FILE_IS_WRITABLE, -}; -enum ENUM_FILE_OPEN_FLAGS { - FILE_READ = 1, - FILE_WRITE = 2, - FILE_BIN = 4, - FILE_CSV = 8, - FILE_TXT = 16, - FILE_ANSI = 32, - FILE_UNICODE = 64, - FILE_SHARE_READ = 128, - FILE_SHARE_WRITE = 256, - FILE_REWRITE = 512, - FILE_COMMON = 4096, -}; -#endif - /** * Class to provide a group of functions for working with files. */ diff --git a/Flags.h b/Flags.h index 341eca289..8807629b4 100644 --- a/Flags.h +++ b/Flags.h @@ -20,6 +20,11 @@ * */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + /** * Flags manipulation helper. */ diff --git a/Indicator/Indicator.define.h b/Indicator/Indicator.define.h index b86a877ea..5d2cd3437 100644 --- a/Indicator/Indicator.define.h +++ b/Indicator/Indicator.define.h @@ -39,8 +39,8 @@ #define DUMMY #define ICUSTOM_DEF(SET_HANDLE, PARAMS) \ - double _res[]; \ - if (_handle == NULL || _handle == INVALID_HANDLE) { \ + ARRAY(double, _res); \ + if (_handle == 0 || _handle == INVALID_HANDLE) { \ if ((_handle = ::iCustom(_symbol, _tf, _name PARAMS)) == INVALID_HANDLE) { \ SetUserError(ERR_USER_INVALID_HANDLE); \ return EMPTY_VALUE; \ @@ -104,33 +104,32 @@ #define EMPTY_VALUE DBL_MAX #endif -#define INDICATOR_BUILTIN_CALL_AND_RETURN(NATIVE_METHOD_CALL, MODE, SHIFT) \ - int _handle = Object::IsValid(_obj) ? _obj.Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : NULL; \ - double _res[]; \ - ResetLastError(); \ - if (_handle == NULL || _handle == INVALID_HANDLE) { \ - if ((_handle = NATIVE_METHOD_CALL) == INVALID_HANDLE) { \ - SetUserError(ERR_USER_INVALID_HANDLE); \ - return EMPTY_VALUE; \ - } else if (Object::IsValid(_obj)) { \ - _obj.SetHandle(_handle); \ - } \ - } \ - 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); \ - if (GetLastError() > 0) { \ - return EMPTY_VALUE; \ - } else if (_bars_calc <= 2) { \ - SetUserError(ERR_USER_INVALID_BUFF_NUM); \ - return EMPTY_VALUE; \ - } \ - } \ - if (CopyBuffer(_handle, MODE, SHIFT, 1, _res) < 0) { \ - Print(#NATIVE_METHOD_CALL, " = ", _res[0], ", LE = ", _LastError); \ - return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; \ - } \ +#define INDICATOR_BUILTIN_CALL_AND_RETURN(NATIVE_METHOD_CALL, MODE, SHIFT) \ + int _handle = Object::IsValid(_obj) ? _obj PTR_DEREF Get(IndicatorState::INDICATOR_STATE_PROP_HANDLE) : 0; \ + ARRAY(double, _res); \ + ResetLastError(); \ + if (_handle == 0 || _handle == INVALID_HANDLE) { \ + if ((_handle = NATIVE_METHOD_CALL) == INVALID_HANDLE) { \ + SetUserError(ERR_USER_INVALID_HANDLE); \ + return EMPTY_VALUE; \ + } else if (Object::IsValid(_obj)) { \ + _obj.SetHandle(_handle); \ + } \ + } \ + 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); \ + if (GetLastError() > 0) { \ + return EMPTY_VALUE; \ + } else if (_bars_calc <= 2) { \ + SetUserError(ERR_USER_INVALID_BUFF_NUM); \ + return EMPTY_VALUE; \ + } \ + } \ + if (CopyBuffer(_handle, MODE, SHIFT, 1, _res) < 0) { \ + return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; \ + } \ return _res[0]; #define INDI_REQUIRE_BARS_OR_RETURN(_indi, _period, _ret) \ diff --git a/Indicator/Indicator.enum.h b/Indicator/Indicator.enum.h index ae303e27a..7e0bc061c 100644 --- a/Indicator/Indicator.enum.h +++ b/Indicator/Indicator.enum.h @@ -177,7 +177,7 @@ enum ENUM_SIGNAL_LINE { FINAL_SIGNAL_LINE_ENTRY, }; -#ifdef __MQL4__ +#ifndef __MQL5__ /** * The volume type is used in calculations. * @@ -195,10 +195,11 @@ enum ENUM_APPLIED_VOLUME { VOLUME_TICK = 0, VOLUME_REAL = 1 }; // Indicator flags. enum ENUM_INDI_FLAGS { - INDI_FLAG_INDEXABLE_BY_SHIFT, // Indicator supports indexation by shift. - INDI_FLAG_INDEXABLE_BY_TIMESTAMP, // Indicator supports indexation by shift. - INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT, // Source indicator must be indexable by shift. - INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP // Source indicator must be indexable by timestamp. + INDI_FLAG_INDEXABLE_BY_SHIFT = 1 << 0, // Indicator supports indexation by shift. + INDI_FLAG_INDEXABLE_BY_TIMESTAMP = 1 << 1, // Indicator supports indexation by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT = 1 << 2, // Source indicator must be indexable by shift. + INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP = 1 << 3, // Source indicator must be indexable by timestamp. + INDI_FLAG_LOOSE_TF_CANDLE_INDICATOR = 1 << 4 // It is a non TF-based indicator, e.g., Renko. }; // Flags indicating which data sources are required to be provided in order indicator to work. diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index 53474ff19..a91a5cdb0 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -127,6 +127,7 @@ class Indicator : public IndicatorData { : IndicatorData(IndicatorDataParams::GetInstance()) { iparams.SetIndicatorType(_itype); iparams.SetShift(_shift); + SetName(_name); Init(); } @@ -171,7 +172,8 @@ class Indicator : public IndicatorData { 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()); + IndicatorDataEntry _entry = GetEntry(shift); + double value = _entry.GetMax(GetModeCount()); if (value > max) { max = value; max_idx = shift; @@ -191,7 +193,8 @@ class Indicator : public IndicatorData { 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()); + IndicatorDataEntry _entry = GetEntry(shift); + double value = _entry.GetMin(GetModeCount()); if (value < min) { min = value; min_idx = shift; @@ -223,9 +226,9 @@ class Indicator : public IndicatorData { * Sets whether indicator's buffers should be drawn on the chart. */ void SetDraw(bool _value, color _color = clrAquamarine, int _window = 0) { - draw.SetEnabled(_value); - draw.SetColorLine(_color); - draw.SetWindow(_window); + // draw.SetEnabled(_value); + // draw.SetColorLine(_color); + // draw.SetWindow(_window); } /* Converters */ @@ -242,7 +245,7 @@ class Indicator : public IndicatorData { /* Buffer methods */ - virtual string CacheKey() { return GetFullName(); } + string CacheKey() override { return GetFullName(); } /** * Initializes a cached proxy between i*OnArray() methods and OnCalculate() @@ -374,9 +377,8 @@ class Indicator : public IndicatorData { * * When indicator values are not valid, returns empty signals. */ - IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) { - bool _is_valid = true; - IndicatorDataEntry _data[]; + IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) override { + ARRAY(IndicatorDataEntry, _data); if (!CopyEntries(_data, _count, _shift)) { // Some copied data is invalid, so returns empty signals. IndicatorSignal _signals(0); @@ -397,7 +399,7 @@ class Indicator : public IndicatorData { /** * Get more descriptive name of the indicator. */ - string GetDescriptiveName() { + string GetDescriptiveName() override { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); string name = iparams.name + " ("; @@ -409,8 +411,10 @@ class Indicator : public IndicatorData { name += "custom, "; break; case IDATA_INDICATOR: - name += "over " + GetDataSource().GetDescriptiveName() + ", "; + name += "over " + GetDataSource() PTR_DEREF GetDescriptiveName() + ", "; break; + default: + name += "unknown "; } name += IntegerToString(_max_modes) + (_max_modes == 1 ? " mode" : " modes"); @@ -423,14 +427,14 @@ class Indicator : public IndicatorData { /** * Sets name of the indicator. */ - void SetName(string _name) { iparams.SetName(_name); } + void SetName(string _name) override { iparams.SetName(_name); } /** * Sets indicator's handle. * * Note: Not supported in MT4. */ - void SetHandle(int _handle) { + void SetHandle(int _handle) override { istate.handle = _handle; istate.is_changed = true; } @@ -452,7 +456,7 @@ class Indicator : public IndicatorData { * @return * Returns true when the condition is met. */ - bool CheckCondition(ENUM_INDICATOR_CONDITION _cond, DataParamEntry& _args[]) { + bool CheckCondition(ENUM_INDICATOR_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { switch (_cond) { case INDI_COND_ENTRY_IS_MAX: // @todo: Add arguments, check if the entry value is max. @@ -477,8 +481,8 @@ class Indicator : public IndicatorData { // Indicator entry value is lesser than median. return false; default: - GetLogger().Error(StringFormat("Invalid indicator condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - SetUserError(ERR_INVALID_PARAMETER); + GetLogger() PTR_DEREF Error( + StringFormat("Invalid indicator condition: %s at %s!", EnumToString(_cond), __FUNCTION_LINE__)); return false; } } @@ -497,7 +501,7 @@ class Indicator : public IndicatorData { * @return * Returns true when the action has been executed successfully. */ - virtual bool ExecuteAction(ENUM_INDICATOR_ACTION _action, DataParamEntry& _args[]) { + virtual bool ExecuteAction(ENUM_INDICATOR_ACTION _action, ARRAY_REF(DataParamEntry, _args)) { bool _result = true; long _arg1 = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; switch (_action) { @@ -506,8 +510,8 @@ class Indicator : public IndicatorData { idata.Clear(_arg1); return true; default: - GetLogger().Error(StringFormat("Invalid Indicator action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - SetUserError(ERR_INVALID_PARAMETER); + GetLogger() PTR_DEREF Error(StringFormat("Invalid Indicator action: %s at %s!", C_STR(EnumToString(_action)), + C_STR(__FUNCTION_LINE__))); return false; } return _result; @@ -573,12 +577,12 @@ class Indicator : public IndicatorData { /** * Returns stored data in human-readable format. */ - // virtual bool ToString() = NULL; // @fixme? + string const ToString() override { return EntryToString(); } /** * Whether we can and have to select mode when specifying data source. */ - virtual bool IsDataSourceModeSelectable() { return true; } + virtual bool IsDataSourceModeSelectable() override { return true; } /** * Checks if indicator entry is valid. @@ -687,13 +691,16 @@ class Indicator : public IndicatorData { } if (_LastError != ERR_SUCCESS) { - datetime _bar_dt = (datetime)_bar_time; - Print("Error: Code ", _LastError, " while trying to retrieve entry at shift ", _rel_shift, " (absolute ", - ToAbsShift(_rel_shift), "), mode ", _mode, ", time ", _bar_dt); - DebugBreak(); + if (_LastError != 4806) { + // Error occured and it's not "4806 Requested data not found". + datetime _bar_dt = (datetime)_bar_time; + Print("Error: Code ", _LastError, " while trying to retrieve entry at shift ", _rel_shift, " (absolute ", + ToAbsShift(_rel_shift), "), mode ", _mode, ", time ", _bar_dt); + DebugBreak(); + } } } - GetEntryAlter(_entry, _rel_shift); + THIS_ATTR GetEntryAlter(_entry, _rel_shift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); if (_entry.IsValid()) { idata.Add(_entry, _bar_time); @@ -716,7 +723,7 @@ class Indicator : public IndicatorData { * This method allows user to modify the struct entry before it's added to cache. * This method is called on GetEntry() right after values are set. */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) { + void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) override { ENUM_DATATYPE _dtype = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE)); _entry.AddFlags(_entry.GetDataTypeFlags(_dtype)); }; @@ -743,7 +750,7 @@ class Indicator : public IndicatorData { /** * Update indicator. */ - virtual bool Update() { + virtual bool Update() override { // @todo return false; }; diff --git a/Indicator/Indicator.struct.h b/Indicator/Indicator.struct.h index f8ec7608e..12e47fbd2 100644 --- a/Indicator/Indicator.struct.h +++ b/Indicator/Indicator.struct.h @@ -50,6 +50,7 @@ struct IndicatorParams { protected: void Init() {} public: // @todo: Change it to protected. + string custom_indi_name; // Name of the indicator passed to iCustom() method. string name; // Name of the indicator. int shift; // Shift (relative to the current bar, 0 - default). uint bps; // A candle chart per number of seconds (e.g. for M1 is 60). @@ -57,7 +58,6 @@ struct IndicatorParams { ENUM_INDICATOR_TYPE itype; // Indicator type (e.g. INDI_RSI). color indi_color; // Indicator color. ARRAY(DataParamEntry, input_params); // Indicator input params. - string custom_indi_name; // Name of the indicator passed to iCustom() method. string symbol; // Symbol used by indicator. public: /* Enumerations */ @@ -105,19 +105,19 @@ struct IndicatorParams { DataParamEntry _param = input_params[_index]; switch (_param.type) { case TYPE_BOOL: - return (T)param.integer_value; + return (T)_param.integer_value; case TYPE_INT: case TYPE_LONG: case TYPE_UINT: case TYPE_ULONG: - return param.integer_value; + return _param.integer_value; case TYPE_DOUBLE: case TYPE_FLOAT: - return (T)param.double_value; + return (T)_param.double_value; case TYPE_CHAR: case TYPE_STRING: case TYPE_UCHAR: - return (T)param.string_value; + return (T)_param.string_value; default: SetUserError(ERR_INVALID_PARAMETER); break; diff --git a/Indicator/IndicatorBase.h b/Indicator/IndicatorBase.h index 6c1506c2c..78d1e9f05 100644 --- a/Indicator/IndicatorBase.h +++ b/Indicator/IndicatorBase.h @@ -34,11 +34,10 @@ #include "../Array.mqh" #include "../BufferStruct.mqh" #include "../Chart.struct.tf.h" -//#include "../ChartBase.h" -#include "../ChartMt.h" #include "../DateTime.mqh" #include "../Log.mqh" #include "../Object.mqh" +#include "../Platform.extern.h" #include "../Refs.mqh" #include "../Serializer/Serializer.h" #include "../Serializer/SerializerCsv.h" @@ -192,7 +191,7 @@ class IndicatorBase : public Object { /** * Get name of the indicator. */ - virtual string GetName() = NULL; + virtual string GetName() = 0; /** * Get full name of the indicator (with "over ..." part). @@ -357,3 +356,13 @@ class IndicatorBase : public Object { #endif } }; + +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(IndicatorBase) { + emscripten::class_("IndicatorBase").smart_ptr>("Ref"); +} + +#endif diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index f8b7fdd0c..7b8ad1c86 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -25,12 +25,11 @@ #define INDICATOR_CANDLE_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. -#include "../Buffer/BufferCandle.h" #include "../Candle.struct.h" #include "../Storage/ItemsHistory.h" #include "../Storage/ValueStorage.price_median.h" @@ -46,7 +45,7 @@ #include "TickBarCounter.h" #ifndef INDI_CANDLE_HISTORY_SIZE -#define INDI_CANDLE_HISTORY_SIZE 86400 + #define INDI_CANDLE_HISTORY_SIZE 86400 #endif // Indicator modes. @@ -72,7 +71,6 @@ enum ENUM_INDI_CANDLE_MODE { template class IndicatorCandle : public Indicator { protected: - BufferCandle icdata; TickBarCounter counter; ItemsHistory, TCP> history; @@ -86,10 +84,8 @@ class IndicatorCandle : public Indicator { */ void Init() { // Along with indexing by shift, we can also index via timestamp! - flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; - icdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); - icdata.SetOverflowListener(IndicatorCandleOverflowListener, 10); - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), FINAL_INDI_CANDLE_MODE_ENTRY); + THIS_ATTR flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; + THIS_ATTR Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), (int)FINAL_INDI_CANDLE_MODE_ENTRY); } public: @@ -98,13 +94,13 @@ class IndicatorCandle : public Indicator { /** * Class constructor. */ - IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = NULL, + IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(INDI_CANDLE_HISTORY_SIZE) { + : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(THIS_PTR, INDI_CANDLE_HISTORY_SIZE) { Init(); } IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name), history(INDI_CANDLE_HISTORY_SIZE) { + : Indicator(_itype, _shift, _name), history(THIS_PTR, INDI_CANDLE_HISTORY_SIZE) { Init(); } @@ -158,13 +154,13 @@ class IndicatorCandle : public Indicator { int GetBars() override { // Will return number of bars prepended and appended to the history, // even if those bars were cleaned up because of history's candle limit. - return (int)history.GetPeakSize() - iparams.shift; + return (int)history.GetPeakSize() - THIS_ATTR iparams.shift; } /** * Returns current tick index (incremented every OnTick()). */ - int GetTickIndex() override { return GetTick() PTR_DEREF GetTickIndex(); } + int GetTickIndex() override { return THIS_ATTR GetTick() PTR_DEREF GetTickIndex(); } /** * Check if there is a new bar to parse. @@ -186,7 +182,7 @@ class IndicatorCandle : public Indicator { /** * Removes candle from the buffer. Used mainly for testing purposes. */ - void InvalidateCandle(int _abs_shift) { + void InvalidateCandle(int _abs_shift) override { if (_abs_shift != GetBarIndex()) { Print( "IndicatorCandle::InvalidateCandle() currently supports specyfing " @@ -202,7 +198,7 @@ class IndicatorCandle : public Indicator { /** * Returns time of the bar for a given shift. */ - virtual datetime GetBarTime(int _rel_shift = 0) { return history.GetItemTimeByShift(_rel_shift); } + datetime GetBarTime(int _rel_shift = 0) override { return history.GetItemTimeByShift(_rel_shift); } /** * Traverses source indicators' hierarchy and tries to find OHLC-featured @@ -220,7 +216,7 @@ class IndicatorCandle : public Indicator { BarOHLC _bar; CandleOCTOHLC _candle; - if (history.TryGetItemByShift(ToAbsShift(_rel_shift), _candle)) { + if (history.TryGetItemByShift(THIS_ATTR ToAbsShift(_rel_shift), _candle)) { _bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.start_time); } @@ -266,7 +262,7 @@ class IndicatorCandle : public Indicator { */ IndicatorDataEntry GetEntry(int _shift = 0) override { ResetLastError(); - int _ishift = _shift + iparams.GetShift(); + int _ishift = _shift + THIS_ATTR iparams.GetShift(); CandleOCTOHLC _candle = history.GetItemByShift(_ishift); return CandleToEntry(_candle.GetTime(), _candle); } @@ -275,35 +271,35 @@ class IndicatorCandle : public Indicator { * Returns value storage for a given mode. */ IValueStorage* GetValueStorage(int _mode = 0) override { - if (_mode >= ArraySize(value_storages)) { - ArrayResize(value_storages, _mode + 1); + if (_mode >= ArraySize(THIS_ATTR value_storages)) { + ArrayResize(THIS_ATTR value_storages, _mode + 1); } - if (!value_storages[_mode].IsSet()) { + if (!THIS_ATTR value_storages[_mode].IsSet()) { // Buffer not yet created. switch (_mode) { case INDI_CANDLE_MODE_PRICE_OPEN: case INDI_CANDLE_MODE_PRICE_HIGH: case INDI_CANDLE_MODE_PRICE_LOW: case INDI_CANDLE_MODE_PRICE_CLOSE: - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + THIS_ATTR value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); break; case INDI_CANDLE_MODE_SPREAD: case INDI_CANDLE_MODE_TICK_VOLUME: case INDI_CANDLE_MODE_VOLUME: - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + THIS_ATTR value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); break; case INDI_CANDLE_MODE_TIME: - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + THIS_ATTR value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); break; case INDI_CANDLE_MODE_PRICE_MEDIAN: - value_storages[_mode] = new PriceMedianValueStorage(THIS_PTR); + THIS_ATTR value_storages[_mode] = new PriceMedianValueStorage(THIS_PTR); break; case INDI_CANDLE_MODE_PRICE_TYPICAL: - value_storages[_mode] = new PriceTypicalValueStorage(THIS_PTR); + THIS_ATTR value_storages[_mode] = new PriceTypicalValueStorage(THIS_PTR); break; case INDI_CANDLE_MODE_PRICE_WEIGHTED: - value_storages[_mode] = new PriceWeightedValueStorage(THIS_PTR); + THIS_ATTR value_storages[_mode] = new PriceWeightedValueStorage(THIS_PTR); break; default: Print("ERROR: Unsupported value storage mode ", _mode); @@ -311,33 +307,7 @@ class IndicatorCandle : public Indicator { } } - return value_storages[_mode].Ptr(); - } - - /** - * Function should return true if resize can be made, or false to overwrite current slot. - */ - static bool IndicatorCandleOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { - switch (_reason) { - case DICT_LISTENER_FULL_CAN_RESIZE: - // We allow resize if dictionary size is less than 86400 slots. - return _size < 86400; - case DICT_LISTENER_CONFLICTS_CAN_OVERWRITE: - default: - // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. - break; - } - return false; - } - - /** - * Sends historic entries to listening indicators. May be overriden. - */ - void EmitHistory() override { - for (DictStructIterator> iter(icdata.Begin()); iter.IsValid(); ++iter) { - IndicatorDataEntry _entry = CandleToEntry(iter.Key(), iter.Value()); - EmitEntry(_entry); - } + return THIS_ATTR value_storages[_mode].Ptr(); } /** @@ -368,7 +338,14 @@ class IndicatorCandle : public Indicator { /** * Called when data source emits new entry (new one in ascending order). */ - void OnDataSourceEntry(IndicatorDataEntry& entry) override { + void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + Indicator::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } + // Parent indicator (e.g., Indi_TickMt) emitted an entry containing tick's // ask and bid price. As an abstract class, we really don't know how to // update/create candles so we just pass the entry into history's @@ -376,6 +353,20 @@ class IndicatorCandle : public Indicator { history.GetItemProvider() PTR_DEREF OnTick(&history, entry.timestamp * 1000, (float)entry[0], (float)entry[1]); }; + /** + * Called when data source expects to emit given number of entries for given type. + * + * Called e.g., from Tick indicator in order Candle indicator to enlarge + * possible history size by given number of entries. We have to do that, + * because otherwise, we could end up with OnCalculate() working on partial + * history candles. + */ + void OnDataSourceWillEmitEntries(ENUM_INDI_EMITTED_ENTRY_TYPE _type, int _num_entries) override { + if (_type == INDI_EMITTED_ENTRY_TYPE_CANDLE) { + idata.Reserve(_num_entries); + } + } + /** * Returns value storage of given kind. */ diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index b6737c945..1b45a6cac 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -25,8 +25,8 @@ #define INDICATOR_CANDLE_PROVIDER_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -34,7 +34,7 @@ #include "../Storage/ItemsHistory.h" /** - * Regenerates candles and updates exising candles from new ticks. Subclasses by IndicatorTf, IndicatorRenko. + * Regenerates candles and updates exising candles from new ticks. Subclassed by IndicatorTf, IndicatorRenko. */ template class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider> { @@ -47,8 +47,8 @@ class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider, ItemsHistoryItemProvider>>* _history, - long _time_ms, float _ask, float _bid) { + void OnTick(ItemsHistory, ItemsHistoryItemProvider>>* _history, long _time_ms, + float _ask, float _bid) { // Should be overrided. } @@ -56,11 +56,19 @@ class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider, ItemsHistoryCandleProvider>* _history, long _from_time_ms, + bool GetItems(ItemsHistory, ItemsHistoryCandleProvider>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. - Print("Error: Retrieving items by this item provider is not implemented!"); - DebugBreak(); + return false; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryCandleProvider>* _history, int _start_index, + int _end_index, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + return false; } }; diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 29fde9ff6..01befb765 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -25,17 +25,24 @@ #define INDICATOR_DATA_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Forward class declaration. -class IndicatorBase; +class IndicatorData; +class DrawIndicator; +class IValueStorage; + +struct ExternInstantiateIndicatorBufferValueStorageDouble { + static IValueStorage* InstantiateIndicatorBufferValueStorageDouble(IndicatorData*, int); +}; // Includes. #include "../Bar.struct.h" -#include "../DrawIndicator.mqh" +#include "../Chart.struct.tf.h" #include "../Flags.h" +#include "../Storage/IValueStorage.h" #include "../Storage/ItemsHistory.h" #include "../Storage/ValueStorage.h" #include "../Storage/ValueStorage.indicator.h" @@ -63,12 +70,13 @@ class IndicatorData : public IndicatorBase { int last_tick_index; // Index of the last tick. long first_tick_time_ms; // Time of the first ask/bid tick. void* mydata; + bool last_tick_result; // Result of the last Tick() invocation. ENUM_INDI_VS_TYPE retarget_ap_av; // Value storage type to be used as applied price/volume. ARRAY(Ref, value_storages); ARRAY(WeakRef, listeners); // List of indicators that listens for events from this one. BufferStruct idata; DictStruct> indicators; // Indicators list keyed by id. - DrawIndicator* draw; + // DrawIndicator* draw; IndicatorCalculateCache cache; IndicatorDataParams idparams; // Indicator data params. IndicatorState istate; @@ -78,6 +86,11 @@ class IndicatorData : public IndicatorBase { /* Protected methods */ bool Init() { +#ifdef __cplusplus + // In C++ we default to On-Indicator mode as there are no built-in ones. + idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_INDICATOR); +#endif + ArrayResize(value_storages, GetModeCount()); if (indi_src.IsSet()) { // SetDataSource(_indi_src, _indi_mode); @@ -89,11 +102,13 @@ class IndicatorData : public IndicatorBase { case IDATA_ICUSTOM: break; case IDATA_INDICATOR: - if (indi_src.IsSet() == NULL) { + if (indi_src.IsSet()) { // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); // SetDataSource(_indi_price, true, PRICE_OPEN); } break; + default: + break; } // By default, indicator is indexable only by shift and data source must be also indexable by shift. flags = INDI_FLAG_INDEXABLE_BY_SHIFT | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT; @@ -122,9 +137,11 @@ class IndicatorData : public IndicatorBase { * Deinitialize drawing. */ void DeinitDraw() { + /* @todo: To refactor. if (draw) { delete draw; } + */ } public: @@ -133,7 +150,7 @@ class IndicatorData : public IndicatorBase { /** * Class constructor. */ - IndicatorData(const IndicatorDataParams& _idparams, IndicatorBase* _indi_src = nullptr, int _indi_mode = 0) + IndicatorData(const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) : do_draw(false), idparams(_idparams), indi_src(_indi_src) { Init(); } @@ -156,7 +173,7 @@ class IndicatorData : public IndicatorBase { * Access indicator entry data using [] operator via shift. */ IndicatorDataEntry operator[](int _rel_shift) { - if (!bool(flags | INDI_FLAG_INDEXABLE_BY_SHIFT)) { + if (!bool(flags & INDI_FLAG_INDEXABLE_BY_SHIFT)) { Print(GetFullName(), " is not indexable by shift!"); DebugBreak(); IndicatorDataEntry _default; @@ -224,10 +241,13 @@ class IndicatorData : public IndicatorBase { case IDATA_INDICATOR: _mode = "On-I"; break; + default: + _mode = "Unkw"; + break; } return GetName() + "#" + IntegerToString(GetId()) + "-" + _mode + "[" + IntegerToString(_max_modes) + "]" + - (HasDataSource() ? (" (over " + GetDataSource(false).GetFullName() + ")") : ""); + (HasDataSource() ? (" (over " + GetDataSource(false) PTR_DEREF GetFullName() + ")") : ""); } /** @@ -253,7 +273,6 @@ class IndicatorData : public IndicatorBase { return _price; } datetime _bar_time = GetBarTime(_shift); - float _value = 0; BarOHLC _ohlc(_values, _bar_time); _price = _ohlc.GetAppliedPrice(_ap); } @@ -412,13 +431,13 @@ class IndicatorData : public IndicatorBase { */ template double GetMin(int start_bar, int count = WHOLE_ARRAY) { - double min = NULL; + double min = DBL_MAX; int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); for (int shift = start_bar; shift <= last_bar; ++shift) { double value = GetEntry(shift).GetMin(_max_modes); - if (min == NULL || value < min) { + if (min == DBL_MAX || value < min) { min = value; } } @@ -452,7 +471,7 @@ class IndicatorData : public IndicatorBase { */ template double GetMed(int start_bar, int count = WHOLE_ARRAY) { - double array[]; + ARRAY(double, array); int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); int num_bars = last_bar - start_bar + 1; @@ -515,7 +534,7 @@ class IndicatorData : public IndicatorBase { * Returns true of successful copy. * Returns false on invalid values. */ - bool CopyEntries(IndicatorDataEntry& _data[], int _count, int _start_shift = 0) { + bool CopyEntries(ARRAY_REF(IndicatorDataEntry, _data), int _count, int _start_shift = 0) { bool _is_valid = true; if (ArraySize(_data) < _count) { _is_valid &= ArrayResize(_data, _count) > 0; @@ -536,7 +555,7 @@ class IndicatorData : public IndicatorBase { * Returns false on invalid values. */ template - bool CopyValues(T& _data[], int _count, int _start_shift = 0, int _mode = 0) { + bool CopyValues(ARRAY_REF(T, _data), int _count, int _start_shift = 0, int _mode = 0) { bool _is_valid = true; if (ArraySize(_data) < _count) { _count = ArrayResize(_data, _count); @@ -575,7 +594,7 @@ class IndicatorData : public IndicatorBase { } else if (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)) != -1) { int _source_id = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID)); - Print("Setting data source by id is now obsolete. Please use SetDataSource(IndicatorBase*) method for ", + Print("Setting data source by id is now obsolete. Please use SetDataSource(IndicatorData*) method for ", GetName(), " (data source id ", _source_id, ")."); DebugBreak(); @@ -607,7 +626,7 @@ class IndicatorData : public IndicatorBase { } if (_validate) { - ValidateDataSource(&this, _result); + ValidateDataSource(THIS_PTR, _result); } return _result; @@ -775,7 +794,7 @@ class IndicatorData : public IndicatorBase { // If _indi or any of the _indi's data source points to this indicator then this would create circular dependency. for (_curr = _indi; _curr != nullptr && _iterations_left != 0; - _curr = _curr.GetDataSource(false), --_iterations_left) { + _curr = _curr PTR_DEREF GetDataSource(false), --_iterations_left) { if (_curr == THIS_PTR) { // Circular dependency found. Print("Error: Circular dependency found when trying to attach " + _indi PTR_DEREF GetFullName() + " into " + @@ -786,16 +805,16 @@ class IndicatorData : public IndicatorBase { } if (indi_src.IsSet()) { - if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT) && - !bool(_indi.GetFlags() | INDI_FLAG_INDEXABLE_BY_SHIFT)) { - Print(GetFullName(), ": Cannot set data source to ", _indi.GetFullName(), + if (bool(flags & INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_SHIFT) && + !bool(_indi PTR_DEREF GetFlags() & INDI_FLAG_INDEXABLE_BY_SHIFT)) { + Print(GetFullName(), ": Cannot set data source to ", _indi PTR_DEREF GetFullName(), ", because source indicator isn't indexable by shift!"); DebugBreak(); return; } - if (bool(flags | INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP) && - !bool(_indi.GetFlags() | INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { - Print(GetFullName(), ": Cannot set data source to ", _indi.GetFullName(), + if (bool(flags & INDI_FLAG_SOURCE_REQ_INDEXABLE_BY_TIMESTAMP) && + !bool(_indi PTR_DEREF GetFlags() & INDI_FLAG_INDEXABLE_BY_TIMESTAMP)) { + Print(GetFullName(), ": Cannot set data source to ", _indi PTR_DEREF GetFullName(), ", because source indicator isn't indexable by timestamp!"); DebugBreak(); return; @@ -803,14 +822,14 @@ class IndicatorData : public IndicatorBase { } if (indi_src.IsSet() && indi_src.Ptr() != _indi) { - indi_src.Ptr().RemoveListener(THIS_PTR); + indi_src REF_DEREF RemoveListener(THIS_PTR); } indi_src = _indi; if (_indi != NULL) { - indi_src.Ptr().AddListener(THIS_PTR); + indi_src REF_DEREF AddListener(THIS_PTR); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_ID), -1); Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_SRC_MODE), _input_mode); - indi_src.Ptr().OnBecomeDataSourceFor(THIS_PTR); + indi_src REF_DEREF OnBecomeDataSourceFor(THIS_PTR); } } @@ -855,10 +874,13 @@ class IndicatorData : public IndicatorBase { HasSpecificValueStorage(INDI_VS_TYPE_TICK_VOLUME); } - void Tick(int _global_tick_index) { + bool Tick(int _global_tick_index) { if (last_tick_index == _global_tick_index) { +#ifdef __debug_indicator__ + Print("We've already ticked tick index #", _global_tick_index, ". Skipping Tick() for ", GetFullName()); +#endif // We've already ticked. - return; + return last_tick_result; } if (_global_tick_index == 0) { @@ -868,19 +890,38 @@ class IndicatorData : public IndicatorBase { last_tick_index = _global_tick_index; + last_tick_result = false; + // Checking and potentially initializing new data source. - if (HasDataSource(true) != NULL) { + if (HasDataSource(true)) { // Ticking data source if not yet ticked. - GetDataSource().Tick(_global_tick_index); + + // If data source returns true, that means it ticked and there could be more ticks in the future. + last_tick_result |= GetDataSource() PTR_DEREF Tick(_global_tick_index); } // Also ticking all used indicators if they've not yet ticked. for (DictStructIterator> iter = indicators.Begin(); iter.IsValid(); ++iter) { - iter.Value().Ptr().Tick(_global_tick_index); + // If any of the attached indicators ticks then we signal that the tick happened, even if this indicator doesn't + // tick. It is because e.g., RSI could use Candle indicator and Candle could use Tick indicator. Ticking RSI + // doesn't signal tick in RSI, nor Candle, but only Tick indicator and only if new tick occured in the Tick + // indicator. In other words: Only Tick indicator returns true in its OnTick(). Also, in OnTick() it sends a tick + // into Candle indicator which aggregates ticks. RSI doesn't have OnTick() and we can't know if there is new RSI + // value. The only way to know that is to Tick all indicators in hierarchy and if one of them returns true in + // OnTick() then we know that we have new value for RSI. + bool _tick_result = iter.Value() REF_DEREF Tick(_global_tick_index); + +#ifdef __debug_indicator__ + Print(iter.Value() REF_DEREF GetFullName(), "'s Tick() result: ", _tick_result ? "true" : "false"); +#endif + + last_tick_result |= _tick_result; } // Overridable OnTick() method. - OnTick(_global_tick_index); + last_tick_result |= OnTick(_global_tick_index); + + return last_tick_result; } /** @@ -924,27 +965,27 @@ class IndicatorData : public IndicatorBase { return; } - if (!_target.IsDataSourceModeSelectable()) { + if (!_target PTR_DEREF IsDataSourceModeSelectable()) { // We don't validate source mode as it will use all modes. return; } - if (_source.GetModeCount() > 1 && - _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { + if (_source PTR_DEREF GetModeCount() > 1 && + _target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { // Mode must be selected if source indicator has more that one mode. Alert("Warning! ", GetName(), " must select source indicator's mode via SetDataSourceMode(int). Defaulting to mode 0."); - _target.idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); + _target PTR_DEREF idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); DebugBreak(); - } else if (_source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == 1 && - _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { - _target.idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); - } else if (_target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) < 0 || - _target.idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) > - _source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) { - Alert("Error! ", _target.GetName(), + } else if (_source PTR_DEREF Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == 1 && + _target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) == -1) { + _target PTR_DEREF idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE), 0); + } else if (_target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) < 0 || + _target PTR_DEREF idparams.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DATA_SRC_MODE)) > + _source PTR_DEREF Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES))) { + Alert("Error! ", _target PTR_DEREF GetName(), " must select valid source indicator's mode via SetDataSourceMode(int) between 0 and ", - _source.Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)), "."); + _source PTR_DEREF Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)), "."); DebugBreak(); } } @@ -1001,7 +1042,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's value in plain format. */ - virtual string ToString(int _index = 0) { + string EntryToString(int _index = 0) { IndicatorDataEntry _entry = GetEntry(_index); int _serializer_flags = SERIALIZER_FLAG_SKIP_HIDDEN | SERIALIZER_FLAG_INCLUDE_DEFAULT | SERIALIZER_FLAG_INCLUDE_DYNAMIC | SERIALIZER_FLAG_INCLUDE_FEATURE; @@ -1059,6 +1100,12 @@ class IndicatorData : public IndicatorBase { return INDI_VS_TYPE_PRICE_TYPICAL; case PRICE_WEIGHTED: return INDI_VS_TYPE_PRICE_WEIGHTED; + default: + if ((int)GetAppliedPrice() == (int)PRICE_ASK) { + return INDI_VS_TYPE_PRICE_ASK; + } else if ((int)GetAppliedPrice() == (int)PRICE_BID) { + return INDI_VS_TYPE_PRICE_BID; + } } Print("Error: ", GetFullName(), " has not supported applied price set: ", EnumToString(GetAppliedPrice()), "!"); @@ -1186,7 +1233,7 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's struct value via index. */ - virtual IndicatorDataEntry GetEntry(int _rel_shift = 0) = nullptr; + virtual IndicatorDataEntry GetEntry(int _rel_shift = 0) = 0; /** * Returns the indicator's struct value via timestamp. @@ -1204,7 +1251,7 @@ class IndicatorData : public IndicatorBase { * This method allows user to modify the struct entry before it's added to cache. * This method is called on GetEntry() right after values are set. */ - virtual void GetEntryAlter(IndicatorDataEntry& _entry) {} + virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) {} // virtual ENUM_IDATA_VALUE_RANGE GetIDataValueRange() = NULL; @@ -1326,9 +1373,14 @@ class IndicatorData : public IndicatorBase { case PRICE_WEIGHTED: return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_WEIGHTED); default: + if ((int)GetAppliedPrice() == (int)PRICE_ASK) { + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); + } else if ((int)GetAppliedPrice() == (int)PRICE_BID) { + return HasSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); + } Print("Error: Invalid applied price " + EnumToString(_ap) + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " - "IndicatorBase::HasSpecificAppliedPriceValueStorage()!"); + "IndicatorData::HasSpecificAppliedPriceValueStorage()!"); DebugBreak(); return false; } @@ -1338,8 +1390,7 @@ class IndicatorData : public IndicatorBase { * Returns value storage to be used for given applied price or applied price overriden by target indicator via * SetDataSourceAppliedPrice(). */ - virtual ValueStorage* GetSpecificAppliedPriceValueStorage(ENUM_APPLIED_PRICE _ap, - IndicatorData* _target = nullptr) { + ValueStorage* GetSpecificAppliedPriceValueStorage(ENUM_APPLIED_PRICE _ap, IndicatorData* _target = nullptr) { if (_target != nullptr) { if (_target PTR_DEREF GetDataSourceAppliedType() != INDI_VS_TYPE_NONE) { // User wants to use custom value storage type as applied price, so we forcefully override AP given as the @@ -1369,11 +1420,16 @@ class IndicatorData : public IndicatorBase { case PRICE_WEIGHTED: return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_WEIGHTED); default: + if ((int)GetAppliedPrice() == (int)PRICE_ASK) { + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_ASK); + } else if ((int)GetAppliedPrice() == (int)PRICE_BID) { + return (ValueStorage*)GetSpecificValueStorage(INDI_VS_TYPE_PRICE_BID); + } Print("Error: Invalid applied price " + EnumToString(_ap) + ", only PRICE_(OPEN|HIGH|LOW|CLOSE|MEDIAN|TYPICAL|WEIGHTED) are currently supported by " - "IndicatorBase::GetSpecificAppliedPriceValueStorage()!"); + "IndicatorData::GetSpecificAppliedPriceValueStorage()!"); DebugBreak(); - return nullptr; + return NULL; } } @@ -1398,6 +1454,7 @@ class IndicatorData : public IndicatorBase { virtual ENUM_TIMEFRAMES GetTf() { return GetCandle() PTR_DEREF GetTf(); } /** + /** * Traverses source indicators' hierarchy and tries to find Ask, Bid, Spread, * Volume and Tick Volume-featured indicator. IndicatorTick satisfies such * requirements. @@ -1434,9 +1491,7 @@ class IndicatorData : public IndicatorBase { /** * Fetches historic ticks for a given time range. */ - virtual bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { - return false; - } + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { return false; } /** * Fetches historic ticks for a given index (absolute shift) range. @@ -1448,8 +1503,8 @@ class IndicatorData : public IndicatorBase { /** * Fetches historic ticks for a given start time and minimum number of tick to retrieve. */ - virtual bool FetchHistoryByStartTimeAndCount(long _from_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _min_count, - ARRAY_REF(TickTAB, _out_ticks)) { + bool FetchHistoryByStartTimeAndCount(long _from_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _min_count, + ARRAY_REF(TickTAB, _out_ticks)) { // Print("FetchHistoryByStartTimeAndCount:"); // Print("- Requested _from_ms = ", _from_ms, ", _dir = ", EnumToString(_dir), ", _min_count = ", _min_count); @@ -1742,7 +1797,9 @@ class IndicatorData : public IndicatorBase { } if (!value_storages[_mode].IsSet()) { - value_storages[_mode] = new IndicatorBufferValueStorage(THIS_PTR, _mode); + value_storages[_mode] = + ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble(THIS_PTR, + _mode); } return value_storages[_mode].Ptr(); } @@ -1757,10 +1814,21 @@ class IndicatorData : public IndicatorBase { /** * Sends entry to listening indicators. */ - void EmitEntry(IndicatorDataEntry& entry) { + void EmitEntry(IndicatorDataEntry& _entry, ENUM_INDI_EMITTED_ENTRY_TYPE _type = INDI_EMITTED_ENTRY_TYPE_PARENT) { for (int i = 0; i < ArraySize(listeners); ++i) { if (listeners[i].ObjectExists()) { - listeners[i].Ptr().OnDataSourceEntry(entry); + listeners[i].Ptr().OnDataSourceEntry(_entry, _type); + } + } + } + + /** + * Sends information about expected number of emitted entries to listening indicators. + */ + void WillEmitEntries(ENUM_INDI_EMITTED_ENTRY_TYPE _type, int _num_entries) { + for (int i = 0; i < ArraySize(listeners); ++i) { + if (listeners[i].ObjectExists()) { + listeners[i].Ptr().OnDataSourceWillEmitEntries(_type, _num_entries); } } } @@ -1824,12 +1892,27 @@ class IndicatorData : public IndicatorBase { /** * Called when data source emits new entry (historic or future one). */ - virtual void OnDataSourceEntry(IndicatorDataEntry& entry){}; + virtual void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) {} + + /** + * Called when data source expects to emit given number of entries for given type. + * + * Called e.g., from Tick indicator in order Candle indicator to enlarge + * possible history size by given number of entries. We have to do that, + * because otherwise, we could end up with OnCalculate() working on partial + * history candles. + */ + virtual void OnDataSourceWillEmitEntries(ENUM_INDI_EMITTED_ENTRY_TYPE _type, int _num_entries) {} /** * Called when new tick is retrieved from attached data source. */ - virtual void OnTick(int _global_tick_index) {} + virtual bool OnTick(int _global_tick_index) { + // We really don't know if new tick have happened. Let's just return false and let the Platform's Tick() method tick + // the Tick indicator in order to know if new tick was signalled. + return false; + } /** * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on @@ -1897,7 +1980,7 @@ class IndicatorData : public IndicatorBase { /** * BarsCalculated()-compatible method to be used on Indicator instance. */ -int BarsCalculated(IndicatorData* _indi) { return _indi.GetBarsCalculated(); } +int BarsCalculated(IndicatorData* _indi) { return _indi PTR_DEREF GetBarsCalculated(); } /** * CopyBuffer() method to be used on Indicator instance with ValueStorage buffer. @@ -1915,7 +1998,7 @@ int CopyBuffer(IndicatorData* _indi, int _mode, int _start, int _count, ValueSto } for (int i = _start; i < _count; ++i) { - IndicatorDataEntry _entry = _indi.GetEntry(i); + IndicatorDataEntry _entry = _indi PTR_DEREF GetEntry(i); if (!_entry.IsValid()) { break; @@ -1930,4 +2013,32 @@ int CopyBuffer(IndicatorData* _indi, int _mode, int _start, int _count, ValueSto return _num_copied; } +// clang-format off +#include "../Storage/ValueStorage.indicator.h" +// clang-format on + +IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIndicatorBufferValueStorageDouble( + IndicatorData* _indi, int _mode) { + return new IndicatorBufferValueStorage(_indi, _mode); +} + +#ifndef __MQL__ +int GetBarsFromStart(IndicatorData* _indi) { return _indi PTR_DEREF GetBars(); } +#endif + +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(IndicatorData) { + emscripten::class_>("IndicatorData") + .smart_ptr>("Ref") + .function("SetSource", emscripten::optional_override([](IndicatorData& self, IndicatorData* base) { + self.SetDataSource(base); + }), + emscripten::allow_raw_pointer>()); +} + +#endif + #endif // INDICATOR_DATA_H diff --git a/Indicator/IndicatorData.struct.cache.h b/Indicator/IndicatorData.struct.cache.h index dba8e9a8e..da27cae48 100644 --- a/Indicator/IndicatorData.struct.cache.h +++ b/Indicator/IndicatorData.struct.cache.h @@ -176,8 +176,10 @@ class IndicatorCalculateCache : public Dynamic { return price_low_buffer; case PRICE_CLOSE: return price_close_buffer; + default: + RUNTIME_ERROR("Applied price not supported!"); } - return NULL; + return nullptr; } /** @@ -221,7 +223,7 @@ class IndicatorCalculateCache : public Dynamic { */ void Resize(int _buffers_size) { for (int i = 0; i < ArraySize(buffers); ++i) { - buffers[i].Resize(_buffers_size, 65535); + buffers[i] PTR_DEREF Resize(_buffers_size, 65535); } } @@ -230,7 +232,7 @@ class IndicatorCalculateCache : public Dynamic { */ template D GetValue(int _buffer_index, int _shift) { - return GetBuffer(_buffer_index).Fetch(_shift).Get(); + return GetBuffer(_buffer_index) PTR_DEREF Fetch(_shift).Get(); } /** @@ -241,7 +243,7 @@ class IndicatorCalculateCache : public Dynamic { template D GetTailValue(int _buffer_index, int _shift) { ValueStorage *_buff = GetBuffer(_buffer_index); - int _index = _buff.IsSeries() ? _shift : (ArraySize(_buff) - _shift - 1); + int _index = _buff PTR_DEREF IsSeries() ? _shift : (ArraySize(_buff) - _shift - 1); return _buff[_index].Get(); } diff --git a/Indicator/IndicatorData.struct.h b/Indicator/IndicatorData.struct.h index 61d55d72d..9b6d8525b 100644 --- a/Indicator/IndicatorData.struct.h +++ b/Indicator/IndicatorData.struct.h @@ -30,6 +30,7 @@ #define STRUCT_ENUM_INDICATOR_STATE_PROP STRUCT_ENUM(IndicatorState, ENUM_INDICATOR_STATE_PROP) // Includes. +#include "../Serializer/SerializerConversions.h" #include "../Serializer/SerializerNode.enum.h" #include "IndicatorData.enum.h" @@ -187,8 +188,8 @@ struct IndicatorDataEntry { ARRAY(IndicatorDataEntryValue, values); // Constructors. - IndicatorDataEntry(int _size = 1) : flags(INDI_ENTRY_FLAG_NONE), timestamp(0) { Resize(_size); } - IndicatorDataEntry(IndicatorDataEntry &_entry) { THIS_REF = _entry; } + IndicatorDataEntry(int _size = 1) : timestamp(0), flags(INDI_ENTRY_FLAG_NONE) { Resize(_size); } + IndicatorDataEntry(const IndicatorDataEntry &_entry) { THIS_REF = _entry; } int GetSize() { return ArraySize(values); } // Operator overloading methods. template @@ -211,7 +212,9 @@ struct IndicatorDataEntry { T operator[](I _index) { return values[(int)_index].Get(); } +#ifdef __MQL__ template <> +#endif double operator[](int _index) { if (_index >= ArraySize(values)) { return 0; @@ -325,7 +328,7 @@ struct IndicatorDataEntry { int GetYear() { return DateTimeStatic::Year(timestamp); } long GetTime() { return timestamp; }; ENUM_DATATYPE GetDataType(int _mode) { return values[_mode].GetDataType(); } - ushort GetDataTypeFlags(ENUM_DATATYPE _dt) { + unsigned short GetDataTypeFlags(ENUM_DATATYPE _dt) { switch (_dt) { case TYPE_BOOL: case TYPE_CHAR: @@ -387,7 +390,8 @@ struct IndicatorDataEntry { int _asize = ArraySize(values); string _result = ""; for (int i = 0; i < _asize; i++) { - _result += StringFormat("%s%s", (string)values[i].Get(), i < _asize ? "," : ""); + _result += + StringFormat("%s%s", C_STR(SerializerConversions::ValueToString(values[i].Get())), i < _asize ? "," : ""); } return _result; } @@ -400,21 +404,21 @@ struct IndicatorDataEntry { /* Structure for indicator data parameters. */ struct IndicatorDataParams { public: - // @todo: Move to protected. - bool is_draw; // Draw active. - color indi_color; // Indicator color. protected: /* Struct protected variables */ - bool is_fed; // Whether calc_start_bar is already calculated. int data_src_mode; // Mode used as input from data source. int draw_window; // Drawing window. - int src_id; // Id of the indicator to be used as data source. - int src_mode; // Mode of source indicator - unsigned int max_buffers; // Max buffers to store. - unsigned int max_modes; // Max supported indicator modes (values per entry). ENUM_DATATYPE dtype; // Type of basic data to store values (DTYPE_DOUBLE, DTYPE_INT). + unsigned int max_modes; // Max supported indicator modes (values per entry). + unsigned int max_buffers; // Max buffers to store. 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. + color indi_color; // Indicator color. + // @todo: Move to protected. + bool is_draw; // Draw active. + bool is_fed; // Whether calc_start_bar is already calculated. + int src_id; // Id of the indicator to be used as data source. + int src_mode; // Mode of source indicator public: /* Struct enumerations */ enum ENUM_IDATA_PARAM { @@ -528,6 +532,8 @@ struct IndicatorDataParams { indi_color = _clr; draw_window = _window; } + bool IsDrawing() { return is_draw; } + void SetIndicatorColor(color _clr) { indi_color = _clr; } }; diff --git a/Indicator/IndicatorData.struct.serialize.h b/Indicator/IndicatorData.struct.serialize.h index 06cff24bf..21b5ee051 100644 --- a/Indicator/IndicatorData.struct.serialize.h +++ b/Indicator/IndicatorData.struct.serialize.h @@ -42,11 +42,11 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { switch (values[i].GetDataType()) { case TYPE_DOUBLE: - _s.Pass(THIS_REF, (string)i, values[i].value.vdbl, + _s.Pass(THIS_REF, IntegerToString(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, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vflt, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); break; case TYPE_INT: @@ -58,7 +58,7 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { _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, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vint, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } break; @@ -74,7 +74,7 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { */ SetUserError(ERR_INVALID_PARAMETER); } else { - _s.Pass(THIS_REF, (string)i, values[i].value.vlong, + _s.Pass(THIS_REF, IntegerToString(i), values[i].value.vlong, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } break; diff --git a/Indicator/IndicatorData.struct.signal.h b/Indicator/IndicatorData.struct.signal.h index b90060014..84c36d2db 100644 --- a/Indicator/IndicatorData.struct.signal.h +++ b/Indicator/IndicatorData.struct.signal.h @@ -79,11 +79,22 @@ struct IndicatorSignal { } } SetSignal(INDICATOR_SIGNAL_CROSSOVER, _is_cross); + // INDICATOR_SIGNAL_DIVERGENCE - int _shift0 = ChartStatic::iBarShift(_symbol, _tf, _data[0].timestamp); - int _shift1 = ChartStatic::iBarShift(_symbol, _tf, _data[_size - 1].timestamp); - double _price_w0 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift0); - double _price_w1 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift1); + // + // @fixit Should use pointer to IndicatorBase as a source of prices. + // int _shift0 = ChartStatic::iBarShift(_symbol, _tf, _data[0].timestamp); + // int _shift1 = ChartStatic::iBarShift(_symbol, _tf, _data[_size - 1].timestamp); + // double _price_w0 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift0); + // double _price_w1 = ChartStatic::iPrice(PRICE_WEIGHTED, _symbol, _tf, _shift1); + Alert(__FUNCSIG__, " Should use pointer to IndicatorBase as a source of prices!"); + DebugBreak(); + + // int _shift0 = 0; + // int _shift1 = 1; + double _price_w0 = 0; + double _price_w1 = 0; + SetSignal(INDICATOR_SIGNAL_DIVERGENCE, ((_price_w0 - _price_w1 > 0) && (_data[0][_m1] - _data[_size - 1][_m1]) < 0) || ((_price_w0 - _price_w1) < 0 && (_data[0][_m1] - _data[_size - 1][_m1]) > 0)); @@ -142,7 +153,7 @@ struct IndicatorSignal { int _size = sizeof(int) * 8; for (int i = 0; i < _size; i++) { int _value = CheckSignals(1 << i) ? 1 : 0; - _s.Pass(this, (string)(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + _s.Pass(THIS_REF, IntegerToString(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } return SerializerNodeObject; } diff --git a/Indicator/IndicatorRenko.h b/Indicator/IndicatorRenko.h index df4a403da..89d459b46 100644 --- a/Indicator/IndicatorRenko.h +++ b/Indicator/IndicatorRenko.h @@ -30,8 +30,8 @@ #define INDICATOR_RENKO_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -55,11 +55,11 @@ enum ENUM_INDI_RENKO_CANDLE_TYPE { struct RenkoParams : IndicatorTfParams { int pips_limit; - RenkoParams(int _pips_limit = 10, int _shift = 0) : IndicatorTfParams("Renko") { + RenkoParams(int _pips_limit = 10, int _shift = 0) : IndicatorTfParams("Renko", PERIOD_TF_IRREGULAR) { pips_limit = _pips_limit; shift = _shift; }; - RenkoParams(RenkoParams &_params) : IndicatorTfParams("Renko") { THIS_REF = _params; }; + RenkoParams(RenkoParams &_params) : IndicatorTfParams("Renko", PERIOD_TF_IRREGULAR) { THIS_REF = _params; }; // Getters. unsigned int GetSecsPerCandle() { @@ -171,97 +171,103 @@ class IndicatorRenko : public IndicatorCandle>::OnDataSourceEntry(entry, type); - if (entry.timestamp < last_entry_ts) { - Print("Error: IndicatorRenko doesn't support sending entries in non-ascending order!"); - DebugBreak(); - } + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } + /* + @todo Move logic into ItemsHistoryRenkoCandleProvider class. - // We'll be updating candle from bid price. - double _price = entry[1]; + if (entry.timestamp < last_entry_ts) { + Print("Error: IndicatorRenko doesn't support sending entries in non-ascending order!"); + DebugBreak(); + } - CandleOCTOHLC _candle; - CandleOCTOHLC _last_completed_candle; - ENUM_INDI_RENKO_CANDLE_TYPE _last_completed_candle_type; + // We'll be updating candle from bid price. + double _price = entry[1]; - if (last_completed_candle_ts != 0) { - _last_completed_candle = icdata.GetByKey(last_completed_candle_ts); - _last_completed_candle_type = GetCandleType(_last_completed_candle); - } else { - _last_completed_candle_type = INDI_RENKO_CANDLE_TYPE_NONE; - } + CandleOCTOHLC _candle; + CandleOCTOHLC _last_completed_candle; + ENUM_INDI_RENKO_CANDLE_TYPE _last_completed_candle_type; - if (last_incomplete_candle_ts != 0) { - // There is previous candle. Retrieving and updating it. - _candle = icdata.GetByKey(last_incomplete_candle_ts); - _candle.Update(entry.timestamp, _price); + if (last_completed_candle_ts != 0) { + _last_completed_candle = icdata.GetByKey(last_completed_candle_ts); + _last_completed_candle_type = GetCandleType(_last_completed_candle); + } else { + _last_completed_candle_type = INDI_RENKO_CANDLE_TYPE_NONE; + } - // Checking for close price difference. - if (RenkoConditionMet(_last_completed_candle_type, _candle, _price)) { - // Closing current candle. - _candle.is_complete = true; - } + if (last_incomplete_candle_ts != 0) { + // There is previous candle. Retrieving and updating it. + _candle = icdata.GetByKey(last_incomplete_candle_ts); + _candle.Update(entry.timestamp, _price); + + // Checking for close price difference. + if (RenkoConditionMet(_last_completed_candle_type, _candle, _price)) { + // Closing current candle. + _candle.is_complete = true; + } - // Updating candle. - icdata.Add(_candle, last_incomplete_candle_ts); + // Updating candle. + icdata.Add(_candle, last_incomplete_candle_ts); - Print("Updated Candle: ", _candle.ToString()); + Print("Updated Candle: ", _candle.ToString()); - if (_candle.is_complete) { - last_completed_candle_ts = last_incomplete_candle_ts; - last_incomplete_candle_ts = 0; - } + if (_candle.is_complete) { + last_completed_candle_ts = last_incomplete_candle_ts; + last_incomplete_candle_ts = 0; + } + } else { + // There is no incomplete candle, creating one. + if (last_completed_candle_ts != 0) { + // Price of the last candle will be used to initialize open price for new, incomplete candle. + double _last_close_price = _last_completed_candle.close; + _candle = CandleOCTOHLC(_last_close_price, _last_close_price, _last_close_price, _last_close_price, + entry.timestamp, entry.timestamp); + // Current price will be added to newly created incomplete candle. + _candle.Update(entry.timestamp, _price); } else { - // There is no incomplete candle, creating one. - if (last_completed_candle_ts != 0) { - // Price of the last candle will be used to initialize open price for new, incomplete candle. - double _last_close_price = _last_completed_candle.close; - _candle = CandleOCTOHLC(_last_close_price, _last_close_price, _last_close_price, _last_close_price, - entry.timestamp, entry.timestamp); - // Current price will be added to newly created incomplete candle. - _candle.Update(entry.timestamp, _price); - } else { - // There was no completed candle. Creating new, incomplete candle from current price. - _candle = CandleOCTOHLC(_price, _price, _price, _price, entry.timestamp, entry.timestamp); - } + // There was no completed candle. Creating new, incomplete candle from current price. + _candle = CandleOCTOHLC(_price, _price, _price, _price, entry.timestamp, entry.timestamp); + } - _candle.is_complete = false; + _candle.is_complete = false; - // Creating new candle. - icdata.Add(_candle, entry.timestamp); + // Creating new candle. + icdata.Add(_candle, entry.timestamp); - Print("Added candle: ", _candle.ToString(), " now there is ", icdata.Size(), " candles in the buffer."); + Print("Added candle: ", _candle.ToString(), " now there is ", icdata.Size(), " candles in the buffer."); - last_incomplete_candle_ts = entry.timestamp; - } + last_incomplete_candle_ts = entry.timestamp; + } - static int iteration = 0; + static int iteration = 0; - ++iteration; + ++iteration; - Print("Iteration: ", iteration); + Print("Iteration: ", iteration); - if (iteration > 1793) { - // Print(icdata.ToJSON()); - } + if (iteration > 1793) { + // Print(icdata.ToJSON()); + } - Print("Last Incomplete Time: ", TimeToString(last_incomplete_candle_ts, TIME_DATE | TIME_MINUTES | - TIME_SECONDS), " (", last_incomplete_candle_ts, ")"); Print("Last Incomplete Candle: ", - icdata.GetByKey(last_incomplete_candle_ts).ToString()); Print("Last Completed Time: ", - TimeToString(last_completed_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS), " (", last_completed_candle_ts, - ")"); Print("Last Completed Candle: ", icdata.GetByKey(last_completed_candle_ts).ToString()); + Print("Last Incomplete Time: ", TimeToString(last_incomplete_candle_ts, TIME_DATE | TIME_MINUTES | + TIME_SECONDS), " (", last_incomplete_candle_ts, ")"); Print("Last Incomplete Candle: ", + icdata.GetByKey(last_incomplete_candle_ts).ToString()); Print("Last Completed Time: ", + TimeToString(last_completed_candle_ts, TIME_DATE | TIME_MINUTES | TIME_SECONDS), " (", last_completed_candle_ts, + ")"); Print("Last Completed Candle: ", icdata.GetByKey(last_completed_candle_ts).ToString()); - // Updating tick & bar indices. Bar time is time of the last completed candle. - // Print(last_completed_candle_ts); - counter.OnTick(last_completed_candle_ts); + // Updating tick & bar indices. Bar time is time of the last completed candle. + // Print(last_completed_candle_ts); + counter.OnTick(last_completed_candle_ts); - Print("---------"); + Print("---------"); - last_entry_ts = entry.timestamp; - */ + last_entry_ts = entry.timestamp; + */ }; /** diff --git a/Indicator/IndicatorRenko.provider.h b/Indicator/IndicatorRenko.provider.h index e987f12ba..63c483a80 100644 --- a/Indicator/IndicatorRenko.provider.h +++ b/Indicator/IndicatorRenko.provider.h @@ -25,8 +25,8 @@ #define INDICATOR_RENKO_PROVIDER_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif /** @@ -68,12 +68,24 @@ class ItemsHistoryRenkoCandleProvider : public ItemsHistoryCandleProvider { * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we * want previous or next items from selected starting point. */ - void GetItems(ItemsHistory, ItemsHistoryRenkoCandleProvider>* _history, long _from_time_ms, + bool GetItems(ItemsHistory, ItemsHistoryRenkoCandleProvider>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. Print("IndicatorRenko is not yet implemented!"); DebugBreak(); + return false; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryRenkoCandleProvider>* _history, int _start_index, + int _end_index, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + Print("IndicatorRenko is not yet implemented!"); + DebugBreak(); + return false; } }; diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index db9ab8980..f00021569 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -25,11 +25,12 @@ #define INDICATOR_TF_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. +#include "../Chart.struct.tf.h" #include "IndicatorCandle.h" #include "IndicatorTf.provider.h" @@ -39,9 +40,6 @@ template class IndicatorTf : public IndicatorCandle> { protected: - // Time-frame used to create candles. - ENUM_TIMEFRAMES tf; - /* Protected methods */ /** @@ -50,7 +48,7 @@ class IndicatorTf : public IndicatorCandle(iparams.GetSecsPerCandle(), THIS_PTR)); + history.SetItemProvider(new ItemsHistoryTfCandleProvider(ChartTf::TfToSeconds(GetTf()), THIS_PTR)); } public: @@ -58,18 +56,12 @@ class IndicatorTf : public IndicatorCandle { /** * Called when new tick was emitted from IndicatorTick-based source. */ - virtual void OnTick(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _time_ms, - float _ask, float _bid) { + void OnTick(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _time_ms, float _ask, + float _bid) { ++tick_index; // Print("IndicatorTf's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | @@ -116,28 +116,58 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { /** * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we - * want previous or next items from selected starting point. + * want previous or next items from selected starting point. Should return false if retrieving items by this method + * is not available. */ - void GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _from_time_ms, + bool GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { // Method is called if there is a missing item (candle) in the history. We need to regenerate it. if (_from_time_ms != 0) { // In order to (re)generate candle, we need to fetch ticks within a fixed time-frame and then update that candle // with all fetched ticks. For IndicatorTf, there is no difference between (re)generating backwards or forwards, // as candles are time-framed. The only problem is that there may be missing candles in fetched time-frames. We - // just need to skip such time-frame and fetch ticks for next time-frame. In order to determine + // just need to skip such time-frame and fetch ticks for next time-frame. IndicatorData* _indi_tick = indi PTR_DEREF GetTick(); // Ticks to form a candle. static ARRAY(TickTAB, _ticks); + if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + // For backward direction we need to start from the beginning of the candle as _from_time_ms determines it's + // ending. + //_ticks_to_ms = _ticks_from_ms + (_candle_length_ms - 1); + } else { + //_ticks_to_ms = _ticks_from_ms - (_candle_length_ms - 1); + } + + bool _is_first_item = true; + while (_num_items > 0) { // Calculating time from which and to which we want to retrieve ticks to form a candle. int _ticks_from_s = GetCandleTimeFromTimeMs(_from_time_ms, spc); long _ticks_from_ms = (long)_ticks_from_s * 1000; long _candle_length_ms = (long)spc * 1000; - long _ticks_to_ms = _ticks_from_ms + _candle_length_ms - 1; + long _ticks_to_ms; + + _ticks_to_ms = _ticks_from_ms + (_candle_length_ms - 1); + + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + // Backwards. + if (_is_first_item) { + // As _from_time_ms in backward direction is next candle time - 1ms + // then we need to include it in our calculations. + long _new_start_ms = _from_time_ms - (_candle_length_ms - 1); + long _new_end_ms = _from_time_ms; + + _ticks_from_ms = _new_start_ms; + _ticks_from_s = int(_new_start_ms / 1000); + _from_time_ms = _new_start_ms; + _ticks_to_ms = _new_end_ms; + + _is_first_item = false; + } + } // We will try to fetch history by two methods. // 1. By time range if IndicatorTick supports that way. @@ -159,7 +189,13 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { // Adding candle to the output array. ArrayPushObject(_out_arr, _candle); - --_num_items; + } + + // Even if we don't form an item (a candle), we assume we've done one item. + --_num_items; + + if (_num_items % 10000 == 0) { + Print(_num_items, " left to process..."); } if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { @@ -172,12 +208,23 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider { Print("Error: GetItems() for IndicatorTf can only work with given _from_time_ms!"); DebugBreak(); } + + return true; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryTfCandleProvider>* _history, int _start_index, + int _end_index, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + return false; } /** * Returns information about item provider. */ - string ToString() override { return "IndicatorTf candle provider on " + indi PTR_DEREF GetFullName(); } + string const ToString() override { return "IndicatorTf candle provider on " + indi PTR_DEREF GetFullName(); } }; #endif // INDICATOR_TF_PROVIDER_H diff --git a/Indicator/IndicatorTf.struct.h b/Indicator/IndicatorTf.struct.h index 49b31ab0c..606023e17 100644 --- a/Indicator/IndicatorTf.struct.h +++ b/Indicator/IndicatorTf.struct.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -36,13 +36,8 @@ /* Structure for IndicatorTf class parameters. */ struct IndicatorTfParams : IndicatorParams { ChartTf tf; - unsigned int spc; // Seconds per candle. // Struct constructor. - IndicatorTfParams(string _name = "", unsigned int _spc = 60) : IndicatorParams(_name), spc(_spc) {} - // Getters. - unsigned int GetSecsPerCandle() { return spc; } - // Setters. - void SetSecsPerCandle(unsigned int _spc) { spc = _spc; } + IndicatorTfParams(string _name, ENUM_TIMEFRAMES _tf) : IndicatorParams(_name) { tf.SetTf(_tf); } // Copy constructor. IndicatorTfParams(const IndicatorTfParams &_params, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { THIS_REF = _params; diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index a9a602440..f9bbfbb9e 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -25,8 +25,8 @@ #define INDICATOR_TICK_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -65,12 +65,12 @@ class IndicatorTick : public Indicator { */ void Init() { // We can't index by shift. - flags &= ~INDI_FLAG_INDEXABLE_BY_SHIFT; + THIS_ATTR flags &= ~INDI_FLAG_INDEXABLE_BY_SHIFT; // We can only index via timestamp. - flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; + THIS_ATTR flags |= INDI_FLAG_INDEXABLE_BY_TIMESTAMP; // Ask and Bid price. - Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), 2); + THIS_ATTR Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES), (int)2); history.SetItemProvider(new ItemsHistoryTickProvider(THIS_PTR)); } @@ -82,17 +82,17 @@ class IndicatorTick : public Indicator { * Class constructor. */ IndicatorTick(string _symbol, const TS& _itparams, const IndicatorDataParams& _idparams, - IndicatorBase* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_itparams, _idparams, _indi_src, _indi_mode) { + IndicatorData* _indi_src = NULL, int _indi_mode = 0) + : Indicator(_itparams, _idparams, _indi_src, _indi_mode), history(THIS_PTR) { itparams = _itparams; if (_indi_src != NULL) { - SetDataSource(_indi_src, _indi_mode); + THIS_ATTR SetDataSource(_indi_src, _indi_mode); } symbol = _symbol; Init(); } IndicatorTick(string _symbol, ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name) { + : Indicator(_itype, _shift, _name), history(THIS_PTR) { symbol = _symbol; Init(); } @@ -115,12 +115,18 @@ class IndicatorTick : public Indicator { /** * Gets ask price for a given date and time. Return current ask price if _dt wasn't passed or is 0. */ - virtual double GetAsk(int _shift = 0) { return GetEntryValue(INDI_TICK_MODE_PRICE_ASK, _shift).Get(); } + double GetAsk(int _shift = 0) override { + IndicatorDataEntryValue _entry = GetEntryValue(INDI_TICK_MODE_PRICE_ASK, _shift); + return _entry.Get(); + } /** * Gets bid price for a given date and time. Return current bid price if _dt wasn't passed or is 0. */ - virtual double GetBid(int _shift = 0) { return GetEntryValue(INDI_TICK_MODE_PRICE_BID, _shift).Get(); } + double GetBid(int _shift = 0) override { + IndicatorDataEntryValue _entry = GetEntryValue(INDI_TICK_MODE_PRICE_BID, _shift); + return _entry.Get(); + } /** * Returns value storage of given kind. @@ -150,7 +156,7 @@ class IndicatorTick : public Indicator { /** * Checks whether indicator support given value storage type. */ - virtual bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) { + bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { switch (_type) { case INDI_VS_TYPE_PRICE_ASK: case INDI_VS_TYPE_PRICE_BID: @@ -158,6 +164,8 @@ class IndicatorTick : public Indicator { case INDI_VS_TYPE_VOLUME: case INDI_VS_TYPE_TICK_VOLUME: return true; + default: + break; } return Indicator::HasSpecificValueStorage(_type); diff --git a/Indicator/IndicatorTick.provider.h b/Indicator/IndicatorTick.provider.h index 16659088a..1b4e5a62d 100644 --- a/Indicator/IndicatorTick.provider.h +++ b/Indicator/IndicatorTick.provider.h @@ -25,15 +25,15 @@ #define INDICATOR_TICK_PROVIDER_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. #include "../Storage/ItemsHistory.h" /** - * Regenerates candles and updates exising candles from new ticks. Subclasses by IndicatorTf, IndicatorRenko. + * Regenerates candles and updates existing candles from new ticks. Derived by IndicatorTf, IndicatorRenko. */ template class ItemsHistoryTickProvider : public ItemsHistoryItemProvider> { @@ -57,18 +57,27 @@ class ItemsHistoryTickProvider : public ItemsHistoryItemProvider> { /** * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we - * want previous or next items from selected starting point. + * want previous or next items from selected starting point. Should return false if retrieving items by this method + * is not available. */ - void GetItems(ItemsHistory, ItemsHistoryTickProvider>* _history, long _from_time_ms, + bool GetItems(ItemsHistory, ItemsHistoryTickProvider>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(TickTAB, _out_arr)) { - // Method is called if there is a missing item (tick) in the history. We need to regenerate it. - indi PTR_DEREF FetchHistoryByStartTimeAndCount(_from_time_ms, _dir, _num_items, _out_arr); + return false; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryTickProvider>* _history, int _start_index, int _end_index, + ARRAY_REF(TickTAB, _out_arr)) { + return false; } /** * Returns information about item provider. */ - string ToString() override { return "IndicatorTick tick provider on " + indi PTR_DEREF GetFullName(); } + string const ToString() override { return "IndicatorTick tick provider on " + indi PTR_DEREF GetFullName(); } }; #endif // INDICATOR_TICK_PROVIDER_H diff --git a/Indicator/tests/IndicatorCandle.test.mq5 b/Indicator/tests/IndicatorCandle.test.mq5 index e56c7755f..460c31890 100644 --- a/Indicator/tests/IndicatorCandle.test.mq5 +++ b/Indicator/tests/IndicatorCandle.test.mq5 @@ -36,7 +36,7 @@ Ref indi_candle; */ int OnInit() { Platform::Init(); - Platform::Add(indi_candle = Platform::FetchDefaultCandleIndicator()); + Platform::Add(indi_candle = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1)); return _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; } diff --git a/Indicator/tests/IndicatorRenko.test.mq5 b/Indicator/tests/IndicatorRenko.test.mq5 index 483749ff6..80ff7d3b5 100644 --- a/Indicator/tests/IndicatorRenko.test.mq5 +++ b/Indicator/tests/IndicatorRenko.test.mq5 @@ -47,7 +47,7 @@ Ref indi_renko; int OnInit() { Platform::Init(); // Platform ticks. - indi_tick = Platform::FetchDefaultTickIndicator(); + indi_tick = Platform::FetchDefaultTickIndicator("EURUSD"); // Renko with 10 pips limit. Platform::Add(indi_renko = new IndicatorRenko(1)); diff --git a/Indicator/tests/IndicatorTf.test.mq5 b/Indicator/tests/IndicatorTf.test.mq5 index dfba778b1..11916f2ff 100644 --- a/Indicator/tests/IndicatorTf.test.mq5 +++ b/Indicator/tests/IndicatorTf.test.mq5 @@ -55,13 +55,13 @@ Ref indi_ama_custom; int OnInit() { Platform::Init(); // Platform ticks. - indi_tick = Platform::FetchDefaultTickIndicator(); + indi_tick = Platform::FetchDefaultTickIndicator("EURUSD"); // 1-second candles. // indicators.Add(indi_tf = new IndicatorTfDummy(1)); // 1:1 candles from platform using current timeframe. - indi_tf_real = Platform::FetchDefaultCandleIndicator(); + indi_tf_real = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); // 1-second candles. // indicators.Add(indi_ama = new Indi_AMA()); @@ -70,7 +70,7 @@ int OnInit() { _ama_params.applied_price = PRICE_OPEN; // AMA on platform candles. - Platform::Add(indi_ama_orig_sim = new Indi_AMA(_ama_params)); + Platform::AddWithDefaultBindings(indi_ama_orig_sim = new Indi_AMA(_ama_params), "EURUSD", PERIOD_M1); // Original built-in AMA indicator on platform OHLCs. Platform::Add(indi_ama_orig = new Indi_AMA(_ama_params, IDATA_BUILTIN)); diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 4b2a73c03..0648a1908 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -25,17 +25,18 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. +#include "../../../Platform.define.h" #include "../../IndicatorTf.h" #include "../../IndicatorTf.struct.h" // Params for dummy candle-based indicator. struct IndicatorTfDummyParams : IndicatorTfParams { - IndicatorTfDummyParams(unsigned int _spc = 60) : IndicatorTfParams("IndicatorTf", _spc) {} + IndicatorTfDummyParams(ENUM_TIMEFRAMES _tf = PLATFORM_WRONG_TIMEFRAME) : IndicatorTfParams("IndicatorTf", _tf) {} }; /** @@ -43,17 +44,30 @@ struct IndicatorTfDummyParams : IndicatorTfParams { */ class IndicatorTfDummy : public IndicatorTf { public: - IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} - IndicatorTfDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTf(_tf) {} - IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi = 0) : IndicatorTf(_tfi) {} + IndicatorTfDummy(ENUM_TIMEFRAMES _tf) : IndicatorTf(IndicatorTfDummyParams(_tf), IndicatorDataParams()) { Init(); } + IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi) + : IndicatorTf(IndicatorTfDummyParams(ChartTf::IndexToTf(_tfi)), IndicatorDataParams()) { + Init(); + } + + void Init() { + // Explicitly specifying built-in mode as in C++ default mode is On-Indicator. + idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_BUILTIN); + } + + string GetName() override { return "IndicatorTfDummy(" + iparams.tf.GetString() + ")"; } - string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } + void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + IndicatorTf::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } - void OnDataSourceEntry(IndicatorDataEntry& entry) override { // When overriding OnDataSourceEntry() we have to remember to call parent // method, because IndicatorCandle also need to invoke it in order to // create/update matching candle. - IndicatorTf::OnDataSourceEntry(entry); #ifdef __debug_indicator__ Print(GetFullName(), " got new tick at ", entry.timestamp, @@ -61,3 +75,33 @@ class IndicatorTfDummy : public IndicatorTf { #endif } }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyParams) { emscripten::value_object("indicators.TfParams"); } + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyBaseBaseBase) { + emscripten::class_, emscripten::base>( + "IndicatorTfDummyBaseBaseBase"); +} + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyBaseBase) { + emscripten::class_>, + emscripten::base>>("IndicatorTfDummyBaseBase"); +} + +EMSCRIPTEN_BINDINGS(IndicatorTfDummyBase) { + emscripten::class_< + IndicatorTf, + emscripten::base>>>( + "IndicatorTfDummyBase"); +} + +EMSCRIPTEN_BINDINGS(IndicatorTfDummy) { + emscripten::class_>>("indicators.Tf") + .smart_ptr>("Ref") + .constructor(); +} + +#endif diff --git a/Indicator/tests/classes/Indicators.h b/Indicator/tests/classes/Indicators.h index d4839b3b3..e5d11c23e 100644 --- a/Indicator/tests/classes/Indicators.h +++ b/Indicator/tests/classes/Indicators.h @@ -37,25 +37,30 @@ * Helper class to store all indicators and call OnTick() on them. */ class Indicators { - Ref _indis[]; + DictStruct> _indis; public: - void Add(IndicatorBase* _indi) { + void Add(IndicatorData* _indi) { Ref _ref = _indi; - ArrayPushObject(_indis, _ref); + _indis.Push(_ref); } - void Remove(IndicatorData* _indi) { - Ref _ref = _indi; - Util::ArrayRemoveFirst(_indis, _ref); - } + void Add(Ref& _indi) { Add(_indi.Ptr()); } + + IndicatorData* Get(int index) { return _indis[index].Ptr(); } + + IndicatorData* operator[](int index) { return Get(index); } + + int Size() { return (int)_indis.Size(); } + + void Clear() { _indis.Clear(); } /** * Executes OnTick() on every added indicator. */ void Tick(int _global_tick_index) { - for (int i = 0; i < ArraySize(_indis); ++i) { - _indis[i].Ptr().OnTick(_global_tick_index); + for (unsigned int i = 0; i < _indis.Size(); ++i) { + _indis[i].Ptr() PTR_DEREF OnTick(_global_tick_index); } } @@ -64,9 +69,9 @@ class Indicators { */ string ToString(int _shift = 0) { string _result; - for (int i = 0; i < ArraySize(_indis); ++i) { - IndicatorDataEntry _entry = _indis[i].Ptr().GetEntry(_shift); - _result += _indis[i].Ptr().GetFullName() + " = " + _entry.ToString() + "\n"; + for (unsigned int i = 0; i < _indis.Size(); ++i) { + IndicatorDataEntry _entry = _indis[i].Ptr() PTR_DEREF GetEntry(_shift); + _result += _indis[i].Ptr() PTR_DEREF GetFullName() + " = " + _entry.ToString() + "\n"; } return _result; } diff --git a/IndicatorLegacy.h b/IndicatorLegacy.h index 188d02fd7..31ee7226e 100644 --- a/IndicatorLegacy.h +++ b/IndicatorLegacy.h @@ -4,86 +4,138 @@ */ #ifndef __MQL__ -#pragma once + #pragma once #endif +// Includes. +#include "Platform.h" + #ifdef INDICATOR_LEGACY_VERSION_MT4 -#define INDICATOR_LEGACY_VERSION_DEFINED + #define INDICATOR_LEGACY_VERSION_DEFINED #endif #ifdef INDICATOR_LEGACY_VERSION_MT5 -#define INDICATOR_LEGACY_VERSION_DEFINED + #define INDICATOR_LEGACY_VERSION_DEFINED #endif -#ifndef INDICATOR_LEGACY_VERSION_DEFINED -#define INDICATOR_LEGACY_VERSION_MT5 -#define INDICATOR_LEGACY_VERSION_DEFINED +#ifdef INDICATOR_STANDALONE_VERSION_LONG + #define INDICATOR_STANDALONE_VERSION_DEFINED #endif -#ifdef __MQL4__ +#ifdef INDICATOR_STANDALONE_VERSION_SHORT + #define INDICATOR_STANDALONE_VERSION_DEFINED +#endif -#include -#include -#include -#include -#include +#ifdef INDICATOR_STANDALONE_VERSION_DEFINED + +/** + * Wrapper for future OnInit(). We may need to init indicator with candle and + * tick inidicator in the hierarchy. + */ +int OnInit() { + int _result = OnInitOriginal(); + Platform::AddWithDefaultBindings(INDICATOR_STANDALONE_INDI_PTR, Symbol(), (ENUM_TIMEFRAMES)Period()); + return _result; +} + + #define OnInit OnInitOriginal + + // In standalone mode without legacy mode we also need to wrap OnCalculate() as + // we need to call Platform::OnCalculate(). The only difference is that we + // don't need to change buffer's AsSeries flag in MT5. + #ifndef INDICATOR_LEGACY_VERSION_DEFINED + #ifndef INDICATOR_LEGACY_EMIT_ONCALCULATE_WRAPPER + #define INDICATOR_LEGACY_EMIT_ONCALCULATE_WRAPPER + #endif + + // No work required for buffers. + #define INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER + #define INDICATOR_LEGACY_VERSION_RELEASE_BUFFER + #ifdef INDICATOR_STANDALONE_VERSION_LONG + // We don't want to write two OnCalculate() wrappers. One is enough. + #define INDICATOR_LEGACY_VERSION_LONG + #endif // INDICATOR_STANDALONE_VERSION_LONG + #ifdef INDICATOR_STANDALONE_VERSION_SHORT + // We don't want to write two OnCalculate() wrappers. One is enough. + #define INDICATOR_LEGACY_VERSION_SHORT + #endif // INDICATOR_STANDALONE_VERSION_LONG + #endif // INDICATOR_LEGACY_VERSION_DEFINED + +#endif // INDICATOR_STANDALONE_VERSION_DEFINED #ifndef INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER -#define INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER + #define INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER #endif #ifndef INDICATOR_LEGACY_VERSION_RELEASE_BUFFER -#define INDICATOR_LEGACY_VERSION_RELEASE_BUFFER + #define INDICATOR_LEGACY_VERSION_RELEASE_BUFFER #endif -#ifdef INDICATOR_LEGACY_VERSION_MT5 +#ifdef INDICATOR_LEGACY_EMIT_ONCALCULATE_WRAPPER -#ifndef INDICATOR_LEGACY_VERSION_SHORT + #include + #include + #include + #include + #include + + #ifdef INDICATOR_LEGACY_VERSION_SHORT /** - * Replacement for future OHLC-based OnCalculate(). + * Wrapper for future price-based OnCalculate(). */ -int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], - const double& high[], const double& low[], const double& close[], const long& tick_volume[], - const long& volume[], const int& spread[]) { +int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double& price[]) { // We need to call Platform::Tick() and maybe also IndicatorData::EmitHistory() before. Platform::OnCalculate(rates_total, prev_calculated); INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER; - int _num_calculated = - OnCalculateMT5(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread); + // NOTE: If compiler sees an error here about 'time' parameter conversion + // then you probably must do: + // #define INDICATOR_LEGACY_VERSION_LONG + // before including IndicatorLegacy.h + int _num_calculated = OnCalculateMT5(rates_total, prev_calculated, begin, price); INDICATOR_LEGACY_VERSION_RELEASE_BUFFER; return _num_calculated; } -#else + #endif // INDICATOR_LEGACY_VERSION_SHORT + + #ifdef INDICATOR_LEGACY_VERSION_LONG /** - * Replacement for future price-based OnCalculate(). + * Wrapper for future OHLC-based OnCalculate(). */ -int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double& price[]) { +int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], + const double& high[], const double& low[], const double& close[], const long& tick_volume[], + const long& volume[], const int& spread[]) { // We need to call Platform::Tick() and maybe also IndicatorData::EmitHistory() before. Platform::OnCalculate(rates_total, prev_calculated); - INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER; - - // NOTE: If compiler sees an error here about parameter conversion then you - // probably must do: + // NOTE: If compiler sees an error here about parameter conversion + // then you probably must do: // #define INDICATOR_LEGACY_VERSION_SHORT // before including IndicatorLegacy.h - int _num_calculated = OnCalculateMT5(rates_total, prev_calculated, begin, price); + INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER; + + int _num_calculated = + OnCalculateMT5(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread); INDICATOR_LEGACY_VERSION_RELEASE_BUFFER; return _num_calculated; } -#endif + #endif // INDICATOR_LEGACY_VERSION_LONG -#define OnCalculate OnCalculateMT5 + #define OnCalculate OnCalculateMT5 + +#endif // INDICATOR_LEGACY_EMIT_ONCALCULATE_WRAPPER + +#ifdef __MQL4__ + #ifdef INDICATOR_LEGACY_VERSION_MT5 /** * Wrapper class to be used by MQL4 code to allow calling MQL5's indicator functions like iMA() in MQL4. @@ -188,10 +240,10 @@ int CopyBuffer(int _handle, int _mode, int _start, int _count, double& _buffer[] return _num_copied; } -/** - * Defines wrapper class and global iNAME() indicator function (e.g., iMA(), iATR()). - */ -// Print(#FN_NAME " key = ", _key); \ + /** + * Defines wrapper class and global iNAME() indicator function (e.g., iMA(), iATR()). + */ + // Print(#FN_NAME " key = ", _key); \ #define DEFINE_LEGACY_INDICATOR(FN_NAME, BUILTIN_NAME, TYPED_PARAMS_COMMA, TYPED_PARAMS_NO_UDL_SEMICOLON, UNTYPED_PARAMS_COMMA_KEY, UNTYPED_PARAMS_COMMA_VALUES, ASSIGNMENTS_COMMA, UNTYPED_PARAMS_NO_UDL_COMMA_VALUES) \ class BUILTIN_NAME##Legacy : public IndicatorLegacy { \ TYPED_PARAMS_NO_UDL_SEMICOLON; \ @@ -218,92 +270,95 @@ int FN_NAME(TYPED_PARAMS_COMMA) { \ return PTR_ATTRIB(_indi.Ptr(), GetHandle()); \ } -/** - * 1-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_1(FN_NAME, INDI_NAME, T1, N1) \ - DEFINE_LEGACY_INDICATOR(INDI_NAME, T1 _##N1, T1 N1, _##N1, _##N1, N1(_##N1), N1); - -/** - * 2-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_2(FN_NAME, INDI_NAME, T1, N1, T2, N2) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2, T1 N1 SEMICOLON T2 N2, _##N1 COMMA _##N2, \ - _##N1 COMMA _##N2, N1(_##N1) COMMA N2(_##N2), N1 COMMA N2); - -/** - * 3-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_3(FN_NAME, INDI_NAME, T1, N1, T2, N2, T3, N3) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3, _##N1 COMMA _##N2 COMMA _##N3, \ - _##N1 COMMA _##N2 COMMA _##N3, N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3), \ - N1 COMMA N2 COMMA N3); - -/** - * 4-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_4(FN_NAME, INDI_NAME) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, \ - N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4), N1 COMMA N2 COMMA N3 COMMA N4); - -/** - * 5-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_5(FN_NAME, INDI_NAME) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ - N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5), \ - N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5); - -/** - * 6-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_6(FN_NAME, INDI_NAME) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, \ - T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ - N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6), \ - N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6); - -/** - * 7-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_7(FN_NAME, INDI_NAME) \ - DEFINE_LEGACY_INDICATOR( \ - FN_NAME, INDI_NAME, \ - T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 _##N7, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 SEMICOLON T7 N7, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ - N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) COMMA N7(_##N7), \ - N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7); - -/** - * 8-parameter helper for DEFINE_LEGACY_INDICATOR. - */ -#define DEFINE_LEGACY_INDICATOR_8(FN_NAME, INDI_NAME) \ - DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, \ - T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 \ - _##N7 COMMA T8 _##N8, \ - T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 \ - SEMICOLON T7 N7 SEMICOLON T8 N8, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ - _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ - N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) \ - COMMA N7(_##N7) COMMA N8(_##N8), \ - N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7 COMMA N8); - -/** - * Replacement for future StringConcatenate(). - */ -#define StringConcatenate StringConcatenateMT5 + /** + * 1-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_1(FN_NAME, INDI_NAME, T1, N1) \ + DEFINE_LEGACY_INDICATOR(INDI_NAME, T1 _##N1, T1 N1, _##N1, _##N1, N1(_##N1), N1); + + /** + * 2-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_2(FN_NAME, INDI_NAME, T1, N1, T2, N2) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2, T1 N1 SEMICOLON T2 N2, _##N1 COMMA _##N2, \ + _##N1 COMMA _##N2, N1(_##N1) COMMA N2(_##N2), N1 COMMA N2); + + /** + * 3-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_3(FN_NAME, INDI_NAME, T1, N1, T2, N2, T3, N3) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3, _##N1 COMMA _##N2 COMMA _##N3, \ + _##N1 COMMA _##N2 COMMA _##N3, N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3), \ + N1 COMMA N2 COMMA N3); + + /** + * 4-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_4(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4), \ + N1 COMMA N2 COMMA N3 COMMA N4); + + /** + * 5-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_5(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR(FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5); + + /** + * 6-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_6(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR( \ + FN_NAME, INDI_NAME, T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6); + + /** + * 7-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_7(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR( \ + FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 _##N7, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 SEMICOLON T7 N7, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) COMMA N7(_##N7), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7); + + /** + * 8-parameter helper for DEFINE_LEGACY_INDICATOR. + */ + #define DEFINE_LEGACY_INDICATOR_8(FN_NAME, INDI_NAME) \ + DEFINE_LEGACY_INDICATOR( \ + FN_NAME, INDI_NAME, \ + T1 _##N1 COMMA T2 _##N2 COMMA T3 _##N3 COMMA T4 _##N4 COMMA T5 _##N5 COMMA T6 _##N6 COMMA T7 _##N7 COMMA T8 \ + _##N8, \ + T1 N1 SEMICOLON T2 N2 SEMICOLON T3 N3 SEMICOLON T4 N4 SEMICOLON T5 N5 SEMICOLON T6 N6 SEMICOLON T7 N7 \ + SEMICOLON T8 N8, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ + _##N1 COMMA _##N2 COMMA _##N3 COMMA _##N4 COMMA _##N5 COMMA _##N6 COMMA _##N7 COMMA _##N8, \ + N1(_##N1) COMMA N2(_##N2) COMMA N3(_##N3) COMMA N4(_##N4) COMMA N5(_##N5) COMMA N6(_##N6) COMMA N7(_##N7) \ + COMMA N8(_##N8), \ + N1 COMMA N2 COMMA N3 COMMA N4 COMMA N5 COMMA N6 COMMA N7 COMMA N8); + + /** + * Replacement for future StringConcatenate(). + */ + #define StringConcatenate StringConcatenateMT5 /** * MQL4 wrapper of MQL5's StringConcatenate(). @@ -395,66 +450,66 @@ DEFINE_LEGACY_INDICATOR_2(iAD, iAD, string, symbol, int, period); // int iATR(string symbol, ENUM_TIMEFRAMES period, int ma_period); DEFINE_LEGACY_INDICATOR_3(iATR, iATR, string, symbol, int, period, int, ma_period); -// int iRSI(string symbol, ENUM_TIMEFRAMES period, int ma_period, int applied_price); -#define T1 string -#define N1 symbol -#define T2 int -#define N2 period -#define T3 int -#define N3 ma_period -#define T4 int -#define N4 applied_price + // int iRSI(string symbol, ENUM_TIMEFRAMES period, int ma_period, int applied_price); + #define T1 string + #define N1 symbol + #define T2 int + #define N2 period + #define T3 int + #define N3 ma_period + #define T4 int + #define N4 applied_price DEFINE_LEGACY_INDICATOR_4(iRSI, iRSI) -#undef T1 -#undef N1 -#undef T2 -#undef N2 -#undef T3 -#undef N3 -#undef T4 -#undef N4 -#undef T5 -#undef N5 -#undef T6 -#undef N6 - -// int iMA(string symbol, ENUM_TIMEFRAMES period, int ma_period, int ma_shift, ENUM_MA_METHOD ma_method, -#define T1 string -#define N1 symbol -#define T2 int -#define N2 period -#define T3 int -#define N3 ma_period -#define T4 int -#define N4 ma_shift -#define T5 int -#define N5 ma_method -#define T6 int -#define N6 applied_price + #undef T1 + #undef N1 + #undef T2 + #undef N2 + #undef T3 + #undef N3 + #undef T4 + #undef N4 + #undef T5 + #undef N5 + #undef T6 + #undef N6 + + // int iMA(string symbol, ENUM_TIMEFRAMES period, int ma_period, int ma_shift, ENUM_MA_METHOD ma_method, + #define T1 string + #define N1 symbol + #define T2 int + #define N2 period + #define T3 int + #define N3 ma_period + #define T4 int + #define N4 ma_shift + #define T5 int + #define N5 ma_method + #define T6 int + #define N6 applied_price DEFINE_LEGACY_INDICATOR_6(iMA, iMA) -#undef T1 -#undef N1 -#undef T2 -#undef N2 -#undef T3 -#undef N3 -#undef T4 -#undef N4 -#undef T5 -#undef N5 -#undef T6 -#undef N6 - -#endif // INDICATOR_LEGACY_VERSION_MT5 -#endif // __MQL4__ + #undef T1 + #undef N1 + #undef T2 + #undef N2 + #undef T3 + #undef N3 + #undef T4 + #undef N4 + #undef T5 + #undef N5 + #undef T6 + #undef N6 + + #endif // INDICATOR_LEGACY_VERSION_MT5 +#endif // __MQL4__ #ifdef __MQL5__ -#ifdef INDICATOR_LEGACY_VERSION_MT4 + #ifdef INDICATOR_LEGACY_VERSION_MT4 -/** - * Replacement for future StringConcatenate(). - */ -#define StringConcatenate StringConcatenateMT4 + /** + * Replacement for future StringConcatenate(). + */ + #define StringConcatenate StringConcatenateMT4 /** * MQL5 wrapper of MQL4's StringConcatenate(). @@ -522,5 +577,5 @@ string StringConcatenateMT4(string& _result, A _a) { return (string)_a; } -#endif // INDICATOR_LEGACY_VERSION_MT4 -#endif // __MQL5__ + #endif // INDICATOR_LEGACY_VERSION_MT4 +#endif // __MQL5__ diff --git a/Indicators/Account/Indi_AccountStats.mqh b/Indicators/Account/Indi_AccountStats.mqh index ece3896dc..10f2946c8 100644 --- a/Indicators/Account/Indi_AccountStats.mqh +++ b/Indicators/Account/Indi_AccountStats.mqh @@ -191,14 +191,13 @@ class Indi_AccountStats : public Indicator { /** * Called when data source emits new entry (historic or future one). */ - virtual void OnDataSourceEntry(IndicatorDataEntry &entry/*, ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT*/) { - /* + virtual void OnDataSourceEntry(IndicatorDataEntry &entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { Indicator::OnDataSourceEntry(entry, type); if (type != INDI_EMITTED_ENTRY_TYPE_CANDLE) { return; } - */ // New candle means that account stats for current index 0 will be that we // will now extract and store in the buffers. diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq5 b/Indicators/Account/tests/Indi_AccountStats.test.mq5 index ffb2666f3..81bca2d2d 100644 --- a/Indicators/Account/tests/Indi_AccountStats.test.mq5 +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq5 @@ -39,7 +39,7 @@ int OnInit() { Platform::Init(); - Platform::AddWithDefaultBindings(indi_account_mt.Ptr()); + Platform::AddWithDefaultBindings(indi_account_mt.Ptr(), _Symbol, (ENUM_TIMEFRAMES)Period()); bool _result = true; assertTrueOrFail(indi_account_mt REF_DEREF IsValid(), "Error on IsValid!"); diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index f0e75db14..2e0a1f74e 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -20,18 +20,15 @@ * */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Includes. #include "../BufferStruct.mqh" #include "../Indicator/Indicator.h" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compability). -double iAC(string _symbol, int _tf, int _shift) { - ResetLastError(); - return Indi_AC::iAC(_symbol, (ENUM_TIMEFRAMES)_tf, _shift); -} -#endif - // Structs. struct IndiACParams : IndicatorParams { // Struct constructor. @@ -139,3 +136,11 @@ class Indi_AC : public Indicator { return _ptr; } }; + +#ifndef __MQL4__ +// Defines global functions (for MQL4 backward compability). +double iAC(string _symbol, int _tf, int _shift) { + ResetLastError(); + return Indi_AC::iAC(_symbol, (ENUM_TIMEFRAMES)_tf, _shift); +} +#endif diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index 3c491465d..08769bbbe 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -138,14 +138,14 @@ class Indi_BWMFI : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ - Print(GetVolume(_shift), ", ", GetVolume(_shift + 1), " | ", GetValue(BWMFI_BUFFER, _shift), " > ", - GetValue(BWMFI_BUFFER, _shift + 1)); + Print(GetVolume(_rel_shift), ", ", GetVolume(_rel_shift + 1), " | ", GetValue(BWMFI_BUFFER, _rel_shift), + " > ", GetValue(BWMFI_BUFFER, _rel_shift + 1)); // @see: https://en.wikipedia.org/wiki/Market_facilitation_index - bool _vol_up = GetVolume(_shift) > GetVolume(_shift + 1); - bool _val_up = GetValue(BWMFI_BUFFER, _shift) > GetValue(BWMFI_BUFFER, _shift + 1); + bool _vol_up = GetVolume(_rel_shift) > GetVolume(_rel_shift + 1); + bool _val_up = GetValue(BWMFI_BUFFER, _rel_shift) > GetValue(BWMFI_BUFFER, _rel_shift + 1); double _histcolor = EMPTY_VALUE; switch (_vol_up) { case true: diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index 9300cb9c5..fcd390dbd 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -176,33 +176,33 @@ class Indi_Bands : public Indicator { /** * OnCalculate() method for Bands indicator. */ - static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &ExtMLBuffer, - ValueStorage &ExtTLBuffer, ValueStorage &ExtBLBuffer, - ValueStorage &ExtStdDevBuffer, int InpBandsPeriod, int InpBandsShift, - double InpBandsDeviations) { + static int Calculate(INDICATOR_CALCULATE_METHOD_PARAMS_SHORT, ValueStorage &_ExtMLBuffer, + ValueStorage &_ExtTLBuffer, ValueStorage &_ExtBLBuffer, + ValueStorage &_ExtStdDevBuffer, int _InpBandsPeriod, int _InpBandsShift, + double _InpBandsDeviations) { int ExtBandsPeriod, ExtBandsShift; double ExtBandsDeviations; int ExtPlotBegin = 0; - if (InpBandsPeriod < 2) { + if (_InpBandsPeriod < 2) { ExtBandsPeriod = 20; PrintFormat("Incorrect value for input variable InpBandsPeriod=%d. Indicator will use value=%d for calculations.", - InpBandsPeriod, ExtBandsPeriod); + _InpBandsPeriod, ExtBandsPeriod); } else - ExtBandsPeriod = InpBandsPeriod; - if (InpBandsShift < 0) { + ExtBandsPeriod = _InpBandsPeriod; + if (_InpBandsShift < 0) { ExtBandsShift = 0; PrintFormat("Incorrect value for input variable InpBandsShift=%d. Indicator will use value=%d for calculations.", - InpBandsShift, ExtBandsShift); + _InpBandsShift, ExtBandsShift); } else - ExtBandsShift = InpBandsShift; - if (InpBandsDeviations == 0.0) { + ExtBandsShift = _InpBandsShift; + if (_InpBandsDeviations == 0.0) { ExtBandsDeviations = 2.0; PrintFormat( "Incorrect value for input variable InpBandsDeviations=%f. Indicator will use value=%f for calculations.", - InpBandsDeviations, ExtBandsDeviations); + _InpBandsDeviations, ExtBandsDeviations); } else - ExtBandsDeviations = InpBandsDeviations; + ExtBandsDeviations = _InpBandsDeviations; if (rates_total < ExtPlotBegin) return (0); //--- indexes draw begin settings, when we've recieved previous begin @@ -221,13 +221,13 @@ class Indi_Bands : public Indicator { //--- main cycle for (int i = pos; i < rates_total && !IsStopped(); i++) { //--- middle line - ExtMLBuffer[i] = Indi_MA::SimpleMA(i, ExtBandsPeriod, price); + _ExtMLBuffer[i] = Indi_MA::SimpleMA(i, ExtBandsPeriod, price); //--- calculate and write down StdDev - ExtStdDevBuffer[i] = StdDev_Func(i, price, ExtMLBuffer, ExtBandsPeriod); + _ExtStdDevBuffer[i] = StdDev_Func(i, price, _ExtMLBuffer, ExtBandsPeriod); //--- upper line - ExtTLBuffer[i] = ExtMLBuffer[i] + ExtBandsDeviations * ExtStdDevBuffer[i].Get(); + _ExtTLBuffer[i] = _ExtMLBuffer[i] + ExtBandsDeviations * _ExtStdDevBuffer[i].Get(); //--- lower line - ExtBLBuffer[i] = ExtMLBuffer[i] - ExtBandsDeviations * ExtStdDevBuffer[i].Get(); + _ExtBLBuffer[i] = _ExtMLBuffer[i] - ExtBandsDeviations * _ExtStdDevBuffer[i].Get(); } //--- OnCalculate done. Return new prev_calculated. return (rates_total); diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index b1c7bbd61..ceb0fac4c 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -81,8 +81,8 @@ class Indi_Demo : public Indicator { */ virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { double _value = Indi_Demo::iDemo(THIS_PTR, ToRelShift(_abs_shift)); - if (idparams.is_draw) { - draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(ToRelShift(_abs_shift)), _value); + if (idparams.IsDrawing()) { + // draw.DrawLineTo(GetName(), GetCandle() PTR_DEREF GetBarTime(ToRelShift(_abs_shift)), _value); } return _value; } diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index d12dc6368..830284920 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -114,8 +114,8 @@ class Indi_Drawer : public Indicator { /** * Called when new tick is retrieved from attached data source. */ - void OnTick(int _global_tick_index) override { - Indicator::OnTick(_global_tick_index); + bool OnTick(int _global_tick_index) override { + return Indicator::OnTick(_global_tick_index); /* @fixme TaskActionEntry action(INDI_ACTION_SET_VALUE); diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 8cc78a95b..24527a7ee 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -150,8 +150,6 @@ class Indi_Envelopes : public Indicator { int _mode, // (MT4 _mode): 0 - MODE_MAIN, 1 - MODE_UPPER, 2 - MODE_LOWER; (MT5 // _mode): 0 - UPPER_LINE, 1 - LOWER_LINE int _shift = 0) { - INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, _shift + _ma_shift + _ma_period); - return iEnvelopesOnArray(_source.GetSpecificAppliedPriceValueStorage(_ap, _target), 0, _ma_period, _ma_method, _ma_shift, _deviation, _mode, _shift, _target PTR_DEREF GetCache()); } @@ -173,6 +171,11 @@ class Indi_Envelopes : public Indicator { static double iEnvelopesOnArray(ValueStorage *_price, int _total, int _ma_period, ENUM_MA_METHOD _ma_method, int _ma_shift, double _deviation, int _mode, int _shift, IndicatorCalculateCache *_cache = NULL) { + // We need 1 bar more because MA methods assumes we have historic bars. + if (_price PTR_DEREF Size() < _shift + _ma_shift + _ma_period + 1) { + return DBL_MIN; + } + double _indi_value_buffer[]; double _result; @@ -237,11 +240,11 @@ class Indi_Envelopes : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ // The LINE_MAIN only exists in MQL4 for Envelopes. - _entry.values[LINE_MAIN] = GetValue((ENUM_LO_UP_LINE)LINE_MAIN, _shift); + _entry.values[LINE_MAIN] = GetValue((ENUM_LO_UP_LINE)LINE_MAIN, _rel_shift); #endif } diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index 636d36fb5..10903fe22 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -124,8 +124,8 @@ class Indi_Fractals : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ // In MT4 line identifiers starts from 1, so populating also at 0. _entry.values[0] = _entry.values[LINE_UPPER]; diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index 92bda24ea..61af56eda 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -200,8 +200,8 @@ class Indi_Gator : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); #ifdef __MQL4__ // @todo: Can we calculate upper and lower histogram color in MT4? // @see: https://docs.mql4.com/indicators/igator diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index d54eea444..87ce9400e 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -164,16 +164,17 @@ class Indi_Ichimoku : public Indicator { /** * Alters indicator's struct value. */ - void GetEntryAlter(IndicatorDataEntry &_entry, int _shift) override { - Indicator::GetEntryAlter(_entry, _shift); + void GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) override { + Indicator::GetEntryAlter(_entry, _rel_shift); + int _abs_shift = ToAbsShift(_rel_shift); #ifdef __MQL4__ // In MQL4 value of LINE_TENKANSEN is 1 (not 0 as in MQL5), // so we are duplicating it. - _entry.values[0] = GetEntryValue(LINE_TENKANSEN, _shift); + _entry.values[0] = GetEntryValue(LINE_TENKANSEN, _abs_shift); #endif - _entry.values[LINE_SENKOUSPANA] = GetEntryValue(LINE_SENKOUSPANA, _shift + GetKijunSen()); - _entry.values[LINE_SENKOUSPANB] = GetEntryValue(LINE_SENKOUSPANB, _shift + GetKijunSen()); - _entry.values[LINE_CHIKOUSPAN] = GetEntryValue(LINE_CHIKOUSPAN, _shift + GetKijunSen()); + _entry.values[LINE_SENKOUSPANA] = GetEntryValue(LINE_SENKOUSPANA, _abs_shift + GetKijunSen()); + _entry.values[LINE_SENKOUSPANB] = GetEntryValue(LINE_SENKOUSPANB, _abs_shift + GetKijunSen()); + _entry.values[LINE_CHIKOUSPAN] = GetEntryValue(LINE_CHIKOUSPAN, _abs_shift + GetKijunSen()); } /** diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 1af92cd2e..f3f1801ab 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -24,7 +24,6 @@ #ifndef INDI_MA_MQH #define INDI_MA_MQH -// Includes. #include "../Dict.mqh" #include "../DictObject.mqh" #include "../Indicator/Indicator.h" @@ -33,20 +32,6 @@ #include "../Storage/ValueStorage.h" #include "../String.mqh" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compability). -double iMA(string _symbol, int _tf, int _ma_period, int _ma_shift, int _ma_method, int _ap, int _shift) { - ResetLastError(); - return Indi_MA::iMA(_symbol, (ENUM_TIMEFRAMES)_tf, _ma_period, _ma_shift, (ENUM_MA_METHOD)_ma_method, - (ENUM_APPLIED_PRICE)_ap, _shift); -} -double iMAOnArray(double &_arr[], int _total, int _period, int _ma_shift, int _ma_method, int _abs_shift, - IndicatorCalculateCache *_cache = NULL) { - ResetLastError(); - return Indi_MA::iMAOnArray(_arr, _total, _period, _ma_shift, _ma_method, _abs_shift, _cache); -} -#endif - // Structs. struct IndiMAParams : IndicatorParams { unsigned int period; @@ -134,7 +119,8 @@ class Indi_MA : public Indicator { unsigned int ma_period, unsigned int ma_shift, ENUM_MA_METHOD ma_method, // (MT4/MT5): MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA ENUM_APPLIED_PRICE _ap, int shift = 0) { - INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, int(ma_period + ma_shift + shift)); + // We need 1 bar more because MA methods assumes we have historic bars. + INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_source, int(ma_period + ma_shift + shift + 1)); ValueStorage *_data = (ValueStorage *)_source.GetSpecificAppliedPriceValueStorage(_ap, _target); return iMAOnArray(_data, 0, ma_period, ma_shift, ma_method, shift, _target PTR_DEREF GetCache()); } @@ -542,6 +528,55 @@ class Indi_MA : public Indicator { return (rates_total); } + static int LinearWeightedMAOnBuffer(const int rates_total, const int prev_calculated, const int begin, + const int period, const ARRAY_REF(double, price), ARRAY_REF(double, buffer), + int &weight_sum) { + int i, k; + + // Check period. + if (period <= 1 || period > (rates_total - begin)) return (0); + // Save as_series flags. + bool as_series_price = ArrayGetAsSeries(price); + bool as_series_buffer = ArrayGetAsSeries(buffer); + + ArraySetAsSeries(price, false); + ArraySetAsSeries(buffer, false); + // Calculate start position. + int start_position; + + if (prev_calculated == 0) { + // First calculation or number of bars was changed. + // Set empty value for first bars. + start_position = period + begin; + + for (i = 0; i < start_position; i++) buffer[i] = 0.0; + // Calculate first visible value. + double first_value = 0; + int wsum = 0; + + for (i = begin, k = 1; i < start_position; i++, k++) { + first_value += k * price[i]; + wsum += k; + } + + buffer[start_position - 1] = first_value / wsum; + weight_sum = wsum; + } else + start_position = prev_calculated - 1; + // Main loop. + for (i = start_position; i < rates_total; i++) { + double sum = 0; + + for (int j = 0; j < period; j++) sum += (period - j) * price[i - j]; + + buffer[i] = sum / weight_sum; + } + // Restore as_series flags. + ArraySetAsSeries(price, as_series_price); + ArraySetAsSeries(buffer, as_series_buffer); + return (rates_total); + } + static int SmoothedMAOnBuffer(const int rates_total, const int prev_calculated, const int begin, const int period, ValueStorage &price, ValueStorage &buffer) { int i; @@ -775,4 +810,26 @@ class Indi_MA : public Indicator { iparams.applied_array = _applied_price; } }; + +#ifdef __MQL4__ +// MQL4 version of the method doesn't have last parameter. +int LinearWeightedMAOnBuffer(const int rates_total, const int prev_calculated, const int begin, const int period, + const double &price[], double &buffer[]) { + int _weight_sum; + return Indi_MA::LinearWeightedMAOnBuffer(rates_total, prev_calculated, begin, period, price, buffer, _weight_sum); +} +#else // !__MQL__4 +// Defines global functions (for MQL4 backward compability). +double iMA(string _symbol, int _tf, int _ma_period, int _ma_shift, int _ma_method, int _ap, int _shift) { + ResetLastError(); + return Indi_MA::iMA(_symbol, (ENUM_TIMEFRAMES)_tf, _ma_period, _ma_shift, (ENUM_MA_METHOD)_ma_method, + (ENUM_APPLIED_PRICE)_ap, _shift); +} +double iMAOnArray(double &_arr[], int _total, int _period, int _ma_shift, int _ma_method, int _abs_shift, + IndicatorCalculateCache *_cache = NULL) { + ResetLastError(); + return Indi_MA::iMAOnArray(_arr, _total, _period, _ma_shift, _ma_method, _abs_shift, _cache); +} +#endif // __MQL4__ + #endif // INDI_MA_MQH diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 6d6d54496..1ecdb366c 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -109,13 +109,9 @@ class Indi_Momentum : public Indicator { double _indi_value_buffer[]; IndicatorDataEntry _entry(_indi.GetModeCount()); - _period += 1; - ArrayResize(_indi_value_buffer, _period); for (int i = 0; i < (int)_period; i++) { - // Print(": Getting data from ", _indi PTR_DEREF GetFullName(), " from shift ", i); - // Getting value from single, selected buffer. _indi_value_buffer[i] = _indi[i].GetValue(_mode); } @@ -150,8 +146,9 @@ class Indi_Momentum : public Indicator { // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), iparams.shift + ToRelShift(_abs_shift)); - if (idparams.is_draw) { - draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); + if (idparams.IsDrawing()) { + // draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, + // 1); } break; case IDATA_ICUSTOM: @@ -164,8 +161,9 @@ class Indi_Momentum : public Indicator { // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_Momentum::iMomentumOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), iparams.shift + ToRelShift(_abs_shift)); - if (idparams.is_draw) { - draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, 1); + if (idparams.IsDrawing()) { + // draw.DrawLineTo(StringFormat("%s", GetName()), GetBarTime(iparams.shift + ToRelShift(_abs_shift)), _value, + // 1); } break; } diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index bdfe6dea4..8b1d6baf1 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -100,15 +100,17 @@ class Indi_PriceFeeder : public Indicator { /** * Called when new tick is retrieved from attached data source. */ - void OnTick(int _global_tick_index) override { - Indicator::OnTick(_global_tick_index); + bool OnTick(int _global_tick_index) override { + bool _result = Indicator::OnTick(_global_tick_index); - if (idparams.is_draw) { + if (idparams.IsDrawing()) { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); IndicatorDataEntry _entry = GetEntry(0); for (int i = 0; i < _max_modes; ++i) { - draw.DrawLineTo(GetName() + "_" + IntegerToString(i), GetBarTime(0), _entry.values[i].GetDbl()); + // draw.DrawLineTo(GetName() + "_" + IntegerToString(i), GetBarTime(0), _entry.values[i].GetDbl()); } } + + return _result; } }; diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 088467c26..1bc0dc454 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -23,42 +23,22 @@ // Includes. #include "../DictStruct.mqh" #include "../Indicator/Indicator.h" -#include "Indi_Bands.mqh" -#include "Indi_CCI.mqh" -#include "Indi_Envelopes.mqh" -#include "Indi_MA.mqh" -#include "Indi_Momentum.mqh" -#include "Indi_StdDev.mqh" #include "Price/Indi_Price.mqh" -#ifndef __MQL4__ -// Defines global functions (for MQL4 backward compability). -double iRSI(string _symbol, int _tf, int _period, int _ap, int _shift) { - ResetLastError(); - return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); -} -double iRSIOnArray(double &_arr[], int _total, int _period, int _abs_shift) { - ResetLastError(); - return Indi_RSI::iRSIOnArray(_arr, _total, _period, _abs_shift); -} -#endif - // Structs. struct IndiRSIParams : IndicatorParams { - protected: int period; ENUM_APPLIED_PRICE applied_price; - public: IndiRSIParams(int _period = 14, ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0) - : applied_price(_ap), IndicatorParams(INDI_RSI) { + : IndicatorParams(INDI_RSI), applied_price(_ap) { shift = _shift; SetCustomIndicatorName("Examples\\RSI"); SetPeriod(_period); }; IndiRSIParams(IndiRSIParams &_params) { THIS_REF = _params; }; // Getters. - ENUM_APPLIED_PRICE GetAppliedPrice() override { return applied_price; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return applied_price; } int GetPeriod() { return period; } // Setters. void SetPeriod(int _period) { period = _period; } @@ -79,6 +59,11 @@ struct IndiRSIParams : IndicatorParams { struct RSIGainLossData { double avg_gain; double avg_loss; + // Default constructor. + RSIGainLossData() {} + + // Copy constructor. + RSIGainLossData(const RSIGainLossData &r) : avg_gain(r.avg_gain), avg_loss(r.avg_loss) {} }; /** @@ -127,8 +112,15 @@ class Indi_RSI : public Indicator { ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, IndicatorData *_obj = NULL) { #ifdef __MQL4__ return ::iRSI(_symbol, _tf, _period, _applied_price, _shift); -#else // __MQL5__ +#else +#ifdef __MQL5__ INDICATOR_BUILTIN_CALL_AND_RETURN(::iRSI(_symbol, _tf, _period, _applied_price), 0, _shift); +#else + RUNTIME_ERROR( + "In C++ Indi_RSI::iRSI() method couldn't be used directly. Please use an On-Indicator mode and attach " + "indicator via Platform::Add/AddWithDefaultBindings()."); + return DBL_MAX; +#endif #endif } @@ -141,13 +133,14 @@ class Indi_RSI : public Indicator { ENUM_APPLIED_PRICE _applied_price = PRICE_CLOSE, int _shift = 0, Indi_RSI *_obj = NULL) { int i; - double indi_values[]; + ARRAY(double, indi_values); ArrayResize(indi_values, _period); double result; for (i = _shift; i < (int)_shift + (int)_period; i++) { - indi_values[_shift + _period - (i - _shift) - 1] = _indi[i][_obj.GetParams().indi_mode]; + indi_values[_shift + _period - (i - _shift) - 1] = + _indi PTR_DEREF GetSpecificAppliedPriceValueStorage(_applied_price) PTR_DEREF Fetch(i); } result = iRSIOnArray(indi_values, 0, _period - 1, 0); @@ -160,7 +153,7 @@ class Indi_RSI : public Indicator { * * @see https://school.stockcharts.com/doku.php?id=technical_indicators:relative_strength_index_rsi * - * Reson behind iRSI with SSMA and not just iRSIOnArray() (from above website): + * Reason behind iRSI with SMMA and not just iRSIOnArray() (from above website): * * "Taking the prior value plus the current value is a smoothing technique * similar to that used in calculating an exponential moving average. This @@ -183,7 +176,7 @@ class Indi_RSI : public Indicator { } int i; - double indi_values[]; + ARRAY(double, indi_values); ArrayResize(indi_values, _period); double result; @@ -239,7 +232,7 @@ class Indi_RSI : public Indicator { new_data.avg_gain = (last_data.avg_gain * (_period - 1) + curr_gain) / _period; new_data.avg_loss = (last_data.avg_loss * (_period - 1) + curr_loss) / _period; - _target.aux_data.Set(_bar_time_curr, new_data); + _target PTR_DEREF aux_data.Set(_bar_time_curr, new_data); if (new_data.avg_loss == 0.0) { // @fixme Why 0 loss? @@ -256,7 +249,7 @@ class Indi_RSI : public Indicator { /** * Calculates RSI on the array of values. */ - static double iRSIOnArray(double &array[], int total, int period, int shift) { + static double iRSIOnArray(ARRAY_REF(double, array), int total, int period, int shift) { #ifdef __MQL4__ return ::iRSIOnArray(array, total, period, shift); #else @@ -309,9 +302,13 @@ class Indi_RSI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override { +#ifdef __debug_indicator__ + Print("Indi_RSI::GetEntryValue(mode = ", _mode, ", abs_shift = ", _abs_shift, ")"); +#endif + double _value = EMPTY_VALUE; - double _res[]; + ARRAY(double, _res); switch (Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE))) { case IDATA_BUILTIN: _value = Indi_RSI::iRSI(GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), @@ -328,37 +325,49 @@ class Indi_RSI : public Indicator { _value = Indi_RSI::iRSIOnIndicator(THIS_PTR, GetDataSource(), GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), ToRelShift(_abs_shift)); break; + default: + RUNTIME_ERROR("Invalid indicator IDATA_* type!"); } return _value; } +}; - /** - * Provides built-in indicators whose can be used as data source. - */ - virtual IndicatorData *FetchDataSource(ENUM_INDICATOR_TYPE _id) { - if (_id == INDI_BANDS) { - IndiBandsParams bands_params; - return new Indi_Bands(bands_params); - } else if (_id == INDI_CCI) { - IndiCCIParams cci_params; - return new Indi_CCI(cci_params); - } else if (_id == INDI_ENVELOPES) { - IndiEnvelopesParams env_params; - return new Indi_Envelopes(env_params); - } else if (_id == INDI_MOMENTUM) { - IndiMomentumParams mom_params; - return new Indi_Momentum(mom_params); - } else if (_id == INDI_MA) { - IndiMAParams ma_params; - return new Indi_MA(ma_params); - } else if (_id == INDI_RSI) { - IndiRSIParams _rsi_params; - return new Indi_RSI(_rsi_params); - } else if (_id == INDI_STDDEV) { - IndiStdDevParams stddev_params; - return new Indi_StdDev(stddev_params); - } +#ifndef __MQL4__ +// Defines global functions (for MQL4 backward compability). +double iRSI(string _symbol, int _tf, int _period, int _ap, int _shift) { + ResetLastError(); + return Indi_RSI::iRSI(_symbol, (ENUM_TIMEFRAMES)_tf, _period, (ENUM_APPLIED_PRICE)_ap, _shift); +} +double iRSIOnArray(ARRAY_REF(double, _arr), int _total, int _period, int _abs_shift) { + ResetLastError(); + return Indi_RSI::iRSIOnArray(_arr, _total, _period, _abs_shift); +} +#endif - return IndicatorData::FetchDataSource(_id); - } -}; +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(Indi_RSI_Params) { + emscripten::value_object("indicators.RSIParams") + .field("period", &IndiRSIParams::period) + .field("appliedPrice", &IndiRSIParams::applied_price) + // Inherited fields: + .field("shift", &IndiRSIParams::shift); +} + +EMSCRIPTEN_BINDINGS(Indi_RSIBase) { + emscripten::class_, emscripten::base>("Indi_RSIBase"); +} + +EMSCRIPTEN_BINDINGS(Indi_RSI) { + emscripten::class_>>("indicators.RSI") + .smart_ptr>("Ref") + .constructor(&make_ref) + .constructor(&make_ref) + .constructor(&make_ref, + emscripten::allow_raw_pointer>()) + .constructor(&make_ref, + emscripten::allow_raw_pointer>()); +} + +#endif diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 089449b0e..2c3800559 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -199,7 +199,8 @@ class Indi_StdDev : public Indicator { Indi_PriceFeeder *_indi_price_feeder; if (!ObjectsCache::TryGet(_key, _indi_price_feeder)) { IndiPriceFeederParams _params(); - _indi_price_feeder = ObjectsCache::Set(_key, new Indi_PriceFeeder(_params)); + IndicatorData *_indi_pf = new Indi_PriceFeeder(_params); + _indi_price_feeder = ObjectsCache::Set(_key, _indi_pf); } // Filling reused price feeder. diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index ba563219b..c33d5353a 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -404,7 +404,9 @@ class Indi_ZigZag : public Indicator { /** * Checks if indicator entry values are valid. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return !_entry.HasValue(EMPTY_VALUE); } + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return _entry.values[0].Get() != DBL_MAX && _entry.values[0].Get() != EMPTY_VALUE; + } /* Getters */ diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index f764a2522..537ca191d 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -61,13 +61,13 @@ class Indi_ZigZagColor : public Indicator { IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) : Indicator( _p, IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), - _indi_src){}; + _indi_src) {} Indi_ZigZagColor(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) : Indicator( IndiZigZagColorParams(), IndicatorDataParams::GetInstance(3, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE_ON_SIGNAL, _indi_src_mode), - _indi_src){}; + _indi_src) {} /** * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. */ @@ -321,7 +321,9 @@ class Indi_ZigZagColor : public Indicator { /** * Checks if indicator entry values are valid. */ - virtual bool IsValidEntry(IndicatorDataEntry &_entry) { return _entry.values[0].Get() != EMPTY_VALUE; } + virtual bool IsValidEntry(IndicatorDataEntry &_entry) { + return _entry.values[0].Get() != DBL_MAX && _entry.values[0].Get() != EMPTY_VALUE; + } /* Getters */ diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index 9eb3b6713..6edf53e1f 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -30,12 +30,12 @@ struct PriceIndiParams : IndicatorParams { ENUM_APPLIED_PRICE ap; // Struct constructor. - PriceIndiParams(ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) : ap(_ap), IndicatorParams(INDI_PRICE) { + PriceIndiParams(ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL, int _shift = 0) : IndicatorParams(INDI_PRICE), ap(_ap) { SetShift(_shift); }; - PriceIndiParams(PriceIndiParams &_params) { THIS_REF = _params; }; + PriceIndiParams(PriceIndiParams &_params) : IndicatorParams() { THIS_REF = _params; }; // Getters. - ENUM_APPLIED_PRICE GetAppliedPrice() override { return ap; } + ENUM_APPLIED_PRICE GetAppliedPrice() { return ap; } // Setters. void SetAppliedPrice(ENUM_APPLIED_PRICE _ap) { ap = _ap; } }; @@ -60,7 +60,7 @@ class Indi_Price : public Indicator { /** * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. */ - virtual unsigned int GetSuitableDataSourceTypes() { + unsigned int GetSuitableDataSourceTypes() override { // We can work only with Candle-based indicator attached. return INDI_SUITABLE_DS_TYPE_CANDLE; } @@ -111,21 +111,21 @@ class Indi_Price : public Indicator { case INDI_VS_TYPE_PRICE_ASK: // Tick. case INDI_VS_TYPE_PRICE_BID: // Tick. return GetPlatformPrices(GetSymbol(), iparams.GetAppliedPrice(), GetTf(), iparams.GetShift()) - .GetValueStorage(0); + PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_OPEN: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_OPEN, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_OPEN, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_HIGH: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_HIGH, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_HIGH, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_LOW: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_LOW, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_LOW, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_CLOSE: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_CLOSE, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_CLOSE, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_MEDIAN: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_MEDIAN, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_MEDIAN, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_TYPICAL: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_TYPICAL, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_TYPICAL, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); case INDI_VS_TYPE_PRICE_WEIGHTED: // Candle. - return GetPlatformPrices(GetSymbol(), PRICE_WEIGHTED, GetTf(), iparams.GetShift()).GetValueStorage(0); + return GetPlatformPrices(GetSymbol(), PRICE_WEIGHTED, GetTf(), iparams.GetShift()) PTR_DEREF GetValueStorage(0); default: // Trying in parent class. return Indicator::GetSpecificValueStorage(_type); diff --git a/Indicators/Tf/Indi_TfMt.h b/Indicators/Tf/Indi_TfMt.h new file mode 100644 index 000000000..ae2f16811 --- /dev/null +++ b/Indicators/Tf/Indi_TfMt.h @@ -0,0 +1,100 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, 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 + * Tf-based candle indicator for MT. + */ + +#ifndef __MQL__ + // Allows the preprocessor to include a header file when it is needed. + #pragma once +#endif + +// Includes. +#include "../../Indicator/IndicatorCandle.h" +#include "Indi_TfMt.provider.h" + +// Params for MT Tf-based candle indicator. +struct Indi_TfMtParams : IndicatorTfParams { + Indi_TfMtParams(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTfParams("IndicatorTf", _tf) {} +}; + +/** + * Tf-based candle indicator for MT. + */ +class Indi_TfMt : public IndicatorCandle> { + protected: + // Time-frame used to create candles. + ENUM_TIMEFRAMES tf; + + /* Protected methods */ + + /** + * Initialize class. + * + * Called on constructor. + */ + void Init() { history.SetItemProvider(new ItemsHistoryTfMtCandleProvider(THIS_PTR)); } + + public: + /* Special methods */ + + /** + * Class constructor with timeframe enum. + */ + Indi_TfMt(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + tf = _tf; + Init(); + } + + /** + * Class constructor with timeframe index. + */ + Indi_TfMt(ENUM_TIMEFRAMES_INDEX _tfi = 0) { + tf = ChartTf::IndexToTf(_tfi); + Init(); + } + + /** + * Class constructor with parameters. + */ + Indi_TfMt(Indi_TfMtParams& _icparams, const IndicatorDataParams& _idparams) { Init(); } + + /** + * Gets indicator's time-frame. + */ + ENUM_TIMEFRAMES GetTf() override { return tf; } + + /** + * Returns current tick index (incremented every OnTick()). + */ + int GetTickIndex() override { return history.GetItemProvider() PTR_DEREF GetTickIndex(); } + + /** + * Returns the number of bars on the chart decremented by iparams.shift. + */ + int GetBars() override { + // Will return number of bars prepended and appended to the history, + // even if those bars were cleaned up because of history's candle limit. + return ::Bars(GetSymbol(), GetTf()) - iparams.shift; + } +}; diff --git a/Indicators/Tf/Indi_TfMt.provider.h b/Indicators/Tf/Indi_TfMt.provider.h new file mode 100644 index 000000000..55e9cf0e3 --- /dev/null +++ b/Indicators/Tf/Indi_TfMt.provider.h @@ -0,0 +1,177 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __MQL__ + // Allows the preprocessor to include a header file when it is needed. + #pragma once +#endif + +/** + * Candle grouping and regeneration for time-frame based candles. + */ +template +class ItemsHistoryTfMtCandleProvider : public ItemsHistoryCandleProvider { + // Pointer to Tf Indicator, e.g., Indi_TfMt or IndicatorTfDummy. Used to fetch data by fixed timeframe candles. + IndicatorData* indi; + + // Current tick index. Effectively a number of ticks generated by attached Tick indicator. + int tick_index; + + public: + /** + * Constructor. + */ + ItemsHistoryTfMtCandleProvider(IndicatorData* _indi_tf) : indi(_indi_tf), tick_index(0) {} + + /** + * Called when new tick was emitted from IndicatorTick-based source. + */ + virtual void OnTick(ItemsHistory, ItemsHistoryTfMtCandleProvider>* _history, long _time_ms, + float _ask, float _bid) { + ++tick_index; + + // Seconds per candle calculated from TF. + int _spc = (int)ChartTf::TfToSeconds(indi PTR_DEREF GetTf()); + + Print("Indi_TfMt's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | TIME_SECONDS), + ", ", _ask, ", ", _bid); + + // We know that tick's timestamp will be ahead of the last tick and thus + // inside or ahead of the last created candle. In order to retrieve last + // valid candle, we need to use ItemsHistory::GetItemByShift(0) to check if + // we have to update last or create/append new candle. + CandleOCTOHLC _candle; + + // Will regenerate candles up to the last added candle ever. We have to + // call it, because some of the previous actions may have removed some of + // the recent candles. Note that OnTick() advances its _time_ms in + // ascending order, so all we need to most recent history. + // + // Note that EnsureShiftExists() may return false when there never been any + // candle added. + _history PTR_DEREF EnsureShiftExists(0); + + if (_history PTR_DEREF TryGetItemByShift(0, _candle, false) && _candle.ContainsTimeMs(_time_ms)) { + // Time given fits in the last added candle's time-frame, updating the candle with given price. + _candle.Update(_time_ms, _bid); + + // Storing candle in the history. + _history PTR_DEREF Update(_candle, _history PTR_DEREF GetShiftIndex(0)); + } else { + CandleOCTOHLC _candle_tmp; + + // We don't want to regenerate history, because at the start there will bo no candle however. + if (_history PTR_DEREF TryGetItemByShift(0, _candle_tmp, false)) { + // Print("Completed candle: ", _candle_tmp.ToString()); + // Print("Real candle: ", iOpen(NULL, Period(), 1), " ", iHigh(NULL, Period(), 1), " ", + // iLow(NULL, Period(), 1), " ", ChartStatic::iClose(NULL, (ENUM_TIMEFRAMES)Period(), 1)); + // Print("--"); + } + + // Either there is no candle at shift 0 or given time doesn't fit in the #0 candle's time-frame. + _candle.Init(GetCandleTimeFromTimeMs(_time_ms, _spc), _spc, _time_ms, _bid); + + // Adding candle as the most recent item in the history. It will now become the candle at shift 0. + _history PTR_DEREF Append(_candle); + } + } + + /** + * Returns current tick index. Effectively a number of ticks generated by + * attached IndicatorTick. + */ + int GetTickIndex() { return tick_index; } + + /** + * Returns start time of the candle (the place it's on the chart) for the given tick's time in milliseconds. + */ + int GetCandleTimeFromTimeMs(long _time_ms, int _length_in_secs) { + return (int)((_time_ms - _time_ms % ((long)_length_in_secs * 1000)) / 1000); + } + + /** + * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we + * want previous or next items from selected starting point. Should return false if retrieving items by this method + * is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryTfMtCandleProvider>* _history, long _from_time_ms, + ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + return false; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory, ItemsHistoryTfMtCandleProvider>* _history, int _start_index, + int _end_index, ARRAY_REF(CandleOCTOHLC, _out_arr)) { + Print("Indi_TfMt::GetItems()"); + + // Converting absolute indices into MT shifts. + int _num_bars = _end_index - _start_index + 1; + // Current candle index. Could be 0 if no candles have been added or if there is only one candle added so far. + int _current_index = _history PTR_DEREF GetCurrentIndex(); + int _start_shift = _current_index - _start_index; + int _end_shift = _current_index - _end_index; + + Print("Indi_TfMt::GetItems(): Will fetch ", _num_bars, " bars between shift ", _start_shift, " and ", _end_shift); + + // Seconds per candle calculated from TF. + int _spc = (int)ChartTf::TfToSeconds(indi PTR_DEREF GetTf()); + + // Static, reusable array of rates. + static ARRAY(MqlRates, _rates); + int _count = _end_index - _start_index + 1; + ArrayResize(_rates, _count); + + Print("CopyRates(", indi PTR_DEREF GetSymbol(), ", ", EnumToString(indi PTR_DEREF GetTf()), ", ", _start_index, + ", ", _count, ", ...)"); + + // As GetItems() will only be called for missing candles, we can just ask MT for OHLCs and return them. + // Note that we have to specify most recent shift and count of history ticks to return. + // Also note that CopyRates() will insert oldest candle at the start of _rates array, so we have to inverse items in + // the array in order all candles be from most recent to the oldest ones. + int _num_copied = CopyRates(indi PTR_DEREF GetSymbol(), indi PTR_DEREF GetTf(), _end_shift, _count, _rates); + ArrayResize(_out_arr, _num_copied); + + // Acknowledging indicator that we will emit _num_copied number of candles. + _history PTR_DEREF GetIndicator() + PTR_DEREF OnDataSourceWillEmitEntries(INDI_EMITTED_ENTRY_TYPE_CANDLE, _num_copied); + + for (int i = 0; i < _num_copied; ++i) { + MqlRates _rate = _rates[i]; + int _start_secs = (int)(long)_rate.time; + CandleOCTOHLC _candle(_rate.open, _rate.high, _rate.low, _rate.close, _start_secs, _spc, + (long)_start_secs * 1000, long(_start_secs + _spc) * 1000 - 1, (int)_rate.tick_volume); + // Reversing output, so most recent candle will be at start. + _out_arr[_num_copied - i - 1] = _candle; + } + + ArrayResize(_rates, 0); + return true; + } + + /** + * Returns information about item provider. + */ + string const ToString() override { return "Indi_TfMt candle provider on " + indi PTR_DEREF GetFullName(); } +}; diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 98e33a884..0bd2f29a9 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -127,60 +127,11 @@ class Indi_TickMt : public IndicatorTick, _out_ticks)) { + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { ArrayResize(_out_ticks, 0); -#ifdef __MQL4__ - // Searching from current bar to older ones. - int _shift; - - if (_to_ms <= _cache_fetch_history_shift_to_ms) { - _shift = _cache_fetch_history_shift_shift; - } else { - _shift = 0; - } - - string _symbol = GetSymbol(); - - while (true) { - double _time = (double)iTime(_symbol, PERIOD_M1, _shift); - - if (_time == 0) { - // Invalid time. - break; - } - - long _time_ms = (long)_time * 1000; - - if (_time_ms > _to_ms) { - // No yet get into valid time range. - ++_shift; - continue; - } - - if (_time_ms < _from_ms) { - // No more ticks. - break; - } - - TickTAB _tick_o(_time_ms, iOpen(_Symbol, PERIOD_M1, _shift)); - TickTAB _tick_h(_time_ms, iHigh(_Symbol, PERIOD_M1, _shift)); - TickTAB _tick_l(_time_ms, iLow(_Symbol, PERIOD_M1, _shift)); - TickTAB _tick_c(_time_ms, iClose(_Symbol, PERIOD_M1, _shift)); - ArrayPushObject(_out_ticks, _tick_o); - ArrayPushObject(_out_ticks, _tick_h); - ArrayPushObject(_out_ticks, _tick_l); - ArrayPushObject(_out_ticks, _tick_c); - ++_shift; - } - - if (_shift != -1) { - _cache_fetch_history_shift_to_ms = _to_ms; - _cache_fetch_history_shift_shift = _shift; - } - - return ArraySize(_out_ticks) != 0; -#else +#ifdef __MQL5__ + // In MQL5 we firstly try to fetch ticks by CopyTicksRange. static MqlTick _tmp_ticks[]; ArrayResize(_tmp_ticks, 0); @@ -196,20 +147,61 @@ class Indi_TickMt : public IndicatorTick _tick(_tmp_ticks[i]); -#ifdef __debug_verbose__ + #ifdef __debug_verbose__ Print("Fetched tick at ", TimeToString(_tmp_ticks[i].time, TIME_DATE | TIME_MINUTES | TIME_SECONDS), ": ", _tmp_ticks[i].ask, ", ", _tmp_ticks[i].bid); -#endif + #endif ArrayPushObject(_out_ticks, _tick); } - return true; + if (_num_copied > 0) { + return true; + } else { + // No ticks found. We will try to create ticks from historic OHLC values. + break; + } } } + #endif - // To many tries. Probably no ticks at the given range. - return false; + // In MQL4 or MQL5 (if there's no history returned by CopyTicksRange) we + // try to create and return OHLC ticks by calling iOpen/iHigh/iLow/iClose + // for each bar in history. Candle indicator will form candles from those + // 4 ticks per bar. + + string _symbol = GetSymbol(); + ARRAY(MqlRates, _rates); + + if (!CopyRates(_symbol, PERIOD_M1, (datetime)(int)(_from_ms / 1000), (datetime)(int)(_to_ms / 1000), _rates)) { + // Failure. + return false; + } + + if (ArraySize(_rates) == 0) { + // 0 ticks is OK. + return true; + } + + ArrayResize(_out_ticks, ArraySize(_rates) * 4); // Number of ticks * OHLC(4). + + int _tick_idx = 0; + + for (int i = 0; i < ArraySize(_rates); ++i) { + long _time_ms = (long)_rates[i].time * 1000; + // Note that we modify the time in order to simulate real open/close time. + TickTAB _tick_o(_time_ms + 0, _rates[i].open, _rates[i].open); + TickTAB _tick_h(_time_ms + 1, _rates[i].high, _rates[i].high); + TickTAB _tick_l(_time_ms + 2, _rates[i].low, _rates[i].low); + TickTAB _tick_c(_time_ms + 3, _rates[i].close, _rates[i].close); + + _out_ticks[_tick_idx++] = _tick_o; + _out_ticks[_tick_idx++] = _tick_h; + _out_ticks[_tick_idx++] = _tick_l; + _out_ticks[_tick_idx++] = _tick_c; + } + + return ArraySize(_out_ticks) != 0; } /** @@ -219,12 +211,7 @@ class Indi_TickMt : public IndicatorTick _tick(0, 0); IndicatorDataEntry _entry(TickToEntry(TimeCurrent(), _tick)); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); // Appending tick into the history. AppendEntry(_entry); return; } -#ifdef __debug_verbose__ + #ifdef __debug_verbose__ Print("CpyT: ", TimeToString(_tmp_ticks[0].time, TIME_DATE | TIME_MINUTES | TIME_SECONDS), " = ", _tmp_ticks[0].bid, " (", _tmp_ticks[0].time, ")"); Print("RlCl: ", TimeToString(::iTime(GetSymbol(), PERIOD_CURRENT, 0), TIME_DATE | TIME_MINUTES | TIME_SECONDS), " = ", ::iClose(GetSymbol(), PERIOD_CURRENT, 0)); -#endif + #endif double _ask = _tmp_ticks[0].ask; double _bid = _tmp_ticks[0].bid; + + #endif + + MqlTick _tick_data; + SymbolInfoTick(GetSymbol(), _tick_data); + + double _ask = _tick_data.ask; + double _bid = _tick_data.bid; + // long _time = _tmp_ticks[0].time; long _time = TimeCurrent(); #endif TickAB _tick(_ask, _bid); IndicatorDataEntry _entry(TickToEntry(_time, _tick)); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); // Appending tick into the history. AppendEntry(_entry); + + return _ask != WRONG_VALUE && _bid != WRONG_VALUE; } }; diff --git a/Indicators/Tick/Indi_TickProvider.h b/Indicators/Tick/Indi_TickProvider.h new file mode 100644 index 000000000..28e9b9f93 --- /dev/null +++ b/Indicators/Tick/Indi_TickProvider.h @@ -0,0 +1,181 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Tick-based indicator which you may feed with data. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../../Indicator/IndicatorTick.h" +#include "../../Indicator/IndicatorTick.provider.h" + +// Structs. +// Params for MT patform's tick-based indicator. +struct Indi_TickProviderParams : IndicatorParams { + Indi_TickProviderParams() : IndicatorParams(INDI_TICK_RANDOM) {} +}; + +// MT platform's tick-based indicator. +class Indi_TickProvider : public IndicatorTick> { + private: + int current_index; + ARRAY(TickTAB, buffer); + + public: + Indi_TickProvider(Indi_TickProviderParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : IndicatorTick(_p.symbol, _p, + IndicatorDataParams::GetInstance(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + Init(); + } + Indi_TickProvider(string _symbol = NULL_STRING, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0, string _name = "") + : IndicatorTick(_symbol, Indi_TickProviderParams(), + IndicatorDataParams(2, TYPE_DOUBLE, _idstype, IDATA_RANGE_PRICE, _indi_src_mode), _indi_src) { + Init(); + } + + /** + * Initializes the class. + */ + void Init() { + current_index = 0; + SetName("Indi_TickProvider"); + // Explicitly specifying built-in mode as in C++ default mode is On-Indicator. + idparams.Set(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE), IDATA_BUILTIN); + } + + string GetName() override { return "Indi_TickProvider"; } + + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + unsigned int GetSuitableDataSourceTypes() override { return INDI_SUITABLE_DS_TYPE_EXPECT_NONE; } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } + + /** + * Returns the indicator's struct entry for the given shift. + */ + IndicatorDataEntry GetEntry(int _index = 0) override { +#ifdef __debug_indicator__ + Print("Indi_TickProvider::GetEntry(index = ", _index, ")"); +#endif + + IndicatorDataEntry _default; + return _default; + } + + /** + * Fetches historic ticks for a given time range. + */ + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { +#ifdef __debug_indicator__ + Print("Indi_TickProvider::FetchHistoryByTimeRange(from_ms = ", _from_ms, ", to_ms = ", _to_ms, ")"); +#endif + // No history. + return false; + } + + /** + * Feeds ticks buffer with given array of new ticks. + */ + void Feed(ARRAY_REF(TickTAB, _ticks)) { + for (int i = 0; i < ArraySize(_ticks); ++i) { + ArrayPush(buffer, _ticks[i]); + } + } + + int BufferSize() { return ArraySize(buffer); } + + bool OnTick(int _global_tick_index) override { +#ifdef __debug_indicator__ + Print("Indi_TickProvider: Tick Index #", _global_tick_index); +#endif + + if (current_index >= ArraySize(buffer)) { +#ifdef __debug_indicator__ + Print("Indi_TickProvider: Tick Index #", _global_tick_index, " is beyond buffer size ", ArraySize(buffer), + ", so acknowledging that there are no more ticks."); +#endif + // No more ticks. + return false; + } + + TickTAB _tick = buffer[current_index++]; +#ifdef __debug_indicator__ + Print("Indi_TickProvider: OHLC: ", _tick.ToString()); +#endif + + IndicatorDataEntry _entry(TickToEntry(_tick.GetTimestamp(), _tick)); + EmitEntry(_entry); + // Appending tick into the history. + AppendEntry(_entry); + + return true; + } +}; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(Indi_TickProviderParams) { + emscripten::value_object("indicators.TickProviderParams") + .field("symbol", &Indi_TickProviderParams::symbol); +} + +EMSCRIPTEN_BINDINGS(Indi_TickProviderBaseBase) { + emscripten::class_, emscripten::base>("IndiTickProviderBaseBase") + .smart_ptr>>("Ref>"); +} + +EMSCRIPTEN_BINDINGS(Indi_TickProviderBase) { + emscripten::class_>, + emscripten::base>>("IndiTickProviderBas e") + .smart_ptr>>>( + "Ref>"); +} + +EMSCRIPTEN_BINDINGS(Indi_TickProvider) { + emscripten::class_< + Indi_TickProvider, + emscripten::base>>>( + "indicators.TickProvider") + .smart_ptr>("Ref") + .constructor(emscripten::optional_override([]() { return Ref(new Indi_TickProvider()); })) + .constructor(emscripten::optional_override( + [](Indi_TickProviderParams &_p) { return Ref(new Indi_TickProvider(_p)); })) + .function("BufferSize", &Indi_TickProvider::BufferSize) + .function("Feed", &Indi_TickProvider::Feed); +} + +#endif diff --git a/Indicators/Tick/Indi_TickRandom.mqh b/Indicators/Tick/Indi_TickRandom.mqh index c3b3a6253..f44c7713f 100644 --- a/Indicators/Tick/Indi_TickRandom.mqh +++ b/Indicators/Tick/Indi_TickRandom.mqh @@ -31,7 +31,6 @@ #endif // Includes. -#include "../../Chart.struct.static.h" #include "../../Indicator/IndicatorTick.h" #include "../../Indicator/IndicatorTick.provider.h" @@ -86,18 +85,20 @@ class Indi_TickRandom : public IndicatorTick, _out_ticks)) { + bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB, _out_ticks)) { // No history. return false; } - void OnTick(int _global_tick_index) override { + bool OnTick(int _global_tick_index) override { float _ask = 1.0f + (1.0f / 32767 * MathRand()); float _bid = 1.0f + (1.0f / 32767 * MathRand()); - TickAB _tick(, _bid); - IndicatorDataEntry _entry(TickToEntry(_time, _tick)); + TickAB _tick(_ask, _bid); + IndicatorDataEntry _entry(TickToEntry(TimeCurrent(), _tick)); EmitEntry(_entry); // Appending tick into the history. AppendEntry(_entry); + + return true; } }; diff --git a/Instances.h b/Instances.h index 53c2a7940..8f293a2bf 100644 --- a/Instances.h +++ b/Instances.h @@ -37,21 +37,18 @@ #include "Dict.mqh" #include "Util.h" -template +template class Instances { -public: - + public: static T* instances[]; - Instances(T* _self) { - Util::ArrayPush(instances, _self); - } + Instances(T* _self) { Util::ArrayPush(instances, _self); } ~Instances() { - //Util::ArrayRemove(instances, &this); + // Util::ArrayRemove(instances, &this); } }; -template +template T* Instances::instances[]; #endif // INSTANCES_MQH diff --git a/Log.mqh b/Log.mqh index b42f6de5c..13bc13fd4 100644 --- a/Log.mqh +++ b/Log.mqh @@ -32,8 +32,8 @@ class DictStruct; #include "Array.mqh" #include "DateTime.mqh" #include "DictStruct.mqh" +#include "File.mqh" #include "Object.mqh" -#include "Storage/Collection.mqh" // Define assert macros. // Alias for function and line macros combined together. @@ -59,12 +59,12 @@ class Log : public Object { ENUM_LOG_LEVEL log_level; string msg; }; - DictStruct> logs; - string filename; - ARRAY(log_entry, data); int last_entry; datetime last_flush; ENUM_LOG_LEVEL log_level; + string filename; + ARRAY(log_entry, data); + DictStruct> logs; public: /** @@ -76,8 +76,7 @@ class Log : public Object { /** * Class copy constructor. */ - Log(const Log &_log) : filename(_log.filename), last_entry(_log.last_entry), log_level(_log.log_level) { - } + Log(const Log &_log) : filename(_log.filename), last_entry(_log.last_entry), log_level(_log.log_level) {} /** * Class deconstructor. @@ -193,7 +192,8 @@ class Log : public Object { void Link(Log *_log) { PTR_ATTRIB(_log, SetLevel(log_level)); // Sets the same level as this instance. // @todo: Make sure we're not linking the same instance twice. - logs.Push(_log); + Ref _ref_log = _log; + logs.Push(_ref_log); } /** @@ -320,7 +320,6 @@ class Log : public Object { bool DeleteByTimestamp(datetime timestamp) { int _size = ArraySize(data); if (_size > 0) { - int offset = 0; for (int i = 0; i < _size; i++) { if (data[i].timestamp == timestamp) { Erase(data, i); @@ -345,4 +344,10 @@ bool Log::AddLastError(string prefix, long suffix) { return Add(V_ERROR, Terminal::GetLastErrorText(), prefix, StringFormat("%d", suffix)); } +// Specialization of StringToType() for enum. +void StringToType(string _value, ENUM_LOG_LEVEL &_out) { + // Maybe parse the string? + _out = V_NONE; +} + #endif diff --git a/Market.struct.h b/Market.struct.h index 8148f7e54..93f6e2e91 100644 --- a/Market.struct.h +++ b/Market.struct.h @@ -29,6 +29,7 @@ class Serializer; // Includes. +#include "DateTime.entry.h" #include "DateTime.struct.h" #include "Serializer/SerializerNode.enum.h" #include "Std.h" diff --git a/Math.extern.h b/Math.extern.h index 948bd1058..c04c4215a 100644 --- a/Math.extern.h +++ b/Math.extern.h @@ -22,28 +22,59 @@ // Define external global functions. #ifndef __MQL__ +#pragma once + +#include +#include + template -extern T MathAbs(T value); +T MathAbs(T value) { + return std::abs(value); +} template -extern T fabs(T value); +T fabs(T value) { + return std::abs(value); +} template -extern T pow(T base, T exponent); +T pow(T base, T exponent) { + return (T)std::pow(base, exponent); +} template -extern T MathPow(T base, T exponent); +T MathPow(T base, T exponent) { + return std::pow(base, exponent); +} template -extern T round(T value); +T round(T value) { + return std::round(value); +} template -extern T MathRound(T value); +T MathRound(T value) { + return std::round(value); +} template -extern T fmax(T value1, T value2); +T fmax(T value1, T value2) { + return std::max(value1, value2); +} template -extern T MathMax(T value1, T value2); +T MathMax(T value1, T value2) { + return std::max(value1, value2); +} template -extern T fmin(T value1, T value2); +T fmin(T value1, T value2) { + return std::min(value1, value2); +} template -extern T MathMin(T value1, T value2); +T MathMin(T value1, T value2) { + return std::min(value1, value2); +} template -extern T MathLog10(T value1); +T MathLog10(T value) { + return std::log10(value); +} template -extern T log10(T value); +T log10(T value) { + return std::log10(value); +} +int MathRand() { return std::rand() % 32768; } +// int rand() { return std::rand() % 32768; } #endif diff --git a/Matrix.mqh b/Matrix.mqh index 4aa2dce9e..63d8ad054 100644 --- a/Matrix.mqh +++ b/Matrix.mqh @@ -149,31 +149,31 @@ struct MatrixDimensionAccessor { /** * Constructor. */ - MatrixDimensionAccessor(Matrix* _ptr_matrix = NULL, MatrixDimension* _ptr_dimension = NULL, int _index = 0) + MatrixDimensionAccessor(Matrix* _ptr_matrix = nullptr, MatrixDimension* _ptr_dimension = nullptr, + int _index = 0) : ptr_matrix(_ptr_matrix), ptr_dimension(_ptr_dimension), index(_index) {} /** * Index operator. Returns container or value accessor. */ MatrixDimensionAccessor operator[](int _index) { - return MatrixDimensionAccessor(ptr_matrix, ptr_dimension.containers[index], _index); + return MatrixDimensionAccessor(ptr_matrix, ptr_dimension PTR_DEREF containers[index], _index); } /** * Returns target dimension type. */ - ENUM_MATRIX_DIMENSION_TYPE Type() const { return ptr_dimension.type; } + ENUM_MATRIX_DIMENSION_TYPE Type() const { return ptr_dimension PTR_DEREF type; } #define MATRIX_ACCESSOR_OPERATOR(OP) \ void operator OP(X _value) { \ - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { \ - Print("Error: Trying to use matrix", ptr_matrix.Repr(), \ + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { \ + Print("Error: Trying to use matrix", ptr_matrix PTR_DEREF Repr(), \ "'s value operator " #OP " in a dimension which doesn't contain values!"); \ - DebugBreak(); \ return; \ } \ \ - ptr_dimension.values[index] OP _value; \ + ptr_dimension PTR_DEREF values[index] OP _value; \ } MATRIX_ACCESSOR_OPERATOR(+=) @@ -185,26 +185,26 @@ struct MatrixDimensionAccessor { * Assignment operator. Sets value for this dimensions. */ void operator=(X _value) { - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { - Print("Error: Trying to set matrix", ptr_matrix.Repr(), "'s value in a dimension which doesn't contain values!"); - DebugBreak(); + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { + Print("Error: Trying to set matrix", ptr_matrix PTR_DEREF Repr(), + "'s value in a dimension which doesn't contain values!"); return; } - ptr_dimension.values[index] = _value; + ptr_dimension PTR_DEREF values[index] = _value; } /** * Returns value pointed by this accessor. */ X Val() { - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { - Print("Error: Trying to get value from matrix", ptr_matrix.Repr(), "'s dimension which doesn't contain values!"); - DebugBreak(); + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { + Print("Error: Trying to get value from matrix", ptr_matrix PTR_DEREF Repr(), + "'s dimension which doesn't contain values!"); return (X)EMPTY_VALUE; } - return ptr_dimension.values[index]; + return ptr_dimension PTR_DEREF values[index]; } /** @@ -212,17 +212,17 @@ struct MatrixDimensionAccessor { * dimension length. */ X ValOrZero() { - if (ptr_dimension.type != MATRIX_DIMENSION_TYPE_VALUES) { - Print("Error: Trying to get value from matrix", ptr_matrix.Repr(), "'s dimension which doesn't contain values!"); - DebugBreak(); + if (ptr_dimension PTR_DEREF type != MATRIX_DIMENSION_TYPE_VALUES) { + Print("Error: Trying to get value from matrix", ptr_matrix PTR_DEREF Repr(), + "'s dimension which doesn't contain values!"); return (X)EMPTY_VALUE; } - int _num_values = ArraySize(ptr_dimension.values); + int _num_values = ArraySize(ptr_dimension PTR_DEREF values); if (_num_values == 0 || index >= _num_values) return (X)0; - return ptr_dimension.values[index]; + return ptr_dimension PTR_DEREF values[index]; } }; @@ -235,13 +235,13 @@ class MatrixDimension { ENUM_MATRIX_DIMENSION_TYPE type; // Values array if type is "Values". - X values[]; + ARRAY(X, values); // Physical position of the dimension in the matrix. int position[MATRIX_DIMENSIONS - 1]; // Containers array if type is "Containers" - MatrixDimension* containers[]; + ARRAY(MatrixDimension*, containers); /** * Constructor. @@ -265,13 +265,13 @@ class MatrixDimension { int i; if (type == MATRIX_DIMENSION_TYPE_CONTAINERS) { - ArrayResize(_clone.containers, ArraySize(containers)); + ArrayResize(_clone PTR_DEREF containers, ArraySize(containers)); for (i = 0; i < ArraySize(containers); ++i) { - _clone.containers[i] = containers[i].Clone(); + _clone PTR_DEREF containers[i] = containers[i].Clone(); } } else { - ArrayCopy(_clone.values, values); + ArrayCopy(_clone PTR_DEREF values, values); } return _clone; @@ -298,7 +298,7 @@ class MatrixDimension { /** * Sets physical position of the dimension in the matrix. */ - void SetPosition(int& _position[], int _level) { + void SetPosition(ARRAY_REF(int, _position), int _level) { for (int i = 0; i < ArraySize(_position); ++i) { position[i] = i < _level ? _position[i] : -1; } @@ -478,6 +478,9 @@ class MatrixDimension { ArrayFill(values, _last_size, _num_items - _last_size, (X)0); } break; + + default: + RUNTIME_ERROR("We shouldn't be here!"); } type = _type; @@ -488,27 +491,27 @@ class MatrixDimension { * * @todo Allow of resizing containers instead of freeing them firstly. */ - static MatrixDimension* SetDimensions(MatrixDimension* _ptr_parent_dimension, int& _dimensions[], int index, - int& _current_position[]) { + static MatrixDimension* SetDimensions(MatrixDimension* _ptr_parent_dimension, ARRAY_REF(int, _dimensions), + int index, ARRAY_REF(int, _current_position)) { if (_ptr_parent_dimension == NULL) _ptr_parent_dimension = new MatrixDimension(); if (index == 0 && _dimensions[0] == 0) { // Matrix without any dimensions. - _ptr_parent_dimension.type = MATRIX_DIMENSION_TYPE_VALUES; + _ptr_parent_dimension PTR_DEREF type = MATRIX_DIMENSION_TYPE_VALUES; } - _ptr_parent_dimension.SetPosition(_current_position, index); + _ptr_parent_dimension PTR_DEREF SetPosition(_current_position, index); int i; if (_dimensions[index + 1] == 0) { - _ptr_parent_dimension.Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_VALUES); + _ptr_parent_dimension PTR_DEREF Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_VALUES); } else { - _ptr_parent_dimension.Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_CONTAINERS); + _ptr_parent_dimension PTR_DEREF Resize(_dimensions[index], MATRIX_DIMENSION_TYPE_CONTAINERS); for (i = 0; i < _dimensions[index]; ++i) { - _ptr_parent_dimension.containers[i] = - SetDimensions(_ptr_parent_dimension.containers[i], _dimensions, index + 1, _current_position); + _ptr_parent_dimension PTR_DEREF containers[i] = + SetDimensions(_ptr_parent_dimension PTR_DEREF containers[i], _dimensions, index + 1, _current_position); ++_current_position[index]; } @@ -521,7 +524,6 @@ class MatrixDimension { * Executes operation on a single value. */ X OpSingle(ENUM_MATRIX_OPERATION _op, X _src = (X)0, X _arg1 = (X)0, X _arg2 = (X)0, X _arg3 = (X)0) { - int _pos = 0; switch (_op) { case MATRIX_OPERATION_ABS: return MathAbs(_src); @@ -648,9 +650,9 @@ class MatrixDimension { } /** - * Extracts dimensions' values to the given array. Used internally. + * Extracts dimensions's values to the given array. Used internally. */ - void FillArray(X& array[], int& offset) { + void FillArray(ARRAY_REF(X, array), int& offset) { int i; if (type == MATRIX_DIMENSION_TYPE_CONTAINERS) { for (i = 0; i < ArraySize(containers); ++i) { @@ -663,7 +665,7 @@ class MatrixDimension { } } - void FromArray(X& _array[], int& offset) { + void FromArray(ARRAY_REF(X, _array), int& offset) { int i; switch (type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: @@ -684,20 +686,19 @@ class MatrixDimension { */ void Op(MatrixDimension* _r, ENUM_MATRIX_OPERATION _op, X _arg1 = (X)0, int _only_value_index = -1) { int i; - bool r_is_single = ArraySize(_r.values) == 1; - if (_r.type == MATRIX_DIMENSION_TYPE_VALUES && ArraySize(_r.values) == 1) { + if (_r PTR_DEREF type == MATRIX_DIMENSION_TYPE_VALUES && ArraySize(_r PTR_DEREF values) == 1) { // There is only one value in the right container, we will use that value for all operations. _only_value_index = 0; } switch (type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: - switch (_r.type) { + switch (_r PTR_DEREF type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: // Both dimensions have containers. for (i = 0; i < ArraySize(containers); ++i) { - containers[i].Op(_r.containers[ArraySize(_r.containers) == 1 ? 0 : i], _op, _arg1); + containers[i].Op(_r PTR_DEREF containers[ArraySize(_r PTR_DEREF containers) == 1 ? 0 : i], _op, _arg1); } break; case MATRIX_DIMENSION_TYPE_VALUES: @@ -711,21 +712,22 @@ class MatrixDimension { } break; case MATRIX_DIMENSION_TYPE_VALUES: - switch (_r.type) { + switch (_r PTR_DEREF type) { case MATRIX_DIMENSION_TYPE_CONTAINERS: // Right dimension have containers. - if (ArraySize(_r.containers) != 1) { + if (ArraySize(_r PTR_DEREF containers) != 1) { Alert("Right container must have exactly one element!"); return; } - Op(_r.containers[0], _op, _arg1); + Op(_r PTR_DEREF containers[0], _op, _arg1); break; case MATRIX_DIMENSION_TYPE_VALUES: // Left and right dimensions have values or we use single right value. for (i = 0; i < ArraySize(values); ++i) { - values[i] = OpSingle(_op, values[i], _r.values[_only_value_index != -1 ? _only_value_index : i]); + values[i] = + OpSingle(_op, values[i], _r PTR_DEREF values[_only_value_index != -1 ? _only_value_index : i]); } break; @@ -1006,7 +1008,7 @@ class Matrix { * Matrix initializer. */ void Initialize(MatrixDimension* _dimension) { - if (ptr_first_dimension != NULL) delete ptr_first_dimension; + if (ptr_first_dimension != nullptr) delete ptr_first_dimension; ptr_first_dimension = _dimension; // Calculating dimensions. @@ -1019,11 +1021,11 @@ class Matrix { for (i = 0; i < MATRIX_DIMENSIONS; ++i) { if (_dimension == NULL) break; - if (_dimension.type == MATRIX_DIMENSION_TYPE_CONTAINERS) { - dimensions[i] = ArraySize(_dimension.containers); - _dimension = _dimension.containers[0]; - } else if (_dimension.type == MATRIX_DIMENSION_TYPE_VALUES) { - dimensions[i++] = ArraySize(_dimension.values); + if (_dimension PTR_DEREF type == MATRIX_DIMENSION_TYPE_CONTAINERS) { + dimensions[i] = ArraySize(_dimension PTR_DEREF containers); + _dimension = _dimension PTR_DEREF containers[0]; + } else if (_dimension PTR_DEREF type == MATRIX_DIMENSION_TYPE_VALUES) { + dimensions[i++] = ArraySize(_dimension PTR_DEREF values); break; } else { Print("Internal error: unknown dimension type!"); @@ -1055,14 +1057,14 @@ class Matrix { /** * Assignment operator. */ - void operator=(const Matrix& _right) { Initialize(_right.ptr_first_dimension.Clone()); } + void operator=(const Matrix& _right) { Initialize(_right.ptr_first_dimension PTR_DEREF Clone()); } /** * Assignment operator. Initializes matrix using given dimension. */ Matrix(MatrixDimensionAccessor& accessor) { if (accessor.Type() == MATRIX_DIMENSION_TYPE_CONTAINERS) { - Initialize(accessor.ptr_dimension.containers[accessor.index].Clone()); + Initialize(accessor.ptr_dimension PTR_DEREF containers[accessor.index].Clone()); } else if (accessor.Type() == MATRIX_DIMENSION_TYPE_VALUES) { SetShape(1); this[0] = accessor.Val(); @@ -1078,7 +1080,7 @@ class Matrix { * Destructor. */ ~Matrix() { - if (ptr_first_dimension != NULL) { + if (ptr_first_dimension != nullptr) { delete ptr_first_dimension; } } @@ -1174,7 +1176,7 @@ class Matrix { return; } - int initial_container_size = ptr_first_dimension.DuplicateDimension(_level, _num); + int initial_container_size = ptr_first_dimension PTR_DEREF DuplicateDimension(_level, _num); dimensions[_level] += _num * initial_container_size; RecalculateSize(); Modified(); @@ -1320,7 +1322,7 @@ class Matrix { */ void Abs() { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_ABS); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_ABS); } } @@ -1329,7 +1331,7 @@ class Matrix { */ void Add(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_ADD, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_ADD, value); Modified(); } } @@ -1344,7 +1346,7 @@ class Matrix { */ void Sub(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_SUBTRACT, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_SUBTRACT, value); Modified(); } } @@ -1359,7 +1361,7 @@ class Matrix { */ void Mul(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_MULTIPLY, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_MULTIPLY, value); Modified(); } } @@ -1374,7 +1376,7 @@ class Matrix { */ void Div(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_DIVIDE, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_DIVIDE, value); Modified(); } } @@ -1384,7 +1386,7 @@ class Matrix { */ void Fill(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL, value); Modified(); } } @@ -1394,7 +1396,7 @@ class Matrix { */ void FillRandom(int _seed = -1) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_RANDOM, _seed); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_RANDOM, _seed); Modified(); } } @@ -1404,7 +1406,7 @@ class Matrix { */ void FillRandom(X _start, X _end, int _seed = -1) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_RANDOM_RANGE, _start, _end, _seed); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_RANDOM_RANGE, _start, _end, _seed); Modified(); } } @@ -1414,7 +1416,7 @@ class Matrix { */ void FillPosAdd() { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_POS_ADD); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_POS_ADD); Modified(); } } @@ -1424,7 +1426,7 @@ class Matrix { */ void FillPosMul() { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_FILL_POS_MUL); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_FILL_POS_MUL); Modified(); } } @@ -1436,7 +1438,7 @@ class Matrix { X _out1 = 0, _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); } return _out1; } @@ -1448,7 +1450,7 @@ class Matrix { X _out1 = MaxOf((X)0), _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_MIN, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_MIN, 0, 0, 0, _out1, _out2, _out3); } return _out1; } @@ -1460,7 +1462,7 @@ class Matrix { X _out1 = MinOf((X)0), _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_MAX, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_MAX, 0, 0, 0, _out1, _out2, _out3); } return _out1; } @@ -1472,7 +1474,7 @@ class Matrix { X _out1 = 0, _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_SUM, 0, 0, 0, _out1, _out2, _out3); return GetSize() > 0 ? _out1 / GetSize() : 0; } return MinOf((X)0); @@ -1483,7 +1485,7 @@ class Matrix { */ void Power(X value) { if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_POWER, value); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_POWER, value); Modified(); } } @@ -1493,7 +1495,7 @@ class Matrix { */ X Med() { if (ptr_first_dimension) { - X array[]; + ARRAY(X, array); GetRawArray(array); ArraySort(array); @@ -1638,8 +1640,8 @@ class Matrix { Matrix* operator+(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); } return result; @@ -1650,7 +1652,7 @@ class Matrix { */ void operator+=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_ADD); Modified(); } } @@ -1661,8 +1663,8 @@ class Matrix { Matrix* operator-(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); } return result; @@ -1673,7 +1675,7 @@ class Matrix { */ void operator-=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_SUBTRACT); Modified(); } } @@ -1684,8 +1686,8 @@ class Matrix { Matrix* operator*(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); } return result; @@ -1696,7 +1698,7 @@ class Matrix { */ void operator*=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); Modified(); } } @@ -1707,8 +1709,8 @@ class Matrix { Matrix* operator/(const Matrix& r) { Matrix* result = Clone(); - if (result.ptr_first_dimension) { - result.ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); + if (result PTR_DEREF ptr_first_dimension) { + result PTR_DEREF ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); } return result; @@ -1719,7 +1721,7 @@ class Matrix { */ void operator/=(const Matrix& r) { if (ptr_first_dimension && r.ptr_first_dimension) { - ptr_first_dimension.Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); + ptr_first_dimension PTR_DEREF Op(r.ptr_first_dimension, MATRIX_OPERATION_DIVIDE); Modified(); } } @@ -1727,17 +1729,17 @@ class Matrix { /** * Fills array with all values from the matrix. */ - void GetRawArrayNoCache(X& array[]) { + void GetRawArrayNoCache(ARRAY_REF(X, array)) { // Filling target array with flattened matrix data. int offset = 0; ArrayResize(array, GetSize()); - ptr_first_dimension.FillArray(array, offset); + ptr_first_dimension PTR_DEREF FillArray(array, offset); } /** * Fills array with all values from the matrix. */ - void GetRawArray(X& array[]) { + void GetRawArray(ARRAY_REF(X, array)) { if (flattened_cache_version == version) { // No need to flatten again as our cache is up to date. ArrayCopy(array, flattened_cache); @@ -1756,14 +1758,14 @@ class Matrix { * Flattens matrix. */ Matrix* Flatten() { - X values[]; + ARRAY(X, values); GetRawArray(values); Matrix* result = new Matrix(ArraySize(values)); for (int i = 0; i < ArraySize(values); ++i) { - result[i] = values[i]; + PTR_TO_REF(result)[i] = values[i]; } return result; @@ -1796,14 +1798,14 @@ class Matrix { /** * Fills matrix with the flattened data. Also fill flattened data cache. */ - void FillFromArray(X& _array[]) { + void FillFromArray(ARRAY_REF(X, _array)) { if (ArraySize(_array) != GetSize()) { Print("Matrix::FillFromArray(): input array (", ArraySize(_array), " elements) must be the same size as matrix (", GetSize(), " elements)!"); } int offset = 0; - ptr_first_dimension.FromArray(_array, offset); + ptr_first_dimension PTR_DEREF FromArray(_array, offset); Modified(); // We also fill flattened data cache. @@ -1876,15 +1878,15 @@ class Matrix { Print("Mean(): Unsupported absolute difference operator: ", EnumToString(_abs_diff_op), "!"); } - if (!ShapeCompatible(&this, _prediction)) { - Print("MeanAbsolute(): Shape ", Repr(), " is not compatible with prediction shape ", _prediction.Repr(), "!"); - return NULL; + if (!ShapeCompatible(THIS_PTR, _prediction)) { + Print("MeanAbsolute(): Shape ", Repr(), " is not compatible with prediction shape ", _prediction PTR_DEREF Repr(), + "!"); + return nullptr; } - if (_weights != NULL && _weights.GetDimensions() > this PTR_DEREF GetDimensions()) { - Print("MeanAbsolute(): Shape ", Repr(), ": Weights must be a tensor level <= ", this PTR_DEREF GetDimensions(), - "!"); - return NULL; + if (_weights != nullptr && _weights PTR_DEREF GetDimensions() > this PTR_DEREF GetDimensions()) { + Print("MeanAbsolute(): Shape ", Repr(), ": Weights must be a tensor level <= ", THIS_ATTR GetDimensions(), "!"); + return nullptr; } Matrix*_matrix, *_pooled; @@ -1893,27 +1895,31 @@ class Matrix { _matrix = Clone(); // Calculating absolute difference between copied tensor and given prediction. - _matrix.ptr_first_dimension.Op(_prediction.ptr_first_dimension, _abs_diff_op); + _matrix PTR_DEREF ptr_first_dimension PTR_DEREF Op(_prediction PTR_DEREF ptr_first_dimension, _abs_diff_op); switch (_abs_diff_op) { case MATRIX_OPERATION_ABS_DIFF_SQUARE: case MATRIX_OPERATION_ABS_DIFF_SQUARE_LOG: // Reducing values of the last dimension of the matrix. - _pooled = _matrix.GetPooled(_reduction, MATRIX_PADDING_SAME, dimensions[1] == 0 ? dimensions[0] : 1, - dimensions[2] == 0 ? dimensions[1] : 1, dimensions[3] == 0 ? dimensions[2] : 1, - dimensions[4] == 0 ? dimensions[3] : 1, dimensions[5] == 0 ? dimensions[4] : 1); + _pooled = + _matrix PTR_DEREF GetPooled(_reduction, MATRIX_PADDING_SAME, dimensions[1] == 0 ? dimensions[0] : 1, + dimensions[2] == 0 ? dimensions[1] : 1, dimensions[3] == 0 ? dimensions[2] : 1, + dimensions[4] == 0 ? dimensions[3] : 1, dimensions[5] == 0 ? dimensions[4] : 1); // Physically reducing last dimension of the matrix. - _pooled.ReduceSimple(); + _pooled PTR_DEREF ReduceSimple(); delete _matrix; _matrix = _pooled; break; + default: + RUNTIME_ERROR("Difference operation not supported!") } - if (_weights != NULL) { + if (_weights != nullptr) { // Multiplying copied tensor by given weights. Note that weights tensor could be of lower level than original // tensor. - _matrix.ptr_first_dimension.Op(_weights.ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); + _matrix PTR_DEREF ptr_first_dimension PTR_DEREF Op(_weights PTR_DEREF ptr_first_dimension, + MATRIX_OPERATION_MULTIPLY); } return _matrix; @@ -1923,18 +1929,17 @@ class Matrix { * Reduces single or all dimensions containing only a single value. */ void ReduceSimple(bool _only_last_dimension = true, ENUM_MATRIX_OPERATION _reduce_op = MATRIX_OPERATION_SUM) { - if (ptr_first_dimension != NULL) { - ptr_first_dimension.ReduceSimple(_only_last_dimension ? GetDimensions() - 1 : 0, _reduce_op); - Modified(); + if (ptr_first_dimension != nullptr) { + ptr_first_dimension PTR_DEREF ReduceSimple(_only_last_dimension ? GetDimensions() - 1 : 0, _reduce_op); } } void Reduce(int _level = 0, ENUM_MATRIX_OPERATION _reduce_op = MATRIX_OPERATION_SUM) { - if (ptr_first_dimension == NULL) { + if (ptr_first_dimension == nullptr) { return; } - ptr_first_dimension.Reduce(_level, _reduce_op); + ptr_first_dimension PTR_DEREF Reduce(_level, _reduce_op); for (int i = _level + 1; i < MATRIX_DIMENSIONS; ++i) { dimensions[i] = 0; @@ -1948,11 +1953,12 @@ class Matrix { * Computes the Poisson loss */ Matrix* Poisson(Matrix* _prediction) { - if (ptr_first_dimension == NULL) { - return NULL; + if (ptr_first_dimension == nullptr) { + return nullptr; } Matrix* _clone = Clone(); - _clone.ptr_first_dimension.Op(_prediction.ptr_first_dimension, MATRIX_OPERATION_POISSON); + _clone PTR_DEREF ptr_first_dimension PTR_DEREF Op(_prediction PTR_DEREF ptr_first_dimension, + MATRIX_OPERATION_POISSON); return _clone; } @@ -1966,7 +1972,7 @@ class Matrix { Matrix* VectorReduce(Matrix* _product, ENUM_MATRIX_VECTOR_REDUCE _reduce, int _dimension = 0) { if (_dimension == -1) _dimension = GetDimensions() - 1; - if (!ShapeCompatibleLossely(&this, _product)) { + if (!ShapeCompatibleLossely(THIS_PTR, _product)) { // Alert("VectorReduce(): Incompatible shapes: ", Repr(), " and ", _product.Repr(), "!"); // return NULL; } @@ -1992,7 +1998,6 @@ class Matrix { Matrix* _ptr_result = new Matrix(_out_dims[0], _out_dims[1], _out_dims[2], _out_dims[3], _out_dims[4]); - int _curr_dimension = 0; bool _stop = false; while (!_stop) { @@ -2010,7 +2015,8 @@ class Matrix { // Taking one group at a time. for (int b = 0; b < dimensions[_dimension]; ++b) { X _value_a = GetValue(_index[0], _index[1], _index[2], _index[3], _index[4]); - X _value_b = _product.GetValueLossely(GetDimensions(), _index[0], _index[1], _index[2], _index[3], _index[4]); + X _value_b = + _product PTR_DEREF GetValueLossely(GetDimensions(), _index[0], _index[1], _index[2], _index[3], _index[4]); switch (_reduce) { case MATRIX_VECTOR_REDUCE_COSINE_SIMILARITY: @@ -2048,7 +2054,7 @@ class Matrix { break; } - _ptr_result.SetValue(_res, _out_index[0], _out_index[1], _out_index[2], _out_index[3], _out_index[4]); + _ptr_result PTR_DEREF SetValue(_res, _out_index[0], _out_index[1], _out_index[2], _out_index[3], _out_index[4]); if (_dimension == 0) ++_index[1]; @@ -2120,19 +2126,19 @@ class Matrix { switch (_reduction) { case MATRIX_OPERATION_SUM: - result = _diff.Sum(); + result = _diff PTR_DEREF Sum(); break; case MATRIX_OPERATION_MIN: - result = _diff.Min(); + result = _diff PTR_DEREF Min(); break; case MATRIX_OPERATION_MAX: - result = _diff.Max(); + result = _diff PTR_DEREF Max(); break; case MATRIX_OPERATION_AVG: - result = _diff.Avg(); + result = _diff PTR_DEREF Avg(); break; case MATRIX_OPERATION_MED: - result = _diff.Med(); + result = _diff PTR_DEREF Med(); break; default: Print("MeanAbsolute(): Unsupported reduction type: ", EnumToString(_reduction), "!"); @@ -2170,7 +2176,7 @@ class Matrix { */ Matrix* Relu() { Matrix* result = Clone(); - result.Relu_(); + result PTR_DEREF Relu_(); return result; } @@ -2181,7 +2187,7 @@ class Matrix { X _out1 = 0, _out2; int _out3; if (ptr_first_dimension) { - ptr_first_dimension.Op(MATRIX_OPERATION_RELU, 0, 0, 0, _out1, _out2, _out3); + ptr_first_dimension PTR_DEREF Op(MATRIX_OPERATION_RELU, 0, 0, 0, _out1, _out2, _out3); Modified(); } } @@ -2191,7 +2197,7 @@ class Matrix { */ Matrix* Clone() const { Matrix* _cloned = new Matrix(dimensions[0], dimensions[1], dimensions[2], dimensions[3], dimensions[4]); - _cloned.ptr_first_dimension.CopyFrom(ptr_first_dimension); + _cloned PTR_DEREF ptr_first_dimension PTR_DEREF CopyFrom(ptr_first_dimension); return _cloned; } @@ -2203,15 +2209,15 @@ class Matrix { void Set(X value, const int _1d, const int _2d = -1, const int _3d = -1, const int _4d = -1, const int _5d = -1) { if (_2d == -1) { - this[_1d] = value; + THIS_REF[_1d] = value; } else if (_3d == -1) { - this[_1d][_2d] = value; + THIS_REF[_1d][_2d] = value; } else if (_4d == -1) { - this[_1d][_2d][_3d] = value; + THIS_REF[_1d][_2d][_3d] = value; } else if (_5d == -1) { - this[_1d][_2d][_3d][_4d] = value; + THIS_REF[_1d][_2d][_3d][_4d] = value; } else { - this[_1d][_2d][_3d][_4d][_5d] = value; + THIS_REF[_1d][_2d][_3d][_4d][_5d] = value; } Modified(); } @@ -2222,25 +2228,25 @@ class Matrix { if (dimensions[0] < _in_channels) { Alert("Insufficient number of channels in the input. First dimensions should have ", _in_channels, " arrays, got ", dimensions[0]); - return NULL; + return nullptr; } Matrix* clone = Clone(); - clone.DuplicateDimension(1, _out_channels - 1); + clone PTR_DEREF DuplicateDimension(1, _out_channels - 1); if (_weights != NULL) { - Matrix* weight_flattened = _weights.Flatten(); + Matrix* weight_flattened = _weights PTR_DEREF Flatten(); for (int _in_channel_idx = 0; _in_channel_idx < _in_channels; ++_in_channel_idx) { - clone.ptr_first_dimension.containers[_in_channel_idx].Op(weight_flattened.ptr_first_dimension, - MATRIX_OPERATION_MULTIPLY); + clone PTR_DEREF ptr_first_dimension PTR_DEREF containers[_in_channel_idx].Op( + weight_flattened PTR_DEREF ptr_first_dimension, MATRIX_OPERATION_MULTIPLY); } delete weight_flattened; } - Matrix* pooled = - clone.GetPooled(MATRIX_OPERATION_SUM, MATRIX_PADDING_VALID, 1, 2, _krn_1d, _krn_2d, 0, // Kernel size. - 1, 2, _stride_1d, _stride_2d); + Matrix* pooled = clone PTR_DEREF GetPooled(MATRIX_OPERATION_SUM, MATRIX_PADDING_VALID, 1, 2, _krn_1d, _krn_2d, + 0, // Kernel size. + 1, 2, _stride_1d, _stride_2d); delete clone; return pooled; @@ -2299,10 +2305,10 @@ class Matrix { return GetDimensionsTotal(_dimensions); } - static int GetDimensionsTotal(int& dimensions[]) { + static int GetDimensionsTotal(FIXED_ARRAY_REF(int, dimensions, MATRIX_DIMENSIONS)) { int size = 0; - for (int i = 0; i < ArraySize(dimensions); ++i) { + for (int i = 0; i < MATRIX_DIMENSIONS; ++i) { if (dimensions[i] != 0) { if (size == 0) { size = 1; @@ -2357,7 +2363,7 @@ class Matrix { ChunkOp(_op, _padding, _pool_1d, _pool_2d, _pool_3d, _pool_4d, _pool_5d, _stride_1d, _stride_2d, _stride_3d, _stride_4d, _stride_5d, _chunk_1d, _chunk_2d, _chunk_3d, _chunk_4d, _chunk_5d); - _result.Set(result, _chunk_1d, _chunk_2d, _chunk_3d, _chunk_4d, _chunk_5d); + _result PTR_DEREF Set(result, _chunk_1d, _chunk_2d, _chunk_3d, _chunk_4d, _chunk_5d); } } } @@ -2407,7 +2413,7 @@ class Matrix { _accessor_d1 = this[d1]; if (_accessor_d1.Type() == MATRIX_DIMENSION_TYPE_VALUES) { - _MATRIX_AGGR(ptr_first_dimension.values[d1]); + _MATRIX_AGGR(ptr_first_dimension PTR_DEREF values[d1]); continue; } @@ -2506,16 +2512,16 @@ class Matrix { /** * Checks whether both matrices have the same dimensions' length. */ - static bool ShapeCompatible(Matrix* _a, Matrix* _b) { return _a.Repr() == _b.Repr(); } + static bool ShapeCompatible(Matrix* _a, Matrix* _b) { return _a PTR_DEREF Repr() == _b PTR_DEREF Repr(); } /** * Checks whether right matrix have less or equal dimensions' length.. */ static bool ShapeCompatibleLossely(Matrix* _a, Matrix* _b) { - if (_b.GetDimensions() > _a.GetDimensions()) return false; + if (_b PTR_DEREF GetDimensions() > _a PTR_DEREF GetDimensions()) return false; - for (int i = 0; i < _b.GetDimensions(); ++i) { - if (_b.dimensions[i] != 1 && _b.dimensions[i] > _a.dimensions[i]) return false; + for (int i = 0; i < _b PTR_DEREF GetDimensions(); ++i) { + if (_b PTR_DEREF dimensions[i] != 1 && _b PTR_DEREF dimensions[i] > _a PTR_DEREF dimensions[i]) return false; } return true; @@ -2524,13 +2530,13 @@ class Matrix { static Matrix* CreateFromString(string text) { Matrix* _ptr_matrix = new Matrix(); - _ptr_matrix.FromString(text); + _ptr_matrix PTR_DEREF FromString(text); return _ptr_matrix; } void FromString(string text) { - MatrixDimension*_dimensions[], *_root_dimension = NULL; + ARRAY(MatrixDimension*, _dimensions), *_root_dimension = NULL; int _dimensions_length[MATRIX_DIMENSIONS] = {0, 0, 0, 0, 0}; int i, _number_start_pos; bool _had_values; @@ -2634,7 +2640,7 @@ class Matrix { * */ string ToString(bool _whitespaces = false, int _precision = 3) { - return ptr_first_dimension.ToString(_whitespaces, _precision); + return ptr_first_dimension PTR_DEREF ToString(_whitespaces, _precision); } /** diff --git a/MiniMatrix.h b/MiniMatrix.h index 646156acb..50adb9653 100644 --- a/MiniMatrix.h +++ b/MiniMatrix.h @@ -27,7 +27,7 @@ template class MiniMatrix2d { public: - T data[]; + ARRAY(T, data); int size_x; int size_y; diff --git a/Object.enum.h b/Object.enum.h index 5e280a4c3..d56973d4b 100644 --- a/Object.enum.h +++ b/Object.enum.h @@ -26,6 +26,9 @@ */ #ifndef __MQLBUILD__ + +#pragma once + // Used for checking the type of the object pointer. // @docs // - https://docs.mql4.com/constants/namedconstants/enum_pointer_type diff --git a/Object.extern.h b/Object.extern.h index 47ec7734b..69d25ece1 100644 --- a/Object.extern.h +++ b/Object.extern.h @@ -25,5 +25,75 @@ * Includes external declarations related to objects. */ #ifndef __MQL__ -extern void *GetPointer(void *anyobject); + +#pragma once + +// Includes. +#include "Object.enum.h" + +template +X* GetPointer(X& value) { + return &value; +} +template +X* GetPointer(X* ptr) { + return ptr; +} + +template +ENUM_POINTER_TYPE CheckPointer(X& value) { + return (&value) != nullptr ? POINTER_DYNAMIC : POINTER_INVALID; +} +template +ENUM_POINTER_TYPE CheckPointer(X* ptr) { + return ptr != nullptr ? POINTER_DYNAMIC : POINTER_INVALID; +} + +enum ENUM_OBJECT { + OBJ_VLINE = 0, // Vertical Line + OBJ_HLINE = 1, // Horizontal Line + OBJ_TREND = 2, // Trend Line + OBJ_TRENDBYANGLE = 3, // Trend Line By Angle + OBJ_CYCLES = 4, // Cycle Lines + OBJ_ARROWED_LINE = 108, // Arrowed Line + OBJ_CHANNEL = 5, // Equidistant Channel + OBJ_STDDEVCHANNEL = 6, // Standard Deviation Channel + OBJ_REGRESSION = 7, // Linear Regression Channel + OBJ_PITCHFORK = 8, // Andrews’ Pitchfork + OBJ_GANNLINE = 9, // Gann Line + OBJ_GANNFAN = 10, // Gann Fan + OBJ_GANNGRID = 11, // Gann Grid + OBJ_FIBO = 12, // Fibonacci Retracement + OBJ_FIBOTIMES = 13, // Fibonacci Time Zones + OBJ_FIBOFAN = 14, // Fibonacci Fan + OBJ_FIBOARC = 15, // Fibonacci Arcs + OBJ_FIBOCHANNEL = 16, // Fibonacci Channel + OBJ_EXPANSION = 17, // Fibonacci Expansion + OBJ_ELLIOTWAVE5 = 18, // Elliott Motive Wave + OBJ_ELLIOTWAVE3 = 19, // Elliott Correction Wave + OBJ_RECTANGLE = 20, // Rectangle + OBJ_TRIANGLE = 21, // Triangle + OBJ_ELLIPSE = 22, // Ellipse + OBJ_ARROW_THUMB_UP = 23, // Thumbs Up + OBJ_ARROW_THUMB_DOWN = 24, // Thumbs Down + OBJ_ARROW_UP = 25, // Arrow Up + OBJ_ARROW_DOWN = 26, // Arrow Down + OBJ_ARROW_STOP = 27, // Stop Sign + OBJ_ARROW_CHECK = 28, // Check Sign + OBJ_ARROW_LEFT_PRICE = 29, // Left Price Label + OBJ_ARROW_RIGHT_PRICE = 30, // Right Price Label + OBJ_ARROW_BUY = 31, // Buy Sign + OBJ_ARROW_SELL = 32, // Sell Sign + OBJ_ARROW = 100, // Arrow + OBJ_TEXT = 101, // Text + OBJ_LABEL = 102, // Label + OBJ_BUTTON = 103, // Button + OBJ_CHART = 104, // Chart + OBJ_BITMAP = 105, // Bitmap + OBJ_BITMAP_LABEL = 106, // Bitmap Label + OBJ_EDIT = 107, // Edit + OBJ_EVENT = 109, // The "Event" object corresponding to an event in the economic calendar + OBJ_RECTANGLE_LABEL = 110 // The "Rectangle label" object for creating and designing the custom graphical interface. +}; + #endif diff --git a/Object.mqh b/Object.mqh index 3c0e90406..cc27a1ad8 100644 --- a/Object.mqh +++ b/Object.mqh @@ -24,8 +24,6 @@ #ifndef OBJECT_MQH #define OBJECT_MQH -#define nullptr NULL - // Includes. #include "Object.enum.h" #include "Object.extern.h" @@ -37,14 +35,11 @@ * Class to deal with objects. */ class Object : public Dynamic { - protected: - void *obj; long id; public: - /** * Class constructor. */ @@ -105,7 +100,7 @@ class Object : public Dynamic { /** * Returns text representation of the object. */ - virtual const string ToString() { return StringFormat("[Object #%04x]", THIS_PTR); } + virtual string const ToString() { return StringFormat("[Object #%04x]", THIS_PTR); } /** * Returns text representation of the object. diff --git a/Order.enum.h b/Order.enum.h index 00f009f17..0bf12814b 100644 --- a/Order.enum.h +++ b/Order.enum.h @@ -245,8 +245,11 @@ enum ENUM_ORDER_TYPE { // price. ORDER_TYPE_SELL_STOP_LIMIT, // Upon reaching the order price, a pending Sell Limit order is placed at the StopLimit // price. - ORDER_TYPE_CLOSE_BY // Order to close a position by an opposite one. + ORDER_TYPE_CLOSE_BY, // Order to close a position by an opposite one. + ORDER_TYPE_UNSET // A NULL value. }; +#else +#define ORDER_TYPE_UNSET NULL #endif /* Positions */ diff --git a/Order.mqh b/Order.mqh index fda94260b..5f4dabd30 100644 --- a/Order.mqh +++ b/Order.mqh @@ -33,7 +33,7 @@ class SymbolInfo; // Includes. -#include "Convert.mqh" +#include "Convert.basic.h" #include "Data.define.h" #include "Data.struct.h" #include "Deal.enum.h" @@ -306,9 +306,10 @@ class Order : public SymbolInfo { int _num = oparams.Get(ORDER_PARAM_COND_CLOSE_NUM); for (int _ci = 0; _ci < _num; _ci++) { ENUM_ORDER_CONDITION _cond = oparams.Get(ORDER_PARAM_COND_CLOSE, _ci); - DataParamEntry _cond_args[1]; - _cond_args[0] = oparams.Get(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _ci); - _result |= _result || Order::CheckCondition(_cond, _cond_args); + ARRAY(DataParamEntry, _cond_args); + DataParamEntry _item0 = oparams.Get(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _ci); + ArrayPushObject(_cond_args, _item0); + _result |= Order::CheckCondition(_cond, _cond_args); } } return _result; @@ -504,7 +505,7 @@ class Order : public SymbolInfo { return (datetime)_result; #endif } - datetime GetCloseTime() { return IsClosed() ? odata.Get(ORDER_PROP_TIME_CLOSED) : 0; } + datetime GetCloseTime() { return IsClosed() ? odata.Get(ORDER_PROP_TIME_CLOSED) : (datetime)0; } /** * Returns comment of the currently selected order/position. @@ -695,8 +696,10 @@ class Order : public SymbolInfo { return OrderStopLoss(); case ORDER_TP: return OrderTakeProfit(); + default: + break; } - return NULL; + return 0; } /** @@ -1024,7 +1027,7 @@ class Order : public SymbolInfo { * * @see: https://docs.mql4.com/trading/orderdelete */ - static bool OrderDelete(unsigned long _ticket, color _color = NULL) { + static bool OrderDelete(unsigned long _ticket, color _color = color()) { #ifdef __MQL4__ return ::OrderDelete((int)_ticket, _color); #else @@ -1068,6 +1071,7 @@ class Order : public SymbolInfo { MqlTradeCheckResult _result_check = {0}; MqlTradeResult _result = {0}; _request.action = TRADE_ACTION_SLTP; + //_request.type = PositionTypeToOrderType(); _request.comment = ::PositionGetString(POSITION_COMMENT); // StringFormat("mn=%d", GetMagicNumber()); _request.magic = ::PositionGetInteger(POSITION_MAGIC); _request.position = _ticket; // Position ticket. @@ -1102,10 +1106,9 @@ class Order : public SymbolInfo { if (IsClosed()) { Refresh(); } else { - GetLogger().Warning(StringFormat("Failed to modify order (#%d/p:%g/sl:%g/tp:%g/code:%d).", - odata.Get(ORDER_PROP_TICKET), _price, _sl, _tp, _last_error), - __FUNCTION_LINE__, ToCSV()); - Refresh(ORDER_PRICE_CURRENT); + GetLogger() PTR_DEREF Warning(StringFormat("Failed to modify order (#%d/p:%g/sl:%g/tp:%g/code:%d).", + odata.Get(ORDER_PROP_TICKET), _price, _sl, _tp, _last_error), + __FUNCTION_LINE__, ToCSV()); Refresh(ORDER_SL); Refresh(ORDER_TP); // TODO: Refresh(ORDER_PRI) @@ -1323,7 +1326,7 @@ class Order : public SymbolInfo { // - https://www.mql5.com/en/docs/constants/errorswarnings/enum_trade_return_codes // - https://www.mql5.com/en/docs/constants/structures/mqltradecheckresult #ifdef __debug__ - PrintFormat("%s: Error %d: %s", __FUNCTION_LINE__, _result_check.retcode, _result_check.comment); + PrintFormat("%s: Error %d: %s", C_STR(__FUNCTION_LINE__), _result_check.retcode, C_STR(_result_check.comment)); #endif _result.retcode = _result_check.retcode; return false; @@ -1720,7 +1723,7 @@ class Order : public SymbolInfo { if (!_result || _last_error > ERR_NO_ERROR) { if (_last_error > ERR_NO_ERROR && _last_error != 4014) { // @fixme: In MT4 (why 4014?). - GetLogger().Warning(StringFormat("Update failed! Error: %d", _last_error), __FUNCTION_LINE__); + GetLogger() PTR_DEREF Warning(StringFormat("Update failed! Error: %d", _last_error), __FUNCTION_LINE__); } odata.ProcessLastError(); ResetLastError(); @@ -1755,6 +1758,8 @@ class Order : public SymbolInfo { RefreshDummy(ORDER_PRICE_CURRENT); } + odata.Set(ORDER_PROP_PROFIT, oresult.bid - oresult.ask); + // @todo: More RefreshDummy(XXX); odata.ResetError(); @@ -1806,6 +1811,8 @@ class Order : public SymbolInfo { OrderCloseDummy(); } break; + default: + break; } break; case ORDER_PRICE_OPEN: @@ -1820,6 +1827,8 @@ class Order : public SymbolInfo { case ORDER_TP: odata.Set(_prop_id, orequest.tp); break; + default: + break; } return true; @@ -1830,12 +1839,13 @@ class Order : public SymbolInfo { */ bool RefreshDummy(ENUM_ORDER_PROPERTY_INTEGER _prop_id) { bool _result = false; - long _value = WRONG_VALUE; ResetLastError(); switch (_prop_id) { case ORDER_MAGIC: odata.Set(_prop_id, orequest.magic); break; + default: + break; } return _result && GetLastError() == ERR_NO_ERROR; @@ -1852,6 +1862,8 @@ class Order : public SymbolInfo { case ORDER_SYMBOL: odata.Set(_prop_id, orequest.symbol); break; + default: + break; } return true; @@ -1898,7 +1910,7 @@ class Order : public SymbolInfo { } else { int _last_error = GetLastError(); ologger.Error("Error refreshing order property!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); } return _result && GetLastError() == ERR_NO_ERROR; } @@ -1955,6 +1967,10 @@ class Order : public SymbolInfo { _result = Order::OrderGetInteger(ORDER_TYPE_TIME, _value); break; default: + if ((int)_prop_id == (int)ORDER_REASON) { + _result = Order::OrderGetInteger((ENUM_ORDER_PROPERTY_INTEGER)ORDER_REASON, _value); + break; + } return false; } if (_result) { @@ -1962,7 +1978,7 @@ class Order : public SymbolInfo { } else { int _last_error = GetLastError(); ologger.Error("Error updating order property!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); } return _result && GetLastError() == ERR_NO_ERROR; } @@ -1986,6 +2002,14 @@ class Order : public SymbolInfo { _value = Order::OrderGetString(ORDER_SYMBOL); break; default: +/* +#ifdef ORDER_EXTERNAL_ID + if ((int)_prop_id == (int)ORDER_EXTERNAL_ID) { + _value = Order::OrderGetString(ORDER_EXTERNAL_ID); + break; + } +#endif +*/ _result = false; break; } @@ -1994,7 +2018,7 @@ class Order : public SymbolInfo { } else { int _last_error = GetLastError(); ologger.Error("Error updating order property!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); } return true; } @@ -2012,7 +2036,7 @@ class Order : public SymbolInfo { * Return text representation of the order. */ static string OrderTypeToString(ENUM_ORDER_TYPE _cmd, bool _lc = false) { - _cmd = _cmd != NULL ? _cmd : OrderType(); + _cmd = _cmd != ORDER_TYPE_UNSET ? _cmd : OrderType(); string _res = StringSubstr(EnumToString(_cmd), 11); StringReplace(_res, "_", " "); if (_lc) { @@ -2047,6 +2071,8 @@ class Order : public SymbolInfo { return ORDER_TYPE_SELL; case ORDER_TYPE_SELL: return ORDER_TYPE_BUY; + default: + break; } return WRONG_VALUE; } @@ -2087,8 +2113,8 @@ class Order : public SymbolInfo { /** * Get color of the order based on its type. */ - static color GetOrderColor(ENUM_ORDER_TYPE _cmd = (ENUM_ORDER_TYPE)-1, color cbuy = Blue, color csell = Red) { - if (_cmd == NULL) _cmd = (ENUM_ORDER_TYPE)OrderType(); + static color GetOrderColor(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, color cbuy = Blue, color csell = Red) { + if (_cmd == ORDER_TYPE_UNSET) _cmd = (ENUM_ORDER_TYPE)OrderType(); return OrderData::GetTypeValue(_cmd) > 0 ? cbuy : csell; } @@ -2336,7 +2362,7 @@ class Order : public SymbolInfo { _out = OrderGetString(property_id); return true; #else - return OrderGetParam(property_id, selected_ticket_type, ORDER_SELECT_DATA_TYPE_STRING, _out) != (string)NULL_VALUE; + return OrderGetParam(property_id, selected_ticket_type, ORDER_SELECT_DATA_TYPE_STRING, _out) != NULL_STRING; #endif } @@ -2361,7 +2387,7 @@ class Order : public SymbolInfo { static long OrderGetValue(int property_id, ENUM_ORDER_SELECT_TYPE type, long &_out) { switch (type) { case ORDER_SELECT_TYPE_NONE: - return NULL; + return 0; case ORDER_SELECT_TYPE_ACTIVE: _out = ::OrderGetInteger((ENUM_ORDER_PROPERTY_INTEGER)property_id); break; @@ -2399,7 +2425,7 @@ class Order : public SymbolInfo { static double OrderGetValue(int property_id, ENUM_ORDER_SELECT_TYPE type, double &_out) { switch (type) { case ORDER_SELECT_TYPE_NONE: - return NULL; + return 0; case ORDER_SELECT_TYPE_ACTIVE: _out = ::OrderGetDouble((ENUM_ORDER_PROPERTY_DOUBLE)property_id); break; @@ -2478,9 +2504,11 @@ class Order : public SymbolInfo { template static X OrderGetParam(int _prop_id, ENUM_ORDER_SELECT_TYPE _type, ENUM_ORDER_SELECT_DATA_TYPE _data_type, X &_out) { #ifndef __MQL4__ + long _long; + string _string; switch (selected_ticket_type) { case ORDER_SELECT_TYPE_NONE: - return NULL; + return NULL_VALUE; case ORDER_SELECT_TYPE_ACTIVE: case ORDER_SELECT_TYPE_HISTORY: @@ -2493,13 +2521,13 @@ class Order : public SymbolInfo { case ORDER_TIME_SETUP: return OrderGetValue(DEAL_TIME, _type, _out); case ORDER_TYPE: - switch ((int)OrderGetValue(DEAL_TYPE, _type, _out)) { + switch ((int)OrderGetValue(DEAL_TYPE, _type, _long)) { case DEAL_TYPE_BUY: - return (X)ORDER_TYPE_BUY; + return ConvertBasic::LongTo(ORDER_TYPE_BUY); case DEAL_TYPE_SELL: - return (X)ORDER_TYPE_SELL; + return ConvertBasic::LongTo(ORDER_TYPE_SELL); default: - return NULL; + return NULL_VALUE; } break; case ORDER_STATE: @@ -2508,43 +2536,44 @@ class Order : public SymbolInfo { case ORDER_TIME_EXPIRATION: case ORDER_TIME_DONE: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TIME_SETUP_MSC: return OrderGetValue(DEAL_TIME_MSC, _type, _out); case ORDER_TIME_DONE_MSC: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TYPE_FILLING: case ORDER_TYPE_TIME: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_MAGIC: return OrderGetValue(DEAL_MAGIC, _type, _out); - case ORDER_REASON: - switch ((int)OrderGetValue(DEAL_REASON, _type, _out)) { - case DEAL_REASON_CLIENT: - return (X)ORDER_REASON_CLIENT; - case DEAL_REASON_MOBILE: - return (X)ORDER_REASON_MOBILE; - case DEAL_REASON_WEB: - return (X)ORDER_REASON_WEB; - case DEAL_REASON_EXPERT: - return (X)ORDER_REASON_EXPERT; - case DEAL_REASON_SL: - return (X)ORDER_REASON_SL; - case DEAL_REASON_TP: - return (X)ORDER_REASON_TP; - case DEAL_REASON_SO: - return (X)ORDER_REASON_SO; - default: - return NULL; - } - break; case ORDER_POSITION_ID: return OrderGetValue(DEAL_POSITION_ID, _type, _out); case ORDER_POSITION_BY_ID: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; + default: + if ((int)_prop_id == (int)ORDER_REASON) { + switch ((int)OrderGetValue(DEAL_REASON, _type, _long)) { + case DEAL_REASON_CLIENT: + return ConvertBasic::LongTo(ORDER_REASON_CLIENT); + case DEAL_REASON_MOBILE: + return ConvertBasic::LongTo(ORDER_REASON_MOBILE); + case DEAL_REASON_WEB: + return ConvertBasic::LongTo(ORDER_REASON_WEB); + case DEAL_REASON_EXPERT: + return ConvertBasic::LongTo(ORDER_REASON_EXPERT); + case DEAL_REASON_SL: + return ConvertBasic::LongTo(ORDER_REASON_SL); + case DEAL_REASON_TP: + return ConvertBasic::LongTo(ORDER_REASON_TP); + case DEAL_REASON_SO: + return ConvertBasic::LongTo(ORDER_REASON_SO); + default: + return NULL_VALUE; + } + } } break; case ORDER_SELECT_DATA_TYPE_DOUBLE: @@ -2553,26 +2582,31 @@ class Order : public SymbolInfo { return OrderGetValue(DEAL_VOLUME, _type, _out); case ORDER_VOLUME_CURRENT: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_PRICE_OPEN: return OrderGetValue(DEAL_PRICE, _type, _out); case ORDER_SL: case ORDER_TP: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_PRICE_CURRENT: return OrderGetValue(DEAL_PRICE, _type, _out); case ORDER_PRICE_STOPLIMIT: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; } break; case ORDER_SELECT_DATA_TYPE_STRING: switch (_prop_id) { case ORDER_SYMBOL: case ORDER_COMMENT: - case ORDER_EXTERNAL_ID: - return NULL; + return NULL_VALUE; + default: +#ifdef ORDER_EXTERNAL_ID + if ((int)_prop_id == (int)ORDER_EXTERNAL_ID) { + return NULL_VALUE; + } +#endif } break; } @@ -2585,13 +2619,13 @@ class Order : public SymbolInfo { case ORDER_TIME_SETUP: return OrderGetValue(POSITION_TIME, _type, _out); case ORDER_TYPE: - switch ((int)OrderGetValue(POSITION_TYPE, _type, _out)) { + switch ((int)OrderGetValue(POSITION_TYPE, _type, _long)) { case POSITION_TYPE_BUY: - return (X)ORDER_TYPE_BUY; + return ConvertBasic::LongTo(ORDER_TYPE_BUY); case POSITION_TYPE_SELL: - return (X)ORDER_TYPE_SELL; + return ConvertBasic::LongTo(ORDER_TYPE_SELL); default: - return NULL; + return NULL_VALUE; } break; case ORDER_STATE: @@ -2600,37 +2634,38 @@ class Order : public SymbolInfo { case ORDER_TIME_EXPIRATION: case ORDER_TIME_DONE: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TIME_SETUP_MSC: return OrderGetValue(POSITION_TIME_MSC, _type, _out); case ORDER_TIME_DONE_MSC: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_TYPE_FILLING: case ORDER_TYPE_TIME: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; case ORDER_MAGIC: return OrderGetValue(POSITION_MAGIC, _type, _out); - case ORDER_REASON: - switch ((int)OrderGetValue(POSITION_REASON, _type, _out)) { - case POSITION_REASON_CLIENT: - return (X)ORDER_REASON_CLIENT; - case POSITION_REASON_MOBILE: - return (X)ORDER_REASON_MOBILE; - case POSITION_REASON_WEB: - return (X)ORDER_REASON_WEB; - case POSITION_REASON_EXPERT: - return (X)ORDER_REASON_EXPERT; - default: - return NULL; - } - break; case ORDER_POSITION_ID: return OrderGetValue(POSITION_IDENTIFIER, _type, _out); case ORDER_POSITION_BY_ID: SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; + default: + if ((int)_prop_id == (int)ORDER_REASON) { + switch ((int)OrderGetValue(POSITION_REASON, _type, _long)) { + case POSITION_REASON_CLIENT: + return ConvertBasic::LongTo(ORDER_REASON_CLIENT); + case POSITION_REASON_MOBILE: + return ConvertBasic::LongTo(ORDER_REASON_MOBILE); + case POSITION_REASON_WEB: + return ConvertBasic::LongTo(ORDER_REASON_WEB); + case POSITION_REASON_EXPERT: + return ConvertBasic::LongTo(ORDER_REASON_EXPERT); + default: + return NULL_VALUE; + } + } } break; case ORDER_SELECT_DATA_TYPE_DOUBLE: @@ -2650,7 +2685,7 @@ class Order : public SymbolInfo { case ORDER_PRICE_STOPLIMIT: // @fixme SetUserError(ERR_INVALID_PARAMETER); - return NULL; + return NULL_VALUE; } break; case ORDER_SELECT_DATA_TYPE_STRING: @@ -2659,15 +2694,19 @@ class Order : public SymbolInfo { return OrderGetValue(POSITION_SYMBOL, _type, _out); case ORDER_COMMENT: return OrderGetValue(POSITION_COMMENT, _type, _out); - case ORDER_EXTERNAL_ID: - return OrderGetValue(POSITION_EXTERNAL_ID, _type, _out); + default: +#ifdef ORDER_EXTERNAL_ID + if ((int)_prop_id == (int)ORDER_EXTERNAL_ID) { + return OrderGetValue(POSITION_EXTERNAL_ID, _type, _out); + } +#endif } break; } break; } - return NULL; + return NULL_VALUE; #else return OrderGetValue(_prop_id, _type, _out); #endif @@ -2683,8 +2722,12 @@ class Order : public SymbolInfo { bool ProcessConditions(bool _refresh = false) { bool _result = true; if (IsOpen(_refresh) && (odata.Get(ORDER_PROP_CLOSE_TRIES) > 0 || ShouldCloseOrder())) { + string _reason = "Close condition"; +#ifdef __MQL__ + // _reason += StringFormat(": %s", EnumToString(oparams.cond_close)); +#endif ARRAY(DataParamEntry, _args); - DataParamEntry _cond = ORDER_REASON_CLOSED_BY_CONDITION; + DataParamEntry _cond = _reason; ArrayPushObject(_args, _cond); _result &= Order::ExecuteAction(ORDER_ACTION_CLOSE, _args); odata.IncCloseTries(); @@ -2703,7 +2746,7 @@ class Order : public SymbolInfo { * Returns true when the condition is met. */ bool CheckCondition(ENUM_ORDER_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { - float _profit = (float)Get(ORDER_PROP_PROFIT_PIPS); + // float _profit = (float)Get(ORDER_PROP_PROFIT_PIPS); switch (_cond) { case ORDER_COND_IN_LOSS: return Get(ORDER_PROP_PROFIT_PIPS) < (ArraySize(_args) > 0 ? -DataParamEntry::ToDouble(_args[0]) : 0); @@ -2722,6 +2765,8 @@ class Order : public SymbolInfo { return TimeCurrent() - odata.Get(ORDER_TIME_SETUP) > _arg_value; case ORDER_COND_LIFETIME_LT_ARG: return TimeCurrent() - odata.Get(ORDER_TIME_SETUP) < _arg_value; + default: + return false; } } case ORDER_COND_PROP_EQ_ARG: @@ -2742,6 +2787,8 @@ class Order : public SymbolInfo { return odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_prop_id) > _args[1].double_value; case ORDER_COND_PROP_LT_ARG: return odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_prop_id) < _args[1].double_value; + default: + return false; } case TYPE_INT: case TYPE_LONG: @@ -2755,6 +2802,8 @@ class Order : public SymbolInfo { return odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_prop_id) > _args[1].integer_value; case ORDER_COND_PROP_LT_ARG: return odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_prop_id) < _args[1].integer_value; + default: + return false; } case TYPE_STRING: Refresh((ENUM_ORDER_PROPERTY_STRING)_prop_id); @@ -2766,12 +2815,17 @@ class Order : public SymbolInfo { return odata.Get((ENUM_ORDER_PROPERTY_STRING)_prop_id) > _args[1].string_value; case ORDER_COND_PROP_LT_ARG: return odata.Get((ENUM_ORDER_PROPERTY_STRING)_prop_id) < _args[1].string_value; + default: + return false; } + default: + return false; } } } default: - ologger.Error(StringFormat("Invalid order condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + ologger.Error( + StringFormat("Invalid order condition: %s at %s!", C_STR(EnumToString(_cond)), C_STR(__FUNCTION_LINE__))); } SetUserError(ERR_INVALID_PARAMETER); return false; @@ -2792,7 +2846,6 @@ class Order : public SymbolInfo { * Returns true when the condition is met. */ bool ExecuteAction(ENUM_ORDER_ACTION _action, ARRAY_REF(DataParamEntry, _args)) { - bool _result = true; switch (_action) { case ORDER_ACTION_CLOSE: switch (oparams.dummy) { @@ -2817,12 +2870,11 @@ class Order : public SymbolInfo { } oparams.AddConditionClose((ENUM_ORDER_CONDITION)_args[0].integer_value, _sargs); } - break; default: - ologger.Error(StringFormat("Invalid order action: %s!", EnumToString(_action), __FUNCTION_LINE__)); + ologger.Error( + StringFormat("Invalid order action: %s at %s!", C_STR(EnumToString(_action)), C_STR(__FUNCTION_LINE__))); return false; } - return _result; } bool ExecuteAction(ENUM_ORDER_ACTION _action) { ARRAY(DataParamEntry, _args); @@ -2849,21 +2901,21 @@ class Order : public SymbolInfo { switch (_type) { case TYPE_DOUBLE: for (i = 0; i < Array::ArraySize(_props); i++) { - _output += StringFormat("%g%s", odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_props[i]), _dlm); + _output += StringFormat("%g%s", odata.Get((ENUM_ORDER_PROPERTY_DOUBLE)_props[i]), C_STR(_dlm)); } break; case TYPE_LONG: for (i = 0; i < Array::ArraySize(_props); i++) { - _output += StringFormat("%d%s", odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_props[i]), _dlm); + _output += StringFormat("%d%s", odata.Get((ENUM_ORDER_PROPERTY_INTEGER)_props[i]), C_STR(_dlm)); } break; case TYPE_STRING: for (i = 0; i < Array::ArraySize(_props); i++) { - _output += StringFormat("%d%s", odata.Get((ENUM_ORDER_PROPERTY_STRING)_props[i]), _dlm); + _output += StringFormat("%s%s", C_STR(odata.Get((ENUM_ORDER_PROPERTY_STRING)_props[i])), C_STR(_dlm)); } break; default: - ologger.Error(StringFormat("%s: Unsupported type: %s!", __FUNCTION_LINE__, EnumToString(_type))); + ologger.Error(StringFormat("%s: Unsupported type: %s!", C_STR(__FUNCTION_LINE__), C_STR(EnumToString(_type)))); } return ""; } diff --git a/Order.struct.h b/Order.struct.h index 0f7e11009..563871e63 100644 --- a/Order.struct.h +++ b/Order.struct.h @@ -33,6 +33,7 @@ // Includes. #include "Data.struct.h" #include "Order.enum.h" +#include "Platform.extern.h" #include "Serializer/Serializer.h" #include "SymbolInfo.struct.static.h" #include "Terminal.mqh" @@ -139,7 +140,8 @@ struct OrderParams { // s.Pass(THIS_REF, "cond_args", cond_args); return SerializerNodeObject; } - } cond_close[]; + }; + ARRAY(OrderCloseCond, cond_close); bool dummy; // Whether order is dummy (fake) or not (real). color color_arrow; // Color of the opening arrow on the chart. unsigned short refresh_freq; // How often to refresh order values (in secs). @@ -152,7 +154,7 @@ struct OrderParams { T Get(ENUM_ORDER_PARAM _param, int _index1 = 0, int _index2 = 0) { switch (_param) { case ORDER_PARAM_COLOR_ARROW: - return (T)color_arrow; + return (T)(unsigned int)color_arrow; case ORDER_PARAM_COND_CLOSE: return (T)cond_close[_index1].cond; case ORDER_PARAM_COND_CLOSE_ARG_VALUE: @@ -165,6 +167,9 @@ struct OrderParams { return (T)refresh_freq; case ORDER_PARAM_UPDATE_FREQ: return (T)update_freq; + default: + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; } SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; @@ -180,7 +185,7 @@ struct OrderParams { void Set(ENUM_ORDER_PARAM _param, T _value, int _index1 = 0, int _index2 = 0) { switch (_param) { case ORDER_PARAM_COLOR_ARROW: - color_arrow = (color)_value; + color_arrow = (color)(unsigned int)_value; return; case ORDER_PARAM_COND_CLOSE: SetConditionClose((ENUM_ORDER_CONDITION)_value, _index1); @@ -197,11 +202,13 @@ struct OrderParams { case ORDER_PARAM_UPDATE_FREQ: update_freq = (unsigned short)_value; return; + default: + SetUserError(ERR_INVALID_PARAMETER); } SetUserError(ERR_INVALID_PARAMETER); } void SetConditionClose(ENUM_ORDER_CONDITION _cond, int _index = 0) { - DataParamEntry _args[]; + ARRAY(DataParamEntry, _args); SetConditionClose(_cond, _args, _index); } void SetConditionClose(ENUM_ORDER_CONDITION _cond, ARRAY_REF(DataParamEntry, _args), int _index = 0) { @@ -230,12 +237,7 @@ struct OrderData { unsigned long position_by_id; // Position By ID. unsigned long ticket; // Ticket number. ENUM_ORDER_STATE state; // State. - datetime time_closed; // Closed time. - datetime time_done; // Execution/cancellation time. - datetime time_expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type). - datetime time_setup; // Setup time. - datetime time_last_refresh; // Last refresh of order values. - datetime time_last_update; // Last update of order stops. + string comment; // Comment. double commission; // Commission. double profit; // Profit. double total_profit; // Total profit (profit minus fees). @@ -244,11 +246,17 @@ struct OrderData { double price_current; // Current price. double price_stoplimit; // The limit order price for the StopLimit order. double swap; // Order cumulative swap. + datetime time_closed; // Closed time. + datetime time_done; // Execution/cancellation time. + long time_done_msc; // The time of execution/cancellation time (in msc). + datetime time_expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type). + datetime time_last_refresh; // Last refresh of order values. + datetime time_last_update; // Last update of order stops. + datetime time_setup; // Setup time. + long time_setup_msc; // The time of placing the order (in msc). double total_fees; // Total fees. double sl; // Current Stop loss level of the order. double tp; // Current Take Profit level of the order. - long time_setup_msc; // The time of placing the order (in msc). - long time_done_msc; // The time of execution/cancellation time (in msc). ENUM_ORDER_TYPE type; // Type. ENUM_ORDER_TYPE_FILLING type_filling; // Filling type. ENUM_ORDER_TYPE_TIME type_time; // Lifetime (the order validity period). @@ -256,11 +264,10 @@ struct OrderData { ENUM_ORDER_REASON_CLOSE reason_close; // Reason or source for closing an order. unsigned int close_tries; // Number of close tries. unsigned int last_error; // Last error code. - double volume_curr; // Current volume. - double volume_init; // Initial volume. - string comment; // Comment. string ext_id; // External trading system identifier. string symbol; // Symbol of the order. + double volume_curr; // Current volume. + double volume_init; // Initial volume. public: OrderData() : close_tries(0), @@ -292,11 +299,10 @@ struct OrderData { volume_curr(0), volume_init(0) {} // Copy constructor. - OrderData(OrderData &_odata) { this = _odata; } + OrderData(OrderData &_odata) { THIS_REF = _odata; } // Getters. template T Get(ENUM_ORDER_PROPERTY_CUSTOM _prop_name) { - double _tick_value = SymbolInfoStatic::GetTickValue(symbol); switch (_prop_name) { case ORDER_PROP_CLOSE_TRIES: return (T)close_tries; @@ -332,6 +338,9 @@ struct OrderData { return (T)time_done; case ORDER_PROP_TOTAL_FEES: return (T)total_fees; + default: + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; } SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; @@ -368,13 +377,13 @@ struct OrderData { case ORDER_STATE: return (T)state; case ORDER_TIME_EXPIRATION: - return (T)time_expiration; + return (T)(long)time_expiration; case ORDER_TIME_DONE: - return (T)time_done; + return (T)(long)time_done; case ORDER_TIME_DONE_MSC: return (T)time_done_msc; case ORDER_TIME_SETUP: - return (T)time_setup; + return (T)(long)time_setup; case ORDER_TIME_SETUP_MSC: return (T)time_setup_msc; case ORDER_TYPE_FILLING: @@ -530,7 +539,7 @@ struct OrderData { profit = (double)_value; return; case ORDER_PROP_REASON_CLOSE: - reason_close = (ENUM_ORDER_REASON_CLOSE)_value; + reason_close = (ENUM_ORDER_REASON_CLOSE)(long)_value; return; case ORDER_PROP_TICKET: ticket = (unsigned long)_value; @@ -550,6 +559,8 @@ struct OrderData { case ORDER_PROP_TOTAL_FEES: total_fees = (double)_value; return; + default: + SetUserError(ERR_INVALID_PARAMETER); } SetUserError(ERR_INVALID_PARAMETER); } diff --git a/OrderQuery.h b/OrderQuery.h index 8dfa8c22c..b81bf9799 100644 --- a/OrderQuery.h +++ b/OrderQuery.h @@ -62,8 +62,8 @@ class OrderQuery : public Dynamic { template T CalcSumByProp(E _prop) { T _sum = 0; - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { - _sum += iter.Value().Ptr().Get(_prop); + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { + _sum += iter.Value() REF_DEREF Get(_prop); } return _sum; } @@ -77,10 +77,10 @@ class OrderQuery : public Dynamic { template T CalcSumByPropWithCond(E _prop, ECT _prop_cond_type, ECV _prop_cond_value) { T _sum = 0; - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { Order *_order = iter.Value().Ptr(); - if (_order.Get(_prop_cond_type) == _prop_cond_value) { - _sum += _order.Get(_prop); + if (_order PTR_DEREF Get(_prop_cond_type) == _prop_cond_value) { + _sum += _order PTR_DEREF Get(_prop); } } return _sum; @@ -96,13 +96,13 @@ class OrderQuery : public Dynamic { template Ref FindByPropViaOp(E _prop, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP) _op) { Ref _order_ref_found; - if (orders.Size() == 0) { + if (orders PTR_DEREF Size() == 0) { return _order_ref_found; } - _order_ref_found = orders.Begin().Value(); - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { + _order_ref_found = orders PTR_DEREF Begin().Value(); + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { Ref _order_ref = iter.Value(); - if (Compare(_order_ref.Ptr().Get(_prop), _op, _order_ref_found.Ptr().Get(_prop))) { + if (Compare(_order_ref REF_DEREF Get(_prop), _op, _order_ref_found REF_DEREF Get(_prop))) { _order_ref_found = _order_ref; } } @@ -119,12 +119,12 @@ class OrderQuery : public Dynamic { template Ref FindByValueViaOp(E _prop, T _value, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP) _op) { Ref _order_ref_found; - if (orders.Size() == 0) { + if (orders PTR_DEREF Size() == 0) { return _order_ref_found; } - for (DictStructIterator> iter = orders.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator> iter = orders PTR_DEREF Begin(); iter.IsValid(); ++iter) { Ref _order_ref = iter.Value(); - if (Compare(_order_ref.Ptr().Get(_prop), _op, _value)) { + if (Compare(_order_ref REF_DEREF Get(_prop), _op, _value)) { _order_ref_found = _order_ref; break; } diff --git a/Orders.mqh b/Orders.mqh index 0767fdc44..2872f261d 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -25,7 +25,7 @@ class Orders; // Includes. #include "Account/Account.h" -#include "Chart.mqh" +#include "Chart.struct.static.h" #include "Log.mqh" #include "Math.h" #include "Order.mqh" @@ -79,7 +79,7 @@ class Orders { // Enum variables. ENUM_ORDERS_POOL pool; // Struct variables. - Order *orders[]; + ARRAY(Order *, orders); // Class variables. Ref logger; // Market *market; @@ -108,7 +108,7 @@ class Orders { orders[_size] = new Order(_req); return true; } else { - Logger().Error("Cannot allocate the memory.", __FUNCTION__); + Logger() PTR_DEREF Error("Cannot allocate the memory.", __FUNCTION__); return false; } } @@ -120,7 +120,7 @@ class Orders { */ Order *SelectOrder(unsigned long _ticket) { for (unsigned int _pos = ArraySize(orders); _pos >= 0; _pos--) { - if (orders[_pos].Get(ORDER_PROP_TICKET) == _ticket) { + if (orders[_pos] PTR_DEREF Get(ORDER_PROP_TICKET) == _ticket) { return orders[_pos]; } } @@ -140,7 +140,7 @@ class Orders { ArrayResize(orders, _size + 1, 100); return orders[_size] = new Order(_ticket); } - Logger().Error(StringFormat("Cannot select order (ticket=#%d)!", _ticket), __FUNCTION__); + Logger() PTR_DEREF Error(StringFormat("Cannot select order (ticket=#%d)!", _ticket), __FUNCTION__); return NULL; } @@ -149,10 +149,10 @@ class Orders { /** * Calculate number of lots for open positions. */ - static double GetOpenLots(string _symbol = NULL, long magic_number = 0, int magic_range = 0) { + static double GetOpenLots(string _symbol = NULL_STRING, long magic_number = 0, int magic_range = 0) { double total_lots = 0; // @todo: Convert to MQL5. - _symbol = _symbol != NULL ? _symbol : _Symbol; + _symbol = _symbol != NULL_STRING ? _symbol : _Symbol; for (int i = 0; i < OrdersTotal(); i++) { if (Order::TryOrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break; if (Order::OrderSymbol() == _symbol) { @@ -174,7 +174,7 @@ class Orders { * Returns sum of all stop loss or profit take points * from all opened orders for the given symbol. */ - static double TotalSLTP(ENUM_ORDER_TYPE _cmd = NULL, bool sl = true) { + static double TotalSLTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, bool sl = true) { double total_buy_sl = 0, total_buy_tp = 0; double total_sell_sl = 0, total_sell_tp = 0; // @todo: Convert to MQL5. @@ -184,7 +184,7 @@ class Orders { // Terminal::GetErrorText(GetLastError())); break; } - if (Order::OrderSymbol() == _Symbol) { + if (Order::OrderSymbol() == (string)_Symbol) { double order_tp = Order::OrderTakeProfit(); double order_sl = Order::OrderStopLoss(); switch (Order::OrderType()) { @@ -204,6 +204,9 @@ class Orders { // PrintFormat("%s:%d%d: OP_SELL: TP=%g, SL=%g, total: %g/%g", __FUNCTION__, i, OrdersTotal(), order_tp, // order_sl, total_sell_sl, total_sell_tp); break; + default: + RUNTIME_ERROR("Not supported order type!"); + return 0; } } } @@ -220,7 +223,7 @@ class Orders { /** * Get sum of total stop loss values of opened orders. */ - double TotalSL(ENUM_ORDER_TYPE _cmd = NULL) { return TotalSLTP(_cmd, true); } + double TotalSL(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return TotalSLTP(_cmd, true); } /** * Get sum of total take profit values of opened orders. @@ -228,7 +231,7 @@ class Orders { * @return * Returns total take profit points. */ - double TotalTP(ENUM_ORDER_TYPE _cmd = NULL) { return TotalSLTP(_cmd, false); } + double TotalTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return TotalSLTP(_cmd, false); } /** * Get ratio of total stop loss points. @@ -236,7 +239,7 @@ class Orders { * @return * Returns ratio between 0 and 1. */ - double RatioSL(ENUM_ORDER_TYPE _cmd = NULL) { + double RatioSL(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return 1.0 / fmax(TotalSL(_cmd) + TotalTP(_cmd), 0.01) * TotalSL(_cmd); } @@ -246,7 +249,7 @@ class Orders { * @return * Returns ratio between 0 and 1. */ - double RatioTP(ENUM_ORDER_TYPE _cmd = NULL) { + double RatioTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return 1.0 / fmax(TotalSL(_cmd) + TotalTP(_cmd), 0.01) * TotalTP(_cmd); } @@ -256,16 +259,16 @@ class Orders { * @return * Returns sum of all lots from all opened orders. */ - double TotalLots(ENUM_ORDER_TYPE _cmd = NULL) { + double TotalLots(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { double buy_lots = 0, sell_lots = 0; // @todo: Convert to MQL5. for (int i = 0; i < OrdersTotal(); i++) { if (!Order::OrderSelect(i, SELECT_BY_POS)) { - Logger().Error(StringFormat("OrderSelect (%d) returned the error", i), __FUNCTION__, - Terminal::GetErrorText(GetLastError())); + Logger() PTR_DEREF Error(StringFormat("OrderSelect (%d) returned the error", i), __FUNCTION__, + Terminal::GetErrorText(GetLastError())); break; } - if (Order::OrderSymbol() == _Symbol) { + if (Order::OrderSymbol() == (string)_Symbol) { switch (Order::OrderType()) { case ORDER_TYPE_BUY: buy_lots += Order::OrderLots(); @@ -273,6 +276,9 @@ class Orders { case ORDER_TYPE_SELL: sell_lots += Order::OrderLots(); break; + default: + RUNTIME_ERROR("Not supported order type!"); + return 0; } } } @@ -300,7 +306,7 @@ class Orders { } else if (_sell_lots > 0 && _sell_lots > _buy_lots) { return ORDER_TYPE_SELL; } else { - return NULL; + return ORDER_TYPE_UNSET; } } @@ -534,7 +540,7 @@ class Orders { */ static unsigned int GetOrdersByType(ENUM_ORDER_TYPE _cmd, string _symbol = NULL) { unsigned int _counter = 0; - _symbol = _symbol != NULL ? _symbol : _Symbol; + _symbol = _symbol != NULL_STRING ? _symbol : _Symbol; for (int i = 0; i < OrdersTotal(); i++) { if (Order::TryOrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break; if (Order::OrderSymbol() == _symbol) { diff --git a/Platform.define.h b/Platform.define.h new file mode 100644 index 000000000..31d4919e3 --- /dev/null +++ b/Platform.define.h @@ -0,0 +1,30 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Defines. +#define PLATFORM_WRONG_SYMBOL "" +#define PLATFORM_WRONG_TIMEFRAME ((ENUM_TIMEFRAMES)INT_MAX) diff --git a/Platform.extern.h b/Platform.extern.h new file mode 100644 index 000000000..11edea715 --- /dev/null +++ b/Platform.extern.h @@ -0,0 +1,172 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once + +// Includes. +#include "Account/Account.enum.h" +#include "Data.define.h" +#include "Deal.enum.h" +#include "Object.extern.h" +#include "Order.define.h" +#include "Terminal.enum.h" + +// Forward declarations. +struct MqlTradeRequest; +struct MqlTradeResult; +struct MqlTradeCheckResult; + +template +double iCustom(string symbol, int timeframe, string name, Args... args) { + Alert(__FUNCSIG__, " it not implemented!"); + return 0; +} + +/** + * Returns number of candles for a given symbol and time-frame. + */ +extern int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf); + +/** + * Returns the number of calculated data for the specified indicator. + */ +extern int BarsCalculated(int indicator_handle); + +/** + * Gets data of a specified buffer of a certain indicator in the necessary quantity. + */ +extern int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)); + +extern int CopyOpen(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); +extern int CopyHigh(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); +extern int CopyLow(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); +extern int CopyClose(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(double, close_array)); + +extern unsigned int64 PositionGetTicket(int _index); + +extern int64 PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id); + +extern double PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE property_id); + +extern string PositionGetString(ENUM_POSITION_PROPERTY_STRING property_id); + +extern int HistoryDealsTotal(); + +extern unsigned int64 HistoryDealGetTicket(int index); + +extern int64 HistoryDealGetInteger(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id); + +extern double HistoryDealGetDouble(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id); + +extern string HistoryDealGetString(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_STRING property_id); + +extern bool OrderSelect(int index); + +extern bool PositionSelectByTicket(int index); + +extern bool HistoryOrderSelect(int index); + +extern bool OrderSend(const MqlTradeRequest& request, MqlTradeResult& result); + +extern bool OrderCheck(const MqlTradeRequest& request, MqlTradeCheckResult& result); + +extern unsigned int64 OrderGetTicket(int index); + +extern unsigned int64 HistoryOrderGetTicket(int index); + +extern bool HistorySelectByPosition(int64 position_id); + +extern bool HistoryDealSelect(unsigned int64 ticket); + +extern int64 OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id); + +extern int64 HistoryOrderGetInteger(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id); + +extern double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property_id); + +extern double HistoryOrderGetDouble(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id); + +string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id); + +string HistoryOrderGetString(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_STRING property_id); + +extern int PositionsTotal(); + +extern bool HistorySelect(datetime from_date, datetime to_date); + +extern int HistoryOrdersTotal(); + +extern int OrdersTotal(); + +extern int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(int64, arr)); + +extern int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, + ARRAY_REF(int64, arr)); + +extern int ChartID(); + +extern bool OrderCalcMargin(ENUM_ORDER_TYPE _action, string _symbol, double _volume, double _price, double& _margin); + +extern double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id); + +extern int64 AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id); + +extern string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id); + +extern string Symbol(); + +extern string ObjectName(int64 _chart_id, int _pos, int _sub_window = -1, int _type = -1); + +extern int ObjectsTotal(int64 chart_id, int type = EMPTY, int window = -1); + +extern bool PlotIndexSetString(int plot_index, int prop_id, string prop_value); + +extern bool PlotIndexSetInteger(int plot_index, int prop_id, int prop_value); + +extern bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int64 prop_value); + +extern bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, + int64 prop_value); + +extern bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value); + +extern bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, + double prop_value); + +extern bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1); +extern bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, + datetime _t2, double _p2); + +extern bool ObjectMove(int64 chart_id, string name, int point_index, datetime time, double price); + +extern bool ObjectDelete(int64 chart_id, string name); + +extern int ObjectFind(int64 chart_id, string name); + +#endif diff --git a/Platform.h b/Platform.h index 14da7148f..8acf63a4e 100644 --- a/Platform.h +++ b/Platform.h @@ -20,23 +20,47 @@ * */ +#ifndef __MQL__ + // Allows the preprocessor to include a header file when it is needed. + #pragma once + + // Includes. + #include "Deal.enum.h" + #include "Order.struct.h" + #include "Platform.define.h" + +/** + * Extern declarations for C++. + */ + +/** + * Returns number of candles for a given symbol and time-frame. + */ +extern int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf); + +#endif + // Includes. /** * Current platform's static methods. */ +#include "DrawIndicator.mqh" #include "Flags.h" #include "Indicator/IndicatorData.h" #include "Indicator/tests/classes/IndicatorTfDummy.h" #include "Std.h" #ifdef __MQLBUILD__ -#include "Indicators/Tick/Indi_TickMt.mqh" -#define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickMt + #include "Indicators/Tf/Indi_TfMt.h" + #include "Indicators/Tick/Indi_TickMt.mqh" + #define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickMt + #define PLATFORM_DEFAULT_INDICATOR_TF Indi_TfMt #else -#include "Indicators/Tick/Indi_TickRandom.mqh" -#define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickRandom + #include "Indicators/Tick/Indi_TickProvider.h" + #define PLATFORM_DEFAULT_INDICATOR_TICK Indi_TickRandom + #define PLATFORM_DEFAULT_INDICATOR_TF IndicatorTfDummy #endif #include "SymbolInfo.struct.static.h" @@ -65,6 +89,15 @@ class Platform { // List of default Candle/Tick indicators. static DictStruct> indis_dflt; + // Result of the last tick. + static bool last_tick_result; + + // Symbol of the currently ticking indicator. + static string symbol; + + // Timeframe of the currently ticking indicator. + static ENUM_TIMEFRAMES period; + public: /** * Initializes platform. @@ -76,9 +109,6 @@ class Platform { } initialized = true; - - // Starting from current timestamp. - time.Update(); } /** @@ -90,20 +120,50 @@ class Platform { * Performs tick on every added indicator. */ static void Tick() { + // @todo Should update time for each ticking indicator and only when it signal a tick. + PlatformTime::Tick(); + time.Update(); + // Checking starting periods and updating time to current one. time_flags = time.GetStartedPeriods(); - time.Update(); DictStructIterator> _iter; + last_tick_result = false; + for (_iter = indis.Begin(); _iter.IsValid(); ++_iter) { - _iter.Value() REF_DEREF Tick(global_tick_index); + // Print("Ticking ", _iter.Value() REF_DEREF GetFullName()); + // Updating current symbol and timeframe to the ones used by ticking indicator and its parents. + symbol = _iter.Value() REF_DEREF GetSymbol(); + period = _iter.Value() REF_DEREF GetTf(); + +#ifdef __debug__ + PrintFormat("Tick #%d for %s for symbol %s and period %s", global_tick_index, + C_STR(_iter.Value() REF_DEREF GetFullName()), C_STR(symbol), C_STR(ChartTf::TfToString(period))); +#endif + + last_tick_result |= _iter.Value() REF_DEREF Tick(global_tick_index); } for (_iter = indis_dflt.Begin(); _iter.IsValid(); ++_iter) { - _iter.Value() REF_DEREF Tick(global_tick_index); + // Updating current symbol and timeframe to the ones used by ticking indicator and its parents. + symbol = (_iter.Value() REF_DEREF GetTick(false) != nullptr) ? _iter.Value() REF_DEREF GetSymbol() + : PLATFORM_WRONG_SYMBOL; + period = (_iter.Value() REF_DEREF GetCandle(false) != nullptr) ? _iter.Value() REF_DEREF GetTf() + : PLATFORM_WRONG_TIMEFRAME; + +#ifdef __debug__ + PrintFormat("Tick #%d for %s for symbol %s and period %s", global_tick_index, + C_STR(_iter.Value() REF_DEREF GetFullName()), C_STR(symbol), C_STR(ChartTf::TfToString(period))); +#endif + + last_tick_result |= _iter.Value() REF_DEREF Tick(global_tick_index); } + // Clearing symbol and period in order to signal retrieving symbol/period outside the ticking indicator. + symbol = PLATFORM_WRONG_SYMBOL; + period = PLATFORM_WRONG_TIMEFRAME; + // Will check for new time periods in consecutive Platform::UpdateTime(). time_clear_flags = true; @@ -119,30 +179,10 @@ class Platform { * via Platform::Add...(). */ static void OnCalculate(const int rates_total, const int prev_calculated) { - if (!emitted_history) { - for (DictStructIterator> _iter = indis.Begin(); _iter.IsValid(); ++_iter) { - EmitHistory(_iter.Value().Ptr()); - } - emitted_history = true; - } - // We're ready for a tick. Tick(); } - /** - * Emits history for parent indicators in hierarchy and then for the indicator itself. - */ - static void EmitHistory(IndicatorData *_indi) { - IndicatorData *_parent = _indi PTR_DEREF GetDataSource(false); - - if (_parent != nullptr) { - EmitHistory(_parent); - } - - _indi PTR_DEREF EmitHistory(); - } - /** * Returns dictionary of added indicators (keyed by unique id). */ @@ -153,14 +193,24 @@ class Platform { */ static void Add(IndicatorData *_indi) { Ref _ref = _indi; + + DictStructIterator> _iter; + for (_iter = indis_dflt.Begin(); _iter.IsValid(); ++_iter) { + if (_iter.Value() == _ref) { + Alert("Warning: ", _indi PTR_DEREF GetFullName(), + " was already added as default candle/tick indicator and shouldn't be added by Platform:Add() as default " + "indicators are also ticked when calling Platform::Tick()."); + DebugBreak(); + } + } + indis.Set(_indi PTR_DEREF GetId(), _ref); } /** * Adds indicator to be processed by platform and tries to initialize its data source(s). */ - static void AddWithDefaultBindings(IndicatorData *_indi, CONST_REF_TO(string) _symbol = "", - ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { + static void AddWithDefaultBindings(IndicatorData *_indi, CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { Add(_indi); BindDefaultDataSource(_indi, _symbol, _tf); } @@ -215,6 +265,30 @@ class Platform { */ static bool IsNewYear() { return (time_flags & DATETIME_YEAR) != 0; } + /** + * Returns number of candles for a given symbol and time-frame. + */ + static int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; + } + + /** + * Returns the number of calculated data for the specified indicator. + */ + static int BarsCalculated(int indicator_handle) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; + } + + /** + * Returns id of the current chart. + */ + static int ChartID() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; + } + /** * Binds Candle and/or Tick indicator as a source of prices or data for given indicator. * @@ -261,29 +335,37 @@ class Platform { /** * Returns default Candle-compatible indicator for current platform for given symbol and TF. */ - static IndicatorData *FetchDefaultCandleIndicator(string _symbol = "", ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { - if (_symbol == "") { - _symbol = _Symbol; + static IndicatorData *FetchDefaultCandleIndicator(string _symbol, ENUM_TIMEFRAMES _tf) { + if (_symbol == PLATFORM_WRONG_SYMBOL) { + Print("Cannot fetch default candle indicator for unknown symbol \"", _symbol, "\" (passed TF value ", (int)_tf, + ")!"); + DebugBreak(); } - if (_tf == PERIOD_CURRENT) { - _tf = (ENUM_TIMEFRAMES)Period(); + if (_tf == PERIOD_CURRENT || _tf == PLATFORM_WRONG_TIMEFRAME) { + Print("Cannot fetch default candle indicator for unknown period/timeframe (passed symbol \"", _symbol, + "\", TF value ", (int)_tf, ")!"); + DebugBreak(); } // Candle is per symbol and TF. Single Candle indicator can't handle multiple TFs. string _key = Util::MakeKey("PlatformIndicatorCandle", _symbol, (int)_tf); IndicatorData *_indi_candle; if (!Objects::TryGet(_key, _indi_candle)) { - _indi_candle = Objects::Set(_key, new IndicatorTfDummy(_tf)); + _indi_candle = Objects::Set(_key, new PLATFORM_DEFAULT_INDICATOR_TF(_tf)); // Adding indicator to list of default indicators in order to tick it on every Tick() call. Ref _ref = _indi_candle; indis_dflt.Set(_indi_candle PTR_DEREF GetId(), _ref); - } - if (!_indi_candle PTR_DEREF HasDataSource()) { - // Missing tick indicator. - _indi_candle PTR_DEREF InjectDataSource(FetchDefaultTickIndicator(_symbol)); + if (!_indi_candle PTR_DEREF HasDataSource()) { + // Missing tick indicator. + _indi_candle PTR_DEREF InjectDataSource(FetchDefaultTickIndicator(_symbol)); + } +#ifdef __debug__ + Print("Added default candle indicator for symbol ", _symbol, " and time-frame ", _tf, ". Now it has symbol ", + _indi_candle PTR_DEREF GetSymbol(), " and time-frame ", EnumToString(_indi_candle PTR_DEREF GetTf())); +#endif } return _indi_candle; @@ -292,9 +374,10 @@ class Platform { /** * Returns default Tick-compatible indicator for current platform for given symbol. */ - static IndicatorData *FetchDefaultTickIndicator(string _symbol = "") { - if (_symbol == "") { - _symbol = _Symbol; + static IndicatorData *FetchDefaultTickIndicator(string _symbol) { + if (_symbol == PLATFORM_WRONG_SYMBOL) { + Alert("Cannot fetch default tick indicator for unknown symbol!"); + DebugBreak(); } string _key = Util::MakeKey("PlatformIndicatorTick", _symbol); @@ -347,18 +430,412 @@ class Platform { } return _result; } + + /** + * Returns symbol of the currently ticking indicator. + **/ + static string GetSymbol() { + if (symbol == PLATFORM_WRONG_SYMBOL) { + RUNTIME_ERROR("Retrieving symbol outside the OnTick() of the currently ticking indicator is prohibited!"); + } + return symbol; + } + + /** + * Returns timeframe of the currently ticking indicator. + **/ + static ENUM_TIMEFRAMES GetPeriod() { + if (period == PLATFORM_WRONG_TIMEFRAME) { + RUNTIME_ERROR( + "Retrieving period/timeframe outside the OnTick() of the currently ticking indicator is prohibited!"); + } + + return period; + } + + private: + /** + * Sets symbol of the currently ticking indicator. + **/ + static void SetSymbol(string _symbol) { symbol = _symbol; } + + /** + * Sets timeframe of the currently ticking indicator. + **/ + static void SetPeriod(ENUM_TIMEFRAMES _period) { period = _period; } }; bool Platform::initialized = false; -DateTime Platform::time = 0; +bool Platform::last_tick_result = false; +DateTime Platform::time = (datetime)0; unsigned int Platform::time_flags = 0; bool Platform::time_clear_flags = true; int Platform::global_tick_index = 0; -bool Platform::emitted_history = false; +string Platform::symbol = PLATFORM_WRONG_SYMBOL; +ENUM_TIMEFRAMES Platform::period = PLATFORM_WRONG_TIMEFRAME; DictStruct> Platform::indis; DictStruct> Platform::indis_dflt; -// void OnTimer() { Print("Timer"); Platform::OnTimer(); } +#ifndef __MQL__ +// Following methods must be there are they're externed in Platform.extern.h +// and there's no better place for them! + +/** + * Returns number of candles for a given symbol and time-frame. + */ +int Bars(CONST_REF_TO(string) _symbol, ENUM_TIMEFRAMES _tf) { return Platform::Bars(_symbol, _tf); } + +/** + * Returns the number of calculated data for the specified indicator. + */ +int BarsCalculated(int indicator_handle) { return Platform::BarsCalculated(indicator_handle); } + +/** + * Gets data of a specified buffer of a certain indicator in the necessary quantity. + */ +int CopyBuffer(int indicator_handle, int buffer_num, int start_pos, int count, ARRAY_REF(double, buffer)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +unsigned int64 PositionGetTicket(int _index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int64 PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +string PositionGetString(ENUM_POSITION_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return ""; +} + +int HistoryDealsTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +unsigned int64 HistoryDealGetTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int64 HistoryDealGetInteger(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double HistoryDealGetDouble(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +string HistoryDealGetString(unsigned int64 ticket_number, ENUM_DEAL_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return 0; +} + +bool OrderSelect(int index, int select, int pool = MODE_TRADES) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool PositionSelectByTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool HistoryOrderSelect(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool OrderSend(const MqlTradeRequest &request, MqlTradeResult &result) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool OrderCheck(const MqlTradeRequest &request, MqlTradeCheckResult &result) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +unsigned int64 OrderGetTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +unsigned int64 HistoryOrderGetTicket(int index) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +bool HistorySelectByPosition(int64 position_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool HistoryDealSelect(unsigned int64 ticket) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +int64 OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int64 HistoryOrderGetInteger(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +double HistoryOrderGetDouble(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return 0; +} + +string HistoryOrderGetString(unsigned int64 ticket_number, ENUM_ORDER_PROPERTY_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return 0; +} + +int PositionsTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +bool HistorySelect(datetime from_date, datetime to_date) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return 0; +} + +int HistoryOrdersTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int OrdersTotal() { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyOpen(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyHigh(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyLow(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyClose(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(double, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyTickVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(int64, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int CopyRealVolume(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(int64, arr)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +int ChartID() { return Platform::ChartID(); } + +bool OrderCalcMargin(ENUM_ORDER_TYPE _action, string _symbol, double _volume, double _price, double &_margin) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return false; +} + +int64 AccountInfoInteger(ENUM_ACCOUNT_INFO_INTEGER property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return false; +} + +string AccountInfoInteger(ENUM_ACCOUNT_INFO_STRING property_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return ""; +} + +string Symbol() { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return ""; +} + +string ObjectName(int64 _chart_id, int _pos, int _sub_window, int _type) { + Print("Not yet implemented: ", __FUNCTION__, " returns empty string."); + return ""; +} + +int ObjectsTotal(int64 chart_id, int type, int window) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +bool PlotIndexSetString(int plot_index, int prop_id, string prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool PlotIndexSetInteger(int plot_index, int prop_id, int prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int64 prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetInteger(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_INTEGER prop_id, int prop_modifier, + int64 prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, double prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectSetDouble(int64 chart_id, string name, ENUM_OBJECT_PROPERTY_DOUBLE prop_id, int prop_modifier, + double prop_value) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectCreate(int64 _cid, string _name, ENUM_OBJECT _otype, int _swindow, datetime _t1, double _p1, datetime _t2, + double _p2) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectMove(int64 chart_id, string name, int point_index, datetime time, double price) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool ObjectDelete(int64 chart_id, string name) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +int GetLastError() { return _LastError; } + +void ResetLastError() { _LastError = 0; } + +int ObjectFind(int64 chart_id, string name) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +string TimeToString(datetime value, int mode) { + static std::stringstream ss; + ss.clear(); + ss.str(""); + + std::time_t time = value; + std::tm *ptm = std::localtime(&time); + char date[16], minutes[16], seconds[16]; + std::strftime(date, 32, "%Y.%m.%d", ptm); + std::strftime(minutes, 32, "%H:%M", ptm); + std::strftime(seconds, 32, "%S", ptm); + + if (mode & TIME_DATE) ss << date; + + if (mode & TIME_MINUTES) { + if (mode & TIME_DATE) { + ss << " "; + } + ss << minutes; + } + + if (mode & TIME_SECONDS) { + if (mode & TIME_DATE && !(mode & TIME_MINUTES)) { + ss << " "; + } else if (mode & TIME_MINUTES) { + ss << ":"; + } + ss << seconds; + } + + return ss.str(); +} + +bool TimeToStruct(datetime dt, MqlDateTime &dt_struct) { + time_t now = (time_t)dt; + + tm *ltm = localtime(&now); + + dt_struct.day = ltm->tm_mday; + dt_struct.day_of_week = ltm->tm_wday; + dt_struct.day_of_year = ltm->tm_yday; + dt_struct.hour = ltm->tm_hour; + dt_struct.min = ltm->tm_min; + dt_struct.mon = ltm->tm_mon; + dt_struct.sec = ltm->tm_sec; + dt_struct.year = ltm->tm_year; + + return true; +} + +SymbolGetter::operator string() const { return Platform::GetSymbol(); } + +ENUM_TIMEFRAMES Period() { return Platform::GetPeriod(); } + +datetime StructToTime(MqlDateTime &dt_struct) { + tm ltm; + ltm.tm_mday = dt_struct.day; + ltm.tm_wday = dt_struct.day_of_week; + ltm.tm_yday = dt_struct.day_of_year; + ltm.tm_hour = dt_struct.hour; + ltm.tm_min = dt_struct.min; + ltm.tm_mon = dt_struct.mon; + ltm.tm_sec = dt_struct.sec; + ltm.tm_year = dt_struct.year; + + return mktime(<m); +} + +#endif /** * Will test given indicator class with platform-default data source bindings. @@ -368,7 +845,7 @@ DictStruct> Platform::indis_dflt; \ int OnInit() { \ Platform::Init(); \ - Platform::AddWithDefaultBindings(indi.Ptr()); \ + Platform::AddWithDefaultBindings(indi.Ptr(), "EURUSD", PERIOD_M1); \ bool _result = true; \ assertTrueOrFail(indi REF_DEREF IsValid(), "Error on IsValid!"); \ return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); \ @@ -380,7 +857,7 @@ DictStruct> Platform::indis_dflt; IndicatorDataEntry _entry = indi REF_DEREF GetEntry(); \ bool _is_ready = indi REF_DEREF Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)); \ bool _is_valid = _entry.IsValid(); \ - Print(indi REF_DEREF ToString(), _is_ready ? "" : " (Not yet ready)"); \ + Print(indi REF_DEREF ToString(), _is_ready ? " (Ready)" : " (Not yet ready)"); \ if (_is_ready && !_is_valid) { \ Print(indi REF_DEREF ToString(), " (Invalid entry!)"); \ assertTrueOrExit(_entry.IsValid(), "Invalid entry!"); \ diff --git a/PlatformTime.h b/PlatformTime.h new file mode 100644 index 000000000..5cad5dd3c --- /dev/null +++ b/PlatformTime.h @@ -0,0 +1,89 @@ +//+------------------------------------------------------------------+ +//| 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 + * Platform time retrieval. + */ +#ifndef __MQL__ +#pragma once + +// Includes. +#include +#include + +#include "DateTime.struct.h" +#endif + +#include "Std.h" + +class PlatformTime { + static MqlDateTime current_time; + static int64 current_timestamp_s; + static int64 current_timestamp_ms; + + public: + static int64 CurrentTimestamp() { return current_timestamp_s; } + static int64 CurrentTimestampMs() { return current_timestamp_ms; } + static MqlDateTime CurrentTime() { return current_time; } + + void static Tick() { +#ifdef __MQL__ + static int64 _last_timestamp_ms = 0; + + current_timestamp_s = ::TimeCurrent(current_time); + + current_timestamp_ms = (int64)GetTickCount(); + + if (_last_timestamp_ms != 0 && current_timestamp_ms < _last_timestamp_ms) { + // Overflow occured (49.7 days passed). + // More info: https://docs.mql4.com/common/gettickcount + current_timestamp_ms += _last_timestamp_ms; + } + + _last_timestamp_ms = current_timestamp_ms; +#else + using namespace std::chrono; + current_timestamp_s = (int64)duration_cast(system_clock::now().time_since_epoch()).count(); + current_timestamp_ms = (int64)duration_cast(system_clock::now().time_since_epoch()).count(); + + using namespace std::chrono; + std::time_t t = current_timestamp_s; + std::tm* now = std::localtime(&t); + current_time.day = now->tm_mday; + current_time.day_of_week = now->tm_wday; + current_time.day_of_year = now->tm_yday; + current_time.hour = now->tm_hour; + current_time.min = now->tm_min; + current_time.mon = now->tm_mon; + current_time.sec = now->tm_sec; + current_time.year = now->tm_year; +#endif + } +}; + +MqlDateTime PlatformTime::current_time = {0, 0, 0, 0, 0, 0, 0, 0}; +int64 PlatformTime::current_timestamp_s = 0; +int64 PlatformTime::current_timestamp_ms = 0; diff --git a/Refs.mqh b/Refs.mqh index 72f5f3044..0acc12d8c 100644 --- a/Refs.mqh +++ b/Refs.mqh @@ -130,6 +130,16 @@ class Dynamic { "side."); } } + + /** + * Returns text representation of the object. + */ + virtual string const ToString() { + if (ptr_ref_counter == nullptr) return ""; + + return StringFormat("%d strong ref(s) and %d weak ref(s)", ptr_ref_counter PTR_DEREF num_strong_refs, + ptr_ref_counter PTR_DEREF num_weak_refs); + } }; #endif diff --git a/Refs.struct.h b/Refs.struct.h index 1b0649250..8748b97ca 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -30,10 +30,13 @@ #pragma once #endif -// Includes. #include "Refs.rc.h" #include "Std.h" +#ifdef EMSCRIPTEN +#include +#endif + class Dynamic; // Forward class declaration. template @@ -97,21 +100,25 @@ struct Ref { */ X* ptr_object; +#ifdef EMSCRIPTEN + typedef X element_type; +#endif + public: /** * Constructor. */ - Ref(X* _ptr) { THIS_REF = _ptr; } + Ref(X* _ptr) : ptr_object(nullptr) { THIS_REF = _ptr; } /** * Constructor. */ - Ref(Ref& ref) { THIS_REF = ref.Ptr(); } + Ref(const Ref& ref) : ptr_object(nullptr) { Set(ref.Ptr()); } /** * Constructor. */ - Ref(WeakRef& ref) { THIS_REF = ref.Ptr(); } + Ref(WeakRef& ref) : ptr_object(nullptr) { Set(ref.Ptr()); } /** * Constructor. @@ -123,10 +130,21 @@ struct Ref { */ ~Ref() { Unset(); } +#ifndef __MQL__ + template + operator Ref() { + return Ref(ptr_object); + } +#endif + /** * Returns pointer to target object. */ - X* Ptr() { return ptr_object; } + X* Ptr() const { return ptr_object; } + +#ifdef EMSCRIPTEN + X* get() const { return ptr_object; } +#endif /** * Checks whether any object is referenced. @@ -208,7 +226,11 @@ struct Ref { /** * Makes a strong reference to the given object. */ - X* operator=(X* _ptr) { + X* operator=(X* _ptr) { return Set(_ptr); } + /** + * Makes a strong reference to the given object. + */ + X* Set(X* _ptr) { if (ptr_object == _ptr) { // Assigning the same object. return Ptr(); @@ -240,25 +262,35 @@ struct Ref { /** * Makes a strong reference to the given weakly-referenced object. */ - X* operator=(WeakRef& right) { - THIS_REF = right.Ptr(); - return Ptr(); - } + X* operator=(const WeakRef& right) { return Set((X*)right.Ptr()); } /** * Makes a strong reference to the strongly-referenced object. */ - X* operator=(Ref& right) { - THIS_REF = right.Ptr(); - return Ptr(); - } + X* operator=(const Ref& right) { return Set((X*)right.Ptr()); } /** * Equality operator. */ bool operator==(const Ref& r) { return ptr_object != NULL && ptr_object == r.ptr_object; } + + /** + * Returns information about object references counter. + */ + string ToString() { + if (ptr_object == nullptr) return "Empty pointer"; + + return ptr_object PTR_DEREF ToString(); + } }; +#ifdef __cplusplus +template +Ref make_ref(Types&&... Args) { + return new T(std::forward(Args)...); +} +#endif + /** * Class used to hold weak reference to reference-counted object. */ @@ -273,26 +305,26 @@ struct WeakRef { /** * Constructor. */ - WeakRef(X* _ptr = NULL) { this = _ptr; } + WeakRef(X* _ptr = NULL) : ptr_ref_counter(nullptr) { THIS_REF = _ptr; } /** * Constructor. */ - WeakRef(WeakRef& ref) { this = ref.Ptr(); } + WeakRef(const WeakRef& ref) : ptr_ref_counter(nullptr) { THIS_REF = ref.Ptr(); } /** * Constructor. */ - WeakRef(Ref& ref) { this = ref.Ptr(); } + WeakRef(Ref& ref) : ptr_ref_counter(nullptr) { THIS_REF = ref.Ptr(); } /** * Destructor. */ ~WeakRef() { Unset(); } - bool ObjectExists() { return ptr_ref_counter != NULL && !PTR_ATTRIB(ptr_ref_counter, deleted); } + bool ObjectExists() const { return ptr_ref_counter != NULL && !PTR_ATTRIB(ptr_ref_counter, deleted); } - X* Ptr() { return ObjectExists() ? (X*)(PTR_ATTRIB(ptr_ref_counter, ptr_object)) : NULL; } + X* Ptr() const { return ObjectExists() ? (X*)(PTR_ATTRIB(ptr_ref_counter, ptr_object)) : NULL; } /** * Makes a weak reference to the given object. @@ -330,7 +362,15 @@ struct WeakRef { * Makes a weak reference to the given weakly-referenced object. */ X* operator=(WeakRef& right) { - this = right.Ptr(); + THIS_REF = right.Ptr(); + return Ptr(); + } + + /** + * Makes a weak reference to the given weakly-referenced object. + */ + X* operator=(const WeakRef& right) { + THIS_REF = right.Ptr(); return Ptr(); } @@ -338,7 +378,15 @@ struct WeakRef { * Makes a weak reference to the strongly-referenced object. */ X* operator=(Ref& right) { - this = right.Ptr(); + THIS_REF = right.Ptr(); + return Ptr(); + } + + /** + * Makes a weak reference to the strongly-referenced object. + */ + X* operator=(const Ref& right) { + THIS_REF = right.Ptr(); return Ptr(); } diff --git a/Serializer/SerializerConverter.h b/Serializer/SerializerConverter.h index 3b6b5418e..f7aaf95ca 100644 --- a/Serializer/SerializerConverter.h +++ b/Serializer/SerializerConverter.h @@ -39,6 +39,10 @@ class SerializerNode; #include "SerializerDict.h" #include "SerializerNode.h" +#ifdef __debug_verbose__ +#include "SerializerJson.h" +#endif + class SerializerConverter { public: SerializerNode* root_node; @@ -47,7 +51,7 @@ class SerializerConverter { SerializerConverter(SerializerNode* _root = NULL, int serializer_flags = 0) : root_node(_root), _serializer_flags(serializer_flags) {} - SerializerConverter(SerializerConverter& right) { + SerializerConverter(const SerializerConverter& right) { root_node = right.root_node; _serializer_flags = right._serializer_flags; } @@ -68,10 +72,11 @@ class SerializerConverter { _serializer.FreeRootNodeOwnership(); _serializer.PassObject(_value, "", _value, SERIALIZER_FIELD_FLAG_VISIBLE); SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); -#ifdef __debug__ +#ifdef __debug_verbose__ Print("FromObject(): serializer flags: ", serializer_flags); - Print("FromObject(): result: ", - _serializer.GetRoot() != NULL ? _serializer.GetRoot().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); + Print("FromObject(): result: ", _serializer.GetRoot() != NULL + ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) + : "NULL"); #endif return _converter; } @@ -82,10 +87,11 @@ class SerializerConverter { _serializer.FreeRootNodeOwnership(); _serializer.PassObject(_value, "", _value, SERIALIZER_FIELD_FLAG_VISIBLE); SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); -#ifdef __debug__ +#ifdef __debug_verbose__ Print("FromObject(): serializer flags: ", serializer_flags); - Print("FromObject(): result: ", - _serializer.GetRoot() != NULL ? _serializer.GetRoot().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); + Print("FromObject(): result: ", _serializer.GetRoot() != NULL + ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) + : "NULL"); #endif return _converter; } @@ -113,9 +119,9 @@ class SerializerConverter { template static SerializerConverter FromString(string arg) { SerializerConverter _converter(((C*)NULL)PTR_DEREF Parse(arg), 0); -#ifdef __debug__ +#ifdef __debug_verbose__ Print("FromString(): result: ", - _converter.Node() != NULL ? _converter.Node().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); + _converter.Node() != NULL ? _converter.Node() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); #endif return _converter; } diff --git a/Serializer/SerializerCsv.h b/Serializer/SerializerCsv.h index f7a97a5a4..099b50edb 100644 --- a/Serializer/SerializerCsv.h +++ b/Serializer/SerializerCsv.h @@ -55,12 +55,12 @@ class SerializerCsv { SerializerConverter* _stub = (SerializerConverter*)serializer_aux_arg; if (CheckPointer(_root) == POINTER_INVALID) { - Alert("SerializerCsv: Invalid root node poiner!"); + Alert("SerializerCsv: Invalid root node pointer!"); DebugBreak(); return NULL; } - if (_stub == NULL || _stub.Node() == NULL) { + if (_stub == NULL || _stub PTR_DEREF Node() == NULL) { Alert("SerializerCsv: Cannot convert to CSV without stub object!"); DebugBreak(); return NULL; @@ -72,12 +72,13 @@ class SerializerCsv { unsigned int _num_columns, _num_rows; int x, y; - if (_stub.Node().IsArray()) { - _num_columns = _stub.Node().MaximumNumChildrenInDeepEnd(); - _num_rows = _root.NumChildren(); + if (_stub PTR_DEREF Node() PTR_DEREF IsArray()) { + _num_columns = _stub PTR_DEREF Node() PTR_DEREF MaximumNumChildrenInDeepEnd(); + _num_rows = _root PTR_DEREF NumChildren(); } else { - _num_columns = MathMax(_stub.Node().MaximumNumChildrenInDeepEnd(), _root.MaximumNumChildrenInDeepEnd()); - _num_rows = _root.NumChildren() > 0 ? 1 : 0; + _num_columns = MathMax(_stub PTR_DEREF Node() PTR_DEREF MaximumNumChildrenInDeepEnd(), + _root PTR_DEREF MaximumNumChildrenInDeepEnd()); + _num_rows = _root PTR_DEREF NumChildren() > 0 ? 1 : 0; } if (_include_titles) { @@ -100,61 +101,61 @@ class SerializerCsv { _column_types_out = &_column_types; } - _matrix_out.Resize(_num_columns, _num_rows); - _column_types_out.Resize(_num_columns, 1); + _matrix_out PTR_DEREF Resize(_num_columns, _num_rows); + _column_types_out PTR_DEREF Resize(_num_columns, 1); if (_include_titles) { _column_titles.Resize(_num_columns, 1); int _titles_current_column = 0; - SerializerCsv::ExtractColumns(_stub.Node(), &_column_titles, _column_types_out, serializer_flags, + SerializerCsv::ExtractColumns(_stub PTR_DEREF Node(), &_column_titles, _column_types_out, serializer_flags, _titles_current_column); - for (x = 0; x < _matrix_out.SizeX(); ++x) { - _matrix_out.Set(x, 0, EscapeString(_column_titles.Get(x, 0))); + for (x = 0; x < _matrix_out PTR_DEREF SizeX(); ++x) { + _matrix_out PTR_DEREF Set(x, 0, EscapeString(_column_titles.Get(x, 0))); } } -#ifdef __debug__ - Print("Stub: ", _stub.Node().ToString()); - Print("Data: ", _root.ToString()); +#ifdef __debug_verbose__ + Print("Stub: ", _stub PTR_DEREF Node() PTR_DEREF ToString()); + Print("Data: ", _root PTR_DEREF ToString()); Print("Size: ", _num_columns, " x ", _num_rows); #endif - if (!SerializerCsv::FlattenNode(_root, _stub.Node(), _matrix_out, _column_types_out, _include_key ? 1 : 0, - _include_titles ? 1 : 0, serializer_flags)) { + if (!SerializerCsv::FlattenNode(_root, _stub PTR_DEREF Node(), PTR_TO_REF(_matrix_out), _column_types_out, + _include_key ? 1 : 0, _include_titles ? 1 : 0, serializer_flags)) { Alert("SerializerCsv: Error occured during flattening!"); } string _result; - for (y = 0; y < _matrix_out.SizeY(); ++y) { - for (x = 0; x < _matrix_out.SizeX(); ++x) { - _result += _matrix_out.Get(x, y); + for (y = 0; y < _matrix_out PTR_DEREF SizeY(); ++y) { + for (x = 0; x < _matrix_out PTR_DEREF SizeX(); ++x) { + _result += _matrix_out PTR_DEREF Get(x, y); - if (x != _matrix_out.SizeX() - 1) { + if (x != _matrix_out PTR_DEREF SizeX() - 1) { _result += ","; } } - if (y != _matrix_out.SizeY() - 1) _result += "\n"; + if (y != _matrix_out PTR_DEREF SizeY() - 1) _result += "\n"; } if ((serializer_flags & SERIALIZER_FLAG_REUSE_STUB) == 0) { - _stub.Clean(); + _stub PTR_DEREF Clean(); } return _result; } static string ParamToString(SerializerNodeParam* param) { - switch (param.GetType()) { + switch (param PTR_DEREF GetType()) { case SerializerNodeParamBool: case SerializerNodeParamLong: case SerializerNodeParamDouble: - return param.AsString(false, false, false, param.GetFloatingPointPrecision()); + return param PTR_DEREF AsString(false, false, false, param PTR_DEREF GetFloatingPointPrecision()); case SerializerNodeParamString: - return EscapeString(param.AsString(false, false, false, param.GetFloatingPointPrecision())); + return EscapeString(param PTR_DEREF AsString(false, false, false, param PTR_DEREF GetFloatingPointPrecision())); default: - Print("Error: Wrong param type ", EnumToString(param.GetType()), "!"); + Print("Error: Wrong param type ", EnumToString(param PTR_DEREF GetType()), "!"); DebugBreak(); } @@ -173,12 +174,12 @@ class SerializerCsv { */ static void ExtractColumns(SerializerNode* _stub, MiniMatrix2d* _titles, MiniMatrix2d* _column_types, int _flags, int& _column) { - for (unsigned int _stub_entry_idx = 0; _stub_entry_idx < _stub.NumChildren(); ++_stub_entry_idx) { - SerializerNode* _child = _stub.GetChild(_stub_entry_idx); - if (_child.IsContainer()) { + for (unsigned int _stub_entry_idx = 0; _stub_entry_idx < _stub PTR_DEREF NumChildren(); ++_stub_entry_idx) { + SerializerNode* _child = _stub PTR_DEREF GetChild(_stub_entry_idx); + if (_child PTR_DEREF IsContainer()) { ExtractColumns(_child, _titles, _column_types, _flags, _column); - } else if (_child.HasKey()) { - _titles.Set(_column++, 0, _child.Key()); + } else if (_child PTR_DEREF HasKey()) { + _titles PTR_DEREF Set(_column++, 0, _child PTR_DEREF Key()); } } } @@ -192,31 +193,31 @@ class SerializerCsv { bool _include_key = bool(_flags & SERIALIZER_CSV_INCLUDE_KEY); - if (_stub.IsArray()) { - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { + if (_stub PTR_DEREF IsArray()) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { if (_include_key) { // Adding object's key in the first row. - SerializerNode* _child = _data.GetChild(_data_entry_idx); - string key = _child.HasKey() ? _child.Key() : ""; + SerializerNode* _child = _data PTR_DEREF GetChild(_data_entry_idx); + string key = _child PTR_DEREF HasKey() ? _child PTR_DEREF Key() : ""; _cells.Set(0, _row + _data_entry_idx, key); } - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), _stub.GetChild(0), _cells, _column_types, _column, - _row + _data_entry_idx, 0, 0, _flags)) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), _stub PTR_DEREF GetChild(0), _cells, + _column_types, _column, _row + _data_entry_idx, 0, 0, _flags)) { return false; } } - } else if (_stub.IsObject()) { + } else if (_stub PTR_DEREF IsObject()) { // Object means that there is only one row. - if (_data.IsArray()) { + if (_data PTR_DEREF IsArray()) { // Stub is an object, but data is an array (should be?). - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), _stub, _cells, _column_types, _column, _row, 0, - 0, _flags)) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), _stub, _cells, _column_types, _column, + _row, 0, 0, _flags)) { return false; } - _column += (int)_stub.GetChild(_data_entry_idx).MaximumNumChildrenInDeepEnd(); + _column += (int)_stub PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF MaximumNumChildrenInDeepEnd(); } } else { // Stub and object are both arrays. @@ -237,34 +238,34 @@ class SerializerCsv { int _level, int _flags) { unsigned int _data_entry_idx, _entry_size; - if (_stub.IsObject()) { - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { - if (_stub.NumChildren() == 0) { - Print("Stub is empty for object representation of: ", _data.ToString(false, 2)); + if (_stub PTR_DEREF IsObject()) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { + if (_stub PTR_DEREF NumChildren() == 0) { + Print("Stub is empty for object representation of: ", _data PTR_DEREF ToString(false, 2)); Print( "Note that if you're serializing a dictionary, your stub must contain a single, dummy key and maximum " "possible object representation."); - Print("Missing key \"", _data.Key(), "\" in stub."); + Print("Missing key \"", _data PTR_DEREF Key(), "\" in stub."); DebugBreak(); } - _entry_size = MathMax(_stub.GetChild(_data_entry_idx).TotalNumChildren(), - _data.GetChild(_data_entry_idx).TotalNumChildren()); + _entry_size = MathMax(_stub PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren(), + _data PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren()); - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), - _stub != NULL ? _stub.GetChild(_data_entry_idx) : NULL, _cells, _column_types, - _column, _row, _data_entry_idx, _level + 1, _flags)) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), + _stub != NULL ? _stub PTR_DEREF GetChild(_data_entry_idx) : NULL, _cells, + _column_types, _column, _row, _data_entry_idx, _level + 1, _flags)) { return false; } _column += (int)_entry_size; } - } else if (_stub.IsArray()) { - for (_data_entry_idx = 0; _data_entry_idx < _data.NumChildren(); ++_data_entry_idx) { - _entry_size = MathMax(_stub.GetChild(_data_entry_idx).TotalNumChildren(), - _data.GetChild(_data_entry_idx).TotalNumChildren()); + } else if (_stub PTR_DEREF IsArray()) { + for (_data_entry_idx = 0; _data_entry_idx < _data PTR_DEREF NumChildren(); ++_data_entry_idx) { + _entry_size = MathMax(_stub PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren(), + _data PTR_DEREF GetChild(_data_entry_idx) PTR_DEREF TotalNumChildren()); - if (!SerializerCsv::FillRow(_data.GetChild(_data_entry_idx), _stub.GetChild(0), _cells, _column_types, _column, - _row, _data_entry_idx, _level + 1, _flags)) { + if (!SerializerCsv::FillRow(_data PTR_DEREF GetChild(_data_entry_idx), _stub PTR_DEREF GetChild(0), _cells, + _column_types, _column, _row, _data_entry_idx, _level + 1, _flags)) { return false; } @@ -273,18 +274,19 @@ class SerializerCsv { } else { // A property. - bool _include_titles = bool(_flags & SERIALIZER_CSV_INCLUDE_TITLES); - bool _include_titles_tree = (_flags & SERIALIZER_CSV_INCLUDE_TITLES_TREE) == SERIALIZER_CSV_INCLUDE_TITLES_TREE; + // bool _include_titles = bool(_flags & SERIALIZER_CSV_INCLUDE_TITLES); + // bool _include_titles_tree = (_flags & SERIALIZER_CSV_INCLUDE_TITLES_TREE) == + // SERIALIZER_CSV_INCLUDE_TITLES_TREE; if (_column_types != NULL) { - if (_data.GetValueParam() == NULL) { + if (_data PTR_DEREF GetValueParam() == NULL) { Alert("Error: Expected value here! Stub is probably initialized without proper structure."); DebugBreak(); } - _column_types.Set(_column, 0, _data.GetValueParam().GetType()); + _column_types PTR_DEREF Set(_column, 0, _data PTR_DEREF GetValueParam() PTR_DEREF GetType()); } - _cells.Set(_column, _row, ParamToString(_data.GetValueParam())); + _cells.Set(_column, _row, ParamToString(_data PTR_DEREF GetValueParam())); } return true; diff --git a/Serializer/SerializerJson.h b/Serializer/SerializerJson.h index e2d3d198a..34325c48e 100644 --- a/Serializer/SerializerJson.h +++ b/Serializer/SerializerJson.h @@ -195,7 +195,7 @@ class SerializerJson { #ifdef __debug__ Print("SerializerJson: Value \"" + extracted + "\" for key " + - (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif expectingValue = false; @@ -217,7 +217,8 @@ class SerializerJson { } #ifdef __debug__ - Print("SerializerJson: Entering object for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Entering object for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif node = new SerializerNode(SerializerNodeObject, current, key); @@ -237,16 +238,18 @@ class SerializerJson { } #ifdef __debug__ - Print("SerializerJson: Leaving object for key " + (current != NULL && current.GetKeyParam() != NULL - ? ("\"" + current.GetKeyParam().ToString() + "\"") - : "")); + Print("SerializerJson: Leaving object for key " + + (current != NULL && current PTR_DEREF GetKeyParam() != NULL + ? ("\"" + current PTR_DEREF GetKeyParam() PTR_DEREF ToString() + "\"") + : "")); #endif current = PTR_ATTRIB(current, GetParent()); expectingValue = false; } else if (ch == '[') { #ifdef __debug__ - Print("SerializerJson: Entering list for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Entering list for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif if (expectingKey) { @@ -264,7 +267,8 @@ class SerializerJson { key = NULL; } else if (ch == ']') { #ifdef __debug__ - Print("SerializerJson: Leaving list for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Leaving list for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif if (expectingKey || expectingValue || PTR_ATTRIB(current, GetType()) != SerializerNodeArray) { @@ -285,8 +289,8 @@ class SerializerJson { value = StringFind(extracted, ".") != -1 ? SerializerNodeParam::FromValue(StringToDouble(extracted)) : SerializerNodeParam::FromValue(StringToInteger(extracted)); #ifdef __debug__ - Print("SerializerJson: Value " + value.AsString() + " for key " + - (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print("SerializerJson: Value " + value PTR_DEREF AsString() + " for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif PTR_ATTRIB(current, AddChild(new SerializerNode(PTR_ATTRIB(current, GetType()) == SerializerNodeObject @@ -306,8 +310,8 @@ class SerializerJson { value = SerializerNodeParam::FromValue(ch == 't' ? true : false); #ifdef __debug__ - Print("SerializerJson: Value " + (value.ToBool() ? "true" : "false") + " for key " + - (key != NULL ? ("\"" + key.ToString() + "\"") : "")); + Print(string("SerializerJson: Value ") + (value PTR_DEREF ToBool() ? "true" : "false") + " for key " + + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif // Skipping value. diff --git a/Socket.mqh b/Socket.mqh index cadcf5897..5f8140b66 100644 --- a/Socket.mqh +++ b/Socket.mqh @@ -121,7 +121,7 @@ class Socket { return true; #else return false; -#endif; +#endif } /** @@ -184,7 +184,7 @@ class Socket { } #else return false; -#endif; +#endif } /** diff --git a/Std.h b/Std.h index c41abd901..b31c8c581 100644 --- a/Std.h +++ b/Std.h @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2021, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -21,129 +21,134 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once -#include "Math.define.h" + // Allows the preprocessor to include a header file when it is needed. + #pragma once + #include "Math.define.h" #endif +// Includes. +#include "Data.enum.h" + // Data types. #ifdef __cplusplus -#include -#include -#include -#include + #include + #include + #include + #include #endif #ifndef __MQL__ -#define __FUNCSIG__ __FUNCTION__ + #define __FUNCSIG__ __FUNCTION__ #endif #ifdef __MQL__ -#define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE)this) = ((TYPE)VALUE) + #define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE)this) = ((TYPE)VALUE) #else -#define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE&)*this) = ((TYPE&)VALUE) + #define ASSIGN_TO_THIS(TYPE, VALUE) ((TYPE&)*this) = ((TYPE&)VALUE) #endif // Pointers. #ifdef __MQL__ -#define GET_PTR(obj) GetPointer(obj) -#define THIS_ATTR -#define THIS_PTR (&this) -#define THIS_REF this -#define PTR_DEREF . -#define PTR_ATTRIB(O, A) O.A -#define PTR_ATTRIB2(O, A, B) O.A.B -#define PTR_TO_REF(PTR) PTR -#define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE* NAME = PTR -#define REF_DEREF .Ptr(). -#define int64 long + #define GET_PTR(obj) GetPointer(obj) + #define THIS_ATTR + #define THIS_PTR (&this) + #define THIS_REF this + #define PTR_DEREF . + #define PTR_ATTRIB(O, A) O.A + #define PTR_ATTRIB2(O, A, B) O.A.B + #define PTR_TO_REF(PTR) PTR + #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE* NAME = PTR + #define REF_DEREF .Ptr(). + #define int64 long + #define nullptr NULL #else -#define GET_PTR(obj) (*obj) -#define THIS_ATTR this-> -#define THIS_PTR (this) -#define THIS_REF (*this) -#define PTR_DEREF -> -#define PTR_ATTRIB(O, A) O->A -#define PTR_ATTRIB2(O, A, B) O->A->B -#define PTR_TO_REF(PTR) (*PTR) -#define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE& NAME = PTR -#define REF_DEREF .Ptr()-> -#define int64 long long + #define GET_PTR(obj) (*obj) + #define THIS_ATTR this-> + #define THIS_PTR (this) + #define THIS_REF (*this) + #define PTR_DEREF -> + #define PTR_ATTRIB(O, A) O->A + #define PTR_ATTRIB2(O, A, B) O->A->B + #define PTR_TO_REF(PTR) (*PTR) + #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE& NAME = PTR + #define REF_DEREF .Ptr()-> + #define int64 long long #endif // References. #ifdef __cplusplus -#define REF(X) (&X) + #define REF(X) (&X) #else -#define REF(X) X& + #define REF(X) X& #endif // Arrays and references to arrays. #define _COMMA , #ifdef __MQL__ -#define ARRAY_DECLARATION_BRACKETS [] + #define ARRAY_DECLARATION_BRACKETS [] #else -// C++'s _cpp_array is an object, so no brackets are needed. -#define ARRAY_DECLARATION_BRACKETS + // C++'s _cpp_array is an object, so no brackets are needed. + #define ARRAY_DECLARATION_BRACKETS #endif #ifdef __MQL__ -/** - * Reference to object. - */ -#define CONST_REF_TO(T) const T + /** + * Reference to object. + */ + #define CONST_REF_TO(T) const T -/** - * Reference to the array. - * - * @usage - * ARRAY_REF(, ) - */ -#define ARRAY_TYPE(T) T[] -#define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS -#define FIXED_ARRAY_REF(T, N, S) ARRAY_REF(T, N) + /** + * Reference to the array. + * + * @usage + * ARRAY_REF(, ) + */ + #define ARRAY_TYPE(T) T[] + #define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS + #define FIXED_ARRAY_REF(T, N, S) ARRAY_REF(T, N) -#define CONST_ARRAY_REF(T, N) const N ARRAY_DECLARATION_BRACKETS + #define CONST_ARRAY_REF(T, N) const N ARRAY_DECLARATION_BRACKETS -/** - * Array definition. - * - * @usage - * ARRAY(, ) - */ -#define ARRAY(T, N) T N[] + /** + * Array definition. + * + * @usage + * ARRAY(, ) + */ + #define ARRAY(T, N) T N[] #else -/** - * Reference to object. - */ -#define CONST_REF_TO(T) const T& + /** + * Reference to object. + */ + #define CONST_REF_TO(T) const T& /** - * Reference to the array. - * - * @usage - * ARRAY_REF(, ) - */ -#define ARRAY_TYPE(T) _cpp_array -#define ARRAY_REF(T, N) ARRAY_TYPE(T)& N -#define FIXED_ARRAY_REF(T, N, S) T(&N)[S] +* Reference to the array. +* +* @usage +* ARRAY_REF(, ) +*/ + #define ARRAY_TYPE(T) _cpp_array + #define ARRAY_REF(T, N) ARRAY_TYPE(T) & N + #define FIXED_ARRAY_REF(T, N, S) T(&N)[S] -#define CONST_ARRAY_REF(T, N) const _cpp_array& N + #define CONST_ARRAY_REF(T, N) const _cpp_array& N + #define CONST_ARRAY_REF(T, N) const _cpp_array& N -/** - * Array definition. - * - * @usage - * ARRAY(, ) - */ -#define ARRAY(T, N) ::_cpp_array N + /** + * Array definition. + * + * @usage + * ARRAY(, ) + */ + #define ARRAY(T, N) ::_cpp_array N #endif // typename(T) #ifndef __MQL__ -#define typename(T) typeid(T).name() + #define typename(T) typeid(T).name() #endif // C++ array class. @@ -235,19 +240,19 @@ class _cpp_array { void setIsSeries(bool _isSeries) { m_isSeries = _isSeries; } }; -#ifdef EMSCRIPTEN -#include + #ifdef EMSCRIPTEN + #include -#define REGISTER_ARRAY_OF(N, T, D) \ - EMSCRIPTEN_BINDINGS(N) { \ - emscripten::register_vector(D "CppVector"); \ - emscripten::class_<_cpp_array>(D) \ - .constructor() \ - .function("Push", &_cpp_array::push) \ - .function("Size", &_cpp_array::size); \ - } + #define REGISTER_ARRAY_OF(N, T, D) \ + EMSCRIPTEN_BINDINGS(N) { \ + emscripten::register_vector(D "CppVector"); \ + emscripten::class_<_cpp_array>(D) \ + .constructor() \ + .function("Push", &_cpp_array::push) \ + .function("Size", &_cpp_array::size); \ + } -#endif + #endif template class _cpp_array; @@ -270,14 +275,14 @@ class color { // MQL defines. #ifndef __MQL__ -#define WHOLE_ARRAY -1 // For processing the entire array. + #define WHOLE_ARRAY -1 // For processing the entire array. #endif // Converts string into C++-style string pointer. #ifdef __MQL__ -#define C_STR(S) S + #define C_STR(S) S #else -#define C_STR(S) cstring_from(S) + #define C_STR(S) cstring_from(S) inline const char* cstring_from(const std::string& _value) { return _value.c_str(); } #endif @@ -295,19 +300,19 @@ inline bool IsNull(const string& str) { return str == ""; } * STRUCT_ENUM(, ) */ #ifdef __MQL4__ -#define STRUCT_ENUM(S, E) E + #define STRUCT_ENUM(S, E) E #else -#define STRUCT_ENUM(S, E) S::E + #define STRUCT_ENUM(S, E) S::E #endif #ifndef __MQL__ -// Additional enum values for ENUM_SYMBOL_INFO_DOUBLE -#define SYMBOL_MARGIN_LIMIT ((ENUM_SYMBOL_INFO_DOUBLE)46) -#define SYMBOL_MARGIN_MAINTENANCE ((ENUM_SYMBOL_INFO_DOUBLE)43) -#define SYMBOL_MARGIN_LONG ((ENUM_SYMBOL_INFO_DOUBLE)44) -#define SYMBOL_MARGIN_SHORT ((ENUM_SYMBOL_INFO_DOUBLE)45) -#define SYMBOL_MARGIN_STOP ((ENUM_SYMBOL_INFO_DOUBLE)47) -#define SYMBOL_MARGIN_STOPLIMIT ((ENUM_SYMBOL_INFO_DOUBLE)48) + // Additional enum values for ENUM_SYMBOL_INFO_DOUBLE + #define SYMBOL_MARGIN_LIMIT ((ENUM_SYMBOL_INFO_DOUBLE)46) + #define SYMBOL_MARGIN_MAINTENANCE ((ENUM_SYMBOL_INFO_DOUBLE)43) + #define SYMBOL_MARGIN_LONG ((ENUM_SYMBOL_INFO_DOUBLE)44) + #define SYMBOL_MARGIN_SHORT ((ENUM_SYMBOL_INFO_DOUBLE)45) + #define SYMBOL_MARGIN_STOP ((ENUM_SYMBOL_INFO_DOUBLE)47) + #define SYMBOL_MARGIN_STOPLIMIT ((ENUM_SYMBOL_INFO_DOUBLE)48) #endif template @@ -360,14 +365,14 @@ template <> _NULL_VALUE::operator string() const { return _empty_string; } -#define NULL_STRING "" + #define NULL_STRING "" #else -#define NULL_VALUE NULL -#define NULL_STRING NULL + #define NULL_VALUE NULL + #define NULL_STRING NULL #endif #ifndef __MQL__ -#include "Chart.enum.h" + #include "Chart.enum.h" /** * Returns currently selected period for platform. */ @@ -389,9 +394,9 @@ extern ENUM_TIMEFRAMES Period(); #define SET_BUFFER_AS_SERIES_FOR_TARGET(A) ArraySetAsSeries(A, false); #ifdef __MQL4__ -#define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, true); + #define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, true); #else -#define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, false); + #define SET_BUFFER_AS_SERIES_FOR_HOST(A) ArraySetAsSeries(A, false); #endif // Ensures that we do RELEASE_BUFFERx after ACQUIRE_BUFFERx. @@ -401,6 +406,7 @@ struct AsSeriesReleaseEnsurer { AsSeriesReleaseEnsurer(int _num_buffs) : released(false), num_buffs(_num_buffs) {} void done(int _num_buffs) { if (_num_buffs != num_buffs) { +#ifdef __MQL__ Alert("You have acquired ", num_buffs, " buffers via ACQUIRE_BUFFER", num_buffs, "(), but now trying to release with mismatched RELEASE_BUFFER", _num_buffs, "()!"); DebugBreak(); @@ -410,15 +416,18 @@ struct AsSeriesReleaseEnsurer { Alert("You have used RELEASE_BUFFER", num_buffs, "() again which is not required!"); DebugBreak(); } +#endif released = true; } ~AsSeriesReleaseEnsurer() { +#ifdef __MQL__ if (!released) { Alert("You have used ACQUIRE_BUFFER", num_buffs, "() but didn't release buffer(s) via RELEASE_BUFFER", num_buffs, "() before returning from the scope!"); DebugBreak(); } +#endif } }; @@ -427,109 +436,141 @@ struct AsSeriesReleaseEnsurer { #define SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(NUM_BUFFS) _as_series_release_ensurer.done(NUM_BUFFS); // Acquiring buffer is preparing it to be used as in MQL5. -#define ACQUIRE_BUFFER1(A) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ +#define ACQUIRE_BUFFER1_NO_ENSURE(A) SET_BUFFER_AS_SERIES_FOR_TARGET(A); +#define ACQUIRE_BUFFER2_NO_ENSURE(A, B) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); +#define ACQUIRE_BUFFER3_NO_ENSURE(A, B, C) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); +#define ACQUIRE_BUFFER4_NO_ENSURE(A, B, C, D) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); +#define ACQUIRE_BUFFER5_NO_ENSURE(A, B, C, D, E) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); +#define ACQUIRE_BUFFER6_NO_ENSURE(A, B, C, D, E, F) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(F); +#define ACQUIRE_BUFFER7_NO_ENSURE(A, B, C, D, E, F, G) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(G); +#define ACQUIRE_BUFFER8_NO_ENSURE(A, B, C, D, E, F, G, H) \ + SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(G); \ + SET_BUFFER_AS_SERIES_FOR_TARGET(H); + +#define ACQUIRE_BUFFER1(A) \ + ACQUIRE_BUFFER1_NO_ENSURE(A); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(1); -#define ACQUIRE_BUFFER2(A, B) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ +#define ACQUIRE_BUFFER2(A, B) \ + ACQUIRE_BUFFER2_NO_ENSURE(A, B); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(2); #define ACQUIRE_BUFFER3(A, B, C) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ + ACQUIRE_BUFFER3_NO_ENSURE(A, B, C); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(3); -#define ACQUIRE_BUFFER4(A, B, C, D) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ +#define ACQUIRE_BUFFER4(A, B, C, D) \ + ACQUIRE_BUFFER4_NO_ENSURE(A, B, C, D); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(4); -#define ACQUIRE_BUFFER5(A, B, C, D, E) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ +#define ACQUIRE_BUFFER5(A, B, C, D, E) \ + ACQUIRE_BUFFER5_NO_ENSURE(A, B, C, D, E); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(5); -#define ACQUIRE_BUFFER6(A, B, C, D, E, F) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ +#define ACQUIRE_BUFFER6(A, B, C, D, E, F) \ + ACQUIRE_BUFFER6_NO_ENSURE(A, B, C, D, E, F); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(6); -#define ACQUIRE_BUFFER7(A, B, C, D, E, F, G) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(G); \ +#define ACQUIRE_BUFFER7(A, B, C, D, E, F, G) \ + ACQUIRE_BUFFER7_NO_ENSURE(A, B, C, D, E, F, G); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(7); -#define ACQUIRE_BUFFER8(A, B, C, D, E, F, G, H) \ - SET_BUFFER_AS_SERIES_FOR_TARGET(A); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(B); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(C); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(D); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(E); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(F); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(G); \ - SET_BUFFER_AS_SERIES_FOR_TARGET(H); \ +#define ACQUIRE_BUFFER8(A, B, C, D, E, F, G, H) \ + ACQUIRE_BUFFER8_NO_ENSURE(A, B, C, D, E, F, G, H); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_BEGIN(8); // Releasing buffer is setting its AsSeries as the default in the host language. -#define RELEASE_BUFFER1(A) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ +#define RELEASE_BUFFER1_NO_ENSURE(A) SET_BUFFER_AS_SERIES_FOR_HOST(A) +#define RELEASE_BUFFER2_NO_ENSURE(A, B) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); +#define RELEASE_BUFFER3_NO_ENSURE(A, B, C) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); +#define RELEASE_BUFFER4_NO_ENSURE(A, B, C, D) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); +#define RELEASE_BUFFER5_NO_ENSURE(A, B, C, D, E) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); +#define RELEASE_BUFFER6_NO_ENSURE(A, B, C, D, E, F) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); \ + SET_BUFFER_AS_SERIES_FOR_HOST(F); +#define RELEASE_BUFFER7_NO_ENSURE(A, B, C, D, E, F, G) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); \ + SET_BUFFER_AS_SERIES_FOR_HOST(F); \ + SET_BUFFER_AS_SERIES_FOR_HOST(G); +#define RELEASE_BUFFER8_NO_ENSURE(A, B, C, D, E, F, G, H) \ + SET_BUFFER_AS_SERIES_FOR_HOST(A); \ + SET_BUFFER_AS_SERIES_FOR_HOST(B); \ + SET_BUFFER_AS_SERIES_FOR_HOST(C); \ + SET_BUFFER_AS_SERIES_FOR_HOST(D); \ + SET_BUFFER_AS_SERIES_FOR_HOST(E); \ + SET_BUFFER_AS_SERIES_FOR_HOST(F); \ + SET_BUFFER_AS_SERIES_FOR_HOST(G); \ + SET_BUFFER_AS_SERIES_FOR_HOST(H); + +#define RELEASE_BUFFER1(A) \ + RELEASE_BUFFER1_NO_ENSURE(A); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(1); -#define RELEASE_BUFFER2(A, B) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ +#define RELEASE_BUFFER2(A, B) \ + RELEASE_BUFFER2_NO_ENSURE(A, B); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(2); -#define RELEASE_BUFFER3(A, B, C) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ +#define RELEASE_BUFFER3(A, B, C) \ + RELEASE_BUFFER3_NO_ENSURE(A, B, C); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(3); -#define RELEASE_BUFFER4(A, B, C, D) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ +#define RELEASE_BUFFER4(A, B, C, D) \ + RELEASE_BUFFER4_NO_ENSURE(A, B, C, D); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(4); -#define RELEASE_BUFFER5(A, B, C, D, E) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ +#define RELEASE_BUFFER5(A, B, C, D, E) \ + RELEASE_BUFFER5_NO_ENSURE(A, B, C, D, E); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(5); -#define RELEASE_BUFFER6(A, B, C, D, E, F) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ - SET_BUFFER_AS_SERIES_FOR_HOST(F); \ +#define RELEASE_BUFFER6(A, B, C, D, E, F) \ + RELEASE_BUFFER6_NO_ENSURE(A, B, C, D, E, F); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(6); -#define RELEASE_BUFFER7(A, B, C, D, E, F, G) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ - SET_BUFFER_AS_SERIES_FOR_HOST(F); \ - SET_BUFFER_AS_SERIES_FOR_HOST(G); \ +#define RELEASE_BUFFER7(A, B, C, D, E, F, G) \ + RELEASE_BUFFER7_NO_ENSURE(A, B, C, D, E, F, G); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(7); -#define RELEASE_BUFFER8(A, B, C, D, E, F, G, H) \ - SET_BUFFER_AS_SERIES_FOR_HOST(A); \ - SET_BUFFER_AS_SERIES_FOR_HOST(B); \ - SET_BUFFER_AS_SERIES_FOR_HOST(C); \ - SET_BUFFER_AS_SERIES_FOR_HOST(D); \ - SET_BUFFER_AS_SERIES_FOR_HOST(E); \ - SET_BUFFER_AS_SERIES_FOR_HOST(F); \ - SET_BUFFER_AS_SERIES_FOR_HOST(G); \ - SET_BUFFER_AS_SERIES_FOR_HOST(H); \ +#define RELEASE_BUFFER8(A, B, C, D, E, F, G, H) \ + RELEASE_BUFFER8_NO_ENSURE(A, B, C, D, E, F, G, H); \ SET_BUFFER_AS_SERIES_RELEASE_ENSURER_END(8); diff --git a/Storage/Collection.mqh b/Storage/Collection.mqh index 7ccd8f6fa..3d49ab173 100644 --- a/Storage/Collection.mqh +++ b/Storage/Collection.mqh @@ -159,7 +159,7 @@ class Collection { X *_object = GetSize() > 0 ? data[0].Ptr() : NULL; for (i = 0; i < ArraySize(data); i++) { double _weight = data[i].Ptr().GetWeight(); - if (_weight < _object.GetWeight()) { + if (_weight < _object PTR_DEREF GetWeight()) { _object = data[i].Ptr(); } } @@ -174,7 +174,7 @@ class Collection { X *_object = GetSize() > 0 ? data[0].Ptr() : NULL; for (i = 0; i < ArraySize(data); i++) { double _weight = data[i].Ptr().GetWeight(); - if (_weight > _object.GetWeight()) { + if (_weight > _object PTR_DEREF GetWeight()) { _object = data[i].Ptr(); } } diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index d1edaed1e..1420a5076 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -25,8 +25,8 @@ #define ITEMS_HISTORY_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif #include "../DictStruct.mqh" @@ -56,13 +56,21 @@ class ItemsHistoryItemProvider : public Dynamic { /** * Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we - * want previous or next items from selected starting point. + * want previous or next items from selected starting point. Should return false if retrieving items by this method + * is not available. */ - void GetItems(ItemsHistory>* _history, long _from_time_ms, + bool GetItems(ItemsHistory>* _history, long _from_time_ms, ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(IV, _out_arr)) { - // Method is called if there is a missing item (candle) in the history. We need to regenerate it. - Print("Error: Retrieving items by this item provider is not implemented!"); - DebugBreak(); + return false; + } + + /** + * Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this + * method is not available. + */ + bool GetItems(ItemsHistory>* _history, int _start_index, int _end_index, + ARRAY_REF(IV, _out_arr)) { + return false; } /** @@ -77,7 +85,7 @@ class ItemsHistoryItemProvider : public Dynamic { /** * Returns information about item provider. */ - virtual string ToString() { return "Abstract items history item provider."; } + string const ToString() override { return "Abstract items history item provider."; } }; /** @@ -92,6 +100,9 @@ class ItemsHistoryItemProvider : public Dynamic { */ template class ItemsHistory { + // Indicator the history is provided for. + IndicatorData* indi; + // Provides items from bound provider. Ref item_provider; @@ -128,13 +139,16 @@ class ItemsHistory { /** * Constructor */ - ItemsHistory(unsigned int _history_max_size = 0) - : history_max_size(_history_max_size), + ItemsHistory(IndicatorData* _indi, unsigned int _history_max_size = 0) + : indi(_indi), + history_max_size(_history_max_size), current_index(0), first_valid_index(0), first_valid_index_ever(0), last_valid_index(0), - peak_size(0) {} + peak_size(0) { + history.SetMaxConflicts(25); + } /** * Returns item provider. @@ -155,12 +169,27 @@ class ItemsHistory { } */ + /** + * Returns indicator the history is provided for. + */ + IndicatorData* GetIndicator() { return indi; } + /** * Returns maximum number of items that occupied the history. Could be used e.g., to determine how many bars could be * retrieved from history and past the history. */ unsigned int GetPeakSize() { return peak_size; } + /** + * Increments maximum size of historic items. + */ + void ReserveAdditionalHistoryMaxSize(unsigned int size) { history_max_size += size; } + + /** + * Changes maximum size of historic items. + */ + void SetHistoryMaxSize(unsigned int size) { history_max_size += size; } + /** * Will regenerate items from item provider. "_dir" indicates if we have to prepend or append items. */ @@ -169,80 +198,111 @@ class ItemsHistory { Print("RegenerateHistory(", _from_index, ", ", _to_index, ", ", EnumToString(_dir), "), ", GetInfo()); #endif - static ARRAY(IV, _items); // Items generated by provider. - ArrayResize(_items, 0); - int _item_count = _to_index - _from_index + 1; - long _from_time_ms; - IV _item; - // Calculating time to be passed to GetItems(). - if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { - if (history.Size() == 0) { -#ifdef __debug_items_history__ - Print("RegenerateHistory: Getting initial time from item provider"); -#endif - - // Time from we'll be getting items will be the time of the first possible item/candle/tick. - _from_time_ms = item_provider REF_DEREF GetInitialTimeMs(); - } else { -#ifdef __debug_items_history__ - Print("RegenerateHistory: Getting last valid item at index ", last_valid_index); -#endif - - // Time will be the time of last valid item + item's length + 1ms. - // Note that ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. - _item = GetItemByIndex(last_valid_index); - _from_time_ms = _item.GetTimeMs() + _item.GetLengthMs() + 1; - } - - long _current_time_ms = TimeCurrent() * 1000; + // Static buffer for items generated by the item provider. + static ARRAY(IV, _items); + ArrayResize(_items, 0); - if (_from_time_ms > (long)TimeCurrent() * 1000) { - // There won't be items in the future. - return; - } - } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { - if (history.Size() == 0) { - // Time from we'll be getting items will be the time of the first possible item/candle/tick - 1ms. - _from_time_ms = item_provider REF_DEREF GetInitialTimeMs() - 1; - } else { -#ifdef __debug_items_history__ - Print("RegenerateHistory: Getting first valid item at index ", first_valid_index); -#endif + // Currently we only support getting items via start -> end indices. - // Time will be the time of the first valid item - 1ms. - _item = GetItemByIndex(first_valid_index); - _from_time_ms = _item.GetTimeMs() - 1; - } - } else { - Print("Error: We shouldn't be here!"); - DebugBreak(); - return; - } - - item_provider REF_DEREF GetItems(THIS_PTR, _from_time_ms, _dir, _item_count, _items); + item_provider REF_DEREF GetItems(THIS_PTR, _from_index, _to_index, _items); if (ArraySize(_items) != _item_count) { -// There's really no problem if number of generated items are less than -// requested. -// @todo However, if there's too many calls for RegenerateHistory then we -// need to find a way to make it exit earlier. #ifdef __debug_items_history__ Print("RegenerateHistory: Notice: Requested ", _item_count, " historic items, got ", ArraySize(_items), ". from index = ", _from_index, ", to index = ", _to_index, ", dir = ", EnumToString(_dir), " (", GetInfo(), ")"); #endif - return; } - for (int i = 0; i < _item_count; ++i) { - if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + int i; + + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + for (i = 0; i < _item_count; ++i) { Append(_items[i], false); - } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + } + } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + // Our _items array contain most recent items at the start, so we have to iterate from the end in order to prepend + // items. + if (peak_size <= 1) { + // It's the first time we're trying to retrieve historic items. We need to make sure all history will fit in the + // buffer. Note that we use <= 1, because Tick indicator could already have appeneded first candle. + history_max_size = MathMax(history_max_size, history.Size() + _item_count); + } + for (i = 0; i < _item_count; ++i) { Prepend(_items[i], false); } } + + /* + + int _item_count = _to_index - _from_index + 1; + long _from_time_ms; + IV _item; + + // Calculating time to be passed to GetItems(). + if (_dir == ITEMS_HISTORY_DIRECTION_FORWARD) { + if (history.Size() == 0) { + #ifdef __debug_items_history__ + Print("RegenerateHistory: Getting initial time from item provider"); + #endif + + // Time from we'll be getting items will be the time of the first possible item/candle/tick. + _from_time_ms = item_provider REF_DEREF GetInitialTimeMs(); + } else { + #ifdef __debug_items_history__ + Print("RegenerateHistory: Getting last valid item at index ", last_valid_index); + #endif + + // Time will be the time of last valid item + item's length + 1ms. + // Note that ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. + _item = GetItemByIndex(last_valid_index); + _from_time_ms = _item.GetTimeMs() + _item.GetLengthMs() + 1; + } + + long _current_time_ms = TimeCurrent() * 1000; + + if (_from_time_ms > (long)TimeCurrent() * 1000) { + // There won't be items in the future. + return; + } + } else if (_dir == ITEMS_HISTORY_DIRECTION_BACKWARD) { + if (history.Size() == 0) { + // Time from we'll be getting items will be the time of the first possible item/candle/tick - 1ms. + _from_time_ms = item_provider REF_DEREF GetInitialTimeMs() - 1; + } else { + #ifdef __debug_items_history__ + Print("RegenerateHistory: Getting first valid item at index ", first_valid_index); + #endif + + // Time will be the time of the first valid item - 1ms. + _item = GetItemByIndex(first_valid_index); + _from_time_ms = _item.GetTimeMs() - 1; + } + } else { + Print("Error: We shouldn't be here!"); + DebugBreak(); + return; + } + + item_provider REF_DEREF GetItems(THIS_PTR, _from_time_ms, _dir, _item_count, _items); + + if (ArraySize(_items) != _item_count) { + // There's really no problem if number of generated items are less than + // requested. + // @todo However, if there's too many calls for RegenerateHistory then we + // need to find a way to make it exit earlier. + #ifdef __debug_items_history__ + Print("RegenerateHistory: Notice: Requested ", _item_count, " historic items, got ", ArraySize(_items), + ". from index = ", _from_index, ", to index = ", _to_index, ", dir = ", EnumToString(_dir), " (", + GetInfo(), + ")"); + #endif + return; + } + + */ } string GetInfo() { @@ -352,11 +412,11 @@ class ItemsHistory { */ bool EnsureShiftExists(int _shift) { if (history.Size() == 0) { - return false; + // return false; } #ifdef __debug_items_history__ - Print("EnsureShiftExists(", _shift, ")"); + // Print("EnsureShiftExists(", _shift, ")"); #endif int _index = GetShiftIndex(_shift); @@ -463,7 +523,13 @@ class ItemsHistory { return (datetime)0; } - return (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); + datetime _dt = (datetime)(GetItemTimeByShiftMsc(_shift) / 1000); + +#ifdef __debug_items_history__ + Print("GetItemTimeByShift(", _shift, "), ", GetInfo(), " = ", _dt); +#endif + + return _dt; } /** diff --git a/Storage/MemoryFileSystem.h b/Storage/MemoryFileSystem.h new file mode 100644 index 000000000..bd84d7a68 --- /dev/null +++ b/Storage/MemoryFileSystem.h @@ -0,0 +1,149 @@ +//+------------------------------------------------------------------+ +//| 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 + * In-memory file-system used e.g., to create files in C++ and access them in JS via Emscripten. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once + +// Includes. +#include + +#include "../DictStruct.mqh" +#include "../File.define.h" +#include "../String.mqh" + +class MemoryFileSystemFile : public Dynamic { + public: + // FILE_* flags from MQL. + unsigned int flags; + + // Whether file is already opened. + bool opened; + + // MemoryFileSystemFile handle index. + int handle; + + // Auto-incremented handle index. + static unsigned int last_handle; + + // String-based buffer. + string buffer; + + // Current cursor offset. + int offset; + + /** + * Constructor. + */ + MemoryFileSystemFile(string data = "") { + handle = last_handle++; + buffer = data; + } +}; + +unsigned int MemoryFileSystemFile::last_handle = 0; + +class MemoryFileSystem { + // Files by path. + DictStruct> files_by_path; + + // Files by handle. + DictStruct> files_by_handle; + + public: + MemoryFileSystem() { + int _ea_version_handle = FileOpen("EA.txt", FILE_WRITE); + FileWrite(_ea_version_handle, "Hello world!"); + FileClose(_ea_version_handle); + } + + /** + * Opens file for reading/writing and returns its handle. + */ + int FileOpen(string _path, int _flags, short _delimiter = ';', unsigned int codepage = CP_ACP) { + Ref _file; + + if (files_by_path.KeyExists("_path")) { + _file = files_by_path.GetByKey(_path); + + if (_file REF_DEREF opened) { + // MemoryFileSystemFile is already opened. + Print("Error: MemoryFileSystemFile \"" + _path + "\" is already opened!"); + DebugBreak(); + return INVALID_HANDLE; + } + + if ((_flags & FILE_WRITE) != 0) { + // Truncating file. + _file REF_DEREF buffer = ""; + } + } else { + if ((_flags & FILE_READ) != 0) { + // MemoryFileSystemFile doesn't exit. + Print("Error: MemoryFileSystemFile \"" + _path + "\" doesn't exist!"); + DebugBreak(); + return INVALID_HANDLE; + } + + _file = new MemoryFileSystemFile(); + files_by_path.Set(_path, _file); + files_by_handle.Set(_file REF_DEREF handle, _file); + } + + return _file REF_DEREF handle; + } + + /** + * Closes file by the handle given. + */ + void FileClose(int handle) { + if (!files_by_handle.KeyExists(handle)) { + Print("Error: MemoryFileSystemFile handle ", handle, " is not opened!"); + DebugBreak(); + return; + } + + files_by_handle.Unset(handle); + } + + template + unsigned int FileWrite(int file_handle, Arg&& arg, Args&&... args) { + if (!files_by_handle.KeyExists(file_handle)) { + Print("Error: MemoryFileSystemFile handle ", file_handle, " is not opened!"); + DebugBreak(); + return 0; + } + + std::stringstream str; + PrintTo(str, arg, args...); + string data = str.str(); + Ref _file = files_by_handle.GetByKey(file_handle); + _file REF_DEREF buffer += data; + return data.size(); + } +}; + +#endif diff --git a/Storage/Objects.h b/Storage/Objects.h index 443c6337c..1f4174ca2 100644 --- a/Storage/Objects.h +++ b/Storage/Objects.h @@ -49,12 +49,12 @@ class Objects { * Tries to retrieve pointer to object for a given key. Returns true if object did exist. */ static bool TryGet(CONST_REF_TO(string) key, C*& out_ptr) { - int position; - if (!GetObjects().KeyExists(key, position)) { + unsigned int position; + if (!GetObjects() PTR_DEREF KeyExists(key, position)) { out_ptr = NULL; return false; } else { - out_ptr = GetObjects().GetByPos(position).Ptr(); + out_ptr = GetObjects() PTR_DEREF GetByPos(position).Ptr(); return true; } } @@ -64,7 +64,7 @@ class Objects { */ static C* Set(CONST_REF_TO(string) key, C* ptr) { Ref _ref(ptr); - GetObjects().Set(key, _ref); + GetObjects() PTR_DEREF Set(key, _ref); return ptr; } }; diff --git a/Storage/ObjectsCache.h b/Storage/ObjectsCache.h index 70a5172bb..ee73d69dc 100644 --- a/Storage/ObjectsCache.h +++ b/Storage/ObjectsCache.h @@ -42,7 +42,7 @@ class DictStructDestructable : public DictStruct { * Destructor. */ ~DictStructDestructable() { - for (DictStructIterator iter = Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator iter = THIS_ATTR Begin(); iter.IsValid(); ++iter) { delete iter.Value(); } } diff --git a/Storage/ValueStorage.accessor.h b/Storage/ValueStorage.accessor.h index 4115a4247..fab97fac3 100644 --- a/Storage/ValueStorage.accessor.h +++ b/Storage/ValueStorage.accessor.h @@ -70,12 +70,12 @@ class ValueStorageAccessor { /** * Fetches value from the storage. */ - const C Get() const { return storage.Fetch(index); } + const C Get() const { return storage PTR_DEREF Fetch(index); } /** * Stores value in the storage. */ - void Set(C value) { storage.Store(index, value); } + void Set(C value) { storage PTR_DEREF Store(index, value); } #define VALUE_STORAGE_ACCESSOR_OP(TYPE, OP) \ TYPE operator OP(const ValueStorageAccessor& _accessor) const { return Get() OP _accessor.Get(); } \ diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index ec40c2d80..7d37e11b4 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -237,8 +237,6 @@ int ArrayCopy(ARRAY_REF(D, _target), ValueStorage &_source, int _dst_start = } } - int _pre_fill = _dst_start; - count = MathMin(count, ArraySize(_source) - _src_start); int _dst_required_size = _dst_start + count; @@ -265,20 +263,6 @@ int ArrayCopy(ARRAY_REF(D, _target), ValueStorage &_source, int _dst_start = return _num_copied; } -/** - * iHigest() version working on ValueStorage. - */ -int iHighest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { - return iPeak(_price, _count, _start, IPEAK_HIGHEST); -} - -/** - * iLowest() version working on ValueStorage. - */ -int iLowest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { - return iPeak(_price, _count, _start, IPEAK_LOWEST); -} - /** * iLowest() version working on ValueStorage. */ @@ -324,4 +308,18 @@ int iPeak(ValueStorage &_price, int _count, int _start, ENUM_IPEAK _type return _price_size - _peak_idx - 1; } +/** + * iHigest() version working on ValueStorage. + */ +int iHighest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { + return iPeak(_price, _count, _start, IPEAK_HIGHEST); +} + +/** + * iLowest() version working on ValueStorage. + */ +int iLowest(ValueStorage &_price, int _count = WHOLE_ARRAY, int _start = 0) { + return iPeak(_price, _count, _start, IPEAK_LOWEST); +} + #endif // VALUE_STORAGE_H diff --git a/Storage/ValueStorage.history.h b/Storage/ValueStorage.history.h index 31883a03f..f4924139f 100644 --- a/Storage/ValueStorage.history.h +++ b/Storage/ValueStorage.history.h @@ -31,7 +31,6 @@ #endif // Includes. -#include "../Indicator/IndicatorData.h" #include "ValueStorage.h" // Forward declarations. @@ -39,6 +38,10 @@ class IndicatorData; template class ValueStorage; +#ifndef __MQL__ +extern int GetBarsFromStart(IndicatorData* _indi); +#endif + /** * Storage for direct access to indicator's buffer for a given mode. */ @@ -66,7 +69,7 @@ class HistoryValueStorage : public ValueStorage { /** * Initializes storage with given value. */ - virtual void Initialize(C _value) { + virtual void Initialize(C _value) override { Print("HistoryValueStorage does not implement Initialize()!"); DebugBreak(); } @@ -91,7 +94,11 @@ class HistoryValueStorage : public ValueStorage { if (!indi_candle.ObjectExists()) { return 0; } +#ifdef __MQL__ return indi_candle REF_DEREF GetBars(); +#else + return GetBarsFromStart(indi_candle.Ptr()); +#endif } /** diff --git a/Storage/ValueStorage.indicator.h b/Storage/ValueStorage.indicator.h index ad69719bc..bdd2ee376 100644 --- a/Storage/ValueStorage.indicator.h +++ b/Storage/ValueStorage.indicator.h @@ -31,7 +31,8 @@ #endif // Forward declarations. -class IndicatorData; +template +class HistoryValueStorage; // Includes. #include "ValueStorage.history.h" @@ -48,11 +49,30 @@ class IndicatorBufferValueStorage : public HistoryValueStorage { /** * Constructor. */ - IndicatorBufferValueStorage(IndicatorBase *_indi_candle, int _mode = 0, bool _is_series = false) - : mode(_mode), HistoryValueStorage(_indi_candle) {} + IndicatorBufferValueStorage(IndicatorData* _indi_candle, int _mode = 0, bool _is_series = false) + : HistoryValueStorage(_indi_candle), mode(_mode) {} - /** - * Fetches value from a given shift. Takes into consideration as-series flag. - */ - C Fetch(int _rel_shift) override { return indi_candle REF_DEREF GetValue(mode, RealShift(_rel_shift)); } +/** + * Fetches value from a given shift. Takes into consideration as-series flag. + */ +#ifdef __MQL__ + C Fetch(int _rel_shift) override { + IndicatorData* _indi = THIS_ATTR indi_candle.Ptr(); + return _indi PTR_DEREF GetValue(mode, THIS_ATTR RealShift(_rel_shift)); + } +#else + C Fetch(int _rel_shift) override; +#endif }; + +// clang-format off +#include "../Indicator/IndicatorData.h" +// clang-format on + +#ifndef __MQL__ +template +C IndicatorBufferValueStorage::Fetch(int _rel_shift) { + IndicatorData* _indi = THIS_ATTR indi_candle.Ptr(); + return _indi PTR_DEREF GetValue(mode, THIS_ATTR RealShift(_rel_shift)); +} +#endif diff --git a/Storage/ValueStorage.price_median.h b/Storage/ValueStorage.price_median.h index 3752af417..890ffee3e 100644 --- a/Storage/ValueStorage.price_median.h +++ b/Storage/ValueStorage.price_median.h @@ -39,12 +39,12 @@ class PriceMedianValueStorage : public HistoryValueStorage { /** * Constructor. */ - PriceMedianValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + PriceMedianValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - PriceMedianValueStorage(PriceMedianValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + PriceMedianValueStorage(PriceMedianValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.price_typical.h b/Storage/ValueStorage.price_typical.h index 4bf51f786..fe99eb869 100644 --- a/Storage/ValueStorage.price_typical.h +++ b/Storage/ValueStorage.price_typical.h @@ -36,12 +36,12 @@ class PriceTypicalValueStorage : public HistoryValueStorage { /** * Constructor. */ - PriceTypicalValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + PriceTypicalValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - PriceTypicalValueStorage(PriceTypicalValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + PriceTypicalValueStorage(PriceTypicalValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.price_weighted.h b/Storage/ValueStorage.price_weighted.h index 17818583e..91029acc4 100644 --- a/Storage/ValueStorage.price_weighted.h +++ b/Storage/ValueStorage.price_weighted.h @@ -36,12 +36,12 @@ class PriceWeightedValueStorage : public HistoryValueStorage { /** * Constructor. */ - PriceWeightedValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + PriceWeightedValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - PriceWeightedValueStorage(PriceWeightedValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + PriceWeightedValueStorage(PriceWeightedValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.spread.h b/Storage/ValueStorage.spread.h index ead33fbcf..e19e3b01c 100644 --- a/Storage/ValueStorage.spread.h +++ b/Storage/ValueStorage.spread.h @@ -25,7 +25,6 @@ */ // Includes. -#include "../Chart.struct.h" #include "ObjectsCache.h" #include "ValueStorage.history.h" @@ -37,12 +36,12 @@ class SpreadValueStorage : public HistoryValueStorage { /** * Constructor. */ - SpreadValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + SpreadValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - SpreadValueStorage(SpreadValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + SpreadValueStorage(SpreadValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.tick_volume.h b/Storage/ValueStorage.tick_volume.h index 40e6a78a9..6a901bc8a 100644 --- a/Storage/ValueStorage.tick_volume.h +++ b/Storage/ValueStorage.tick_volume.h @@ -36,12 +36,12 @@ class TickVolumeValueStorage : public HistoryValueStorage { /** * Constructor. */ - TickVolumeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + TickVolumeValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - TickVolumeValueStorage(TickVolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + TickVolumeValueStorage(TickVolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.time.h b/Storage/ValueStorage.time.h index be83827e9..ee4edc93c 100644 --- a/Storage/ValueStorage.time.h +++ b/Storage/ValueStorage.time.h @@ -37,12 +37,12 @@ class TimeValueStorage : public HistoryValueStorage { /** * Constructor. */ - TimeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + TimeValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - TimeValueStorage(TimeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + TimeValueStorage(TimeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Storage/ValueStorage.volume.h b/Storage/ValueStorage.volume.h index 39bd4d8ba..33d8c01f6 100644 --- a/Storage/ValueStorage.volume.h +++ b/Storage/ValueStorage.volume.h @@ -36,12 +36,12 @@ class VolumeValueStorage : public HistoryValueStorage { /** * Constructor. */ - VolumeValueStorage(IndicatorBase *_indi_candle) : HistoryValueStorage(_indi_candle) {} + VolumeValueStorage(IndicatorData *_indi_candle) : HistoryValueStorage(_indi_candle) {} /** * Copy constructor. */ - VolumeValueStorage(VolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} + VolumeValueStorage(VolumeValueStorage &_r) : HistoryValueStorage(_r.indi_candle.Ptr()) {} /** * Fetches value from a given shift. Takes into consideration as-series flag. diff --git a/Strategy.mqh b/Strategy.mqh index 115b7660a..79ab81eba 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -668,7 +668,7 @@ class Strategy : public Taskable { virtual void OnInit() { // Link log instances. logger.Link(trade.Ptr().GetLogger()); - trade.Ptr().GetLogger().SetLevel(sparams.Get(STRAT_PARAM_LOG_LEVEL)); + trade.Ptr().GetLogger().SetLevel((ENUM_LOG_LEVEL)sparams.Get(STRAT_PARAM_LOG_LEVEL)); // Sets strategy stops. SetStops(THIS_PTR, THIS_PTR); // trade.SetStrategy(&this); // @fixme @@ -926,12 +926,12 @@ class Strategy : public Taskable { bool _result = true; if (_method != 0) { int _shift = _method / 64; - if (METHOD(_method, 0)) _result &= !trade REF_DEREF HasBarOrder(_cmd, _shift); // 1 - if (METHOD(_method, 1)) _result &= IsTrend(_cmd); // 2 - if (METHOD(_method, 2)) _result &= trade REF_DEREF IsPivot(_cmd, _shift); // 4 - if (METHOD(_method, 3)) _result &= !trade REF_DEREF HasOrderOppositeType(_cmd); // 8 - if (METHOD(_method, 4)) _result &= trade REF_DEREF IsPeak(_cmd, _shift); // 16 - if (METHOD(_method, 5)) _result &= !trade REF_DEREF HasOrderBetter(_cmd); // 32 + if (METHOD(_method, 0)) _result &= !trade REF_DEREF HasBarOrder(_cmd, _shift); // 1 + if (METHOD(_method, 1)) _result &= IsTrend(_cmd); // 2 + if (METHOD(_method, 2)) _result &= trade REF_DEREF IsPivot(_cmd, _shift); // 4 + if (METHOD(_method, 3)) _result &= !trade REF_DEREF HasOrderOppositeType(_cmd); // 8 + if (METHOD(_method, 4)) _result &= trade REF_DEREF IsPeak(_cmd, _shift); // 16 + if (METHOD(_method, 5)) _result &= !trade REF_DEREF HasOrderBetter(_cmd); // 32 if (METHOD(_method, 6)) _result &= trade REF_DEREF CalcActiveProfitInValue() <= 0.0f; // 64 /* if (METHOD(_method, 6)) @@ -1054,15 +1054,14 @@ class Strategy : public Taskable { virtual bool SignalCloseFilter(ENUM_ORDER_TYPE _cmd, int _method = 0, int _shift = 0) { bool _result = _method == 0; if (_method != 0) { - if (METHOD(_method, 0)) _result |= _result || !trade REF_DEREF HasBarOrder(_cmd, _shift); // 1 - if (METHOD(_method, 1)) _result |= _result || !IsTrend(_cmd); // 2 + if (METHOD(_method, 1)) _result |= _result || !IsTrend(_cmd); // 2 if (METHOD(_method, 2)) _result |= _result || !trade REF_DEREF IsPivot(_cmd, _shift); // 4 if (METHOD(_method, 3)) - _result |= _result || Open[_shift] > High[_shift + 1] || Open[_shift] < Low[_shift + 1]; // 8 - if (METHOD(_method, 4)) _result |= _result || trade REF_DEREF IsPeak(_cmd, _shift); // 16 - if (METHOD(_method, 5)) _result |= _result || trade REF_DEREF HasOrderBetter(_cmd); // 32 - if (METHOD(_method, 6)) _result |= _result || trade REF_DEREF CalcActiveProfitInValue() > 0.0f; // 64 + _result |= _result || Open[_shift] > High[_shift + 1] || Open[_shift] < Low[_shift + 1]; // 8 + if (METHOD(_method, 4)) _result |= _result || trade REF_DEREF IsPeak(_cmd, _shift); // 16 + if (METHOD(_method, 5)) _result |= _result || trade REF_DEREF HasOrderBetter(_cmd); // 32 + if (METHOD(_method, 6)) _result |= _result || trade REF_DEREF CalcActiveProfitInValue() > 0.0f; // 64 /* if (METHOD(_method, 6)) _result |= diff --git a/String.extern.h b/String.extern.h index cb052e4a1..16e44b2b2 100644 --- a/String.extern.h +++ b/String.extern.h @@ -23,21 +23,163 @@ // Prevents processing this includes file for the second time. #ifndef __MQL__ #pragma once + +// Includes. +#include + +#include +#include +#include +#include +#include + +#include "Math.extern.h" #include "Std.h" #include "Terminal.define.h" -#endif // Define external global functions. -#ifndef __MQL__ -extern double StringToDouble(string value); -extern int StringFind(string string_value, string match_substring, int start_pos = 0); -extern int StringLen(string string_value); -extern int StringSplit(const string& string_value, const unsigned short separator, ARRAY_REF(string, result)); -extern long StringToInteger(string value); -extern string IntegerToString(long number, int str_len = 0, unsigned short fill_symbol = ' '); -extern string StringFormat(string format, ...); -extern string StringSubstr(string string_value, int start_pos, int length = -1); -extern unsigned short StringGetCharacter(string string_value, int pos); +double StringToDouble(string value) { return std::stod(value); } + +auto StringFind(const string string_value, string match_substring, int start_pos = 0) -> int { + return string_value.find(match_substring); +} +int StringLen(string string_value) { return string_value.size(); } +int StringSplit(const string& string_value, const unsigned short separator, ARRAY_REF(string, result)) { + auto start = 0U; + auto end = string_value.find((char)separator); + while (end != std::string::npos) { + result.str().push_back(string_value.substr(start, end - start)); + start = end + 1; // 1 - size of the separator. + end = string_value.find((char)separator, start); + } + return result.size(); +} +long StringToInteger(string value) { return std::stol(value); } +string IntegerToString(int64 number, int str_len = 0, unsigned short fill_symbol = ' ') { + return std::to_string(number); +} + +template +std::string StringFormat(std::string f, Args&&... args) { + int size = snprintf(nullptr, 0, f.c_str(), args...); + std::string res; + res.resize(size); + snprintf(&res[0], size + 1, f.c_str(), args...); + return res; +} + +template +void PrintTo(std::ostream& out, Arg&& arg, Args&&... args) { + out << std::forward(arg); + using expander = int[]; + (void)expander{0, (void(out << std::forward(args)), 0)...}; + out << std::endl; + out.flush(); +} + +template +void Print(Arg&& arg, Args&&... args) { + PrintTo(std::cout, arg, args...); +} + +template +void Alert(Arg&& arg, Args&&... args) { + PrintTo(std::cerr, arg, args...); +} + +template +void PrintFormat(const std::string& fmt, Args&&... args) { + std::cout << StringFormat(fmt, args...) << std::endl; +} + +string StringSubstr(string string_value, int start_pos, int length = -1) { + return string_value.substr(start_pos, length == -1 ? (string_value.size() - start_pos) : length); +} +unsigned short StringGetCharacter(string string_value, int pos) { + if (pos < 0 || pos >= string_value.size()) { + Alert("Character index out of string boundary! Position passed: ", pos, ", string passed: \"", string_value, "\""); + } + return string_value[pos]; +} + int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, - unsigned int codepage = CP_ACP); + unsigned int codepage = CP_ACP) { + if (count == -1) count = text_string.size(); + + for (int i = start; i < MathMin(start + count, (int)text_string.size()); ++i) + array.push((unsigned char)text_string[i]); + + return array.size(); +} + +bool StringInit(string& string_var, int new_len = 0, unsigned short character = 0) { + string_var = string(new_len, (char)character); + return true; +} + +/** + * It replaces all the found substrings of a string by a set sequence of symbols. + * + * @docs + * - https://www.mql5.com/en/docs/strings/stringreplace + */ +int StringReplace(string& str, const string& find, const string& replacement) { + int num_replacements = 0; + for (size_t pos = 0;; pos += replacement.length()) { + // Locate the substring to replace + pos = str.find(find, pos); + if (pos == string::npos) break; + // Replace by erasing and inserting + str.erase(pos, find.length()); + str.insert(pos, replacement); + ++num_replacements; + } + return num_replacements; +} + +string StringToLower(string str) { + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return ::tolower(c); }); + return str; +} + +string StringToUpper(string str) { + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return ::toupper(c); }); + return str; +} + +string EnumToString(ENUM_DATATYPE _value) { + switch (_value) { + case TYPE_BOOL: + return "TYPE_BOOL"; + case TYPE_CHAR: + return "TYPE_CHAR"; + case TYPE_COLOR: + return "TYPE_COLOR"; + case TYPE_DATETIME: + return "TYPE_DATETIME"; + case TYPE_DOUBLE: + return "TYPE_DOUBLE"; + case TYPE_FLOAT: + return "TYPE_FLOAT"; + case TYPE_INT: + return "TYPE_INT"; + case TYPE_LONG: + return "TYPE_LONG"; + case TYPE_SHORT: + return "TYPE_SHORT"; + case TYPE_STRING: + return "TYPE_STRING"; + case TYPE_UCHAR: + return "TYPE_UCHAR"; + case TYPE_UINT: + return "TYPE_UINT"; + case TYPE_ULONG: + return "TYPE_ULONG"; + case TYPE_USHORT: + return "TYPE_USHORT"; + } + + return ""; +} + #endif diff --git a/SummaryReport.mqh b/SummaryReport.mqh index 5a448aa38..2e88769b5 100644 --- a/SummaryReport.mqh +++ b/SummaryReport.mqh @@ -22,6 +22,7 @@ #include "Account/AccountMt.h" #include "Convert.mqh" +#include "Indicator/IndicatorData.h" #include "Order.struct.h" #include "Terminal.mqh" #include "Trade.mqh" @@ -30,291 +31,291 @@ * Class to provide a summary report. */ class SummaryReport { - protected: - // Variables. - double init_deposit; - double summary_profit; - double gross_profit; - double gross_loss; - double max_profit; - double min_profit; - double con_profit1; - double con_profit2; - double con_loss1; - double con_loss2; - double max_loss; - double max_dd; - double max_dd_pct; - double rel_dd_pct; - double rel_dd; - double expected_payoff; - double profit_factor; - double abs_dd; - int summary_trades; - int profit_trades; - int loss_trades; - int short_trades; - int long_trades; - int win_short_trades; - int win_long_trades; - int con_profit_trades1; - int con_profit_trades2; - int con_loss_trades1; - int con_loss_trades2; - int avg_con_wins; - int avg_con_losses; + protected: + // Variables. + double init_deposit; + double summary_profit; + double gross_profit; + double gross_loss; + double max_profit; + double min_profit; + double con_profit1; + double con_profit2; + double con_loss1; + double con_loss2; + double max_loss; + double max_dd; + double max_dd_pct; + double rel_dd_pct; + double rel_dd; + double expected_payoff; + double profit_factor; + double abs_dd; + int summary_trades; + int profit_trades; + int loss_trades; + int short_trades; + int long_trades; + int win_short_trades; + int win_long_trades; + int con_profit_trades1; + int con_profit_trades2; + int con_loss_trades1; + int con_loss_trades2; + int avg_con_wins; + int avg_con_losses; - double init_balance; + double init_balance; - public: - /** - * Default constructor. - */ + public: + /** + * Default constructor. + */ SummaryReport() { InitVars(AccountMt::AccountBalance()); } - /** - * Constructor to initialize starting balance. - */ + /** + * Constructor to initialize starting balance. + */ SummaryReport(double deposit) { InitVars(deposit); } - /** - * Constructor to initialize starting balance. - */ - void InitVars(double deposit = 0) { - init_deposit = deposit; - max_loss = deposit; - summary_profit = 0.0; - gross_profit = 0.0; - gross_loss = 0.0; - max_profit = 0.0; - min_profit = 0.0; - con_profit1 = 0.0; - con_profit2 = 0.0; - con_loss1 = 0.0; - con_loss2 = 0.0; - max_dd = 0.0; - max_dd_pct = 0.0; - rel_dd_pct = 0.0; - rel_dd = 0.0; - expected_payoff = 0.0; - profit_factor = 0.0; - abs_dd = 0.0; - summary_trades = 0; - profit_trades = 0; - loss_trades = 0; - short_trades = 0; - long_trades = 0; - win_short_trades = 0; - win_long_trades = 0; - con_profit_trades1 = 0; - con_profit_trades2 = 0; - con_loss_trades1 = 0; - con_loss_trades2 = 0; - avg_con_wins = 0; - avg_con_losses = 0; - } + /** + * Constructor to initialize starting balance. + */ + void InitVars(double deposit = 0) { + init_deposit = deposit; + max_loss = deposit; + summary_profit = 0.0; + gross_profit = 0.0; + gross_loss = 0.0; + max_profit = 0.0; + min_profit = 0.0; + con_profit1 = 0.0; + con_profit2 = 0.0; + con_loss1 = 0.0; + con_loss2 = 0.0; + max_dd = 0.0; + max_dd_pct = 0.0; + rel_dd_pct = 0.0; + rel_dd = 0.0; + expected_payoff = 0.0; + profit_factor = 0.0; + abs_dd = 0.0; + summary_trades = 0; + profit_trades = 0; + loss_trades = 0; + short_trades = 0; + long_trades = 0; + win_short_trades = 0; + win_long_trades = 0; + con_profit_trades1 = 0; + con_profit_trades2 = 0; + con_loss_trades1 = 0; + con_loss_trades2 = 0; + avg_con_wins = 0; + avg_con_losses = 0; + } - /** - * Get initial deposit. - */ - double GetInitDeposit() { - static double deposit = 0; - if (deposit > 0) { - return deposit; + /** + * Get initial deposit. + */ + double GetInitDeposit() { + static double deposit = 0; + if (deposit > 0) { + return deposit; } else if (!Terminal::IsRealtime() && init_deposit > 0) { - deposit = init_deposit; - } else { - deposit = AccountMt::CalcInitDeposit(); - } - return (deposit); + deposit = init_deposit; + } else { + deposit = AccountMt::CalcInitDeposit(); } + return (deposit); + } - /** - * Calculates summary details. - */ - void CalculateSummary() { - int sequence = 0, profitseqs = 0, loss_seqs = 0; - double sequential = 0.0, prev_profit = EMPTY_VALUE, dd_pct, drawdown; - double max_peak = init_deposit, min_peak = init_deposit, balance = init_deposit; - int trades_total = TradeHistoryStatic::HistoryOrdersTotal(); - double profit; + /** + * Calculates summary details. + */ + void CalculateSummary() { + int sequence = 0, profitseqs = 0, loss_seqs = 0; + double sequential = 0.0, prev_profit = EMPTY_VALUE, dd_pct, drawdown; + double max_peak = init_deposit, min_peak = init_deposit, balance = init_deposit; + int trades_total = TradeHistoryStatic::HistoryOrdersTotal(); + double profit; - // Initialize summaries. - InitVars(init_deposit); + // Initialize summaries. + InitVars(init_deposit); - for (int i = 0; i < trades_total; i++) { - if (!Order::TryOrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) { - continue; - } - int type = Order::OrderType(); - // Initial balance not considered. - if (i == 0 && type == ACC_OP_BALANCE) continue; - // Calculate profit. - profit = OrderStatic::Profit() + OrderStatic::Commission() + Order::OrderSwap(); - balance += profit; - // Drawdown check. - if (max_peak < balance) { - drawdown = max_peak-min_peak; - if (max_peak != 0.0) { - dd_pct = drawdown / max_peak * 100.0; - if (rel_dd_pct < dd_pct) { - rel_dd_pct = dd_pct; - rel_dd = drawdown; - } - } - if (max_dd < drawdown) { - max_dd = drawdown; - max_dd_pct = max_peak != 0.0 ? max_dd / max_peak * 100.0 : 100.0; + for (int i = 0; i < trades_total; i++) { + if (!Order::TryOrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) { + continue; + } + int type = Order::OrderType(); + // Initial balance not considered. + if (i == 0 && type == ACC_OP_BALANCE) continue; + // Calculate profit. + profit = OrderStatic::Profit() + OrderStatic::Commission() + Order::OrderSwap(); + balance += profit; + // Drawdown check. + if (max_peak < balance) { + drawdown = max_peak - min_peak; + if (max_peak != 0.0) { + dd_pct = drawdown / max_peak * 100.0; + if (rel_dd_pct < dd_pct) { + rel_dd_pct = dd_pct; + rel_dd = drawdown; } - max_peak = balance; - min_peak = balance; } - if (min_peak > balance) min_peak = balance; - if (max_loss > balance) max_loss = balance; - // Market orders only. - if (type != ORDER_TYPE_BUY && type != ORDER_TYPE_SELL) continue; - // Calculate profit in points. - // profit = (OrderClosePrice() - OrderOpenPrice()) / MarketInfo(OrderSymbol(), MODE_POINT); - summary_profit += profit; - summary_trades++; - if (type == ORDER_TYPE_BUY) { - long_trades++; - } else if (type == ORDER_TYPE_SELL) { - short_trades++; + if (max_dd < drawdown) { + max_dd = drawdown; + max_dd_pct = max_peak != 0.0 ? max_dd / max_peak * 100.0 : 100.0; } - if (profit < 0) { - // Loss trades. - loss_trades++; - gross_loss += profit; - if (min_profit > profit) min_profit = profit; - // Fortune changed. - if (prev_profit != EMPTY_VALUE && prev_profit >= 0) { + max_peak = balance; + min_peak = balance; + } + if (min_peak > balance) min_peak = balance; + if (max_loss > balance) max_loss = balance; + // Market orders only. + if (type != ORDER_TYPE_BUY && type != ORDER_TYPE_SELL) continue; + // Calculate profit in points. + // profit = (OrderClosePrice() - OrderOpenPrice()) / MarketInfo(OrderSymbol(), MODE_POINT); + summary_profit += profit; + summary_trades++; + if (type == ORDER_TYPE_BUY) { + long_trades++; + } else if (type == ORDER_TYPE_SELL) { + short_trades++; + } + if (profit < 0) { + // Loss trades. + loss_trades++; + gross_loss += profit; + if (min_profit > profit) min_profit = profit; + // Fortune changed. + if (prev_profit != EMPTY_VALUE && prev_profit >= 0) { if (con_profit_trades1 < sequence || (con_profit_trades1 == sequence && con_profit2 < sequential)) { - con_profit_trades1 = sequence; - con_profit1 = sequential; - } - if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { - con_profit2 = sequential; - con_profit_trades2 = sequence; - } - profitseqs++; - avg_con_wins += sequence; - sequence = 0; - sequential = 0.0; + con_profit_trades1 = sequence; + con_profit1 = sequential; } - } else { - // Profit trades (profit >= 0). - profit_trades++; - if (type == ORDER_TYPE_BUY) win_long_trades++; - if (type == ORDER_TYPE_SELL) win_short_trades++; - gross_profit += profit; - if (max_profit < profit) max_profit = profit; - // Fortune changed. - if (prev_profit != EMPTY_VALUE && prev_profit < 0) { - if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { - con_loss_trades1 = sequence; - con_loss1 = sequential; - } - if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { - con_loss2 = sequential; - con_loss_trades2 = sequence; - } - loss_seqs++; - avg_con_losses += sequence; - sequence = 0; - sequential = 0.0; + if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { + con_profit2 = sequential; + con_profit_trades2 = sequence; } + profitseqs++; + avg_con_wins += sequence; + sequence = 0; + sequential = 0.0; } - sequence++; - sequential += profit; - prev_profit = profit; - } - // Final drawdown check. - drawdown = max_peak - min_peak; - if (max_peak != 0.0) { - dd_pct = drawdown / max_peak * 100.0; - if (rel_dd_pct < dd_pct) { - rel_dd_pct = dd_pct; - rel_dd = drawdown; - } - } - if (max_dd < drawdown) { - max_dd = drawdown; - max_dd_pct = max_peak != 0 ? max_dd / max_peak * 100.0 : 100.0; - } - // Consider last trade. - if (prev_profit != EMPTY_VALUE) { - profit = prev_profit; - if (profit < 0) { - if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { + } else { + // Profit trades (profit >= 0). + profit_trades++; + if (type == ORDER_TYPE_BUY) win_long_trades++; + if (type == ORDER_TYPE_SELL) win_short_trades++; + gross_profit += profit; + if (max_profit < profit) max_profit = profit; + // Fortune changed. + if (prev_profit != EMPTY_VALUE && prev_profit < 0) { + if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { con_loss_trades1 = sequence; con_loss1 = sequential; } - if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { + if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { con_loss2 = sequential; con_loss_trades2 = sequence; } loss_seqs++; avg_con_losses += sequence; + sequence = 0; + sequential = 0.0; + } + } + sequence++; + sequential += profit; + prev_profit = profit; + } + // Final drawdown check. + drawdown = max_peak - min_peak; + if (max_peak != 0.0) { + dd_pct = drawdown / max_peak * 100.0; + if (rel_dd_pct < dd_pct) { + rel_dd_pct = dd_pct; + rel_dd = drawdown; + } + } + if (max_dd < drawdown) { + max_dd = drawdown; + max_dd_pct = max_peak != 0 ? max_dd / max_peak * 100.0 : 100.0; + } + // Consider last trade. + if (prev_profit != EMPTY_VALUE) { + profit = prev_profit; + if (profit < 0) { + if (con_loss_trades1 < sequence || (con_loss_trades1 == sequence && con_loss2 > sequential)) { + con_loss_trades1 = sequence; + con_loss1 = sequential; + } + if (con_loss2 > sequential || (con_loss2 == sequential && con_loss_trades1 < sequence)) { + con_loss2 = sequential; + con_loss_trades2 = sequence; + } + loss_seqs++; + avg_con_losses += sequence; } else { if (con_profit_trades1 < sequence || (con_profit_trades1 == sequence && con_profit2 < sequential)) { - con_profit_trades1 = sequence; - con_profit1 = sequential; - } + con_profit_trades1 = sequence; + con_profit1 = sequential; + } if (con_profit2 < sequential || (con_profit2 == sequential && con_profit_trades1 < sequence)) { - con_profit2 = sequential; - con_profit_trades2 = sequence; - } - profitseqs++; - avg_con_wins += sequence; + con_profit2 = sequential; + con_profit_trades2 = sequence; } + profitseqs++; + avg_con_wins += sequence; } - // Collecting done. - double dnum, profitkoef = 0.0, losskoef = 0.0, avg_profit = 0.0, avgloss = 0.0; - // Average consecutive wins and losses. - dnum = avg_con_wins; - avg_con_wins = profitseqs > 0 ? (int) (dnum / profitseqs + 0.5) : 0; - dnum = avg_con_losses; - avg_con_losses = loss_seqs > 0 ? (int) (dnum / loss_seqs + 0.5) : 0; - // Absolute values. - if (gross_loss < 0.0) gross_loss *=- 1.0; - if (min_profit < 0.0) min_profit *=- 1.0; - if (con_loss1 < 0.0) con_loss1 *=- 1.0; - if (con_loss2 < 0.0) con_loss2 *=- 1.0; - profit_factor = gross_loss > 0.0 ? gross_profit / gross_loss : 0.0; - // Expected payoff. - avg_profit = profit_trades > 0 ? gross_profit / profit_trades : 0; - avgloss = loss_trades > 0 ? gross_loss / loss_trades : 0; - if (summary_trades > 0) { - profitkoef = 1.0 * profit_trades / summary_trades; - losskoef = 1.0 * loss_trades / summary_trades; - expected_payoff = profitkoef * avg_profit - losskoef * avgloss; - } - // Absolute drawdown. - abs_dd = init_deposit - max_loss; } + // Collecting done. + double dnum, profitkoef = 0.0, losskoef = 0.0, avg_profit = 0.0, avgloss = 0.0; + // Average consecutive wins and losses. + dnum = avg_con_wins; + avg_con_wins = profitseqs > 0 ? (int)(dnum / profitseqs + 0.5) : 0; + dnum = avg_con_losses; + avg_con_losses = loss_seqs > 0 ? (int)(dnum / loss_seqs + 0.5) : 0; + // Absolute values. + if (gross_loss < 0.0) gross_loss *= -1.0; + if (min_profit < 0.0) min_profit *= -1.0; + if (con_loss1 < 0.0) con_loss1 *= -1.0; + if (con_loss2 < 0.0) con_loss2 *= -1.0; + profit_factor = gross_loss > 0.0 ? gross_profit / gross_loss : 0.0; + // Expected payoff. + avg_profit = profit_trades > 0 ? gross_profit / profit_trades : 0; + avgloss = loss_trades > 0 ? gross_loss / loss_trades : 0; + if (summary_trades > 0) { + profitkoef = 1.0 * profit_trades / summary_trades; + losskoef = 1.0 * loss_trades / summary_trades; + expected_payoff = profitkoef * avg_profit - losskoef * avgloss; + } + // Absolute drawdown. + abs_dd = init_deposit - max_loss; + } - /** - * Return summary report. - */ - string GetReport(string sep = "\n", string _currency = "") { - string output = ""; - _currency = _currency != "" ? _currency : AccountInfoString(ACCOUNT_CURRENCY); - output += StringFormat("Currency pair symbol: %s", _Symbol) + sep; - output += StringFormat("Initial deposit: %.2f %s", GetInitDeposit(), _currency) + sep; - output += StringFormat("Total net profit: %.2f %s", summary_profit, _currency) + sep; - output += StringFormat("Gross profit: %.2f %s", gross_profit, _currency) + sep; - output += StringFormat("Gross loss: %.2f %s", gross_loss, _currency) + sep; - output += StringFormat("Absolute drawdown: %.2f %s", abs_dd, _currency) + sep; + /** + * Return summary report. + */ + string GetReport(string sep = "\n", string _currency = "") { + string output = ""; + _currency = _currency != "" ? _currency : AccountInfoString(ACCOUNT_CURRENCY); + output += StringFormat("Currency pair symbol: %s", _Symbol) + sep; + output += StringFormat("Initial deposit: %.2f %s", GetInitDeposit(), _currency) + sep; + output += StringFormat("Total net profit: %.2f %s", summary_profit, _currency) + sep; + output += StringFormat("Gross profit: %.2f %s", gross_profit, _currency) + sep; + output += StringFormat("Gross loss: %.2f %s", gross_loss, _currency) + sep; + output += StringFormat("Absolute drawdown: %.2f %s", abs_dd, _currency) + sep; output += StringFormat("Maximal drawdown: %.1f %s (%.1f%%)", max_dd, _currency, max_dd_pct) + sep; output += StringFormat("Relative drawdown: (%.1f%%) %.1f %s", rel_dd_pct, rel_dd, _currency) + sep; - output += StringFormat("Profit factor: %.2f", profit_factor) + sep; - output += StringFormat("Expected payoff: %.2f", expected_payoff) + sep; - output += StringFormat("Trades total %d", summary_trades) + sep; + output += StringFormat("Profit factor: %.2f", profit_factor) + sep; + output += StringFormat("Expected payoff: %.2f", expected_payoff) + sep; + output += StringFormat("Trades total %d", summary_trades) + sep; output += StringFormat("Short positions (won %%): %d (%.1f%%)", short_trades, short_trades ? 100.0 * win_short_trades / short_trades : 0) + sep; @@ -327,22 +328,22 @@ class SummaryReport { output += StringFormat("Loss trades (%% of total): %d (%.1f%%)", loss_trades, loss_trades ? 100.0 * loss_trades / summary_trades : 0) + sep; - output += StringFormat("Largest profit trade: %.2f", max_profit) + sep; - output += StringFormat("Largest loss trade: %.2f", -min_profit) + sep; + output += StringFormat("Largest profit trade: %.2f", max_profit) + sep; + output += StringFormat("Largest loss trade: %.2f", -min_profit) + sep; output += StringFormat("Average profit trade: %.2f", profit_trades ? gross_profit / profit_trades : 0) + sep; output += StringFormat("Average loss trade: %.2f", loss_trades ? -gross_loss / loss_trades : 0) + sep; - output += StringFormat("Average consecutive wins: %.2f", avg_con_wins) + sep; - output += StringFormat("Average consecutive losses: %.2f", avg_con_losses) + sep; + output += StringFormat("Average consecutive wins: %.2f", avg_con_wins) + sep; + output += StringFormat("Average consecutive losses: %.2f", avg_con_losses) + sep; output += StringFormat("Maximum consecutive wins (profit in money): %d (%.2f)", con_profit_trades1, con_profit1) + sep; - output += StringFormat("Maximum consecutive losses (loss in money): %d (%.2f)", con_loss_trades1, -con_loss1) + sep; + output += StringFormat("Maximum consecutive losses (loss in money): %d (%.2f)", con_loss_trades1, -con_loss1) + sep; output += StringFormat("Maximal consecutive profit (count of wins): %.2f (%d)", con_profit2, con_profit_trades2) + sep; - output += StringFormat("Maximal consecutive loss (count of losses): %.2f (%d)", con_loss2, con_loss_trades2) + sep; - return output; - } + output += StringFormat("Maximal consecutive loss (count of losses): %.2f (%d)", con_loss2, con_loss_trades2) + sep; + return output; + } }; diff --git a/SymbolInfo.extern.h b/SymbolInfo.extern.h index 0d2f6018b..dd768d866 100644 --- a/SymbolInfo.extern.h +++ b/SymbolInfo.extern.h @@ -27,11 +27,17 @@ // Define external global functions. #ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once + extern long SymbolInfoInteger(string name, ENUM_SYMBOL_INFO_INTEGER prop_id); extern bool SymbolInfoMarginRate(string name, ENUM_ORDER_TYPE order_type, double &initial_margin_rate, double &maintenance_margin_rate); extern bool SymbolInfoTick(string symbol, MqlTick &tick); // Define external global variables. -extern string _Symbol; +class SymbolGetter { + public: + operator string() const; +} _Symbol; #endif diff --git a/SymbolInfo.mqh b/SymbolInfo.mqh index 45dbc5b12..3de9448bb 100644 --- a/SymbolInfo.mqh +++ b/SymbolInfo.mqh @@ -111,7 +111,7 @@ class SymbolInfo : public Object { */ MqlTick GetTick() { if (!SymbolInfoTick(symbol, last_tick)) { - GetLogger().Error("Cannot return current prices!", __FUNCTION__); + GetLogger() PTR_DEREF Error("Cannot return current prices!", __FUNCTION__); } return last_tick; } @@ -492,7 +492,7 @@ class SymbolInfo : public Object { static int _index = 0; if (_index++ >= ArraySize(tick_data) - 1) { if (ArrayResize(tick_data, _index + 100, 1000) < 0) { - GetLogger().Error(StringFormat("Cannot resize array (size: %d)!", _index), __FUNCTION__); + GetLogger() PTR_DEREF Error(StringFormat("Cannot resize array (size: %d)!", _index), __FUNCTION__); return false; } } @@ -523,10 +523,11 @@ class SymbolInfo : public Object { "Tick size: %g (%g pts), Tick value: %g (%g/%g), " + "Digits: %d, Spread: %d pts, Trade stops level: %d, " + "Trade contract size: %g, Min lot: %g, Max lot: %g, Lot step: %g, " + "Freeze level: %d, Swap (long/short/mode): %g/%g/%d, Margin initial (maintenance): %g (%g)", - GetSymbol(), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), GetPointSize(), GetPipSize(), - GetTickSize(), GetTradeTickSize(), GetTickValue(), GetTickValueProfit(), GetTickValueLoss(), GetDigits(), - GetSpread(), GetTradeStopsLevel(), GetTradeContractSize(), GetVolumeMin(), GetVolumeMax(), GetVolumeStep(), - GetFreezeLevel(), GetSwapLong(), GetSwapShort(), GetSwapMode(), GetMarginInit(), GetMarginMaintenance()); + C_STR(GetSymbol()), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), GetPointSize(), + GetPipSize(), GetTickSize(), GetTradeTickSize(), GetTickValue(), GetTickValueProfit(), GetTickValueLoss(), + GetDigits(), GetSpread(), GetTradeStopsLevel(), GetTradeContractSize(), GetVolumeMin(), GetVolumeMax(), + GetVolumeStep(), GetFreezeLevel(), GetSwapLong(), GetSwapShort(), GetSwapMode(), GetMarginInit(), + GetMarginMaintenance()); } /** @@ -536,7 +537,7 @@ class SymbolInfo : public Object { return !_header ? StringFormat(string("%s,%g,%g,%d,%g,%g,%g,") + "%g,%g,%g,%g,%g," + "%d,%d,%d," + "%g,%g,%g,%g," + "%d,%g,%g,%d,%g,%g", - GetSymbol(), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), + C_STR(GetSymbol()), GetLastAsk(), GetLastBid(), GetLastVolume(), GetSessionVolume(), GetPointSize(), GetPipSize(), GetTickSize(), GetTradeTickSize(), GetTickValue(), GetTickValueProfit(), GetTickValueLoss(), GetDigits(), GetSpread(), GetTradeStopsLevel(), GetTradeContractSize(), GetVolumeMin(), GetVolumeMax(), GetVolumeStep(), GetFreezeLevel(), diff --git a/SymbolInfo.struct.h b/SymbolInfo.struct.h index e7488b05a..89cdc9ae8 100644 --- a/SymbolInfo.struct.h +++ b/SymbolInfo.struct.h @@ -32,10 +32,10 @@ // Includes. #include "Serializer/Serializable.h" +#include "Serializer/Serializer.h" #include "Std.h" #include "SymbolInfo.struct.static.h" #include "Tick/Tick.struct.h" -#include "Serializer/Serializer.h" // Defines struct to store symbol data. struct SymbolInfoEntry @@ -58,7 +58,7 @@ struct SymbolInfoEntry spread = (unsigned int)round((ask - bid) * pow(10, SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS))); } // Copy constructor. - SymbolInfoEntry(const SymbolInfoEntry& _sie) { this = _sie; } + SymbolInfoEntry(const SymbolInfoEntry& _sie) { THIS_REF = _sie; } // Getters string ToCSV() { return StringFormat("%g,%g,%g,%g,%d", bid, ask, last, spread, volume); } // Serializers. diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index f845ba690..d88e53e0c 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -27,7 +27,10 @@ #include "MQL5.mqh" #include "Order.enum.h" +#include "Platform.extern.h" #include "Std.h" +#include "SymbolInfo.enum.h" +#include "SymbolInfo.extern.h" #include "Tick/Tick.struct.h" /** @@ -38,7 +41,7 @@ struct SymbolInfoStatic { /** * Get the current symbol pair from the current chart. */ - static string GetCurrentSymbol() { return _Symbol; } + static string GetCurrentSymbol() { return ::Symbol(); } /** * Updates and gets the latest tick prices. diff --git a/Task/Task.h b/Task/Task.h index 37f799bed..104c44fc4 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -30,10 +30,6 @@ #pragma once #endif -// Prevents processing this includes file for the second time. -#ifndef TASK_H -#define TASK_H - // Includes. #include "../DictStruct.mqh" #include "../Refs.mqh" @@ -60,7 +56,7 @@ class Task : public Taskable { /** * Class copy constructor. */ - Task(Task &_task) { tasks = PTR_TO_REF(_task.GetTasks()); } + Task(const Task &_task) { tasks = PTR_TO_REF(_task.GetTasks()); } /** * Class deconstructor. @@ -215,7 +211,7 @@ class Task : public Taskable { /** * Returns tasks. */ - DictStruct *GetTasks() { return &tasks; } + const DictStruct *GetTasks() const { return &tasks; } /** * Count entry flags. @@ -318,4 +314,17 @@ class Task : public Taskable { /* Other methods */ }; -#endif // TASK_H + +#ifdef EMSCRIPTEN +#include +#include + +EMSCRIPTEN_BINDINGS(Task) { + emscripten::class_("Task").smart_ptr>("Ref").constructor(emscripten::optional_override([]() { + return Ref(new Task()); + })) + //.function("Add", optional_override([](Task &self, Ref task) { self.Add(task.Ptr()); })) + ; +} + +#endif diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 98ffe2375..ebf9bada0 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -65,6 +65,15 @@ struct TaskEntry { public: // Constructors. TaskEntry() { Init(); } + TaskEntry(const TaskEntry &_entry) + : action(_entry.action), + cond(_entry.cond), + expires(_entry.expires), + last_process(_entry.last_process), + last_success(_entry.last_success), + flags(_entry.flags) { + Init(); + } TaskEntry(const TaskActionEntry &_action, const TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } template TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { @@ -143,3 +152,10 @@ struct TaskEntry { SERIALIZER_EMPTY_STUB; }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TaskEntry) { emscripten::class_("TaskEntry").constructor(); } + +#endif diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 88b35bbed..83792f8af 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -35,6 +35,7 @@ #define TASK_ACTION_H // Includes. +#include "../DateTime.mqh" #include "../Std.h" #include "../Terminal.define.h" #include "TaskAction.enum.h" diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 12d1338f1..f604fa60c 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -35,6 +35,7 @@ #define TASK_CONDITION_H // Includes. +#include "../DateTime.mqh" #include "../Std.h" #include "../Terminal.define.h" #include "TaskCondition.enum.h" diff --git a/Task/TaskGetter.h b/Task/TaskGetter.h index 8c7f2fddd..9ece2c0ba 100644 --- a/Task/TaskGetter.h +++ b/Task/TaskGetter.h @@ -36,6 +36,7 @@ // Includes. //#include "TaskGetter.enum.h" +#include "../DateTime.mqh" #include "../Terminal.define.h" #include "TaskGetter.struct.h" #include "TaskGetterBase.h" diff --git a/Task/TaskManager.h b/Task/TaskManager.h index d827222f4..f9937324e 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -93,6 +93,27 @@ class TaskManager { return Add((Task *)_task_obj); } + /** + * Clears tasks list. + */ + void Clear() { + Task *task0 = tasks[0].Ptr(); + +#ifndef __MQL__ + for (unsigned int i = 0; i < tasks.Size(); ++i) { + std::cout << "Task #" << i << ": " << tasks[i].ToString() << std::endl; + } +#endif + + tasks.Clear(); + +#ifndef __MQL__ + std::cout << "Tasks cleared." << std::endl; + std::cout << task0 PTR_DEREF ToString() << std::endl; + // std::cout.flush(); +#endif + } + /* Getters */ /** @@ -117,4 +138,23 @@ class TaskManager { } }; +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TaskManager) { + emscripten::class_("TaskManager") + .constructor() + .function("Add", emscripten::optional_override([](TaskManager &self, Ref task) { + Print("Adding Task"); + Print(StringToUpper("Testing StringToUpper")); + Print(StringToLower("Testing StringToLower")); + self.Add(task.Ptr()); + })) + // .function("Add", emscripten::select_overload(&TaskManager::Add)) + .function("Clear", &TaskManager::Clear) + .function("Process", &TaskManager::Process); +} + +#endif + #endif // TASK_MANAGER_H diff --git a/Task/TaskObject.h b/Task/TaskObject.h index 6a5ac7cdc..279a12935 100644 --- a/Task/TaskObject.h +++ b/Task/TaskObject.h @@ -54,7 +54,7 @@ class TaskObject : public Task { /** * Class constructor with task entry as argument. */ - TaskObject(TaskEntry &_tentry, TA *_obja = NULL, TC *_objc = NULL) : obja(_obja), objc(_objc), Task(_tentry) {} + TaskObject(TaskEntry &_tentry, TA *_obja = nullptr, TC *_objc = nullptr) : Task(_tentry), obja(_obja), objc(_objc) {} /** * Class deconstructor. diff --git a/Task/tests/TaskGetter.test.cpp b/Task/tests/TaskGetter.test.cpp index 43d1c2f65..6bc453109 100644 --- a/Task/tests/TaskGetter.test.cpp +++ b/Task/tests/TaskGetter.test.cpp @@ -32,4 +32,4 @@ #include "../../Std.h" #include "../../String.extern.h" -int main(int argc, char **argv) {} +int main(int argc, char **argv) { return 0; } diff --git a/Task/tests/TaskSetter.test.cpp b/Task/tests/TaskSetter.test.cpp index 7df0708a3..b114e8460 100644 --- a/Task/tests/TaskSetter.test.cpp +++ b/Task/tests/TaskSetter.test.cpp @@ -25,10 +25,11 @@ */ // Includes. +#include "../TaskSetter.h" + #include "../../Common.define.h" #include "../../Common.extern.h" #include "../../Std.h" #include "../../String.extern.h" -#include "../TaskSetter.h" int main(int argc, char **argv) {} diff --git a/Terminal.define.h b/Terminal.define.h index 7f5f39347..fcdc5e646 100644 --- a/Terminal.define.h +++ b/Terminal.define.h @@ -37,142 +37,280 @@ #define CP_UTF7 65000 // UTF-7 code page. #define CP_UTF8 65001 // UTF-8 code page. +#ifndef __MQL__ + // Colors. -#define AliceBlue 0xFFF8F0 -#define AntiqueWhite 0xD7EBFA -#define Aqua 0xFFFF00 -#define Aquamarine 0xD4FF7F -#define Beige 0xDCF5F5 -#define Bisque 0xC4E4FF -#define Black 0x000000 -#define BlanchedAlmond 0xCDEBFF -#define Blue 0xFF0000 -#define BlueViolet 0xE22B8A -#define Brown 0x2A2AA5 -#define BurlyWood 0x87B8DE -#define CadetBlue 0xA09E5F -#define Chartreuse 0x00FF7F -#define Chocolate 0x1E69D2 -#define Coral 0x507FFF -#define CornflowerBlue 0xED9564 -#define Cornsilk 0xDCF8FF -#define Crimson 0x3C14DC -#define DarkBlue 0x8B0000 -#define DarkGoldenrod 0x0B86B8 -#define DarkGray 0xA9A9A9 -#define DarkGreen 0x006400 -#define DarkKhaki 0x6BB7BD -#define DarkOliveGreen 0x2F6B55 -#define DarkOrange 0x008CFF -#define DarkOrchid 0xCC3299 -#define DarkSalmon 0x7A96E9 -#define DarkSlateBlue 0x8B3D48 -#define DarkSlateGray 0x4F4F2F -#define DarkTurquoise 0xD1CE00 -#define DarkViolet 0xD30094 -#define DeepPink 0x9314FF -#define DeepSkyBlue 0xFFBF00 -#define DimGray 0x696969 -#define DodgerBlue 0xFF901E -#define FireBrick 0x2222B2 -#define ForestGreen 0x228B22 -#define Gainsboro 0xDCDCDC -#define Gold 0x00D7FF -#define Goldenrod 0x20A5DA -#define Gray 0x808080 -#define Green 0x008000 -#define GreenYellow 0x2FFFAD -#define Honeydew 0xF0FFF0 -#define HotPink 0xB469FF -#define IndianRed 0x5C5CCD -#define Indigo 0x82004B -#define Ivory 0xF0FFFF -#define Khaki 0x8CE6F0 -#define Lavender 0xFAE6E6 -#define LavenderBlush 0xF5F0FF -#define LawnGreen 0x00FC7C -#define LemonChiffon 0xCDFAFF -#define LightBlue 0xE6D8AD -#define LightCoral 0x8080F0 -#define LightCyan 0xFFFFE0 -#define LightGoldenrod 0xD2FAFA -#define LightGray 0xD3D3D3 -#define LightGreen 0x90EE90 -#define LightPink 0xC1B6FF -#define LightSalmon 0x7AA0FF -#define LightSeaGreen 0xAAB220 -#define LightSkyBlue 0xFACE87 -#define LightSlateGray 0x998877 -#define LightSteelBlue 0xDEC4B0 -#define LightYellow 0xE0FFFF -#define Lime 0x00FF00 -#define LimeGreen 0x32CD32 -#define Linen 0xE6F0FA -#define Magenta 0xFF00FF -#define Maroon 0x000080 -#define MediumAquamarine 0xAACD66 -#define MediumBlue 0xCD0000 -#define MediumOrchid 0xD355BA -#define MediumPurple 0xDB7093 -#define MediumSeaGreen 0x71B33C -#define MediumSlateBlue 0xEE687B -#define MediumSpringGreen 0x9AFA00 -#define MediumTurquoise 0xCCD148 -#define MediumVioletRed 0x8515C7 -#define MidnightBlue 0x701919 -#define MintCream 0xFAFFF5 -#define MistyRose 0xE1E4FF -#define Moccasin 0xB5E4FF -#define NavajoWhite 0xADDEFF -#define Navy 0x800000 -#define OldLace 0xE6F5FD -#define Olive 0x008080 -#define OliveDrab 0x238E6B -#define Orange 0x00A5FF -#define OrangeRed 0x0045FF -#define Orchid 0xD670DA -#define PaleGoldenrod 0xAAE8EE -#define PaleGreen 0x98FB98 -#define PaleTurquoise 0xEEEEAF -#define PaleVioletRed 0x9370DB -#define PapayaWhip 0xD5EFFF -#define PeachPuff 0xB9DAFF -#define Peru 0x3F85CD -#define Pink 0xCBC0FF -#define Plum 0xDDA0DD -#define PowderBlue 0xE6E0B0 -#define Purple 0x800080 -#define Red 0x0000FF -#define RosyBrown 0x8F8FBC -#define RoyalBlue 0xE16941 -#define SaddleBrown 0x13458B -#define Salmon 0x7280FA -#define SandyBrown 0x60A4F4 -#define SeaGreen 0x578B2E -#define Seashell 0xEEF5FF -#define Sienna 0x2D52A0 -#define Silver 0xC0C0C0 -#define SkyBlue 0xEBCE87 -#define SlateBlue 0xCD5A6A -#define SlateGray 0x908070 -#define Snow 0xFAFAFF -#define SpringGreen 0x7FFF00 -#define SteelBlue 0xB48246 -#define Tan 0x8CB4D2 -#define Teal 0x808000 -#define Thistle 0xD8BFD8 -#define Tomato 0x4763FF -#define Turquoise 0xD0E040 -#define Violet 0xEE82EE -#define Wheat 0xB3DEF5 -#define White 0xFFFFFF -#define WhiteSmoke 0xF5F5F5 -#define Yellow 0x00FFFF -#define YellowGreen 0x32CD9A +#define clrAliceBlue 0x00F0F8FF +#define clrAntiqueWhite 0x00FAEBD7 +#define clrAqua 0x0000FFFF +#define clrAquamarine 0x007FFFD4 +#define clrBeige 0x00F5F5DC +#define clrBisque 0x00FFE4C4 +#define clrBlack 0x00000000 +#define clrBlanchedAlmond 0x00FFEBCD +#define clrBlue 0x000000FF +#define clrBlueViolet 0x008A2BE2 +#define clrBrown 0x00A52A2A +#define clrBurlyWood 0x00DEB887 +#define clrCadetBlue 0x005F9EA0 +#define clrChartreuse 0x007FFF00 +#define clrChocolate 0x00D2691E +#define clrCoral 0x00FF7F50 +#define clrCornflowerBlue 0x006495ED +#define clrCornsilk 0x00FFF8DC +#define clrCrimson 0x00DC143C +#define clrDarkBlue 0x0000008B +#define clrDarkGoldenrod 0x00B8860B +#define clrDarkGray 0x00A9A9A9 +#define clrDarkGreen 0x00006400 +#define clrDarkKhaki 0x00BDB76B +#define clrDarkOliveGreen 0x00556B2F +#define clrDarkOrange 0x00FF8C00 +#define clrDarkOrchid 0x009932CC +#define clrDarkSalmon 0x00E9967A +#define clrDarkSeaGreen 0x008FBC8F +#define clrDarkSlateBlue 0x00483D8B +#define clrDarkSlateGray 0x002F4F4F +#define clrDarkTurquoise 0x0000CED1 +#define clrDarkViolet 0x009400D3 +#define clrDeepPink 0x00FF1493 +#define clrDeepSkyBlue 0x0000BFFF +#define clrDimGray 0x00696969 +#define clrDodgerBlue 0x001E90FF +#define clrFireBrick 0x00B22222 +#define clrForestGreen 0x00228B22 +#define clrGainsboro 0x00DCDCDC +#define clrGold 0x00FFD700 +#define clrGoldenrod 0x00DAA520 +#define clrGray 0x00808080 +#define clrGreen 0x00008000 +#define clrGreenYellow 0x00ADFF2F +#define clrHoneydew 0x00F0FFF0 +#define clrHotPink 0x00FF69B4 +#define clrIndianRed 0x00CD5C5C +#define clrIndigo 0x004B0082 +#define clrIvory 0x00FFFFF0 +#define clrKhaki 0x00F0E68C +#define clrLavender 0x00E6E6FA +#define clrLavenderBlush 0x00FFF0F5 +#define clrLawnGreen 0x007CFC00 +#define clrLemonChiffon 0x00FFFACD +#define clrLightBlue 0x00ADD8E6 +#define clrLightCoral 0x00F08080 +#define clrLightCyan 0x00E0FFFF +#define clrLightGoldenrodYellow 0x00FAFAD2 +#define clrLightGreen 0x0090EE90 +#define clrLightGrey 0x00D3D3D3 +#define clrLightPink 0x00FFB6C1 +#define clrLightSalmon 0x00FFA07A +#define clrLightSeaGreen 0x0020B2AA +#define clrLightSkyBlue 0x0087CEFA +#define clrLightSlateGray 0x00778899 +#define clrLightSteelBlue 0x00B0C4DE +#define clrLightYellow 0x00FFFFE0 +#define clrLime 0x0000FF00 +#define clrLimeGreen 0x0032CD32 +#define clrLinen 0x00FAF0E6 +#define clrMagenta 0x00FF00FF +#define clrMaroon 0x00800000 +#define clrMediumAquamarine 0x0066CDAA +#define clrMediumBlue 0x000000CD +#define clrMediumOrchid 0x00BA55D3 +#define clrMediumPurple 0x009370DB +#define clrMediumSeaGreen 0x003CB371 +#define clrMediumSlateBlue 0x007B68EE +#define clrMediumSpringGreen 0x0000FA9A +#define clrMediumTurquoise 0x0048D1CC +#define clrMediumVioletRed 0x00C71585 +#define clrMidnightBlue 0x00191970 +#define clrMintCream 0x00F5FFFA +#define clrMistyRose 0x00FFE4E1 +#define clrMoccasin 0x00FFE4B5 +#define clrNavajoWhite 0x00FFDEAD +#define clrNavy 0x00000080 +#define clrOldLace 0x00FDF5E6 +#define clrOlive 0x00808000 +#define clrOliveDrab 0x006B8E23 +#define clrOrange 0x00FFA500 +#define clrOrangeRed 0x00FF4500 +#define clrOrchid 0x00DA70D6 +#define clrPaleGoldenrod 0x00EEE8AA +#define clrPaleGreen 0x0098FB98 +#define clrPaleTurquoise 0x00AFEEEE +#define clrPaleVioletRed 0x00DB7093 +#define clrPapayaWhip 0x00FFEFD5 +#define clrPeachPuff 0x00FFDAB9 +#define clrPeru 0x00CD853F +#define clrPink 0x00FFC0CB +#define clrPlum 0x00DDA0DD +#define clrPowderBlue 0x00B0E0E6 +#define clrPurple 0x00800080 +#define clrRed 0x00FF0000 +#define clrRosyBrown 0x00BC8F8F +#define clrRoyalBlue 0x004169E1 +#define clrSaddleBrown 0x008B4513 +#define clrSalmon 0x00FA8072 +#define clrSandyBrown 0x00F4A460 +#define clrSeaGreen 0x002E8B57 +#define clrSeashell 0x00FFF5EE +#define clrSienna 0x00A0522D +#define clrSilver 0x00C0C0C0 +#define clrSkyBlue 0x0087CEEB +#define clrSlateBlue 0x006A5ACD +#define clrSlateGray 0x00708090 +#define clrSnow 0x00FFFAFA +#define clrSpringGreen 0x0000FF7F +#define clrSteelBlue 0x004682B4 +#define clrTan 0x00D2B48C +#define clrTeal 0x00008080 +#define clrThistle 0x00D8BFD8 +#define clrTomato 0x00FF6347 +#define clrTurquoise 0x0040E0D0 +#define clrViolet 0x00EE82EE +#define clrWheat 0x00F5DEB3 +#define clrWhite 0x00FFFFFF +#define clrWhiteSmoke 0x00F5F5F5 +#define clrYellow 0x00FFFF00 +#define clrYellowGreen 0x009ACD32 + +#define AliceBlue clrAliceBlue +#define AntiqueWhite clrAntiqueWhite +#define Aqua clrAqua +#define Aquamarine clrAquamarine +#define Beige clrBeige +#define Bisque clrBisque +#define Black clrBlack +#define BlanchedAlmond clrBlanchedAlmond +#define Blue clrBlue +#define BlueViolet clrBlueViolet +#define Brown clrBrown +#define BurlyWood clrBurlyWood +#define CadetBlue clrCadetBlue +#define Chartreuse clrChartreuse +#define Chocolate clrChocolate +#define Coral clrCoral +#define CornflowerBlue clrCornflowerBlue +#define Cornsilk clrCornsilk +#define Crimson clrCrimson +#define DarkBlue clrDarkBlue +#define DarkGoldenrod clrDarkGoldenrod +#define DarkGray clrDarkGray +#define DarkGreen clrDarkGreen +#define DarkKhaki clrDarkKhaki +#define DarkOliveGreen clrDarkOliveGreen +#define DarkOrange clrDarkOrange +#define DarkOrchid clrDarkOrchid +#define DarkSalmon clrDarkSalmon +#define DarkSeaGreen clrDarkSeaGreen +#define DarkSlateBlue clrDarkSlateBlue +#define DarkSlateGray clrDarkSlateGray +#define DarkTurquoise clrDarkTurquoise +#define DarkViolet clrDarkViolet +#define DeepPink clrDeepPink +#define DeepSkyBlue clrDeepSkyBlue +#define DimGray clrDimGray +#define DodgerBlue clrDodgerBlue +#define FireBrick clrFireBrick +#define ForestGreen clrForestGreen +#define Gainsboro clrGainsboro +#define Gold clrGold +#define Goldenrod clrGoldenrod +#define Gray clrGray +#define Green clrGreen +#define GreenYellow clrGreenYellow +#define Honeydew clrHoneydew +#define HotPink clrHotPink +#define IndianRed clrIndianRed +#define Indigo clrIndigo +#define Ivory clrIvory +#define Khaki clrKhaki +#define Lavender clrLavender +#define LavenderBlush clrLavenderBlush +#define LawnGreen clrLawnGreen +#define LemonChiffon clrLemonChiffon +#define LightBlue clrLightBlue +#define LightCoral clrLightCoral +#define LightCyan clrLightCyan +#define LightGoldenrod clrLightGoldenrod +#define LightGray clrLightGray +#define LightGreen clrLightGreen +#define LightPink clrLightPink +#define LightSalmon clrLightSalmon +#define LightSeaGreen clrLightSeaGreen +#define LightSkyBlue clrLightSkyBlue +#define LightSlateGray clrLightSlateGray +#define LightSteelBlue clrLightSteelBlue +#define LightYellow clrLightYellow +#define Lime clrLime +#define LimeGreen clrLimeGreen +#define Linen clrLinen +#define Magenta clrMagenta +#define Maroon clrMaroon +#define MediumAquamarine clrMediumAquamarine +#define MediumBlue clrMediumBlue +#define MediumOrchid clrMediumOrchid +#define MediumPurple clrMediumPurple +#define MediumSeaGreen clrMediumSeaGreen +#define MediumSlateBlue clrMediumSlateBlue +#define MediumSpringGreen clrMediumSpringGreen +#define MediumTurquoise clrMediumTurquoise +#define MediumVioletRed clrMediumVioletRed +#define MidnightBlue clrMidnightBlue +#define MintCream clrMintCream +#define MistyRose clrMistyRose +#define Moccasin clrMoccasin +#define NavajoWhite clrNavajoWhite +#define Navy clrNavy +#define OldLace clrOldLace +#define Olive clrOlive +#define OliveDrab clrOliveDrab +#define Orange clrOrange +#define OrangeRed clrOrangeRed +#define Orchid clrOrchid +#define PaleGoldenrod clrPaleGoldenrod +#define PaleGreen clrPaleGreen +#define PaleTurquoise clrPaleTurquoise +#define PaleVioletRed clrPaleVioletRed +#define PapayaWhip clrPapayaWhip +#define PeachPuff clrPeachPuff +#define Peru clrPeru +#define Pink clrPink +#define Plum clrPlum +#define PowderBlue clrPowderBlue +#define Purple clrPurple +#define Red clrRed +#define RosyBrown clrRosyBrown +#define RoyalBlue clrRoyalBlue +#define SaddleBrown clrSaddleBrown +#define Salmon clrSalmon +#define SandyBrown clrSandyBrown +#define SeaGreen clrSeaGreen +#define Seashell clrSeashell +#define Sienna clrSienna +#define Silver clrSilver +#define SkyBlue clrSkyBlue +#define SlateBlue clrSlateBlue +#define SlateGray clrSlateGray +#define Snow clrSnow +#define SpringGreen clrSpringGreen +#define SteelBlue clrSteelBlue +#define Tan clrTan +#define Teal clrTeal +#define Thistle clrThistle +#define Tomato clrTomato +#define Turquoise clrTurquoise +#define Violet clrViolet +#define Wheat clrWheat +#define White clrWhite +#define WhiteSmoke clrWhiteSmoke +#define Yellow clrYellow +#define YellowGreen clrYellowGreen + +#endif + #ifndef __MQL__ #define clrNONE -1 #define CLR_NONE -1 -#define DarkSeaGreen 0x8BBC8F #endif // Custom user errors. diff --git a/Terminal.enum.h b/Terminal.enum.h index c1df1d2c2..a79712f4c 100644 --- a/Terminal.enum.h +++ b/Terminal.enum.h @@ -59,26 +59,46 @@ enum ENUM_INIT_RETCODE { #ifndef __MQL__ /** - * Enumeration for the MQL program properties (integer type). + * Enumeration for the MQL5 program properties (integer type). * * @docs * - https://www.mql5.com/en/docs/constants/environment_state/mql5_programm_info */ + enum ENUM_MQL_INFO_INTEGER { - MQL_DEBUG, // Indication that the program is running in the debugging mode (bool). - MQL_DLLS_ALLOWED, // The permission to use DLL for the given running program (bool). - MQL_FORWARD, // Indication that the program is running in the forward testing process (bool). - MQL_FRAME_MODE, // Indication that the program is running in gathering optimization result frames mode (bool). - MQL_LICENSE_TYPE, // Type of license of the EX module. - MQL_MEMORY_LIMIT, // Maximum possible amount of dynamic memory for MQL5 program in MB (int). - MQL_MEMORY_USED, // Memory used by MQL5 program in MB (int). - MQL_OPTIMIZATION, // Indication that the program is running in the optimization mode (bool). - MQL_PROFILER, // Indication that the program is running in the code profiling mode (bool). - MQL_PROGRAM_TYPE, // Type of the MQL5 program (ENUM_PROGRAM_TYPE). - MQL_SIGNALS_ALLOWED, // The permission to modify the Signals for the given running program (bool). - MQL_TESTER, // Indication that the program is running in the tester (bool). - MQL_TRADE_ALLOWED, // The permission to trade for the given running program (bool). - MQL_VISUAL_MODE, // Indication that the program is running in the visual testing mode (bool). + MQL_DEBUG = 5, // Indication that the program is running in the debugging mode (bool). + MQL_DLLS_ALLOWED = 3, // The permission to use DLL for the given running program (bool). + MQL_FORWARD = 16, // Indication that the program is running in the forward testing process (bool). + MQL_FRAME_MODE = 12, // Indication that the program is running in gathering optimization result frames mode (bool). + MQL_HANDLES_USED = 17, // The current number of active object handles. These include both dynamic (created via new) + // and non-dynamic objects, global/local variables or class members. The more handles a + // program uses, the more resources it consumes. + MQL_LICENSE_TYPE = 9, // Type of license of the EX module. + MQL_MEMORY_LIMIT = 13, // Maximum possible amount of dynamic memory for MQL5 program in MB (int). + MQL_MEMORY_USED = 11, // Memory used by MQL5 program in MB (int). + MQL_OPTIMIZATION = 7, // Indication that the program is running in the optimization mode (bool). + MQL_PROFILER = 10, // Indication that the program is running in the code profiling mode (bool). + MQL_PROGRAM_TYPE = 2, // Type of the MQL5 program (ENUM_PROGRAM_TYPE). + MQL_SIGNALS_ALLOWED = 14, // The permission to modify the Signals for the given running program (bool). + MQL_TESTER = 6, // Indication that the program is running in the tester (bool). + MQL_TRADE_ALLOWED = 4, // The permission to trade for the given running program (bool). + MQL_VISUAL_MODE = 8, // Indication that the program is running in the visual testing mode (bool). + + // Additional enumerations for MQL4 compatibility: + + // MQL4: + MQL_CODEPAGE = 128 +}; + +/** + * @docs + * - https://www.mql5.com/en/docs/constants/environment_state/mql5_programm_info#enum_program_type + */ +enum ENUM_PROGRAM_TYPE { + PROGRAM_SCRIPT, // Script. + PROGRAM_EXPERT, // Expert. + PROGRAM_INDICATOR, // Indicator + PROGRAM_SERVICE, // Service. }; /** @@ -88,8 +108,9 @@ enum ENUM_MQL_INFO_INTEGER { * - https://www.mql5.com/en/docs/constants/environment_state/mql5_programm_info */ enum ENUM_MQL_INFO_STRING { - MQL_PROGRAM_NAME, // Name of the running mql5-program (string). - MQL5_PROGRAM_PATH, // Path for the given running program (string). + MQL_PROGRAM_NAME, // Name of the running mql5-program (string). + MQL5_PROGRAM_PATH, // Path for the given running program (string). + MQL_PROGRAM_PATH = MQL5_PROGRAM_PATH // Same as above. }; /** @@ -164,6 +185,17 @@ enum ENUM_TERMINAL_INFO_INTEGER { TERMINAL_X64, // Indication of the "64-bit terminal" (bool). }; +/** + * Enumeration for MQLInfoInteger(MQL_LICENSE_TYPE). + */ +enum ENUM_LICENSE_TYPE { + LICENSE_FREE, // A free unlimited version. + LICENSE_DEMO, // A trial version of a paid product from the Market. It works only in the strategy tester. + LICENSE_FULL, // A purchased licensed version allows at least 5 activations. The number of activations is specified + // by seller. Seller may increase the allowed number of activations. + LICENSE_TIME // A version with limited term liсense. +}; + /** * Enumeration for the Terminal properties (string). * @@ -198,4 +230,109 @@ enum ENUM_UNINIT_REASON { REASON_INITFAILED = 8, REASON_CLOSE = 9, }; + +enum ENUM_DRAW_TYPE { + DRAW_NONE, + DRAW_LINE, + DRAW_SECTION, + DRAW_HISTOGRAM, + DRAW_HISTOGRAM2, + DRAW_ARROW, + DRAW_ZIGZAG, + DRAW_FILLING, + DRAW_BARS, + DRAW_CANDLES, + DRAW_COLOR_LINE, + DRAW_COLOR_SECTION, + DRAW_COLOR_HISTOGRAM, + DRAW_COLOR_HISTOGRAM2, + DRAW_COLOR_ARROW, + DRAW_COLOR_ZIGZAG, + DRAW_COLOR_BARS, + DRAW_COLOR_CANDLES +}; + +enum ENUM_PLOT_PROPERTY_INTEGER { + PLOT_ARROW, + PLOT_ARROW_SHIFT, + PLOT_DRAW_BEGIN, + PLOT_DRAW_TYPE, + PLOT_SHOW_DATA, + PLOT_SHIFT, + PLOT_LINE_STYLE, + PLOT_LINE_WIDTH, + PLOT_COLOR_INDEXES, + PLOT_LINE_COLOR +}; + +enum ENUM_PLOT_PROPERTY_DOUBLE { PLOT_EMPTY_VALUE }; + +enum ENUM_PLOT_PROPERTY_STRING { PLOT_LABEL }; + +enum ENUM_LINE_STYLE { STYLE_SOLID, STYLE_DASH, STYLE_DOT, STYLE_DASHDOT, STYLE_DASHDOTDOT }; + +enum ENUM_OBJECT_PROPERTY_INTEGER { + OBJPROP_COLOR, + OBJPROP_STYLE, + OBJPROP_WIDTH, + OBJPROP_BACK, + OBJPROP_ZORDER, + OBJPROP_FILL, + OBJPROP_HIDDEN, + OBJPROP_SELECTED, + OBJPROP_READONLY, + OBJPROP_TYPE, + OBJPROP_TIME, + OBJPROP_SELECTABLE, + OBJPROP_CREATETIME, + OBJPROP_LEVELS, + OBJPROP_LEVELCOLOR, + OBJPROP_LEVELSTYLE, + OBJPROP_LEVELWIDTH, + OBJPROP_ALIGN, + OBJPROP_FONTSIZE, + OBJPROP_RAY_LEFT, + OBJPROP_RAY_RIGHT, + OBJPROP_RAY, + OBJPROP_ELLIPSE, + OBJPROP_ARROWCODE, + OBJPROP_TIMEFRAMES, + OBJPROP_ANCHOR, + OBJPROP_XDISTANCE, + OBJPROP_YDISTANCE, + OBJPROP_DIRECTION, + OBJPROP_DEGREE, + OBJPROP_DRAWLINES, + OBJPROP_STATE, + OBJPROP_CHART_ID, + OBJPROP_XSIZE, + OBJPROP_YSIZE, + OBJPROP_XOFFSET, + OBJPROP_YOFFSET, + OBJPROP_PERIOD, + OBJPROP_DATE_SCALE, + OBJPROP_PRICE_SCALE, + OBJPROP_CHART_SCALE, + OBJPROP_BGCOLOR, + OBJPROP_CORNER, + OBJPROP_BORDER_TYPE, + OBJPROP_BORDER_COLOR +}; + +enum ENUM_OBJECT_PROPERTY_DOUBLE { OBJPROP_PRICE, OBJPROP_LEVELVALUE, OBJPROP_SCALE, OBJPROP_ANGLE, OBJPROP_DEVIATION }; + +enum ENUM_OBJECT_PROPERTY_STRING { + OBJPROP_NAME, + OBJPROP_TEXT, + OBJPROP_TOOLTIP, + OBJPROP_LEVELTEXT, + OBJPROP_FONT, + OBJPROP_BMPFILE, + OBJPROP_SYMBOL +}; + +enum ENUM_BORDER_TYPE { BORDER_FLAT, BORDER_RAISED, BORDER_SUNKEN }; + +enum ENUM_ALIGN_MODE { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT }; + #endif diff --git a/Terminal.extern.h b/Terminal.extern.h index d20fa5b93..e97e33ff0 100644 --- a/Terminal.extern.h +++ b/Terminal.extern.h @@ -22,7 +22,58 @@ // Define external global functions. #ifndef __MQL__ +#pragma once + +// Includes. +#include "String.mqh" +#include "Terminal.define.h" +#include "Terminal.enum.h" + extern int GetLastError(); extern string TerminalInfoString(int property_id); extern void ResetLastError(); +string MQLInfoString(int property_id) { + switch (property_id) { + case MQL_PROGRAM_NAME: + return "EA"; + case MQL_PROGRAM_PATH: + return ""; + } + return ""; +} + +int MQLInfoInteger(int property_id) { + switch (property_id) { + case MQL_CODEPAGE: + return CP_ACP; + case MQL_PROGRAM_TYPE: + return PROGRAM_EXPERT; + case MQL_DLLS_ALLOWED: + return false; + case MQL_TRADE_ALLOWED: + return true; + case MQL_SIGNALS_ALLOWED: + return true; + case MQL_DEBUG: + return true; + case MQL_PROFILER: + return false; + case MQL_TESTER: + return true; + case MQL_OPTIMIZATION: + return true; + case MQL_VISUAL_MODE: + return false; + case MQL_FRAME_MODE: + return false; + case MQL_LICENSE_TYPE: + return LICENSE_FREE; + } + return -1; +} + +bool _StopFlag = false; + +bool IsStopped() { return _StopFlag; } + #endif diff --git a/Terminal.mqh b/Terminal.mqh index 806aca7e9..6015a1da7 100644 --- a/Terminal.mqh +++ b/Terminal.mqh @@ -43,8 +43,8 @@ class Terminal; #include "Refs.mqh" #include "String.mqh" #include "Terminal.define.h" -#include "Terminal.extern.h" #include "Terminal.enum.h" +#include "Terminal.extern.h" #include "Terminal.struct.h" #ifdef __MQL5__ @@ -996,8 +996,8 @@ class Terminal : public Object { * Returns true when the condition is met. */ bool CheckCondition(ENUM_TERMINAL_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { - long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; - long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; + // long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; + // long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; switch (_cond) { case TERMINAL_COND_IS_CONNECTED: return !IsConnected(); @@ -1030,9 +1030,9 @@ class Terminal : public Object { * Returns true when the condition is met. */ bool ExecuteAction(ENUM_TERMINAL_ACTION _action, ARRAY_REF(MqlParam, _args)) { - long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; - long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; - long _arg3l = ArraySize(_args) > 2 ? DataParamEntry::ToInteger(_args[2]) : WRONG_VALUE; + // long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; + // long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; + // long _arg3l = ArraySize(_args) > 2 ? DataParamEntry::ToInteger(_args[2]) : WRONG_VALUE; switch (_action) { case TERMINAL_ACTION_CRASH: delete THIS_PTR; diff --git a/Tick/Tick.struct.h b/Tick/Tick.struct.h index 8cb0897ca..83e7ebf51 100644 --- a/Tick/Tick.struct.h +++ b/Tick/Tick.struct.h @@ -31,6 +31,7 @@ // Includes. #include "../DateTime.extern.h" +#include "../Std.h" #ifndef __MQL__ /** @@ -39,14 +40,28 @@ * https://www.mql5.com/en/docs/constants/structures/mqltick */ struct MqlTick { - datetime time; // Time of the last prices update. - double ask; // Current Ask price. - double bid; // Current Bid price. - double last; // Price of the last deal (last). - double volume_real; // Volume for the current last price with greater accuracy. - long time_msc; // Time of a price last update in milliseconds. - unsigned int flags; // Tick flags. - unsigned long volume; // Volume for the current last price. + datetime time; // Time of the last prices update. + double ask; // Current Ask price. + double bid; // Current Bid price. + double last; // Price of the last deal (last). + double volume_real; // Volume for the current last price with greater accuracy. + int64 time_msc; // Time of a price last update in milliseconds. + unsigned int flags; // Tick flags. + unsigned int64 volume; // Volume for the current last price. + // Default constructor. + MqlTick() {} + + // Copy constructor. + MqlTick(const MqlTick &r) { + time = r.time; + ask = r.ask; + bid = r.bid; + last = r.last; + volume_real = r.volume_real; + time_msc = r.time_msc; + flags = r.flags; + volume = r.volume; + } }; #endif @@ -62,26 +77,65 @@ struct TickAB { TickAB(MqlTick &_tick) : ask((T)_tick.ask), bid((T)_tick.bid) {} }; +struct DoubleTickAB : TickAB {}; + /** * Structure for storing ask and bid prices of the symbol. */ template struct TickTAB : TickAB { - long time_ms; // Time of the last prices update. + int64 time_ms; // Time of the last prices update. // Struct constructors. - TickTAB(long _time_ms = 0, T _ask = 0, T _bid = 0) : time_ms(_time_ms), TickAB(_ask, _bid) {} - TickTAB(MqlTick &_tick) : time_ms(_tick.time_msc), TickAB(_tick) {} + TickTAB(int64 _time_ms = 0, T _ask = 0, T _bid = 0) : TickAB(_ask, _bid), time_ms(_time_ms) {} + TickTAB(MqlTick &_tick) : TickAB(_tick), time_ms(_tick.time_msc) {} + TickTAB(const TickTAB &r) { THIS_REF = r; } /** * Method used by ItemsHistory. */ - long GetTimeMs() { return time_ms; } + int64 GetTimeMs() { return time_ms; } + + /** + * Returns time as timestamp (in seconds). + */ + int64 GetTimestamp() { return time_ms / 1000; } /** * Method used by ItemsHistory. */ - long GetLengthMs() { + int64 GetLengthMs() { // Ticks have length of 0ms, so next tick could be at least 1ms after the previous tick. return 0; } + + /** + * Return string representation of tick's OHLC. + */ + string ToString() { + return IntegerToString(time_ms) + ": Ask " + DoubleToString(THIS_ATTR ask) + + ", Bid: " + DoubleToString(THIS_ATTR bid); + } }; + +struct DoubleTickTAB : TickTAB {}; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TickAB) { + emscripten::value_object>("TickAB") + .field("ask", &TickAB::ask) + .field("bid", &TickAB::bid); +} + +EMSCRIPTEN_BINDINGS(TickTAB) { + // emscripten::value_object, emscripten::base>>("TickTABDouble") + emscripten::value_object>("TickTAB") + .field("ask", &TickTAB::ask) + .field("bid", &TickTAB::bid) + .field("time_ms", &TickTAB::time_ms); +} + +REGISTER_ARRAY_OF(ArrayTickTABDouble, TickTAB, "TickTABArray"); + +#endif diff --git a/Tick/TickManager.h b/Tick/TickManager.h index ffad7e4cb..2445c026a 100644 --- a/Tick/TickManager.h +++ b/Tick/TickManager.h @@ -27,6 +27,7 @@ // Includes. #include "../BufferStruct.mqh" +#include "Tick.struct.h" #include "TickManager.h" //#include "TickManager.struct.h" diff --git a/Trade.mqh b/Trade.mqh index bb6fc778f..4ec0a0ec5 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -31,7 +31,6 @@ class Trade; // Includes. #include "Account/AccountMt.h" -#include "Chart.mqh" #include "Convert.mqh" #include "DictStruct.mqh" #include "Indicator/IndicatorData.h" @@ -47,7 +46,7 @@ class Trade; class Trade : public Taskable { public: AccountMt account; - Ref indi_candle; + Ref indi_candle; DictStruct> orders_active; DictStruct> orders_history; DictStruct> orders_pending; @@ -77,11 +76,11 @@ class Trade : public Taskable { /** * Class constructor. */ - Trade(IndicatorBase *_indi_candle) : indi_candle(_indi_candle), order_last(NULL) { + Trade(IndicatorData *_indi_candle) : indi_candle(_indi_candle), order_last(NULL) { SetName(); OrdersLoadByMagic(tparams.magic_no); }; - Trade(TradeParams &_tparams, IndicatorBase *_indi_candle) + Trade(TradeParams &_tparams, IndicatorData *_indi_candle) : indi_candle(_indi_candle), tparams(_tparams), order_last(NULL) { Init(); SetName(); @@ -255,7 +254,8 @@ class Trade : public Taskable { * Sets default name of trade instance. */ void SetName() { - name = StringFormat("%s@%s", GetSource() PTR_DEREF GetSymbol(), ChartTf::TfToString(GetSource() PTR_DEREF GetTf())); + name = StringFormat("%s@%s", C_STR(GetSource() PTR_DEREF GetSymbol()), + C_STR(ChartTf::TfToString(GetSource() PTR_DEREF GetTf()))); } /** @@ -283,6 +283,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result = _open < _low; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } return _result; @@ -305,6 +308,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result = GetSource() PTR_DEREF GetOpenOffer(_cmd) < _pp; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } return _result; @@ -343,16 +349,16 @@ class Trade : public Taskable { bool _result = false; Ref _order = order_last; - if (_order.IsSet() && _order.Ptr().Get(ORDER_TYPE) == _cmd && - _order.Ptr().Get(ORDER_TIME_SETUP) > GetSource() PTR_DEREF GetBarTime()) { + if (_order.IsSet() && _order REF_DEREF Get(ORDER_TYPE) == _cmd && + _order REF_DEREF Get(ORDER_TIME_SETUP) > GetSource() PTR_DEREF GetBarTime()) { _result |= true; } if (!_result) { for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().Get(ORDER_TYPE) == _cmd) { - long _time_opened = _order.Ptr().Get(ORDER_TIME_SETUP); + if (_order REF_DEREF Get(ORDER_TYPE) == _cmd) { + long _time_opened = _order REF_DEREF Get(ORDER_TIME_SETUP); _result |= _shift > 0 && _time_opened < GetSource() PTR_DEREF GetBarTime(_shift - 1); _result |= _time_opened >= GetSource() PTR_DEREF GetBarTime(_shift); if (_result) { @@ -373,7 +379,7 @@ class Trade : public Taskable { OrderData _odata; double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); - if (_order.IsSet() && _order.Ptr().IsOpen()) { + if (_order.IsSet() && _order REF_DEREF IsOpen()) { if (_odata.Get(ORDER_TYPE) == _cmd) { switch (_cmd) { case ORDER_TYPE_BUY: @@ -382,6 +388,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result |= _odata.Get(ORDER_PRICE_OPEN) >= _price_curr; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } } @@ -389,7 +398,7 @@ class Trade : public Taskable { if (!_result) { for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid() && !_result; ++iter) { _order = iter.Value(); - if (_order.IsSet() && _order.Ptr().IsOpen()) { + if (_order.IsSet() && _order REF_DEREF IsOpen()) { if (_odata.Get(ORDER_TYPE) == _cmd) { switch (_cmd) { case ORDER_TYPE_BUY: @@ -398,6 +407,9 @@ class Trade : public Taskable { case ORDER_TYPE_SELL: _result |= _odata.Get(ORDER_PRICE_OPEN) >= _price_curr; break; + default: + RUNTIME_ERROR("Order type not supported!"); + _result = false; } } } else if (_order.IsSet()) { @@ -415,7 +427,7 @@ class Trade : public Taskable { bool _result = false; Ref _order = order_last; OrderData _odata; - double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); + // double _price_curr = GetSource() PTR_DEREF GetOpenOffer(_cmd); if (_order.IsSet()) { _result = _odata.Get(ORDER_TYPE) != _cmd; @@ -547,8 +559,8 @@ class Trade : public Taskable { * * @see: https://www.mql5.com/en/code/8568 */ - double GetMaxLotSize(double _sl, ENUM_ORDER_TYPE _cmd = NULL) { - _cmd = _cmd == NULL ? Order::OrderType() : _cmd; + double GetMaxLotSize(double _sl, ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { + _cmd = _cmd == ORDER_TYPE_UNSET ? Order::OrderType() : _cmd; double risk_amount = account.GetTotalBalance() / 100 * tparams.risk_margin; double _ticks = fabs(_sl - GetSource() PTR_DEREF GetOpenOffer(_cmd)) / GetSource() PTR_DEREF GetSymbolProps().GetTickSize(); @@ -556,7 +568,7 @@ class Trade : public Taskable { lot_size1 *= GetSource() PTR_DEREF GetSymbolProps().GetVolumeMin(); return NormalizeLots(lot_size1); } - double GetMaxLotSize(unsigned int _pips, ENUM_ORDER_TYPE _cmd = NULL) { + double GetMaxLotSize(unsigned int _pips, ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET) { return GetMaxLotSize(CalcOrderSLTP(_pips, _cmd, ORDER_TYPE_SL)); } @@ -669,18 +681,17 @@ HistorySelect(0, TimeCurrent()); // Select history for access. */ bool OrderAdd(Order *_order) { bool _result = false; - unsigned int _last_error = _order.Get(ORDER_PROP_LAST_ERROR); - logger.Link(_order.GetLogger()); - _order.GetLogger().SetLevel(tparams.Get(TRADE_PARAM_LOG_LEVEL)); + unsigned int _last_error = _order PTR_DEREF Get(ORDER_PROP_LAST_ERROR); + logger.Link(_order PTR_DEREF GetLogger()); Ref _ref_order = _order; switch (_last_error) { case 69539: logger.Error("Error while opening an order!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); tstats.Add(TRADE_STAT_ORDERS_ERRORS); // Pass-through. case ERR_NO_ERROR: // 0 - orders_active.Set(_order.Get(ORDER_PROP_TICKET), _ref_order); + orders_active.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _ref_order); order_last = _order; tstates.AddState(TRADE_STATE_ORDERS_ACTIVE); tstats.Add(TRADE_STAT_ORDERS_OPENED); @@ -699,15 +710,12 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; default: logger.Error("Cannot add order!", __FUNCTION_LINE__, - StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error))); + StringFormat("Code: %d, Msg: %s", _last_error, C_STR(Terminal::GetErrorText(_last_error)))); tstats.Add(TRADE_STAT_ORDERS_ERRORS); _result = false; break; } UpdateStates(_result); - if (logger.GetLevel() >= V_DEBUG) { - logger.Debug(_order.ToString(), __FUNCTION_LINE__, StringFormat("Code: %d", _last_error)); - } return _result; } @@ -715,10 +723,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * Moves active order to history. */ bool OrderMoveToHistory(Order *_order) { - _order.Refresh(true); - orders_active.Unset(_order.Get(ORDER_PROP_TICKET)); + _order PTR_DEREF Refresh(true); + orders_active.Unset(_order PTR_DEREF Get(ORDER_PROP_TICKET)); Ref _ref_order = _order; - bool result = orders_history.Set(_order.Get(ORDER_PROP_TICKET), _ref_order); + bool result = orders_history.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _ref_order); /* @todo if (strategy != NULL) { strategy.OnOrderClose(_order); @@ -744,8 +752,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool _result = true; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { Ref _order = iter.Value(); - if (_order.IsSet() && _order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh(_force); + if (_order.IsSet() && _order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh(_force); } else if (_order.IsSet()) { _result &= OrderMoveToHistory(_order.Ptr()); if (_first_close) { @@ -764,9 +772,9 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool _result = true; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { Ref _order = iter.Value(); - if (_order.IsSet() && _order.Ptr().IsOpen(true)) { - if (_force || _order.Ptr().ShouldRefresh()) { - _order.Ptr().Refresh(_prop); + if (_order.IsSet() && _order REF_DEREF IsOpen(true)) { + if (_force || _order REF_DEREF ShouldRefresh()) { + _order REF_DEREF Refresh(_prop); } } else if (_order.IsSet()) { _result &= OrderMoveToHistory(_order.Ptr()); @@ -778,7 +786,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Sends a trade request. */ - bool RequestSend(MqlTradeRequest &_request, OrderParams &_oparams) { + bool RequestSend(const MqlTradeRequest &_request, OrderParams &_oparams) { bool _result = false; switch (_request.action) { case TRADE_ACTION_CLOSE_BY: @@ -803,11 +811,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. Order *_order = new Order(_request, _oparams); _result = OrderAdd(_order); if (_result) { - OnOrderOpen(_order); + OnOrderOpen(PTR_TO_REF(_order)); } return _result; } - bool RequestSend(MqlTradeRequest &_request) { + bool RequestSend(const MqlTradeRequest &_request) { OrderParams _oparams; return RequestSend(_request, _oparams); } @@ -818,13 +826,13 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool OrderLoad(Order *_order) { bool _result = false; Ref _order_ref = _order; - if (_order.IsOpen()) { + if (_order PTR_DEREF IsOpen()) { // @todo: _order.IsPending()? - _result &= orders_active.Set(_order.Get(ORDER_PROP_TICKET), _order_ref); + _result &= orders_active.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); logger.Link(_order.GetLogger()); - _order.GetLogger().SetLevel(tparams.Get(TRADE_PARAM_LOG_LEVEL)); + _order PTR_DEREF GetLogger().SetLevel((ENUM_LOG_LEVEL)tparams.Get(TRADE_PARAM_LOG_LEVEL)); } else { - _result &= orders_history.Set(_order.Get(ORDER_PROP_TICKET), _order_ref); + _result &= orders_history.Set(_order PTR_DEREF Get(ORDER_PROP_TICKET), _order_ref); } return _result && GetLastError() == ERR_NO_ERROR; } @@ -840,6 +848,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. if (OrderStatic::MagicNumber() == _magic_no) { unsigned long _ticket = OrderStatic::Ticket(); Ref _order = new Order(_ticket); + orders_active.Set(_ticket, _order); OrderLoad(_order.Ptr()); } } @@ -874,22 +883,22 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * On error, returns -1. */ int OrdersCloseAll(ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_ALL, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : "TOCA:"; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - if (_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + if (_order REF_DEREF OrderClose(_reason, _comment)) { _closed++; OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.Error( - StringFormat("Failed to close the order: %d! Error: %d (%s)", _order.Ptr().Get(ORDER_PROP_TICKET), - _order.Ptr().Get(ORDER_PROP_LAST_ERROR), - Terminal::GetErrorText(_order.Ptr().Get(ORDER_PROP_LAST_ERROR))), - __FUNCTION_LINE__); + logger.Error(StringFormat("Failed to close the order: %d! Error: %d (%s)", + _order REF_DEREF Get(ORDER_PROP_TICKET), + _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), + Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), + __FUNCTION_LINE__); continue; } } else { @@ -914,18 +923,19 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _comment = _comment != "" ? _comment : "TOCVC:"; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh(); - if (_order.Ptr().GetRequest().type == _cmd) { - if (_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh(); + if (_order REF_DEREF GetRequest().type == _cmd) { + if (_order REF_DEREF OrderClose(_reason, _comment)) { _closed++; OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { logger.Error( - StringFormat("Failed to close the order: %d! Error: %d (%s)", _order.Ptr().Get(ORDER_PROP_TICKET), - _order.Ptr().Get(ORDER_PROP_LAST_ERROR), - Terminal::GetErrorText(_order.Ptr().Get(ORDER_PROP_LAST_ERROR))), + StringFormat("Failed to close the order: %d! Error: %d (%s)", + _order REF_DEREF Get(ORDER_PROP_TICKET), + _order REF_DEREF Get(ORDER_PROP_LAST_ERROR), + Terminal::GetErrorText(_order REF_DEREF Get(ORDER_PROP_LAST_ERROR))), __FUNCTION_LINE__); continue; } @@ -951,20 +961,20 @@ HistorySelect(0, TimeCurrent()); // Select history for access. template int OrdersCloseViaProp(E _prop, T _value, ENUM_MATH_CONDITION _op, ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh((E)_prop); - if (Math::Compare(_order.Ptr().Get((E)_prop), _value, _op)) { - if (_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh((E)_prop); + if (Math::Compare(_order REF_DEREF Get((E)_prop), _value, _op)) { + if (_order REF_DEREF OrderClose(_reason, _comment)) { _closed++; OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + logger.AddLastError(__FUNCTION_LINE__, _order REF_DEREF Get(ORDER_PROP_LAST_ERROR)); return -1; } } @@ -987,22 +997,22 @@ HistorySelect(0, TimeCurrent()); // Select history for access. template int OrdersCloseViaProp2(E _prop1, T _value1, E _prop2, T _value2, ENUM_MATH_CONDITION _op, ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : __FUNCTION__; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { _order = iter.Value(); - if (_order.Ptr().IsOpen(true)) { - _order.Ptr().Refresh(); - if (Math::Compare(_order.Ptr().Get((E)_prop1), _value1, _op) && - Math::Compare(_order.Ptr().Get((E)_prop2), _value2, _op)) { - if (!_order.Ptr().OrderClose(_reason, _comment)) { + if (_order REF_DEREF IsOpen(true)) { + _order REF_DEREF Refresh(); + if (Math::Compare(_order REF_DEREF Get((E)_prop1), _value1, _op) && + Math::Compare(_order REF_DEREF Get((E)_prop2), _value2, _op)) { + if (!_order REF_DEREF OrderClose(_reason, _comment)) { #ifndef __MQL4__ // @fixme: GH-571. - logger.Info(__FUNCTION_LINE__, _order.Ptr().ToString()); + logger.Info(__FUNCTION_LINE__, _order REF_DEREF ToString()); #endif // @fixme: GH-570. - // logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + // logger.AddLastError(__FUNCTION_LINE__, _order REF_DEREF Get(ORDER_PROP_LAST_ERROR)); logger.Warning("Issue with closing the order!", __FUNCTION_LINE__); ResetLastError(); return -1; @@ -1055,11 +1065,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Calculates the best SL/TP value for the order given the limits. */ - float CalcBestSLTP(float _value, // Suggested value. - float _max_pips, // Maximal amount of pips. - ENUM_ORDER_TYPE_VALUE _mode, // Type of value (stop loss or take profit). - ENUM_ORDER_TYPE _cmd = NULL, // Order type (e.g. buy or sell). - float _lot_size = 0 // Lot size of the order. + float CalcBestSLTP(float _value, // Suggested value. + float _max_pips, // Maximal amount of pips. + ENUM_ORDER_TYPE_VALUE _mode, // Type of value (stop loss or take profit). + ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, // Order type (e.g. buy or sell). + float _lot_size = 0 // Lot size of the order. ) { float _max_value1 = _max_pips > 0 ? CalcOrderSLTP(_max_pips, _cmd, _mode) : 0; float _max_value2 = tparams.risk_margin > 0 ? GetMaxSLTP(_cmd, _lot_size, _mode) : 0; @@ -1080,8 +1090,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. ENUM_ORDER_TYPE_VALUE _mode // Type of value (stop loss or take profit). ) { double _pip_size = SymbolInfoStatic::GetPipSize(GetSource() PTR_DEREF GetSymbol()); - double _price = _cmd == NULL ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); - _cmd = _cmd == NULL ? Order::OrderType() : _cmd; + double _price = _cmd == ORDER_TYPE_UNSET ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); + _cmd = _cmd == ORDER_TYPE_UNSET ? Order::OrderType() : _cmd; return _value > 0 ? float(_price + _value * _pip_size * Order::OrderDirection(_cmd, _mode)) : 0; } float CalcOrderSL(float _value, ENUM_ORDER_TYPE _cmd) { return CalcOrderSLTP(_value, _cmd, ORDER_TYPE_SL); } @@ -1099,14 +1109,14 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * @return * Returns maximum stop loss price value for the given symbol. */ - float GetMaxSLTP(ENUM_ORDER_TYPE _cmd = NULL, float _lot_size = 0, ENUM_ORDER_TYPE_VALUE _mode = ORDER_TYPE_SL, - float _risk_margin = 1.0) { - double _price = _cmd == NULL ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); + float GetMaxSLTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, float _lot_size = 0, + ENUM_ORDER_TYPE_VALUE _mode = ORDER_TYPE_SL, float _risk_margin = 1.0) { + double _price = _cmd == ORDER_TYPE_UNSET ? Order::OrderOpenPrice() : GetSource() PTR_DEREF GetOpenOffer(_cmd); // For the new orders, use the available margin for calculation, otherwise use the account balance. float _margin = Convert::MoneyToValue( - (_cmd == NULL ? account.GetMarginAvail() : account.GetTotalBalance()) / 100 * _risk_margin, _lot_size, - GetSource() PTR_DEREF GetSymbol()); - _cmd = _cmd == NULL ? Order::OrderType() : _cmd; + (_cmd == ORDER_TYPE_UNSET ? account.GetMarginAvail() : account.GetTotalBalance()) / 100 * _risk_margin, + _lot_size, GetSource() PTR_DEREF GetSymbol()); + _cmd = _cmd == ORDER_TYPE_UNSET ? Order::OrderType() : _cmd; // @fixme // _lot_size = _lot_size <= 0 ? fmax(Order::OrderLots(), GetSource() PTR_DEREF GetVolumeMin()) : _lot_size; return (float)_price + @@ -1115,10 +1125,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // + Convert::MoneyToValue(account.GetMarginAvail() / 100 * _risk_margin, _lot_size) + _margin * Order::OrderDirection(_cmd, _mode); } - float GetMaxSL(ENUM_ORDER_TYPE _cmd = NULL, float _lot_size = 0, float _risk_margin = 1.0) { + float GetMaxSL(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, float _lot_size = 0, float _risk_margin = 1.0) { return GetMaxSLTP(_cmd, _lot_size, ORDER_TYPE_SL, _risk_margin); } - float GetMaxTP(ENUM_ORDER_TYPE _cmd = NULL, float _lot_size = 0, float _risk_margin = 1.0) { + float GetMaxTP(ENUM_ORDER_TYPE _cmd = ORDER_TYPE_UNSET, float _lot_size = 0, float _risk_margin = 1.0) { return GetMaxSLTP(_cmd, _lot_size, ORDER_TYPE_TP, _risk_margin); } @@ -1138,7 +1148,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return NormalizeSLTP(_value1 < _value2 ? _value1 : _value2, _cmd, _mode); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; case ORDER_TYPE_SELL_LIMIT: @@ -1149,11 +1159,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return NormalizeSLTP(_value1 > _value2 ? _value1 : _value2, _cmd, _mode); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; default: - logger.Error(StringFormat("Invalid order type: %s!", EnumToString(_cmd), __FUNCTION__)); + logger.Error(StringFormat("Invalid order type: %s at %s!", C_STR(EnumToString(_cmd)), C_STR(__FUNCTION__))); } return EMPTY_VALUE; } @@ -1238,7 +1248,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * * @todo: Improve number of increases for bull/bear variables. */ - double GetTrend(int method, ENUM_TIMEFRAMES _tf = NULL, bool simple = false) { + double GetTrend(int method, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, bool simple = false) { static datetime _last_trend_check = 0; static double _last_trend = 0; string symbol = GetSource() PTR_DEREF GetSymbol(); @@ -1517,7 +1527,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return fmax(_value, GetSource() PTR_DEREF GetBid() + GetTradeDistanceInValue()); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; // Selling is done at the Bid price. @@ -1532,13 +1542,13 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case ORDER_TYPE_TP: return fmin(_value, GetSource() PTR_DEREF GetAsk() - GetTradeDistanceInValue()); default: - logger.Error(StringFormat("Invalid mode: %s!", EnumToString(_mode), __FUNCTION__)); + logger.Error(StringFormat("Invalid mode: %s at %s!", C_STR(EnumToString(_mode)), C_STR(__FUNCTION__))); } break; default: - logger.Error(StringFormat("Invalid order type: %s!", EnumToString(_cmd), __FUNCTION__)); + logger.Error(StringFormat("Invalid order type: %s at %s!", C_STR(EnumToString(_cmd)), C_STR(__FUNCTION__))); } - return NULL; + return 0; } double NormalizeSL(double _value, ENUM_ORDER_TYPE _cmd) { @@ -1620,7 +1630,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } #ifdef __debug__ if (!_is_valid) { - PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", __FUNCTION__, EnumToString(_cmd), _value, _price); + PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", __FUNCTION__, C_STR(EnumToString(_cmd)), _value, + _price); } #endif if (_is_valid && _value_prev > 0 && _locked) { @@ -1651,7 +1662,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. double ask = GetSource() PTR_DEREF GetAsk(); double bid = GetSource() PTR_DEREF GetBid(); double openprice = GetSource() PTR_DEREF GetOpenOffer(_cmd); - double closeprice = GetSource() PTR_DEREF GetCloseOffer(_cmd); + // double closeprice = GetSource() PTR_DEREF GetCloseOffer(_cmd); // The minimum distance of SYMBOL_TRADE_STOPS_LEVEL taken into account. double distance = GetTradeDistanceInValue(); // bool result; @@ -1740,7 +1751,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } #ifdef __debug__ if (!_is_valid) { - PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", __FUNCTION__, EnumToString(_cmd), _value, _price); + PrintFormat("%s(): Invalid stop for %s! Value: %g, price: %g", C_STR(__FUNCTION__), C_STR(EnumToString(_cmd)), + _value, _price); } #endif if (_is_valid && _value_prev > 0 && _locked) { @@ -1810,7 +1822,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool AddTask(TaskEntry &_tentry) { bool _is_valid = _tentry.IsValid(); if (_is_valid) { - tasks.Add(new TaskObject(_tentry, THIS_PTR, THIS_PTR)); + TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); + tasks.Add(&_taskobj); } return _is_valid; } @@ -1961,7 +1974,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } break; default: - GetLogger().Error(StringFormat("Invalid Trade condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + GetLogger() PTR_DEREF Error( + StringFormat("Invalid Trade condition: %d at %s!", _entry.GetId(), C_STR(__FUNCTION_LINE__))); SetUserError(ERR_INVALID_PARAMETER); break; } @@ -2013,21 +2027,17 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDER_CLOSE_MOST_LOSS: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - _result = _oquery_ref.Ptr() - .FindByPropViaOp(ORDER_PROP_PROFIT, - STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_LT)) - .Ptr() - .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); + _result = _oquery_ref REF_DEREF FindByPropViaOp( + ORDER_PROP_PROFIT, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_LT)) + REF_DEREF OrderClose(ORDER_REASON_CLOSED_BY_ACTION); RefreshActiveOrders(true, true); } break; case TRADE_ACTION_ORDER_CLOSE_MOST_PROFIT: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - _result = _oquery_ref.Ptr() - .FindByPropViaOp(ORDER_PROP_PROFIT, - STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_GT)) - .Ptr() - .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); + _result = _oquery_ref REF_DEREF FindByPropViaOp( + ORDER_PROP_PROFIT, STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_GT)) + REF_DEREF OrderClose(ORDER_REASON_CLOSED_BY_ACTION); RefreshActiveOrders(true, true); } break; @@ -2049,14 +2059,13 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDERS_CLOSE_IN_TREND: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result = OrdersCloseViaCmd(GetTrendOp(18, PERIOD_D1), ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd(GetTrendOp(0), ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; case TRADE_ACTION_ORDERS_CLOSE_IN_TREND_NOT: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result = - OrdersCloseViaCmd(Order::NegateOrderType(GetTrendOp(18, PERIOD_D1)), ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd(Order::NegateOrderType(GetTrendOp(0)), ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; @@ -2068,22 +2077,24 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDERS_CLOSE_SIDE_IN_LOSS: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - ENUM_ORDER_TYPE _order_types1[] = {ORDER_TYPE_BUY, ORDER_TYPE_SELL}; - ENUM_ORDER_TYPE _order_type_profitable = - _oquery_ref.Ptr() - .FindPropBySum( - _order_types1, ORDER_PROP_PROFIT, ORDER_TYPE); + ARRAY(ENUM_ORDER_TYPE, _order_types1); + ArrayPush(_order_types1, ORDER_TYPE_BUY); + ArrayPush(_order_types1, ORDER_TYPE_SELL); + ENUM_ORDER_TYPE _order_type_profitable = _oquery_ref REF_DEREF + FindPropBySum( + _order_types1, ORDER_PROP_PROFIT, ORDER_TYPE); _result = OrdersCloseViaCmd(Order::NegateOrderType(_order_type_profitable), ORDER_REASON_CLOSED_BY_ACTION) >= 0; } break; case TRADE_ACTION_ORDERS_CLOSE_SIDE_IN_PROFIT: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - ENUM_ORDER_TYPE _order_types2[] = {ORDER_TYPE_BUY, ORDER_TYPE_SELL}; - ENUM_ORDER_TYPE _order_type_profitable2 = - _oquery_ref.Ptr() - .FindPropBySum( - _order_types2, ORDER_PROP_PROFIT, ORDER_TYPE); + ARRAY(ENUM_ORDER_TYPE, _order_types2); + ArrayPush(_order_types2, ORDER_TYPE_BUY); + ArrayPush(_order_types2, ORDER_TYPE_SELL); + ENUM_ORDER_TYPE _order_type_profitable2 = _oquery_ref REF_DEREF + FindPropBySum( + _order_types2, ORDER_PROP_PROFIT, ORDER_TYPE); _result = OrdersCloseViaCmd(_order_type_profitable2, ORDER_REASON_CLOSED_BY_ACTION) >= 0; } break; @@ -2097,7 +2108,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case TRADE_ACTION_STATE_ADD: tstates.AddState(_entry.GetArg(0).ToValue()); default: - GetLogger().Error(StringFormat("Invalid Trade action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + GetLogger() + PTR_DEREF Error(StringFormat("Invalid Trade action: %d at %s!", _entry.GetId(), C_STR(__FUNCTION_LINE__))); SetUserError(ERR_INVALID_PARAMETER); break; } @@ -2147,12 +2159,12 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Binds IndicatorCandle-based class. */ - void SetSource(IndicatorBase *_indi_candle) { indi_candle = _indi_candle; } + void SetSource(IndicatorData *_indi_candle) { indi_candle = _indi_candle; } /** * Returns pointer to Log class. */ - Log *GetLogger() { return GET_PTR(logger); } + Log *GetLogger() { return GetPointer(logger); } /* Serializers */ diff --git a/Trade.struct.h b/Trade.struct.h index b529c2118..19fb2c171 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -37,66 +37,95 @@ struct TradeStats; #include "DateTime.mqh" #include "Trade.enum.h" -#ifndef __MQL__ - -// Defines Trade Request structure. -// @see: https://www.mql5.com/en/docs/constants/structures/mqltraderequest -struct MqlTradeRequest { - ENUM_TRADE_REQUEST_ACTIONS action; // Trade operation type - ulong magic; // Expert Advisor ID (magic number) - ulong order; // Order ticket - string symbol; // Trade symbol - double volume; // Requested volume for a deal in lots - double price; // Price - double stoplimit; // StopLimit level of the order - double sl; // Stop Loss level of the order - double tp; // Take Profit level of the order - ulong deviation; // Maximal possible deviation from the requested price - ENUM_ORDER_TYPE type; // Order type - ENUM_ORDER_TYPE_FILLING type_filling; // Order execution type - ENUM_ORDER_TYPE_TIME type_time; // Order expiration type - datetime expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type) - string comment; // Order comment - ulong position; // Position ticket - ulong position_by; // The ticket of an opposite position -}; - -// Defines Trade Request Result structure. -// @see: https://www.mql5.com/en/docs/constants/structures/mqltraderesult -struct MqlTradeResult { - uint retcode; // Operation return code - ulong deal; // Deal ticket, if it is performed - ulong order; // Order ticket, if it is placed - double volume; // Deal volume, confirmed by broker - double price; // Deal price, confirmed by broker - double bid; // Current Bid price - double ask; // Current Ask price - string comment; // Broker comment to operation (by default it is filled by description of trade server return code) - uint request_id; // Request ID set by the terminal during the dispatch - int retcode_external; // Return code of an external trading system -}; - -// Defines Trade Transaction structure. -// @see: https://www.mql5.com/en/docs/constants/structures/mqltradetransaction -struct MqlTradeTransaction { - ulong deal; // Deal ticket - ulong order; // Order ticket - string symbol; // Trade symbol name - ENUM_TRADE_TRANSACTION_TYPE type; // Trade transaction type - ENUM_ORDER_TYPE order_type; // Order type - ENUM_ORDER_STATE order_state; // Order state - ENUM_DEAL_TYPE deal_type; // Deal type - ENUM_ORDER_TYPE_TIME time_type; // Order type by action period - datetime time_expiration; // Order expiration time - double price; // Price - double price_trigger; // Stop limit order activation price - double price_sl; // Stop Loss level - double price_tp; // Take Profit level - double volume; // Volume in lots - ulong position; // Position ticket - ulong position_by; // Ticket of an opposite position -}; +/* Structure for trade statistics. */ +struct TradeStats { + DateTime dt[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; + unsigned int order_stats[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; + // Struct constructors. + TradeStats() { ResetStats(); } + TradeStats(const TradeStats &r) { THIS_REF = r; } + // Check statistics for new periods + void Check() {} + /* Getters */ + // Get order stats for the given type and period. + unsigned int GetOrderStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, bool _reset = true) { +#ifdef __debug_verbose__ + Print("GetOrderStats: type ", EnumToString(_type), ", period ", EnumToString(_period), ", reset = ", _reset); +#endif + if (_reset && _period > TRADE_STAT_ALL) { + unsigned int _periods_started = dt[(int)_type][(int)_period].GetStartedPeriods(true, false); +#ifdef __debug_verbose__ + Print("GetOrderStats: _periods_started = ", _periods_started); #endif + if (_periods_started >= DATETIME_HOUR) { + ResetStats(_type, _period, _periods_started); + } + } + return order_stats[(int)_type][(int)_period]; + } + /* Setters */ + // Add value for the given type and period. + void Add(ENUM_TRADE_STAT_TYPE _type, int _value = 1) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + order_stats[(int)_type][(int)p] += _value; + } + } + /* Reset stats for the given periods. */ + void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, unsigned int _periods) { + if ((_periods & DATETIME_HOUR) != 0) { + ResetStats(TRADE_STAT_PER_HOUR); + } + if ((_periods & DATETIME_DAY) != 0) { + ResetStats(TRADE_STAT_PER_DAY); + } + if ((_periods & DATETIME_WEEK) != 0) { + ResetStats(TRADE_STAT_PER_WEEK); + } + if ((_periods & DATETIME_MONTH) != 0) { + ResetStats(TRADE_STAT_PER_MONTH); + } + if ((_periods & DATETIME_YEAR) != 0) { + ResetStats(TRADE_STAT_PER_YEAR); + } + } + /* Reset stats for the given type and period. */ + void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period) { + order_stats[(int)_type][(int)_period] = 0; + } + /* Reset stats for the given period. */ + void ResetStats(ENUM_TRADE_STAT_PERIOD _period) { + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { + order_stats[t][(int)_period] = 0; +#ifdef __debug_verbose__ + Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(_period)); +#endif + dt[t][(int)_period].GetStartedPeriods(true, true); + } + } + /* Reset stats for the given type. */ + void ResetStats(ENUM_TRADE_STAT_TYPE _type) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + order_stats[(int)_type][p] = 0; +#ifdef __debug_vebose__ + Print("Resetting trade counter for type ", EnumToString(_type), " and period ", EnumToString(p)); +#endif + dt[(int)_type][p].GetStartedPeriods(true, true); + } + } + /* Reset all stats. */ + void ResetStats() { + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + order_stats[t][p] = 0; +#ifdef __debug_verbose__ + Print("Resetting trade counter for type ", EnumToString((ENUM_TRADE_STAT_TYPE)t), " and period ", + EnumToString((ENUM_TRADE_STAT_PERIOD)p)); +#endif + dt[t][p].GetStartedPeriods(true, true); + } + } + } +}; /* Structure for trade parameters. */ struct TradeParams { @@ -128,7 +157,7 @@ struct TradeParams { magic_no(_magic_no), risk_margin(1.0f), slippage(0) {} - TradeParams(TradeParams &_tparams) { this = _tparams; } + TradeParams(const TradeParams &_tparams) { THIS_REF = _tparams; } // Deconstructor. ~TradeParams() {} // Getters. @@ -146,11 +175,13 @@ struct TradeParams { case TRADE_PARAM_MAX_SPREAD: return (T)max_spread; case TRADE_PARAM_ORDER_COMMENT: - return (T)order_comment; + return ConvertBasic::StringTo(order_comment); case TRADE_PARAM_RISK_MARGIN: return (T)risk_margin; case TRADE_PARAM_SLIPPAGE: return (T)slippage; + default: + break; } SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; @@ -197,20 +228,14 @@ struct TradeParams { case TRADE_PARAM_BARS_MIN: bars_min = (unsigned short)_value; return; - case TRADE_PARAM_LOG_LEVEL: - log_level = (ENUM_LOG_LEVEL)_value; - return; case TRADE_PARAM_LOT_SIZE: lot_size = (float)_value; return; case TRADE_PARAM_MAGIC_NO: magic_no = (unsigned long)_value; return; - case TRADE_PARAM_MAX_SPREAD: - max_spread = (float)_value; - return; case TRADE_PARAM_ORDER_COMMENT: - order_comment = (string)_value; + order_comment = SerializerConversions::ValueToString(_value); return; case TRADE_PARAM_RISK_MARGIN: risk_margin = (float)_value; @@ -218,6 +243,8 @@ struct TradeParams { case TRADE_PARAM_SLIPPAGE: slippage = (unsigned int)_value; return; + default: + break; } SetUserError(ERR_INVALID_PARAMETER); } @@ -248,16 +275,16 @@ struct TradeParams { } void SetLimits(ENUM_TRADE_STAT_TYPE _type, unsigned int _value = 0) { // Set new trading limits for the given type. - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - limits_stats[(int)_type][(int)p] = _value; + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + limits_stats[(int)_type][p] = _value; } } void SetLimits(unsigned int _value = 0) { // Set new trading limits for all types and periods. // Zero value is for no limits. - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - limits_stats[(int)t][(int)p] = _value; + for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { + for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { + limits_stats[t][p] = _value; } } } @@ -275,94 +302,6 @@ struct TradeParams { } } trade_params_defaults; -/* Structure for trade statistics. */ -struct TradeStats { - DateTime dt[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; - unsigned int order_stats[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; - // Struct constructors. - TradeStats() { ResetStats(); } - // Check statistics for new periods - void Check() {} - /* Getters */ - // Get order stats for the given type and period. - unsigned int GetOrderStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, bool _reset = true) { -#ifdef __debug_verbose__ - Print("GetOrderStats: type ", EnumToString(_type), ", period ", EnumToString(_period), ", reset = ", _reset); -#endif - if (_reset && _period > TRADE_STAT_ALL) { - unsigned int _periods_started = dt[(int)_type][(int)_period].GetStartedPeriods(true, false); -#ifdef __debug_verbose__ - Print("GetOrderStats: _periods_started = ", _periods_started); -#endif - if (_periods_started >= DATETIME_HOUR) { - ResetStats(_type, _period, _periods_started); - } - } - return order_stats[(int)_type][(int)_period]; - } - /* Setters */ - // Add value for the given type and period. - void Add(ENUM_TRADE_STAT_TYPE _type, int _value = 1) { - for (int p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - order_stats[(int)_type][(int)p] += _value; - } - } - /* Reset stats for the given periods. */ - void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, unsigned int _periods) { - if ((_periods & DATETIME_HOUR) != 0) { - ResetStats(TRADE_STAT_PER_HOUR); - } - if ((_periods & DATETIME_DAY) != 0) { - ResetStats(TRADE_STAT_PER_DAY); - } - if ((_periods & DATETIME_WEEK) != 0) { - ResetStats(TRADE_STAT_PER_WEEK); - } - if ((_periods & DATETIME_MONTH) != 0) { - ResetStats(TRADE_STAT_PER_MONTH); - } - if ((_periods & DATETIME_YEAR) != 0) { - ResetStats(TRADE_STAT_PER_YEAR); - } - } - /* Reset stats for the given type and period. */ - void ResetStats(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period) { - order_stats[(int)_type][(int)_period] = 0; - } - /* Reset stats for the given period. */ - void ResetStats(ENUM_TRADE_STAT_PERIOD _period) { - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - order_stats[(int)t][(int)_period] = 0; -#ifdef __debug_verbose__ - Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(_period)); -#endif - dt[(int)t][(int)_period].GetStartedPeriods(true, true); - } - } - /* Reset stats for the given type. */ - void ResetStats(ENUM_TRADE_STAT_TYPE _type) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - order_stats[(int)_type][(int)p] = 0; -#ifdef __debug_vebose__ - Print("Resetting trade counter for type ", EnumToString(_type), " and period ", EnumToString(p)); -#endif - dt[(int)_type][(int)p].GetStartedPeriods(true, true); - } - } - /* Reset all stats. */ - void ResetStats() { - for (ENUM_TRADE_STAT_TYPE t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { - for (ENUM_TRADE_STAT_PERIOD p = 0; p < FINAL_ENUM_TRADE_STAT_PERIOD; p++) { - order_stats[(int)t][(int)p] = 0; -#ifdef __debug_verbose__ - Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(p)); -#endif - dt[(int)t][(int)p].GetStartedPeriods(true, true); - } - } - } -}; - /* Structure for trade states. */ struct TradeStates { protected: @@ -426,6 +365,8 @@ struct TradeStates { return "Terminal offline"; case TRADE_STATE_TRADE_TERMINAL_SHUTDOWN: return "Terminal is shutting down"; + default: + break; } return "Unknown!"; } @@ -455,7 +396,7 @@ struct TradeStates { int _size = sizeof(int) * 8; for (int i = 0; i < _size; i++) { int _value = CheckState(1 << i) ? 1 : 0; - _s.Pass(THIS_REF, (string)(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC); + _s.Pass(THIS_REF, IntegerToString(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC); } return SerializerNodeObject; } diff --git a/Trade/TradeSignal.h b/Trade/TradeSignal.h index 129cc2775..b9861db88 100644 --- a/Trade/TradeSignal.h +++ b/Trade/TradeSignal.h @@ -179,3 +179,12 @@ class TradeSignal { */ string ToString() { return signal.ToString(); } }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TradeSignal) { + emscripten::class_("TradeSignal").constructor().function("ToString", &TradeSignal::ToString); +} + +#endif diff --git a/Trade/TradeSignalManager.h b/Trade/TradeSignalManager.h index 84e89480c..c159d64af 100644 --- a/Trade/TradeSignalManager.h +++ b/Trade/TradeSignalManager.h @@ -234,9 +234,21 @@ class TradeSignalManager : Dynamic { * @return * Returns a JSON serialized signal. */ - string ToString() { + string const ToString() { // SerializerConverter _stub = SerializerConverter::MakeStubObject(SERIALIZER_FLAG_SKIP_HIDDEN); return SerializerConverter::FromObject(THIS_REF, SERIALIZER_FLAG_INCLUDE_ALL | SERIALIZER_FLAG_SKIP_HIDDEN) .ToString(SERIALIZER_JSON_NO_WHITESPACES); } }; + +#ifdef EMSCRIPTEN +#include + +EMSCRIPTEN_BINDINGS(TradeSignalManager) { + emscripten::class_("TradeSignalManager") + .constructor() + .function("SignalAdd", &TradeSignalManager::SignalAdd) + .function("ToString", &TradeSignalManager::ToString); +} + +#endif diff --git a/Trade/tests/TradeSignal.test.cpp.fixme b/Trade/tests/TradeSignal.test.cpp.fixme index 998e8129f..ac2fe8fba 100644 --- a/Trade/tests/TradeSignal.test.cpp.fixme +++ b/Trade/tests/TradeSignal.test.cpp.fixme @@ -25,10 +25,11 @@ */ // Includes. +#include "../TradeSignal.h" + #include "../../Common.define.h" #include "../../Common.extern.h" #include "../../Std.h" #include "../../String.extern.h" -#include "../TradeSignal.h" int main(int argc, char **argv) {} diff --git a/Trade/tests/TradeSignalManager.test.cpp.fixme b/Trade/tests/TradeSignalManager.test.cpp.fixme index 2dbdeefef..31fdfefe6 100644 --- a/Trade/tests/TradeSignalManager.test.cpp.fixme +++ b/Trade/tests/TradeSignalManager.test.cpp.fixme @@ -25,10 +25,11 @@ */ // Includes. +#include "../TradeSignalManager.h" + #include "../../Common.define.h" #include "../../Common.extern.h" #include "../../Std.h" #include "../../String.extern.h" -#include "../TradeSignalManager.h" int main(int argc, char **argv) {} diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 6b73372a9..01f9dbe9b 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -66,7 +66,7 @@ int OnInit() { _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); _mesh.Ptr().SetShaderPS(_shader_p.Ptr()); - Ref _chart = new Chart3D(Platform::FetchDefaultCandleIndicator(), CHART3D_TYPE_CANDLES); + Ref _chart = new Chart3D(Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1), CHART3D_TYPE_CANDLES); unsigned int _rand_color = rand() * 1256; diff --git a/tests/BufferFXTTest.mq5 b/tests/BufferFXTTest.mq5 index 4de298ea3..25168a969 100644 --- a/tests/BufferFXTTest.mq5 +++ b/tests/BufferFXTTest.mq5 @@ -36,7 +36,7 @@ BufferFXT *ticks; */ int OnInit() { Platform::Init(); - ticks = new BufferFXT(Platform::FetchDefaultCandleIndicator()); + ticks = new BufferFXT(Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1)); // Test 1. // @todo return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED); diff --git a/tests/DatabaseTest.mq5 b/tests/DatabaseTest.mq5 index 22d150186..5bf18c8dd 100644 --- a/tests/DatabaseTest.mq5 +++ b/tests/DatabaseTest.mq5 @@ -45,13 +45,13 @@ int OnInit() { db = new Database(":memory:", DATABASE_OPEN_MEMORY); // Create Table1 table. - DatabaseTableColumnEntry columns[] = { - {"SYMBOL", TYPE_CHAR, DATABASE_COLUMN_FLAG_NONE, 6}, - {"BID", TYPE_DOUBLE}, - {"ASK", TYPE_DOUBLE}, - {"VOLUME", TYPE_INT, DATABASE_COLUMN_FLAG_IS_NULL}, - {"COMMENT", TYPE_STRING, DATABASE_COLUMN_FLAG_IS_NULL}, - }; + ARRAY(DatabaseTableColumnEntry, columns); + ArrayPushObject(columns, DatabaseTableColumnEntry("SYMBOL", TYPE_CHAR, DATABASE_COLUMN_FLAG_NONE, 6)); + ArrayPushObject(columns, DatabaseTableColumnEntry("BID", TYPE_DOUBLE)); + ArrayPushObject(columns, DatabaseTableColumnEntry("ASK", TYPE_DOUBLE)); + ArrayPushObject(columns, DatabaseTableColumnEntry("VOLUME", TYPE_INT, DATABASE_COLUMN_FLAG_IS_NULL)); + ArrayPushObject(columns, DatabaseTableColumnEntry("COMMENT", TYPE_STRING, DATABASE_COLUMN_FLAG_IS_NULL)); + DatabaseTableSchema schema = columns; assertTrueOrFail(db.CreateTable("Table1", schema), "Cannot create table! Error: " + (string)_LastError); DatabasePrint(db.GetHandle(), "PRAGMA TABLE_INFO(Table1);", 0); diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index d12c26762..3e2c8c1bc 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -24,6 +24,9 @@ * Test functionality of DrawIndicator class. */ +//#define __debug__ +//#define __debug_verbose__ + // Includes. #include "../DictStruct.mqh" #include "../DrawIndicator.mqh" @@ -44,7 +47,7 @@ int bar_processed; */ int OnInit() { Platform::Init(); - candles = Platform::FetchDefaultCandleIndicator(); + candles = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); bool _result = true; // Initialize indicators. _result &= InitIndicators(); @@ -70,7 +73,9 @@ void OnTick() { _indi.OnTick(Platform::GetGlobalTickIndex()); IndicatorDataEntry _entry = _indi.GetEntry(); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)) && _entry.IsValid()) { +#ifdef __debug__ PrintFormat("%s: bar %d: %s", _indi.GetName(), bar_processed, _indi.ToString()); +#endif } } } @@ -89,28 +94,28 @@ bool InitIndicators() { // Bollinger Bands. IndiBandsParams bands_params(20, 2, 0, PRICE_MEDIAN); - Platform::AddWithDefaultBindings(new Indi_Bands(bands_params)); + Platform::AddWithDefaultBindings(new Indi_Bands(bands_params), "EURUSD", PERIOD_M1); // Moving Average. IndiMAParams ma_params(13, 10, MODE_SMA, PRICE_OPEN); - Platform::AddWithDefaultBindings(new Indi_MA(ma_params)); + Platform::AddWithDefaultBindings(new Indi_MA(ma_params), "EURUSD", PERIOD_M1); // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); - Platform::AddWithDefaultBindings(new Indi_RSI(rsi_params)); + Platform::AddWithDefaultBindings(new Indi_RSI(rsi_params), "EURUSD", PERIOD_M1); /* Special indicators */ // Demo/Dummy Indicator. IndiDemoParams demo_params; - Platform::AddWithDefaultBindings(new Indi_Demo(demo_params)); + Platform::AddWithDefaultBindings(new Indi_Demo(demo_params), "EURUSD", PERIOD_M1); #ifndef __MQL4__ // @fixme: Make it work for MT4. // Current Price (used by custom indicators) . PriceIndiParams price_params(); // price_params.SetDraw(clrGreenYellow); - Platform::AddWithDefaultBindings(new Indi_Price(price_params)); + Platform::AddWithDefaultBindings(new Indi_Price(price_params), "EURUSD", PERIOD_M1); #endif /* @fixme: Array out of range. diff --git a/tests/EATest.mq5 b/tests/EATest.mq5 index 9891ac8c1..e8c9dcbce 100644 --- a/tests/EATest.mq5 +++ b/tests/EATest.mq5 @@ -28,6 +28,7 @@ struct DataParamEntry; // Includes. +#include "../Account/Account.struct.h" #include "../EA.mqh" #include "../Test.mqh" diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 317ef3b8c..b5c32f4df 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -38,6 +38,7 @@ struct DataParamEntry; #include "../DictObject.mqh" #include "../Indicator/Indicator.h" #include "../Indicator/tests/classes/IndicatorTfDummy.h" +#include "../Indicator/tests/classes/Indicators.h" #include "../Indicators/Bitwise/indicators.h" #include "../Indicators/Tick/Indi_TickMt.mqh" #include "../Indicators/indicators.h" @@ -51,9 +52,9 @@ struct DataParamEntry; enum ENUM_CUSTOM_INDICATORS { INDI_SPECIAL_MATH_CUSTOM = FINAL_INDICATOR_TYPE_ENTRY + 1 }; // Global variables. -DictStruct> indis; -DictStruct> whitelisted_indis; -DictStruct> tested; +Indicators indis; +Dict whitelisted_indis; +Dict tested; double test_values[] = {1.245, 1.248, 1.254, 1.264, 1.268, 1.261, 1.256, 1.250, 1.242, 1.240, 1.235, 1.240, 1.234, 1.245, 1.265, 1.274, 1.285, 1.295, 1.300, 1.312, 1.315, 1.320, 1.325, 1.335, 1.342, 1.348, 1.352, 1.357, 1.359, 1.422, 1.430, 1.435}; @@ -74,8 +75,8 @@ int OnInit() { Print("Connecting candle and tick indicators to all indicators..."); // Connecting all indicators to default candle indicator (which is connected to default tick indicator). - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - Platform::AddWithDefaultBindings(iter.Value().Ptr(), _Symbol, PERIOD_CURRENT); + for (int i = 0; i < indis.Size(); ++i) { + Platform::AddWithDefaultBindings(indis[i], "EURUSD", PERIOD_M1); } // Check for any errors. @@ -95,7 +96,7 @@ int OnInit() { */ void OnTick() { Platform::Tick(); - IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); + IndicatorData* _candles = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_M1); if (_candles PTR_DEREF IsNewBar()) { if (_candles PTR_DEREF GetBarIndex() > 550) { @@ -106,19 +107,20 @@ void OnTick() { return; } - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + for (int i = 0; i < indis.Size(); ++i) { + IndicatorData* _indi = indis[i]; + if (whitelisted_indis.Size() == 0) { - if (tested.Contains(iter.Value())) { + if (tested.Contains(_indi)) { // Indicator is already tested, skipping. continue; } } else { - if (!whitelisted_indis.Contains(iter.Value())) { + if (!whitelisted_indis.Contains(_indi)) { continue; } } - IndicatorData* _indi = iter.Value().Ptr(); IndicatorDataEntry _entry(_indi PTR_DEREF GetEntry()); // if (_indi.GetType() != INDI_AMA) @@ -128,7 +130,7 @@ void OnTick() { if (_entry.IsValid()) { PrintFormat("%s: bar %d: %s", _indi PTR_DEREF GetFullName(), _candles PTR_DEREF GetBars(), _indi PTR_DEREF ToString()); - tested.Push(iter.Value()); // Mark as tested. + tested.Push(_indi); // Mark as tested. } } } @@ -140,9 +142,11 @@ void OnTick() { */ void OnDeinit(const int reason) { int num_not_tested = 0; - for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - if (!tested.Contains(iter.Value())) { - PrintFormat("%s: Indicator not tested: %s", __FUNCTION__, iter.Value().Ptr().GetFullName()); + for (int i = 0; i < indis.Size(); ++i) { + IndicatorData* _indi = indis[i]; + + if (!tested.Contains(_indi)) { + PrintFormat("%s: Indicator not tested: %s", __FUNCTION__, _indi.GetFullName()); ++num_not_tested; } } @@ -159,127 +163,127 @@ bool InitIndicators() { // Price indicator. Ref indi_price = new Indi_Price(PriceIndiParams()); - // indis.Push(indi_price); // @fixme: Make it work with the test? + // indis.Add(indi_price); // @fixme: Make it work with the test? /* Standard indicators */ // AC. - indis.Push(new Indi_AC()); + indis.Add(new Indi_AC()); // AD. - indis.Push(new Indi_AD()); + indis.Add(new Indi_AD()); // ADX. IndiADXParams adx_params(14); - indis.Push(new Indi_ADX(adx_params)); + indis.Add(new Indi_ADX(adx_params)); // Alligator. IndiAlligatorParams alli_params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - indis.Push(new Indi_Alligator(alli_params)); + indis.Add(new Indi_Alligator(alli_params)); // Awesome Oscillator (AO). - indis.Push(new Indi_AO()); + indis.Add(new Indi_AO()); // Accumulation Swing Index (ASI). IndiASIParams _asi_params; - indis.Push(new Indi_ASI(_asi_params)); + indis.Add(new Indi_ASI(_asi_params)); // Average True Range (ATR). IndiATRParams atr_params(14); - indis.Push(new Indi_ATR(atr_params)); + indis.Add(new Indi_ATR(atr_params)); // Bollinger Bands - Built-in. IndiBandsParams bands_params(20, 2, 0, PRICE_OPEN); Ref indi_bands = new Indi_Bands(bands_params); - indis.Push(indi_bands); - // whitelisted_indis.Push(indi_bands); + indis.Add(indi_bands); + // whitelisted_indis.Add(indi_bands); // Bollinger Bands - OnCalculate. Ref indi_bands_oncalculate = new Indi_Bands(bands_params, IDATA_ONCALCULATE); - indis.Push(indi_bands_oncalculate); - // whitelisted_indis.Push(indi_bands_oncalculate); + indis.Add(indi_bands_oncalculate); + // whitelisted_indis.Add(indi_bands_oncalculate); // Bears Power. IndiBearsPowerParams bears_params(13, PRICE_CLOSE); - indis.Push(new Indi_BearsPower(bears_params)); + indis.Add(new Indi_BearsPower(bears_params)); // Bulls Power. IndiBullsPowerParams bulls_params(13, PRICE_CLOSE); - indis.Push(new Indi_BullsPower(bulls_params)); + indis.Add(new Indi_BullsPower(bulls_params)); // Market Facilitation Index (BWMFI). IndiBWIndiMFIParams _bwmfi_params(1); - indis.Push(new Indi_BWMFI(_bwmfi_params)); + indis.Add(new Indi_BWMFI(_bwmfi_params)); // Commodity Channel Index (CCI). IndiCCIParams cci_params(14, PRICE_OPEN); - indis.Push(new Indi_CCI(cci_params)); + indis.Add(new Indi_CCI(cci_params)); // DeMarker. IndiDeMarkerParams dm_params(14); - indis.Push(new Indi_DeMarker(dm_params)); + indis.Add(new Indi_DeMarker(dm_params)); // Envelopes. IndiEnvelopesParams env_params(13, 0, MODE_SMA, PRICE_OPEN, 2); - indis.Push(new Indi_Envelopes(env_params)); + indis.Add(new Indi_Envelopes(env_params)); // Force Index. IndiForceParams force_params(13, MODE_SMA, PRICE_CLOSE); - indis.Push(new Indi_Force(force_params)); + indis.Add(new Indi_Force(force_params)); // Fractals. - indis.Push(new Indi_Fractals()); + indis.Add(new Indi_Fractals()); // Fractal Adaptive Moving Average (FRAMA). IndiFrAIndiMAParams frama_params(); - indis.Push(new Indi_FrAMA(frama_params)); + indis.Add(new Indi_FrAMA(frama_params)); // Gator Oscillator. IndiGatorParams gator_params(13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); - indis.Push(new Indi_Gator(gator_params)); + indis.Add(new Indi_Gator(gator_params)); // Heiken Ashi. IndiHeikenAshiParams _ha_params(); - indis.Push(new Indi_HeikenAshi(_ha_params)); + indis.Add(new Indi_HeikenAshi(_ha_params)); // Ichimoku Kinko Hyo. IndiIchimokuParams ichi_params(9, 26, 52); - indis.Push(new Indi_Ichimoku(ichi_params)); + indis.Add(new Indi_Ichimoku(ichi_params)); // Moving Average. IndiMAParams ma_params(13, 0, MODE_SMA, PRICE_OPEN); Ref indi_ma = new Indi_MA(ma_params); - indis.Push(indi_ma); + indis.Add(indi_ma); // DEMA. IndiDEMAParams dema_params(13, 2, PRICE_OPEN); Ref indi_dema = new Indi_DEMA(dema_params, INDI_DEMA_DEFAULT_IDSTYPE, indi_price.Ptr()); - // indis.Push(indi_dema); // @fixme + // indis.Add(indi_dema); // @fixme // MACD. IndiMACDParams macd_params(12, 26, 9, PRICE_CLOSE); Ref macd = new Indi_MACD(macd_params); - indis.Push(macd); + indis.Add(macd); // Money Flow Index (MFI). IndiMFIParams mfi_params(14); - indis.Push(new Indi_MFI(mfi_params)); + indis.Add(new Indi_MFI(mfi_params)); // Momentum (MOM). IndiMomentumParams mom_params(); - indis.Push(new Indi_Momentum(mom_params)); + indis.Add(new Indi_Momentum(mom_params)); // On Balance Volume (OBV). - indis.Push(new Indi_OBV()); + indis.Add(new Indi_OBV()); // OsMA. IndiOsMAParams osma_params(12, 26, 9, PRICE_CLOSE); - indis.Push(new Indi_OsMA(osma_params)); + indis.Add(new Indi_OsMA(osma_params)); // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); Ref indi_rsi = new Indi_RSI(rsi_params); - indis.Push(indi_rsi.Ptr()); + indis.Add(indi_rsi.Ptr()); // Bollinger Bands over RSI. IndiBandsParams indi_bands_over_rsi_params(20, 2, 0, PRICE_OPEN); @@ -287,26 +291,26 @@ bool InitIndicators() { // Using RSI's mode 0 as applied price. indi_bands_over_rsi REF_DEREF SetDataSourceAppliedPrice(INDI_VS_TYPE_INDEX_0); indi_bands_over_rsi REF_DEREF SetDataSource(indi_rsi.Ptr()); - indis.Push(indi_bands_over_rsi); + indis.Add(indi_bands_over_rsi); // Standard Deviation (StdDev). IndiStdDevParams stddev_params(13, 10, MODE_SMA, PRICE_OPEN); Ref indi_stddev = new Indi_StdDev(stddev_params); - indis.Push(indi_stddev); + indis.Add(indi_stddev); // Relative Strength Index (RSI) over Standard Deviation (StdDev). IndiRSIParams indi_rsi_over_stddev_params(); Ref indi_rsi_over_stddev = new Indi_RSI(indi_rsi_over_stddev_params); indi_rsi_over_stddev.Ptr().SetDataSource(indi_stddev.Ptr()); - indis.Push(indi_rsi_over_stddev); + indis.Add(indi_rsi_over_stddev); // Relative Vigor Index (RVI). IndiRVIParams rvi_params(14); - indis.Push(new Indi_RVI(rvi_params)); + indis.Add(new Indi_RVI(rvi_params)); // Parabolic SAR. IndiSARParams sar_params(0.02, 0.2); - indis.Push(new Indi_SAR(sar_params)); + indis.Add(new Indi_SAR(sar_params)); // Standard Deviation (StdDev). Ref indi_price_for_stdev = new Indi_Price(PriceIndiParams()); @@ -314,24 +318,24 @@ bool InitIndicators() { // stddev_on_price_params.SetDraw(clrBlue, 1); // @fixme Ref indi_stddev_on_price = new Indi_StdDev(stddev_on_price_params, IDATA_BUILTIN, indi_price_for_stdev.Ptr()); - indis.Push(indi_stddev_on_price.Ptr()); + indis.Add(indi_stddev_on_price.Ptr()); // Stochastic Oscillator. IndiStochParams stoch_params(5, 3, 3, MODE_SMMA, STO_LOWHIGH); - indis.Push(new Indi_Stochastic(stoch_params)); + indis.Add(new Indi_Stochastic(stoch_params)); // Williams' Percent Range (WPR). IndiWPRParams wpr_params(14); - indis.Push(new Indi_WPR(wpr_params)); + indis.Add(new Indi_WPR(wpr_params)); // ZigZag. IndiZigZagParams zz_params(12, 5, 3); - indis.Push(new Indi_ZigZag(zz_params)); + indis.Add(new Indi_ZigZag(zz_params)); /* Special indicators */ // Demo/Dummy Indicator. - indis.Push(new Indi_Demo()); + indis.Add(new Indi_Demo()); // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); @@ -339,7 +343,7 @@ bool InitIndicators() { IndiBandsParams bands_on_price_params(); // bands_on_price_params.SetDraw(clrCadetBlue); // @fixme Ref indi_bands_on_price = new Indi_Bands(bands_on_price_params, IDATA_BUILTIN, indi_price_4_bands.Ptr()); - indis.Push(indi_bands_on_price.Ptr()); + indis.Add(indi_bands_on_price.Ptr()); // Standard Deviation (StdDev) over MA(SMA). // NOTE: If you set ma_shift parameter for MA, then StdDev will no longer @@ -352,7 +356,7 @@ bool InitIndicators() { Ref indi_stddev_on_ma_sma = new Indi_StdDev(stddev_params_on_ma_sma, IDATA_BUILTIN, indi_ma_sma_for_stddev.Ptr()); - indis.Push(indi_stddev_on_ma_sma.Ptr()); + indis.Add(indi_stddev_on_ma_sma.Ptr()); // Standard Deviation (StdDev) in SMA mode over Price. PriceIndiParams price_params_for_stddev_sma(); @@ -361,7 +365,7 @@ bool InitIndicators() { // stddev_sma_on_price_params.SetDraw(true, 1); // @fixme Ref indi_stddev_on_sma = new Indi_StdDev(stddev_sma_on_price_params, IDATA_BUILTIN, indi_price_for_stddev_sma.Ptr()); - indis.Push(indi_stddev_on_sma.Ptr()); + indis.Add(indi_stddev_on_sma.Ptr()); // Moving Average (MA) over Price indicator. PriceIndiParams price_params_4_ma(); @@ -370,7 +374,7 @@ bool InitIndicators() { // ma_on_price_params.SetDraw(clrYellowGreen); // @fixme ma_on_price_params.SetIndicatorType(INDI_MA_ON_PRICE); Ref indi_ma_on_price = new Indi_MA(ma_on_price_params, IDATA_BUILTIN, indi_price_4_ma.Ptr()); - indis.Push(indi_ma_on_price.Ptr()); + indis.Add(indi_ma_on_price.Ptr()); // Commodity Channel Index (CCI) over Price indicator. PriceIndiParams price_params_4_cci(); @@ -378,7 +382,7 @@ bool InitIndicators() { IndiCCIParams cci_on_price_params(); // cci_on_price_params.SetDraw(clrYellowGreen, 1); // @fixme Ref indi_cci_on_price = new Indi_CCI(cci_on_price_params, IDATA_BUILTIN, indi_price_4_cci.Ptr()); - indis.Push(indi_cci_on_price.Ptr()); + indis.Add(indi_cci_on_price.Ptr()); // Envelopes over Price indicator. PriceIndiParams price_params_4_envelopes(); @@ -387,7 +391,7 @@ bool InitIndicators() { // env_on_price_params.SetDraw(clrBrown); // @fixme Ref indi_envelopes_on_price = new Indi_Envelopes(env_on_price_params, IDATA_BUILTIN, indi_price_4_envelopes.Ptr()); - indis.Push(indi_envelopes_on_price.Ptr()); + indis.Add(indi_envelopes_on_price.Ptr()); // DEMA over Price indicator. PriceIndiParams price_params_4_dema(); @@ -396,7 +400,7 @@ bool InitIndicators() { // dema_on_price_params.SetDraw(clrRed); // @fixme Ref indi_dema_on_price = new Indi_DEMA(dema_on_price_params, INDI_DEMA_DEFAULT_IDSTYPE, indi_price_4_dema.Ptr()); - // indis.Push(indi_dema_on_price.Ptr()); // @fixme + // indis.Add(indi_dema_on_price.Ptr()); // @fixme // Momentum over Price indicator. Ref indi_price_4_momentum = new Indi_Price(); @@ -404,7 +408,7 @@ bool InitIndicators() { // mom_on_price_params.SetDraw(clrDarkCyan); // @fixme Ref indi_momentum_on_price = new Indi_Momentum(mom_on_price_params, IDATA_BUILTIN, indi_price_4_momentum.Ptr()); - indis.Push(indi_momentum_on_price.Ptr()); + indis.Add(indi_momentum_on_price.Ptr()); // Relative Strength Index (RSI) over Price indicator. PriceIndiParams price_params_4_rsi(); @@ -412,13 +416,13 @@ bool InitIndicators() { IndiRSIParams rsi_on_price_params(); // rsi_on_price_params.SetDraw(clrBisque, 1); // @fixme Ref indi_rsi_on_price = new Indi_RSI(rsi_on_price_params, IDATA_BUILTIN, indi_price_4_rsi.Ptr()); - indis.Push(indi_rsi_on_price.Ptr()); + indis.Add(indi_rsi_on_price.Ptr()); // Drawer (socket-based) indicator over RSI over Price. IndiDrawerParams drawer_params(14, PRICE_OPEN); // drawer_params.SetDraw(clrBisque, 0); // @fixme Ref indi_drawer_on_rsi = new Indi_Drawer(drawer_params, IDATA_BUILTIN, indi_rsi_on_price.Ptr()); - indis.Push(indi_drawer_on_rsi.Ptr()); + indis.Add(indi_drawer_on_rsi.Ptr()); // Applied Price over OHCL indicator. IndiAppliedPriceParams applied_price_params(); @@ -426,11 +430,11 @@ bool InitIndicators() { IndiOHLCParams applied_price_ohlc_params(PRICE_TYPICAL); Ref indi_applied_price_on_price = new Indi_AppliedPrice(applied_price_params, IDATA_INDICATOR, new Indi_OHLC(applied_price_ohlc_params)); - indis.Push(indi_applied_price_on_price.Ptr()); + indis.Add(indi_applied_price_on_price.Ptr()); // ADXW. IndiADXWParams adxw_params(14); - indis.Push(new Indi_ADXW(adxw_params)); + indis.Add(new Indi_ADXW(adxw_params)); // AMA. IndiAMAParams ama_params(); @@ -438,129 +442,129 @@ bool InitIndicators() { // However, in that case we need to specifiy applied price (excluding ASK and BID). Indi_AMA* _indi_ama = new Indi_AMA(ama_params, IDATA_INDICATOR); _indi_ama.SetAppliedPrice(PRICE_OPEN); - indis.Push(_indi_ama); + indis.Add(_indi_ama); // Original AMA. IndiAMAParams ama_params_orig(); ama_params_orig.SetName("Original AMA to compare"); - indis.Push(new Indi_AMA(ama_params_orig)); + indis.Add(new Indi_AMA(ama_params_orig)); // Chaikin Oscillator. IndiCHOParams cho_params(); - indis.Push(new Indi_CHO(cho_params)); + indis.Add(new Indi_CHO(cho_params)); // Chaikin Volatility. IndiCHVParams chv_params(); - indis.Push(new Indi_CHV(chv_params)); + indis.Add(new Indi_CHV(chv_params)); // Color Bars. IndiColorBarsParams color_bars_params(); - indis.Push(new Indi_ColorBars(color_bars_params)); + indis.Add(new Indi_ColorBars(color_bars_params)); // Color Candles Daily. IndiColorCandlesDailyParams color_candles_daily_params(); - indis.Push(new Indi_ColorCandlesDaily(color_candles_daily_params)); + indis.Add(new Indi_ColorCandlesDaily(color_candles_daily_params)); // Color Line. IndiColorLineParams color_line_params(); - indis.Push(new Indi_ColorLine(color_line_params)); + indis.Add(new Indi_ColorLine(color_line_params)); // Detrended Price Oscillator. IndiDetrendedPriceParams detrended_params(); - indis.Push(new Indi_DetrendedPrice(detrended_params)); + indis.Add(new Indi_DetrendedPrice(detrended_params)); // Mass Index. IndiMassIndexParams mass_index_params(); - indis.Push(new Indi_MassIndex(mass_index_params)); + indis.Add(new Indi_MassIndex(mass_index_params)); // OHLC. IndiOHLCParams ohlc_params(); - indis.Push(new Indi_OHLC(ohlc_params)); + indis.Add(new Indi_OHLC(ohlc_params)); // Price Channel. IndiPriceChannelParams price_channel_params(); - indis.Push(new Indi_PriceChannel(price_channel_params)); + indis.Add(new Indi_PriceChannel(price_channel_params)); // Price Volume Trend. IndiPriceVolumeTrendParams price_volume_trend_params(); - indis.Push(new Indi_PriceVolumeTrend(price_volume_trend_params)); + indis.Add(new Indi_PriceVolumeTrend(price_volume_trend_params)); // Bill Williams' Zone Trade. IndiBWZTParams bwzt_params(); - indis.Push(new Indi_BWZT(bwzt_params)); + indis.Add(new Indi_BWZT(bwzt_params)); // Rate of Change. IndiRateOfChangeParams rate_of_change_params(); - indis.Push(new Indi_RateOfChange(rate_of_change_params)); + indis.Add(new Indi_RateOfChange(rate_of_change_params)); // Triple Exponential Moving Average. IndiTEMAParams tema_params(); - indis.Push(new Indi_TEMA(tema_params)); + indis.Add(new Indi_TEMA(tema_params)); // Triple Exponential Average. IndiTRIXParams trix_params(); - indis.Push(new Indi_TRIX(trix_params)); + indis.Add(new Indi_TRIX(trix_params)); // Ultimate Oscillator. IndiUltimateOscillatorParams ultimate_oscillator_params(); - indis.Push(new Indi_UltimateOscillator(ultimate_oscillator_params)); + indis.Add(new Indi_UltimateOscillator(ultimate_oscillator_params)); // VIDYA. IndiVIDYAParams vidya_params(); - indis.Push(new Indi_VIDYA(vidya_params)); + indis.Add(new Indi_VIDYA(vidya_params)); // Volumes. IndiVolumesParams volumes_params(); - indis.Push(new Indi_Volumes(volumes_params)); + indis.Add(new Indi_Volumes(volumes_params)); // Volume Rate of Change. IndiVROCParams vol_rate_of_change_params(); - indis.Push(new Indi_VROC(vol_rate_of_change_params)); + indis.Add(new Indi_VROC(vol_rate_of_change_params)); // Larry Williams' Accumulation/Distribution. IndiWilliamsADParams williams_ad_params(); - indis.Push(new Indi_WilliamsAD(williams_ad_params)); + indis.Add(new Indi_WilliamsAD(williams_ad_params)); // ZigZag Color. IndiZigZagColorParams zigzag_color_params(); - indis.Push(new Indi_ZigZagColor(zigzag_color_params)); + indis.Add(new Indi_ZigZagColor(zigzag_color_params)); // Custom Moving Average. IndiCustomMovingAverageParams cma_params(); - indis.Push(new Indi_CustomMovingAverage(cma_params)); + indis.Add(new Indi_CustomMovingAverage(cma_params)); // Math (specialized indicator). IndiMathParams math_params(MATH_OP_SUB, BAND_UPPER, BAND_LOWER, 0, 0); // math_params.SetDraw(clrBlue); // @fixme math_params.SetName("Bands(UP - LO)"); Ref indi_math_1 = new Indi_Math(math_params, IDATA_INDICATOR, indi_bands.Ptr()); - indis.Push(indi_math_1.Ptr()); + indis.Add(indi_math_1.Ptr()); // Math (specialized indicator) via custom math method. IndiMathParams math_custom_params(MathCustomOp, BAND_UPPER, BAND_LOWER, 0, 0); // math_custom_params.SetDraw(clrBeige); // @fixme math_custom_params.SetName("Bands(Custom math fn)"); Ref indi_math_2 = new Indi_Math(math_custom_params, IDATA_INDICATOR, indi_bands.Ptr()); - indis.Push(indi_math_2.Ptr()); + indis.Add(indi_math_2.Ptr()); // RS (Math-based) indicator. IndiRSParams rs_params(); - indis.Push(new Indi_RS(rs_params)); + indis.Add(new Indi_RS(rs_params)); // Pattern Detector. IndiPatternParams pattern_params(); - indis.Push(new Indi_Pattern(pattern_params)); + indis.Add(new Indi_Pattern(pattern_params)); // Pivot. IndiPivotParams pivot_params(); - indis.Push(new Indi_Pivot(pivot_params)); + indis.Add(new Indi_Pivot(pivot_params)); // Candle Pattern Detector. CandleParams candle_params(); - indis.Push(new Indi_Candle(candle_params)); + indis.Add(new Indi_Candle(candle_params)); // Push white-listed indicators here. - // whitelisted_indis.Push(_indi_test); + // whitelisted_indis.Add(_indi_test); return GetLastError() == ERR_NO_ERROR; } @@ -571,13 +575,13 @@ double MathCustomOp(double a, double b) { return 1.11 + (b - a) * 2.0; } * Print indicators. */ bool PrintIndicators(string _prefix = "") { - for (DictIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { - if (whitelisted_indis.Size() != 0 && !whitelisted_indis.Contains(iter.Value())) { + for (int i = 0; i < indis.Size(); ++i) { + IndicatorData* _indi = indis[i]; + + if (whitelisted_indis.Size() != 0 && !whitelisted_indis.Contains(_indi)) { continue; } - IndicatorData* _indi = iter.Value().Ptr(); - if (_indi.GetModeCount() == 0) { // Indicator has no modes. PrintFormat("Skipping %s as it has no modes.", _indi.GetFullName()); @@ -592,7 +596,7 @@ bool PrintIndicators(string _prefix = "") { continue; } if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { - PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString(0)); + PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString()); } } return GetLastError() == ERR_NO_ERROR; diff --git a/tests/OrderTest.mq5 b/tests/OrderTest.mq5 index 90e383e7e..fe52252a9 100644 --- a/tests/OrderTest.mq5 +++ b/tests/OrderTest.mq5 @@ -48,7 +48,7 @@ Order *orders_dummy[MAX_ORDERS]; */ int OnInit() { Platform::Init(); - _candles = Platform::FetchDefaultCandleIndicator(); + _candles = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); bool _result = true; bar_processed = 0; assertTrueOrFail(GetLastError() == ERR_NO_ERROR, StringFormat("Error: %d!", GetLastError())); @@ -113,7 +113,7 @@ bool OpenOrder(int _index, int _order_no) { OrderParams _oparams; if (_request.type == ORDER_TYPE_SELL) { ARRAY(DataParamEntry, _cond_args); - DataParamEntry _param1 = ORDER_TYPE_TIME; + DataParamEntry _param1 = (int)ORDER_TYPE_TIME; DataParamEntry _param2 = PeriodSeconds() * (MAX_ORDERS + _index); ArrayPushObject(_cond_args, _param1); ArrayPushObject(_cond_args, _param2); diff --git a/tests/RefsTest.mq5 b/tests/RefsTest.mq5 index b1ede0055..0cbb8cc72 100644 --- a/tests/RefsTest.mq5 +++ b/tests/RefsTest.mq5 @@ -39,6 +39,7 @@ class DynamicClass : public Dynamic { int number; DynamicClass(int _number, DynamicClass* _parent = NULL) : number(_number), parent(_parent) {} + DynamicClass(const DynamicClass& r) { THIS_REF = r; } }; /** @@ -57,7 +58,6 @@ class BadDynamicClass : public Dynamic { */ int OnInit() { // Weak references only. - WeakRef dyn1 = new DynamicClass(1); assertTrueOrFail(dyn1.ObjectExists(), "Object should exist"); diff --git a/tests/TerminalTest.mq5 b/tests/TerminalTest.mq5 index 27bed3c2f..0721111f3 100644 --- a/tests/TerminalTest.mq5 +++ b/tests/TerminalTest.mq5 @@ -37,7 +37,7 @@ Terminal *terminal; */ int OnInit() { terminal = new Terminal(); - Print("TERMINAL (OnInit):\n\t\t\t", terminal.ToString("\n\t\t\t")); + Print("TERMINAL (OnInit):\n\t\t\t", terminal.ToString()); assertTrueOrFail(terminal.IsDllsAllowed(), "DLLs not allowed!"); assertTrueOrFail(terminal.IsExpertEnabled(), "Expert Advisors not allowed!"); assertTrueOrFail(terminal.IsLibrariesAllowed(), "Libraries not allowed!"); @@ -73,6 +73,6 @@ int OnInit() { * Implements OnDeinit(). */ void OnDeinit(const int reason) { - Print("TERMINAL (OnDeinit):\n\t\t\t", terminal.ToString("\n\t\t\t")); + Print("TERMINAL (OnDeinit):\n\t\t\t", terminal.ToString()); Object::Delete(terminal); } diff --git a/tests/TradeTest.mq5 b/tests/TradeTest.mq5 index 0d0de3356..09f476f95 100644 --- a/tests/TradeTest.mq5 +++ b/tests/TradeTest.mq5 @@ -46,10 +46,9 @@ bool _finish_test = false; */ int OnInit() { Platform::Init(); - _chart_m1 = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_M1); - _chart_m5 = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_M5); - Platform::Add(_chart_m1.Ptr()); - Platform::Add(_chart_m5.Ptr()); + _chart_m1 = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M1); + _chart_m5 = Platform::FetchDefaultCandleIndicator("EURUSD", PERIOD_M5); + return INIT_SUCCEEDED; } @@ -83,7 +82,7 @@ int Test() { // Test market. assertTrueOrFail(trade1 PTR_DEREF IsTradeAllowed(), "Trade not allowed!"); assertTrueOrFail(trade1 PTR_DEREF GetSource() PTR_DEREF GetTf() == PERIOD_M1, - StringFormat("Fail on GetTf() => [%s]!", trade1 PTR_DEREF GetSource() PTR_DEREF GetTf())); + StringFormat("Fail on GetTf() => [%d]!", trade1 PTR_DEREF GetSource() PTR_DEREF GetTf())); assertTrueOrFail(trade1 PTR_DEREF GetSource() PTR_DEREF GetOpen() > 0, "Fail on GetOpen()!"); assertTrueOrFail(trade1 PTR_DEREF GetSource() PTR_DEREF GetSymbol() == _Symbol, "Fail on GetSymbol()!"); // assertTrueOrFail(trade1.IsTradeAllowed(), "Fail on IsTradeAllowed()!"); // @fixme