From ef21d9a8c91bf96dd6c5c02e6916982ea0a1caf1 Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 6 Oct 2021 14:54:43 +0100 Subject: [PATCH 01/84] Task: Moves Task to Task/ directory --- Action.struct.h | 2 +- Condition.struct.h | 2 +- EA.mqh | 2 +- EA.struct.h | 2 +- Strategy.mqh | 2 +- Strategy.struct.h | 2 +- Task.enum.h => Task/Task.enum.h | 0 Task.mqh => Task/Task.h | 8 ++++---- Task.struct.h => Task/Task.struct.h | 4 ++-- tests/TaskTest.mq4 => Task/tests/Task.test.mq4 | 2 +- tests/TaskTest.mq5 => Task/tests/Task.test.mq5 | 12 ++++++------ tests/CompileTest.mq5 | 2 +- 12 files changed, 20 insertions(+), 20 deletions(-) rename Task.enum.h => Task/Task.enum.h (100%) rename Task.mqh => Task/Task.h (98%) rename Task.struct.h => Task/Task.struct.h (98%) rename tests/TaskTest.mq4 => Task/tests/Task.test.mq4 (97%) rename tests/TaskTest.mq5 => Task/tests/Task.test.mq5 (95%) diff --git a/Action.struct.h b/Action.struct.h index 1f5481f14..5d9d1d962 100644 --- a/Action.struct.h +++ b/Action.struct.h @@ -40,7 +40,7 @@ #include "Order.enum.h" #include "Serializer.mqh" #include "Strategy.enum.h" -#include "Task.enum.h" +#include "Task/Task.enum.h" #include "Trade.enum.h" /* Entry for Action class. */ diff --git a/Condition.struct.h b/Condition.struct.h index 6e3376812..8a09c7160 100644 --- a/Condition.struct.h +++ b/Condition.struct.h @@ -38,7 +38,7 @@ //#include "Market.enum.h" #include "Order.enum.h" #include "Strategy.enum.h" -#include "Task.enum.h" +#include "Task/Task.enum.h" #include "Trade.enum.h" struct ConditionEntry { diff --git a/EA.mqh b/EA.mqh index dc69164c8..aaf1118c8 100644 --- a/EA.mqh +++ b/EA.mqh @@ -46,7 +46,7 @@ #include "SerializerSqlite.mqh" #include "Strategy.mqh" #include "SummaryReport.mqh" -#include "Task.mqh" +#include "Task/Task.h" #include "Terminal.mqh" #include "Trade.mqh" diff --git a/EA.struct.h b/EA.struct.h index aa36c2e5e..115329e19 100644 --- a/EA.struct.h +++ b/EA.struct.h @@ -32,7 +32,7 @@ // Includes. #include "DateTime.mqh" -#include "Task.struct.h" +#include "Task/Task.struct.h" /* Defines EA config parameters. */ struct EAParams { diff --git a/Strategy.mqh b/Strategy.mqh index 84af95675..3823f986f 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -36,7 +36,7 @@ class Trade; #include "Strategy.enum.h" #include "Strategy.struct.h" #include "String.mqh" -#include "Task.mqh" +#include "Task/Task.h" #include "Trade.mqh" // Defines. diff --git a/Strategy.struct.h b/Strategy.struct.h index 11c55f85f..2bd46ee92 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -34,7 +34,7 @@ #include "Serializer.mqh" #include "Strategy.enum.h" #include "Strategy.struct.pricestop.h" -#include "Task.struct.h" +#include "Task/Task.struct.h" // Forward class declaration. class Strategy; diff --git a/Task.enum.h b/Task/Task.enum.h similarity index 100% rename from Task.enum.h rename to Task/Task.enum.h diff --git a/Task.mqh b/Task/Task.h similarity index 98% rename from Task.mqh rename to Task/Task.h index 2db50c5e4..96152ec9a 100644 --- a/Task.mqh +++ b/Task/Task.h @@ -30,10 +30,10 @@ #define TASK_MQH // Includes. -#include "Action.mqh" -#include "Condition.mqh" -#include "DictStruct.mqh" -#include "Refs.mqh" +#include "../Action.mqh" +#include "../Condition.mqh" +#include "../DictStruct.mqh" +#include "../Refs.mqh" #include "Task.enum.h" #include "Task.struct.h" diff --git a/Task.struct.h b/Task/Task.struct.h similarity index 98% rename from Task.struct.h rename to Task/Task.struct.h index d1b7487ce..e9a4e977d 100644 --- a/Task.struct.h +++ b/Task/Task.struct.h @@ -31,8 +31,8 @@ #endif // Includes. -#include "Action.struct.h" -#include "Condition.struct.h" +#include "../Action.struct.h" +#include "../Condition.struct.h" #include "Task.enum.h" struct TaskEntry { diff --git a/tests/TaskTest.mq4 b/Task/tests/Task.test.mq4 similarity index 97% rename from tests/TaskTest.mq4 rename to Task/tests/Task.test.mq4 index 9dd81f28c..3ab46d4b9 100644 --- a/tests/TaskTest.mq4 +++ b/Task/tests/Task.test.mq4 @@ -25,4 +25,4 @@ */ // Includes. -#include "TaskTest.mq5" +#include "Task.test.mq5" diff --git a/tests/TaskTest.mq5 b/Task/tests/Task.test.mq5 similarity index 95% rename from tests/TaskTest.mq5 rename to Task/tests/Task.test.mq5 index 67ebb58d3..34652fedc 100644 --- a/tests/TaskTest.mq5 +++ b/Task/tests/Task.test.mq5 @@ -28,12 +28,12 @@ struct DataParamEntry; // Includes. -#include "../Action.mqh" -#include "../Chart.mqh" -#include "../DictObject.mqh" -#include "../EA.mqh" -#include "../Task.mqh" -#include "../Test.mqh" +#include "../../Action.mqh" +#include "../../Chart.mqh" +#include "../../DictObject.mqh" +#include "../../EA.mqh" +#include "../Task.h" +#include "../../Test.mqh" // Global variables. Chart *chart; diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index f9baa3e85..94171d422 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -99,7 +99,7 @@ #include "../String.mqh" #include "../SummaryReport.mqh" #include "../SymbolInfo.mqh" -#include "../Task.mqh" +#include "../Task/Task.h" #include "../Terminal.mqh" // #include "../Tester.mqh" // @removeme #include "../Storage/ValueStorage.h" From 9ad467e0efd839b835e710c40d5ba8e7ea81110e Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 6 Oct 2021 15:07:17 +0100 Subject: [PATCH 02/84] Renames Condition to TaskCondition --- .github/workflows/test.yml | 2 - Action.mqh | 2 +- Chart.mqh | 2 +- Condition.struct.h | 111 ------------------ EA.mqh | 2 +- Market.mqh | 2 +- Task/Task.h | 4 +- Task/Task.struct.h | 22 ++-- Condition.enum.h => Task/TaskCondition.enum.h | 8 +- Condition.mqh => Task/TaskCondition.h | 60 +++++----- Task/TaskCondition.struct.h | 111 ++++++++++++++++++ Task/tests/Task.test.mq5 | 2 +- .../tests/TaskCondition.test.mq4 | 4 +- .../tests/TaskCondition.test.mq5 | 36 +++--- Trade.mqh | 2 +- tests/CompileTest.mq5 | 2 +- 16 files changed, 185 insertions(+), 187 deletions(-) delete mode 100644 Condition.struct.h rename Condition.enum.h => Task/TaskCondition.enum.h (98%) rename Condition.mqh => Task/TaskCondition.h (84%) create mode 100644 Task/TaskCondition.struct.h rename tests/ConditionTest.mq4 => Task/tests/TaskCondition.test.mq4 (92%) rename tests/ConditionTest.mq5 => Task/tests/TaskCondition.test.mq5 (77%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 18c954e3f..d8b156bbd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,7 +59,6 @@ jobs: - BufferTest - ChartTest - CompileIndicatorsTest - - ConditionTest - DatabaseTest - DrawIndicatorTest - EATest @@ -76,7 +75,6 @@ jobs: - StrategyTest-RSI - SymbolInfoTest - SummaryReportTest - - TaskTest - TickerTest - TradeTest steps: diff --git a/Action.mqh b/Action.mqh index 85f9a3a9b..2885da24c 100644 --- a/Action.mqh +++ b/Action.mqh @@ -35,8 +35,8 @@ class Action; // Includes. #include "Action.enum.h" #include "Action.struct.h" -#include "Condition.enum.h" #include "EA.mqh" +#include "Task/TaskCondition.enum.h" /** * Action class. diff --git a/Chart.mqh b/Chart.mqh index a568d8ae5..6a98e0644 100644 --- a/Chart.mqh +++ b/Chart.mqh @@ -42,10 +42,10 @@ class Market; #include "Chart.enum.h" #include "Chart.struct.h" #include "Chart.struct.serialize.h" -#include "Condition.enum.h" #include "Convert.mqh" #include "Market.mqh" #include "Serializer.mqh" +#include "Task/TaskCondition.enum.h" #ifndef __MQL4__ // Defines structs (for MQL4 backward compatibility). diff --git a/Condition.struct.h b/Condition.struct.h deleted file mode 100644 index 8a09c7160..000000000 --- a/Condition.struct.h +++ /dev/null @@ -1,111 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 Condition's structs. - */ - -#ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once -#endif - -// Includes. -#include "Account.enum.h" -#include "Chart.enum.h" -#include "DateTime.enum.h" -#include "EA.enum.h" -#include "Indicator.enum.h" -//#include "Market.enum.h" -#include "Order.enum.h" -#include "Strategy.enum.h" -#include "Task/Task.enum.h" -#include "Trade.enum.h" - -struct ConditionEntry { - unsigned char flags; // Condition flags. - datetime last_check; // Time of the latest check. - datetime last_success; // Time of the last success. - int frequency; // How often to check. - long cond_id; // Condition ID. - short tries; // Number of successful tries left. - void *obj; // Reference to associated object. - ENUM_CONDITION_STATEMENT next_statement; // Statement type of the next condition. - ENUM_CONDITION_TYPE type; // Condition type. - DataParamEntry args[]; // Condition arguments. - // Constructors. - void ConditionEntry() : type(FINAL_CONDITION_TYPE_ENTRY), cond_id(WRONG_VALUE) { Init(); } - void ConditionEntry(long _cond_id, ENUM_CONDITION_TYPE _type) : type(_type), cond_id(_cond_id) { Init(); } - void ConditionEntry(ConditionEntry &_ce) { this = _ce; } - void ConditionEntry(ENUM_ACCOUNT_CONDITION _cond_id) : type(COND_TYPE_ACCOUNT), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_CHART_CONDITION _cond_id) : type(COND_TYPE_CHART), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_DATETIME_CONDITION _cond_id) : type(COND_TYPE_DATETIME), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_EA_CONDITION _cond_id) : type(COND_TYPE_EA), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_INDICATOR_CONDITION _cond_id) : type(COND_TYPE_INDICATOR), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_MARKET_CONDITION _cond_id) : type(COND_TYPE_MARKET), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_ORDER_CONDITION _cond_id) : type(COND_TYPE_ORDER), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_STRATEGY_CONDITION _cond_id) : type(COND_TYPE_STRATEGY), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_TASK_CONDITION _cond_id) : type(COND_TYPE_TASK), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_TRADE_CONDITION _cond_id) : type(COND_TYPE_TRADE), cond_id(_cond_id) { Init(); } - // Deconstructor. - void ~ConditionEntry() { - // Object::Delete(obj); - } - // Flag methods. - bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } - void AddFlags(unsigned char _flags) { flags |= _flags; } - void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } - void SetFlag(ENUM_CONDITION_ENTRY_FLAGS _flag, bool _value) { - if (_value) - AddFlags(_flag); - else - RemoveFlags(_flag); - } - void SetFlags(unsigned char _flags) { flags = _flags; } - // State methods. - bool IsActive() { return HasFlag(COND_ENTRY_FLAG_IS_ACTIVE); } - bool IsExpired() { return HasFlag(COND_ENTRY_FLAG_IS_EXPIRED); } - bool IsReady() { return HasFlag(COND_ENTRY_FLAG_IS_READY); } - bool IsInvalid() { return HasFlag(COND_ENTRY_FLAG_IS_INVALID); } - bool IsValid() { return !IsInvalid(); } - // Getters. - long GetId() { return cond_id; } - ENUM_CONDITION_TYPE GetType() { return type; } - // Setters. - void AddArg(MqlParam &_arg) { - // @todo: Add another value to args[]. - } - void Init() { - flags = COND_ENTRY_FLAG_NONE; - frequency = 60; - SetFlag(COND_ENTRY_FLAG_IS_ACTIVE, cond_id != WRONG_VALUE); - SetFlag(COND_ENTRY_FLAG_IS_INVALID, cond_id == WRONG_VALUE); - last_check = last_success = 0; - next_statement = COND_AND; - tries = 1; - } - void SetArgs(MqlParam &_args[]) { - // @todo: for(). - } - void SetObject(void *_obj) { obj = _obj; } - void SetTries(short _count) { tries = _count; } -}; diff --git a/EA.mqh b/EA.mqh index aaf1118c8..d94f61ea5 100644 --- a/EA.mqh +++ b/EA.mqh @@ -32,7 +32,6 @@ // Includes. #include "Action.enum.h" #include "Chart.mqh" -#include "Condition.enum.h" #include "Data.struct.h" #include "Dict.mqh" #include "DictObject.mqh" @@ -47,6 +46,7 @@ #include "Strategy.mqh" #include "SummaryReport.mqh" #include "Task/Task.h" +#include "Task/TaskCondition.enum.h" #include "Terminal.mqh" #include "Trade.mqh" diff --git a/Market.mqh b/Market.mqh index b9a2bf9bc..c5945335b 100644 --- a/Market.mqh +++ b/Market.mqh @@ -29,12 +29,12 @@ class Market; class SymbolInfo; // Includes. -#include "Condition.enum.h" #include "Market.struct.h" #include "Math.h" #include "Order.mqh" #include "Serializer.mqh" #include "SymbolInfo.mqh" +#include "Task/TaskCondition.enum.h" // Structs. // Market info. diff --git a/Task/Task.h b/Task/Task.h index 96152ec9a..2c41e2ead 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -31,9 +31,9 @@ // Includes. #include "../Action.mqh" -#include "../Condition.mqh" #include "../DictStruct.mqh" #include "../Refs.mqh" +#include "../Task/TaskCondition.h" #include "Task.enum.h" #include "Task.struct.h" @@ -98,7 +98,7 @@ class Task { static bool Process(TaskEntry &_entry) { bool _result = false; if (_entry.IsActive()) { - if (Condition::Test(_entry.GetCondition())) { + if (TaskCondition::Test(_entry.GetCondition())) { ActionEntry _action = _entry.GetAction(); Action::Execute(_action); if (_action.IsDone()) { diff --git a/Task/Task.struct.h b/Task/Task.struct.h index e9a4e977d..57b5d856c 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -32,20 +32,20 @@ // Includes. #include "../Action.struct.h" -#include "../Condition.struct.h" #include "Task.enum.h" +#include "TaskCondition.struct.h" struct TaskEntry { - ActionEntry action; // Action of the task. - ConditionEntry cond; // Condition of the task. - datetime expires; // Time of expiration. - datetime last_process; // Time of the last process. - datetime last_success; // Time of the last success. - unsigned char flags; // Action flags. + ActionEntry action; // Action of the task. + TaskConditionEntry cond; // TaskCondition of the task. + datetime expires; // Time of expiration. + datetime last_process; // Time of the last process. + datetime last_success; // Time of the last success. + unsigned char flags; // Action flags. // Constructors. void TaskEntry() { Init(); } - void TaskEntry(ActionEntry &_action, ConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } - void TaskEntry(long _aid, ENUM_ACTION_TYPE _atype, long _cid, ENUM_CONDITION_TYPE _ctype) + void TaskEntry(ActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } + void TaskEntry(long _aid, ENUM_ACTION_TYPE _atype, long _cid, ENUM_TASK_CONDITION_TYPE _ctype) : action(_aid, _atype), cond(_cid, _ctype) { Init(); } @@ -80,9 +80,9 @@ struct TaskEntry { long GetActionId() { return action.GetId(); } long GetConditionId() { return cond.GetId(); } ActionEntry GetAction() { return action; } - ConditionEntry GetCondition() { return cond; } + TaskConditionEntry GetCondition() { return cond; } ENUM_ACTION_TYPE GetActionType() { return action.GetType(); } - ENUM_CONDITION_TYPE GetConditionType() { return cond.GetType(); } + ENUM_TASK_CONDITION_TYPE GetConditionType() { return cond.GetType(); } // Setters. void SetActionObject(void *_obj) { action.SetObject(_obj); } void SetConditionObject(void *_obj) { cond.SetObject(_obj); } diff --git a/Condition.enum.h b/Task/TaskCondition.enum.h similarity index 98% rename from Condition.enum.h rename to Task/TaskCondition.enum.h index 3f7a8e9a4..25faf93a4 100644 --- a/Condition.enum.h +++ b/Task/TaskCondition.enum.h @@ -21,7 +21,7 @@ /** * @file - * Includes Condition's enums. + * Includes TaskCondition's enums. */ #ifndef __MQL__ @@ -85,7 +85,7 @@ enum ENUM_MARKET_EVENT { #endif /* Defines condition entry flags. */ -enum ENUM_CONDITION_ENTRY_FLAGS { +enum ENUM_TASK_CONDITION_ENTRY_FLAGS { COND_ENTRY_FLAG_NONE = 0, COND_ENTRY_FLAG_IS_ACTIVE = 1, COND_ENTRY_FLAG_IS_EXPIRED = 2, @@ -94,7 +94,7 @@ enum ENUM_CONDITION_ENTRY_FLAGS { }; /* Defines condition statements (operators). */ -enum ENUM_CONDITION_STATEMENT { +enum ENUM_TASK_CONDITION_STATEMENT { COND_AND = 1, // Use AND statement. COND_OR, // Use OR statement. COND_SEQ, // Use sequential checks. @@ -102,7 +102,7 @@ enum ENUM_CONDITION_STATEMENT { }; /* Defines condition types. */ -enum ENUM_CONDITION_TYPE { +enum ENUM_TASK_CONDITION_TYPE { COND_TYPE_ACCOUNT = 1, // Account condition. COND_TYPE_ACTION, // Action condition. COND_TYPE_CHART, // Chart condition. diff --git a/Condition.mqh b/Task/TaskCondition.h similarity index 84% rename from Condition.mqh rename to Task/TaskCondition.h index 27183866b..194a5920d 100644 --- a/Condition.mqh +++ b/Task/TaskCondition.h @@ -26,28 +26,28 @@ */ // Prevents processing this includes file for the second time. -#ifndef CONDITION_MQH -#define CONDITION_MQH +#ifndef TASK_CONDITION_MQH +#define TASK_CONDITION_MQH // Includes. -#include "Account.mqh" -#include "Chart.mqh" -#include "DateTime.mqh" -#include "DictStruct.mqh" -#include "EA.mqh" -#include "Indicator.mqh" -#include "Market.mqh" -#include "Object.mqh" -#include "Order.mqh" +#include "../Account.mqh" +#include "../Chart.mqh" +#include "../DateTime.mqh" +#include "../DictStruct.mqh" +#include "../EA.mqh" +#include "../Indicator.mqh" +#include "../Market.mqh" +#include "../Object.mqh" +#include "../Order.mqh" // Includes class enum and structs. -#include "Condition.enum.h" -#include "Condition.struct.h" +#include "TaskCondition.enum.h" +#include "TaskCondition.struct.h" /** - * Condition class. + * TaskCondition class. */ -class Condition { +class TaskCondition { public: protected: // Class variables. @@ -55,31 +55,31 @@ class Condition { public: // Class variables. - DictStruct conds; + DictStruct conds; /* Special methods */ /** * Class constructor. */ - Condition() {} - Condition(ConditionEntry &_entry) { conds.Push(_entry); } - Condition(long _cond_id, ENUM_CONDITION_TYPE _type) { - ConditionEntry _entry(_cond_id, _type); + TaskCondition() {} + TaskCondition(TaskConditionEntry &_entry) { conds.Push(_entry); } + TaskCondition(long _cond_id, ENUM_TASK_CONDITION_TYPE _type) { + TaskConditionEntry _entry(_cond_id, _type); conds.Push(_entry); } template - Condition(T _cond_id, void *_obj = NULL) { - ConditionEntry _entry(_cond_id); + TaskCondition(T _cond_id, void *_obj = NULL) { + TaskConditionEntry _entry(_cond_id); if (_obj != NULL) { _entry.SetObject(_obj); } conds.Push(_entry); } template - Condition(T _cond_id, MqlParam &_args[], void *_obj = NULL) { + TaskCondition(T _cond_id, MqlParam &_args[], void *_obj = NULL) { Init(); - ConditionEntry _entry(_cond_id); + TaskConditionEntry _entry(_cond_id); _entry.SetArgs(_args); if (_obj != NULL) { _entry.SetObject(_obj); @@ -90,7 +90,7 @@ class Condition { /** * Class copy constructor. */ - Condition(Condition &_cond) { conds = _cond.GetConditions(); } + TaskCondition(TaskCondition &_cond) { conds = _cond.GetConditions(); } /* Main methods */ @@ -99,9 +99,9 @@ class Condition { */ bool Test() { bool _result = false, _prev_result = true; - for (DictStructIterator iter = conds.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator iter = conds.Begin(); iter.IsValid(); ++iter) { bool _curr_result = false; - ConditionEntry _entry = iter.Value(); + TaskConditionEntry _entry = iter.Value(); if (!_entry.IsValid()) { // Ignore invalid entries. continue; @@ -130,7 +130,7 @@ class Condition { /** * Test specific condition. */ - static bool Test(ConditionEntry &_entry) { + static bool Test(TaskConditionEntry &_entry) { bool _result = false; switch (_entry.type) { case COND_TYPE_ACCOUNT: @@ -260,8 +260,8 @@ class Condition { /** * Returns conditions. */ - DictStruct *GetConditions() { return &conds; } + DictStruct *GetConditions() { return &conds; } /* Setters */ }; -#endif // CONDITION_MQH +#endif // TASK_CONDITION_MQH diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h new file mode 100644 index 000000000..97b10383e --- /dev/null +++ b/Task/TaskCondition.struct.h @@ -0,0 +1,111 @@ +//+------------------------------------------------------------------+ +//| 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 Condition's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Account.enum.h" +#include "../Chart.enum.h" +#include "../DateTime.enum.h" +#include "../EA.enum.h" +#include "../Indicator.enum.h" +//#include "Market.enum.h" +#include "../Order.enum.h" +#include "../Strategy.enum.h" +#include "../Trade.enum.h" +#include "Task.enum.h" + +struct TaskConditionEntry { + unsigned char flags; // Condition flags. + datetime last_check; // Time of the latest check. + datetime last_success; // Time of the last success. + int frequency; // How often to check. + long cond_id; // Condition ID. + short tries; // Number of successful tries left. + void *obj; // Reference to associated object. + ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. + ENUM_TASK_CONDITION_TYPE type; // Task's condition type. + DataParamEntry args[]; // Task's condition arguments. + // Constructors. + void TaskConditionEntry() : type(FINAL_CONDITION_TYPE_ENTRY), cond_id(WRONG_VALUE) { Init(); } + void TaskConditionEntry(long _cond_id, ENUM_TASK_CONDITION_TYPE _type) : type(_type), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(TaskConditionEntry &_ce) { this = _ce; } + void TaskConditionEntry(ENUM_ACCOUNT_CONDITION _cond_id) : type(COND_TYPE_ACCOUNT), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_CHART_CONDITION _cond_id) : type(COND_TYPE_CHART), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_DATETIME_CONDITION _cond_id) : type(COND_TYPE_DATETIME), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_EA_CONDITION _cond_id) : type(COND_TYPE_EA), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_INDICATOR_CONDITION _cond_id) : type(COND_TYPE_INDICATOR), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_MARKET_CONDITION _cond_id) : type(COND_TYPE_MARKET), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_ORDER_CONDITION _cond_id) : type(COND_TYPE_ORDER), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_STRATEGY_CONDITION _cond_id) : type(COND_TYPE_STRATEGY), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_TASK_CONDITION _cond_id) : type(COND_TYPE_TASK), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_TRADE_CONDITION _cond_id) : type(COND_TYPE_TRADE), cond_id(_cond_id) { Init(); } + // Deconstructor. + void ~TaskConditionEntry() { + // Object::Delete(obj); + } + // Flag methods. + bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } + void AddFlags(unsigned char _flags) { flags |= _flags; } + void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void SetFlag(ENUM_TASK_CONDITION_ENTRY_FLAGS _flag, bool _value) { + if (_value) + AddFlags(_flag); + else + RemoveFlags(_flag); + } + void SetFlags(unsigned char _flags) { flags = _flags; } + // State methods. + bool IsActive() { return HasFlag(COND_ENTRY_FLAG_IS_ACTIVE); } + bool IsExpired() { return HasFlag(COND_ENTRY_FLAG_IS_EXPIRED); } + bool IsReady() { return HasFlag(COND_ENTRY_FLAG_IS_READY); } + bool IsInvalid() { return HasFlag(COND_ENTRY_FLAG_IS_INVALID); } + bool IsValid() { return !IsInvalid(); } + // Getters. + long GetId() { return cond_id; } + ENUM_TASK_CONDITION_TYPE GetType() { return type; } + // Setters. + void AddArg(MqlParam &_arg) { + // @todo: Add another value to args[]. + } + void Init() { + flags = COND_ENTRY_FLAG_NONE; + frequency = 60; + SetFlag(COND_ENTRY_FLAG_IS_ACTIVE, cond_id != WRONG_VALUE); + SetFlag(COND_ENTRY_FLAG_IS_INVALID, cond_id == WRONG_VALUE); + last_check = last_success = 0; + next_statement = COND_AND; + tries = 1; + } + void SetArgs(MqlParam &_args[]) { + // @todo: for(). + } + void SetObject(void *_obj) { obj = _obj; } + void SetTries(short _count) { tries = _count; } +}; diff --git a/Task/tests/Task.test.mq5 b/Task/tests/Task.test.mq5 index 34652fedc..f84783996 100644 --- a/Task/tests/Task.test.mq5 +++ b/Task/tests/Task.test.mq5 @@ -32,8 +32,8 @@ struct DataParamEntry; #include "../../Chart.mqh" #include "../../DictObject.mqh" #include "../../EA.mqh" -#include "../Task.h" #include "../../Test.mqh" +#include "../Task.h" // Global variables. Chart *chart; diff --git a/tests/ConditionTest.mq4 b/Task/tests/TaskCondition.test.mq4 similarity index 92% rename from tests/ConditionTest.mq4 rename to Task/tests/TaskCondition.test.mq4 index 89bff6caa..961feb86a 100644 --- a/tests/ConditionTest.mq4 +++ b/Task/tests/TaskCondition.test.mq4 @@ -21,8 +21,8 @@ /** * @file - * Test functionality of Condition class. + * Test functionality of TaskCondition class. */ // Includes. -#include "ConditionTest.mq5" +#include "TaskCondition.test.mq5" diff --git a/tests/ConditionTest.mq5 b/Task/tests/TaskCondition.test.mq5 similarity index 77% rename from tests/ConditionTest.mq5 rename to Task/tests/TaskCondition.test.mq5 index bb92cf89b..fd2d006f9 100644 --- a/tests/ConditionTest.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -21,21 +21,21 @@ /** * @file - * Test functionality of Condition class. + * Test functionality of TaskCondition class. */ // Forward declaration. struct DataParamEntry; // Includes. -#include "../Condition.mqh" -#include "../DictObject.mqh" -#include "../Indicators/Indi_Demo.mqh" -#include "../Test.mqh" +#include "../../DictObject.mqh" +#include "../../Indicators/Indi_Demo.mqh" +#include "../../Test.mqh" +#include "../TaskCondition.h" // Global variables. Chart *chart; -DictObject conds; +DictObject conds; int bar_processed; /** @@ -78,7 +78,7 @@ void OnDeinit(const int reason) { delete chart; } bool TestAccountConditions() { bool _result = true; Account *_acc = new Account(); - Condition *_cond = new Condition(ACCOUNT_COND_BAL_IN_LOSS); + TaskCondition *_cond = new TaskCondition(ACCOUNT_COND_BAL_IN_LOSS); assertTrueOrReturnFalse(_cond.Test() == _acc.CheckCondition(ACCOUNT_COND_BAL_IN_LOSS), "Wrong condition: ACCOUNT_COND_BAL_IN_LOSS!"); delete _cond; @@ -92,7 +92,7 @@ bool TestAccountConditions() { bool TestChartConditions() { bool _result = true; Chart *_chart = new Chart(); - Condition *_cond = new Condition(CHART_COND_ASK_BAR_PEAK, _chart); + TaskCondition *_cond = new TaskCondition(CHART_COND_ASK_BAR_PEAK, _chart); assertTrueOrReturnFalse(_cond.Test() == _chart.CheckCondition(CHART_COND_ASK_BAR_PEAK), "Wrong condition: CHART_COND_ASK_BAR_PEAK!"); delete _cond; @@ -106,11 +106,11 @@ bool TestChartConditions() { bool TestDateTimeConditions() { bool _result = true; DateTime *_dt = new DateTime(); - Condition *_cond1 = new Condition(DATETIME_COND_NEW_HOUR, _dt); + TaskCondition *_cond1 = new TaskCondition(DATETIME_COND_NEW_HOUR, _dt); assertTrueOrReturnFalse(_cond1.Test() == _dt.CheckCondition(DATETIME_COND_NEW_HOUR), "Wrong condition: DATETIME_COND_NEW_HOUR (dynamic)!"); delete _cond1; - Condition *_cond2 = new Condition(DATETIME_COND_NEW_HOUR); + TaskCondition *_cond2 = new TaskCondition(DATETIME_COND_NEW_HOUR); assertTrueOrReturnFalse(_cond2.Test() == DateTime::CheckCondition(DATETIME_COND_NEW_HOUR), "Wrong condition: DATETIME_COND_NEW_HOUR (static)!"); delete _cond2; @@ -126,22 +126,22 @@ bool TestIndicatorConditions() { Indi_Demo *_demo = new Indi_Demo(); /* @fixme assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_IS_MAX, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MAX), + (new TaskCondition(INDI_COND_ENTRY_IS_MAX, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MAX), "Wrong condition: INDI_COND_ENTRY_IS_MAX!"); assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_IS_MIN, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MIN), + (new TaskCondition(INDI_COND_ENTRY_IS_MIN, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MIN), "Wrong condition: INDI_COND_ENTRY_IS_MIN!"); assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_GT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_AVG), + (new TaskCondition(INDI_COND_ENTRY_GT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_AVG), "Wrong condition: INDI_COND_ENTRY_GT_AVG!"); assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_GT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_MED), + (new TaskCondition(INDI_COND_ENTRY_GT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_MED), "Wrong condition: INDI_COND_ENTRY_GT_MED!"); assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_LT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_AVG), + (new TaskCondition(INDI_COND_ENTRY_LT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_AVG), "Wrong condition: INDI_COND_ENTRY_LT_AVG!"); assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_LT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_MED), + (new TaskCondition(INDI_COND_ENTRY_LT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_MED), "Wrong condition: INDI_COND_ENTRY_LT_MED!"); */ delete _demo; @@ -154,7 +154,7 @@ bool TestIndicatorConditions() { bool TestMarketConditions() { bool _result = true; Market *_market = new Market(); - Condition *_cond = new Condition(MARKET_COND_IN_PEAK_HOURS, _market); + TaskCondition *_cond = new TaskCondition(MARKET_COND_IN_PEAK_HOURS, _market); assertTrueOrReturnFalse(_cond.Test() == _market.CheckCondition(MARKET_COND_IN_PEAK_HOURS), "Wrong condition: MARKET_COND_IN_PEAK_HOURS!"); delete _cond; @@ -186,7 +186,7 @@ bool TestOrderConditions() { bool TestTradeConditions() { bool _result = true; Trade *_trade = new Trade(); - Condition *_cond = new Condition(TRADE_COND_ALLOWED_NOT, _trade); + TaskCondition *_cond = new TaskCondition(TRADE_COND_ALLOWED_NOT, _trade); assertTrueOrReturnFalse(_cond.Test() == _trade.CheckCondition(TRADE_COND_ALLOWED_NOT), "Wrong condition: TRADE_COND_ALLOWED_NOT!"); delete _cond; diff --git a/Trade.mqh b/Trade.mqh index c19a1db9e..78877e5e7 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -33,13 +33,13 @@ class Trade; #include "Account.mqh" #include "Action.enum.h" #include "Chart.mqh" -#include "Condition.enum.h" #include "Convert.mqh" #include "DictStruct.mqh" #include "Math.h" #include "Object.mqh" #include "Order.mqh" #include "OrderQuery.h" +#include "Task/TaskCondition.enum.h" #include "Trade.enum.h" #include "Trade.struct.h" diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index 94171d422..aa40a93cb 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -33,7 +33,6 @@ #include "../BufferStruct.mqh" #include "../Chart.mqh" #include "../Collection.mqh" -#include "../Condition.mqh" #include "../Config.mqh" #include "../Convert.mqh" #include "../Database.mqh" @@ -56,6 +55,7 @@ #include "../Log.mqh" #include "../MD5.mqh" #include "../Storage/IValueStorage.h" +#include "../Task/TaskCondition.h" //#include "../MQL4.mqh" // @removeme //#include "../MQL5.mqh" // @removeme #include "../Mail.mqh" From 54d8c0abc1abaab607df942fd54570a86e907c4f Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 6 Oct 2021 15:45:18 +0100 Subject: [PATCH 03/84] Renames Action to TaskAction --- .github/workflows/test.yml | 1 - EA.mqh | 2 +- EA.struct.h | 2 +- Indicators/Indi_Drawer.mqh | 6 +- Order.mqh | 2 +- Task/Task.enum.h | 4 +- Task/Task.h | 8 +-- Task/Task.struct.h | 10 +-- Action.enum.h => Task/TaskAction.enum.h | 6 +- Action.mqh => Task/TaskAction.h | 62 +++++++++---------- Action.struct.h => Task/TaskAction.struct.h | 58 ++++++++--------- Task/TaskCondition.enum.h | 4 +- Task/tests/Task.test.mq5 | 3 +- .../tests/TaskAction.test.mq4 | 4 +- .../tests/TaskAction.test.mq5 | 16 ++--- Trade.mqh | 4 +- tests/CompileTest.mq5 | 2 +- 17 files changed, 97 insertions(+), 97 deletions(-) rename Action.enum.h => Task/TaskAction.enum.h (95%) rename Action.mqh => Task/TaskAction.h (84%) rename Action.struct.h => Task/TaskAction.struct.h (67%) rename tests/ActionTest.mq4 => Task/tests/TaskAction.test.mq4 (93%) rename tests/ActionTest.mq5 => Task/tests/TaskAction.test.mq5 (92%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d8b156bbd..297e43562 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -54,7 +54,6 @@ jobs: matrix: test: - AccountTest - - ActionTest - BufferStructTest - BufferTest - ChartTest diff --git a/EA.mqh b/EA.mqh index d94f61ea5..54aef90b3 100644 --- a/EA.mqh +++ b/EA.mqh @@ -30,7 +30,6 @@ #define EA_MQH // Includes. -#include "Action.enum.h" #include "Chart.mqh" #include "Data.struct.h" #include "Dict.mqh" @@ -46,6 +45,7 @@ #include "Strategy.mqh" #include "SummaryReport.mqh" #include "Task/Task.h" +#include "Task/TaskAction.enum.h" #include "Task/TaskCondition.enum.h" #include "Terminal.mqh" #include "Trade.mqh" diff --git a/EA.struct.h b/EA.struct.h index 115329e19..a750d2e11 100644 --- a/EA.struct.h +++ b/EA.struct.h @@ -222,7 +222,7 @@ struct EAProcessResult { /* Defines EA state variables. */ struct EAState { - unsigned short flags; // Action flags. + unsigned short flags; // TaskAction flags. unsigned int new_periods; // Started periods. DateTime last_updated; // Last updated. // Constructor. diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index d6f81854b..d5878da2e 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -24,10 +24,10 @@ struct IndicatorParams; // Includes. -#include "../Action.mqh" #include "../DictStruct.mqh" #include "../Indicator.mqh" #include "../Redis.mqh" +#include "../Task/TaskAction.h" #include "Indi_Drawer.struct.h" #include "Indi_Price.mqh" @@ -114,7 +114,7 @@ class Indi_Drawer : public Indicator { virtual void OnTick() { Indicator::OnTick(); - ActionEntry action(INDI_ACTION_SET_VALUE); + TaskActionEntry action(INDI_ACTION_SET_VALUE); ArrayResize(action.args, 3); action.args[0].type = TYPE_LONG; action.args[0].integer_value = GetBarTime(); @@ -141,7 +141,7 @@ class Indi_Drawer : public Indicator { Print("Got: ", message.Message); #endif if (message.Command == "message" && message.Channel == "INDICATOR_DRAW") { - ActionEntry action_entry; + TaskActionEntry action_entry; SerializerConverter::FromString(message.Message).ToObject(action_entry); ExecuteAction((ENUM_INDICATOR_ACTION)action_entry.action_id, action_entry.args); #ifdef __debug__ diff --git a/Order.mqh b/Order.mqh index 7cbba164b..38ad8d33f 100644 --- a/Order.mqh +++ b/Order.mqh @@ -30,7 +30,6 @@ #define ORDER_MQH // Includes. -#include "Action.enum.h" #include "Convert.mqh" #include "Data.define.h" #include "Data.struct.h" @@ -43,6 +42,7 @@ #include "Std.h" #include "String.mqh" #include "SymbolInfo.mqh" +#include "Task/TaskAction.enum.h" /* Defines for backward compatibility. */ diff --git a/Task/Task.enum.h b/Task/Task.enum.h index 0fcbc5b48..66b180b1f 100644 --- a/Task/Task.enum.h +++ b/Task/Task.enum.h @@ -30,14 +30,14 @@ #pragma once #endif -/* Structure for task actions for Action class. */ +/* Structure for task actions for TaskAction class. */ enum ENUM_TASK_ACTION { TASK_ACTION_NONE = 0, // Does nothing. TASK_ACTION_PROCESS, // Process tasks. FINAL_TASK_ACTION_ENTRY }; -/* Structure for task conditions for Action class. */ +/* Structure for task conditions for TaskAction class. */ enum ENUM_TASK_CONDITION { TASK_COND_NONE = 0, // Empty condition. TASK_COND_IS_ACTIVE, // Is active. diff --git a/Task/Task.h b/Task/Task.h index 2c41e2ead..4c5863a32 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -30,12 +30,12 @@ #define TASK_MQH // Includes. -#include "../Action.mqh" #include "../DictStruct.mqh" #include "../Refs.mqh" -#include "../Task/TaskCondition.h" #include "Task.enum.h" #include "Task.struct.h" +#include "TaskAction.h" +#include "TaskCondition.h" class Task { protected: @@ -99,8 +99,8 @@ class Task { bool _result = false; if (_entry.IsActive()) { if (TaskCondition::Test(_entry.GetCondition())) { - ActionEntry _action = _entry.GetAction(); - Action::Execute(_action); + TaskActionEntry _action = _entry.GetAction(); + TaskAction::Execute(_action); if (_action.IsDone()) { _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, _action.IsDone()); _entry.SetFlag(TASK_ENTRY_FLAG_IS_FAILED, _action.IsFailed()); diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 57b5d856c..4c9b328d0 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -31,20 +31,20 @@ #endif // Includes. -#include "../Action.struct.h" #include "Task.enum.h" +#include "TaskAction.struct.h" #include "TaskCondition.struct.h" struct TaskEntry { - ActionEntry action; // Action of the task. + TaskActionEntry action; // TaskAction of the task. TaskConditionEntry cond; // TaskCondition of the task. datetime expires; // Time of expiration. datetime last_process; // Time of the last process. datetime last_success; // Time of the last success. - unsigned char flags; // Action flags. + unsigned char flags; // TaskAction flags. // Constructors. void TaskEntry() { Init(); } - void TaskEntry(ActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } + void TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } void TaskEntry(long _aid, ENUM_ACTION_TYPE _atype, long _cid, ENUM_TASK_CONDITION_TYPE _ctype) : action(_aid, _atype), cond(_cid, _ctype) { Init(); @@ -79,7 +79,7 @@ struct TaskEntry { // Getters. long GetActionId() { return action.GetId(); } long GetConditionId() { return cond.GetId(); } - ActionEntry GetAction() { return action; } + TaskActionEntry GetAction() { return action; } TaskConditionEntry GetCondition() { return cond; } ENUM_ACTION_TYPE GetActionType() { return action.GetType(); } ENUM_TASK_CONDITION_TYPE GetConditionType() { return cond.GetType(); } diff --git a/Action.enum.h b/Task/TaskAction.enum.h similarity index 95% rename from Action.enum.h rename to Task/TaskAction.enum.h index 551ae44f7..ed6a40cb6 100644 --- a/Action.enum.h +++ b/Task/TaskAction.enum.h @@ -21,7 +21,7 @@ /** * @file - * Includes Action's enums. + * Includes TaskAction's enums. */ #ifndef __MQL__ @@ -45,7 +45,7 @@ enum ENUM_ACTION_ENTRY_FLAGS { /* Defines action types. */ enum ENUM_ACTION_TYPE { ACTION_TYPE_NONE = 0, // None. - ACTION_TYPE_ACTION, // Action of action. + ACTION_TYPE_ACTION, // TaskAction of action. ACTION_TYPE_EA, // EA action. ACTION_TYPE_INDICATOR, // Order action. ACTION_TYPE_ORDER, // Order action. @@ -56,7 +56,7 @@ enum ENUM_ACTION_TYPE { FINAL_ACTION_TYPE_ENTRY }; -/* Defines action types for Action class. */ +/* Defines action types for TaskAction class. */ enum ENUM_ACTION_ACTION { ACTION_ACTION_NONE = 0, // Does nothing. ACTION_ACTION_DISABLE, // Disables action. diff --git a/Action.mqh b/Task/TaskAction.h similarity index 84% rename from Action.mqh rename to Task/TaskAction.h index 2885da24c..15650d050 100644 --- a/Action.mqh +++ b/Task/TaskAction.h @@ -30,18 +30,18 @@ #define ACTION_MQH // Forward class declaration. -class Action; +class TaskAction; // Includes. -#include "Action.enum.h" -#include "Action.struct.h" -#include "EA.mqh" -#include "Task/TaskCondition.enum.h" +#include "../EA.mqh" +#include "TaskAction.enum.h" +#include "TaskAction.struct.h" +#include "TaskCondition.enum.h" /** - * Action class. + * TaskAction class. */ -class Action { +class TaskAction { public: protected: // Class variables. @@ -49,30 +49,30 @@ class Action { public: // Class variables. - DictStruct actions; + DictStruct actions; /* Special methods */ /** * Class constructor. */ - Action() {} - Action(ActionEntry &_entry) { actions.Push(_entry); } - Action(long _action_id, ENUM_ACTION_TYPE _type) { - ActionEntry _entry(_action_id, _type); + TaskAction() {} + TaskAction(TaskActionEntry &_entry) { actions.Push(_entry); } + TaskAction(long _action_id, ENUM_ACTION_TYPE _type) { + TaskActionEntry _entry(_action_id, _type); actions.Push(_entry); } template - Action(T _action_id, void *_obj = NULL) { - ActionEntry _entry(_action_id); + TaskAction(T _action_id, void *_obj = NULL) { + TaskActionEntry _entry(_action_id); if (_obj != NULL) { _entry.SetObject(_obj); } actions.Push(_entry); } template - Action(T _action_id, MqlParam &_args[], void *_obj = NULL) { - ActionEntry _entry(_action_id); + TaskAction(T _action_id, MqlParam &_args[], void *_obj = NULL) { + TaskActionEntry _entry(_action_id); _entry.SetArgs(_args); if (_obj != NULL) { _entry.SetObject(_obj); @@ -83,7 +83,7 @@ class Action { /** * Class copy constructor. */ - Action(Action &_cond) { actions = _cond.GetActions(); } + TaskAction(TaskAction &_cond) { actions = _cond.GetActions(); } /* Main methods */ @@ -92,9 +92,9 @@ class Action { */ bool Execute() { bool _result = true, _executed = false; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { bool _curr_result = false; - ActionEntry _entry = iter.Value(); + TaskActionEntry _entry = iter.Value(); if (!_entry.IsValid()) { // Ignore invalid entries. continue; @@ -109,12 +109,12 @@ class Action { /** * Execute specific action. */ - static bool Execute(ActionEntry &_entry) { + static bool Execute(TaskActionEntry &_entry) { bool _result = false; switch (_entry.type) { case ACTION_TYPE_ACTION: if (Object::IsValid(_entry.obj)) { - _result = ((Action *)_entry.obj).ExecuteAction((ENUM_ACTION_ACTION)_entry.action_id, _entry.args); + _result = ((TaskAction *)_entry.obj).ExecuteAction((ENUM_ACTION_ACTION)_entry.action_id, _entry.args); } else { _result = false; _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); @@ -247,15 +247,15 @@ class Action { /** * Returns actions. */ - DictStruct *GetActions() { return &actions; } + DictStruct *GetActions() { return &actions; } /** * Count entry flags. */ unsigned int GetFlagCount(ENUM_ACTION_ENTRY_FLAGS _flag) { unsigned int _counter = 0; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { - ActionEntry _entry = iter.Value(); + for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { + TaskActionEntry _entry = iter.Value(); if (_entry.HasFlag(_flag)) { _counter++; } @@ -270,8 +270,8 @@ class Action { */ bool SetFlags(ENUM_ACTION_ENTRY_FLAGS _flag, bool _value = true) { unsigned int _counter = 0; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { - ActionEntry _entry = iter.Value(); + for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { + TaskActionEntry _entry = iter.Value(); switch (_value) { case false: if (_entry.HasFlag(_flag)) { @@ -296,7 +296,7 @@ class Action { * Checks for Task condition. * * @param ENUM_ACTION_CONDITION _cond - * Action condition. + * TaskAction condition. * @return * Returns true when the condition is met. */ @@ -318,20 +318,20 @@ class Action { // Is invalid. return IsInvalid(); default: - logger.Ptr().Error(StringFormat("Invalid Action condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + logger.Ptr().Error(StringFormat("Invalid TaskAction condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); return false; } } bool CheckCondition(ENUM_ACTION_CONDITION _cond) { ARRAY(DataParamEntry, _args); - return Action::CheckCondition(_cond, _args); + return TaskAction::CheckCondition(_cond, _args); } /** * Execute action of action. * * @param ENUM_ACTION_ACTION _action - * Action of action to execute. + * TaskAction of action to execute. * @return * Returns true when the action has been executed successfully. */ @@ -364,7 +364,7 @@ class Action { } bool ExecuteAction(ENUM_ACTION_ACTION _action) { ARRAY(DataParamEntry, _args); - return Action::ExecuteAction(_action, _args); + return TaskAction::ExecuteAction(_action, _args); } /* Other methods */ diff --git a/Action.struct.h b/Task/TaskAction.struct.h similarity index 67% rename from Action.struct.h rename to Task/TaskAction.struct.h index 5d9d1d962..21434aa67 100644 --- a/Action.struct.h +++ b/Task/TaskAction.struct.h @@ -21,7 +21,7 @@ /** * @file - * Includes Action's structs. + * Includes TaskAction's structs. */ #ifndef __MQL__ @@ -30,41 +30,41 @@ #endif // Includes. -#include "Account.enum.h" -#include "Action.enum.h" -#include "Chart.enum.h" -#include "Data.struct.h" -#include "EA.enum.h" -#include "Indicator.enum.h" -//#include "Market.enum.h" -#include "Order.enum.h" -#include "Serializer.mqh" -#include "Strategy.enum.h" -#include "Task/Task.enum.h" -#include "Trade.enum.h" +#include "../Account.enum.h" +#include "../Chart.enum.h" +#include "../Data.struct.h" +#include "../EA.enum.h" +#include "../Indicator.enum.h" +#include "TaskAction.enum.h" +//#include "../Market.enum.h" +#include "../Order.enum.h" +#include "../Serializer.mqh" +#include "../Strategy.enum.h" +#include "../Trade.enum.h" +#include "Task.enum.h" -/* Entry for Action class. */ -struct ActionEntry { - unsigned char flags; /* Action flags. */ +/* Entry for TaskAction class. */ +struct TaskActionEntry { + unsigned char flags; /* TaskAction flags. */ datetime last_success; /* Time of the previous check. */ int frequency; /* How often to check. */ - long action_id; /* Action ID. */ + long action_id; /* TaskAction ID. */ short tries; /* Number of retries left. */ void *obj; /* Reference to associated object. */ - ENUM_ACTION_TYPE type; /* Action type. */ - DataParamEntry args[]; /* Action arguments. */ + ENUM_ACTION_TYPE type; /* TaskAction type. */ + DataParamEntry args[]; /* TaskAction arguments. */ // Constructors. - ActionEntry() : type(FINAL_ACTION_TYPE_ENTRY), action_id(WRONG_VALUE) { Init(); } - ActionEntry(long _action_id, ENUM_ACTION_TYPE _type) : type(_type), action_id(_action_id) { Init(); } - ActionEntry(ActionEntry &_ae) { this = _ae; } - ActionEntry(ENUM_EA_ACTION _action_id) : type(ACTION_TYPE_EA), action_id(_action_id) { Init(); } - ActionEntry(ENUM_ORDER_ACTION _action_id) : type(ACTION_TYPE_ORDER), action_id(_action_id) { Init(); } - ActionEntry(ENUM_INDICATOR_ACTION _action_id) : type(ACTION_TYPE_INDICATOR), action_id(_action_id) { Init(); } - ActionEntry(ENUM_STRATEGY_ACTION _action_id) : type(ACTION_TYPE_STRATEGY), action_id(_action_id) { Init(); } - ActionEntry(ENUM_TASK_ACTION _action_id) : type(ACTION_TYPE_TASK), action_id(_action_id) { Init(); } - ActionEntry(ENUM_TRADE_ACTION _action_id) : type(ACTION_TYPE_TRADE), action_id(_action_id) { Init(); } + TaskActionEntry() : type(FINAL_ACTION_TYPE_ENTRY), action_id(WRONG_VALUE) { Init(); } + TaskActionEntry(long _action_id, ENUM_ACTION_TYPE _type) : type(_type), action_id(_action_id) { Init(); } + TaskActionEntry(TaskActionEntry &_ae) { this = _ae; } + TaskActionEntry(ENUM_EA_ACTION _action_id) : type(ACTION_TYPE_EA), action_id(_action_id) { Init(); } + TaskActionEntry(ENUM_ORDER_ACTION _action_id) : type(ACTION_TYPE_ORDER), action_id(_action_id) { Init(); } + TaskActionEntry(ENUM_INDICATOR_ACTION _action_id) : type(ACTION_TYPE_INDICATOR), action_id(_action_id) { Init(); } + TaskActionEntry(ENUM_STRATEGY_ACTION _action_id) : type(ACTION_TYPE_STRATEGY), action_id(_action_id) { Init(); } + TaskActionEntry(ENUM_TASK_ACTION _action_id) : type(ACTION_TYPE_TASK), action_id(_action_id) { Init(); } + TaskActionEntry(ENUM_TRADE_ACTION _action_id) : type(ACTION_TYPE_TRADE), action_id(_action_id) { Init(); } // Deconstructor. - ~ActionEntry() { + ~TaskActionEntry() { // Object::Delete(obj); } // Flag methods. diff --git a/Task/TaskCondition.enum.h b/Task/TaskCondition.enum.h index 25faf93a4..13cb5542c 100644 --- a/Task/TaskCondition.enum.h +++ b/Task/TaskCondition.enum.h @@ -104,7 +104,7 @@ enum ENUM_TASK_CONDITION_STATEMENT { /* Defines condition types. */ enum ENUM_TASK_CONDITION_TYPE { COND_TYPE_ACCOUNT = 1, // Account condition. - COND_TYPE_ACTION, // Action condition. + COND_TYPE_ACTION, // TaskAction condition. COND_TYPE_CHART, // Chart condition. COND_TYPE_DATETIME, // Datetime condition. COND_TYPE_EA, // EA condition. @@ -164,7 +164,7 @@ enum ENUM_ACCOUNT_CONDITION { FINAL_ACCOUNT_CONDITION_ENTRY }; -/* Action conditions. */ +/* TaskAction conditions. */ enum ENUM_ACTION_CONDITION { ACTION_COND_NONE = 0, // Empty condition. ACTION_COND_IS_ACTIVE, // Is active. diff --git a/Task/tests/Task.test.mq5 b/Task/tests/Task.test.mq5 index f84783996..5b38c12df 100644 --- a/Task/tests/Task.test.mq5 +++ b/Task/tests/Task.test.mq5 @@ -28,10 +28,11 @@ struct DataParamEntry; // Includes. -#include "../../Action.mqh" #include "../../Chart.mqh" #include "../../DictObject.mqh" #include "../../EA.mqh" +#include "../TaskAction.h" +#include "../TaskCondition.h" #include "../../Test.mqh" #include "../Task.h" diff --git a/tests/ActionTest.mq4 b/Task/tests/TaskAction.test.mq4 similarity index 93% rename from tests/ActionTest.mq4 rename to Task/tests/TaskAction.test.mq4 index 5aba4100d..080ea3c49 100644 --- a/tests/ActionTest.mq4 +++ b/Task/tests/TaskAction.test.mq4 @@ -21,8 +21,8 @@ /** * @file - * Test functionality of Action class. + * Test functionality of TaskAction class. */ // Includes. -#include "ActionTest.mq5" +#include "TaskAction.test.mq5" diff --git a/tests/ActionTest.mq5 b/Task/tests/TaskAction.test.mq5 similarity index 92% rename from tests/ActionTest.mq5 rename to Task/tests/TaskAction.test.mq5 index f5a8ece2c..475530773 100644 --- a/tests/ActionTest.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -21,7 +21,7 @@ /** * @file - * Test functionality of Action class. + * Test functionality of TaskAction class. */ // Defines. @@ -31,15 +31,15 @@ struct DataParamEntry; // Includes. -#include "../Action.mqh" -#include "../DictObject.mqh" -#include "../EA.mqh" -#include "../Test.mqh" +#include "../../DictObject.mqh" +#include "../../EA.mqh" +#include "../../Test.mqh" +#include "../TaskAction.h" // Global variables. Chart *chart; EA *ea; -DictObject actions; +DictObject actions; // Define strategy classes. class Stg1 : public Strategy { @@ -79,12 +79,12 @@ int OnInit() { assertTrueOrReturnFalse(ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); #ifdef ACTION_EA_ENABLED // Disables EA and confirm it's disabled. - Action *action1 = new Action(EA_ACTION_DISABLE, ea); + TaskAction *action1 = new TaskAction(EA_ACTION_DISABLE, ea); action1.Execute(); assertTrueOrReturnFalse(!ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); delete action1; // Re-enables EA and confirm it's enabled. - Action *action2 = new Action(EA_ACTION_ENABLE, ea); + TaskAction *action2 = new TaskAction(EA_ACTION_ENABLE, ea); action2.Execute(); assertTrueOrReturnFalse(ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); delete action2; diff --git a/Trade.mqh b/Trade.mqh index 78877e5e7..d4ab21fa9 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -31,7 +31,6 @@ class Trade; // Includes. #include "Account.mqh" -#include "Action.enum.h" #include "Chart.mqh" #include "Convert.mqh" #include "DictStruct.mqh" @@ -39,6 +38,7 @@ class Trade; #include "Object.mqh" #include "Order.mqh" #include "OrderQuery.h" +#include "Task/TaskAction.enum.h" #include "Task/TaskCondition.enum.h" #include "Trade.enum.h" #include "Trade.struct.h" @@ -1810,7 +1810,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. return Trade::CheckCondition(_cond, _args); } - /* Actions */ + /* TaskActions */ /** * Execute trade action. diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index aa40a93cb..1f5648d64 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -26,8 +26,8 @@ // Includes. #include "../Account.mqh" -#include "../Action.mqh" #include "../Array.mqh" +#include "../Task/TaskAction.h" //#include "../BasicTrade.mqh" // @removeme #include "../Buffer.mqh" #include "../BufferStruct.mqh" From a2a642dfd7fa34705c344bb2ac2e1a25de46a905 Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 6 Oct 2021 19:30:39 +0100 Subject: [PATCH 04/84] TaskAction: Initial code refactor --- EA.mqh | 2 + EA.struct.h | 2 +- Indicators/Indi_Drawer.mqh | 6 +- Strategy.mqh | 2 + Task/Task.h | 2 + Task/Task.struct.h | 21 +-- Task/TaskAction.enum.h | 9 - Task/TaskAction.h | 330 ++++----------------------------- Task/TaskAction.struct.h | 154 +++++++++------ Task/TaskActionBase.h | 52 ++++++ Task/tests/Task.test.mq5 | 4 +- Task/tests/TaskAction.test.mq5 | 111 ++++------- tests/EATest.mq5 | 6 +- 13 files changed, 248 insertions(+), 453 deletions(-) create mode 100644 Task/TaskActionBase.h diff --git a/EA.mqh b/EA.mqh index 54aef90b3..e1ac8fff3 100644 --- a/EA.mqh +++ b/EA.mqh @@ -617,6 +617,7 @@ class EA { */ bool TaskAdd(TaskEntry &_entry) { bool _result = false; + /* @fixme if (_entry.IsValid()) { switch (_entry.GetConditionType()) { case COND_TYPE_ACCOUNT: @@ -639,6 +640,7 @@ class EA { } _result |= tasks.Push(_entry); } + */ return _result; } diff --git a/EA.struct.h b/EA.struct.h index a750d2e11..dca307294 100644 --- a/EA.struct.h +++ b/EA.struct.h @@ -195,7 +195,7 @@ struct EAParams { ver = _ver; author = _author; } - void SetTaskEntry(TaskEntry &_task_entry) { task_init = _task_entry; } + //void SetTaskEntry(TaskEntry &_task_entry) { task_init = _task_entry; } // Printers. string ToString(string _dlm = ",") { return StringFormat("%s v%s by %s (%s)", name, ver, author, desc); } }; diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index d5878da2e..fb8e22c2e 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -114,6 +114,7 @@ class Indi_Drawer : public Indicator { virtual void OnTick() { Indicator::OnTick(); + /* @fixme TaskActionEntry action(INDI_ACTION_SET_VALUE); ArrayResize(action.args, 3); action.args[0].type = TYPE_LONG; @@ -124,9 +125,11 @@ class Indi_Drawer : public Indicator { action.args[2].type = TYPE_DOUBLE; action.args[2].double_value = 1.25; + */ - string json = SerializerConverter::FromObject(action).ToString(/*SERIALIZER_JSON_NO_WHITESPACES*/); + //string json = SerializerConverter::FromObject(action).ToString(/*SERIALIZER_JSON_NO_WHITESPACES*/); + /* @fixme RedisMessage msg; msg.Add("message"); msg.Add("INDICATOR_DRAW"); @@ -151,6 +154,7 @@ class Indi_Drawer : public Indicator { // Drawing on the buffer. } } + */ } Redis *Redis() { return &redis; } diff --git a/Strategy.mqh b/Strategy.mqh index 3823f986f..e23a3adcb 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -238,12 +238,14 @@ class Strategy : public Object { */ void AddTask(TaskEntry &_entry) { if (_entry.IsValid()) { + /* @fixme if (_entry.GetAction().GetType() == ACTION_TYPE_STRATEGY) { _entry.SetActionObject(GetPointer(this)); } if (_entry.GetCondition().GetType() == COND_TYPE_STRATEGY) { _entry.SetConditionObject(GetPointer(this)); } + */ tasks.Push(_entry); } } diff --git a/Task/Task.h b/Task/Task.h index 4c5863a32..cec38d381 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -97,6 +97,7 @@ class Task { */ static bool Process(TaskEntry &_entry) { bool _result = false; + /* @fixme if (_entry.IsActive()) { if (TaskCondition::Test(_entry.GetCondition())) { TaskActionEntry _action = _entry.GetAction(); @@ -111,6 +112,7 @@ class Task { _entry.last_process = TimeCurrent(); _result = true; } + */ return _result; } diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 4c9b328d0..15ec0aac9 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -45,13 +45,8 @@ struct TaskEntry { // Constructors. void TaskEntry() { Init(); } void TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } - void TaskEntry(long _aid, ENUM_ACTION_TYPE _atype, long _cid, ENUM_TASK_CONDITION_TYPE _ctype) - : action(_aid, _atype), cond(_cid, _ctype) { - Init(); - } template - void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { - Init(); + void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { : action(_aid, _atype), cond(_cid, _ctype){Init()}; } // Main methods. void Init() { @@ -72,18 +67,16 @@ struct TaskEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - bool IsActive() { return HasFlag(ACTION_ENTRY_FLAG_IS_ACTIVE); } - bool IsDone() { return HasFlag(ACTION_ENTRY_FLAG_IS_DONE); } - bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); } - bool IsValid() { return !HasFlag(ACTION_ENTRY_FLAG_IS_INVALID); } + // bool IsActive() { return HasFlag(ACTION_ENTRY_FLAG_IS_ACTIVE); } + // bool IsDone() { return HasFlag(ACTION_ENTRY_FLAG_IS_DONE); } + // bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); } + bool IsValid() { return action.IsValid() && cond.IsValid(); } // Getters. long GetActionId() { return action.GetId(); } long GetConditionId() { return cond.GetId(); } TaskActionEntry GetAction() { return action; } TaskConditionEntry GetCondition() { return cond; } - ENUM_ACTION_TYPE GetActionType() { return action.GetType(); } - ENUM_TASK_CONDITION_TYPE GetConditionType() { return cond.GetType(); } // Setters. - void SetActionObject(void *_obj) { action.SetObject(_obj); } - void SetConditionObject(void *_obj) { cond.SetObject(_obj); } + // void SetActionObject(void *_obj) { action.SetObject(_obj); } + // void SetConditionObject(void *_obj) { cond.SetObject(_obj); } }; diff --git a/Task/TaskAction.enum.h b/Task/TaskAction.enum.h index ed6a40cb6..3756722ea 100644 --- a/Task/TaskAction.enum.h +++ b/Task/TaskAction.enum.h @@ -33,15 +33,6 @@ #ifndef ACTION_ENUM_H #define ACTION_ENUM_H -/* Defines action entry flags. */ -enum ENUM_ACTION_ENTRY_FLAGS { - ACTION_ENTRY_FLAG_NONE = 0, - ACTION_ENTRY_FLAG_IS_ACTIVE = 1, - ACTION_ENTRY_FLAG_IS_DONE = 2, - ACTION_ENTRY_FLAG_IS_FAILED = 4, - ACTION_ENTRY_FLAG_IS_INVALID = 8 -}; - /* Defines action types. */ enum ENUM_ACTION_TYPE { ACTION_TYPE_NONE = 0, // None. diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 15650d050..859544eec 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -26,30 +26,22 @@ */ // Prevents processing this includes file for the second time. -#ifndef ACTION_MQH -#define ACTION_MQH - -// Forward class declaration. -class TaskAction; +#ifndef TASK_ACTION_MQH +#define TASK_ACTION_MQH // Includes. -#include "../EA.mqh" #include "TaskAction.enum.h" #include "TaskAction.struct.h" -#include "TaskCondition.enum.h" /** * TaskAction class. */ -class TaskAction { - public: - protected: - // Class variables. - Ref logger; - +template +class TaskAction : TaskActionBase { public: // Class variables. - DictStruct actions; + TaskActionEntry entry; // Action entry. + TO obj; // Object to run the action on. /* Special methods */ @@ -57,317 +49,67 @@ class TaskAction { * Class constructor. */ TaskAction() {} - TaskAction(TaskActionEntry &_entry) { actions.Push(_entry); } - TaskAction(long _action_id, ENUM_ACTION_TYPE _type) { - TaskActionEntry _entry(_action_id, _type); - actions.Push(_entry); - } - template - TaskAction(T _action_id, void *_obj = NULL) { - TaskActionEntry _entry(_action_id); - if (_obj != NULL) { - _entry.SetObject(_obj); - } - actions.Push(_entry); - } - template - TaskAction(T _action_id, MqlParam &_args[], void *_obj = NULL) { - TaskActionEntry _entry(_action_id); - _entry.SetArgs(_args); - if (_obj != NULL) { - _entry.SetObject(_obj); - } - actions.Push(_entry); - } - - /** - * Class copy constructor. - */ - TaskAction(TaskAction &_cond) { actions = _cond.GetActions(); } + TaskAction(TaskActionEntry &_entry) : entry(_entry) {} /* Main methods */ /** - * Execute actions. - */ - bool Execute() { - bool _result = true, _executed = false; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { - bool _curr_result = false; - TaskActionEntry _entry = iter.Value(); - if (!_entry.IsValid()) { - // Ignore invalid entries. - continue; - } - if (_entry.IsActive()) { - _executed = _result &= Execute(_entry); - } - } - return _result && _executed; - } - - /** - * Execute specific action. + * Runs an action. */ - static bool Execute(TaskActionEntry &_entry) { - bool _result = false; - switch (_entry.type) { - case ACTION_TYPE_ACTION: - if (Object::IsValid(_entry.obj)) { - _result = ((TaskAction *)_entry.obj).ExecuteAction((ENUM_ACTION_ACTION)_entry.action_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; - case ACTION_TYPE_EA: - if (Object::IsValid(_entry.obj)) { - _result = ((EA *)_entry.obj).ExecuteAction((ENUM_EA_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#ifdef ORDER_MQH - case ACTION_TYPE_ORDER: - if (Object::IsValid(_entry.obj)) { - _result = ((Order *)_entry.obj).ExecuteAction((ENUM_ORDER_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#endif -#ifdef INDICATOR_MQH - case ACTION_TYPE_INDICATOR: - if (Object::IsValid(_entry.obj)) { - _result = ((Indicator *)_entry.obj).ExecuteAction((ENUM_INDICATOR_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#endif -#ifdef STRATEGY_MQH - case ACTION_TYPE_STRATEGY: - if (Object::IsValid(_entry.obj)) { - _result = ((Strategy *)_entry.obj).ExecuteAction((ENUM_STRATEGY_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#endif -#ifdef TASK_MQH - case ACTION_TYPE_TASK: - if (Object::IsValid(_entry.obj)) { - _result = ((Task *)_entry.obj).ExecuteAction((ENUM_TASK_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#endif - case ACTION_TYPE_TRADE: - if (Object::IsValid(_entry.obj)) { - _result = ((Trade *)_entry.obj).ExecuteAction((ENUM_TRADE_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#ifdef TERMINAL_MQH - case ACTION_TYPE_TERMINAL: - if (Object::IsValid(_entry.obj)) { - _result = ((Terminal *)_entry.obj).ExecuteAction((ENUM_TERMINAL_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#endif - } + bool Run() { + bool _result = entry.IsValid() && entry.HasTriesLeft(); + _result &= obj.Run(entry); if (_result) { - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_DONE); - _entry.RemoveFlags(ACTION_ENTRY_FLAG_IS_ACTIVE); - _entry.last_success = TimeCurrent(); + entry.TriesDec(); + entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE)); + entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); + entry.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_TIME_LAST_RUN), TimeCurrent()); } else { - if (--_entry.tries <= 0) { - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - _entry.RemoveFlags(ACTION_ENTRY_FLAG_IS_ACTIVE); + entry.TriesDec(); + if (!entry.HasTriesLeft()) { + entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID)); + entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); } } return _result; } - /* State methods */ - - /** - * Check if action is active. - */ - bool IsActive() { - // The whole action is active when at least one action is active. - return GetFlagCount(ACTION_ENTRY_FLAG_IS_ACTIVE) > 0; - } - - /** - * Check if action is done. - */ - bool IsDone() { - // The whole action is done when all actions has been executed successfully. - return GetFlagCount(ACTION_ENTRY_FLAG_IS_DONE) == actions.Size(); - } - - /** - * Check if action has failed. - */ - bool IsFailed() { - // The whole action is failed when at least one action failed. - return GetFlagCount(ACTION_ENTRY_FLAG_IS_FAILED) > 0; - } - - /** - * Check if action is finished. - */ - bool IsFinished() { - // The whole action is finished when there are no more active actions. - return GetFlagCount(ACTION_ENTRY_FLAG_IS_ACTIVE) == 0; - } - - /** - * Check if action is invalid. - */ - bool IsInvalid() { - // The whole action is invalid when at least one action is invalid. - return GetFlagCount(ACTION_ENTRY_FLAG_IS_INVALID) > 0; - } - /* Getters */ /** - * Returns actions. + * Gets an entry's flag. */ - DictStruct *GetActions() { return &actions; } + bool Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag) const { return entry.Get(_flag); } /** - * Count entry flags. + * Gets an entry's property value. */ - unsigned int GetFlagCount(ENUM_ACTION_ENTRY_FLAGS _flag) { - unsigned int _counter = 0; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { - TaskActionEntry _entry = iter.Value(); - if (_entry.HasFlag(_flag)) { - _counter++; - } - } - return _counter; + template + T Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop) const { + entry.Get(_prop); } - /* Setters */ - /** - * Sets entry flags. + * Gets an reference to the object. */ - bool SetFlags(ENUM_ACTION_ENTRY_FLAGS _flag, bool _value = true) { - unsigned int _counter = 0; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { - TaskActionEntry _entry = iter.Value(); - switch (_value) { - case false: - if (_entry.HasFlag(_flag)) { - _entry.SetFlag(_flag, _value); - _counter++; - } - break; - case true: - if (!_entry.HasFlag(_flag)) { - _entry.SetFlag(_flag, _value); - _counter++; - } - break; - } - } - return _counter > 0; - } + TO *GetObject() { return GetPointer(obj); } - /* Conditions and actions */ + /* Setters */ /** - * Checks for Task condition. - * - * @param ENUM_ACTION_CONDITION _cond - * TaskAction condition. - * @return - * Returns true when the condition is met. + * Sets an entry's flag. */ - bool CheckCondition(ENUM_ACTION_CONDITION _cond, DataParamEntry &_args[]) { - switch (_cond) { - case ACTION_COND_IS_ACTIVE: - // Is active; - return IsActive(); - case ACTION_COND_IS_DONE: - // Is done. - return IsDone(); - case ACTION_COND_IS_FAILED: - // Is failed. - return IsFailed(); - case ACTION_COND_IS_FINISHED: - // Is finished. - return IsFinished(); - case ACTION_COND_IS_INVALID: - // Is invalid. - return IsInvalid(); - default: - logger.Ptr().Error(StringFormat("Invalid TaskAction condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - return false; - } - } - bool CheckCondition(ENUM_ACTION_CONDITION _cond) { - ARRAY(DataParamEntry, _args); - return TaskAction::CheckCondition(_cond, _args); + void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value = true) { + entry.Set(_flag, _value); } /** - * Execute action of action. - * - * @param ENUM_ACTION_ACTION _action - * TaskAction of action to execute. - * @return - * Returns true when the action has been executed successfully. + * Sets an entry's property value. */ - bool ExecuteAction(ENUM_ACTION_ACTION _action, DataParamEntry &_args[]) { - bool _result = true; - switch (_action) { - case ACTION_ACTION_DISABLE: - // Disable action. - return SetFlags(ACTION_ENTRY_FLAG_IS_ACTIVE, false); - case ACTION_ACTION_EXECUTE: - // Execute action. - return Execute(); - case ACTION_ACTION_MARK_AS_DONE: - // Marks as done. - return SetFlags(ACTION_ENTRY_FLAG_IS_DONE); - case ACTION_ACTION_MARK_AS_FAILED: - // Mark as failed. - return SetFlags(ACTION_ENTRY_FLAG_IS_FAILED); - case ACTION_ACTION_MARK_AS_FINISHED: - // Mark as finished. - return SetFlags(ACTION_ENTRY_FLAG_IS_ACTIVE, false); - case ACTION_ACTION_MARK_AS_INVALID: - // Mark as invalid. - return SetFlags(ACTION_ENTRY_FLAG_IS_INVALID); - default: - logger.Ptr().Error(StringFormat("Invalid action of action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - return false; - } - return _result; - } - bool ExecuteAction(ENUM_ACTION_ACTION _action) { - ARRAY(DataParamEntry, _args); - return TaskAction::ExecuteAction(_action, _args); + template + void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop, T _value) { + entry.Set(_prop, _value); } - - /* Other methods */ }; -#endif // ACTION_MQH +#endif // TASK_ACTION_MQH diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 21434aa67..7c7d08138 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -30,88 +30,126 @@ #endif // Includes. -#include "../Account.enum.h" -#include "../Chart.enum.h" #include "../Data.struct.h" -#include "../EA.enum.h" -#include "../Indicator.enum.h" -#include "TaskAction.enum.h" -//#include "../Market.enum.h" -#include "../Order.enum.h" -#include "../Serializer.mqh" -#include "../Strategy.enum.h" -#include "../Trade.enum.h" +#include "../Std.h" #include "Task.enum.h" /* Entry for TaskAction class. */ struct TaskActionEntry { - unsigned char flags; /* TaskAction flags. */ - datetime last_success; /* Time of the previous check. */ - int frequency; /* How often to check. */ - long action_id; /* TaskAction ID. */ - short tries; /* Number of retries left. */ - void *obj; /* Reference to associated object. */ - ENUM_ACTION_TYPE type; /* TaskAction type. */ - DataParamEntry args[]; /* TaskAction arguments. */ + public: + // Defines enumerations. + enum ENUM_TASK_ACTION_ENTRY_PROP { + TASK_ACTION_ENTRY_FLAGS, + TASK_ACTION_ENTRY_FREQUENCY, + TASK_ACTION_ENTRY_ID, + TASK_ACTION_ENTRY_TRIES, + TASK_ACTION_ENTRY_TIME_LAST_RUN, + }; + /* Defines action entry flags. */ + enum ENUM_TASK_ACTION_ENTRY_FLAG { + TASK_ACTION_ENTRY_FLAG_NONE = 0 << 0, + TASK_ACTION_ENTRY_FLAG_IS_ACTIVE = 1 << 0, + TASK_ACTION_ENTRY_FLAG_IS_DONE = 1 << 1, + TASK_ACTION_ENTRY_FLAG_IS_FAILED = 1 << 2, + TASK_ACTION_ENTRY_FLAG_IS_INVALID = 1 << 3, + }; + + protected: + unsigned char flags; /* TaskAction flags. */ + datetime time_last_run; /* Time of the successful run. */ + int freq; /* How often to run (0 for no limit). */ + long id; /* TaskAction's enum ID. */ + short tries; /* Number of retries left. */ + DataParamEntry args[]; /* TaskAction arguments. */ + public: // Constructors. - TaskActionEntry() : type(FINAL_ACTION_TYPE_ENTRY), action_id(WRONG_VALUE) { Init(); } - TaskActionEntry(long _action_id, ENUM_ACTION_TYPE _type) : type(_type), action_id(_action_id) { Init(); } + TaskActionEntry() : flags(0), freq(0), id(WRONG_VALUE), time_last_run(0), tries(0) {} + TaskActionEntry(long _id) + : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), id(_id), time_last_run(0), tries(0) {} TaskActionEntry(TaskActionEntry &_ae) { this = _ae; } - TaskActionEntry(ENUM_EA_ACTION _action_id) : type(ACTION_TYPE_EA), action_id(_action_id) { Init(); } - TaskActionEntry(ENUM_ORDER_ACTION _action_id) : type(ACTION_TYPE_ORDER), action_id(_action_id) { Init(); } - TaskActionEntry(ENUM_INDICATOR_ACTION _action_id) : type(ACTION_TYPE_INDICATOR), action_id(_action_id) { Init(); } - TaskActionEntry(ENUM_STRATEGY_ACTION _action_id) : type(ACTION_TYPE_STRATEGY), action_id(_action_id) { Init(); } - TaskActionEntry(ENUM_TASK_ACTION _action_id) : type(ACTION_TYPE_TASK), action_id(_action_id) { Init(); } - TaskActionEntry(ENUM_TRADE_ACTION _action_id) : type(ACTION_TYPE_TRADE), action_id(_action_id) { Init(); } - // Deconstructor. - ~TaskActionEntry() { - // Object::Delete(obj); - } // Flag methods. - bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } + bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } - void SetFlag(ENUM_ACTION_ENTRY_FLAGS _flag, bool _value) { - if (_value) + void SetFlag(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value) { + if (_value) { AddFlags(_flag); - else + } else { RemoveFlags(_flag); + } } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - bool IsActive() { return HasFlag(ACTION_ENTRY_FLAG_IS_ACTIVE); } - bool IsDone() { return HasFlag(ACTION_ENTRY_FLAG_IS_DONE); } - bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); } - bool IsInvalid() { return HasFlag(ACTION_ENTRY_FLAG_IS_INVALID); } - bool IsValid() { return !IsInvalid(); } + bool HasTriesLeft() const { return tries > 0; } + bool IsActive() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); } + bool IsDone() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE)); } + bool IsFailed() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_FAILED)); } + bool IsInvalid() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID)); } + bool IsValid() const { return !IsInvalid(); } // Getters. - long GetId() { return action_id; } - ENUM_ACTION_TYPE GetType() { return type; } - // Setter methods. + bool Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag) const { return HasFlag(_flag); } + template + T Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop) const { + switch (_prop) { + case TASK_ACTION_ENTRY_FLAGS: + return (T)flags; + case TASK_ACTION_ENTRY_FREQUENCY: + return (T)freq; + case TASK_ACTION_ENTRY_ID: + return (T)id; + case TASK_ACTION_ENTRY_TRIES: + return (T)tries; + case TASK_ACTION_ENTRY_TIME_LAST_RUN: + return (T)time_last_run; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + long GetId() const { return id; } + // Setters. + void TriesDec() { tries--; } + void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value = true) { + SetFlag(_flag, _value); + } + template + void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop, T _value) { + switch (_prop) { + case TASK_ACTION_ENTRY_FLAGS: // ID (magic number). + flags = (unsigned char)_value; + return; + case TASK_ACTION_ENTRY_FREQUENCY: + freq = (int)_value; + return; + case TASK_ACTION_ENTRY_ID: + id = (long)_value; + SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + return; + case TASK_ACTION_ENTRY_TRIES: + tries = (short)_value; + return; + case TASK_ACTION_ENTRY_TIME_LAST_RUN: + time_last_run = (datetime)_value; + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + } void AddArg(MqlParam &_arg) { // @todo: Add another value to args[]. } - void Init() { - flags = ACTION_ENTRY_FLAG_NONE; - frequency = 60; - SetFlag(ACTION_ENTRY_FLAG_IS_ACTIVE, action_id != WRONG_VALUE); - SetFlag(ACTION_ENTRY_FLAG_IS_INVALID, action_id == WRONG_VALUE); - last_success = 0; - tries = 1; - } void SetArgs(ARRAY_REF(MqlParam, _args)) { // @todo: for(). } - void SetObject(void *_obj) { obj = _obj; } - void SetTries(short _count) { tries = _count; } - + // Serializers SerializerNodeType Serialize(Serializer &s) { s.Pass(THIS_REF, "flags", flags); - s.Pass(THIS_REF, "last_success", last_success); - s.Pass(THIS_REF, "action_id", action_id); - // s.Pass(THIS_REF, "tries", tries); - s.PassEnum(THIS_REF, "type", type); - s.PassEnum(THIS_REF, "frequency", frequency); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "time_last_run", time_last_run); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); s.PassArray(this, "args", args); return SerializerNodeObject; } diff --git a/Task/TaskActionBase.h b/Task/TaskActionBase.h new file mode 100644 index 000000000..3b4a6ed9a --- /dev/null +++ b/Task/TaskActionBase.h @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides a base class for a task's action. + */ + +// Prevents processing this includes file for the second time. +#ifndef TASK_ACTION_BASE_MQH +#define TASK_ACTION_BASE_MQH + +/** + * TaskActionBase class. + */ +class TaskActionBase { + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskActionBase() {} + + /* Main methods */ + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry); +}; + +#endif // TASK_ACTION_BASE_MQH diff --git a/Task/tests/Task.test.mq5 b/Task/tests/Task.test.mq5 index 5b38c12df..31be5230c 100644 --- a/Task/tests/Task.test.mq5 +++ b/Task/tests/Task.test.mq5 @@ -31,10 +31,10 @@ struct DataParamEntry; #include "../../Chart.mqh" #include "../../DictObject.mqh" #include "../../EA.mqh" -#include "../TaskAction.h" -#include "../TaskCondition.h" #include "../../Test.mqh" #include "../Task.h" +#include "../TaskAction.h" +#include "../TaskCondition.h" // Global variables. Chart *chart; diff --git a/Task/tests/TaskAction.test.mq5 b/Task/tests/TaskAction.test.mq5 index 475530773..3b7d3dec5 100644 --- a/Task/tests/TaskAction.test.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -24,40 +24,42 @@ * Test functionality of TaskAction class. */ -// Defines. -#define ACTION_EA_ENABLED - -// Forward declaration. -struct DataParamEntry; - // Includes. -#include "../../DictObject.mqh" -#include "../../EA.mqh" #include "../../Test.mqh" #include "../TaskAction.h" +#include "../TaskActionBase.h" + +enum ENUM_TASK_ACTION_TEST { + TASK_ACTION_TEST01 = 1, + TASK_ACTION_TEST02 = 2, + TASK_ACTION_TEST03 = 3, +}; -// Global variables. -Chart *chart; -EA *ea; -DictObject actions; +class TaskActionTest01 : public TaskActionBase { + protected: + long sum; -// Define strategy classes. -class Stg1 : public Strategy { public: - void Stg1(StgParams &_params, TradeParams &_tparams, ChartParams &_cparams, string _name = "Stg1") - : Strategy(_params, _tparams, _cparams, _name) {} - static Stg1 *Init(ENUM_TIMEFRAMES _tf = NULL, unsigned long _magic_no = 0, ENUM_LOG_LEVEL _log_level = V_INFO) { - ChartParams _cparams(_tf); - TradeParams _tparams(_magic_no, _log_level); - Strategy *_strat = new Stg1(stg_params_defaults, _tparams, _cparams, __FUNCTION__); - return _strat; + TaskActionTest01() : sum(0){}; + long GetSum() { return sum; } + bool Run(const TaskActionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); + return true; } - bool SignalOpen(ENUM_ORDER_TYPE _cmd, int _method, float _level, int _shift) { return true; } - bool SignalOpenFilterMethod(ENUM_ORDER_TYPE _cmd, int _method = 0) { return true; } - float SignalOpenBoost(ENUM_ORDER_TYPE _cmd, int _method = 0) { return 1.0; } - bool SignalClose(ENUM_ORDER_TYPE _cmd, int _method, float _level, int _shift) { return true; } - float PriceStop(ENUM_ORDER_TYPE _cmd, ENUM_ORDER_TYPE_VALUE _mode, int _method = 0, float _level = 0.0f) { - return _level; +}; + +class TaskActionTest02 : public TaskActionBase { + protected: + long sum; + + public: + TaskActionTest02() : sum(0){}; + long GetSum() { return sum; } + bool Run(const TaskActionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); + return true; } }; @@ -66,58 +68,25 @@ class Stg1 : public Strategy { */ int OnInit() { bool _result = true; - // Initializes chart. - chart = new Chart(); - // Initializes EA. - EAParams ea_params(__FILE__); - ea = new EA(ea_params); - _result &= ea.StrategyAdd(127); - // Check asserts. - // Confirm EA is active. - assertTrueOrReturnFalse(ea.CheckCondition(EA_COND_IS_ACTIVE), "Wrong condition: EA_COND_IS_ACTIVE!"); - // Confirm EA is enabled. - assertTrueOrReturnFalse(ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); -#ifdef ACTION_EA_ENABLED - // Disables EA and confirm it's disabled. - TaskAction *action1 = new TaskAction(EA_ACTION_DISABLE, ea); - action1.Execute(); - assertTrueOrReturnFalse(!ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); - delete action1; - // Re-enables EA and confirm it's enabled. - TaskAction *action2 = new TaskAction(EA_ACTION_ENABLE, ea); - action2.Execute(); - assertTrueOrReturnFalse(ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); - delete action2; -#endif + // Test01 + TaskActionEntry _entry01(TASK_ACTION_TEST01); + TaskAction _action01(_entry01); + _action01.Run(); + _action01.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST02); + _action01.Run(); + _action01.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST03); + _action01.Run(); + assertTrueOrFail(_action01.GetObject().GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; - return (_result ? INIT_SUCCEEDED : INIT_FAILED); } /** * Implements Tick event handler. */ -void OnTick() { - chart.OnTick(); - if (chart.IsNewBar()) { - unsigned int _bar_index = chart.GetBarIndex(); - switch (_bar_index) { - case 1: - break; - case 2: - break; - case 3: - break; - case 4: - break; - } - } -} +void OnTick() {} /** * Implements Deinit event handler. */ -void OnDeinit(const int reason) { - delete chart; - delete ea; -} +void OnDeinit(const int reason) {} diff --git a/tests/EATest.mq5 b/tests/EATest.mq5 index 31d11e524..176be0a21 100644 --- a/tests/EATest.mq5 +++ b/tests/EATest.mq5 @@ -59,7 +59,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - ea_params.SetTaskEntry(_task_export_per_hour); + //ea_params.SetTaskEntry(_task_export_per_hour); ea = new EA(ea_params); assertTrueOrFail(ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA", StringFormat("Invalid EA name: %s!", ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)))); @@ -69,7 +69,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params1.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params1.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - ea_params1.SetTaskEntry(_task_export_per_hour); + //ea_params1.SetTaskEntry(_task_export_per_hour); ea1 = new EA1(ea_params1); assertTrueOrFail(ea1.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA1", "Invalid EA1 name!"); @@ -78,7 +78,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params2.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params2.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - ea_params2.SetTaskEntry(_task_export_per_hour); + //ea_params2.SetTaskEntry(_task_export_per_hour); ea2 = new EA2(ea_params2); assertTrueOrFail(ea2.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA2", "Invalid EA2 name!"); From 02232347f72a8767f2a59487efba8a217d8caa00 Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 6 Oct 2021 19:34:25 +0100 Subject: [PATCH 05/84] GHA: Adds tests for Task-related classes --- .github/workflows/test-task.yml | 61 +++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/test-task.yml diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml new file mode 100644 index 000000000..36ed3cbf9 --- /dev/null +++ b/.github/workflows/test-task.yml @@ -0,0 +1,61 @@ +--- +name: Test Task + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Task/**.h' + - '.github/workflows/test-task.yml' + push: + paths: + - 'Task/**.h' + - '.github/workflows/test-task.yml' + +jobs: + + Compile: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Compile + uses: fx31337/mql-compile-action@master + with: + init-platform: true + path: 'Task/tests' + verbose: true + - name: Print compiled files + run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname' + shell: powershell + - name: Upload artifacts (MQL4) + uses: actions/upload-artifact@v2 + with: + name: files-ex4 + path: '**/*.ex4' + - name: Upload artifacts (MQL5) + uses: actions/upload-artifact@v2 + with: + name: files-ex5 + path: '**/*.ex5' + + Task-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Task/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - Task.test + - TaskAction.test + - TaskCondition.test + steps: + - uses: actions/download-artifact@v2 + with: + name: files-ex4 + - name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + Script: ${{ matrix.test }} From a8ebb4a64f882b8a48414fa2c5be1f7d6159dbf5 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 24 Oct 2021 20:41:08 +0100 Subject: [PATCH 06/84] TaskCondition: Code refactor --- Task/Task.h | 11 +- Task/Task.struct.h | 5 +- Task/TaskAction.h | 43 ++++-- Task/TaskAction.struct.h | 20 ++- Task/TaskActionBase.h | 13 +- Task/TaskCondition.enum.h | 9 -- Task/TaskCondition.h | 222 +++++++++--------------------- Task/TaskCondition.struct.h | 142 ++++++++++++++----- Task/TaskConditionBase.h | 57 ++++++++ Task/tests/TaskCondition.test.mq5 | 197 +++++++------------------- 10 files changed, 340 insertions(+), 379 deletions(-) create mode 100644 Task/TaskConditionBase.h diff --git a/Task/Task.h b/Task/Task.h index cec38d381..d6a718f02 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -25,9 +25,14 @@ * Provides integration with tasks (manages conditions and actions). */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Prevents processing this includes file for the second time. -#ifndef TASK_MQH -#define TASK_MQH +#ifndef TASK_H +#define TASK_H // Includes. #include "../DictStruct.mqh" @@ -270,4 +275,4 @@ class Task { /* Other methods */ }; -#endif // TASK_MQH +#endif // TASK_H diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 15ec0aac9..82e7b6684 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -46,8 +46,9 @@ struct TaskEntry { void TaskEntry() { Init(); } void TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } template - void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { : action(_aid, _atype), cond(_cid, _ctype){Init()}; - } + void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { + Init(); + }; // Main methods. void Init() { flags = TASK_ENTRY_FLAG_NONE; diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 859544eec..56ed17fe2 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -25,9 +25,14 @@ * Provides integration with actions. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Prevents processing this includes file for the second time. -#ifndef TASK_ACTION_MQH -#define TASK_ACTION_MQH +#ifndef TASK_ACTION_H +#define TASK_ACTION_H // Includes. #include "TaskAction.enum.h" @@ -38,42 +43,52 @@ */ template class TaskAction : TaskActionBase { - public: - // Class variables. + protected: + // Protected class variables. TaskActionEntry entry; // Action entry. TO obj; // Object to run the action on. + public: /* Special methods */ /** - * Class constructor. + * Default class constructor. */ TaskAction() {} + + /** + * Class constructor with an entry as argument. + */ TaskAction(TaskActionEntry &_entry) : entry(_entry) {} /* Main methods */ /** - * Runs an action. + * Runs a current action. */ bool Run() { bool _result = entry.IsValid() && entry.HasTriesLeft(); _result &= obj.Run(entry); if (_result) { - entry.TriesDec(); entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE)); entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); entry.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_TIME_LAST_RUN), TimeCurrent()); } else { - entry.TriesDec(); - if (!entry.HasTriesLeft()) { - entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID)); - entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); - } + entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID)); + entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); } + entry.TriesDec(); return _result; } + /** + * Runs a TaskAction action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + // @todo + return false; + } + /* Getters */ /** @@ -90,7 +105,7 @@ class TaskAction : TaskActionBase { } /** - * Gets an reference to the object. + * Gets s reference to the object. */ TO *GetObject() { return GetPointer(obj); } @@ -112,4 +127,4 @@ class TaskAction : TaskActionBase { } }; -#endif // TASK_ACTION_MQH +#endif // TASK_ACTION_H diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 7c7d08138..2518789f8 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -37,7 +37,9 @@ /* Entry for TaskAction class. */ struct TaskActionEntry { public: - // Defines enumerations. + /* Enumerations */ + + // Defines action entry properties. enum ENUM_TASK_ACTION_ENTRY_PROP { TASK_ACTION_ENTRY_FLAGS, TASK_ACTION_ENTRY_FREQUENCY, @@ -45,7 +47,7 @@ struct TaskActionEntry { TASK_ACTION_ENTRY_TRIES, TASK_ACTION_ENTRY_TIME_LAST_RUN, }; - /* Defines action entry flags. */ + // Defines action entry flags. enum ENUM_TASK_ACTION_ENTRY_FLAG { TASK_ACTION_ENTRY_FLAG_NONE = 0 << 0, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE = 1 << 0, @@ -61,11 +63,21 @@ struct TaskActionEntry { long id; /* TaskAction's enum ID. */ short tries; /* Number of retries left. */ DataParamEntry args[]; /* TaskAction arguments. */ + protected: + // Protected methods. + void Init() { SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + public: // Constructors. - TaskActionEntry() : flags(0), freq(0), id(WRONG_VALUE), time_last_run(0), tries(0) {} + TaskActionEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_run(0), tries(0) { Init(); } TaskActionEntry(long _id) - : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), id(_id), time_last_run(0), tries(0) {} + : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), + id(_id), + freq(60), + time_last_run(0), + tries(0) { + Init(); + } TaskActionEntry(TaskActionEntry &_ae) { this = _ae; } // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } diff --git a/Task/TaskActionBase.h b/Task/TaskActionBase.h index 3b4a6ed9a..55c99c1e8 100644 --- a/Task/TaskActionBase.h +++ b/Task/TaskActionBase.h @@ -25,9 +25,14 @@ * Provides a base class for a task's action. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Prevents processing this includes file for the second time. -#ifndef TASK_ACTION_BASE_MQH -#define TASK_ACTION_BASE_MQH +#ifndef TASK_ACTION_BASE_H +#define TASK_ACTION_BASE_H /** * TaskActionBase class. @@ -46,7 +51,7 @@ class TaskActionBase { /** * Runs an action. */ - virtual bool Run(const TaskActionEntry &_entry); + virtual bool Run(const TaskActionEntry &_entry) = NULL; }; -#endif // TASK_ACTION_BASE_MQH +#endif // TASK_ACTION_BASE_H diff --git a/Task/TaskCondition.enum.h b/Task/TaskCondition.enum.h index 13cb5542c..3a8a9fbee 100644 --- a/Task/TaskCondition.enum.h +++ b/Task/TaskCondition.enum.h @@ -84,15 +84,6 @@ enum ENUM_MARKET_EVENT { }; #endif -/* Defines condition entry flags. */ -enum ENUM_TASK_CONDITION_ENTRY_FLAGS { - COND_ENTRY_FLAG_NONE = 0, - COND_ENTRY_FLAG_IS_ACTIVE = 1, - COND_ENTRY_FLAG_IS_EXPIRED = 2, - COND_ENTRY_FLAG_IS_INVALID = 4, - COND_ENTRY_FLAG_IS_READY = 8 -}; - /* Defines condition statements (operators). */ enum ENUM_TASK_CONDITION_STATEMENT { COND_AND = 1, // Use AND statement. diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index fc114af66..b51028f59 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -25,9 +25,14 @@ * Provides integration with conditions. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Prevents processing this includes file for the second time. -#ifndef TASK_CONDITION_MQH -#define TASK_CONDITION_MQH +#ifndef TASK_CONDITION_H +#define TASK_CONDITION_H // Includes. #include "../Account.mqh" @@ -47,56 +52,33 @@ /** * TaskCondition class. */ +template class TaskCondition { public: protected: - // Class variables. - Ref logger; + // Protected class variables. + TaskConditionEntry entry; // Condition entry. + TC obj; // Object to run the action on. public: - // Class variables. - DictStruct conds; - /* Special methods */ /** - * Class constructor. + * Default class constructor. */ TaskCondition() {} - TaskCondition(TaskConditionEntry &_entry) { conds.Push(_entry); } - TaskCondition(long _cond_id, ENUM_TASK_CONDITION_TYPE _type) { - TaskConditionEntry _entry(_cond_id, _type); - conds.Push(_entry); - } - template - TaskCondition(T _cond_id, void *_obj = NULL) { - TaskConditionEntry _entry(_cond_id); - if (_obj != NULL) { - _entry.SetObject(_obj); - } - conds.Push(_entry); - } - template - TaskCondition(T _cond_id, MqlParam &_args[], void *_obj = NULL) { - Init(); - TaskConditionEntry _entry(_cond_id); - _entry.SetArgs(_args); - if (_obj != NULL) { - _entry.SetObject(_obj); - } - conds.Push(_entry); - } /** - * Class copy constructor. + * Class constructor with an entry as argument. */ - TaskCondition(TaskCondition &_cond) { conds = _cond.GetConditions(); } + TaskCondition(TaskConditionEntry &_entry) : entry(_entry) {} /* Main methods */ /** * Test conditions. */ + /* bool Test() { bool _result = false, _prev_result = true; for (DictStructIterator iter = conds.Begin(); iter.IsValid(); ++iter) { @@ -126,142 +108,70 @@ class TaskCondition { } return _result; } + */ /** - * Test specific condition. + * Checks a current condition. */ - static bool Test(TaskConditionEntry &_entry) { - bool _result = false; - switch (_entry.type) { - case COND_TYPE_ACCOUNT: - if (Object::IsValid(_entry.obj)) { - _result = ((Account *)_entry.obj).CheckCondition((ENUM_ACCOUNT_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; - case COND_TYPE_CHART: - if (Object::IsValid(_entry.obj)) { - _result = ((Chart *)_entry.obj).CheckCondition((ENUM_CHART_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; - case COND_TYPE_DATETIME: - if (Object::IsValid(_entry.obj)) { - _result = ((DateTime *)_entry.obj).CheckCondition((ENUM_DATETIME_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = DateTime::CheckCondition((ENUM_DATETIME_CONDITION)_entry.cond_id, _entry.args); - } - break; - case COND_TYPE_EA: - if (Object::IsValid(_entry.obj)) { - _result = ((EA *)_entry.obj).CheckCondition((ENUM_EA_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#ifdef INDICATOR_MQH - case COND_TYPE_INDICATOR: - if (Object::IsValid(_entry.obj)) { - _result = ((IndicatorBase *)_entry.obj).CheckCondition((ENUM_INDICATOR_CONDITION)_entry.cond_id, _entry.args); - } else { - // Static method not supported. - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#endif - case COND_TYPE_MARKET: - if (Object::IsValid(_entry.obj)) { - _result = ((Market *)_entry.obj).CheckCondition((ENUM_MARKET_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#ifdef MATH_H - case COND_TYPE_MATH: - /* - if (Object::IsValid(_entry.obj)) { - _result = ((Math *)_entry.obj).CheckCondition((ENUM_MATH_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - */ - return false; - break; -#endif // MATH_M -#ifdef ORDER_MQH - case COND_TYPE_ORDER: - if (Object::IsValid(_entry.obj)) { - _result = ((Order *)_entry.obj).CheckCondition((ENUM_ORDER_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#endif -#ifdef STRATEGY_MQH - case COND_TYPE_STRATEGY: - if (Object::IsValid(_entry.obj)) { - _result = ((Strategy *)_entry.obj).CheckCondition((ENUM_STRATEGY_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#endif -#ifdef TASK_MQH - case COND_TYPE_TASK: - if (Object::IsValid(_entry.obj)) { - _result = ((Task *)_entry.obj).CheckCondition((ENUM_TASK_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#endif - case COND_TYPE_TRADE: - if (Object::IsValid(_entry.obj)) { - _result = ((Trade *)_entry.obj).CheckCondition((ENUM_TRADE_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#ifdef TERMINAL_MQH - case COND_TYPE_TERMINAL: - if (Object::IsValid(_entry.obj)) { - _result = ((Terminal *)_entry.obj).CheckCondition((ENUM_TERMINAL_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#endif - } + bool Check() { + bool _result = entry.IsValid() && entry.HasTriesLeft(); + _result &= obj.Check(entry); if (_result) { - _entry.last_success = TimeCurrent(); - _entry.tries--; + entry.RemoveFlags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)); + entry.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_TIME_LAST_CHECK), TimeCurrent()); + entry.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_TIME_LAST_SUCCESS), TimeCurrent()); + } else { + entry.AddFlags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID)); + entry.RemoveFlags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)); + entry.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_TIME_LAST_CHECK), TimeCurrent()); } - _entry.last_check = TimeCurrent(); + entry.TriesDec(); return _result; } - /* Other methods */ + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) { + // @todo + return false; + } /* Getters */ /** - * Returns conditions. + * Gets an entry's flag. */ - DictStruct *GetConditions() { return &conds; } + bool Get(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag) const { return entry.Get(_flag); } + + /** + * Gets an entry's property value. + */ + template + T Get(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_PROP) _prop) const { + entry.Get(_prop); + } + + /** + * Gets a reference to the object. + */ + TC *GetObject() { return GetPointer(obj); } /* Setters */ + + /** + * Sets an entry's flag. + */ + void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag, bool _value = true) { + entry.Set(_flag, _value); + } + + /** + * Sets an entry's property value. + */ + template + void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_PROP) _prop, T _value) { + entry.Set(_prop, _value); + } }; -#endif // TASK_CONDITION_MQH +#endif // TASK_CONDITION_H diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 97b10383e..582d12e0d 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -42,36 +42,115 @@ #include "Task.enum.h" struct TaskConditionEntry { + public: + /* Enumerations */ + + // Defines condition entry properties. + enum ENUM_TASK_CONDITION_ENTRY_PROP { + TASK_CONDITION_ENTRY_FLAGS, + TASK_CONDITION_ENTRY_FREQUENCY, + TASK_CONDITION_ENTRY_ID, + TASK_CONDITION_ENTRY_TRIES, + TASK_CONDITION_ENTRY_TIME_LAST_CHECK, + TASK_CONDITION_ENTRY_TIME_LAST_SUCCESS, + }; + + // Defines condition entry flags.. + enum ENUM_TASK_CONDITION_ENTRY_FLAGS { + TASK_CONDITION_ENTRY_FLAG_NONE = 0 << 0, + TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE = 1 << 0, + TASK_CONDITION_ENTRY_FLAG_IS_EXPIRED = 1 << 1, + TASK_CONDITION_ENTRY_FLAG_IS_INVALID = 1 << 2, + TASK_CONDITION_ENTRY_FLAG_IS_READY = 1 << 3, + }; + + protected: unsigned char flags; // Condition flags. datetime last_check; // Time of the latest check. datetime last_success; // Time of the last success. - int frequency; // How often to check. - long cond_id; // Condition ID. + int freq; // How often to run (0 for no limit). + long id; // Condition ID. short tries; // Number of successful tries left. - void *obj; // Reference to associated object. ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. ENUM_TASK_CONDITION_TYPE type; // Task's condition type. DataParamEntry args[]; // Task's condition arguments. + protected: + // Protected methods. + void Init() { SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + + public: // Constructors. - void TaskConditionEntry() : type(FINAL_CONDITION_TYPE_ENTRY), cond_id(WRONG_VALUE) { Init(); } - void TaskConditionEntry(long _cond_id, ENUM_TASK_CONDITION_TYPE _type) : type(_type), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(TaskConditionEntry &_ce) { this = _ce; } - void TaskConditionEntry(ENUM_ACCOUNT_CONDITION _cond_id) : type(COND_TYPE_ACCOUNT), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_CHART_CONDITION _cond_id) : type(COND_TYPE_CHART), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_DATETIME_CONDITION _cond_id) : type(COND_TYPE_DATETIME), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_EA_CONDITION _cond_id) : type(COND_TYPE_EA), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_INDICATOR_CONDITION _cond_id) : type(COND_TYPE_INDICATOR), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_MARKET_CONDITION _cond_id) : type(COND_TYPE_MARKET), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_ORDER_CONDITION _cond_id) : type(COND_TYPE_ORDER), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_STRATEGY_CONDITION _cond_id) : type(COND_TYPE_STRATEGY), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_TASK_CONDITION _cond_id) : type(COND_TYPE_TASK), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_TRADE_CONDITION _cond_id) : type(COND_TYPE_TRADE), cond_id(_cond_id) { Init(); } + TaskConditionEntry() : flags(0), freq(60), id(WRONG_VALUE), tries(0) { Init(); } + TaskConditionEntry(long _id) + : flags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)), + freq(60), + id(_id), + last_check(0), + last_success(0), + tries(0) { + Init(); + } + TaskConditionEntry(TaskConditionEntry &_ae) { this = _ae; } // Deconstructor. - void ~TaskConditionEntry() { - // Object::Delete(obj); + void ~TaskConditionEntry() {} + // Getters. + bool Get(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag) const { return HasFlag(_flag); } + template + T Get(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_PROP) _prop) const { + switch (_prop) { + case TASK_CONDITION_ENTRY_FLAGS: + return (T)flags; + case TASK_CONDITION_ENTRY_FREQUENCY: + return (T)freq; + case TASK_CONDITION_ENTRY_ID: + return (T)id; + case TASK_CONDITION_ENTRY_TRIES: + return (T)tries; + case TASK_CONDITION_ENTRY_TIME_LAST_CHECK: + return (T)last_check; + case TASK_CONDITION_ENTRY_TIME_LAST_SUCCESS: + return (T)last_success; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + long GetId() const { return id; } + // Setters. + void TriesDec() { tries--; } + void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag, bool _value = true) { + SetFlag(_flag, _value); + } + template + void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_PROP) _prop, T _value) { + switch (_prop) { + case TASK_CONDITION_ENTRY_FLAGS: // ID (magic number). + flags = (unsigned char)_value; + return; + case TASK_CONDITION_ENTRY_FREQUENCY: + freq = (int)_value; + return; + case TASK_CONDITION_ENTRY_ID: + id = (long)_value; + SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + return; + case TASK_CONDITION_ENTRY_TRIES: + tries = (short)_value; + return; + case TASK_CONDITION_ENTRY_TIME_LAST_CHECK: + last_check = (datetime)_value; + return; + case TASK_CONDITION_ENTRY_TIME_LAST_SUCCESS: + last_success = (datetime)_value; + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); } // Flag methods. - bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } + bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } void SetFlag(ENUM_TASK_CONDITION_ENTRY_FLAGS _flag, bool _value) { @@ -82,30 +161,19 @@ struct TaskConditionEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - bool IsActive() { return HasFlag(COND_ENTRY_FLAG_IS_ACTIVE); } - bool IsExpired() { return HasFlag(COND_ENTRY_FLAG_IS_EXPIRED); } - bool IsReady() { return HasFlag(COND_ENTRY_FLAG_IS_READY); } - bool IsInvalid() { return HasFlag(COND_ENTRY_FLAG_IS_INVALID); } - bool IsValid() { return !IsInvalid(); } - // Getters. - long GetId() { return cond_id; } - ENUM_TASK_CONDITION_TYPE GetType() { return type; } + bool HasTriesLeft() const { return tries > 0; } + bool IsActive() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE); } + bool IsExpired() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_EXPIRED); } + bool IsReady() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_READY); } + bool IsInvalid() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_INVALID); } + bool IsValid() const { return !IsInvalid(); } + ENUM_TASK_CONDITION_TYPE GetType() const { return type; } // Setters. void AddArg(MqlParam &_arg) { // @todo: Add another value to args[]. } - void Init() { - flags = COND_ENTRY_FLAG_NONE; - frequency = 60; - SetFlag(COND_ENTRY_FLAG_IS_ACTIVE, cond_id != WRONG_VALUE); - SetFlag(COND_ENTRY_FLAG_IS_INVALID, cond_id == WRONG_VALUE); - last_check = last_success = 0; - next_statement = COND_AND; - tries = 1; - } void SetArgs(MqlParam &_args[]) { // @todo: for(). } - void SetObject(void *_obj) { obj = _obj; } void SetTries(short _count) { tries = _count; } }; diff --git a/Task/TaskConditionBase.h b/Task/TaskConditionBase.h new file mode 100644 index 000000000..c2cf52cbf --- /dev/null +++ b/Task/TaskConditionBase.h @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides a base class for a task's action. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_CONDITION_BASE_H +#define TASK_CONDITION_BASE_H + +/** + * TaskConditionBase class. + */ +class TaskConditionBase { + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskConditionBase() {} + + /* Main methods */ + + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) = NULL; +}; + +#endif // TASK_CONDITION_BASE_H diff --git a/Task/tests/TaskCondition.test.mq5 b/Task/tests/TaskCondition.test.mq5 index fd2d006f9..71a4a6446 100644 --- a/Task/tests/TaskCondition.test.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -24,172 +24,69 @@ * Test functionality of TaskCondition class. */ -// Forward declaration. -struct DataParamEntry; - // Includes. #include "../../DictObject.mqh" -#include "../../Indicators/Indi_Demo.mqh" -#include "../../Test.mqh" #include "../TaskCondition.h" - -// Global variables. -Chart *chart; -DictObject conds; -int bar_processed; +#include "../TaskConditionBase.h" + +enum ENUM_TASK_CONDITION_TEST { + TASK_CONDITION_TEST01 = 1, + TASK_CONDITION_TEST02 = 2, + TASK_CONDITION_TEST03 = 3, +}; + +class TaskConditionTest01 : public TaskConditionBase { + protected: + long sum; + + public: + TaskConditionTest01() : sum(0){}; + long GetSum() { return sum; } + bool Check(const TaskConditionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); + return true; + } +}; + +class TaskConditionTest02 : public TaskConditionBase { + protected: + long sum; + + public: + TaskConditionTest02() : sum(0){}; + long GetSum() { return sum; } + bool Check(const TaskConditionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); + return true; + } +}; /** * Implements Init event handler. */ int OnInit() { bool _result = true; - bar_processed = 0; - chart = new Chart(PERIOD_M1); - _result &= TestAccountConditions(); - _result &= TestChartConditions(); - _result &= TestDateTimeConditions(); - _result &= TestIndicatorConditions(); - _result &= TestMarketConditions(); - _result &= TestMathConditions(); - _result &= TestOrderConditions(); - _result &= TestTradeConditions(); + // Test01 + TaskConditionEntry _entry01(TASK_CONDITION_TEST01); + TaskCondition _cond01(_entry01); + _cond01.Check(); + //_cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST02); + _cond01.Check(); + //_cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST03); + _cond01.Check(); + // assertTrueOrFail(_cond01.GetObject().GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; - return _result ? INIT_SUCCEEDED : INIT_FAILED; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); } /** * Implements Tick event handler. */ -void OnTick() { - if (chart.IsNewBar()) { - // ... - bar_processed++; - } -} +void OnTick() {} /** * Implements Deinit event handler. */ -void OnDeinit(const int reason) { delete chart; } - -/** - * Test account conditions. - */ -bool TestAccountConditions() { - bool _result = true; - Account *_acc = new Account(); - TaskCondition *_cond = new TaskCondition(ACCOUNT_COND_BAL_IN_LOSS); - assertTrueOrReturnFalse(_cond.Test() == _acc.CheckCondition(ACCOUNT_COND_BAL_IN_LOSS), - "Wrong condition: ACCOUNT_COND_BAL_IN_LOSS!"); - delete _cond; - delete _acc; - return _result; -} - -/** - * Test chart conditions. - */ -bool TestChartConditions() { - bool _result = true; - Chart *_chart = new Chart(); - TaskCondition *_cond = new TaskCondition(CHART_COND_ASK_BAR_PEAK, _chart); - assertTrueOrReturnFalse(_cond.Test() == _chart.CheckCondition(CHART_COND_ASK_BAR_PEAK), - "Wrong condition: CHART_COND_ASK_BAR_PEAK!"); - delete _cond; - delete _chart; - return _result; -} - -/** - * Test date time conditions. - */ -bool TestDateTimeConditions() { - bool _result = true; - DateTime *_dt = new DateTime(); - TaskCondition *_cond1 = new TaskCondition(DATETIME_COND_NEW_HOUR, _dt); - assertTrueOrReturnFalse(_cond1.Test() == _dt.CheckCondition(DATETIME_COND_NEW_HOUR), - "Wrong condition: DATETIME_COND_NEW_HOUR (dynamic)!"); - delete _cond1; - TaskCondition *_cond2 = new TaskCondition(DATETIME_COND_NEW_HOUR); - assertTrueOrReturnFalse(_cond2.Test() == DateTime::CheckCondition(DATETIME_COND_NEW_HOUR), - "Wrong condition: DATETIME_COND_NEW_HOUR (static)!"); - delete _cond2; - delete _dt; - return _result; -} - -/** - * Test indicator conditions. - */ -bool TestIndicatorConditions() { - bool _result = true; - Indi_Demo *_demo = new Indi_Demo(); - /* @fixme - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_IS_MAX, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MAX), - "Wrong condition: INDI_COND_ENTRY_IS_MAX!"); - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_IS_MIN, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MIN), - "Wrong condition: INDI_COND_ENTRY_IS_MIN!"); - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_GT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_AVG), - "Wrong condition: INDI_COND_ENTRY_GT_AVG!"); - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_GT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_MED), - "Wrong condition: INDI_COND_ENTRY_GT_MED!"); - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_LT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_AVG), - "Wrong condition: INDI_COND_ENTRY_LT_AVG!"); - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_LT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_MED), - "Wrong condition: INDI_COND_ENTRY_LT_MED!"); - */ - delete _demo; - return _result; -} - -/** - * Test market conditions. - */ -bool TestMarketConditions() { - bool _result = true; - Market *_market = new Market(); - TaskCondition *_cond = new TaskCondition(MARKET_COND_IN_PEAK_HOURS, _market); - assertTrueOrReturnFalse(_cond.Test() == _market.CheckCondition(MARKET_COND_IN_PEAK_HOURS), - "Wrong condition: MARKET_COND_IN_PEAK_HOURS!"); - delete _cond; - delete _market; - return _result; -} - -/** - * Test math conditions. - */ -bool TestMathConditions() { - bool _result = true; - // @todo - return _result; -} - -/** - * Test order conditions. - */ -bool TestOrderConditions() { - bool _result = true; - // @todo - return _result; -} - -/** - * Test trade conditions. - */ -bool TestTradeConditions() { - bool _result = true; - Trade *_trade = new Trade(); - TaskCondition *_cond = new TaskCondition(TRADE_COND_ALLOWED_NOT, _trade); - assertTrueOrReturnFalse(_cond.Test() == _trade.CheckCondition(TRADE_COND_ALLOWED_NOT), - "Wrong condition: TRADE_COND_ALLOWED_NOT!"); - delete _cond; - delete _trade; - return _result; -} +void OnDeinit(const int reason) {} From d37cd3184397cbbe84c2cf7155ea486332222db9 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Oct 2021 21:27:11 +0100 Subject: [PATCH 07/84] TaskCondition: Code test fixes --- Task/TaskAction.struct.h | 10 +++++----- Task/TaskCondition.h | 11 ++--------- Task/TaskCondition.struct.h | 21 +++++++-------------- Task/tests/TaskAction.test.mq5 | 2 +- Task/tests/TaskCondition.test.mq5 | 14 +++++++------- 5 files changed, 22 insertions(+), 36 deletions(-) diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 2518789f8..4d2d38ce9 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -61,7 +61,7 @@ struct TaskActionEntry { datetime time_last_run; /* Time of the successful run. */ int freq; /* How often to run (0 for no limit). */ long id; /* TaskAction's enum ID. */ - short tries; /* Number of retries left. */ + short tries; /* Number of retries left (-1 for unlimited). */ DataParamEntry args[]; /* TaskAction arguments. */ protected: // Protected methods. @@ -69,13 +69,13 @@ struct TaskActionEntry { public: // Constructors. - TaskActionEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_run(0), tries(0) { Init(); } + TaskActionEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_run(0), tries(-1) { Init(); } TaskActionEntry(long _id) : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), id(_id), freq(60), time_last_run(0), - tries(0) { + tries(-1) { Init(); } TaskActionEntry(TaskActionEntry &_ae) { this = _ae; } @@ -92,7 +92,7 @@ struct TaskActionEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - bool HasTriesLeft() const { return tries > 0; } + bool HasTriesLeft() const { return tries > 0 || tries == -1; } bool IsActive() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); } bool IsDone() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE)); } bool IsFailed() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_FAILED)); } @@ -121,7 +121,7 @@ struct TaskActionEntry { } long GetId() const { return id; } // Setters. - void TriesDec() { tries--; } + void TriesDec() { tries -= tries > 0 ? 1 : 0; } void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value = true) { SetFlag(_flag, _value); } diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index b51028f59..17bfa086d 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -35,15 +35,8 @@ #define TASK_CONDITION_H // Includes. -#include "../Account.mqh" -#include "../Chart.mqh" -#include "../DateTime.mqh" -#include "../DictStruct.mqh" -#include "../EA.mqh" -#include "../Indicator.mqh" -#include "../Market.mqh" -#include "../Object.mqh" -#include "../Order.mqh" +#include "TaskCondition.enum.h" +#include "TaskCondition.struct.h" // Includes class enum and structs. #include "TaskCondition.enum.h" diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 582d12e0d..b56e7e112 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -30,15 +30,8 @@ #endif // Includes. -#include "../Account.enum.h" -#include "../Chart.enum.h" -#include "../DateTime.enum.h" -#include "../EA.enum.h" -#include "../Indicator.enum.h" -//#include "Market.enum.h" -#include "../Order.enum.h" -#include "../Strategy.enum.h" -#include "../Trade.enum.h" +#include "../Data.struct.h" +#include "../Std.h" #include "Task.enum.h" struct TaskConditionEntry { @@ -70,7 +63,7 @@ struct TaskConditionEntry { datetime last_success; // Time of the last success. int freq; // How often to run (0 for no limit). long id; // Condition ID. - short tries; // Number of successful tries left. + short tries; // Number of successful tries left (-1 for unlimited). ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. ENUM_TASK_CONDITION_TYPE type; // Task's condition type. DataParamEntry args[]; // Task's condition arguments. @@ -80,14 +73,14 @@ struct TaskConditionEntry { public: // Constructors. - TaskConditionEntry() : flags(0), freq(60), id(WRONG_VALUE), tries(0) { Init(); } + TaskConditionEntry() : flags(0), freq(60), id(WRONG_VALUE), tries(-1) { Init(); } TaskConditionEntry(long _id) : flags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)), freq(60), id(_id), last_check(0), last_success(0), - tries(0) { + tries(-1) { Init(); } TaskConditionEntry(TaskConditionEntry &_ae) { this = _ae; } @@ -118,7 +111,7 @@ struct TaskConditionEntry { } long GetId() const { return id; } // Setters. - void TriesDec() { tries--; } + void TriesDec() { tries -= tries > 0 ? 1 : 0; } void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag, bool _value = true) { SetFlag(_flag, _value); } @@ -161,7 +154,7 @@ struct TaskConditionEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - bool HasTriesLeft() const { return tries > 0; } + bool HasTriesLeft() const { return tries > 0 || tries == -1; } bool IsActive() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE); } bool IsExpired() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_EXPIRED); } bool IsReady() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_READY); } diff --git a/Task/tests/TaskAction.test.mq5 b/Task/tests/TaskAction.test.mq5 index 3b7d3dec5..6db57f164 100644 --- a/Task/tests/TaskAction.test.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -76,7 +76,7 @@ int OnInit() { _action01.Run(); _action01.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST03); _action01.Run(); - assertTrueOrFail(_action01.GetObject().GetSum() == 6, "Fail!"); + assertTrueOrFail(_result && _action01.GetObject().GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } diff --git a/Task/tests/TaskCondition.test.mq5 b/Task/tests/TaskCondition.test.mq5 index 71a4a6446..e565a5fc3 100644 --- a/Task/tests/TaskCondition.test.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -25,7 +25,7 @@ */ // Includes. -#include "../../DictObject.mqh" +#include "../../Test.mqh" #include "../TaskCondition.h" #include "../TaskConditionBase.h" @@ -71,12 +71,12 @@ int OnInit() { // Test01 TaskConditionEntry _entry01(TASK_CONDITION_TEST01); TaskCondition _cond01(_entry01); - _cond01.Check(); - //_cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST02); - _cond01.Check(); - //_cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST03); - _cond01.Check(); - // assertTrueOrFail(_cond01.GetObject().GetSum() == 6, "Fail!"); + _result &= _cond01.Check(); + _cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST02); + _result &= _cond01.Check(); + _cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST03); + _result &= _cond01.Check(); + assertTrueOrFail(_result && _cond01.GetObject().GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From 12dbb363d73cfc2068b63d88ca7adc745b979afb Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Oct 2021 22:11:36 +0100 Subject: [PATCH 08/84] Task: Code cleanup --- Task/Task.h | 9 +--- Task/Task.struct.h | 21 +++++----- Task/TaskAction.h | 3 +- Task/TaskAction.struct.h | 2 +- Task/TaskCondition.h | 7 +--- Task/TaskCondition.struct.h | 21 +++++----- Task/TaskConditionBase.h | 2 +- Task/tests/Task.test.mq5 | 69 ++----------------------------- Task/tests/TaskAction.test.mq5 | 1 - Task/tests/TaskCondition.test.mq5 | 1 - 10 files changed, 31 insertions(+), 105 deletions(-) diff --git a/Task/Task.h b/Task/Task.h index d6a718f02..dfd7eaf9c 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -43,10 +43,6 @@ #include "TaskCondition.h" class Task { - protected: - // Class variables. - Ref logger; - public: // Class variables. DictStruct tasks; @@ -69,8 +65,6 @@ class Task { */ ~Task() {} - Log *Logger() { return logger.Ptr(); } - /* Main methods */ /** @@ -239,7 +233,6 @@ class Task { // Is invalid. return IsInvalid(); default: - Logger().Error(StringFormat("Invalid Task condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); return false; } } @@ -263,7 +256,7 @@ class Task { // Process tasks. return Process(); default: - Logger().Error(StringFormat("Invalid Task action: %s!", EnumToString(_action), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); return false; } return _result; diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 82e7b6684..5d8061c62 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -36,12 +36,23 @@ #include "TaskCondition.struct.h" struct TaskEntry { + protected: TaskActionEntry action; // TaskAction of the task. TaskConditionEntry cond; // TaskCondition of the task. datetime expires; // Time of expiration. datetime last_process; // Time of the last process. datetime last_success; // Time of the last success. unsigned char flags; // TaskAction flags. + protected: + // Protected methods. + void Init() { + flags = TASK_ENTRY_FLAG_NONE; + SetFlag(TASK_ENTRY_FLAG_IS_ACTIVE, action.IsActive() && cond.IsActive()); + SetFlag(TASK_ENTRY_FLAG_IS_INVALID, action.IsInvalid() || cond.IsInvalid()); + expires = last_process = last_success = 0; + } + + public: // Constructors. void TaskEntry() { Init(); } void TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } @@ -49,13 +60,6 @@ struct TaskEntry { void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { Init(); }; - // Main methods. - void Init() { - flags = TASK_ENTRY_FLAG_NONE; - SetFlag(TASK_ENTRY_FLAG_IS_ACTIVE, action.IsActive() && cond.IsActive()); - SetFlag(TASK_ENTRY_FLAG_IS_INVALID, action.IsInvalid() || cond.IsInvalid()); - expires = last_process = last_success = 0; - } // Flag methods. bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } @@ -77,7 +81,4 @@ struct TaskEntry { long GetConditionId() { return cond.GetId(); } TaskActionEntry GetAction() { return action; } TaskConditionEntry GetCondition() { return cond; } - // Setters. - // void SetActionObject(void *_obj) { action.SetObject(_obj); } - // void SetConditionObject(void *_obj) { cond.SetObject(_obj); } }; diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 56ed17fe2..bd56eb8ac 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -22,7 +22,7 @@ /** * @file - * Provides integration with actions. + * Provides integration with task's actions. */ #ifndef __MQL__ @@ -37,6 +37,7 @@ // Includes. #include "TaskAction.enum.h" #include "TaskAction.struct.h" +#include "TaskActionBase.h" /** * TaskAction class. diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 4d2d38ce9..0f251d674 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -21,7 +21,7 @@ /** * @file - * Includes TaskAction's structs. + * Includes TaskAction's structures. */ #ifndef __MQL__ diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 17bfa086d..909e244ba 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -22,7 +22,7 @@ /** * @file - * Provides integration with conditions. + * Provides integration with task's conditions. */ #ifndef __MQL__ @@ -37,10 +37,7 @@ // Includes. #include "TaskCondition.enum.h" #include "TaskCondition.struct.h" - -// Includes class enum and structs. -#include "TaskCondition.enum.h" -#include "TaskCondition.struct.h" +#include "TaskConditionBase.h" /** * TaskCondition class. diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index b56e7e112..82b0dc7ca 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -21,7 +21,7 @@ /** * @file - * Includes Condition's structs. + * Includes TaskCondition's structures. */ #ifndef __MQL__ @@ -58,15 +58,15 @@ struct TaskConditionEntry { }; protected: - unsigned char flags; // Condition flags. - datetime last_check; // Time of the latest check. - datetime last_success; // Time of the last success. - int freq; // How often to run (0 for no limit). - long id; // Condition ID. - short tries; // Number of successful tries left (-1 for unlimited). - ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. - ENUM_TASK_CONDITION_TYPE type; // Task's condition type. - DataParamEntry args[]; // Task's condition arguments. + unsigned char flags; // Condition flags. + datetime last_check; // Time of the latest check. + datetime last_success; // Time of the last success. + int freq; // How often to run (0 for no limit). + long id; // Condition ID. + short tries; // Number of successful tries left (-1 for unlimited). + // ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. + // ENUM_TASK_CONDITION_TYPE type; // Task's condition type. + DataParamEntry args[]; // Task's condition arguments. protected: // Protected methods. void Init() { SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } @@ -160,7 +160,6 @@ struct TaskConditionEntry { bool IsReady() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_READY); } bool IsInvalid() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_INVALID); } bool IsValid() const { return !IsInvalid(); } - ENUM_TASK_CONDITION_TYPE GetType() const { return type; } // Setters. void AddArg(MqlParam &_arg) { // @todo: Add another value to args[]. diff --git a/Task/TaskConditionBase.h b/Task/TaskConditionBase.h index c2cf52cbf..0e8e12d5b 100644 --- a/Task/TaskConditionBase.h +++ b/Task/TaskConditionBase.h @@ -22,7 +22,7 @@ /** * @file - * Provides a base class for a task's action. + * Provides a base class for a task's condition. */ #ifndef __MQL__ diff --git a/Task/tests/Task.test.mq5 b/Task/tests/Task.test.mq5 index 31be5230c..623bd8d9e 100644 --- a/Task/tests/Task.test.mq5 +++ b/Task/tests/Task.test.mq5 @@ -28,50 +28,15 @@ struct DataParamEntry; // Includes. -#include "../../Chart.mqh" -#include "../../DictObject.mqh" -#include "../../EA.mqh" #include "../../Test.mqh" #include "../Task.h" -#include "../TaskAction.h" -#include "../TaskCondition.h" - -// Global variables. -Chart *chart; -EA *ea; -DictObject tasks; - -// Define strategy classes. -class Stg1 : public Strategy { - public: - void Stg1(StgParams &_params, TradeParams &_tparams, ChartParams &_cparams, string _name = "Stg1") - : Strategy(_params, _tparams, _cparams, _name) {} - static Stg1 *Init(ENUM_TIMEFRAMES _tf = NULL, unsigned long _magic_no = 0, ENUM_LOG_LEVEL _log_level = V_INFO) { - ChartParams _cparams(_tf); - TradeParams _tparams(_magic_no, _log_level); - Strategy *_strat = new Stg1(stg_params_defaults, _tparams, _cparams, __FUNCTION__); - return _strat; - } - bool SignalOpen(ENUM_ORDER_TYPE _cmd, int _method, float _level, int _shift) { return true; } - bool SignalOpenFilterMethod(ENUM_ORDER_TYPE _cmd, int _method = 0) { return true; } - float SignalOpenBoost(ENUM_ORDER_TYPE _cmd, int _method = 0) { return 1.0f; } - bool SignalClose(ENUM_ORDER_TYPE _cmd, int _method, float _level, int _shift) { return true; } - float PriceStop(ENUM_ORDER_TYPE _cmd, ENUM_ORDER_TYPE_VALUE _mode, int _method = 0, float _level = 0.0f) { - return _level; - } -}; /** * Implements Init event handler. */ int OnInit() { bool _result = true; - // Initializes chart. - chart = new Chart(); - // Initializes EA. - EAParams ea_params(__FILE__); - ea = new EA(ea_params); - //_result &= ea.StrategyAdd(127); + // @todo _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } @@ -79,37 +44,9 @@ int OnInit() { /** * Implements Tick event handler. */ -void OnTick() { - chart.OnTick(); - if (chart.IsNewBar()) { - unsigned int _bar_index = chart.GetBarIndex(); - switch (_bar_index) { - case 1: - break; - case 2: - break; - case 3: - break; - case 4: - break; - case 5: - break; - case 6: - break; - case 7: - break; - case 8: - break; - case 9: - break; - } - } -} +void OnTick() {} /** * Implements Deinit event handler. */ -void OnDeinit(const int reason) { - delete chart; - delete ea; -} +void OnDeinit(const int reason) {} diff --git a/Task/tests/TaskAction.test.mq5 b/Task/tests/TaskAction.test.mq5 index 6db57f164..4b6b815df 100644 --- a/Task/tests/TaskAction.test.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -27,7 +27,6 @@ // Includes. #include "../../Test.mqh" #include "../TaskAction.h" -#include "../TaskActionBase.h" enum ENUM_TASK_ACTION_TEST { TASK_ACTION_TEST01 = 1, diff --git a/Task/tests/TaskCondition.test.mq5 b/Task/tests/TaskCondition.test.mq5 index e565a5fc3..aeef3cede 100644 --- a/Task/tests/TaskCondition.test.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -27,7 +27,6 @@ // Includes. #include "../../Test.mqh" #include "../TaskCondition.h" -#include "../TaskConditionBase.h" enum ENUM_TASK_CONDITION_TEST { TASK_CONDITION_TEST01 = 1, From bec31a5b8b81d87c83f16ae8cba6624767cef9ac Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Oct 2021 22:41:56 +0100 Subject: [PATCH 09/84] Task: Adds Taskable class --- .github/workflows/test-task.yml | 1 + Task/Task.h | 3 +- Task/Taskable.h | 66 +++++++++++++++++++++++++ Task/tests/Taskable.test.mq4 | 28 +++++++++++ Task/tests/Taskable.test.mq5 | 86 +++++++++++++++++++++++++++++++++ 5 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 Task/Taskable.h create mode 100644 Task/tests/Taskable.test.mq4 create mode 100644 Task/tests/Taskable.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index 36ed3cbf9..fa56d6cab 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -49,6 +49,7 @@ jobs: matrix: test: - Task.test + - Taskable.test - TaskAction.test - TaskCondition.test steps: diff --git a/Task/Task.h b/Task/Task.h index dfd7eaf9c..93f445f3e 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -41,8 +41,9 @@ #include "Task.struct.h" #include "TaskAction.h" #include "TaskCondition.h" +#include "Taskable.h" -class Task { +class Task : protected Taskable { public: // Class variables. DictStruct tasks; diff --git a/Task/Taskable.h b/Task/Taskable.h new file mode 100644 index 000000000..cbd9b6ebe --- /dev/null +++ b/Task/Taskable.h @@ -0,0 +1,66 @@ +//+------------------------------------------------------------------+ +//| 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 + * Defines Taskable class. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASKABLE_H +#define TASKABLE_H + +// Includes. +#include "TaskAction.h" +#include "TaskCondition.h" + +/** + * Taskable class. + */ +class Taskable { + public: + /* Special methods */ + + /** + * Class constructor. + */ + Taskable() {} + + /* Main methods */ + + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) = NULL; + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) = NULL; +}; + +#endif // TASKABLE_H diff --git a/Task/tests/Taskable.test.mq4 b/Task/tests/Taskable.test.mq4 new file mode 100644 index 000000000..47e309712 --- /dev/null +++ b/Task/tests/Taskable.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Taskable class. + */ + +// Includes. +#include "Taskable.test.mq5" diff --git a/Task/tests/Taskable.test.mq5 b/Task/tests/Taskable.test.mq5 new file mode 100644 index 000000000..9bbd4519d --- /dev/null +++ b/Task/tests/Taskable.test.mq5 @@ -0,0 +1,86 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Taskable class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../Taskable.h" + +class TaskTest01 : public Taskable { + protected: + long sum; + + public: + TaskTest01() : sum(0){}; + long GetSum() { return sum; } + + /** + * Checks a condition. + */ + bool Check(const TaskConditionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); + return true; + } + + /* Main methods */ + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); + return true; + } +}; + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + TaskTest01 _test01; + // Checks dummy condition. + TaskConditionEntry _entry_cond(2); + _result &= _test01.Check(_entry_cond); + // Runs dummy action. + TaskActionEntry _entry_action(2); + _result &= _test01.Run(_entry_action); + // Checks the results. + assertTrueOrFail(_result && _test01.GetSum() == 4, "Fail!"); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From 45e02427bdd8adf8cc5e39b6cec45353ef82bfa2 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Oct 2021 23:14:34 +0100 Subject: [PATCH 10/84] Task: Code improvements --- Task/Task.h | 8 ++--- Task/TaskAction.h | 28 +++++++++++------ Task/TaskAction.struct.h | 8 ++--- Task/TaskCondition.h | 63 +++++++++++-------------------------- Task/TaskCondition.struct.h | 8 ++--- 5 files changed, 48 insertions(+), 67 deletions(-) diff --git a/Task/Task.h b/Task/Task.h index 93f445f3e..0fe53b3e7 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -36,7 +36,6 @@ // Includes. #include "../DictStruct.mqh" -#include "../Refs.mqh" #include "Task.enum.h" #include "Task.struct.h" #include "TaskAction.h" @@ -80,11 +79,10 @@ class Task : protected Taskable { * Returns true when tasks has been processed. */ bool Process() { - bool _result = false; + bool _result = true; for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { - bool _curr_result = false; TaskEntry _entry = iter.Value(); - Process(_entry); + _result &= Process(_entry); } return _result; } @@ -116,6 +114,8 @@ class Task : protected Taskable { return _result; } + /* Task methods */ + /* State methods */ /** diff --git a/Task/TaskAction.h b/Task/TaskAction.h index bd56eb8ac..db6c78745 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -43,7 +43,7 @@ * TaskAction class. */ template -class TaskAction : TaskActionBase { +class TaskAction : protected TaskActionBase { protected: // Protected class variables. TaskActionEntry entry; // Action entry. @@ -65,7 +65,7 @@ class TaskAction : TaskActionBase { /* Main methods */ /** - * Runs a current action. + * Runs a current stored action. */ bool Run() { bool _result = entry.IsValid() && entry.HasTriesLeft(); @@ -82,14 +82,6 @@ class TaskAction : TaskActionBase { return _result; } - /** - * Runs a TaskAction action. - */ - virtual bool Run(const TaskActionEntry &_entry) { - // @todo - return false; - } - /* Getters */ /** @@ -126,6 +118,22 @@ class TaskAction : TaskActionBase { void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop, T _value) { entry.Set(_prop, _value); } + + /* TaskActionBase methods */ + + /** + * Runs an action. + */ + bool Run(const TaskActionEntry &_entry) { + switch (_entry.GetId()) { + case 0: + return Run(); + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + return false; + } }; #endif // TASK_ACTION_H diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 0f251d674..7014144c6 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -60,7 +60,7 @@ struct TaskActionEntry { unsigned char flags; /* TaskAction flags. */ datetime time_last_run; /* Time of the successful run. */ int freq; /* How often to run (0 for no limit). */ - long id; /* TaskAction's enum ID. */ + int id; /* TaskAction's enum ID. */ short tries; /* Number of retries left (-1 for unlimited). */ DataParamEntry args[]; /* TaskAction arguments. */ protected: @@ -70,7 +70,7 @@ struct TaskActionEntry { public: // Constructors. TaskActionEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_run(0), tries(-1) { Init(); } - TaskActionEntry(long _id) + TaskActionEntry(int _id) : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), id(_id), freq(60), @@ -119,7 +119,7 @@ struct TaskActionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } - long GetId() const { return id; } + int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value = true) { @@ -135,7 +135,7 @@ struct TaskActionEntry { freq = (int)_value; return; case TASK_ACTION_ENTRY_ID: - id = (long)_value; + id = (int)_value; SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); return; case TASK_ACTION_ENTRY_TRIES: diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 909e244ba..42d977754 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -43,7 +43,7 @@ * TaskCondition class. */ template -class TaskCondition { +class TaskCondition : protected TaskConditionBase { public: protected: // Protected class variables. @@ -66,42 +66,7 @@ class TaskCondition { /* Main methods */ /** - * Test conditions. - */ - /* - bool Test() { - bool _result = false, _prev_result = true; - for (DictStructIterator iter = conds.Begin(); iter.IsValid(); ++iter) { - bool _curr_result = false; - TaskConditionEntry _entry = iter.Value(); - if (!_entry.IsValid()) { - // Ignore invalid entries. - continue; - } - if (_entry.IsActive()) { - switch (_entry.next_statement) { - case COND_AND: - _curr_result = _prev_result && this.Test(_entry); - break; - case COND_OR: - _curr_result = _prev_result || this.Test(_entry); - break; - case COND_SEQ: - _curr_result = this.Test(_entry); - if (!_curr_result) { - // Do not check further conditions when the current condition is false. - return false; - } - } - _result = _prev_result = _curr_result; - } - } - return _result; - } - */ - - /** - * Checks a current condition. + * Checks a current stored condition. */ bool Check() { bool _result = entry.IsValid() && entry.HasTriesLeft(); @@ -119,14 +84,6 @@ class TaskCondition { return _result; } - /** - * Checks a condition. - */ - virtual bool Check(const TaskConditionEntry &_entry) { - // @todo - return false; - } - /* Getters */ /** @@ -163,5 +120,21 @@ class TaskCondition { void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_PROP) _prop, T _value) { entry.Set(_prop, _value); } + + /* TaskConditionBase methods */ + + /** + * Checks a condition. + */ + bool Check(const TaskConditionEntry &_entry) { + switch (_entry.GetId()) { + case 0: + return Check(); + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + return false; + } }; #endif // TASK_CONDITION_H diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 82b0dc7ca..bbd1c557e 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -62,7 +62,7 @@ struct TaskConditionEntry { datetime last_check; // Time of the latest check. datetime last_success; // Time of the last success. int freq; // How often to run (0 for no limit). - long id; // Condition ID. + int id; // Condition ID. short tries; // Number of successful tries left (-1 for unlimited). // ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. // ENUM_TASK_CONDITION_TYPE type; // Task's condition type. @@ -74,7 +74,7 @@ struct TaskConditionEntry { public: // Constructors. TaskConditionEntry() : flags(0), freq(60), id(WRONG_VALUE), tries(-1) { Init(); } - TaskConditionEntry(long _id) + TaskConditionEntry(int _id) : flags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)), freq(60), id(_id), @@ -109,7 +109,7 @@ struct TaskConditionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } - long GetId() const { return id; } + int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag, bool _value = true) { @@ -125,7 +125,7 @@ struct TaskConditionEntry { freq = (int)_value; return; case TASK_CONDITION_ENTRY_ID: - id = (long)_value; + id = (int)_value; SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); return; case TASK_CONDITION_ENTRY_TRIES: From b086fd9abecc28f45062215b619b431103f1e655 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Oct 2021 23:59:29 +0100 Subject: [PATCH 11/84] Task: Adds TaskGetter class --- .github/workflows/test-task.yml | 1 + Task/TaskCondition.h | 6 +- Task/TaskGetter.h | 133 +++++++++++++++++++++++++ Task/TaskGetter.struct.h | 170 ++++++++++++++++++++++++++++++++ Task/TaskGetterBase.h | 58 +++++++++++ Task/tests/TaskGetter.test.mq4 | 28 ++++++ Task/tests/TaskGetter.test.mq5 | 86 ++++++++++++++++ 7 files changed, 479 insertions(+), 3 deletions(-) create mode 100644 Task/TaskGetter.h create mode 100644 Task/TaskGetter.struct.h create mode 100644 Task/TaskGetterBase.h create mode 100644 Task/tests/TaskGetter.test.mq4 create mode 100644 Task/tests/TaskGetter.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index fa56d6cab..d5869346f 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -52,6 +52,7 @@ jobs: - Taskable.test - TaskAction.test - TaskCondition.test + - TaskGetter.test steps: - uses: actions/download-artifact@v2 with: diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 42d977754..21670e684 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -42,13 +42,13 @@ /** * TaskCondition class. */ -template +template class TaskCondition : protected TaskConditionBase { public: protected: // Protected class variables. TaskConditionEntry entry; // Condition entry. - TC obj; // Object to run the action on. + TO obj; // Object to run the action on. public: /* Special methods */ @@ -102,7 +102,7 @@ class TaskCondition : protected TaskConditionBase { /** * Gets a reference to the object. */ - TC *GetObject() { return GetPointer(obj); } + TO *GetObject() { return GetPointer(obj); } /* Setters */ diff --git a/Task/TaskGetter.h b/Task/TaskGetter.h new file mode 100644 index 000000000..b25ac67f1 --- /dev/null +++ b/Task/TaskGetter.h @@ -0,0 +1,133 @@ +//+------------------------------------------------------------------+ +//| 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 + * Provides integration with task's actions. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_GETTER_H +#define TASK_GETTER_H + +// Includes. +//#include "TaskGetter.enum.h" +#include "TaskGetter.struct.h" +#include "TaskGetterBase.h" + +/** + * TaskGetter class. + */ +template +class TaskGetter : protected TaskGetterBase { + protected: + // Protected class variables. + TaskGetterEntry entry; // Getter entry. + TO obj; // Object to run the action on. + + public: + /* Special methods */ + + /** + * Default class constructor. + */ + TaskGetter() {} + + /** + * Class constructor with an entry as argument. + */ + TaskGetter(TaskGetterEntry &_entry) : entry(_entry) {} + + /* Main methods */ + + /** + * Runs a current stored action. + */ + TS Get() { + TS _result = obj.Get(entry); + entry.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_TIME_LAST_GET), TimeCurrent()); + entry.TriesDec(); + return _result; + } + + /* Getters */ + + /** + * Gets an entry's flag. + */ + bool Get(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag) const { return entry.Get(_flag); } + + /** + * Gets an entry's property value. + */ + template + T Get(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_PROP) _prop) const { + entry.Get(_prop); + } + + /** + * Gets a reference to the object. + */ + TO *GetObject() { return GetPointer(obj); } + + /* Setters */ + + /** + * Sets an entry's flag. + */ + void Set(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag, bool _value = true) { + entry.Set(_flag, _value); + } + + /** + * Sets an entry's property value. + */ + template + void Set(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_PROP) _prop, T _value) { + entry.Set(_prop, _value); + } + + /* TaskGetterBase methods */ + + /** + * Runs an action. + */ + TS Get(const TaskGetterEntry &_entry) { + TS _result; + switch (_entry.GetId()) { + case 0: + _result = Get(); + break; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + return _result; + } +}; + +#endif // TASK_GETTER_H diff --git a/Task/TaskGetter.struct.h b/Task/TaskGetter.struct.h new file mode 100644 index 000000000..2abe464da --- /dev/null +++ b/Task/TaskGetter.struct.h @@ -0,0 +1,170 @@ +//+------------------------------------------------------------------+ +//| 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 TaskGetter's structures. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Data.struct.h" +#include "../Std.h" +#include "Task.enum.h" + +/* Entry for TaskGetter class. */ +struct TaskGetterEntry { + public: + /* Enumerations */ + + // Defines action entry properties. + enum ENUM_TASK_GETTER_ENTRY_PROP { + TASK_GETTER_ENTRY_FLAGS, + TASK_GETTER_ENTRY_FREQUENCY, + TASK_GETTER_ENTRY_ID, + TASK_GETTER_ENTRY_TRIES, + TASK_GETTER_ENTRY_TIME_LAST_GET, + }; + // Defines action entry flags. + enum ENUM_TASK_GETTER_ENTRY_FLAG { + TASK_GETTER_ENTRY_FLAG_NONE = 0 << 0, + TASK_GETTER_ENTRY_FLAG_IS_ACTIVE = 1 << 0, + TASK_GETTER_ENTRY_FLAG_IS_DONE = 1 << 1, + TASK_GETTER_ENTRY_FLAG_IS_FAILED = 1 << 2, + TASK_GETTER_ENTRY_FLAG_IS_INVALID = 1 << 3, + }; + + protected: + unsigned char flags; /* TaskGetter flags. */ + datetime time_last_get; /* Time of the successful get. */ + int freq; /* How often to run (0 for no limit). */ + int id; /* TaskGetter's enum ID. */ + short tries; /* Number of retries left (-1 for unlimited). */ + DataParamEntry args[]; /* TaskGetter arguments. */ + protected: + // Protected methods. + void Init() { SetFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + + public: + // Constructors. + TaskGetterEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_get(0), tries(-1) { Init(); } + TaskGetterEntry(int _id) + : flags(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)), + id(_id), + freq(60), + time_last_get(0), + tries(-1) { + Init(); + } + TaskGetterEntry(TaskGetterEntry &_ae) { this = _ae; } + // Flag methods. + bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } + void AddFlags(unsigned char _flags) { flags |= _flags; } + void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void SetFlag(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag, bool _value) { + if (_value) { + AddFlags(_flag); + } else { + RemoveFlags(_flag); + } + } + void SetFlags(unsigned char _flags) { flags = _flags; } + // State methods. + bool HasTriesLeft() const { return tries > 0 || tries == -1; } + bool IsActive() const { return HasFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); } + bool IsDone() const { return HasFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_DONE)); } + bool IsFailed() const { return HasFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_FAILED)); } + bool IsInvalid() const { return HasFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_INVALID)); } + bool IsValid() const { return !IsInvalid(); } + // Getters. + bool Get(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag) const { return HasFlag(_flag); } + template + T Get(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_PROP) _prop) const { + switch (_prop) { + case TASK_GETTER_ENTRY_FLAGS: + return (T)flags; + case TASK_GETTER_ENTRY_FREQUENCY: + return (T)freq; + case TASK_GETTER_ENTRY_ID: + return (T)id; + case TASK_GETTER_ENTRY_TRIES: + return (T)tries; + case TASK_GETTER_ENTRY_TIME_LAST_RUN: + return (T)time_last_run; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + int GetId() const { return id; } + // Setters. + void TriesDec() { tries -= tries > 0 ? 1 : 0; } + void Set(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag, bool _value = true) { + SetFlag(_flag, _value); + } + template + void Set(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_PROP) _prop, T _value) { + switch (_prop) { + case TASK_GETTER_ENTRY_FLAGS: // ID (magic number). + flags = (unsigned char)_value; + return; + case TASK_GETTER_ENTRY_FREQUENCY: + freq = (int)_value; + return; + case TASK_GETTER_ENTRY_ID: + id = (int)_value; + SetFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + return; + case TASK_GETTER_ENTRY_TRIES: + tries = (short)_value; + return; + case TASK_GETTER_ENTRY_TIME_LAST_GET: + time_last_get = (datetime)_value; + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + } + void AddArg(MqlParam &_arg) { + // @todo: Add another value to args[]. + } + void SetArgs(ARRAY_REF(MqlParam, _args)) { + // @todo: for(). + } + // Serializers + SerializerNodeType Serialize(Serializer &s) { + s.Pass(THIS_REF, "flags", flags); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "time_last_get", time_last_get); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); + s.PassArray(this, "args", args); + return SerializerNodeObject; + } + + SERIALIZER_EMPTY_STUB; +}; diff --git a/Task/TaskGetterBase.h b/Task/TaskGetterBase.h new file mode 100644 index 000000000..6c53af020 --- /dev/null +++ b/Task/TaskGetterBase.h @@ -0,0 +1,58 @@ +//+------------------------------------------------------------------+ +//| 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 + * Provides a base class for a task's getter. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_GETTER_BASE_H +#define TASK_GETTER_BASE_H + +/** + * TaskGetterBase class. + */ +template +class TaskGetterBase { + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskGetterBase() {} + + /* Main methods */ + + /** + * Gets a structure. + */ + virtual TS Get(const TaskGetterEntry &_entry) = NULL; +}; + +#endif // TASK_GETTER_BASE_H diff --git a/Task/tests/TaskGetter.test.mq4 b/Task/tests/TaskGetter.test.mq4 new file mode 100644 index 000000000..688c4942e --- /dev/null +++ b/Task/tests/TaskGetter.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskGetter class. + */ + +// Includes. +#include "TaskGetter.test.mq5" diff --git a/Task/tests/TaskGetter.test.mq5 b/Task/tests/TaskGetter.test.mq5 new file mode 100644 index 000000000..05760ff6a --- /dev/null +++ b/Task/tests/TaskGetter.test.mq5 @@ -0,0 +1,86 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskGetter class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../TaskGetter.h" + +enum ENUM_TASK_GETTER_TEST { + TASK_GETTER_TEST01 = 1, + TASK_GETTER_TEST02 = 2, + TASK_GETTER_TEST03 = 3, +}; + +struct TaskGetterTest01Data { + int value; + TaskGetterTest01Data() : value(0) {} + int GetValue() { return value; } + void SetValue(int _value) { value = _value; } +}; + +class TaskGetterTest01 : protected TaskGetterBase { + protected: + TaskGetterTest01Data data; + + public: + TaskGetterTest01(){}; + // long GetSum() { return sum; } + TaskGetterTest01Data Get(const TaskGetterEntry &_entry) { + data.SetValue(_entry.GetId()); + PrintFormat("Get: %s; value=%d", __FUNCSIG__, data.GetValue()); + return data; + } +}; + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + int _sum = 0; + // Test01 + TaskGetterEntry _entry01(TASK_GETTER_TEST01); + TaskGetter _getter01(_entry01); + _result &= _getter01.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); + _sum += _getter01.Get().GetValue(); + _getter01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST02); + _sum += _getter01.Get().GetValue(); + _getter01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST03); + _sum += _getter01.Get().GetValue(); + assertTrueOrFail(_result && _sum == 6, "Fail!"); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From d3b891615600e074c9a7b08d746b227571e61935 Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 27 Oct 2021 11:23:03 +0100 Subject: [PATCH 12/84] Task: TaskGetter: Improves tests --- Task/Task.h | 2 +- Task/TaskGetterBase.h | 2 +- Task/Taskable.h | 9 ++++- Task/tests/TaskAction.test.mq5 | 4 +-- Task/tests/TaskCondition.test.mq5 | 4 +-- Task/tests/Taskable.test.mq5 | 55 +++++++++++++++++++++++-------- 6 files changed, 55 insertions(+), 21 deletions(-) diff --git a/Task/Task.h b/Task/Task.h index 0fe53b3e7..5d0864b3b 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -42,7 +42,7 @@ #include "TaskCondition.h" #include "Taskable.h" -class Task : protected Taskable { +class Task : protected Taskable { public: // Class variables. DictStruct tasks; diff --git a/Task/TaskGetterBase.h b/Task/TaskGetterBase.h index 6c53af020..6261d2ce6 100644 --- a/Task/TaskGetterBase.h +++ b/Task/TaskGetterBase.h @@ -50,7 +50,7 @@ class TaskGetterBase { /* Main methods */ /** - * Gets a structure. + * Gets a copy of structure. */ virtual TS Get(const TaskGetterEntry &_entry) = NULL; }; diff --git a/Task/Taskable.h b/Task/Taskable.h index cbd9b6ebe..88345b0ee 100644 --- a/Task/Taskable.h +++ b/Task/Taskable.h @@ -37,10 +37,12 @@ // Includes. #include "TaskAction.h" #include "TaskCondition.h" +#include "TaskGetter.h" /** * Taskable class. */ +template class Taskable { public: /* Special methods */ @@ -50,13 +52,18 @@ class Taskable { */ Taskable() {} - /* Main methods */ + /* Virtual methods */ /** * Checks a condition. */ virtual bool Check(const TaskConditionEntry &_entry) = NULL; + /** + * Gets a copy of structure. + */ + virtual TS Get(const TaskGetterEntry &_entry) = NULL; + /** * Runs an action. */ diff --git a/Task/tests/TaskAction.test.mq5 b/Task/tests/TaskAction.test.mq5 index 4b6b815df..f1f0721af 100644 --- a/Task/tests/TaskAction.test.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -43,7 +43,7 @@ class TaskActionTest01 : public TaskActionBase { long GetSum() { return sum; } bool Run(const TaskActionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); return true; } }; @@ -57,7 +57,7 @@ class TaskActionTest02 : public TaskActionBase { long GetSum() { return sum; } bool Run(const TaskActionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); return true; } }; diff --git a/Task/tests/TaskCondition.test.mq5 b/Task/tests/TaskCondition.test.mq5 index aeef3cede..ad8f241b0 100644 --- a/Task/tests/TaskCondition.test.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -43,7 +43,7 @@ class TaskConditionTest01 : public TaskConditionBase { long GetSum() { return sum; } bool Check(const TaskConditionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); return true; } }; @@ -57,7 +57,7 @@ class TaskConditionTest02 : public TaskConditionBase { long GetSum() { return sum; } bool Check(const TaskConditionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); return true; } }; diff --git a/Task/tests/Taskable.test.mq5 b/Task/tests/Taskable.test.mq5 index 9bbd4519d..38160113a 100644 --- a/Task/tests/Taskable.test.mq5 +++ b/Task/tests/Taskable.test.mq5 @@ -28,32 +28,53 @@ #include "../../Test.mqh" #include "../Taskable.h" -class TaskTest01 : public Taskable { +// Defines structure. +struct TaskableIntValue { protected: - long sum; + int value; // Field to store a double type. + public: + TaskableIntValue() : value(0) {} + void SetValue(int _value) { value = _value; } +}; + +// Defines class. +class TaskTest01 : public Taskable { + protected: + int sum; + TaskableIntValue data; public: TaskTest01() : sum(0){}; - long GetSum() { return sum; } + int GetSum() { return sum; } + + /* Taskable methods */ /** * Checks a condition. */ bool Check(const TaskConditionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); - return true; + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); + return sum > 0; } - /* Main methods */ + /** + * Gets a copy of structure. + */ + TaskableIntValue Get(const TaskGetterEntry &_entry) { + sum += _entry.GetId(); + data.SetValue(sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); + return data; + } /** * Runs an action. */ - virtual bool Run(const TaskActionEntry &_entry) { + bool Run(const TaskActionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); - return true; + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); + return sum > 0; } }; @@ -63,14 +84,20 @@ class TaskTest01 : public Taskable { int OnInit() { bool _result = true; TaskTest01 _test01; - // Checks dummy condition. - TaskConditionEntry _entry_cond(2); - _result &= _test01.Check(_entry_cond); - // Runs dummy action. + // Runs a dummy action. TaskActionEntry _entry_action(2); _result &= _test01.Run(_entry_action); + _result &= _entry_action.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); + // Checks a dummy condition. + TaskConditionEntry _entry_cond(2); + _result &= _test01.Check(_entry_cond); + _result &= _entry_cond.Get(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)); + // Gets a dummy value. + TaskGetterEntry _entry_get(2); + TaskableIntValue _value = _test01.Get(_entry_get); + _result &= _entry_get.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); // Checks the results. - assertTrueOrFail(_result && _test01.GetSum() == 4, "Fail!"); + assertTrueOrFail(_result && _test01.GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From ad5c9748075e0f9781b706f8e898a5c71cdd925f Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 27 Oct 2021 21:24:54 +0100 Subject: [PATCH 13/84] Task: Adds TaskSetter class --- .github/workflows/test-task.yml | 1 + Task/TaskGetter.h | 2 +- Task/TaskSetter.h | 133 +++++++++++++++++++++++++ Task/TaskSetter.struct.h | 170 ++++++++++++++++++++++++++++++++ Task/TaskSetterBase.h | 58 +++++++++++ Task/tests/TaskSetter.test.mq4 | 28 ++++++ Task/tests/TaskSetter.test.mq5 | 85 ++++++++++++++++ 7 files changed, 476 insertions(+), 1 deletion(-) create mode 100644 Task/TaskSetter.h create mode 100644 Task/TaskSetter.struct.h create mode 100644 Task/TaskSetterBase.h create mode 100644 Task/tests/TaskSetter.test.mq4 create mode 100644 Task/tests/TaskSetter.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index d5869346f..e0b0458c6 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -53,6 +53,7 @@ jobs: - TaskAction.test - TaskCondition.test - TaskGetter.test + - TaskSetter.test steps: - uses: actions/download-artifact@v2 with: diff --git a/Task/TaskGetter.h b/Task/TaskGetter.h index b25ac67f1..ee81da1a9 100644 --- a/Task/TaskGetter.h +++ b/Task/TaskGetter.h @@ -114,7 +114,7 @@ class TaskGetter : protected TaskGetterBase { /* TaskGetterBase methods */ /** - * Runs an action. + * Gets a copy of structure. */ TS Get(const TaskGetterEntry &_entry) { TS _result; diff --git a/Task/TaskSetter.h b/Task/TaskSetter.h new file mode 100644 index 000000000..031da2b3d --- /dev/null +++ b/Task/TaskSetter.h @@ -0,0 +1,133 @@ +//+------------------------------------------------------------------+ +//| 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 + * Provides integration with task's actions. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_SETTER_H +#define TASK_SETTER_H + +// Includes. +//#include "TaskSetter.enum.h" +#include "TaskSetter.struct.h" +#include "TaskSetterBase.h" + +/** + * TaskSetter class. + */ +template +class TaskSetter : protected TaskSetterBase { + protected: + // Protected class variables. + TaskSetterEntry entry; // Setter entry. + TO obj; // Object to run the action on. + + public: + /* Special methods */ + + /** + * Default class constructor. + */ + TaskSetter() {} + + /** + * Class constructor with an entry as argument. + */ + TaskSetter(TaskSetterEntry &_entry) : entry(_entry) {} + + /* Main methods */ + + /** + * Runs a current stored action. + */ + bool Set(const TS &_entry_value) { + bool _result = obj.Set(entry, _entry_value); + entry.Set(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_TIME_LAST_GET), TimeCurrent()); + entry.TriesDec(); + return _result; + } + + /* Setters */ + + /** + * Gets an entry's flag. + */ + bool Get(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag) const { return entry.Get(_flag); } + + /** + * Gets an entry's property value. + */ + template + T Get(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_PROP) _prop) const { + entry.Get(_prop); + } + + /** + * Gets a reference to the object. + */ + TO *GetObject() { return GetPointer(obj); } + + /* Setters */ + + /** + * Sets an entry's flag. + */ + void Set(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag, bool _value = true) { + entry.Set(_flag, _value); + } + + /** + * Sets an entry's property value. + */ + template + void Set(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_PROP) _prop, T _value) { + entry.Set(_prop, _value); + } + + /* TaskSetterBase methods */ + + /** + * Sets entry value. + */ + bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) { + bool _result = false; + switch (_entry.GetId()) { + case 0: + _result = Set(_entry_value); + break; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + return _result; + } +}; + +#endif // TASK_SETTER_H diff --git a/Task/TaskSetter.struct.h b/Task/TaskSetter.struct.h new file mode 100644 index 000000000..d33715ca3 --- /dev/null +++ b/Task/TaskSetter.struct.h @@ -0,0 +1,170 @@ +//+------------------------------------------------------------------+ +//| 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 TaskSetter's structures. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Data.struct.h" +#include "../Std.h" +#include "Task.enum.h" + +/* Entry for TaskSetter class. */ +struct TaskSetterEntry { + public: + /* Enumerations */ + + // Defines action entry properties. + enum ENUM_TASK_SETTER_ENTRY_PROP { + TASK_SETTER_ENTRY_FLAGS, + TASK_SETTER_ENTRY_FREQUENCY, + TASK_SETTER_ENTRY_ID, + TASK_SETTER_ENTRY_TRIES, + TASK_SETTER_ENTRY_TIME_LAST_GET, + }; + // Defines action entry flags. + enum ENUM_TASK_SETTER_ENTRY_FLAG { + TASK_SETTER_ENTRY_FLAG_NONE = 0 << 0, + TASK_SETTER_ENTRY_FLAG_IS_ACTIVE = 1 << 0, + TASK_SETTER_ENTRY_FLAG_IS_DONE = 1 << 1, + TASK_SETTER_ENTRY_FLAG_IS_FAILED = 1 << 2, + TASK_SETTER_ENTRY_FLAG_IS_INVALID = 1 << 3, + }; + + protected: + unsigned char flags; /* TaskSetter flags. */ + datetime time_last_get; /* Time of the successful get. */ + int freq; /* How often to run (0 for no limit). */ + int id; /* TaskSetter's enum ID. */ + short tries; /* Number of retries left (-1 for unlimited). */ + DataParamEntry args[]; /* TaskSetter arguments. */ + protected: + // Protected methods. + void Init() { SetFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + + public: + // Constructors. + TaskSetterEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_get(0), tries(-1) { Init(); } + TaskSetterEntry(int _id) + : flags(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_ACTIVE)), + id(_id), + freq(60), + time_last_get(0), + tries(-1) { + Init(); + } + TaskSetterEntry(TaskSetterEntry &_ae) { this = _ae; } + // Flag methods. + bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } + void AddFlags(unsigned char _flags) { flags |= _flags; } + void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void SetFlag(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag, bool _value) { + if (_value) { + AddFlags(_flag); + } else { + RemoveFlags(_flag); + } + } + void SetFlags(unsigned char _flags) { flags = _flags; } + // State methods. + bool HasTriesLeft() const { return tries > 0 || tries == -1; } + bool IsActive() const { return HasFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_ACTIVE)); } + bool IsDone() const { return HasFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_DONE)); } + bool IsFailed() const { return HasFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_FAILED)); } + bool IsInvalid() const { return HasFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_INVALID)); } + bool IsValid() const { return !IsInvalid(); } + // Setters. + bool Get(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag) const { return HasFlag(_flag); } + template + T Get(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_PROP) _prop) const { + switch (_prop) { + case TASK_SETTER_ENTRY_FLAGS: + return (T)flags; + case TASK_SETTER_ENTRY_FREQUENCY: + return (T)freq; + case TASK_SETTER_ENTRY_ID: + return (T)id; + case TASK_SETTER_ENTRY_TRIES: + return (T)tries; + case TASK_SETTER_ENTRY_TIME_LAST_RUN: + return (T)time_last_run; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + int GetId() const { return id; } + // Setters. + void TriesDec() { tries -= tries > 0 ? 1 : 0; } + void Set(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag, bool _value = true) { + SetFlag(_flag, _value); + } + template + void Set(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_PROP) _prop, T _value) { + switch (_prop) { + case TASK_SETTER_ENTRY_FLAGS: // ID (magic number). + flags = (unsigned char)_value; + return; + case TASK_SETTER_ENTRY_FREQUENCY: + freq = (int)_value; + return; + case TASK_SETTER_ENTRY_ID: + id = (int)_value; + SetFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + return; + case TASK_SETTER_ENTRY_TRIES: + tries = (short)_value; + return; + case TASK_SETTER_ENTRY_TIME_LAST_GET: + time_last_get = (datetime)_value; + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + } + void AddArg(MqlParam &_arg) { + // @todo: Add another value to args[]. + } + void SetArgs(ARRAY_REF(MqlParam, _args)) { + // @todo: for(). + } + // Serializers + SerializerNodeType Serialize(Serializer &s) { + s.Pass(THIS_REF, "flags", flags); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "time_last_get", time_last_get); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); + s.PassArray(this, "args", args); + return SerializerNodeObject; + } + + SERIALIZER_EMPTY_STUB; +}; diff --git a/Task/TaskSetterBase.h b/Task/TaskSetterBase.h new file mode 100644 index 000000000..88896f915 --- /dev/null +++ b/Task/TaskSetterBase.h @@ -0,0 +1,58 @@ +//+------------------------------------------------------------------+ +//| 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 + * Provides a base class for a task's getter. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_SETTER_BASE_H +#define TASK_SETTER_BASE_H + +/** + * TaskSetterBase class. + */ +template +class TaskSetterBase { + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskSetterBase() {} + + /* Main methods */ + + /** + * Sets entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) = NULL; +}; + +#endif // TASK_SETTER_BASE_H diff --git a/Task/tests/TaskSetter.test.mq4 b/Task/tests/TaskSetter.test.mq4 new file mode 100644 index 000000000..8c3ebc2c1 --- /dev/null +++ b/Task/tests/TaskSetter.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskSetter class. + */ + +// Includes. +#include "TaskSetter.test.mq5" diff --git a/Task/tests/TaskSetter.test.mq5 b/Task/tests/TaskSetter.test.mq5 new file mode 100644 index 000000000..6769309c7 --- /dev/null +++ b/Task/tests/TaskSetter.test.mq5 @@ -0,0 +1,85 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskSetter class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../TaskSetter.h" + +enum ENUM_TASK_SETTER_TEST { + TASK_SETTER_TEST01 = 1, + TASK_SETTER_TEST02 = 2, + TASK_SETTER_TEST03 = 3, +}; + +struct TaskSetterTest01Data { + int value; + TaskSetterTest01Data(int _value) : value(_value) {} + int GetValue() const { return value; } + void SetValue(int _value) { value = _value; } +}; + +class TaskSetterTest01 : protected TaskSetterBase { + protected: + TaskSetterTest01Data data; + + public: + TaskSetterTest01() : data(0) {}; + int GetValue() const { return data.GetValue(); } + bool Set(const TaskSetterEntry &_entry, const TaskSetterTest01Data &_entry_value) { + data.SetValue(data.GetValue() + _entry_value.GetValue()); + PrintFormat("Set: %s; value=%d", __FUNCSIG__, data.GetValue()); + return true; + } +}; + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + // Test01 + TaskSetterEntry _entry01(TASK_SETTER_TEST01); + TaskSetterTest01 _test01; + TaskSetterTest01Data _data_entry(1); + _result &= _test01.Set(_entry01, _data_entry); + _data_entry.SetValue(2); + _result &= _test01.Set(_entry01, _data_entry); + _data_entry.SetValue(3); + _result &= _test01.Set(_entry01, _data_entry); + assertTrueOrFail(_result && _test01.GetValue() == 6, "Fail!"); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From aafa1972abe9fed4233d8f76fe53baf5e1a29f26 Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 27 Oct 2021 21:48:11 +0100 Subject: [PATCH 14/84] Task: Adds Set() integration to Taskable --- Task/TaskSetter.h | 4 ++-- Task/TaskSetterBase.h | 2 +- Task/Taskable.h | 6 ++++++ Task/tests/Taskable.test.mq5 | 17 ++++++++++++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Task/TaskSetter.h b/Task/TaskSetter.h index 031da2b3d..a08f01957 100644 --- a/Task/TaskSetter.h +++ b/Task/TaskSetter.h @@ -67,7 +67,7 @@ class TaskSetter : protected TaskSetterBase { /** * Runs a current stored action. */ - bool Set(const TS &_entry_value) { + bool Set(const TS &_entry_value) { bool _result = obj.Set(entry, _entry_value); entry.Set(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_TIME_LAST_GET), TimeCurrent()); entry.TriesDec(); @@ -114,7 +114,7 @@ class TaskSetter : protected TaskSetterBase { /* TaskSetterBase methods */ /** - * Sets entry value. + * Sets an entry value. */ bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) { bool _result = false; diff --git a/Task/TaskSetterBase.h b/Task/TaskSetterBase.h index 88896f915..2b6f0ca84 100644 --- a/Task/TaskSetterBase.h +++ b/Task/TaskSetterBase.h @@ -50,7 +50,7 @@ class TaskSetterBase { /* Main methods */ /** - * Sets entry value. + * Sets an entry value. */ virtual bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) = NULL; }; diff --git a/Task/Taskable.h b/Task/Taskable.h index 88345b0ee..fe610aa77 100644 --- a/Task/Taskable.h +++ b/Task/Taskable.h @@ -38,6 +38,7 @@ #include "TaskAction.h" #include "TaskCondition.h" #include "TaskGetter.h" +#include "TaskSetter.h" /** * Taskable class. @@ -68,6 +69,11 @@ class Taskable { * Runs an action. */ virtual bool Run(const TaskActionEntry &_entry) = NULL; + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) = NULL; }; #endif // TASKABLE_H diff --git a/Task/tests/Taskable.test.mq5 b/Task/tests/Taskable.test.mq5 index 38160113a..16c01a8de 100644 --- a/Task/tests/Taskable.test.mq5 +++ b/Task/tests/Taskable.test.mq5 @@ -34,6 +34,7 @@ struct TaskableIntValue { int value; // Field to store a double type. public: TaskableIntValue() : value(0) {} + int GetValue() { return value; } void SetValue(int _value) { value = _value; } }; @@ -76,6 +77,16 @@ class TaskTest01 : public Taskable { PrintFormat("%s; sum=%d", __FUNCSIG__, sum); return sum > 0; } + + /** + * Sets an entry value. + */ + bool Set(const TaskSetterEntry &_entry, const TaskableIntValue &_entry_value) { + sum += _entry.GetId(); + data.SetValue(sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, data.GetValue()); + return data.GetValue() > 0; + } }; /** @@ -96,8 +107,12 @@ int OnInit() { TaskGetterEntry _entry_get(2); TaskableIntValue _value = _test01.Get(_entry_get); _result &= _entry_get.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); + // Sets a dummy value. + TaskSetterEntry _entry_set(2); + _result &= _test01.Set(_entry_set, _value); + _result &= _entry_get.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); // Checks the results. - assertTrueOrFail(_result && _test01.GetSum() == 6, "Fail!"); + assertTrueOrFail(_result && _test01.GetSum() == 8, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From 00d470c41b4b22168c8120a30e90eb0f4e01849f Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 28 Oct 2021 00:27:18 +0100 Subject: [PATCH 15/84] Task/TaskGetter: Improves logic and test --- Task/TaskGetter.h | 12 +++--------- Task/tests/TaskGetter.test.mq5 | 23 ++++++++++++++--------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Task/TaskGetter.h b/Task/TaskGetter.h index ee81da1a9..6d28ee9f8 100644 --- a/Task/TaskGetter.h +++ b/Task/TaskGetter.h @@ -42,12 +42,11 @@ /** * TaskGetter class. */ -template -class TaskGetter : protected TaskGetterBase { +template +class TaskGetter : public TaskGetterBase { protected: // Protected class variables. TaskGetterEntry entry; // Getter entry. - TO obj; // Object to run the action on. public: /* Special methods */ @@ -68,7 +67,7 @@ class TaskGetter : protected TaskGetterBase { * Runs a current stored action. */ TS Get() { - TS _result = obj.Get(entry); + TS _result = Get(entry); entry.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_TIME_LAST_GET), TimeCurrent()); entry.TriesDec(); return _result; @@ -89,11 +88,6 @@ class TaskGetter : protected TaskGetterBase { entry.Get(_prop); } - /** - * Gets a reference to the object. - */ - TO *GetObject() { return GetPointer(obj); } - /* Setters */ /** diff --git a/Task/tests/TaskGetter.test.mq5 b/Task/tests/TaskGetter.test.mq5 index 05760ff6a..8a8761597 100644 --- a/Task/tests/TaskGetter.test.mq5 +++ b/Task/tests/TaskGetter.test.mq5 @@ -41,13 +41,14 @@ struct TaskGetterTest01Data { void SetValue(int _value) { value = _value; } }; -class TaskGetterTest01 : protected TaskGetterBase { +class TaskGetterTest01 : public TaskGetter { protected: TaskGetterTest01Data data; public: TaskGetterTest01(){}; // long GetSum() { return sum; } + TaskGetterTest01Data Get() { return TaskGetter::Get(); } TaskGetterTest01Data Get(const TaskGetterEntry &_entry) { data.SetValue(_entry.GetId()); PrintFormat("Get: %s; value=%d", __FUNCSIG__, data.GetValue()); @@ -62,15 +63,19 @@ int OnInit() { bool _result = true; int _sum = 0; // Test01 + TaskGetterTest01 _test01; TaskGetterEntry _entry01(TASK_GETTER_TEST01); - TaskGetter _getter01(_entry01); - _result &= _getter01.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); - _sum += _getter01.Get().GetValue(); - _getter01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST02); - _sum += _getter01.Get().GetValue(); - _getter01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST03); - _sum += _getter01.Get().GetValue(); - assertTrueOrFail(_result && _sum == 6, "Fail!"); + _result &= _entry01.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); + _test01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST01); + _sum += _test01.Get().GetValue(); + _sum += _test01.Get(_entry01).GetValue(); + _test01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST02); + _sum += _test01.Get().GetValue(); + _sum += _test01.Get(_entry01).GetValue(); + _test01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST03); + _sum += _test01.Get().GetValue(); + _sum += _test01.Get(_entry01).GetValue(); + assertTrueOrFail(_result && _sum == 9, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From 25945cc55c5238e15740841538589d07238206cc Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 8 Jan 2022 23:25:02 +0000 Subject: [PATCH 16/84] Improves tasks return logic --- EA.mqh | 6 ++++-- Strategy.mqh | 9 +++++---- Trade.mqh | 43 +++++++++++++++++++++---------------------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/EA.mqh b/EA.mqh index a8525712d..033820ac7 100644 --- a/EA.mqh +++ b/EA.mqh @@ -882,6 +882,7 @@ class EA { * Returns true when the condition is met. */ bool CheckCondition(ENUM_EA_CONDITION _cond, DataParamEntry &_args[]) { + bool _result = false; switch (_cond) { case EA_COND_IS_ACTIVE: return estate.IsActive(); @@ -908,8 +909,9 @@ class EA { return estate.IsOnQuit(); default: logger.Error(StringFormat("Invalid EA condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - return false; + break; } + return _result; } bool CheckCondition(ENUM_EA_CONDITION _cond) { ARRAY(DataParamEntry, _args); @@ -925,7 +927,7 @@ class EA { * Returns true when the action has been executed successfully. */ bool ExecuteAction(ENUM_EA_ACTION _action, DataParamEntry &_args[]) { - bool _result = true; + bool _result = false; long arg_size = ArraySize(_args); switch (_action) { case EA_ACTION_DISABLE: diff --git a/Strategy.mqh b/Strategy.mqh index c8bed49a1..38b412f66 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -684,7 +684,7 @@ class Strategy : public Object { * Returns true when the condition is met. */ bool CheckCondition(ENUM_STRATEGY_CONDITION _cond, DataParamEntry &_args[]) { - bool _result = true; + bool _result = false; long arg_size = ArraySize(_args); long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; @@ -718,8 +718,9 @@ class Strategy : public Object { return _result; default: GetLogger().Error(StringFormat("Invalid EA condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - return false; + break; } + return _result; } bool CheckCondition(ENUM_STRATEGY_CONDITION _cond, long _arg1) { ARRAY(DataParamEntry, _args); @@ -751,7 +752,7 @@ class Strategy : public Object { * Returns true when the action has been executed successfully. */ bool ExecuteAction(ENUM_STRATEGY_ACTION _action, DataParamEntry &_args[]) { - bool _result = true; + bool _result = false; double arg1d = EMPTY_VALUE; double arg2d = EMPTY_VALUE; double arg3d = EMPTY_VALUE; @@ -813,7 +814,7 @@ class Strategy : public Object { return true; default: GetLogger().Error(StringFormat("Invalid Strategy action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - return false; + break; } return _result; } diff --git a/Trade.mqh b/Trade.mqh index bc01e1f56..1d5a2a64e 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -1729,7 +1729,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * Returns true when the condition is met. */ bool CheckCondition(ENUM_TRADE_CONDITION _cond, DataParamEntry &_args[]) { - bool _result = true; + bool _result = false; long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; Ref _oquery_ref; @@ -1798,7 +1798,6 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // case TRADE_ORDER_CONDS_IN_TREND_NOT: default: logger.Error(StringFormat("Invalid trade condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - _result = false; break; } return _result; @@ -1827,7 +1826,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * Returns true when the condition is met. */ bool ExecuteAction(ENUM_TRADE_ACTION _action, DataParamEntry &_args[]) { - bool _result = true; + bool _result = false; Ref _oquery_ref; if (Get(TRADE_STATE_ORDERS_ACTIVE)) { _oquery_ref = OrderQuery::GetInstance(orders_active); @@ -1852,21 +1851,21 @@ 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.Ptr() + .FindByPropViaOp(ORDER_PROP_PROFIT, + STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_LT)) + .Ptr() + .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.Ptr() + .FindByPropViaOp(ORDER_PROP_PROFIT, + STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_GT)) + .Ptr() + .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); RefreshActiveOrders(true, true); } break; @@ -1874,33 +1873,33 @@ HistorySelect(0, TimeCurrent()); // Select history for access. return RequestSend(GetTradeOpenRequest((ENUM_ORDER_TYPE)_args[0].integer_value)); case TRADE_ACTION_ORDERS_CLOSE_ALL: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result &= OrdersCloseAll(ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseAll(ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; case TRADE_ACTION_ORDERS_CLOSE_IN_PROFIT: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result &= OrdersCloseViaProp( - ORDER_PROP_PROFIT_PIPS, (int)chart.Ptr().GetSpreadInPips(), MATH_COND_GT, - ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaProp( + ORDER_PROP_PROFIT_PIPS, (int)chart.Ptr().GetSpreadInPips(), MATH_COND_GT, + ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; case TRADE_ACTION_ORDERS_CLOSE_IN_TREND: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result &= OrdersCloseViaCmd(GetTrendOp(0), 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(0)), ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd(Order::NegateOrderType(GetTrendOp(0)), ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; case TRADE_ACTION_ORDERS_CLOSE_BY_TYPE: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result &= OrdersCloseViaCmd((ENUM_ORDER_TYPE)_args[0].integer_value, ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd((ENUM_ORDER_TYPE)_args[0].integer_value, ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; @@ -1911,7 +1910,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _oquery_ref.Ptr() .FindPropBySum( _order_types1, ORDER_PROP_PROFIT, ORDER_TYPE); - _result &= + _result = OrdersCloseViaCmd(Order::NegateOrderType(_order_type_profitable), ORDER_REASON_CLOSED_BY_ACTION) >= 0; } break; @@ -1922,7 +1921,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _oquery_ref.Ptr() .FindPropBySum( _order_types2, ORDER_PROP_PROFIT, ORDER_TYPE); - _result &= OrdersCloseViaCmd(_order_type_profitable2, ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd(_order_type_profitable2, ORDER_REASON_CLOSED_BY_ACTION) >= 0; } break; case TRADE_ACTION_ORDERS_LIMIT_SET: From 63cb49f6de42e6aa1196912a73140a8873a55daf Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 15 Jan 2022 23:15:49 +0000 Subject: [PATCH 17/84] Task: TaskEntry: Uses int for getters --- Task/Task.struct.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 5d8061c62..787e763cc 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -77,8 +77,8 @@ struct TaskEntry { // bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); } bool IsValid() { return action.IsValid() && cond.IsValid(); } // Getters. - long GetActionId() { return action.GetId(); } - long GetConditionId() { return cond.GetId(); } + int GetActionId() { return action.GetId(); } + int GetConditionId() { return cond.GetId(); } TaskActionEntry GetAction() { return action; } TaskConditionEntry GetCondition() { return cond; } }; From 8c21c329d68c77cac3164404300cf06fa3ea3939 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 15 Jan 2022 23:16:23 +0000 Subject: [PATCH 18/84] EA: Inherits from Taskable --- EA.mqh | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/EA.mqh b/EA.mqh index 033820ac7..841e822cb 100644 --- a/EA.mqh +++ b/EA.mqh @@ -52,7 +52,7 @@ #include "Trade/TradeSignal.h" #include "Trade/TradeSignalManager.h" -class EA { +class EA : public Taskable { protected: // Class variables. Account *account; @@ -663,9 +663,9 @@ class EA { */ bool TaskAdd(TaskEntry &_entry) { bool _result = false; - /* @fixme if (_entry.IsValid()) { - switch (_entry.GetConditionType()) { + /* @fixme + switch (_entry.GetConditionId()) { case COND_TYPE_ACCOUNT: _entry.SetConditionObject(account); break; @@ -676,7 +676,7 @@ class EA { _entry.SetConditionObject(trade.GetByKey(_Symbol)); break; } - switch (_entry.GetActionType()) { + switch (_entry.GetActionId()) { case ACTION_TYPE_EA: _entry.SetActionObject(THIS_PTR); break; @@ -684,9 +684,9 @@ class EA { _entry.SetActionObject(trade.GetByKey(_Symbol)); break; } + */ _result |= tasks.Push(_entry); } - */ return _result; } @@ -981,6 +981,57 @@ class EA { return EA::ExecuteAction(_action, _args); } + /* Tasks */ + + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Gets a copy of structure. + */ + virtual DataParamEntry Get(const TaskGetterEntry &_entry) { + DataParamEntry _result; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const DataParamEntry &_entry_value) { + bool _result = false; + switch (_entry.GetId()) { + // _entry_value.GetValue() + default: + break; + } + return _result; + } + /* Getters */ /** From 691b5a8bdae058dd72aa4e49639f5eb4e3d13e64 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 15 Jan 2022 23:34:23 +0000 Subject: [PATCH 19/84] Taskable: Inherits from Object --- Task/Taskable.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Task/Taskable.h b/Task/Taskable.h index fe610aa77..f6adcae25 100644 --- a/Task/Taskable.h +++ b/Task/Taskable.h @@ -35,6 +35,7 @@ #define TASKABLE_H // Includes. +#include "../Object.mqh" #include "TaskAction.h" #include "TaskCondition.h" #include "TaskGetter.h" @@ -44,14 +45,14 @@ * Taskable class. */ template -class Taskable { +class Taskable : public Object { public: /* Special methods */ /** - * Class constructor. + * Class constructor with default arguments. */ - Taskable() {} + Taskable() : Object(GetPointer(this), __LINE__) {} /* Virtual methods */ From 9fdb894ca4ed56b857bf95e6a3189e13ca1e031c Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 15 Jan 2022 23:34:37 +0000 Subject: [PATCH 20/84] Strategy: Inherits from Taskable --- EA.mqh | 3 +-- Strategy.mqh | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/EA.mqh b/EA.mqh index 841e822cb..40e5b1610 100644 --- a/EA.mqh +++ b/EA.mqh @@ -45,8 +45,7 @@ #include "Strategy.mqh" #include "SummaryReport.mqh" #include "Task/Task.h" -#include "Task/TaskAction.enum.h" -#include "Task/TaskCondition.enum.h" +#include "Task/Taskable.h" #include "Terminal.mqh" #include "Trade.mqh" #include "Trade/TradeSignal.h" diff --git a/Strategy.mqh b/Strategy.mqh index 38b412f66..15ec64f03 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -37,6 +37,7 @@ class Trade; #include "Strategy.struct.h" #include "String.mqh" #include "Task/Task.h" +#include "Task/Taskable.h" #include "Trade.mqh" // Defines. @@ -85,7 +86,7 @@ class Trade; /** * Implements strategy class. */ -class Strategy : public Object { +class Strategy : public Taskable { public: StgParams sparams; @@ -122,7 +123,7 @@ class Strategy : public Object { * Class constructor. */ Strategy(StgParams &_sparams, TradeParams &_tparams, ChartParams &_cparams, string _name = "") - : sparams(_sparams), trade(_tparams, _cparams), Object(GetPointer(this), __LINE__) { + : sparams(_sparams), trade(_tparams, _cparams) { // Initialize variables. name = _name; MqlTick _tick = {0}; @@ -1254,6 +1255,57 @@ class Strategy : public Object { return _result; }; + /* Tasks */ + + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Gets a copy of structure. + */ + virtual DataParamEntry Get(const TaskGetterEntry &_entry) { + DataParamEntry _result; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const DataParamEntry &_entry_value) { + bool _result = false; + switch (_entry.GetId()) { + // _entry_value.GetValue() + default: + break; + } + return _result; + } + /* Serializers */ /** From a223bc39dc03dff9fad5b63a1dccb43bcf69cdb2 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 16:06:13 +0000 Subject: [PATCH 21/84] IndicatorsTest: Fixes Indi_Drawer --- tests/IndicatorsTest.mq5 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 5d44e708b..880056e03 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -390,12 +390,12 @@ bool InitIndicators() { indi_rsi_on_price.Ptr().SetDataSource(indi_price_4_rsi.Ptr()); indis.Push(indi_rsi_on_price.Ptr()); - // Drawer (socket-based) indicator. + // Drawer (socket-based) indicator over RSI over Price. IndiDrawerParams drawer_params(14, /*unused*/ PRICE_OPEN); - // drawer_params.SetIndicatorData(indi_price_4_rsi); - // drawer_params.SetIndicatorMode(INDI_PRICE_MODE_OPEN); drawer_params.SetDraw(clrBisque, 0); - indis.Push(_indi_drawer = new Indi_Drawer(drawer_params)); + Ref indi_drawer_on_rsi = new Indi_Drawer(drawer_params); + indi_drawer_on_rsi.Ptr().SetDataSource(indi_rsi_on_price.Ptr(), PRICE_OPEN); + indis.Push(indi_drawer_on_rsi.Ptr()); // Applied Price over OHCL indicator. IndiAppliedPriceParams applied_price_params(); From 86b9c39b2b200f67a5cab0c88d97827c7f972f92 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 19:26:43 +0000 Subject: [PATCH 22/84] Task/TaskAction: Adds GetArg() --- Task/TaskAction.struct.h | 1 + Task/TaskCondition.struct.h | 1 + 2 files changed, 2 insertions(+) diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 7014144c6..ab7db5b16 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -119,6 +119,7 @@ struct TaskActionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } + DataParamEntry GetArg(int _index) { return args[_index]; } int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index bbd1c557e..1485a49d7 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -109,6 +109,7 @@ struct TaskConditionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } + DataParamEntry GetArg(int _index) { return args[_index]; } int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } From 4b9fe8055450da93deeec26e35195a9f07ff0104 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 19:47:16 +0000 Subject: [PATCH 23/84] Indi_Drawer: Do not enforce double --- Indicators/Indi_Drawer.mqh | 2 -- 1 file changed, 2 deletions(-) diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index 896e0a830..b18eebf98 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -72,8 +72,6 @@ class Indi_Drawer : public Indicator { int num_args = ArraySize(_args), i; IndicatorDataEntry entry(num_args - 1); - // @fixit Not sure if we should enforce double. - entry.AddFlags(INDI_ENTRY_FLAG_IS_DOUBLE); if (_action == INDI_ACTION_SET_VALUE) { iparams.SetMaxModes(num_args - 1); From 0a022cfd2524150298542d531b4bd62c1d8cb6d1 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 19:26:58 +0000 Subject: [PATCH 24/84] Adds Taskable.car.test --- .github/workflows/test-task.yml | 3 +- Task/tests/TaskSetter.test.mq5 | 2 +- Task/tests/Taskable.car.test.mq4 | 28 +++++ Task/tests/Taskable.car.test.mq5 | 203 +++++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 Task/tests/Taskable.car.test.mq4 create mode 100644 Task/tests/Taskable.car.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index e0b0458c6..3a4e6abe8 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -49,11 +49,12 @@ jobs: matrix: test: - Task.test - - Taskable.test - TaskAction.test - TaskCondition.test - TaskGetter.test - TaskSetter.test + - Taskable.car.test + - Taskable.test steps: - uses: actions/download-artifact@v2 with: diff --git a/Task/tests/TaskSetter.test.mq5 b/Task/tests/TaskSetter.test.mq5 index 6769309c7..50fb1688e 100644 --- a/Task/tests/TaskSetter.test.mq5 +++ b/Task/tests/TaskSetter.test.mq5 @@ -46,7 +46,7 @@ class TaskSetterTest01 : protected TaskSetterBase { TaskSetterTest01Data data; public: - TaskSetterTest01() : data(0) {}; + TaskSetterTest01() : data(0){}; int GetValue() const { return data.GetValue(); } bool Set(const TaskSetterEntry &_entry, const TaskSetterTest01Data &_entry_value) { data.SetValue(data.GetValue() + _entry_value.GetValue()); diff --git a/Task/tests/Taskable.car.test.mq4 b/Task/tests/Taskable.car.test.mq4 new file mode 100644 index 000000000..ad723ca6d --- /dev/null +++ b/Task/tests/Taskable.car.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Taskable class. + */ + +// Includes. +#include "Taskable.car.test.mq5" diff --git a/Task/tests/Taskable.car.test.mq5 b/Task/tests/Taskable.car.test.mq5 new file mode 100644 index 000000000..db002a564 --- /dev/null +++ b/Task/tests/Taskable.car.test.mq5 @@ -0,0 +1,203 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Task class. + */ + +// Forward declaration. +struct DataParamEntry; + +// Includes. +#include "../../Data.struct.h" +#include "../../Test.mqh" +#include "../Task.h" + +// Implements test classes. +class Car : public Taskable { + protected: + enum ENUM_CAR_ACTION { + CAR_ACTION_NONE = 0, + CAR_ACTION_CONTINUE, + CAR_ACTION_SPEED_DEC_BY, + CAR_ACTION_SPEED_INC_BY, + CAR_ACTION_SPEED_SET_BY, + CAR_ACTION_STOP, + }; + enum ENUM_CAR_COND { + CAR_COND_NONE = 0, + CAR_COND_NEEDS_SERVICE, + CAR_COND_IS_MOVING_BACKWARD, + CAR_COND_IS_MOVING_FORWARD, + CAR_COND_IS_SPEED_MAX, + CAR_COND_IS_STOPPED, + }; + enum ENUM_CAR_PROP { + CAR_PROP_NONE = 0, + CAR_PROP_MILEAGE_CURR, + CAR_PROP_MILEAGE_MAX, + CAR_PROP_SPEED, + }; + int mileage_curr, mileage_max, speed_curr, speed_max; + + public: + Car(int _speed_max = 100, int _mileage_max = 10000) : mileage_curr(0), speed_max(_speed_max) {} + + /* Tasks */ + + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + case CAR_COND_NEEDS_SERVICE: + _result = mileage_curr > mileage_max; + break; + case CAR_COND_IS_MOVING_BACKWARD: + _result = speed_curr < 0; + break; + case CAR_COND_IS_MOVING_FORWARD: + _result = speed_curr > 0; + break; + case CAR_COND_IS_SPEED_MAX: + _result = speed_curr >= speed_max; + break; + case CAR_COND_IS_STOPPED: + _result = speed_curr == 0; + break; + default: + break; + } + return _result; + } + + /** + * Gets a copy of structure. + */ + virtual DataParamEntry Get(const TaskGetterEntry &_entry) { + DataParamEntry _result; + switch (_entry.GetId()) { + case CAR_PROP_MILEAGE_CURR: + _result = mileage_curr; + break; + case CAR_PROP_MILEAGE_MAX: + _result = mileage_max; + break; + case CAR_PROP_SPEED: + _result = speed_curr; + break; + default: + break; + } + return _result; + } + template + DataParamEntry Get(E _id) { + TaskGetterEntry _entry(_id); + return Get(_entry); + }; + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + case CAR_ACTION_CONTINUE: + mileage_curr += speed_curr; + break; + case CAR_ACTION_SPEED_DEC_BY: + // speed_curr -= _entry.GetArg(); // @fixme + break; + case CAR_ACTION_SPEED_INC_BY: + // speed_curr += _entry.GetArg(); // @fixme + break; + case CAR_ACTION_SPEED_SET_BY: + // speed_curr = _entry.GetArg(); // @fixme + break; + case CAR_ACTION_STOP: + speed_curr = 0; + break; + default: + break; + } + return _result; + } + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const DataParamEntry &_entry_value) { + bool _result = true; + switch (_entry.GetId()) { + case CAR_PROP_MILEAGE_CURR: + // mileage_curr = _entry_value.ToValue(); // @fixme + break; + case CAR_PROP_MILEAGE_MAX: + // mileage_max = _entry_value.ToValue(); // @fixme + break; + case CAR_PROP_SPEED: + // speed_curr = _entry_value.ToValue(); // @fixme + break; + default: + _result = false; + break; + } + return _result; + } + template + DataParamEntry Set(E _id) { + TaskSetterEntry _entry(_id); + return Set(_entry); + }; +}; + +// Test if car can drive. +bool TestCarCanDrive() { + bool _result = true; + Car *_car = new Car(); + _result &= _car.Get(STRUCT_ENUM(Car, CAR_PROP_SPEED)).ToValue() == 0; + delete _car; + return _result; +} + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + // @todo + _result &= TestCarCanDrive(); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From 03bda7295b465f5b9b7e22189dad9fe708b68d33 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 20:33:44 +0000 Subject: [PATCH 25/84] Task/Task: Adds missing virtual methods --- Task/Task.h | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/Task/Task.h b/Task/Task.h index 5d0864b3b..60ce05399 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -116,6 +116,57 @@ class Task : protected Taskable { /* Task methods */ + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) { + bool _result = true; + switch (_entry.GetId()) { + default: + _result = false; + break; + } + return _result; + } + + /** + * Gets a copy of structure. + */ + virtual TaskEntry Get(const TaskGetterEntry &_entry) { + TaskEntry _result; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + bool _result = true; + switch (_entry.GetId()) { + default: + _result = false; + break; + } + return _result; + } + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const TaskEntry &_entry_value) { + bool _result = true; + switch (_entry.GetId()) { + default: + _result = false; + break; + } + return _result; + } + /* State methods */ /** From e5323fb61e50018357697dd0c95e953d73680cbc Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 20:35:02 +0000 Subject: [PATCH 26/84] Task.test: Adds TestTask01() --- Task/tests/Task.test.mq5 | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/Task/tests/Task.test.mq5 b/Task/tests/Task.test.mq5 index 623bd8d9e..24191b6f3 100644 --- a/Task/tests/Task.test.mq5 +++ b/Task/tests/Task.test.mq5 @@ -31,12 +31,50 @@ struct DataParamEntry; #include "../../Test.mqh" #include "../Task.h" +// Define test classes. +class ConditionType1 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ConditionType2 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ActionType1 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class ActionType2 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class TaskType1 : public Taskable { + bool Check(const TaskConditionEntry &_entry) { return true; } + MqlParam Get(const TaskGetterEntry &_entry) { + MqlParam _result; + return _result; + } + bool Run(const TaskActionEntry &_entry) { return true; } + bool Set(const TaskSetterEntry &_entry, const MqlParam &_entry_value) { return true; } +}; + +// Test 1. +bool TestTask01() { + bool _result = true; + Task _task1; + TaskAction _taction1; + TaskAction _taction2; + TaskCondition _tcond1; + TaskCondition _tcond2; + return _result; +} + /** * Implements Init event handler. */ int OnInit() { bool _result = true; - // @todo + _result &= TestTask01(); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From 4355fedf885d7addb53d13d95fb1169d1cb1793a Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 21:05:37 +0000 Subject: [PATCH 27/84] Task: Adds TaskObject --- .github/workflows/test-task.yml | 1 + Task/TaskAction.h | 2 +- Task/TaskCondition.h | 2 +- Task/TaskObject.h | 75 +++++++++++++++++++++++++++ Task/tests/TaskObject.test.mq4 | 28 ++++++++++ Task/tests/TaskObject.test.mq5 | 92 +++++++++++++++++++++++++++++++++ 6 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 Task/TaskObject.h create mode 100644 Task/tests/TaskObject.test.mq4 create mode 100644 Task/tests/TaskObject.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index 3a4e6abe8..52dd9346f 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -52,6 +52,7 @@ jobs: - TaskAction.test - TaskCondition.test - TaskGetter.test + - TaskObject.test - TaskSetter.test - Taskable.car.test - Taskable.test diff --git a/Task/TaskAction.h b/Task/TaskAction.h index db6c78745..4c647f98e 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -43,7 +43,7 @@ * TaskAction class. */ template -class TaskAction : protected TaskActionBase { +class TaskAction : public TaskActionBase { protected: // Protected class variables. TaskActionEntry entry; // Action entry. diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 21670e684..30214c373 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -43,7 +43,7 @@ * TaskCondition class. */ template -class TaskCondition : protected TaskConditionBase { +class TaskCondition : public TaskConditionBase { public: protected: // Protected class variables. diff --git a/Task/TaskObject.h b/Task/TaskObject.h new file mode 100644 index 000000000..38db316b9 --- /dev/null +++ b/Task/TaskObject.h @@ -0,0 +1,75 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides integration with tasks (manages conditions and actions). + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_OBJECT_H +#define TASK_OBJECT_H + +// Includes. +#include "Task.h" + +template +class TaskObject : protected Task { + protected: + TaskAction action; + TaskCondition condition; + + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskObject(TaskActionEntry &_aentry, TaskConditionEntry &_centry) : action(_aentry), condition(_centry) {} + + /** + * Class deconstructor. + */ + ~TaskObject() {} + + /* Main methods */ + + /** + * Process task entry. + * + * @return + * Returns true when tasks has been processed. + */ + static bool Process(TaskEntry &_entry) { + bool _result = false; + // @todo + return _result; + } + + /* Other methods */ +}; +#endif // TASK_OBJECT_H diff --git a/Task/tests/TaskObject.test.mq4 b/Task/tests/TaskObject.test.mq4 new file mode 100644 index 000000000..a6d856946 --- /dev/null +++ b/Task/tests/TaskObject.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskObject class. + */ + +// Includes. +#include "TaskObject.test.mq5" diff --git a/Task/tests/TaskObject.test.mq5 b/Task/tests/TaskObject.test.mq5 new file mode 100644 index 000000000..c47a394ae --- /dev/null +++ b/Task/tests/TaskObject.test.mq5 @@ -0,0 +1,92 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskObject class. + */ + +// Forward declaration. +struct DataParamEntry; + +// Includes. +#include "../../Test.mqh" +#include "../TaskObject.h" + +// Define test classes. +class ConditionType1 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ConditionType2 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ActionType1 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class ActionType2 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class TaskType1 : public Taskable { + bool Check(const TaskConditionEntry &_entry) { return true; } + MqlParam Get(const TaskGetterEntry &_entry) { + MqlParam _result; + return _result; + } + bool Run(const TaskActionEntry &_entry) { return true; } + bool Set(const TaskSetterEntry &_entry, const MqlParam &_entry_value) { return true; } +}; + +// Test 1. +bool TestTaskObject01() { + bool _result = true; + TaskActionEntry _aentry; + TaskConditionEntry _centry; + // TaskAction _taction1; + // TaskAction _taction2; + // TaskCondition _tcond1; + // TaskCondition _tcond2; + TaskObject _task1(_aentry, _centry); + return _result; +} + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + _result &= TestTaskObject01(); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From 912e3ef0b2f88b6084a2cef3d7d8eef600a4b2f8 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 17 Jan 2022 21:20:09 +0000 Subject: [PATCH 28/84] Task: Improves processing methods --- Task/Task.h | 27 +++++++++++------------ Task/Task.struct.h | 54 +++++++++++++++++++++++++++++++++++++++++++--- Task/TaskObject.h | 47 ++++++++++++++++++++++++++++++++++------ 3 files changed, 105 insertions(+), 23 deletions(-) diff --git a/Task/Task.h b/Task/Task.h index 60ce05399..1f937672d 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -72,13 +72,15 @@ class Task : protected Taskable { */ void Add(TaskEntry &_entry) { tasks.Push(_entry); } + /* Virtual methods */ + /** * Process tasks. * * @return * Returns true when tasks has been processed. */ - bool Process() { + virtual bool Process() { bool _result = true; for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { TaskEntry _entry = iter.Value(); @@ -93,24 +95,21 @@ class Task : protected Taskable { * @return * Returns true when tasks has been processed. */ - static bool Process(TaskEntry &_entry) { + virtual bool Process(TaskEntry &_entry) { bool _result = false; - /* @fixme if (_entry.IsActive()) { - if (TaskCondition::Test(_entry.GetCondition())) { - TaskActionEntry _action = _entry.GetAction(); - TaskAction::Execute(_action); - if (_action.IsDone()) { - _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, _action.IsDone()); - _entry.SetFlag(TASK_ENTRY_FLAG_IS_FAILED, _action.IsFailed()); - _entry.SetFlag(TASK_ENTRY_FLAG_IS_INVALID, _action.IsInvalid()); - _entry.RemoveFlags(TASK_ENTRY_FLAG_IS_ACTIVE); - } + _entry.Set(STRUCT_ENUM(TaskEntry, TASK_ENTRY_PROP_LAST_PROCESS), TimeCurrent()); + if (_entry.IsDone()) { + _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE))); + _entry.SetFlag(TASK_ENTRY_FLAG_IS_FAILED, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_FAILED))); + _entry.SetFlag(TASK_ENTRY_FLAG_IS_INVALID, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID))); + _entry.RemoveFlags(TASK_ENTRY_FLAG_IS_ACTIVE); } - _entry.last_process = TimeCurrent(); _result = true; } - */ return _result; } diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 787e763cc..f9cbf9815 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -36,6 +36,15 @@ #include "TaskCondition.struct.h" struct TaskEntry { + public: + /* Enumerations */ + enum ENUM_TASK_ENTRY_PROP { + TASK_ENTRY_PROP_NONE = 0, // None + TASK_ENTRY_PROP_EXPIRES, // Expires + TASK_ENTRY_PROP_LAST_PROCESS, // Last process + TASK_ENTRY_PROP_LAST_SUCCESS, // Last success + }; + protected: TaskActionEntry action; // TaskAction of the task. TaskConditionEntry cond; // TaskCondition of the task. @@ -60,6 +69,45 @@ struct TaskEntry { void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { Init(); }; + // Getters. + template + T Get(ENUM_TASK_ENTRY_PROP _prop) { + switch (_prop) { + case TASK_ENTRY_PROP_EXPIRES: // Expires + return (T)expires; + case TASK_ENTRY_PROP_LAST_PROCESS: // Last process + return (T)last_process; + case TASK_ENTRY_PROP_LAST_SUCCESS: // Last success + return (T)last_success; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + return (T) false; + }; + bool Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag) { return action.Get(_flag); }; + template + bool Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop) { + return action.Get(_prop); + }; + // bool Get(ENUM_TASK_ENTRY_FLAGS _flag) { return HasFlag(_flag); } + // TaskActionEntry GetAction() { return action; } + // TaskConditionEntry GetCondition() { return cond; } + // Setters. + template + void Set(ENUM_TASK_ENTRY_PROP _prop, T _value) { + switch (_prop) { + case TASK_ENTRY_PROP_EXPIRES: // Expires + expires = (T)_value; + case TASK_ENTRY_PROP_LAST_PROCESS: // Last process + last_process = (T)_value; + case TASK_ENTRY_PROP_LAST_SUCCESS: // Last success + last_success = (T)_value; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + }; // Flag methods. bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } @@ -72,9 +120,9 @@ struct TaskEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - // bool IsActive() { return HasFlag(ACTION_ENTRY_FLAG_IS_ACTIVE); } - // bool IsDone() { return HasFlag(ACTION_ENTRY_FLAG_IS_DONE); } - // bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); } + bool IsActive() { return HasFlag(TASK_ENTRY_FLAG_IS_ACTIVE); } + bool IsDone() { return HasFlag(TASK_ENTRY_FLAG_IS_DONE); } + bool IsFailed() { return HasFlag(TASK_ENTRY_FLAG_IS_FAILED); } bool IsValid() { return action.IsValid() && cond.IsValid(); } // Getters. int GetActionId() { return action.GetId(); } diff --git a/Task/TaskObject.h b/Task/TaskObject.h index 38db316b9..b3f4650bb 100644 --- a/Task/TaskObject.h +++ b/Task/TaskObject.h @@ -38,7 +38,7 @@ #include "Task.h" template -class TaskObject : protected Task { +class TaskObject : public Task { protected: TaskAction action; TaskCondition condition; @@ -47,16 +47,36 @@ class TaskObject : protected Task { /* Special methods */ /** - * Class constructor. + * Default class constructor. */ - TaskObject(TaskActionEntry &_aentry, TaskConditionEntry &_centry) : action(_aentry), condition(_centry) {} + TaskObject() {} + + /** + * Class constructor with task entry as argument. + */ + TaskObject(TaskEntry &_tentry) : Task(_tentry) {} /** * Class deconstructor. */ ~TaskObject() {} - /* Main methods */ + /* Virtual methods */ + + /** + * Process tasks. + * + * @return + * Returns true when tasks has been processed. + */ + virtual bool Process() { + bool _result = true; + for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { + TaskEntry _entry = iter.Value(); + _result &= Process(_entry); + } + return _result; + } /** * Process task entry. @@ -64,9 +84,24 @@ class TaskObject : protected Task { * @return * Returns true when tasks has been processed. */ - static bool Process(TaskEntry &_entry) { + virtual bool Process(TaskEntry &_entry) { bool _result = false; - // @todo + if (_entry.IsActive()) { + if (condition.Check()) { + action.Run(); + _entry.Set(STRUCT_ENUM(TaskEntry, TASK_ENTRY_PROP_LAST_PROCESS), TimeCurrent()); + if (_entry.IsDone()) { + _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE))); + _entry.SetFlag(TASK_ENTRY_FLAG_IS_FAILED, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_FAILED))); + _entry.SetFlag(TASK_ENTRY_FLAG_IS_INVALID, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID))); + _entry.RemoveFlags(TASK_ENTRY_FLAG_IS_ACTIVE); + } + _result = true; + } + } return _result; } From 99cde57c20e584fae27019601a0b3b1a103de3a5 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 17 Jan 2022 21:20:51 +0000 Subject: [PATCH 29/84] Task: Adds TaskManager --- .github/workflows/test-task.yml | 1 + Task/TaskManager.h | 89 +++++++++++++++++++++++++++++ Task/tests/TaskManager.test.mq4 | 28 ++++++++++ Task/tests/TaskManager.test.mq5 | 99 +++++++++++++++++++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 Task/TaskManager.h create mode 100644 Task/tests/TaskManager.test.mq4 create mode 100644 Task/tests/TaskManager.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index 52dd9346f..fab47a667 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -52,6 +52,7 @@ jobs: - TaskAction.test - TaskCondition.test - TaskGetter.test + - TaskManager.test - TaskObject.test - TaskSetter.test - Taskable.car.test diff --git a/Task/TaskManager.h b/Task/TaskManager.h new file mode 100644 index 000000000..190f72ecb --- /dev/null +++ b/Task/TaskManager.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 . + * + */ + +/** + * @file + * Provides task management. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_MANAGER_H +#define TASK_MANAGER_H + +// Includes. +#include "../DictObject.mqh" +#include "TaskObject.h" + +class TaskManager { + protected: + DictObject tasks; + // DictObject> tasks; + // DictObject> tasks; // @todo: Which one? + + /* Protected methods */ + + /** + * Init code (called on constructor). + */ + void Init() {} + + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskManager() { Init(); } + + /** + * Class deconstructor. + */ + ~TaskManager() {} + + /* Adder methods */ + + /** + * Adds new task. + */ + bool Add(Task &_task) { return tasks.Push(_task); } + + /* Processing methods */ + + /** + * Process tasks. + */ + bool Process() { + bool _result = true; + for (DictObjectIterator _iter = tasks.Begin(); _iter.IsValid(); ++_iter) { + TaskObject *_task = _iter.Value(); + _result &= _task.Process(); + } + return _result; + } +}; + +#endif // TASK_MANAGER_H diff --git a/Task/tests/TaskManager.test.mq4 b/Task/tests/TaskManager.test.mq4 new file mode 100644 index 000000000..1092ba332 --- /dev/null +++ b/Task/tests/TaskManager.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskManager class. + */ + +// Includes. +#include "TaskManager.test.mq5" diff --git a/Task/tests/TaskManager.test.mq5 b/Task/tests/TaskManager.test.mq5 new file mode 100644 index 000000000..a6c964df7 --- /dev/null +++ b/Task/tests/TaskManager.test.mq5 @@ -0,0 +1,99 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskManager class. + */ + +// Forward declaration. +struct DataParamEntry; + +// Includes. +#include "../../Test.mqh" +#include "../TaskManager.h" + +// Define test classes. +class ConditionType1 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ConditionType2 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ActionType1 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class ActionType2 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class TaskType1 : public Taskable { + bool Check(const TaskConditionEntry &_entry) { return true; } + MqlParam Get(const TaskGetterEntry &_entry) { + MqlParam _result; + return _result; + } + bool Run(const TaskActionEntry &_entry) { return true; } + bool Set(const TaskSetterEntry &_entry, const MqlParam &_entry_value) { return true; } +}; + +// Test 1. +bool TestTaskManager01() { + bool _result = true; + TaskManager _tsm; + TaskActionEntry _aentry(1); + TaskConditionEntry _centry(1); + TaskEntry _tentry(_aentry, _centry); + TaskObject _task01(_tentry); + TaskObject _task02(_tentry); + TaskObject _task03(_tentry); + TaskObject _task04(_tentry); + _tsm.Add(_task01); + _tsm.Add(_task02); + _tsm.Add(_task03); + _tsm.Add(_task04); + _tsm.Process(); + // @todo: Print via ToString(). + return _result; +} + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + _result &= TestTaskManager01(); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From 32ec9558aba5be1e956982ab306b9ecffd2dff37 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 17 Jan 2022 23:28:22 +0000 Subject: [PATCH 30/84] Task/TaskObject: Adds support for objects --- Task/Task.struct.h | 4 ++-- Task/TaskAction.h | 4 ++-- Task/TaskCondition.h | 4 ++-- Task/TaskManager.h | 8 ++++++++ Task/TaskObject.h | 10 +++++----- Task/tests/TaskManager.test.mq5 | 20 ++++++++++++-------- Task/tests/TaskObject.test.mq5 | 18 +++++++++++------- 7 files changed, 42 insertions(+), 26 deletions(-) diff --git a/Task/Task.struct.h b/Task/Task.struct.h index f9cbf9815..2be699492 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -91,8 +91,8 @@ struct TaskEntry { return action.Get(_prop); }; // bool Get(ENUM_TASK_ENTRY_FLAGS _flag) { return HasFlag(_flag); } - // TaskActionEntry GetAction() { return action; } - // TaskConditionEntry GetCondition() { return cond; } + TaskActionEntry GetActionEntry() { return action; } + TaskConditionEntry GetConditionEntry() { return cond; } // Setters. template void Set(ENUM_TASK_ENTRY_PROP _prop, T _value) { diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 4c647f98e..8fdf06693 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -47,7 +47,7 @@ class TaskAction : public TaskActionBase { protected: // Protected class variables. TaskActionEntry entry; // Action entry. - TO obj; // Object to run the action on. + TO *obj; // Object to run the action on. public: /* Special methods */ @@ -60,7 +60,7 @@ class TaskAction : public TaskActionBase { /** * Class constructor with an entry as argument. */ - TaskAction(TaskActionEntry &_entry) : entry(_entry) {} + TaskAction(TaskActionEntry &_entry, TO *_obj = NULL) : entry(_entry), obj(_obj) {} /* Main methods */ diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 30214c373..0ae7e995b 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -48,7 +48,7 @@ class TaskCondition : public TaskConditionBase { protected: // Protected class variables. TaskConditionEntry entry; // Condition entry. - TO obj; // Object to run the action on. + TO *obj; // Object to run the action on. public: /* Special methods */ @@ -61,7 +61,7 @@ class TaskCondition : public TaskConditionBase { /** * Class constructor with an entry as argument. */ - TaskCondition(TaskConditionEntry &_entry) : entry(_entry) {} + TaskCondition(TaskConditionEntry &_entry, TO *_obj = NULL) : entry(_entry), obj(_obj) {} /* Main methods */ diff --git a/Task/TaskManager.h b/Task/TaskManager.h index 190f72ecb..e886c6886 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -71,6 +71,14 @@ class TaskManager { */ bool Add(Task &_task) { return tasks.Push(_task); } + /** + * Adds new object task. + */ + template + bool Add(TaskObject &_task_obj) { + return tasks.Push(_task_obj); + } + /* Processing methods */ /** diff --git a/Task/TaskObject.h b/Task/TaskObject.h index b3f4650bb..f673f7945 100644 --- a/Task/TaskObject.h +++ b/Task/TaskObject.h @@ -40,8 +40,8 @@ template class TaskObject : public Task { protected: - TaskAction action; - TaskCondition condition; + TA *obja; + TC *objc; public: /* Special methods */ @@ -54,7 +54,7 @@ class TaskObject : public Task { /** * Class constructor with task entry as argument. */ - TaskObject(TaskEntry &_tentry) : Task(_tentry) {} + TaskObject(TaskEntry &_tentry, TA *_obja = NULL, TC *_objc = NULL) : obja(_obja), objc(_objc), Task(_tentry) {} /** * Class deconstructor. @@ -87,8 +87,8 @@ class TaskObject : public Task { virtual bool Process(TaskEntry &_entry) { bool _result = false; if (_entry.IsActive()) { - if (condition.Check()) { - action.Run(); + if (Object::IsValid(objc) && objc.Check(_entry.GetCondition()) && Object::IsValid(obja)) { + obja.Run(_entry.GetAction()); _entry.Set(STRUCT_ENUM(TaskEntry, TASK_ENTRY_PROP_LAST_PROCESS), TimeCurrent()); if (_entry.IsDone()) { _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, diff --git a/Task/tests/TaskManager.test.mq5 b/Task/tests/TaskManager.test.mq5 index a6c964df7..51475dea2 100644 --- a/Task/tests/TaskManager.test.mq5 +++ b/Task/tests/TaskManager.test.mq5 @@ -61,18 +61,22 @@ class TaskType1 : public Taskable { // Test 1. bool TestTaskManager01() { bool _result = true; + ActionType1 _actionobj1; + ActionType2 _actionobj2; + ConditionType1 _condobj1; + ConditionType2 _condobj2; TaskManager _tsm; TaskActionEntry _aentry(1); TaskConditionEntry _centry(1); TaskEntry _tentry(_aentry, _centry); - TaskObject _task01(_tentry); - TaskObject _task02(_tentry); - TaskObject _task03(_tentry); - TaskObject _task04(_tentry); - _tsm.Add(_task01); - _tsm.Add(_task02); - _tsm.Add(_task03); - _tsm.Add(_task04); + TaskObject _taskobj01(_tentry, &_actionobj1, &_condobj1); + TaskObject _taskobj02(_tentry, &_actionobj2, &_condobj1); + TaskObject _taskobj03(_tentry, &_actionobj1, &_condobj2); + TaskObject _taskobj04(_tentry, &_actionobj2, &_condobj2); + _tsm.Add(_taskobj01); + _tsm.Add(_taskobj02); + _tsm.Add(_taskobj03); + _tsm.Add(_taskobj04); _tsm.Process(); // @todo: Print via ToString(). return _result; diff --git a/Task/tests/TaskObject.test.mq5 b/Task/tests/TaskObject.test.mq5 index c47a394ae..9cbe84c1a 100644 --- a/Task/tests/TaskObject.test.mq5 +++ b/Task/tests/TaskObject.test.mq5 @@ -61,13 +61,17 @@ class TaskType1 : public Taskable { // Test 1. bool TestTaskObject01() { bool _result = true; - TaskActionEntry _aentry; - TaskConditionEntry _centry; - // TaskAction _taction1; - // TaskAction _taction2; - // TaskCondition _tcond1; - // TaskCondition _tcond2; - TaskObject _task1(_aentry, _centry); + ActionType1 _actionobj1; + ActionType2 _actionobj2; + ConditionType1 _condobj1; + ConditionType2 _condobj2; + TaskActionEntry _aentry(1); + TaskConditionEntry _centry(1); + TaskEntry _tentry(_aentry, _centry); + TaskObject _taskobj01(_tentry, &_actionobj1, &_condobj1); + TaskObject _taskobj02(_tentry, &_actionobj2, &_condobj1); + TaskObject _taskobj03(_tentry, &_actionobj1, &_condobj2); + TaskObject _taskobj04(_tentry, &_actionobj2, &_condobj2); return _result; } From 8d748055c32cf21f9867bada0d0c265dabe8b9b7 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 18 Jan 2022 18:08:17 +0100 Subject: [PATCH 31/84] Fixed DictObjectIterator's value pointer's cast. Fixed TaskEntry::Get()'s switch. Made tasks dictionary to store references to Task type. --- Task/Task.h | 2 +- Task/Task.struct.h | 3 +++ Task/TaskManager.h | 15 +++++++++------ Task/tests/TaskManager.test.mq5 | 20 ++++++++++++-------- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Task/Task.h b/Task/Task.h index 1f937672d..8bba0c7e1 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -42,7 +42,7 @@ #include "TaskCondition.h" #include "Taskable.h" -class Task : protected Taskable { +class Task : public Taskable { public: // Class variables. DictStruct tasks; diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 2be699492..81d8ba682 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -99,10 +99,13 @@ struct TaskEntry { switch (_prop) { case TASK_ENTRY_PROP_EXPIRES: // Expires expires = (T)_value; + break; case TASK_ENTRY_PROP_LAST_PROCESS: // Last process last_process = (T)_value; + break; case TASK_ENTRY_PROP_LAST_SUCCESS: // Last success last_success = (T)_value; + break; default: SetUserError(ERR_INVALID_PARAMETER); break; diff --git a/Task/TaskManager.h b/Task/TaskManager.h index e886c6886..7559f5ce5 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -40,7 +40,7 @@ class TaskManager { protected: - DictObject tasks; + DictStruct> tasks; // DictObject> tasks; // DictObject> tasks; // @todo: Which one? @@ -69,14 +69,17 @@ class TaskManager { /** * Adds new task. */ - bool Add(Task &_task) { return tasks.Push(_task); } + bool Add(Task *_task) { + Ref _ref = _task; + return tasks.Push(_ref); + } /** * Adds new object task. */ template - bool Add(TaskObject &_task_obj) { - return tasks.Push(_task_obj); + bool Add(TaskObject *_task_obj) { + return Add((Task *)_task_obj); } /* Processing methods */ @@ -86,8 +89,8 @@ class TaskManager { */ bool Process() { bool _result = true; - for (DictObjectIterator _iter = tasks.Begin(); _iter.IsValid(); ++_iter) { - TaskObject *_task = _iter.Value(); + for (DictStructIterator> _iter = tasks.Begin(); _iter.IsValid(); ++_iter) { + Task *_task = _iter.Value().Ptr(); _result &= _task.Process(); } return _result; diff --git a/Task/tests/TaskManager.test.mq5 b/Task/tests/TaskManager.test.mq5 index 51475dea2..fa8fd72a9 100644 --- a/Task/tests/TaskManager.test.mq5 +++ b/Task/tests/TaskManager.test.mq5 @@ -69,14 +69,18 @@ bool TestTaskManager01() { TaskActionEntry _aentry(1); TaskConditionEntry _centry(1); TaskEntry _tentry(_aentry, _centry); - TaskObject _taskobj01(_tentry, &_actionobj1, &_condobj1); - TaskObject _taskobj02(_tentry, &_actionobj2, &_condobj1); - TaskObject _taskobj03(_tentry, &_actionobj1, &_condobj2); - TaskObject _taskobj04(_tentry, &_actionobj2, &_condobj2); - _tsm.Add(_taskobj01); - _tsm.Add(_taskobj02); - _tsm.Add(_taskobj03); - _tsm.Add(_taskobj04); + Ref> _taskobj01 = + new TaskObject(_tentry, &_actionobj1, &_condobj1); + Ref> _taskobj02 = + new TaskObject(_tentry, &_actionobj2, &_condobj1); + Ref> _taskobj03 = + new TaskObject(_tentry, &_actionobj1, &_condobj2); + Ref> _taskobj04 = + new TaskObject(_tentry, &_actionobj2, &_condobj2); + _tsm.Add(_taskobj01.Ptr()); + _tsm.Add(_taskobj02.Ptr()); + _tsm.Add(_taskobj03.Ptr()); + _tsm.Add(_taskobj04.Ptr()); _tsm.Process(); // @todo: Print via ToString(). return _result; From cb7cd42515f5a7ee4c8213258951416c2a03eb77 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 20:04:09 +0000 Subject: [PATCH 32/84] Strategy: Integrates TaskManager logic with Task's conditions --- EA.mqh | 2 - Strategy.enum.h | 1 - Strategy.mqh | 141 +++++++++--------------------------- Task/TaskCondition.struct.h | 2 +- 4 files changed, 35 insertions(+), 111 deletions(-) diff --git a/EA.mqh b/EA.mqh index 40e5b1610..ee368e1a7 100644 --- a/EA.mqh +++ b/EA.mqh @@ -374,8 +374,6 @@ class EA : public Taskable { } if (_strat.TickFilter(_tick)) { _can_trade &= !_strat.IsSuspended(); - _can_trade &= - !_strat.CheckCondition(STRAT_COND_TRADE_COND, TRADE_COND_HAS_STATE, TRADE_STATE_TRADE_CANNOT); TradeSignalEntry _sentry = GetStrategySignalEntry(_strat, _can_trade, _strat.Get(STRAT_PARAM_SHIFT)); if (_sentry.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_SIGNALS)) > 0) { TradeSignal _signal(_sentry); diff --git a/Strategy.enum.h b/Strategy.enum.h index b3f60b197..1b54ffaf7 100644 --- a/Strategy.enum.h +++ b/Strategy.enum.h @@ -62,7 +62,6 @@ enum ENUM_STRATEGY_CONDITION { STRAT_COND_IS_SUSPENDED, // Strategy is suspended. STRAT_COND_IS_TREND, // Strategy is in trend. STRAT_COND_SIGNALOPEN, // On strategy's signal to open. - STRAT_COND_TRADE_COND, // On strategy's trade condition (args). FINAL_STRATEGY_CONDITION_ENTRY }; diff --git a/Strategy.mqh b/Strategy.mqh index 15ec64f03..5ae2df38b 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -36,7 +36,7 @@ class Trade; #include "Strategy.enum.h" #include "Strategy.struct.h" #include "String.mqh" -#include "Task/Task.h" +#include "Task/TaskManager.h" #include "Task/Taskable.h" #include "Trade.mqh" @@ -95,11 +95,11 @@ class Strategy : public Taskable { Dict fdata; Dict idata; DictStruct> indicators; // Indicators list. - DictStruct tasks; - Log logger; // Log instance. + Log logger; // Log instance. MqlTick last_tick; StgProcessResult sresult; Strategy *strat_sl, *strat_tp; // Strategy pointers for stop-loss and profit-take. + TaskManager tsm; // Tasks. Trade trade; // Trade instance. // TradeSignalEntry last_signal; // Last signals. @@ -163,46 +163,11 @@ class Strategy : public Taskable { StgProcessResult Process(unsigned short _periods_started = DATETIME_NONE) { sresult.last_error = ERR_NO_ERROR; if (_periods_started > 0) { - ProcessTasks(); + tsm.Process(); } return sresult; } - /* Tasks */ - - /** - * Add task. - */ - void AddTask(TaskEntry &_entry) { - if (_entry.IsValid()) { - /* @fixme - if (_entry.GetAction().GetType() == ACTION_TYPE_STRATEGY) { - _entry.SetActionObject(GetPointer(this)); - } - if (_entry.GetCondition().GetType() == COND_TYPE_STRATEGY) { - _entry.SetConditionObject(GetPointer(this)); - } - */ - tasks.Push(_entry); - } - } - - /** - * Process strategy's tasks. - * - * @return - * Returns StgProcessResult struct. - */ - void ProcessTasks() { - for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { - bool _is_processed = false; - TaskEntry _entry = iter.Value(); - _is_processed = Task::Process(_entry); - sresult.tasks_processed += (unsigned short)_is_processed; - sresult.tasks_processed_not += (unsigned short)!_is_processed; - } - } - /* State checkers */ /** @@ -674,74 +639,6 @@ class Strategy : public Taskable { return true; } - /* Conditions and actions */ - - /** - * Checks for Strategy condition. - * - * @param ENUM_STRATEGY_CONDITION _cond - * Strategy condition. - * @return - * Returns true when the condition is met. - */ - bool CheckCondition(ENUM_STRATEGY_CONDITION _cond, DataParamEntry &_args[]) { - bool _result = false; - long arg_size = ArraySize(_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; - switch (_cond) { - case STRAT_COND_IS_ENABLED: - return sparams.IsEnabled(); - case STRAT_COND_IS_SUSPENDED: - return sparams.IsSuspended(); - case STRAT_COND_IS_TREND: - _arg1l = _arg1l != WRONG_VALUE ? _arg1l : 0; - return IsTrend((ENUM_ORDER_TYPE)_arg1l); - case STRAT_COND_SIGNALOPEN: { - ENUM_ORDER_TYPE _cmd = ArraySize(_args) > 1 ? (ENUM_ORDER_TYPE)_args[0].integer_value : ORDER_TYPE_BUY; - int _method = ArraySize(_args) > 1 ? (int)_args[1].integer_value : 0; - float _level = ArraySize(_args) > 2 ? (float)_args[2].double_value : 0; - return SignalOpen(_cmd, _method, _level); - } - case STRAT_COND_TRADE_COND: - // Args: - // 1st (i:0) - Trade's enum condition to check. - // 2rd... (i:1) - Optionally trade's arguments to pass. - if (arg_size > 0) { - DataParamEntry _sargs[]; - ArrayResize(_sargs, ArraySize(_args) - 1); - for (int i = 0; i < ArraySize(_sargs); i++) { - _sargs[i] = _args[i + 1]; - } - _result = trade.CheckCondition((ENUM_TRADE_CONDITION)_arg1l, _sargs); - } - return _result; - default: - GetLogger().Error(StringFormat("Invalid EA condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - break; - } - return _result; - } - bool CheckCondition(ENUM_STRATEGY_CONDITION _cond, long _arg1) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - ArrayPushObject(_args, _param1); - return Strategy::CheckCondition(_cond, _args); - } - bool CheckCondition(ENUM_STRATEGY_CONDITION _cond, long _arg1, long _arg2) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - DataParamEntry _param2 = _arg2; - ArrayPushObject(_args, _param1); - ArrayPushObject(_args, _param2); - return Strategy::CheckCondition(_cond, _args); - } - bool CheckCondition(ENUM_STRATEGY_CONDITION _cond) { - ARRAY(DataParamEntry, _args); - return CheckCondition(_cond, _args); - } - /** * Execute Strategy action. * @@ -1255,6 +1152,25 @@ class Strategy : public Taskable { return _result; }; + /* Tasks methods */ + + /** + * Add task. + */ + bool AddTask(TaskEntry &_tentry) { + bool _is_valid = _tentry.IsValid(); + if (_is_valid) { + TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); + tsm.Add(&_taskobj); + } + return _is_valid; + } + + /** + * Process tasks. + */ + void ProcessTasks() { tsm.Process(); } + /* Tasks */ /** @@ -1263,7 +1179,18 @@ class Strategy : public Taskable { virtual bool Check(const TaskConditionEntry &_entry) { bool _result = false; switch (_entry.GetId()) { + case STRAT_COND_IS_ENABLED: + return sparams.IsEnabled(); + case STRAT_COND_IS_SUSPENDED: + return sparams.IsSuspended(); + case STRAT_COND_IS_TREND: + return IsTrend(_entry.GetArg(0).ToValue()); + case STRAT_COND_SIGNALOPEN: + return SignalOpen(_entry.GetArg(0).ToValue(), _entry.GetArg(1).ToValue(), + _entry.GetArg(2).ToValue()); default: + GetLogger().Error(StringFormat("Invalid EA condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); break; } return _result; diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 1485a49d7..abdc4f3a7 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -109,7 +109,7 @@ struct TaskConditionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } - DataParamEntry GetArg(int _index) { return args[_index]; } + DataParamEntry GetArg(int _index) const { return args[_index]; } int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } From 66fda0d059c3e3a68a42b0ba30140b905f431a0d Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 20:23:47 +0000 Subject: [PATCH 33/84] Task: Fixes TaskAction test --- Task/tests/TaskAction.test.mq5 | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Task/tests/TaskAction.test.mq5 b/Task/tests/TaskAction.test.mq5 index f1f0721af..981d8c760 100644 --- a/Task/tests/TaskAction.test.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -68,14 +68,25 @@ class TaskActionTest02 : public TaskActionBase { int OnInit() { bool _result = true; // Test01 + TaskActionTest01 _atest01; TaskActionEntry _entry01(TASK_ACTION_TEST01); - TaskAction _action01(_entry01); + TaskAction _action01(_entry01, &_atest01); _action01.Run(); _action01.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST02); _action01.Run(); _action01.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST03); _action01.Run(); assertTrueOrFail(_result && _action01.GetObject().GetSum() == 6, "Fail!"); + // Test02. + TaskActionTest02 _atest02; + TaskActionEntry _entry02(TASK_ACTION_TEST02); + TaskAction _action02(_entry02, &_atest02); + _action02.Run(); + _action02.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST02); + _action02.Run(); + _action02.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST03); + _action02.Run(); + assertTrueOrFail(_result && _action02.GetObject().GetSum() == 7, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From d6fb602f94df2662b0c36ccc3310e06db9eaee79 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 20:27:23 +0000 Subject: [PATCH 34/84] GHA: Includes testing on .mq? changes --- .github/workflows/test-task.yml | 2 ++ .github/workflows/test-trade.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index fab47a667..9890da617 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -6,10 +6,12 @@ on: pull_request: paths: - 'Task/**.h' + - 'Task/**.mq?' - '.github/workflows/test-task.yml' push: paths: - 'Task/**.h' + - 'Task/**.mq?' - '.github/workflows/test-task.yml' jobs: diff --git a/.github/workflows/test-trade.yml b/.github/workflows/test-trade.yml index 4ab779efd..a3a9091ec 100644 --- a/.github/workflows/test-trade.yml +++ b/.github/workflows/test-trade.yml @@ -6,10 +6,12 @@ on: pull_request: paths: - 'Trade/**.h' + - 'Trade/**.mq?' - '.github/workflows/test-trade.yml' push: paths: - 'Trade/**.h' + - 'Trade/**.mq?' - '.github/workflows/test-trade.yml' jobs: From a975c3b4ffeda299d95f22531e39e04919892f7f Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 21:00:37 +0000 Subject: [PATCH 35/84] Task: Fixes TaskCondition test --- .github/workflows/test-task.yml | 6 ++---- Task/tests/TaskCondition.test.mq5 | 13 ++++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index 9890da617..faccb308a 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -5,13 +5,11 @@ name: Test Task on: pull_request: paths: - - 'Task/**.h' - - 'Task/**.mq?' + - 'Task/**' - '.github/workflows/test-task.yml' push: paths: - - 'Task/**.h' - - 'Task/**.mq?' + - 'Task/**' - '.github/workflows/test-task.yml' jobs: diff --git a/Task/tests/TaskCondition.test.mq5 b/Task/tests/TaskCondition.test.mq5 index ad8f241b0..30d96f5e4 100644 --- a/Task/tests/TaskCondition.test.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -68,14 +68,25 @@ class TaskConditionTest02 : public TaskConditionBase { int OnInit() { bool _result = true; // Test01 + TaskConditionTest01 _test01; TaskConditionEntry _entry01(TASK_CONDITION_TEST01); - TaskCondition _cond01(_entry01); + TaskCondition _cond01(_entry01, &_test01); _result &= _cond01.Check(); _cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST02); _result &= _cond01.Check(); _cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST03); _result &= _cond01.Check(); assertTrueOrFail(_result && _cond01.GetObject().GetSum() == 6, "Fail!"); + // Test02 + TaskConditionTest02 _test02; + TaskConditionEntry _entry02(TASK_CONDITION_TEST02); + TaskCondition _cond02(_entry02, &_test02); + _result &= _cond02.Check(); + _cond02.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST02); + _result &= _cond02.Check(); + _cond02.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST03); + _result &= _cond02.Check(); + assertTrueOrFail(_result && _cond01.GetObject().GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From 6dc2988d648005cd8c79b6dd2ba573635bff97ca Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 21:23:39 +0000 Subject: [PATCH 36/84] Strategy: Renames tsm to tasks --- Strategy.mqh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Strategy.mqh b/Strategy.mqh index 5ae2df38b..a84cc0588 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -99,7 +99,7 @@ class Strategy : public Taskable { MqlTick last_tick; StgProcessResult sresult; Strategy *strat_sl, *strat_tp; // Strategy pointers for stop-loss and profit-take. - TaskManager tsm; // Tasks. + TaskManager tasks; // Tasks. Trade trade; // Trade instance. // TradeSignalEntry last_signal; // Last signals. @@ -163,7 +163,7 @@ class Strategy : public Taskable { StgProcessResult Process(unsigned short _periods_started = DATETIME_NONE) { sresult.last_error = ERR_NO_ERROR; if (_periods_started > 0) { - tsm.Process(); + tasks.Process(); } return sresult; } @@ -1161,7 +1161,7 @@ class Strategy : public Taskable { bool _is_valid = _tentry.IsValid(); if (_is_valid) { TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); - tsm.Add(&_taskobj); + tasks.Add(&_taskobj); } return _is_valid; } @@ -1169,7 +1169,7 @@ class Strategy : public Taskable { /** * Process tasks. */ - void ProcessTasks() { tsm.Process(); } + void ProcessTasks() { tasks.Process(); } /* Tasks */ From 1388e1419c0fa023d76868f939ed83c680216d1e Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 21:34:44 +0000 Subject: [PATCH 37/84] EA: Integrates TaskManager logic with Task's conditions --- EA.mqh | 149 +++++++++++++++++++-------------------------------------- 1 file changed, 49 insertions(+), 100 deletions(-) diff --git a/EA.mqh b/EA.mqh index ee368e1a7..4c501ced6 100644 --- a/EA.mqh +++ b/EA.mqh @@ -44,7 +44,7 @@ #include "SerializerSqlite.mqh" #include "Strategy.mqh" #include "SummaryReport.mqh" -#include "Task/Task.h" +#include "Task/TaskManager.h" #include "Task/Taskable.h" #include "Terminal.mqh" #include "Trade.mqh" @@ -67,10 +67,10 @@ class EA : public Taskable { DictObject trade; DictObject> data_indi; DictObject> data_stg; - DictStruct tasks; EAParams eparams; EAProcessResult eresults; EAState estate; + TaskManager tasks; TradeSignalManager tsm; public: @@ -82,7 +82,7 @@ class EA : public Taskable { estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), true); UpdateStateFlags(); // Add and process tasks. - TaskAdd(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); + AddTask(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); ProcessTasks(); estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), false); // Initialize a trade instance for the current chart and symbol. @@ -653,55 +653,6 @@ class EA : public Taskable { } */ - /* Tasks */ - - /** - * Add task. - */ - bool TaskAdd(TaskEntry &_entry) { - bool _result = false; - if (_entry.IsValid()) { - /* @fixme - switch (_entry.GetConditionId()) { - case COND_TYPE_ACCOUNT: - _entry.SetConditionObject(account); - break; - case COND_TYPE_EA: - _entry.SetConditionObject(THIS_PTR); - break; - case COND_TYPE_TRADE: - _entry.SetConditionObject(trade.GetByKey(_Symbol)); - break; - } - switch (_entry.GetActionId()) { - case ACTION_TYPE_EA: - _entry.SetActionObject(THIS_PTR); - break; - case ACTION_TYPE_TRADE: - _entry.SetActionObject(trade.GetByKey(_Symbol)); - break; - } - */ - _result |= tasks.Push(_entry); - } - return _result; - } - - /** - * Process EA tasks. - */ - unsigned int ProcessTasks() { - unsigned int _counter = 0; - for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { - bool _is_processed = false; - TaskEntry _entry = iter.Value(); - _is_processed = _is_processed || Task::Process(_entry); - // _entry.last_process = TimeCurrent(); - _counter += (unsigned short)_is_processed; - } - return _counter; - } - /* Strategy methods */ /** @@ -868,53 +819,6 @@ class EA : public Taskable { return _result; } - /* Conditions and actions */ - - /** - * Checks for EA condition. - * - * @param ENUM_EA_CONDITION _cond - * EA condition. - * @return - * Returns true when the condition is met. - */ - bool CheckCondition(ENUM_EA_CONDITION _cond, DataParamEntry &_args[]) { - bool _result = false; - switch (_cond) { - case EA_COND_IS_ACTIVE: - return estate.IsActive(); - case EA_COND_IS_ENABLED: - return estate.IsEnabled(); - case EA_COND_IS_NOT_CONNECTED: - estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_CONNECTED), GetTerminal().IsConnected()); - return !estate.IsConnected(); - case EA_COND_ON_NEW_MINUTE: // On new minute. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MINUTE) != 0; - case EA_COND_ON_NEW_HOUR: // On new hour. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_HOUR) != 0; - case EA_COND_ON_NEW_DAY: // On new day. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_DAY) != 0; - case EA_COND_ON_NEW_WEEK: // On new week. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_WEEK) != 0; - case EA_COND_ON_NEW_MONTH: // On new month. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MONTH) != 0; - case EA_COND_ON_NEW_YEAR: // On new year. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_YEAR) != 0; - case EA_COND_ON_INIT: - return estate.IsOnInit(); - case EA_COND_ON_QUIT: - return estate.IsOnQuit(); - default: - logger.Error(StringFormat("Invalid EA condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - break; - } - return _result; - } - bool CheckCondition(ENUM_EA_CONDITION _cond) { - ARRAY(DataParamEntry, _args); - return EA::CheckCondition(_cond, _args); - } - /** * Execute EA action. * @@ -952,7 +856,8 @@ class EA : public Taskable { return _result; case EA_ACTION_TASKS_CLEAN: // @todo - return tasks.Size() == 0; + // return tasks.Size() == 0; + return false; default: logger.Error(StringFormat("Invalid EA action: %s!", EnumToString(_action), __FUNCTION_LINE__)); return false; @@ -978,6 +883,25 @@ class EA : public Taskable { return EA::ExecuteAction(_action, _args); } + /* Tasks methods */ + + /** + * Add task. + */ + bool AddTask(TaskEntry &_tentry) { + bool _is_valid = _tentry.IsValid(); + if (_is_valid) { + TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); + tasks.Add(&_taskobj); + } + return _is_valid; + } + + /** + * Process tasks. + */ + void ProcessTasks() { tasks.Process(); } + /* Tasks */ /** @@ -986,7 +910,32 @@ class EA : public Taskable { virtual bool Check(const TaskConditionEntry &_entry) { bool _result = false; switch (_entry.GetId()) { + case EA_COND_IS_ACTIVE: + return estate.IsActive(); + case EA_COND_IS_ENABLED: + return estate.IsEnabled(); + case EA_COND_IS_NOT_CONNECTED: + estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_CONNECTED), GetTerminal().IsConnected()); + return !estate.IsConnected(); + case EA_COND_ON_NEW_MINUTE: // On new minute. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MINUTE) != 0; + case EA_COND_ON_NEW_HOUR: // On new hour. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_HOUR) != 0; + case EA_COND_ON_NEW_DAY: // On new day. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_DAY) != 0; + case EA_COND_ON_NEW_WEEK: // On new week. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_WEEK) != 0; + case EA_COND_ON_NEW_MONTH: // On new month. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MONTH) != 0; + case EA_COND_ON_NEW_YEAR: // On new year. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_YEAR) != 0; + case EA_COND_ON_INIT: + return estate.IsOnInit(); + case EA_COND_ON_QUIT: + return estate.IsOnQuit(); default: + GetLogger().Error(StringFormat("Invalid EA condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); break; } return _result; From a602b9d16dd771d9bee6f6fc5fad611e3cf530e0 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 22:28:41 +0000 Subject: [PATCH 38/84] Task: Adds struct methods for arguments --- Task/TaskAction.struct.h | 30 +++++++++++++++++++++++++----- Task/TaskCondition.struct.h | 33 ++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index ab7db5b16..d6a9210f1 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -78,7 +78,7 @@ struct TaskActionEntry { tries(-1) { Init(); } - TaskActionEntry(TaskActionEntry &_ae) { this = _ae; } + TaskActionEntry(TaskActionEntry &_ae) { THIS_REF = _ae; } // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } @@ -150,11 +150,31 @@ struct TaskActionEntry { } SetUserError(ERR_INVALID_PARAMETER); } - void AddArg(MqlParam &_arg) { - // @todo: Add another value to args[]. + // Methods for arguments. + void ArgAdd(DataParamEntry &_arg) { ArgSet(_arg, ::ArraySize(args)); } + void ArgsGet(ARRAY_REF(MqlParam, _args)) { + ::ArrayResize(_args, ::ArraySize(args)); + for (unsigned int i = 0; i < _args.Size(); i++) { + _args[i] = args[i]; + } + } + void ArgSet(DataParamEntry &_arg, int _index = 0) { + if (::ArraySize(args) <= _index) { + ::ArrayResize(args, _index + 1); + } + args[_index] = _arg; } - void SetArgs(ARRAY_REF(MqlParam, _args)) { - // @todo: for(). + void ArgsSet(ARRAY_REF(MqlParam, _args)) { + ::ArrayResize(args, ::ArraySize(_args)); + for (unsigned int i = 0; i < _args.Size(); i++) { + args[i] = _args[i]; + } + } + void ArgRemove(int _index) { + for (unsigned int i = 1; i < args.Size(); i++) { + ArgSet(args[i], i - 1); + } + ::ArrayResize(args, _index - 1); } // Serializers SerializerNodeType Serialize(Serializer &s) { diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index abdc4f3a7..8f890ac51 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -83,7 +83,7 @@ struct TaskConditionEntry { tries(-1) { Init(); } - TaskConditionEntry(TaskConditionEntry &_ae) { this = _ae; } + TaskConditionEntry(TaskConditionEntry &_ae) { THIS_REF = _ae; } // Deconstructor. void ~TaskConditionEntry() {} // Getters. @@ -143,6 +143,7 @@ struct TaskConditionEntry { } SetUserError(ERR_INVALID_PARAMETER); } + void SetTries(short _count) { tries = _count; } // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } @@ -161,12 +162,30 @@ struct TaskConditionEntry { bool IsReady() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_READY); } bool IsInvalid() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_INVALID); } bool IsValid() const { return !IsInvalid(); } - // Setters. - void AddArg(MqlParam &_arg) { - // @todo: Add another value to args[]. + // Methods for arguments. + void ArgAdd(DataParamEntry &_arg) { ArgSet(_arg, ::ArraySize(args)); } + void ArgsGet(ARRAY_REF(MqlParam, _args)) { + ::ArrayResize(_args, ::ArraySize(args)); + for (unsigned int i = 0; i < _args.Size(); i++) { + _args[i] = args[i]; + } } - void SetArgs(MqlParam &_args[]) { - // @todo: for(). + void ArgSet(DataParamEntry &_arg, int _index = 0) { + if (::ArraySize(args) <= _index) { + ::ArrayResize(args, _index + 1); + } + args[_index] = _arg; + } + void ArgsSet(ARRAY_REF(MqlParam, _args)) { + ::ArrayResize(args, ::ArraySize(_args)); + for (unsigned int i = 0; i < _args.Size(); i++) { + args[i] = _args[i]; + } + } + void ArgRemove(int _index) { + for (unsigned int i = 1; i < args.Size(); i++) { + ArgSet(args[i], i - 1); + } + ::ArrayResize(args, _index - 1); } - void SetTries(short _count) { tries = _count; } }; From c786bb6e0dbc24a04d36afef8e4c09f87bdf3928 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 22:41:43 +0000 Subject: [PATCH 39/84] EA/Strategy: Integrates taskable actions --- EA.mqh | 94 +++++++++------------------- Strategy.enum.h | 1 - Strategy.mqh | 120 +++++------------------------------- Task/TaskAction.struct.h | 10 +-- Task/TaskCondition.struct.h | 10 +-- 5 files changed, 53 insertions(+), 182 deletions(-) diff --git a/EA.mqh b/EA.mqh index 4c501ced6..4cef18cd0 100644 --- a/EA.mqh +++ b/EA.mqh @@ -819,70 +819,6 @@ class EA : public Taskable { return _result; } - /** - * Execute EA action. - * - * @param ENUM_EA_ACTION _action - * EA action to execute. - * @return - * Returns true when the action has been executed successfully. - */ - bool ExecuteAction(ENUM_EA_ACTION _action, DataParamEntry &_args[]) { - bool _result = false; - long arg_size = ArraySize(_args); - switch (_action) { - case EA_ACTION_DISABLE: - estate.Enable(false); - return true; - case EA_ACTION_ENABLE: - estate.Enable(); - return true; - case EA_ACTION_EXPORT_DATA: - DataExport(); - return true; - case EA_ACTION_STRATS_EXE_ACTION: - // Args: - // 1st (i:0) - Strategy's enum action to execute. - // 2nd (i:1) - Strategy's argument to pass. - for (DictStructIterator> iter_strat = strats.Begin(); iter_strat.IsValid(); ++iter_strat) { - DataParamEntry _sargs[]; - ArrayResize(_sargs, ArraySize(_args) - 1); - for (int i = 0; i < ArraySize(_sargs); i++) { - _sargs[i] = _args[i + 1]; - } - Strategy *_strat = iter_strat.Value().Ptr(); - _result &= _strat.ExecuteAction((ENUM_STRATEGY_ACTION)_args[0].integer_value, _sargs); - } - return _result; - case EA_ACTION_TASKS_CLEAN: - // @todo - // return tasks.Size() == 0; - return false; - default: - logger.Error(StringFormat("Invalid EA action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - return false; - } - return _result; - } - bool ExecuteAction(ENUM_EA_ACTION _action) { - ARRAY(DataParamEntry, _args); - return EA::ExecuteAction(_action, _args); - } - bool ExecuteAction(ENUM_EA_ACTION _action, long _arg1) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - ArrayPushObject(_args, _param1); - return EA::ExecuteAction(_action, _args); - } - bool ExecuteAction(ENUM_EA_ACTION _action, long _arg1, long _arg2) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - DataParamEntry _param2 = _arg2; - ArrayPushObject(_args, _param1); - ArrayPushObject(_args, _param2); - return EA::ExecuteAction(_action, _args); - } - /* Tasks methods */ /** @@ -959,8 +895,36 @@ class EA : public Taskable { virtual bool Run(const TaskActionEntry &_entry) { bool _result = false; switch (_entry.GetId()) { + case EA_ACTION_DISABLE: + estate.Enable(false); + return true; + case EA_ACTION_ENABLE: + estate.Enable(); + return true; + case EA_ACTION_EXPORT_DATA: + DataExport(); + return true; + case EA_ACTION_STRATS_EXE_ACTION: { + // Args: + // 1st (i:0) - Strategy's enum action to execute. + // 2nd (i:1) - Strategy's argument to pass. + TaskActionEntry _entry_strat = _entry; + _entry_strat.ArgRemove(0); + for (DictStructIterator> iter_strat = strats.Begin(); iter_strat.IsValid(); ++iter_strat) { + Strategy *_strat = iter_strat.Value().Ptr(); + + _result &= _strat.Run(_entry_strat); + } + return _result; + } + case EA_ACTION_TASKS_CLEAN: + // @todo + // return tasks.Size() == 0; + SetUserError(ERR_INVALID_PARAMETER); + return false; default: - break; + GetLogger().Error(StringFormat("Invalid EA action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); } return _result; } diff --git a/Strategy.enum.h b/Strategy.enum.h index 1b54ffaf7..defb9d4e2 100644 --- a/Strategy.enum.h +++ b/Strategy.enum.h @@ -51,7 +51,6 @@ enum ENUM_STRATEGY_ACTION { STRAT_ACTION_DISABLE = 0, // Disables strategy. STRAT_ACTION_ENABLE, // Enables strategy. STRAT_ACTION_SUSPEND, // Suspend Strategy. - STRAT_ACTION_TRADE_EXE, // Execute trade action. STRAT_ACTION_UNSUSPEND, // Unsuspend Strategy. FINAL_STRATEGY_ACTION_ENTRY }; diff --git a/Strategy.mqh b/Strategy.mqh index a84cc0588..0b694f7cc 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -639,112 +639,6 @@ class Strategy : public Taskable { return true; } - /** - * Execute Strategy action. - * - * @param ENUM_STRATEGY_ACTION _action - * Strategy action to execute. - * @param MqlParam _args - * Strategy action arguments. - * @return - * Returns true when the action has been executed successfully. - */ - bool ExecuteAction(ENUM_STRATEGY_ACTION _action, DataParamEntry &_args[]) { - bool _result = false; - double arg1d = EMPTY_VALUE; - double arg2d = EMPTY_VALUE; - double arg3d = EMPTY_VALUE; - long arg1i = EMPTY; - long arg2i = EMPTY; - long arg3i = EMPTY; - long arg_size = ArraySize(_args); - if (arg_size > 0) { - arg1d = _args[0].type == TYPE_DOUBLE ? _args[0].double_value : EMPTY_VALUE; - arg1i = _args[0].type == TYPE_INT ? _args[0].integer_value : EMPTY; - if (arg_size > 1) { - arg2d = _args[1].type == TYPE_DOUBLE ? _args[1].double_value : EMPTY_VALUE; - arg2i = _args[1].type == TYPE_INT ? _args[1].integer_value : EMPTY; - } - if (arg_size > 2) { - arg3d = _args[2].type == TYPE_DOUBLE ? _args[2].double_value : EMPTY_VALUE; - arg3i = _args[2].type == TYPE_INT ? _args[2].integer_value : EMPTY; - } - } - switch (_action) { - case STRAT_ACTION_DISABLE: - sparams.Enabled(false); - return true; - case STRAT_ACTION_ENABLE: - sparams.Enabled(true); - return true; - case STRAT_ACTION_SUSPEND: - sparams.Suspended(true); - return true; - case STRAT_ACTION_TRADE_EXE: - // Args: - // 1st (i:0) - Trade's enum action to execute. - // 2rd (i:1) - Trade's argument to pass. - if (arg_size > 0) { - DataParamEntry _sargs[]; - ArrayResize(_sargs, ArraySize(_args) - 1); - for (int i = 0; i < ArraySize(_sargs); i++) { - _sargs[i] = _args[i + 1]; - } - _result = trade.ExecuteAction((ENUM_TRADE_ACTION)_args[0].integer_value, _sargs); - /* @fixme - if (_result) { - Order *_order = trade.GetOrderLast(); - switch ((ENUM_TRADE_ACTION)_args[0].integer_value) { - case TRADE_ACTION_ORDERS_CLOSE_BY_TYPE: - // OnOrderClose();// @todo - break; - case TRADE_ACTION_ORDER_OPEN: - // @fixme: Operation on the structure copy. - OnOrderOpen(_order.GetParams()); - break; - } - } - */ - } - return _result; - case STRAT_ACTION_UNSUSPEND: - sparams.Suspended(false); - return true; - default: - GetLogger().Error(StringFormat("Invalid Strategy action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - break; - } - return _result; - } - bool ExecuteAction(ENUM_STRATEGY_ACTION _action, long _arg1) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - ArrayPushObject(_args, _param1); - return Strategy::ExecuteAction(_action, _args); - } - bool ExecuteAction(ENUM_STRATEGY_ACTION _action, long _arg1, long _arg2) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - DataParamEntry _param2 = _arg2; - ArrayPushObject(_args, _param1); - ArrayPushObject(_args, _param2); - return Strategy::ExecuteAction(_action, _args); - } - bool ExecuteAction(ENUM_STRATEGY_ACTION _action, long _arg1, long _arg2, long _arg3) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - DataParamEntry _param2 = _arg2; - DataParamEntry _param3 = _arg3; - ArrayPushObject(_args, _param1); - ArrayPushObject(_args, _param2); - ArrayPushObject(_args, _param3); - return Strategy::ExecuteAction(_action, _args); - } - bool ExecuteAction(ENUM_STRATEGY_ACTION _action) { - ARRAY(DataParamEntry, _args); - return Strategy::ExecuteAction(_action, _args); - } - /* Printers methods */ /** @@ -1214,7 +1108,21 @@ class Strategy : public Taskable { virtual bool Run(const TaskActionEntry &_entry) { bool _result = false; switch (_entry.GetId()) { + case STRAT_ACTION_DISABLE: + sparams.Enabled(false); + return true; + case STRAT_ACTION_ENABLE: + sparams.Enabled(true); + return true; + case STRAT_ACTION_SUSPEND: + sparams.Suspended(true); + return true; + case STRAT_ACTION_UNSUSPEND: + sparams.Suspended(false); + return true; default: + GetLogger().Error(StringFormat("Invalid Strategy action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); break; } return _result; diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index d6a9210f1..b0ca39f06 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -152,9 +152,9 @@ struct TaskActionEntry { } // Methods for arguments. void ArgAdd(DataParamEntry &_arg) { ArgSet(_arg, ::ArraySize(args)); } - void ArgsGet(ARRAY_REF(MqlParam, _args)) { + void ArgsGet(ARRAY_REF(DataParamEntry, _args)) { ::ArrayResize(_args, ::ArraySize(args)); - for (unsigned int i = 0; i < _args.Size(); i++) { + for (int i = 0; i < ::ArraySize(_args); i++) { _args[i] = args[i]; } } @@ -164,14 +164,14 @@ struct TaskActionEntry { } args[_index] = _arg; } - void ArgsSet(ARRAY_REF(MqlParam, _args)) { + void ArgsSet(ARRAY_REF(DataParamEntry, _args)) { ::ArrayResize(args, ::ArraySize(_args)); - for (unsigned int i = 0; i < _args.Size(); i++) { + for (int i = 0; i < ::ArraySize(_args); i++) { args[i] = _args[i]; } } void ArgRemove(int _index) { - for (unsigned int i = 1; i < args.Size(); i++) { + for (int i = 1; i < ::ArraySize(args); i++) { ArgSet(args[i], i - 1); } ::ArrayResize(args, _index - 1); diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 8f890ac51..49ddf4eec 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -164,9 +164,9 @@ struct TaskConditionEntry { bool IsValid() const { return !IsInvalid(); } // Methods for arguments. void ArgAdd(DataParamEntry &_arg) { ArgSet(_arg, ::ArraySize(args)); } - void ArgsGet(ARRAY_REF(MqlParam, _args)) { + void ArgsGet(ARRAY_REF(DataParamEntry, _args)) { ::ArrayResize(_args, ::ArraySize(args)); - for (unsigned int i = 0; i < _args.Size(); i++) { + for (int i = 0; i < ::ArraySize(_args); i++) { _args[i] = args[i]; } } @@ -176,14 +176,14 @@ struct TaskConditionEntry { } args[_index] = _arg; } - void ArgsSet(ARRAY_REF(MqlParam, _args)) { + void ArgsSet(ARRAY_REF(DataParamEntry, _args)) { ::ArrayResize(args, ::ArraySize(_args)); - for (unsigned int i = 0; i < _args.Size(); i++) { + for (int i = 0; i < ::ArraySize(_args); i++) { args[i] = _args[i]; } } void ArgRemove(int _index) { - for (unsigned int i = 1; i < args.Size(); i++) { + for (int i = 1; i < ::ArraySize(args); i++) { ArgSet(args[i], i - 1); } ::ArrayResize(args, _index - 1); From 2798a65fbe91e4cd510204ceac63b16c2857a7f4 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 23:03:41 +0000 Subject: [PATCH 40/84] CompileTest: Adds missing Task includes --- tests/CompileTest.mq5 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index 1f5648d64..2e9e76d69 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -100,6 +100,13 @@ #include "../SummaryReport.mqh" #include "../SymbolInfo.mqh" #include "../Task/Task.h" +#include "../Task/TaskAction.h" +#include "../Task/TaskCondition.h" +#include "../Task/TaskGetter.h" +#include "../Task/TaskManager.h" +#include "../Task/TaskObject.h" +#include "../Task/TaskSetter.h" +#include "../Task/Taskable.h" #include "../Terminal.mqh" // #include "../Tester.mqh" // @removeme #include "../Storage/ValueStorage.h" From 41d50e4675441a100f48feea8443bf8d9a7c952d Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 23 Jan 2022 00:09:09 +0000 Subject: [PATCH 41/84] Trade: Integrates TaskManager logic --- EA.mqh | 2 +- Strategy.mqh | 12 ++- Task/TaskAction.struct.h | 2 +- Trade.mqh | 153 ++++++++++++++++++++------------------- 4 files changed, 92 insertions(+), 77 deletions(-) diff --git a/EA.mqh b/EA.mqh index 4cef18cd0..43010c033 100644 --- a/EA.mqh +++ b/EA.mqh @@ -813,7 +813,7 @@ class EA : public Taskable { if (eparams.CheckFlag(EA_PARAM_FLAG_LOTSIZE_AUTO)) { // Auto calculate lot size for all strategies. Trade *_trade = trade.GetByKey(_Symbol); - _result &= _trade.ExecuteAction(TRADE_ACTION_CALC_LOT_SIZE); + _result &= _trade.Run(TRADE_ACTION_CALC_LOT_SIZE); Set(STRAT_PARAM_LS, _trade.Get(TRADE_PARAM_LOT_SIZE)); } return _result; diff --git a/Strategy.mqh b/Strategy.mqh index 0b694f7cc..dcdb4b081 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -855,9 +855,11 @@ class Strategy : public Taskable { if (METHOD(_method, 3)) _result &= !trade.HasOrderOppositeType(_cmd); // 8 if (METHOD(_method, 4)) _result &= trade.IsPeak(_cmd); // 16 if (METHOD(_method, 5)) _result &= !trade.HasOrderBetter(_cmd); // 32 + /* if (METHOD(_method, 6)) - _result &= !trade.CheckCondition( + _result &= !trade.Check( TRADE_COND_ACCOUNT, _method > 0 ? ACCOUNT_COND_EQUITY_01PC_LOW : ACCOUNT_COND_EQUITY_01PC_HIGH); // 64 + */ // if (METHOD(_method, 5)) _result &= Trade().IsRoundNumber(_cmd); // if (METHOD(_method, 6)) _result &= Trade().IsHedging(_cmd); _method = _method > 0 ? _method : !_method; @@ -962,10 +964,12 @@ class Strategy : public Taskable { _result |= _result || Open[_shift] > High[_shift + 1] || Open[_shift] < Low[_shift + 1]; // 8 if (METHOD(_method, 4)) _result |= _result || trade.IsPeak(_cmd); // 16 if (METHOD(_method, 5)) _result |= _result || trade.HasOrderBetter(_cmd); // 32 + /* if (METHOD(_method, 6)) _result |= - _result || trade.CheckCondition(TRADE_COND_ACCOUNT, _method > 0 ? ACCOUNT_COND_EQUITY_01PC_HIGH + _result || trade.Check(TRADE_COND_ACCOUNT, _method > 0 ? ACCOUNT_COND_EQUITY_01PC_HIGH : ACCOUNT_COND_EQUITY_01PC_LOW); // 64 + */ // if (METHOD(_method, 7)) _result |= _result || Trade().IsRoundNumber(_cmd); // if (METHOD(_method, 8)) _result |= _result || Trade().IsHedging(_cmd); _method = _method > 0 ? _method : !_method; @@ -1089,6 +1093,10 @@ class Strategy : public Taskable { } return _result; } + bool Check(int _id) { + TaskConditionEntry _entry(_id); + return Check(_entry); + } /** * Gets a copy of structure. diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index b0ca39f06..e82723fab 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -119,7 +119,7 @@ struct TaskActionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } - DataParamEntry GetArg(int _index) { return args[_index]; } + DataParamEntry GetArg(int _index) const { return args[_index]; } int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } diff --git a/Trade.mqh b/Trade.mqh index 1d5a2a64e..021f29203 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -38,12 +38,12 @@ class Trade; #include "Object.mqh" #include "Order.mqh" #include "OrderQuery.h" -#include "Task/TaskAction.enum.h" -#include "Task/TaskCondition.enum.h" +#include "Task/TaskManager.h" +#include "Task/Taskable.h" #include "Trade.enum.h" #include "Trade.struct.h" -class Trade { +class Trade : public Taskable { public: Account account; Ref chart; @@ -51,6 +51,7 @@ class Trade { DictStruct> orders_history; DictStruct> orders_pending; Log logger; // Trade logger. + TaskManager tasks; // Tasks. TradeParams tparams; // Trade parameters. TradeStates tstates; // Trade states. TradeStats tstats; // Trade statistics. @@ -1716,44 +1717,49 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } } - /* Conditions */ + /* Tasks methods */ /** - * Checks for trade condition. - * - * @param ENUM_TRADE_CONDITION _cond - * Trade condition. - * @param MqlParam[] _args - * Condition arguments. - * @return - * Returns true when the condition is met. + * Add task. + */ + bool AddTask(TaskEntry &_tentry) { + bool _is_valid = _tentry.IsValid(); + if (_is_valid) { + TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); + tasks.Add(&_taskobj); + } + return _is_valid; + } + + /** + * Process tasks. + */ + void ProcessTasks() { tasks.Process(); } + + /* Tasks */ + + /** + * Checks a condition. */ - bool CheckCondition(ENUM_TRADE_CONDITION _cond, DataParamEntry &_args[]) { + virtual bool Check(const TaskConditionEntry &_entry) { bool _result = false; - long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; - long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; Ref _oquery_ref; if (Get(TRADE_STATE_ORDERS_ACTIVE)) { _oquery_ref = OrderQuery::GetInstance(orders_active); } - switch (_cond) { + switch (_entry.GetId()) { case TRADE_COND_ACCOUNT: - return account.CheckCondition((ENUM_ACCOUNT_CONDITION)_args[0].integer_value); + return account.CheckCondition(_entry.GetArg(0).ToValue()); case TRADE_COND_ALLOWED_NOT: return !IsTradeAllowed(); case TRADE_COND_HAS_STATE: - _arg1l = _arg1l != WRONG_VALUE ? _arg1l : 0; - return HasState((ENUM_TRADE_STATE)_arg1l); + return HasState(_entry.GetArg(0).ToValue()); case TRADE_COND_IS_ORDER_LIMIT: return tparams.IsLimitGe(tstats); case TRADE_COND_IS_PEAK: - _arg1l = _arg1l != WRONG_VALUE ? _arg1l : 0; - _arg2l = _arg2l != WRONG_VALUE ? _arg2l : 0; - return IsPeak((ENUM_ORDER_TYPE)_arg1l, (int)_arg2l); + return IsPeak(_entry.GetArg(0).ToValue(), _entry.GetArg(1).ToValue()); case TRADE_COND_IS_PIVOT: - _arg1l = _arg1l != WRONG_VALUE ? _arg1l : 0; - _arg2l = _arg2l != WRONG_VALUE ? _arg2l : 0; - return IsPivot((ENUM_ORDER_TYPE)_arg1l, (int)_arg2l); + return IsPivot(_entry.GetArg(0).ToValue(), _entry.GetArg(1).ToValue()); case TRADE_COND_ORDERS_PROFIT_GT_01PC: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { return CalcActiveEquityInPct() >= 1; @@ -1797,41 +1803,39 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // case TRADE_ORDER_CONDS_IN_TREND: // case TRADE_ORDER_CONDS_IN_TREND_NOT: default: - logger.Error(StringFormat("Invalid trade condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + GetLogger().Error(StringFormat("Invalid Trade condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); break; } return _result; } - bool CheckCondition(ENUM_TRADE_CONDITION _cond, long _arg1) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - ArrayPushObject(_args, _param1); - return Trade::CheckCondition(_cond, _args); - } - bool CheckCondition(ENUM_TRADE_CONDITION _cond) { - ARRAY(DataParamEntry, _args); - return Trade::CheckCondition(_cond, _args); + bool Check(int _id) { + TaskConditionEntry _entry(_id); + return Check(_entry); } - /* TaskActions */ + /** + * Gets a copy of structure. + */ + virtual DataParamEntry Get(const TaskGetterEntry &_entry) { + DataParamEntry _result; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } /** - * Execute trade action. - * - * @param ENUM_TRADE_ACTION _action - * Trade action to execute. - * @param MqlParam _args - * Trade action arguments. - * @return - * Returns true when the condition is met. + * Runs an action. */ - bool ExecuteAction(ENUM_TRADE_ACTION _action, DataParamEntry &_args[]) { + virtual bool Run(const TaskActionEntry &_entry) { bool _result = false; Ref _oquery_ref; if (Get(TRADE_STATE_ORDERS_ACTIVE)) { _oquery_ref = OrderQuery::GetInstance(orders_active); } - switch (_action) { + switch (_entry.GetId()) { case TRADE_ACTION_CALC_LOT_SIZE: tparams.Set(TRADE_PARAM_LOT_SIZE, CalcLotSize(tparams.Get(TRADE_PARAM_RISK_MARGIN))); return tparams.Get(TRADE_PARAM_LOT_SIZE) > 0; @@ -1870,7 +1874,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } break; case TRADE_ACTION_ORDER_OPEN: - return RequestSend(GetTradeOpenRequest((ENUM_ORDER_TYPE)_args[0].integer_value)); + return RequestSend(GetTradeOpenRequest(_entry.GetArg(0).ToValue())); case TRADE_ACTION_ORDERS_CLOSE_ALL: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { _result = OrdersCloseAll(ORDER_REASON_CLOSED_BY_ACTION) >= 0; @@ -1899,7 +1903,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDERS_CLOSE_BY_TYPE: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result = OrdersCloseViaCmd((ENUM_ORDER_TYPE)_args[0].integer_value, ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd(_entry.GetArg(0).ToValue(), ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; @@ -1926,37 +1930,36 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDERS_LIMIT_SET: // Sets the new limits. - tparams.SetLimits((ENUM_TRADE_STAT_TYPE)_args[0].integer_value, (ENUM_TRADE_STAT_PERIOD)_args[1].integer_value, - (int)_args[2].integer_value); + tparams.SetLimits(_entry.GetArg(0).ToValue(), + _entry.GetArg(1).ToValue(), _entry.GetArg(2).ToValue()); // Verify the new limits. - return tparams.GetLimits((ENUM_TRADE_STAT_TYPE)_args[0].integer_value, - (ENUM_TRADE_STAT_PERIOD)_args[1].integer_value) == _args[2].integer_value; + return tparams.GetLimits(_entry.GetArg(0).ToValue(), + _entry.GetArg(1).ToValue()) == _entry.GetArg(2).ToValue(); case TRADE_ACTION_STATE_ADD: - tstates.AddState((unsigned int)_args[0].integer_value); + tstates.AddState(_entry.GetArg(0).ToValue()); default: - logger.Error(StringFormat("Invalid trade action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - _result = false; + GetLogger().Error(StringFormat("Invalid Trade action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); break; } - return _result && GetLastError() == ERR_NO_ERROR; - } - bool ExecuteAction(ENUM_TRADE_ACTION _action) { - DataParamEntry _args[]; - return Trade::ExecuteAction(_action, _args); + return _result; } - bool ExecuteAction(ENUM_TRADE_ACTION _action, long _arg1) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - ArrayPushObject(_args, _param1); - return Trade::ExecuteAction(_action, _args); + bool Run(int _id) { + TaskActionEntry _entry(_id); + return Run(_entry); } - bool ExecuteAction(ENUM_TRADE_ACTION _action, long _arg1, long _arg2) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - DataParamEntry _param2 = _arg2; - ArrayPushObject(_args, _param1); - ArrayPushObject(_args, _param2); - return Trade::ExecuteAction(_action, _args); + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const DataParamEntry &_entry_value) { + bool _result = false; + switch (_entry.GetId()) { + // _entry_value.GetValue() + default: + break; + } + return _result; } /* Printer methods */ @@ -1964,7 +1967,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Returns textual representation of the Trade class. */ - string ToString() { return StringFormat("Margin required: %g/lot", GetMarginRequired()); } + string ToString() const { + // @todo + // return StringFormat("Margin required: %g/lot", GetMarginRequired()); + return ""; + } /* Class handlers */ From 61b201cc0cfc402546efb63947844162f338a1bb Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 23 Jan 2022 13:10:30 +0000 Subject: [PATCH 42/84] EA: Reenables initial task logic --- EA.mqh | 24 ++++++++++++++++++++---- EA.struct.h | 2 +- tests/EATest.mq5 | 6 +++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/EA.mqh b/EA.mqh index 43010c033..360d6aa2a 100644 --- a/EA.mqh +++ b/EA.mqh @@ -73,18 +73,34 @@ class EA : public Taskable { TaskManager tasks; TradeSignalManager tsm; + protected: + /* Protected methods */ + + /** + * Init code (called on constructor). + */ + void Init() { InitTask(); } + + /** + * Process initial task (called on constructor). + */ + void InitTask() { + // Add and process init task. + TaskObject _taskobj_init(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); + estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), true); + _taskobj_init.Process(); + estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), false); + } + public: /** * Class constructor. */ EA(EAParams &_params) : account(new Account) { eparams = _params; - estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), true); UpdateStateFlags(); // Add and process tasks. - AddTask(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); - ProcessTasks(); - estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), false); + Init(); // Initialize a trade instance for the current chart and symbol. ChartParams _cparams((ENUM_TIMEFRAMES)_Period, _Symbol); TradeParams _tparams; diff --git a/EA.struct.h b/EA.struct.h index ce30ff70d..5bed4845d 100644 --- a/EA.struct.h +++ b/EA.struct.h @@ -195,7 +195,7 @@ struct EAParams { ver = _ver; author = _author; } - // void SetTaskEntry(TaskEntry &_task_entry) { task_init = _task_entry; } + void SetTaskEntry(TaskEntry &_task_entry) { task_init = _task_entry; } // Printers. string ToString(string _dlm = ",") { return StringFormat("%s v%s by %s (%s)", name, ver, author, desc); } }; diff --git a/tests/EATest.mq5 b/tests/EATest.mq5 index 176be0a21..31d11e524 100644 --- a/tests/EATest.mq5 +++ b/tests/EATest.mq5 @@ -59,7 +59,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - //ea_params.SetTaskEntry(_task_export_per_hour); + ea_params.SetTaskEntry(_task_export_per_hour); ea = new EA(ea_params); assertTrueOrFail(ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA", StringFormat("Invalid EA name: %s!", ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)))); @@ -69,7 +69,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params1.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params1.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - //ea_params1.SetTaskEntry(_task_export_per_hour); + ea_params1.SetTaskEntry(_task_export_per_hour); ea1 = new EA1(ea_params1); assertTrueOrFail(ea1.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA1", "Invalid EA1 name!"); @@ -78,7 +78,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params2.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params2.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - //ea_params2.SetTaskEntry(_task_export_per_hour); + ea_params2.SetTaskEntry(_task_export_per_hour); ea2 = new EA2(ea_params2); assertTrueOrFail(ea2.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA2", "Invalid EA2 name!"); From 2d6c6cf72615a6b7f794381c73de6d0574cd9eba Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 23 Jan 2022 14:19:29 +0000 Subject: [PATCH 43/84] EA: Adds test for task init --- EA.mqh | 3 ++- tests/EATest.mq5 | 35 ++++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/EA.mqh b/EA.mqh index 360d6aa2a..d663ceff2 100644 --- a/EA.mqh +++ b/EA.mqh @@ -86,7 +86,8 @@ class EA : public Taskable { */ void InitTask() { // Add and process init task. - TaskObject _taskobj_init(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); + TaskObject _taskobj_init(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY)), + THIS_PTR, THIS_PTR); estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), true); _taskobj_init.Process(); estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), false); diff --git a/tests/EATest.mq5 b/tests/EATest.mq5 index 31d11e524..96eb8238f 100644 --- a/tests/EATest.mq5 +++ b/tests/EATest.mq5 @@ -42,10 +42,15 @@ class EA2 : public EA { EA2(EAParams &_params) : EA(_params) {} }; +class EA3 : public EA { + public: + EA3(EAParams &_params) : EA(_params) {} +}; + // Global variables. -EA *ea; EA1 *ea1; EA2 *ea2; +EA3 *ea3; /** * Implements OnInit(). @@ -54,16 +59,6 @@ int OnInit() { // Task to export to all possible formats once per hour. TaskEntry _task_export_per_hour(EA_ACTION_EXPORT_DATA, EA_COND_ON_NEW_HOUR); - /* Initialize base class EA */ - EAParams ea_params("EA"); - // Exporting to all possible formats once per hour. - ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); - ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - ea_params.SetTaskEntry(_task_export_per_hour); - ea = new EA(ea_params); - assertTrueOrFail(ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA", - StringFormat("Invalid EA name: %s!", ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)))); - /* Initialize 1st custom EA */ EAParams ea_params1("EA1"); // Exporting to all possible formats once per hour. @@ -71,9 +66,11 @@ int OnInit() { ea_params1.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); ea_params1.SetTaskEntry(_task_export_per_hour); ea1 = new EA1(ea_params1); - assertTrueOrFail(ea1.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA1", "Invalid EA1 name!"); + assertTrueOrFail(ea1.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA1", + StringFormat("Invalid EA name: %s!", ea1.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)))); + assertTrueOrFail(ea1.Get(STRUCT_ENUM(EAState, EA_STATE_FLAG_ENABLED)), "EA should be enabled by default!"); - /* Initialize 2st custom EA */ + /* Initialize 2nd custom EA */ EAParams ea_params2("EA2"); // Exporting to all possible formats once per hour. ea_params2.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); @@ -82,6 +79,14 @@ int OnInit() { ea2 = new EA2(ea_params2); assertTrueOrFail(ea2.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA2", "Invalid EA2 name!"); + /* Initialize 3rd custom EA */ + EAParams ea_params3("EA3"); + // Create an init task to disable EA when enabled. + TaskEntry _tentry_ea_disable(EA_ACTION_DISABLE, EA_COND_IS_ENABLED); + ea_params3.SetTaskEntry(_tentry_ea_disable); + ea3 = new EA3(ea_params3); + assertTrueOrFail(!ea3.Get(STRUCT_ENUM(EAState, EA_STATE_FLAG_ENABLED)), "EA should be disabled by a task!"); + return (INIT_SUCCEEDED); } @@ -89,16 +94,16 @@ int OnInit() { * Implements OnTick(). */ void OnTick() { - ea.ProcessTick(); ea1.ProcessTick(); ea2.ProcessTick(); + ea3.ProcessTick(); } /** * Implements OnDeinit(). */ void OnDeinit(const int reason) { - delete ea; delete ea1; delete ea2; + delete ea3; } From 6941c25b41b2b60f8a833ad3595464836db5771f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 26 Jan 2022 17:55:49 +0100 Subject: [PATCH 44/84] Added TaskManager::Add(string _entry) method which creates TaskEntry from JSON string. --- SerializerConverter.mqh | 4 ++++ Task/Task.struct.h | 9 +++++++++ Task/TaskCondition.struct.h | 15 +++++++++++++++ Task/TaskManager.h | 13 +++++++++++++ Task/tests/TaskManager.test.mq5 | 4 ++++ 5 files changed, 45 insertions(+) diff --git a/SerializerConverter.mqh b/SerializerConverter.mqh index 37753e76d..f9076e71d 100644 --- a/SerializerConverter.mqh +++ b/SerializerConverter.mqh @@ -84,6 +84,10 @@ class SerializerConverter { template static SerializerConverter FromString(string arg) { SerializerConverter _converter(((C*)NULL).Parse(arg), 0); +#ifdef __debug__ + Print("FromString(): result: ", + _converter.Node() != NULL ? _converter.Node().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); +#endif return _converter; } diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 81d8ba682..d9ab789c5 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -132,4 +132,13 @@ struct TaskEntry { int GetConditionId() { return cond.GetId(); } TaskActionEntry GetAction() { return action; } TaskConditionEntry GetCondition() { return cond; } + + public: + SerializerNodeType Serialize(Serializer &s) { + s.PassStruct(THIS_REF, "aentry", action); + s.PassStruct(THIS_REF, "centry", cond); + return SerializerNodeObject; + } + + SERIALIZER_EMPTY_STUB; }; diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 49ddf4eec..24df55dc7 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -188,4 +188,19 @@ struct TaskConditionEntry { } ::ArrayResize(args, _index - 1); } + + public: + // Serializers + SerializerNodeType Serialize(Serializer &s) { + s.Pass(THIS_REF, "flags", flags); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "last_check", last_check); + s.Pass(THIS_REF, "last_success", last_success); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); + s.PassArray(this, "args", args); + return SerializerNodeObject; + } + + SERIALIZER_EMPTY_STUB; }; diff --git a/Task/TaskManager.h b/Task/TaskManager.h index 7559f5ce5..2ae9dd44f 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -36,6 +36,9 @@ // Includes. #include "../DictObject.mqh" +#include "../SerializerConverter.mqh" +#include "../SerializerJson.mqh" +#include "Task.struct.h" #include "TaskObject.h" class TaskManager { @@ -74,6 +77,16 @@ class TaskManager { return tasks.Push(_ref); } + /** + * Adds new task. + */ + bool Add(string _entry_str) { + TaskEntry _entry; + SerializerConverter::FromString(_entry_str).ToObject(_entry); + Ref _task = new Task(_entry); + return Add(_task.Ptr()); + } + /** * Adds new object task. */ diff --git a/Task/tests/TaskManager.test.mq5 b/Task/tests/TaskManager.test.mq5 index fa8fd72a9..4ade617b8 100644 --- a/Task/tests/TaskManager.test.mq5 +++ b/Task/tests/TaskManager.test.mq5 @@ -81,6 +81,10 @@ bool TestTaskManager01() { _tsm.Add(_taskobj02.Ptr()); _tsm.Add(_taskobj03.Ptr()); _tsm.Add(_taskobj04.Ptr()); + + // @todo: Need a way to test if object was added properly. + _tsm.Add("{\"aentry\": {\"id\": 1}, \"centry\": {\"id\": 2}}"); + _tsm.Process(); // @todo: Print via ToString(). return _result; From a08550590a1e360dbf7442b6be8df2bda2e8fa03 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 2 Feb 2022 17:56:17 +0100 Subject: [PATCH 45/84] Indi_Drawer will now have max_modes=1 in order to simulate a single, valid buffer. Also removed unnecessary debug prints in Indi_AMA. --- Indicators/Indi_AMA.mqh | 5 ----- Indicators/Indi_Drawer.struct.h | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index e72de2fdc..489595e09 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -176,11 +176,6 @@ class Indi_AMA : public IndicatorTickOrCandleSource { CalculateInit(InpPeriodAMA, InpFastPeriodEMA, InpSlowPeriodEMA, InpShiftAMA, ExtFastSC, ExtSlowSC, ExtPeriodAMA, ExtSlowPeriodEMA, ExtFastPeriodEMA); - - for (int x = prev_calculated; x < rates_total; ++x) { - Print("price[", x, "] = ", price[x].Get(), ", O = ", iOpen(Symbol(), PERIOD_CURRENT, Bars(Symbol(), PERIOD_CURRENT) - x - 1)); - } - int i; // Check for rates count. if (rates_total < ExtPeriodAMA + begin) return (0); diff --git a/Indicators/Indi_Drawer.struct.h b/Indicators/Indi_Drawer.struct.h index e868d110e..608e953d6 100644 --- a/Indicators/Indi_Drawer.struct.h +++ b/Indicators/Indi_Drawer.struct.h @@ -39,6 +39,8 @@ struct IndiDrawerParams : IndicatorParams { : period(_period), applied_price(_ap), IndicatorParams(INDI_DRAWER, 0, TYPE_DOUBLE) { // Fetching history data is not yet implemented. SetCustomIndicatorName("Examples\\Drawer"); + // Simulating a single, valid buffer. + max_modes = 1; }; IndiDrawerParams(IndiDrawerParams &_params, ENUM_TIMEFRAMES _tf) { THIS_REF = _params; From 243ae3a940a753756be48400336f2b76162f8adf Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 31 Jan 2022 00:10:44 +0000 Subject: [PATCH 46/84] Adds CPP tests for Task-related classes --- Task/tests/Task.test.cpp | 35 +++++++++++++++++++++++++++ Task/tests/TaskAction.test.cpp | 35 +++++++++++++++++++++++++++ Task/tests/TaskActionBase.test.cpp | 35 +++++++++++++++++++++++++++ Task/tests/TaskCondition.test.cpp | 35 +++++++++++++++++++++++++++ Task/tests/TaskConditionBase.test.cpp | 35 +++++++++++++++++++++++++++ Task/tests/TaskGetter.test.cpp | 35 +++++++++++++++++++++++++++ Task/tests/TaskGetterBase.test.cpp | 35 +++++++++++++++++++++++++++ Task/tests/TaskManager.test.cpp | 35 +++++++++++++++++++++++++++ Task/tests/TaskObject.test.cpp | 35 +++++++++++++++++++++++++++ Task/tests/TaskSetter.test.cpp | 34 ++++++++++++++++++++++++++ Task/tests/Taskable.test.cpp | 35 +++++++++++++++++++++++++++ 11 files changed, 384 insertions(+) create mode 100644 Task/tests/Task.test.cpp create mode 100644 Task/tests/TaskAction.test.cpp create mode 100644 Task/tests/TaskActionBase.test.cpp create mode 100644 Task/tests/TaskCondition.test.cpp create mode 100644 Task/tests/TaskConditionBase.test.cpp create mode 100644 Task/tests/TaskGetter.test.cpp create mode 100644 Task/tests/TaskGetterBase.test.cpp create mode 100644 Task/tests/TaskManager.test.cpp create mode 100644 Task/tests/TaskObject.test.cpp create mode 100644 Task/tests/TaskSetter.test.cpp create mode 100644 Task/tests/Taskable.test.cpp diff --git a/Task/tests/Task.test.cpp b/Task/tests/Task.test.cpp new file mode 100644 index 000000000..9b12549aa --- /dev/null +++ b/Task/tests/Task.test.cpp @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of Task class. + */ + +// Includes. +#include "../Task.h" + +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" + +int main(int argc, char **argv) {} diff --git a/Task/tests/TaskAction.test.cpp b/Task/tests/TaskAction.test.cpp new file mode 100644 index 000000000..79a16e95e --- /dev/null +++ b/Task/tests/TaskAction.test.cpp @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of TaskAction class. + */ + +// Includes. +#include "../TaskAction.h" + +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" + +int main(int argc, char **argv) {} diff --git a/Task/tests/TaskActionBase.test.cpp b/Task/tests/TaskActionBase.test.cpp new file mode 100644 index 000000000..8bddd771e --- /dev/null +++ b/Task/tests/TaskActionBase.test.cpp @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of TaskActionBase class. + */ + +// Includes. +#include "../TaskActionBase.h" + +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" + +int main(int argc, char **argv) {} diff --git a/Task/tests/TaskCondition.test.cpp b/Task/tests/TaskCondition.test.cpp new file mode 100644 index 000000000..6689d9e2b --- /dev/null +++ b/Task/tests/TaskCondition.test.cpp @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of TaskCondition class. + */ + +// Includes. +#include "../TaskCondition.h" + +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" + +int main(int argc, char **argv) {} diff --git a/Task/tests/TaskConditionBase.test.cpp b/Task/tests/TaskConditionBase.test.cpp new file mode 100644 index 000000000..12bc9c618 --- /dev/null +++ b/Task/tests/TaskConditionBase.test.cpp @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of TaskConditionBase class. + */ + +// Includes. +#include "../TaskConditionBase.h" + +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" + +int main(int argc, char **argv) {} diff --git a/Task/tests/TaskGetter.test.cpp b/Task/tests/TaskGetter.test.cpp new file mode 100644 index 000000000..e34c6dc56 --- /dev/null +++ b/Task/tests/TaskGetter.test.cpp @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of TaskGetter class. + */ + +// Includes. +#include "../TaskGetter.h" + +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" + +int main(int argc, char **argv) {} diff --git a/Task/tests/TaskGetterBase.test.cpp b/Task/tests/TaskGetterBase.test.cpp new file mode 100644 index 000000000..7d47abf1c --- /dev/null +++ b/Task/tests/TaskGetterBase.test.cpp @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of TaskGetterBase class. + */ + +// Includes. +#include "../TaskGetterBase.h" + +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" + +int main(int argc, char **argv) {} diff --git a/Task/tests/TaskManager.test.cpp b/Task/tests/TaskManager.test.cpp new file mode 100644 index 000000000..c92dbf5ba --- /dev/null +++ b/Task/tests/TaskManager.test.cpp @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of TaskManager class. + */ + +// Includes. +#include "../TaskManager.h" + +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" + +int main(int argc, char **argv) {} diff --git a/Task/tests/TaskObject.test.cpp b/Task/tests/TaskObject.test.cpp new file mode 100644 index 000000000..c4d09897b --- /dev/null +++ b/Task/tests/TaskObject.test.cpp @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of TaskObject class. + */ + +// Includes. +#include "../TaskObject.h" + +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" + +int main(int argc, char **argv) {} diff --git a/Task/tests/TaskSetter.test.cpp b/Task/tests/TaskSetter.test.cpp new file mode 100644 index 000000000..c422842f2 --- /dev/null +++ b/Task/tests/TaskSetter.test.cpp @@ -0,0 +1,34 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of TaskSetter class. + */ + +// Includes. +#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/Task/tests/Taskable.test.cpp b/Task/tests/Taskable.test.cpp new file mode 100644 index 000000000..c0063e7a8 --- /dev/null +++ b/Task/tests/Taskable.test.cpp @@ -0,0 +1,35 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of Taskable class. + */ + +// Includes. +#include "../Taskable.h" + +#include "../../Common.define.h" +#include "../../Common.extern.h" +#include "../../Std.h" +#include "../../String.extern.h" + +int main(int argc, char **argv) {} From 5c78a9b11eb5945c1e7cb650dac5636ed3ad52db Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 27 Jan 2022 23:12:19 +0000 Subject: [PATCH 47/84] Adds CONTRIBUTING.md file --- CONTRIBUTING.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..aa721a3f4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,43 @@ +# Contributing + +## Bugs + +### Submitting A Bug Report + +Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). +After you've determined which repository your bug is related to, +create an issue on that repository and provide the details. + +## Code + +### Compatibility + +We aim at syntax compatibility with 3 languages at once: MQL4, MQL5 and C++. + +### Coding conventions + +To optimize the code for readability, please follow these guidelines: + +* Indent using two spaces (soft tabs). +* Consider the people who will read your code, and make it look nice for them. + +We use a `clang-format` code formatter tool to format the code +(both MQL and C++ files). + +For example, to format file inplace, run: + + clang-format -i File.mqh + +## Proposing changes + +To propose a code change on GitHub, +please send a [Pull Request](https://support.github.com/features/pull-requests). + +## Testing + +### Continuous integration + +The project uses [GitHub Actions](https://github.com/features/actions) +to automate builds and tests. + +When contributing, your code should pass all the CI tests. From 66d9918cc6bcfbc1921170ea57078b4057118d61 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 3 Feb 2022 19:40:35 +0100 Subject: [PATCH 48/84] WIP. More compatibility with C++. --- Account/Account.extern.h | 1 + Convert.extern.h | 4 +- Data.struct.h | 18 ++++--- DictStruct.mqh | 100 +++++++++++++++++++----------------- Std.h | 11 ++-- String.extern.h | 3 +- Task/Task.struct.h | 6 +-- Task/TaskAction.struct.h | 28 ++++++---- Task/TaskActionBase.h | 2 +- Task/TaskCondition.struct.h | 17 +++--- Task/TaskConditionBase.h | 2 +- Task/TaskGetter.struct.h | 10 ++-- 12 files changed, 116 insertions(+), 86 deletions(-) diff --git a/Account/Account.extern.h b/Account/Account.extern.h index 28aa8909d..e3378c4c4 100644 --- a/Account/Account.extern.h +++ b/Account/Account.extern.h @@ -21,6 +21,7 @@ */ // Includes. +#include "../String.extern.h" #include "Account.enum.h" // Define external global functions. diff --git a/Convert.extern.h b/Convert.extern.h index 353a96b6b..4a5a02ed0 100644 --- a/Convert.extern.h +++ b/Convert.extern.h @@ -28,7 +28,7 @@ // Define external global functions. #ifndef __MQL__ extern double NormalizeDouble(double value, int digits); -extern string CharToString(uchar char_code); +extern string CharToString(unsigned char char_code); extern string DoubleToString(double value, int digits = 8); -extern string ShortToString(ushort symbol_code); +extern string ShortToString(unsigned short symbol_code); #endif diff --git a/Data.struct.h b/Data.struct.h index 37e15051a..81d4cb517 100644 --- a/Data.struct.h +++ b/Data.struct.h @@ -56,7 +56,7 @@ struct MqlParam { double double_value; // Field to store a double type. string string_value; // Field to store a string type. }; - MqlParam() { type = (ENUM_DATATYPE)WRONG_VALUE; } + MqlParam() { type = InvalidEnumValue::value(); } MqlParam(const MqlParam &_r) { THIS_REF = _r; } @@ -83,6 +83,7 @@ struct MqlParam { case TYPE_STRING: string_value = _r.string_value; } + return THIS_REF; } MqlParam(long _value) { @@ -118,7 +119,7 @@ struct MqlParam { */ struct DataParamEntry : public MqlParam { public: - DataParamEntry() { type = (ENUM_DATATYPE)WRONG_VALUE; } + DataParamEntry() { type = InvalidEnumValue::value(); } DataParamEntry(ENUM_DATATYPE _type, long _integer_value, double _double_value, string _string_value) { type = _type; integer_value = _integer_value; @@ -189,14 +190,14 @@ struct DataParamEntry : public MqlParam { return (T)::StringToDouble(string_value); case TYPE_DOUBLE: case TYPE_FLOAT: - return (T)ToDouble(this); + return (T)ToDouble(THIS_REF); default: case TYPE_BOOL: case TYPE_INT: case TYPE_LONG: case TYPE_UINT: case TYPE_ULONG: - return (T)ToInteger(this); + return (T)ToInteger(THIS_REF); } } @@ -278,8 +279,12 @@ struct DataParamEntry : public MqlParam { case TYPE_STRING: case TYPE_UCHAR: return ::StringToDouble(param.string_value); + case TYPE_COLOR: + case TYPE_DATETIME: + case TYPE_SHORT: + case TYPE_USHORT: + return DBL_MIN; } - return DBL_MIN; } /** @@ -305,8 +310,9 @@ struct DataParamEntry : public MqlParam { case TYPE_STRING: case TYPE_UCHAR: return ::StringToInteger(param.string_value); + case TYPE_USHORT: + return INT_MIN; } - return INT_MIN; } /* Serializers */ diff --git a/DictStruct.mqh b/DictStruct.mqh index 405dcee7a..3e1ae5d22 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -58,36 +58,36 @@ class DictStruct : public DictBase { Clear(); Resize(right.GetSlotCount()); for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; + this PTR_DEREF _DictSlots_ref PTR_DEREF 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 DictStruct& right) { Clear(); Resize(right.GetSlotCount()); for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - _DictSlots_ref.DictSlots[i] = right._DictSlots_ref.DictSlots[i]; + this PTR_DEREF _DictSlots_ref PTR_DEREF 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) { - _DictSlots_ref.DictSlots[i].SetFlags(0); + for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { + THIS_ATTR _DictSlots_ref PTR_DEREF DictSlots[i].SetFlags(0); } - _DictSlots_ref._num_used = 0; + THIS_ATTR _DictSlots_ref PTR_DEREF _num_used = 0; } DictStructIterator Begin() { // Searching for first item index. - for (unsigned int i = 0; i < (unsigned int)ArraySize(_DictSlots_ref.DictSlots); ++i) { - if (_DictSlots_ref.DictSlots[i].IsValid() && _DictSlots_ref.DictSlots[i].IsUsed()) { + for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { + if (THIS_ATTR _DictSlots_ref.DictSlots[i].IsValid() && THIS_ATTR _DictSlots_ref.DictSlots[i].IsUsed()) { DictStructIterator iter(this, i); return iter; } @@ -101,7 +101,7 @@ class DictStruct : public DictBase { * 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; } @@ -119,7 +119,7 @@ class DictStruct : public DictBase { bool Push(Dynamic* value) { V ptr = value; - if (!InsertInto(_DictSlots_ref, ptr)) return false; + if (!InsertInto(THIS_ATTR _DictSlots_ref, ptr)) return false; return true; } @@ -127,7 +127,7 @@ class DictStruct : 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; } @@ -139,10 +139,10 @@ class DictStruct : public DictBase { int position; - if (_mode == DictModeList) - slot = GetSlot((unsigned int)key); + if (THIS_ATTR _mode == DictModeList) + slot = THIS_ATTR GetSlot((unsigned int)key); else - slot = GetSlotByKey(_DictSlots_ref, key, position); + slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); if (slot == NULL || !slot.IsUsed()) { Alert("Invalid DictStruct key \"", key, "\" (called by [] operator). Returning empty structure."); @@ -159,7 +159,7 @@ class DictStruct : public DictBase { */ V GetByKey(const K _key) { unsigned int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, _key, position); + DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); if (!slot) { static V _empty; @@ -177,7 +177,7 @@ class DictStruct : public DictBase { */ V GetByKey(const K _key, V& _default) { unsigned int position; - DictSlot* slot = GetSlotByKey(_DictSlots_ref, _key, position); + DictSlot* slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, _key, position); if (!slot) { return _default; @@ -190,7 +190,7 @@ class DictStruct : public DictBase { * Returns value for a given position. */ V GetByPos(unsigned int _position) { - DictSlot* slot = GetSlotByPos(_DictSlots_ref, _position); + DictSlot* slot = THIS_ATTR GetSlotByPos(THIS_ATTR _DictSlots_ref, _position); if (!slot) { Alert("Invalid DictStruct position \"", _position, "\" (called by GetByPos()). Returning empty structure."); @@ -224,10 +224,12 @@ class DictStruct : public DictBase { /** * Checks whether dictionary contains given key and value. */ +#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; @@ -237,7 +239,9 @@ class DictStruct : public DictBase { /** * Returns index of dictionary's value or -1 if value doesn't exist. */ +#ifdef __MQL__ template <> +#endif int IndexOf(const V& value) { for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { if (i.Value() == value) { @@ -253,9 +257,9 @@ class DictStruct : public DictBase { * Inserts value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { - if (_mode == DictModeUnknown) - _mode = DictModeDict; - else if (_mode != DictModeDict) { + if (THIS_ATTR _mode == DictModeUnknown) + THIS_ATTR _mode = DictModeDict; + else if (THIS_ATTR _mode != DictModeDict) { Alert("Warning: Dict already operates as a list, not a dictionary!"); return false; } @@ -263,13 +267,13 @@ class DictStruct : public DictBase { unsigned int position; DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); - if (keySlot == NULL && !IsGrowUpAllowed()) { + if (keySlot == NULL && !THIS_ATTR IsGrowUpAllowed()) { // Resize is prohibited. return false; } // Will resize dict if there were performance problems before. - if (allow_resize && IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (allow_resize && THIS_ATTR IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { if (!GrowUp()) { return false; } @@ -279,7 +283,7 @@ class DictStruct : public DictBase { if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { // No DictSlotsRef.DictSlots available. - if (overflow_listener != NULL) { + if (THIS_ATTR overflow_listener != NULL) { if (!overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { // Overwriting slot pointed exactly by key's position in the hash table (we don't check for possible // conflicts). @@ -303,8 +307,9 @@ class DictStruct : public DictBase { // Searching for empty DictSlot or used one with the matching key. It skips used, hashless DictSlots. while (dictSlotsRef.DictSlots[position].IsUsed() && (!dictSlotsRef.DictSlots[position].HasKey() || dictSlotsRef.DictSlots[position].key != key)) { - if (overflow_listener_max_conflicts != 0 && ++_num_conflicts == overflow_listener_max_conflicts) { - if (overflow_listener != NULL) { + if (THIS_ATTR overflow_listener_max_conflicts != 0 && + ++_num_conflicts == THIS_ATTR overflow_listener_max_conflicts) { + if (THIS_ATTR overflow_listener != NULL) { if (!overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used, _num_conflicts)) { // Overflow listener returned false so we won't search for further empty slot. _overwrite_slot = true; @@ -343,9 +348,9 @@ class DictStruct : public DictBase { * Inserts hashless value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { - if (_mode == DictModeUnknown) - _mode = DictModeList; - else if (_mode != DictModeList) { + if (THIS_ATTR _mode == DictModeUnknown) + THIS_ATTR _mode = DictModeList; + else if (THIS_ATTR _mode != DictModeList) { Alert("Warning: Dict already operates as a dictionary, not a list!"); return false; } @@ -355,7 +360,7 @@ class DictStruct : 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()) { @@ -375,14 +380,15 @@ class DictStruct : 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 THIS_ATTR_DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } /** * Shrinks or expands array of DictSlots. */ bool Resize(int new_size) { - if (new_size <= MathMin(_DictSlots_ref._num_used, ArraySize(_DictSlots_ref.DictSlots))) { + if (new_size <= MathMin(THIS_ATTR _DictSlots_ref._num_used, ArraySize(THIS_ATTR _DictSlots_ref.DictSlots))) { // We already use minimum number of slots possible. return true; } @@ -398,20 +404,22 @@ class DictStruct : public DictBase { } // Copies entire array of DictSlots into new array of DictSlots. Hashes will be rehashed. - for (i = 0; i < ArraySize(_DictSlots_ref.DictSlots); ++i) { - if (!_DictSlots_ref.DictSlots[i].IsUsed()) continue; + for (i = 0; i < ArraySize(THIS_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); - _DictSlots_ref = new_DictSlots; + THIS_ATTR _DictSlots_ref = new_DictSlots; return true; } @@ -423,9 +431,9 @@ class DictStruct : public DictBase { SerializerNodeType Serialize(Serializer& s) { if (s.IsWriting()) { for (DictIteratorBase i(Begin()); i.IsValid(); ++i) - s.PassObject(this, GetMode() == DictModeDict ? i.KeyAsString() : "", i.Value()); + s.PassObject(this, THIS_ATTR GetMode() == DictModeDict ? i.KeyAsString() : "", i.Value()); - return (GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray; + return (THIS_ATTR GetMode() == DictModeDict) ? SerializerNodeObject : SerializerNodeArray; } else { if (s.IsArray()) { unsigned int num_items = s.NumArrayItems(); diff --git a/Std.h b/Std.h index cd268432c..e23332fab 100644 --- a/Std.h +++ b/Std.h @@ -26,6 +26,7 @@ #include "Math.define.h" #endif + // Data types. #ifdef __cplusplus #include @@ -37,11 +38,12 @@ #ifdef __MQL__ #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 THIS_ATTR #define THIS_PTR (&this) #define THIS_REF this #define PTR_DEREF . @@ -50,6 +52,7 @@ #define PTR_TO_REF(PTR) PTR #define MAKE_REF_FROM_PTR(TYPE, NAME, PTR) TYPE* NAME = PTR #else +#define THIS_ATTR this-> #define THIS_PTR (this) #define THIS_REF (*this) #define PTR_DEREF -> @@ -71,7 +74,7 @@ #ifdef __MQL__ #define ARRAY_DECLARATION_BRACKETS [] #else -// C++'s _cpp_array is an object, so no brackets are nedded. +// C++'s _cpp_array is an object, so no brackets are needed. #define ARRAY_DECLARATION_BRACKETS #endif @@ -201,14 +204,14 @@ class color { #else #define C_STR(S) cstring_from(S) -const char* cstring_from(const std::string& _value) { return _value.c_str(); } +inline const char* cstring_from(const std::string& _value) { return _value.c_str(); } #endif #ifdef __cplusplus using std::string; #endif -bool IsNull(const string& str) { return str == ""; } +inline bool IsNull(const string& str) { return str == ""; } /** * Referencing struct's enum. diff --git a/String.extern.h b/String.extern.h index 04f359fef..1cc9542cb 100644 --- a/String.extern.h +++ b/String.extern.h @@ -23,6 +23,7 @@ // Prevents processing this includes file for the second time. #ifndef __MQL__ #pragma once +#include "Std.h" #include "Terminal.define.h" #endif @@ -37,6 +38,6 @@ extern string IntegerToString(long number, int str_len = 0, ushort fill_symbol = extern string StringFormat(string format, ...); extern string StringSubstr(string string_value, int start_pos, int length = -1); extern ushort StringGetCharacter(string string_value, int pos); -int StringToCharArray(string text_string, ARRAY_REF(uchar, array), int start = 0, int count = -1, +int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, uint codepage = CP_ACP); #endif diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 2b2e3282f..1820d3d8c 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -64,10 +64,10 @@ struct TaskEntry { public: // Constructors. - void TaskEntry() { Init(); } - void TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } + TaskEntry() { Init(); } + TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } template - void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { + TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { Init(); }; // Getters. diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 8e5774d3a..756248422 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -58,23 +58,28 @@ struct TaskActionEntry { }; protected: - unsigned char flags; /* TaskAction flags. */ - datetime time_last_run; /* Time of the successful run. */ + ARRAY(DataParamEntry, args); /* TaskAction arguments. */ + unsigned char flags; /* TaskAction flags. */ int freq; /* How often to run (0 for no limit). */ int id; /* TaskAction's enum ID. */ + datetime time_last_run; /* Time of the successful run. */ short tries; /* Number of retries left (-1 for unlimited). */ - DataParamEntry args[]; /* TaskAction arguments. */ protected: // Protected methods. - void Init() { SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + void Init() { + SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), + id == InvalidEnumValue::value()); + } public: // Constructors. - TaskActionEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_run(0), tries(-1) { Init(); } + TaskActionEntry() : flags(0), freq(60), id(InvalidEnumValue::value()), time_last_run(0), tries(-1) { + Init(); + } TaskActionEntry(int _id) : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), - id(_id), freq(60), + id(_id), time_last_run(0), tries(-1) { Init(); @@ -83,7 +88,7 @@ struct TaskActionEntry { // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } - void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void RemoveFlags(unsigned char _flags) { flags &= (unsigned char)~_flags; } void SetFlag(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value) { if (_value) { AddFlags(_flag); @@ -118,12 +123,12 @@ struct TaskActionEntry { break; } SetUserError(ERR_INVALID_PARAMETER); - return WRONG_VALUE; + return InvalidEnumValue::value(); } DataParamEntry GetArg(int _index) const { return args[_index]; } int GetId() const { return id; } // Setters. - void TriesDec() { tries -= tries > 0 ? 1 : 0; } + void TriesDec() { if(tries > 0) --tries; } void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value = true) { SetFlag(_flag, _value); } @@ -138,7 +143,8 @@ struct TaskActionEntry { return; case TASK_ACTION_ENTRY_ID: id = (int)_value; - SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), + id == InvalidEnumValue::value()); return; case TASK_ACTION_ENTRY_TRIES: tries = (short)_value; @@ -184,7 +190,7 @@ struct TaskActionEntry { s.Pass(THIS_REF, "time_last_run", time_last_run); s.Pass(THIS_REF, "tries", tries); s.PassEnum(THIS_REF, "freq", freq); - s.PassArray(this, "args", args); + s.PassArray(THIS_REF, "args", args); return SerializerNodeObject; } diff --git a/Task/TaskActionBase.h b/Task/TaskActionBase.h index 55c99c1e8..eb2a4df0f 100644 --- a/Task/TaskActionBase.h +++ b/Task/TaskActionBase.h @@ -51,7 +51,7 @@ class TaskActionBase { /** * Runs an action. */ - virtual bool Run(const TaskActionEntry &_entry) = NULL; + virtual bool Run(const TaskActionEntry &_entry) = 0; }; #endif // TASK_ACTION_BASE_H diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index a6b4252e8..b12998699 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -67,14 +67,17 @@ struct TaskConditionEntry { short tries; // Number of successful tries left (-1 for unlimited). // ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. // ENUM_TASK_CONDITION_TYPE type; // Task's condition type. - DataParamEntry args[]; // Task's condition arguments. + ARRAY(DataParamEntry, args); // Task's condition arguments. protected: // Protected methods. - void Init() { SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + void Init() { + SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), + id == InvalidEnumValue::value()); + } public: // Constructors. - TaskConditionEntry() : flags(0), freq(60), id(WRONG_VALUE), tries(-1) { Init(); } + TaskConditionEntry() : flags(0), freq(60), id(InvalidEnumValue::value()), tries(-1) { Init(); } TaskConditionEntry(int _id) : flags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)), freq(60), @@ -86,7 +89,7 @@ struct TaskConditionEntry { } TaskConditionEntry(TaskConditionEntry &_ae) { THIS_REF = _ae; } // Deconstructor. - void ~TaskConditionEntry() {} + ~TaskConditionEntry() {} // Getters. bool Get(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag) const { return HasFlag(_flag); } template @@ -108,7 +111,7 @@ struct TaskConditionEntry { break; } SetUserError(ERR_INVALID_PARAMETER); - return WRONG_VALUE; + return InvalidEnumValue::value(); } DataParamEntry GetArg(int _index) const { return args[_index]; } int GetId() const { return id; } @@ -128,7 +131,7 @@ struct TaskConditionEntry { return; case TASK_CONDITION_ENTRY_ID: id = (int)_value; - SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == InvalidEnumValue::value()); return; case TASK_CONDITION_ENTRY_TRIES: tries = (short)_value; @@ -199,7 +202,7 @@ struct TaskConditionEntry { s.Pass(THIS_REF, "last_success", last_success); s.Pass(THIS_REF, "tries", tries); s.PassEnum(THIS_REF, "freq", freq); - s.PassArray(this, "args", args); + s.PassArray(THIS_REF, "args", args); return SerializerNodeObject; } diff --git a/Task/TaskConditionBase.h b/Task/TaskConditionBase.h index 0e8e12d5b..29c7df8c4 100644 --- a/Task/TaskConditionBase.h +++ b/Task/TaskConditionBase.h @@ -51,7 +51,7 @@ class TaskConditionBase { /** * Checks a condition. */ - virtual bool Check(const TaskConditionEntry &_entry) = NULL; + virtual bool Check(const TaskConditionEntry &_entry) = 0; }; #endif // TASK_CONDITION_BASE_H diff --git a/Task/TaskGetter.struct.h b/Task/TaskGetter.struct.h index f937f9cf8..2505209ac 100644 --- a/Task/TaskGetter.struct.h +++ b/Task/TaskGetter.struct.h @@ -63,14 +63,16 @@ struct TaskGetterEntry { int freq; /* How often to run (0 for no limit). */ int id; /* TaskGetter's enum ID. */ short tries; /* Number of retries left (-1 for unlimited). */ - DataParamEntry args[]; /* TaskGetter arguments. */ + ARRAY(DataParamEntry, args); /* TaskGetter arguments. */ protected: // Protected methods. - void Init() { SetFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + void Init() { + SetFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_INVALID), id == InvalidEnumValue::value()); + } public: // Constructors. - TaskGetterEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_get(0), tries(-1) { Init(); } + TaskGetterEntry() : flags(0), freq(60), id(InvalidEnumValue::value()), time_last_get(0), tries(-1) { Init(); } TaskGetterEntry(int _id) : flags(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)), id(_id), @@ -79,7 +81,7 @@ struct TaskGetterEntry { tries(-1) { Init(); } - TaskGetterEntry(TaskGetterEntry &_ae) { this = _ae; } + TaskGetterEntry(TaskGetterEntry &_ae) { THIS_REF = _ae; } // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } From d75e22943185497d7b53eb690ac9f8601bdd1b4b Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 4 Feb 2022 20:45:37 +0100 Subject: [PATCH 49/84] WIP. More C++ compatibility. --- DictStruct.mqh | 28 ++++++++++++------------- Serializer.mqh | 2 +- Task/Task.h | 6 +++--- Task/Task.struct.h | 6 +++--- Task/TaskAction.struct.h | 24 ++++++++++----------- Task/TaskCondition.struct.h | 25 ++++++++++++---------- Task/TaskGetter.struct.h | 36 +++++++++++++++++++------------ Task/TaskGetterBase.h | 2 +- Task/TaskSetter.struct.h | 42 ++++++++++++++++++++++++------------- Task/TaskSetterBase.h | 2 +- Task/Taskable.h | 8 +++---- 11 files changed, 102 insertions(+), 79 deletions(-) diff --git a/DictStruct.mqh b/DictStruct.mqh index 3e1ae5d22..1e6d8e800 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -69,7 +69,7 @@ class DictStruct : public DictBase { Clear(); Resize(right.GetSlotCount()); for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { - this PTR_DEREF _DictSlots_ref PTR_DEREF DictSlots[i] = 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; @@ -78,17 +78,17 @@ class DictStruct : public DictBase { void Clear() { for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { - THIS_ATTR _DictSlots_ref PTR_DEREF DictSlots[i].SetFlags(0); + THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); } - THIS_ATTR _DictSlots_ref PTR_DEREF _num_used = 0; + THIS_ATTR _DictSlots_ref._num_used = 0; } DictStructIterator Begin() { // Searching for first item index. for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { if (THIS_ATTR _DictSlots_ref.DictSlots[i].IsValid() && THIS_ATTR _DictSlots_ref.DictSlots[i].IsUsed()) { - DictStructIterator iter(this, i); + DictStructIterator iter(THIS_REF, i); return iter; } } @@ -265,7 +265,7 @@ class DictStruct : public DictBase { } unsigned int position; - DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); + DictSlot* keySlot = THIS_ATTR GetSlotByKey(dictSlotsRef, key, position); if (keySlot == NULL && !THIS_ATTR IsGrowUpAllowed()) { // Resize is prohibited. @@ -278,16 +278,16 @@ class DictStruct : public DictBase { return false; } // We now have new positions of slots, so we have to take the corrent slot again. - keySlot = GetSlotByKey(dictSlotsRef, key, position); + keySlot = THIS_ATTR GetSlotByKey(dictSlotsRef, key, position); } if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { // No DictSlotsRef.DictSlots available. if (THIS_ATTR overflow_listener != NULL) { - if (!overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { + if (!THIS_ATTR overflow_listener(DICT_OVERFLOW_REASON_FULL, dictSlotsRef._num_used, 0)) { // Overwriting slot pointed exactly by key's position in the hash table (we don't check for possible // conflicts). - keySlot = &dictSlotsRef.DictSlots[Hash(key) % ArraySize(dictSlotsRef.DictSlots)]; + keySlot = &dictSlotsRef.DictSlots[THIS_ATTR Hash(key) % ArraySize(dictSlotsRef.DictSlots)]; } } @@ -298,10 +298,10 @@ class DictStruct : public DictBase { } if (keySlot == NULL) { - position = Hash(key) % ArraySize(dictSlotsRef.DictSlots); + position = THIS_ATTR Hash(key) % ArraySize(dictSlotsRef.DictSlots); unsigned int _starting_position = position; - int _num_conflicts = 0; + unsigned int _num_conflicts = 0; bool _overwrite_slot = false; // Searching for empty DictSlot or used one with the matching key. It skips used, hashless DictSlots. @@ -310,7 +310,8 @@ class DictStruct : public DictBase { if (THIS_ATTR overflow_listener_max_conflicts != 0 && ++_num_conflicts == THIS_ATTR overflow_listener_max_conflicts) { if (THIS_ATTR overflow_listener != NULL) { - if (!overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used, _num_conflicts)) { + if (!THIS_ATTR overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used, + _num_conflicts)) { // Overflow listener returned false so we won't search for further empty slot. _overwrite_slot = true; break; @@ -381,7 +382,7 @@ class DictStruct : public DictBase { */ bool GrowUp(int percent = DICT_GROW_UP_PERCENT_DEFAULT) { return Resize( - MathMax(10, (int)((float)ArraySize(THIS_ATTR THIS_ATTR_DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); + MathMax(10, (int)((float)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } /** @@ -409,8 +410,7 @@ class DictStruct : public DictBase { 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)) + THIS_ATTR _DictSlots_ref.DictSlots[i].value, false)) return false; } else { if (!InsertInto(new_DictSlots, THIS_ATTR _DictSlots_ref.DictSlots[i].value)) return false; diff --git a/Serializer.mqh b/Serializer.mqh index 533aff32c..e47079396 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -333,7 +333,7 @@ class Serializer { if (Enter(SerializerEnterArray, name)) { num_items = ArraySize(array); for (int i = 0; i < num_items; ++i) { - PassStruct(this, "", array[i]); + PassStruct(THIS_REF, "", array[i]); } Leave(); } diff --git a/Task/Task.h b/Task/Task.h index aee85381d..deb626cad 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -59,7 +59,7 @@ class Task : public Taskable { /** * Class copy constructor. */ - Task(Task &_task) { tasks = _task.GetTasks(); } + Task(Task &_task) { tasks = PTR_TO_REF(_task.GetTasks()); } /** * Class deconstructor. @@ -267,7 +267,7 @@ class Task : public Taskable { * @return * Returns true when the condition is met. */ - bool CheckCondition(ENUM_TASK_CONDITION _cond, DataParamEntry &_args[]) { + bool CheckCondition(ENUM_TASK_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) { switch (_cond) { case TASK_COND_IS_ACTIVE: // Is active; @@ -301,7 +301,7 @@ class Task : public Taskable { * @return * Returns true when the action has been executed successfully. */ - bool ExecuteAction(ENUM_TASK_ACTION _action, DataParamEntry &_args[]) { + bool ExecuteAction(ENUM_TASK_ACTION _action, ARRAY_REF(DataParamEntry, _args)) { bool _result = true; switch (_action) { case TASK_ACTION_PROCESS: diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 1820d3d8c..391eebc9c 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -65,7 +65,7 @@ struct TaskEntry { public: // Constructors. TaskEntry() { Init(); } - TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } + TaskEntry(const TaskActionEntry &_action, const TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } template TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { Init(); @@ -89,7 +89,7 @@ struct TaskEntry { bool Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag) { return action.Get(_flag); }; template bool Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop) { - return action.Get(_prop); + return action.Get(_prop); }; // bool Get(ENUM_TASK_ENTRY_FLAGS _flag) { return HasFlag(_flag); } TaskActionEntry GetActionEntry() { return action; } @@ -115,7 +115,7 @@ struct TaskEntry { // Flag methods. bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } - void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void RemoveFlags(unsigned char _flags) { flags &= (unsigned char)~_flags; } void SetFlag(ENUM_TASK_ENTRY_FLAGS _flag, bool _value) { if (_value) AddFlags(_flag); diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 756248422..173ae3bef 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -60,22 +60,19 @@ struct TaskActionEntry { protected: ARRAY(DataParamEntry, args); /* TaskAction arguments. */ unsigned char flags; /* TaskAction flags. */ - int freq; /* How often to run (0 for no limit). */ - int id; /* TaskAction's enum ID. */ - datetime time_last_run; /* Time of the successful run. */ - short tries; /* Number of retries left (-1 for unlimited). */ + int freq; /* How often to run (0 for no limit). */ + int id; /* TaskAction's enum ID. */ + datetime time_last_run; /* Time of the successful run. */ + short tries; /* Number of retries left (-1 for unlimited). */ protected: // Protected methods. void Init() { - SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), - id == InvalidEnumValue::value()); + SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), id == InvalidEnumValue::value()); } public: // Constructors. - TaskActionEntry() : flags(0), freq(60), id(InvalidEnumValue::value()), time_last_run(0), tries(-1) { - Init(); - } + TaskActionEntry() : flags(0), freq(60), id(InvalidEnumValue::value()), time_last_run(0), tries(-1) { Init(); } TaskActionEntry(int _id) : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), freq(60), @@ -84,7 +81,7 @@ struct TaskActionEntry { tries(-1) { Init(); } - TaskActionEntry(TaskActionEntry &_ae) { THIS_REF = _ae; } + TaskActionEntry(const TaskActionEntry &_ae) { THIS_REF = _ae; } // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } @@ -128,7 +125,9 @@ struct TaskActionEntry { DataParamEntry GetArg(int _index) const { return args[_index]; } int GetId() const { return id; } // Setters. - void TriesDec() { if(tries > 0) --tries; } + void TriesDec() { + if (tries > 0) --tries; + } void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value = true) { SetFlag(_flag, _value); } @@ -143,8 +142,7 @@ struct TaskActionEntry { return; case TASK_ACTION_ENTRY_ID: id = (int)_value; - SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), - id == InvalidEnumValue::value()); + SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), id == InvalidEnumValue::value()); return; case TASK_ACTION_ENTRY_TRIES: tries = (short)_value; diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index b12998699..494e8bf3e 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -59,15 +59,15 @@ struct TaskConditionEntry { }; protected: - unsigned char flags; // Condition flags. - datetime last_check; // Time of the latest check. - datetime last_success; // Time of the last success. - int freq; // How often to run (0 for no limit). - int id; // Condition ID. - short tries; // Number of successful tries left (-1 for unlimited). + ARRAY(DataParamEntry, args); // Task's condition arguments. + unsigned char flags; // Condition flags. + int freq; // How often to run (0 for no limit). + int id; // Condition ID. + datetime last_check; // Time of the latest check. + datetime last_success; // Time of the last success. + short tries; // Number of successful tries left (-1 for unlimited). // ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. // ENUM_TASK_CONDITION_TYPE type; // Task's condition type. - ARRAY(DataParamEntry, args); // Task's condition arguments. protected: // Protected methods. void Init() { @@ -87,7 +87,7 @@ struct TaskConditionEntry { tries(-1) { Init(); } - TaskConditionEntry(TaskConditionEntry &_ae) { THIS_REF = _ae; } + TaskConditionEntry(const TaskConditionEntry &_ae) { THIS_REF = _ae; } // Deconstructor. ~TaskConditionEntry() {} // Getters. @@ -116,7 +116,9 @@ struct TaskConditionEntry { DataParamEntry GetArg(int _index) const { return args[_index]; } int GetId() const { return id; } // Setters. - void TriesDec() { tries -= tries > 0 ? 1 : 0; } + void TriesDec() { + if (tries > 0) --tries; + } void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag, bool _value = true) { SetFlag(_flag, _value); } @@ -131,7 +133,8 @@ struct TaskConditionEntry { return; case TASK_CONDITION_ENTRY_ID: id = (int)_value; - SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == InvalidEnumValue::value()); + SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), + id == InvalidEnumValue::value()); return; case TASK_CONDITION_ENTRY_TRIES: tries = (short)_value; @@ -151,7 +154,7 @@ struct TaskConditionEntry { // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } - void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void RemoveFlags(unsigned char _flags) { flags &= (unsigned char)~_flags; } void SetFlag(ENUM_TASK_CONDITION_ENTRY_FLAGS _flag, bool _value) { if (_value) AddFlags(_flag); diff --git a/Task/TaskGetter.struct.h b/Task/TaskGetter.struct.h index 2505209ac..8177d8e04 100644 --- a/Task/TaskGetter.struct.h +++ b/Task/TaskGetter.struct.h @@ -47,6 +47,7 @@ struct TaskGetterEntry { TASK_GETTER_ENTRY_ID, TASK_GETTER_ENTRY_TRIES, TASK_GETTER_ENTRY_TIME_LAST_GET, + TASK_GETTER_ENTRY_TIME_LAST_RUN, }; // Defines action entry flags. enum ENUM_TASK_GETTER_ENTRY_FLAG { @@ -58,12 +59,13 @@ struct TaskGetterEntry { }; protected: - unsigned char flags; /* TaskGetter flags. */ - datetime time_last_get; /* Time of the successful get. */ - int freq; /* How often to run (0 for no limit). */ - int id; /* TaskGetter's enum ID. */ - short tries; /* Number of retries left (-1 for unlimited). */ - ARRAY(DataParamEntry, args); /* TaskGetter arguments. */ + ARRAY(DataParamEntry, args); /* TaskGetter arguments. */ + unsigned char flags; /* TaskGetter flags. */ + int freq; /* How often to run (0 for no limit). */ + int id; /* TaskGetter's enum ID. */ + datetime time_last_get; /* Time of the successful get. */ + datetime time_last_run; /* Time of the successful run. */ + short tries; /* Number of retries left (-1 for unlimited). */ protected: // Protected methods. void Init() { @@ -72,12 +74,16 @@ struct TaskGetterEntry { public: // Constructors. - TaskGetterEntry() : flags(0), freq(60), id(InvalidEnumValue::value()), time_last_get(0), tries(-1) { Init(); } + TaskGetterEntry() + : flags(0), freq(60), id(InvalidEnumValue::value()), time_last_get(0), time_last_run(0), tries(-1) { + Init(); + } TaskGetterEntry(int _id) : flags(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)), - id(_id), freq(60), + id(_id), time_last_get(0), + time_last_run(0), tries(-1) { Init(); } @@ -85,7 +91,7 @@ struct TaskGetterEntry { // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } - void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void RemoveFlags(unsigned char _flags) { flags &= (unsigned char)~_flags; } void SetFlag(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag, bool _value) { if (_value) { AddFlags(_flag); @@ -114,17 +120,21 @@ struct TaskGetterEntry { return (T)id; case TASK_GETTER_ENTRY_TRIES: return (T)tries; + case TASK_GETTER_ENTRY_TIME_LAST_GET: + return (T)time_last_get; case TASK_GETTER_ENTRY_TIME_LAST_RUN: return (T)time_last_run; default: break; } SetUserError(ERR_INVALID_PARAMETER); - return WRONG_VALUE; + return InvalidEnumValue::value(); } int GetId() const { return id; } // Setters. - void TriesDec() { tries -= tries > 0 ? 1 : 0; } + void TriesDec() { + if (tries > 0) --tries; + } void Set(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag, bool _value = true) { SetFlag(_flag, _value); } @@ -139,7 +149,7 @@ struct TaskGetterEntry { return; case TASK_GETTER_ENTRY_ID: id = (int)_value; - SetFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + SetFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_INVALID), id == InvalidEnumValue::value()); return; case TASK_GETTER_ENTRY_TRIES: tries = (short)_value; @@ -165,7 +175,7 @@ struct TaskGetterEntry { s.Pass(THIS_REF, "time_last_get", time_last_get); s.Pass(THIS_REF, "tries", tries); s.PassEnum(THIS_REF, "freq", freq); - s.PassArray(this, "args", args); + s.PassArray(THIS_REF, "args", args); return SerializerNodeObject; } diff --git a/Task/TaskGetterBase.h b/Task/TaskGetterBase.h index 6261d2ce6..ccf6a1f5c 100644 --- a/Task/TaskGetterBase.h +++ b/Task/TaskGetterBase.h @@ -52,7 +52,7 @@ class TaskGetterBase { /** * Gets a copy of structure. */ - virtual TS Get(const TaskGetterEntry &_entry) = NULL; + virtual TS Get(const TaskGetterEntry &_entry) = 0; }; #endif // TASK_GETTER_BASE_H diff --git a/Task/TaskSetter.struct.h b/Task/TaskSetter.struct.h index d33715ca3..349500a18 100644 --- a/Task/TaskSetter.struct.h +++ b/Task/TaskSetter.struct.h @@ -46,6 +46,7 @@ struct TaskSetterEntry { TASK_SETTER_ENTRY_ID, TASK_SETTER_ENTRY_TRIES, TASK_SETTER_ENTRY_TIME_LAST_GET, + TASK_SETTER_ENTRY_TIME_LAST_RUN, }; // Defines action entry flags. enum ENUM_TASK_SETTER_ENTRY_FLAG { @@ -57,32 +58,39 @@ struct TaskSetterEntry { }; protected: - unsigned char flags; /* TaskSetter flags. */ - datetime time_last_get; /* Time of the successful get. */ - int freq; /* How often to run (0 for no limit). */ - int id; /* TaskSetter's enum ID. */ - short tries; /* Number of retries left (-1 for unlimited). */ - DataParamEntry args[]; /* TaskSetter arguments. */ + ARRAY(DataParamEntry, args); /* TaskSetter arguments. */ + unsigned char flags; /* TaskSetter flags. */ + int freq; /* How often to run (0 for no limit). */ + int id; /* TaskSetter's enum ID. */ + datetime time_last_get; /* Time of the successful get. */ + datetime time_last_run; /* Time of the successful run. */ + short tries; /* Number of retries left (-1 for unlimited). */ protected: // Protected methods. - void Init() { SetFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + void Init() { + SetFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_INVALID), id == InvalidEnumValue::value()); + } public: // Constructors. - TaskSetterEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_get(0), tries(-1) { Init(); } + TaskSetterEntry() + : flags(0), freq(60), id(InvalidEnumValue::value()), time_last_get(0), time_last_run(0), tries(-1) { + Init(); + } TaskSetterEntry(int _id) : flags(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_ACTIVE)), - id(_id), freq(60), + id(_id), time_last_get(0), + time_last_run(0), tries(-1) { Init(); } - TaskSetterEntry(TaskSetterEntry &_ae) { this = _ae; } + TaskSetterEntry(TaskSetterEntry &_ae) { THIS_REF = _ae; } // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } - void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void RemoveFlags(unsigned char _flags) { flags &= (unsigned char)~_flags; } void SetFlag(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag, bool _value) { if (_value) { AddFlags(_flag); @@ -111,17 +119,21 @@ struct TaskSetterEntry { return (T)id; case TASK_SETTER_ENTRY_TRIES: return (T)tries; + case TASK_SETTER_ENTRY_TIME_LAST_GET: + return (T)time_last_run; case TASK_SETTER_ENTRY_TIME_LAST_RUN: return (T)time_last_run; default: break; } SetUserError(ERR_INVALID_PARAMETER); - return WRONG_VALUE; + return InvalidEnumValue::value(); } int GetId() const { return id; } // Setters. - void TriesDec() { tries -= tries > 0 ? 1 : 0; } + void TriesDec() { + if (tries > 0) --tries; + } void Set(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag, bool _value = true) { SetFlag(_flag, _value); } @@ -136,7 +148,7 @@ struct TaskSetterEntry { return; case TASK_SETTER_ENTRY_ID: id = (int)_value; - SetFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + SetFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_INVALID), id == InvalidEnumValue::value()); return; case TASK_SETTER_ENTRY_TRIES: tries = (short)_value; @@ -162,7 +174,7 @@ struct TaskSetterEntry { s.Pass(THIS_REF, "time_last_get", time_last_get); s.Pass(THIS_REF, "tries", tries); s.PassEnum(THIS_REF, "freq", freq); - s.PassArray(this, "args", args); + s.PassArray(THIS_REF, "args", args); return SerializerNodeObject; } diff --git a/Task/TaskSetterBase.h b/Task/TaskSetterBase.h index 2b6f0ca84..06023dd80 100644 --- a/Task/TaskSetterBase.h +++ b/Task/TaskSetterBase.h @@ -52,7 +52,7 @@ class TaskSetterBase { /** * Sets an entry value. */ - virtual bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) = NULL; + virtual bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) = 0; }; #endif // TASK_SETTER_BASE_H diff --git a/Task/Taskable.h b/Task/Taskable.h index f6adcae25..b4c733abd 100644 --- a/Task/Taskable.h +++ b/Task/Taskable.h @@ -59,22 +59,22 @@ class Taskable : public Object { /** * Checks a condition. */ - virtual bool Check(const TaskConditionEntry &_entry) = NULL; + virtual bool Check(const TaskConditionEntry &_entry) = 0; /** * Gets a copy of structure. */ - virtual TS Get(const TaskGetterEntry &_entry) = NULL; + virtual TS Get(const TaskGetterEntry &_entry) = 0; /** * Runs an action. */ - virtual bool Run(const TaskActionEntry &_entry) = NULL; + virtual bool Run(const TaskActionEntry &_entry) = 0; /** * Sets an entry value. */ - virtual bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) = NULL; + virtual bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) = 0; }; #endif // TASKABLE_H From ce626850e2e3bb4cf231155e269167d7fc14f162 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 8 Feb 2022 20:04:29 +0100 Subject: [PATCH 50/84] WIP. Fixed SerializerNode and SerializerNodeIterator's loop. Now i'm stuck with another complicated compiler error. --- Array.extern.h | 2 ++ Data.struct.h | 1 + DateTime.extern.h | 6 +++--- DateTime.mqh | 2 -- DateTime.struct.h | 16 ++++++++-------- Dict.mqh | 2 ++ Refs.mqh | 2 +- Refs.rc.h | 3 +++ Refs.struct.h | 21 ++++++++++++++++----- Serializer.mqh | 30 +++++++++++++++++++++++++++++- SerializerConverter.mqh | 2 +- SerializerNodeIterator.mqh | 34 ---------------------------------- Std.h | 2 +- String.mqh | 1 + Task/TaskActionBase.h | 3 +++ Task/TaskGetterBase.h | 3 +++ Task/TaskManager.h | 6 +++--- 17 files changed, 77 insertions(+), 59 deletions(-) diff --git a/Array.extern.h b/Array.extern.h index b09748d67..4b6580d4d 100644 --- a/Array.extern.h +++ b/Array.extern.h @@ -24,6 +24,8 @@ #ifndef __MQL__ #pragma once +#include "Std.h" + template extern int ArraySize(const ARRAY_REF(T, _array)); diff --git a/Data.struct.h b/Data.struct.h index 81d4cb517..c3d28d695 100644 --- a/Data.struct.h +++ b/Data.struct.h @@ -37,6 +37,7 @@ struct MqlRates; // Includes. #include "Data.enum.h" +#include "DateTime.mqh" #include "Serializer.enum.h" #include "SerializerNode.enum.h" #include "Std.h" diff --git a/DateTime.extern.h b/DateTime.extern.h index 87d156d81..e6ebbe21a 100644 --- a/DateTime.extern.h +++ b/DateTime.extern.h @@ -42,10 +42,10 @@ class datetime { datetime(); datetime(const long& _time); datetime(const int& _time); - bool operator==(const int& _time) const; + 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 int _time) const; + bool operator>(const int _time) const; bool operator<(const datetime& _time); bool operator>(const datetime& _time); operator long() const; diff --git a/DateTime.mqh b/DateTime.mqh index c081d0d44..eadee1326 100644 --- a/DateTime.mqh +++ b/DateTime.mqh @@ -188,8 +188,6 @@ class DateTime { dt_last = dt_curr; Update(); } - int _prev_secs = dt_last.GetSeconds(); - int _curr_secs = dt_curr.GetSeconds(); if (dt_curr.GetSeconds() < dt_last.GetSeconds()) { _result = true; } diff --git a/DateTime.struct.h b/DateTime.struct.h index e961670d0..c03391a23 100644 --- a/DateTime.struct.h +++ b/DateTime.struct.h @@ -64,7 +64,7 @@ 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 = NULL) { + static int Day(datetime dt = 0) { if (dt == 0) { dt = TimeCurrent(); } @@ -80,7 +80,7 @@ struct DateTimeStatic { /** * Returns the current zero-based day of the week of the last known server time. */ - static int DayOfWeek(datetime dt = NULL) { + static int DayOfWeek(datetime dt = 0) { if (dt == 0) { dt = TimeCurrent(); } @@ -96,7 +96,7 @@ struct DateTimeStatic { /** * Returns the current day of the year (e.g. the day of year of the last known server time). */ - static int DayOfYear(datetime dt = NULL) { + static int DayOfYear(datetime dt = 0) { if (dt == 0) { dt = TimeCurrent(); } @@ -112,7 +112,7 @@ struct DateTimeStatic { /** * Returns the hour of the last known server time by the moment of the program start. */ - static int Hour(datetime dt = NULL) { + static int Hour(datetime dt = 0) { if (dt == 0) { dt = TimeCurrent(); } @@ -137,7 +137,7 @@ struct DateTimeStatic { /** * Returns the current minute of the last known server time by the moment of the program start. */ - static int Minute(datetime dt = NULL) { + static int Minute(datetime dt = 0) { if (dt == 0) { dt = TimeCurrent(); } @@ -153,7 +153,7 @@ struct DateTimeStatic { /** * Returns the current month as number (e.g. the number of month of the last known server time). */ - static int Month(datetime dt = NULL) { + static int Month(datetime dt = 0) { if (dt == 0) { dt = TimeCurrent(); } @@ -169,7 +169,7 @@ struct DateTimeStatic { /** * Returns the amount of seconds elapsed from the beginning of the current minute of the last known server time. */ - static int Seconds(datetime dt = NULL) { + static int Seconds(datetime dt = 0) { if (dt == 0) { dt = TimeCurrent(); } @@ -213,7 +213,7 @@ struct DateTimeStatic { /** * Returns the current year (e.g. the year of the last known server time). */ - static int Year(datetime dt = NULL) { + static int Year(datetime dt = 0) { if (dt == 0) { dt = TimeCurrent(); } diff --git a/Dict.mqh b/Dict.mqh index 8da1f31e7..68db5f703 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -373,7 +373,9 @@ class Dict : public DictBase { } public: +#ifdef __cplusplus template <> +#endif SerializerNodeType Serialize(Serializer& s) { if (s.IsWriting()) { for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { diff --git a/Refs.mqh b/Refs.mqh index 07b530ff4..6d55078d8 100644 --- a/Refs.mqh +++ b/Refs.mqh @@ -98,7 +98,7 @@ class Dynamic { /** * Destructor. */ - ~Dynamic() { + virtual ~Dynamic() { if (ptr_ref_counter != NULL && PTR_ATTRIB(ptr_ref_counter, num_strong_refs) == 0 && PTR_ATTRIB(ptr_ref_counter, num_weak_refs) == 0) { #ifdef __MQL__ diff --git a/Refs.rc.h b/Refs.rc.h index c24c32b0f..baf2a9153 100644 --- a/Refs.rc.h +++ b/Refs.rc.h @@ -30,6 +30,9 @@ #pragma once #endif +// Includes. +#include "String.mqh" + // Forward declarations. class Dynamic; diff --git a/Refs.struct.h b/Refs.struct.h index c63b4322f..b84849303 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -101,17 +101,17 @@ struct Ref { /** * Constructor. */ - Ref(X* _ptr) { this = _ptr; } + Ref(X* _ptr) { THIS_REF = _ptr; } /** * Constructor. */ - Ref(Ref& ref) { this = ref.Ptr(); } + Ref(Ref& ref) { THIS_REF = ref.Ptr(); } /** * Constructor. */ - Ref(WeakRef& ref) { this = ref.Ptr(); } + Ref(WeakRef& ref) { THIS_REF = ref.Ptr(); } /** * Constructor. @@ -138,11 +138,13 @@ struct Ref { */ void Unset() { if (ptr_object != NULL) { +#ifdef __MQL__ if (CheckPointer(ptr_object) == POINTER_INVALID) { // Double check the pointer for invalid references. Can happen in rare circumstances. ptr_object = NULL; return; } +#endif if (PTR_ATTRIB(ptr_object, ptr_ref_counter) == NULL) { // Object is not reference counted. Maybe a stack-based one? return; @@ -155,6 +157,7 @@ struct Ref { // No more strong references. if (!PTR_ATTRIB2(ptr_object, ptr_ref_counter, num_weak_refs)) { +#ifdef __MQL__ if (CheckPointer(PTR_ATTRIB(ptr_object, ptr_ref_counter)) == POINTER_INVALID) { // Serious problem. #ifndef __MQL4__ @@ -163,6 +166,7 @@ struct Ref { #endif return; } +#endif // Also no more weak references. delete PTR_ATTRIB(ptr_object, ptr_ref_counter); @@ -175,6 +179,7 @@ struct Ref { // Avoiding delete loop for cyclic references. X* ptr_to_delete = ptr_object; +#ifdef __MQL__ if (CheckPointer(ptr_to_delete) == POINTER_INVALID) { // Serious problem. #ifndef __MQL4__ @@ -183,6 +188,7 @@ struct Ref { #endif return; } +#endif // Avoiding double deletion in Dynamic's destructor. PTR_ATTRIB(ptr_object, ptr_ref_counter) = NULL; @@ -213,7 +219,12 @@ struct Ref { ptr_object = _ptr; if (ptr_object != NULL) { - if (CheckPointer(ptr_object) == POINTER_INVALID || PTR_ATTRIB(ptr_object, ptr_ref_counter) == NULL) { +#ifdef __MQL__ + if (CheckPointer(ptr_object) == POINTER_INVALID) { + return Ptr(); + } +#endif + if (PTR_ATTRIB(ptr_object, ptr_ref_counter) == NULL) { // Double check the pointer for invalid references. Can happen very rarely. return Ptr(); } @@ -238,7 +249,7 @@ struct Ref { * Makes a strong reference to the strongly-referenced object. */ X* operator=(Ref& right) { - this = right.Ptr(); + THIS_REF = right.Ptr(); return Ptr(); } diff --git a/Serializer.mqh b/Serializer.mqh index e47079396..f33c6b2b0 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -349,7 +349,7 @@ class Serializer { // Should not happen. } else { _node = parent PTR_DEREF GetChild(si.Index()); - array[si.Index()] = si.Struct(); + array[si.Index()] = Struct(si.Key()); } } @@ -434,6 +434,34 @@ class Serializer { return NULL; } + + /** + * Returns next value or value by given key. + */ + template + X Value(string key = "") { + X value; + Pass(THIS_REF, key, value); + return value; + } + + /** + * Returns next structure or structure by given key. + */ + template + X Struct(string key = "") { + X value; + PassStruct(THIS_REF, key, value); + return value; + } + + /** + * Returns next object or object by given key. + */ + template + X Object(string key = "") { + return Struct(key); + } }; #endif // End: SERIALIZER_MQH diff --git a/SerializerConverter.mqh b/SerializerConverter.mqh index 3aac6a0dc..b1ef151fe 100644 --- a/SerializerConverter.mqh +++ b/SerializerConverter.mqh @@ -93,7 +93,7 @@ class SerializerConverter { template static SerializerConverter FromString(string arg) { - SerializerConverter _converter(((C*)NULL).Parse(arg), 0); + SerializerConverter _converter(((C*)NULL)PTR_DEREF Parse(arg), 0); #ifdef __debug__ Print("FromString(): result: ", _converter.Node() != NULL ? _converter.Node().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); diff --git a/SerializerNodeIterator.mqh b/SerializerNodeIterator.mqh index 57acc5265..a821bacaf 100644 --- a/SerializerNodeIterator.mqh +++ b/SerializerNodeIterator.mqh @@ -109,40 +109,6 @@ class SerializerIterator : public SerializerNodeIterator { */ SerializerIterator(const SerializerIterator& r) : SerializerNodeIterator(r) { _serializer = r._serializer; } - /** - * Returns next value or value by given key. - */ -#ifdef __MQL__ - template <> -#endif - X Value(string key = "") { - X value; - _serializer PTR_DEREF Pass(PTR_TO_REF(_serializer), key, value); - return value; - } - - /** - * Returns next object or object by given key. - */ -#ifdef __MQL__ - template <> -#endif - X Object(string key = "") { - return Struct(key); - } - - /** - * Returns next structure or structure by given key. - */ -#ifdef __MQL__ - template <> -#endif - X Struct(string key = "") { - X value; - _serializer PTR_DEREF PassStruct(PTR_TO_REF(_serializer), key, value); - return value; - } - SerializerNodeType ParentNodeType() { return _collection PTR_DEREF GetType(); } }; diff --git a/Std.h b/Std.h index e23332fab..3daf6829b 100644 --- a/Std.h +++ b/Std.h @@ -26,7 +26,6 @@ #include "Math.define.h" #endif - // Data types. #ifdef __cplusplus #include @@ -51,6 +50,7 @@ #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 nullptr NULL #else #define THIS_ATTR this-> #define THIS_PTR (this) diff --git a/String.mqh b/String.mqh index ab240c4db..a145c3350 100644 --- a/String.mqh +++ b/String.mqh @@ -26,6 +26,7 @@ // Includes. #include "Array.extern.h" +#include "Common.extern.h" #include "Std.h" #include "String.extern.h" diff --git a/Task/TaskActionBase.h b/Task/TaskActionBase.h index eb2a4df0f..805105160 100644 --- a/Task/TaskActionBase.h +++ b/Task/TaskActionBase.h @@ -34,6 +34,9 @@ #ifndef TASK_ACTION_BASE_H #define TASK_ACTION_BASE_H +// Includes. +#include "TaskAction.struct.h" + /** * TaskActionBase class. */ diff --git a/Task/TaskGetterBase.h b/Task/TaskGetterBase.h index ccf6a1f5c..249670822 100644 --- a/Task/TaskGetterBase.h +++ b/Task/TaskGetterBase.h @@ -34,6 +34,9 @@ #ifndef TASK_GETTER_BASE_H #define TASK_GETTER_BASE_H +// Includes. +#include "TaskGetter.struct.h" + /** * TaskGetterBase class. */ diff --git a/Task/TaskManager.h b/Task/TaskManager.h index 2ae9dd44f..dfa28c10c 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -73,7 +73,7 @@ class TaskManager { * Adds new task. */ bool Add(Task *_task) { - Ref _ref = _task; + Ref _ref(_task); return tasks.Push(_ref); } @@ -83,7 +83,7 @@ class TaskManager { bool Add(string _entry_str) { TaskEntry _entry; SerializerConverter::FromString(_entry_str).ToObject(_entry); - Ref _task = new Task(_entry); + Ref _task(new Task(_entry)); return Add(_task.Ptr()); } @@ -104,7 +104,7 @@ class TaskManager { bool _result = true; for (DictStructIterator> _iter = tasks.Begin(); _iter.IsValid(); ++_iter) { Task *_task = _iter.Value().Ptr(); - _result &= _task.Process(); + _result &= _task PTR_DEREF Process(); } return _result; } From 7ac3b001b0b30bdf630a1b12fa6d77ab7a5687b8 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 9 Feb 2022 18:22:24 +0100 Subject: [PATCH 51/84] WIP. Stuck on const qualifier problems due to usage of Ref type, which requires non-const r-value in constructor and assignment operator. --- DictSlot.mqh | 12 ++++++++++++ DictSlotsRef.h | 22 ++++++++++++++++++++++ DictStruct.mqh | 2 +- Std.h | 14 ++++++++++++++ Task/TaskConditionBase.h | 3 +++ Task/TaskSetter.struct.h | 2 +- 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/DictSlot.mqh b/DictSlot.mqh index 3c1fe29e1..269684f0f 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,6 +40,18 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} +#ifdef __cplusplus + // Ensuring we are able to use Ref type which requires non-const r-value in constructor. + DictSlot(const DictSlot &r) = delete; +#endif + + void operator=(DictSlot &r) { + _flags = r._flags; + key = r.key; + typedef typename std::remove_const::type non_const_v; + value = (non_const_v &)r.value; + } + 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 e5ae9ee58..1b1bbce66 100644 --- a/DictSlotsRef.h +++ b/DictSlotsRef.h @@ -32,6 +32,7 @@ // Includes. #include "Dict.enum.h" +#include "Std.h" template class DictSlot; @@ -56,6 +57,27 @@ struct DictSlotsRef { _avg_conflicts = 0; } + void operator=(const DictSlotsRef& r) { + DictSlots = r.DictSlots; + _list_index = r._list_index; + _num_used = r._num_used; + _num_conflicts = r._num_conflicts; + _avg_conflicts = r._avg_conflicts; + } + + void operator=(DictSlotsRef& r) { +#ifdef __MQL__ + DictSlots = r.DictSlots; +#else + // Getting rid of "const" qualifier. + DictSlots = (_cpp_array >&)r.DictSlots; +#endif + _list_index = r._list_index; + _num_used = r._num_used; + _num_conflicts = r._num_conflicts; + _avg_conflicts = r._avg_conflicts; + } + /** * 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 1e6d8e800..2ac3b4343 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -419,7 +419,7 @@ class DictStruct : public DictBase { // Freeing old DictSlots array. ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots); - THIS_ATTR _DictSlots_ref = new_DictSlots; + THIS_ATTR _DictSlots_ref = (DictSlotsRef&)new_DictSlots; return true; } diff --git a/Std.h b/Std.h index 3daf6829b..cac2b45db 100644 --- a/Std.h +++ b/Std.h @@ -87,6 +87,8 @@ */ #define ARRAY_REF(T, N) REF(T) N ARRAY_DECLARATION_BRACKETS +#define CONST_ARRAY_REF(T, N) const N ARRAY_DECLARATION_BRACKETS + /** * Array definition. * @@ -106,6 +108,8 @@ */ #define ARRAY_REF(T, N) _cpp_array& N +#define CONST_ARRAY_REF(T, N) const _cpp_array& N + /** * Array definition. * @@ -141,6 +145,16 @@ class _cpp_array { for (const auto& _item : _arr) m_data.push_back(_item); } + _cpp_array(_cpp_array& r) { + m_data = (std::vector&)r.m_data; + m_isSeries = r.m_isSeries; + } + + _cpp_array(const _cpp_array& r) { + m_data = r.m_data; + m_isSeries = r.m_isSeries; + } + /** * Returns pointer of first element (provides a way to iterate over array elements). */ diff --git a/Task/TaskConditionBase.h b/Task/TaskConditionBase.h index 29c7df8c4..831cdfef6 100644 --- a/Task/TaskConditionBase.h +++ b/Task/TaskConditionBase.h @@ -34,6 +34,9 @@ #ifndef TASK_CONDITION_BASE_H #define TASK_CONDITION_BASE_H +// Includes. +#include "TaskCondition.struct.h" + /** * TaskConditionBase class. */ diff --git a/Task/TaskSetter.struct.h b/Task/TaskSetter.struct.h index 349500a18..35ac5db24 100644 --- a/Task/TaskSetter.struct.h +++ b/Task/TaskSetter.struct.h @@ -120,7 +120,7 @@ struct TaskSetterEntry { case TASK_SETTER_ENTRY_TRIES: return (T)tries; case TASK_SETTER_ENTRY_TIME_LAST_GET: - return (T)time_last_run; + return (T)time_last_get; case TASK_SETTER_ENTRY_TIME_LAST_RUN: return (T)time_last_run; default: From 4068e6c4bf30b6a0d976d1084b6c4541588482b2 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 16 Feb 2022 18:26:03 +0100 Subject: [PATCH 52/84] WIP. Fixed C++ compilation errors regarding Ref used as non-const value of _cpp_array class. Fixed some MQL tests. Some tests still fails. --- Data.struct.h | 2 ++ Dict.mqh | 4 ++-- DictObject.mqh | 4 ++-- DictSlot.mqh | 24 +++++++++++++----------- DictSlotsRef.h | 18 ++++-------------- DictStruct.mqh | 31 ++++++++++++++++++++++++++++--- Refs.struct.h | 4 ++-- Std.h | 14 ++++++++++++-- Util.h | 30 +++++++++++++++++++++++------- 9 files changed, 88 insertions(+), 43 deletions(-) diff --git a/Data.struct.h b/Data.struct.h index c3d28d695..9ee4ee34f 100644 --- a/Data.struct.h +++ b/Data.struct.h @@ -286,6 +286,7 @@ struct DataParamEntry : public MqlParam { case TYPE_USHORT: return DBL_MIN; } + return DBL_MIN; } /** @@ -314,6 +315,7 @@ struct DataParamEntry : public MqlParam { case TYPE_USHORT: return INT_MIN; } + return INT_MIN; } /* Serializers */ diff --git a/Dict.mqh b/Dict.mqh index 68db5f703..76eb3cd53 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -395,9 +395,9 @@ class Dict : public DictBase { // Note that we're retrieving value by a key (as we are in an // object!). - Set(key, i.Value(i.Key())); + Set(key, s.Value(i.Key())); } else { - Push(i.Value()); + Push(s.Value()); } } return i.ParentNodeType(); diff --git a/DictObject.mqh b/DictObject.mqh index fbfd681aa..719115c22 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -420,10 +420,10 @@ class DictObject : public DictBase { // Note that we're retrieving value by a key (as we are in an // object!). - V _prop = i.Struct(i.Key()); + V _prop = s.Struct(i.Key()); Set(key, _prop); } else { - V _prop = i.Struct(); + V _prop = s.Struct(); Push(_prop); } } diff --git a/DictSlot.mqh b/DictSlot.mqh index 269684f0f..af7ada6e6 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,17 +40,19 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} -#ifdef __cplusplus - // Ensuring we are able to use Ref type which requires non-const r-value in constructor. - DictSlot(const DictSlot &r) = delete; -#endif - - void operator=(DictSlot &r) { - _flags = r._flags; - key = r.key; - typedef typename std::remove_const::type non_const_v; - value = (non_const_v &)r.value; - } + /* + DictSlot(DictSlot &r) { + _flags = r._flags; + key = r.key; + value = r.value; + } + + void operator=(DictSlot &r) { + _flags = r._flags; + key = r.key; + value = r.value; + } + */ bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } diff --git a/DictSlotsRef.h b/DictSlotsRef.h index 1b1bbce66..1164261cd 100644 --- a/DictSlotsRef.h +++ b/DictSlotsRef.h @@ -31,8 +31,11 @@ #endif // Includes. +#include "Array.mqh" #include "Dict.enum.h" +#include "DictSlot.mqh" #include "Std.h" +#include "Util.h" template class DictSlot; @@ -57,21 +60,8 @@ struct DictSlotsRef { _avg_conflicts = 0; } - void operator=(const DictSlotsRef& r) { - DictSlots = r.DictSlots; - _list_index = r._list_index; - _num_used = r._num_used; - _num_conflicts = r._num_conflicts; - _avg_conflicts = r._avg_conflicts; - } - void operator=(DictSlotsRef& r) { -#ifdef __MQL__ - DictSlots = r.DictSlots; -#else - // Getting rid of "const" qualifier. - DictSlots = (_cpp_array >&)r.DictSlots; -#endif + Util::ArrayCopy(DictSlots, r.DictSlots); _list_index = r._list_index; _num_used = r._num_used; _num_conflicts = r._num_conflicts; diff --git a/DictStruct.mqh b/DictStruct.mqh index 2ac3b4343..6ba129907 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -65,6 +65,20 @@ class DictStruct : public DictBase { THIS_ATTR _mode = right._mode; } + /** + * Copy constructor. + */ + DictStruct(DictStruct& right) { + Clear(); + Resize(right.GetSlotCount()); + for (unsigned int i = 0; i < (unsigned int)ArraySize(right._DictSlots_ref.DictSlots); ++i) { + this PTR_DEREF _DictSlots_ref PTR_DEREF 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 operator=(const DictStruct& right) { Clear(); Resize(right.GetSlotCount()); @@ -76,6 +90,17 @@ 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() { for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); @@ -419,7 +444,7 @@ class DictStruct : public DictBase { // Freeing old DictSlots array. ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots); - THIS_ATTR _DictSlots_ref = (DictSlotsRef&)new_DictSlots; + THIS_ATTR _DictSlots_ref = new_DictSlots; return true; } @@ -462,9 +487,9 @@ class DictStruct : public DictBase { // Note that we're retrieving value by a key (as we are in an // object!). - Set(key, i.Struct(i.Key())); + Set(key, s.Struct(i.Key())); } else { - Push(i.Struct()); + Push(s.Struct()); } } return i.ParentNodeType(); diff --git a/Refs.struct.h b/Refs.struct.h index b84849303..adea3f206 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -126,7 +126,7 @@ struct Ref { /** * Returns pointer to target object. */ - X* Ptr() { return ptr_object; } + X* Ptr() const { return ptr_object; } /** * Checks whether any object is referenced. @@ -241,7 +241,7 @@ struct Ref { * Makes a strong reference to the given weakly-referenced object. */ X* operator=(WeakRef& right) { - this = right.Ptr(); + THIS_REF = right.Ptr(); return Ptr(); } diff --git a/Std.h b/Std.h index cac2b45db..cd62af350 100644 --- a/Std.h +++ b/Std.h @@ -145,16 +145,26 @@ class _cpp_array { for (const auto& _item : _arr) m_data.push_back(_item); } + _cpp_array(const _cpp_array& r) { + m_data = r.m_data; + m_isSeries = r.m_isSeries; + } + _cpp_array(_cpp_array& r) { - m_data = (std::vector&)r.m_data; + m_data.assign(r.m_data.begin(), r.m_data.end()); m_isSeries = r.m_isSeries; } - _cpp_array(const _cpp_array& r) { + void operator=(const _cpp_array& r) { m_data = r.m_data; m_isSeries = r.m_isSeries; } + void operator=(_cpp_array& r) { + m_data.assign(r.m_data.begin(), r.m_data.end()); + m_isSeries = r.m_isSeries; + } + /** * Returns pointer of first element (provides a way to iterate over array elements). */ diff --git a/Util.h b/Util.h index 904fde211..572de36db 100644 --- a/Util.h +++ b/Util.h @@ -37,11 +37,27 @@ */ class Util { public: + /** + * Replaces content of the given array with items from another array. It is a non-const r-value version, as MQL's + * built-in ArrayCopy does not support such source arrays. + */ + template + static void ArrayCopy(ARRAY_REF(T, _dst_array), ARRAY_REF(T, _src_array)) { +#ifdef __MQL__ + ::ArrayResize(_dst_array, ::ArraySize(_src_array)); + for (int i = 0; i < ArraySize(_src_array); ++i) { + _dst_array[i] = _src_array[i]; + } +#else + _dst_array = _src_array; +#endif + } + /** * Resizes native array and reserves space for further items by some fixed step. */ template - static void ArrayResize(T& _array[], int _new_size, int _resize_pool = 32) { + static void ArrayResize(ARRAY_REF(T, _array), int _new_size, int _resize_pool = 32) { ::ArrayResize(_array, _new_size, (_new_size / _resize_pool + 1) * _resize_pool); } @@ -49,7 +65,7 @@ class Util { * Pushes item into the native array and reserves space for further items by some fixed step. */ template - static int ArrayPush(T& _array[], V& _value, int _resize_pool = 32) { + static int ArrayPush(ARRAY_REF(T, _array), V& _value, int _resize_pool = 32) { Util::ArrayResize(_array, ArraySize(_array) + 1, _resize_pool); _array[ArraySize(_array) - 1] = _value; return ArraySize(_array) - 1; @@ -59,7 +75,7 @@ class Util { * Resizes native array and reserves space for further items by some fixed step. */ template - static T ArrayPop(T& _array[]) { + static T ArrayPop(ARRAY_REF(T, _array)) { T _result = _array[ArraySize(_array) - 1]; ::ArrayResize(_array, ArraySize(_array) - 1); return _result; @@ -69,7 +85,7 @@ class Util { * Removes value from the array. */ template - static bool ArrayRemove(T& _array[], int index) { + static bool ArrayRemove(ARRAY_REF(T, _array), int index) { if (index < 0 || index >= ArraySize(_array)) { // Index out of array bounds. return false; @@ -85,7 +101,7 @@ class Util { * Removes value from the array. */ template - static bool ArrayRemoveFirst(T& _array[], T& value) { + static bool ArrayRemoveFirst(ARRAY_REF(T, _array), T& value) { for (int i = 0; i < ArraySize(_array); ++i) { if (_array[i] == value) { Util::ArrayRemove(_array, i); @@ -96,7 +112,7 @@ class Util { } template - static T Print(T& _array[]) { + static T Print(ARRAY_REF(T, _array)) { string _result; for (int i = 0; i < ArraySize(_array); ++i) { _result += IntegerToString(i) + ": " + (string)_array[i]; @@ -123,7 +139,7 @@ class Util { * Checks whether array has given value. */ template - static bool ArrayContains(T& _array[], const V& _value) { + static bool ArrayContains(ARRAY_REF(T, _array), const V& _value) { for (int i = 0; i < ArraySize(_array); ++i) { if (_array[i] == _value) { return true; From 0c70d2637c035b228d78277794ccdcbd657a575d Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 17 Feb 2022 15:47:10 +0100 Subject: [PATCH 53/84] Added `-c` option for `g++` --- .github/workflows/compile-cpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile-cpp.yml b/.github/workflows/compile-cpp.yml index 085b4f3e0..5fa17e2ca 100644 --- a/.github/workflows/compile-cpp.yml +++ b/.github/workflows/compile-cpp.yml @@ -41,4 +41,4 @@ jobs: with: compiler: gcc-latest - name: Compile ${{ matrix.file }} - run: g++ "${{ matrix.file }}" + run: g++ -c "${{ matrix.file }}" From 1928de21c6887895acd0d0f78bdfbf69579ed07f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 17 Feb 2022 17:55:46 +0100 Subject: [PATCH 54/84] Fixed "cannot instantiate abstract class" due to deserialize code trying to create new abstract instance of IndicatorBase class. Dict now have template specialization which will print an error and stop debugging if you try do deserialize such Dict. --- Serializer.mqh | 16 ++++++++++++++++ Std.h | 8 +++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Serializer.mqh b/Serializer.mqh index f33c6b2b0..b33084118 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -37,6 +37,7 @@ // Forward declarations. template class SerializerIterator; +class IndicatorBase; class Serializer { protected: @@ -378,6 +379,21 @@ class Serializer { } } + template + void Pass(T& self, string name, IndicatorBase*& value, unsigned int flags = SERIALIZER_FIELD_FLAG_DEFAULT) { + if (_mode == Serialize) { + if (!IsFieldVisible(_flags, flags)) { + return; + } + + PassObject(self, name, value, flags); + } else { + Print("Error: Deserialization of IndicatorBase* cannot be done as method is abstract!"); + DebugBreak(); + value = nullptr; + } + } + /** * Serializes or unserializes simple value. */ diff --git a/Std.h b/Std.h index cd62af350..500b5f34f 100644 --- a/Std.h +++ b/Std.h @@ -262,7 +262,13 @@ inline bool IsNull(const string& str) { return str == ""; } template class InvalidEnumValue { public: - static T value() { return (T)INT_MAX; } +#ifdef __cplusplus + constexpr +#endif + static const T + value() { + return (T)INT_MAX; + } }; #ifndef __MQL__ From ee5037bd0a35f6f90b004b5829ff4d35d8935086 Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 17 Feb 2022 21:47:18 +0000 Subject: [PATCH 55/84] GHA: Installs Emscripten toolchain --- .github/workflows/compile-cpp.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile-cpp.yml b/.github/workflows/compile-cpp.yml index 5fa17e2ca..9a2d220e4 100644 --- a/.github/workflows/compile-cpp.yml +++ b/.github/workflows/compile-cpp.yml @@ -36,9 +36,13 @@ jobs: file: ${{ fromJson(needs.FileList.outputs.filelist) }} steps: - uses: actions/checkout@v2 - - name: Install compiler + - name: Install Emscripten toolchain + uses: mymindstorm/setup-emsdk@v11 + - name: Install CPP compiler uses: rlalik/setup-cpp-compiler@v1.1 with: compiler: gcc-latest - - name: Compile ${{ matrix.file }} + - name: Compile ${{ matrix.file }} via emcc + run: emcc "${{ matrix.file }}" + - name: Compile ${{ matrix.file }} via g++ run: g++ -c "${{ matrix.file }}" From bb3628642910744267b41192e7da2cdd173e01e1 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 18 Feb 2022 17:27:11 +0100 Subject: [PATCH 56/84] Got rid of `u(char, int, long)`s so we have `unsigned (char, int, long)`s --- 3D/Math.h | 12 +-- Account.mqh | 4 +- Buffer/BufferTick.h | 6 +- Chart.mqh | 38 +++++--- Chart.struct.static.h | 10 +- Chart.struct.tf.h | 2 +- Common.define.h | 4 - Common.extern.h | 2 +- Convert.mqh | 22 +++-- Data.enum.h | 8 +- EA.mqh | 40 ++++---- File.extern.h | 4 +- Indicator.enum.h | 2 +- Indicator.mqh | 12 +-- Indicator.struct.h | 2 +- Indicator/IndicatorTf.h | 2 +- Indicator/IndicatorTf.struct.h | 8 +- Indicator/IndicatorTick.h | 8 +- Indicator/tests/classes/IndicatorTfDummy.h | 4 +- IndicatorData.mqh | 20 ++-- Log.mqh | 2 +- MQL4.mqh | 62 ++++++------- Order.mqh | 5 +- Order.struct.h | 30 +++--- Orders.mqh | 30 +++--- Profiler.mqh | 4 +- Stats.mqh | 16 ++-- Strategy.mqh | 18 ++-- Strategy.struct.h | 20 ++-- String.extern.h | 6 +- String.mqh | 6 +- SymbolInfo.mqh | 24 ++--- SymbolInfo.struct.static.h | 17 ++-- Tester.mqh | 101 ++++++++++----------- Tests.mqh | 26 +++--- Ticker.mqh | 12 +-- Timer.mqh | 28 +++--- Trade.mqh | 24 ++--- Trade.struct.h | 8 +- tests/IndicatorDataTest.mq4 | 9 +- tests/IndicatorTest.mq5 | 2 +- tests/TickerTest.mq5 | 2 +- tests/TimerTest.mq5 | 2 +- 43 files changed, 337 insertions(+), 327 deletions(-) diff --git a/3D/Math.h b/3D/Math.h index e631a214a..651741a88 100644 --- a/3D/Math.h +++ b/3D/Math.h @@ -209,10 +209,10 @@ struct DXQuaternion { //| DViewport | //+------------------------------------------------------------------+ struct DViewport { - ulong x; - ulong y; - ulong width; - ulong height; + unsigned long x; + unsigned long y; + unsigned long width; + unsigned long height; float minz; float maxz; }; @@ -2336,7 +2336,7 @@ float DXSHDot(int order, const float &a[], const float &b[]) { //+------------------------------------------------------------------+ //| weightedcapintegrale | //+------------------------------------------------------------------+ -void weightedcapintegrale(float &out[], uint order, float angle) { +void weightedcapintegrale(float &out[], unsigned int order, float angle) { float coeff[3]; coeff[0] = (float)cos(angle); @@ -3031,7 +3031,7 @@ void DXSHMultiply4(float &out[], const float &a[], const float &b[]) { //+------------------------------------------------------------------+ //| rotate_X | //+------------------------------------------------------------------+ -void rotate_X(float &out[], uint order, float a, float &in[]) { +void rotate_X(float &out[], unsigned int order, float a, float &in[]) { out[0] = in[0]; out[1] = a * in[2]; out[2] = -a * in[1]; diff --git a/Account.mqh b/Account.mqh index 3dd4a1054..fc1c796d7 100644 --- a/Account.mqh +++ b/Account.mqh @@ -250,7 +250,7 @@ class Account { * Returns the limit orders (0 for unlimited). */ static long AccountLimitOrders() { return AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); } - long GetLimitOrders(uint _max = 999) { + long GetLimitOrders(unsigned int _max = 999) { long _limit = AccountLimitOrders(); return _limit > 0 ? _limit : _max; } @@ -322,7 +322,7 @@ class Account { double UpdateStats(ENUM_ACC_STAT_VALUE _type, double _value) { static datetime _last_check = TimeCurrent(); bool _stats_rotate = false; - for (uint _pindex = 0; _pindex < FINAL_ENUM_ACC_STAT_PERIOD; _pindex++) { + for (unsigned int _pindex = 0; _pindex < FINAL_ENUM_ACC_STAT_PERIOD; _pindex++) { acc_stats[_type][_pindex][ACC_VALUE_MIN][ACC_VALUE_CURR] = fmin(acc_stats[_type][_pindex][ACC_VALUE_MIN][ACC_VALUE_CURR], _value); acc_stats[_type][_pindex][ACC_VALUE_MAX][ACC_VALUE_CURR] = diff --git a/Buffer/BufferTick.h b/Buffer/BufferTick.h index d3eb35dab..bbbdc2039 100644 --- a/Buffer/BufferTick.h +++ b/Buffer/BufferTick.h @@ -135,10 +135,10 @@ class BufferTick : public BufferStruct> { /** * Group ticks by seconds. */ - DictStruct>> GroupBySecs(uint _spc) { - // DictStruct>> _result; + DictStruct>> GroupBySecs(unsigned int _spc) { + // DictStruct>> _result; // @todo: for each iter - // for (DictStructIterator>> iter(Begin()); iter.IsValid(); ++iter) { + // for (DictStructIterator>> iter(Begin()); iter.IsValid(); ++iter) { // Load timestamp from key, TickAB from value // foreach some timestamp mod % _spc - calculate shift // _result.Push(_shift, TickAB) diff --git a/Chart.mqh b/Chart.mqh index 9ec050222..ea3ade072 100644 --- a/Chart.mqh +++ b/Chart.mqh @@ -199,7 +199,7 @@ class Chart : public Market { * * @param * _tf ENUM_TIMEFRAMES Timeframe to use. - * _shift uint _shift Shift to use. + * _shift unsigned int _shift Shift to use. * _symbol string Symbol to use. * * @return @@ -219,7 +219,7 @@ class Chart : public Market { * Gets chart entry. * * @param - * _shift uint _shift Shift to use. + * _shift unsigned int _shift Shift to use. * * @return * Returns ChartEntry struct. @@ -287,7 +287,7 @@ class Chart : public Market { /* Timeseries */ /* @see: https://docs.mql4.com/series */ - datetime GetBarTime(ENUM_TIMEFRAMES _tf, uint _shift = 0) { return ChartStatic::iTime(symbol, _tf, _shift); } + datetime GetBarTime(ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { return ChartStatic::iTime(symbol, _tf, _shift); } datetime GetBarTime(unsigned int _shift = 0) { return ChartStatic::iTime(symbol, Get(CHART_PARAM_TF), _shift); } @@ -298,8 +298,10 @@ class Chart : public Market { * * If local history is empty (not loaded), function returns 0. */ - double GetOpen(ENUM_TIMEFRAMES _tf, uint _shift = 0) { return ChartStatic::iOpen(symbol, _tf, _shift); } - double GetOpen(uint _shift = 0) { return ChartStatic::iOpen(symbol, Get(CHART_PARAM_TF), _shift); } + double GetOpen(ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { return ChartStatic::iOpen(symbol, _tf, _shift); } + double GetOpen(unsigned int _shift = 0) { + return ChartStatic::iOpen(symbol, Get(CHART_PARAM_TF), _shift); + } /** * Returns close price value for the bar of indicated symbol. @@ -316,16 +318,20 @@ class Chart : public Market { * * If local history is empty (not loaded), function returns 0. */ - double GetLow(ENUM_TIMEFRAMES _tf, uint _shift = 0) { return ChartStatic::iLow(symbol, _tf, _shift); } - double GetLow(uint _shift = 0) { return ChartStatic::iLow(symbol, Get(CHART_PARAM_TF), _shift); } + double GetLow(ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { return ChartStatic::iLow(symbol, _tf, _shift); } + double GetLow(unsigned int _shift = 0) { + return ChartStatic::iLow(symbol, Get(CHART_PARAM_TF), _shift); + } /** * Returns low price value for the bar of indicated symbol. * * If local history is empty (not loaded), function returns 0. */ - double GetHigh(ENUM_TIMEFRAMES _tf, uint _shift = 0) { return ChartStatic::iHigh(symbol, _tf, _shift); } - double GetHigh(uint _shift = 0) { return ChartStatic::iHigh(symbol, Get(CHART_PARAM_TF), _shift); } + double GetHigh(ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { return ChartStatic::iHigh(symbol, _tf, _shift); } + double GetHigh(unsigned int _shift = 0) { + return ChartStatic::iHigh(symbol, Get(CHART_PARAM_TF), _shift); + } /** * Returns the current price value given applied price type. @@ -339,8 +345,10 @@ class Chart : public Market { * * If local history is empty (not loaded), function returns 0. */ - long GetVolume(ENUM_TIMEFRAMES _tf, uint _shift = 0) { return ChartStatic::iVolume(symbol, _tf, _shift); } - long GetVolume(uint _shift = 0) { return ChartStatic::iVolume(symbol, Get(CHART_PARAM_TF), _shift); } + long GetVolume(ENUM_TIMEFRAMES _tf, unsigned int _shift = 0) { return ChartStatic::iVolume(symbol, _tf, _shift); } + long GetVolume(unsigned int _shift = 0) { + return ChartStatic::iVolume(symbol, Get(CHART_PARAM_TF), _shift); + } /** * Returns the shift of the maximum value over a specific number of periods depending on type. @@ -849,7 +857,7 @@ class Chart : public Market { */ bool SaveChartEntry() { // @todo: Use MqlRates. - uint _last = ArraySize(chart_saves); + unsigned int _last = ArraySize(chart_saves); if (ArrayResize(chart_saves, _last + 1, 100)) { chart_saves[_last].bar.ohlc.time = ChartStatic::iTime(); chart_saves[_last].bar.ohlc.open = (float)Chart::GetOpen(); @@ -866,16 +874,16 @@ class Chart : public Market { * Load stored BarOHLC values. * * @param - * _index uint Index of the element in BarOHLC array. + * _index unsigned int Index of the element in BarOHLC array. * @return * Returns BarOHLC struct element. */ - ChartEntry LoadChartEntry(uint _index = 0) { return chart_saves[_index]; } + ChartEntry LoadChartEntry(unsigned int _index = 0) { return chart_saves[_index]; } /** * Return size of BarOHLC array. */ - ulong SizeChartEntry() { return ArraySize(chart_saves); } + unsigned long SizeChartEntry() { return ArraySize(chart_saves); } /* Serializers */ diff --git a/Chart.struct.static.h b/Chart.struct.static.h index f892cf2a8..5a1e91c72 100644 --- a/Chart.struct.static.h +++ b/Chart.struct.static.h @@ -89,7 +89,7 @@ struct ChartStatic { * * If local history is empty (not loaded), function returns 0. */ - static double iHigh(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, uint _shift = 0) { + static double iHigh(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _shift = 0) { #ifdef __MQL4__ return ::iHigh(_symbol, _tf, _shift); // Same as: High[_shift] #else // __MQL5__ @@ -103,7 +103,7 @@ struct ChartStatic { * Returns the shift of the maximum value over a specific number of periods depending on type. */ static int iHighest(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _type = MODE_HIGH, - uint _count = WHOLE_ARRAY, int _start = 0) { + unsigned int _count = WHOLE_ARRAY, int _start = 0) { #ifdef __MQL4__ return ::iHighest(_symbol, _tf, _type, _count, _start); #else // __MQL5__ @@ -146,7 +146,7 @@ struct ChartStatic { * * If local history is empty (not loaded), function returns 0. */ - static double iLow(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, uint _shift = 0) { + static double iLow(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _shift = 0) { #ifdef __MQL4__ return ::iLow(_symbol, _tf, _shift); // Same as: Low[_shift] #else // __MQL5__ @@ -203,7 +203,7 @@ struct ChartStatic { * * If local history is empty (not loaded), function returns 0. */ - static double iOpen(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, uint _shift = 0) { + static double iOpen(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _shift = 0) { #ifdef __MQL4__ return ::iOpen(_symbol, _tf, _shift); // Same as: Open[_shift] #else // __MQL5__ @@ -261,7 +261,7 @@ struct ChartStatic { * * If local history is empty (not loaded), function returns 0. */ - static datetime iTime(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, uint _shift = 0) { + static datetime iTime(string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, unsigned int _shift = 0) { #ifdef __MQL4__ return ::iTime(_symbol, _tf, _shift); // Same as: Time[_shift] #else // __MQL5__ diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 625fa74ae..3bff64239 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -127,7 +127,7 @@ struct ChartTf { * @return ENUM_TIMEFRAMES * Returns enum representing chart's timeframe value. */ - static ENUM_TIMEFRAMES SecsToTf(uint _secs = 0) { + static ENUM_TIMEFRAMES SecsToTf(unsigned int _secs = 0) { switch (_secs) { case 0: return PERIOD_CURRENT; diff --git a/Common.define.h b/Common.define.h index 09f7d754a..f95e124ae 100644 --- a/Common.define.h +++ b/Common.define.h @@ -28,8 +28,4 @@ // Data types. #include typedef std::string string; -typedef unsigned char uchar; -typedef unsigned int uint; -typedef unsigned long ulong; -typedef unsigned short ushort; #endif diff --git a/Common.extern.h b/Common.extern.h index 2092a4c16..03a90a139 100644 --- a/Common.extern.h +++ b/Common.extern.h @@ -28,7 +28,7 @@ extern void DebugBreak(); // Errors. -extern void SetUserError(ushort user_error); +extern void SetUserError(unsigned short user_error); // Exceptions. extern int NotImplementedException(); // Print-related functions. diff --git a/Convert.mqh b/Convert.mqh index 010a358e4..507bf4292 100644 --- a/Convert.mqh +++ b/Convert.mqh @@ -102,13 +102,15 @@ class Convert { /** * Points per pip given digits after decimal point of a symbol price. */ - static uint PointsPerPip(uint digits) { return (uint)pow((unsigned int)10, digits - (digits < 4 ? 2 : 4)); } + static unsigned int PointsPerPip(unsigned int digits) { + return (unsigned int)pow((unsigned int)10, digits - (digits < 4 ? 2 : 4)); + } /** * Returns number of points per pip. */ - static uint PointsPerPip(string _symbol = NULL) { - return PointsPerPip((uint)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS)); + static unsigned int PointsPerPip(string _symbol = NULL) { + return PointsPerPip((unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS)); } /** @@ -134,31 +136,31 @@ class Convert { * Convert pips into price value. */ static double PipsToValue(double pips, string _symbol = NULL) { - return PipsToValue(pips, (uint)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS)); + return PipsToValue(pips, (unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS)); } /** * Convert value into pips given price value and digits. */ - static double ValueToPips(double value, uint digits) { return value * pow(10, digits < 4 ? 2 : 4); } + static double ValueToPips(double value, unsigned int digits) { return value * pow(10, digits < 4 ? 2 : 4); } /** * Convert value into pips. */ static double ValueToPips(double value, string _symbol = NULL) { - return ValueToPips(value, (uint)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS)); + return ValueToPips(value, (unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS)); } /** * Convert pips into points. */ - static uint PipsToPoints(double pips, int digits) { return (uint)pips * PointsPerPip(digits); } + static unsigned int PipsToPoints(double pips, int digits) { return (unsigned int)pips * PointsPerPip(digits); } /** * Convert pips into points. */ - static uint PipsToPoints(double pips, string _symbol = NULL) { - return PipsToPoints(pips, (uint)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS)); + static unsigned int PipsToPoints(double pips, string _symbol = NULL) { + return PipsToPoints(pips, (unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS)); } /** @@ -170,7 +172,7 @@ class Convert { * Convert points into pips. */ static double PointsToPips(long pts, string _symbol = NULL) { - return PointsToPips(pts, (uint)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS)); + return PointsToPips(pts, (unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_DIGITS)); } /** diff --git a/Data.enum.h b/Data.enum.h index 0ae73679b..6b76c3732 100644 --- a/Data.enum.h +++ b/Data.enum.h @@ -48,9 +48,9 @@ enum ENUM_DATATYPE { TYPE_LONG, // long TYPE_SHORT, // short TYPE_STRING, // string - TYPE_UCHAR, // uchar - TYPE_UINT, // uint - TYPE_ULONG, // ulong - TYPE_USHORT, // ushort + TYPE_UCHAR, // unsigned char + TYPE_UINT, // unsigned int + TYPE_ULONG, // unsigned long + TYPE_USHORT, // unsigned short }; #endif diff --git a/EA.mqh b/EA.mqh index 0aa62972f..406e4e537 100644 --- a/EA.mqh +++ b/EA.mqh @@ -382,17 +382,17 @@ class EA : public Taskable { Strategy *_strat = iter.Value().Ptr(); Trade *_trade = trade.GetByKey(_Symbol); if (_strat.IsEnabled()) { - if (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) >= DATETIME_MINUTE) { + if (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) >= DATETIME_MINUTE) { // Process when new periods started. _strat.OnPeriod(estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS))); _strat.ProcessTasks(); - _trade.OnPeriod(estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS))); + _trade.OnPeriod(estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS))); eresults.stg_processed_periods++; } if (_strat.TickFilter(_tick)) { _can_trade &= !_strat.IsSuspended(); TradeSignalEntry _sentry = GetStrategySignalEntry(_strat, _can_trade, _strat.Get(STRAT_PARAM_SHIFT)); - if (_sentry.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_SIGNALS)) > 0) { + if (_sentry.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_SIGNALS)) > 0) { TradeSignal _signal(_sentry); if (_signal.GetSignalClose() != _signal.GetSignalOpen()) { tsm.SignalAdd(_signal); //, _tick.time); @@ -413,13 +413,13 @@ class EA : public Taskable { // On error, print logs. logger.Flush(); } - if (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) >= DATETIME_MINUTE) { + if (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) >= DATETIME_MINUTE) { // Process data, tasks and trades on new periods. ProcessTrades(); } } estate.last_updated.Update(); - if (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) >= DATETIME_MINUTE) { + if (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) >= DATETIME_MINUTE) { // Process data and tasks on new periods. ProcessData(); ProcessTasks(); @@ -482,9 +482,9 @@ class EA : public Taskable { * Checks for new starting periods. */ unsigned int ProcessPeriods() { - estate.Set(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS), estate.last_updated.GetStartedPeriods()); + estate.Set(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS), estate.last_updated.GetStartedPeriods()); OnPeriod(); - return estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)); + return estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)); } /** @@ -764,7 +764,7 @@ class EA : public Taskable { continue; } ENUM_ORDER_TYPE _otype = _order.Get(ORDER_TYPE); - Strategy *_strat = strats.GetByKey(_order.Get(ORDER_MAGIC)).Ptr(); + Strategy *_strat = strats.GetByKey(_order.Get(ORDER_MAGIC)).Ptr(); Strategy *_strat_sl = _strat.GetStratSl(); Strategy *_strat_tp = _strat.GetStratTp(); if (_strat_sl != NULL) { @@ -872,17 +872,17 @@ class EA : public Taskable { estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_CONNECTED), GetTerminal().IsConnected()); return !estate.IsConnected(); case EA_COND_ON_NEW_MINUTE: // On new minute. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MINUTE) != 0; + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MINUTE) != 0; case EA_COND_ON_NEW_HOUR: // On new hour. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_HOUR) != 0; + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_HOUR) != 0; case EA_COND_ON_NEW_DAY: // On new day. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_DAY) != 0; + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_DAY) != 0; case EA_COND_ON_NEW_WEEK: // On new week. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_WEEK) != 0; + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_WEEK) != 0; case EA_COND_ON_NEW_MONTH: // On new month. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MONTH) != 0; + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MONTH) != 0; case EA_COND_ON_NEW_YEAR: // On new year. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_YEAR) != 0; + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_YEAR) != 0; case EA_COND_ON_INIT: return estate.IsOnInit(); case EA_COND_ON_QUIT: @@ -1044,7 +1044,7 @@ class EA : public Taskable { * Executed when new time is started (like each minute). */ virtual void OnPeriod() { - if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MINUTE) != 0) { + if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MINUTE) != 0) { // New minute started. #ifndef __optimize__ if (Terminal::IsRealtime()) { @@ -1052,24 +1052,24 @@ class EA : public Taskable { } #endif } - if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_HOUR) != 0) { + if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_HOUR) != 0) { // New hour started. tsm.Refresh(); } - if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_DAY) != 0) { + if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_DAY) != 0) { // New day started. UpdateLotSize(); #ifndef __optimize__ logger.Flush(); #endif } - if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_WEEK) != 0) { + if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_WEEK) != 0) { // New week started. } - if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MONTH) != 0) { + if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MONTH) != 0) { // New month started. } - if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_YEAR) != 0) { + if ((estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_YEAR) != 0) { // New year started. } } diff --git a/File.extern.h b/File.extern.h index 52e15849a..cc1c63cf6 100644 --- a/File.extern.h +++ b/File.extern.h @@ -29,8 +29,8 @@ extern bool FileIsEnding(int file_handle); extern bool FileIsExist(const string file_name, int common_flag = 0); extern int FileClose(int file_handle); -extern int FileOpen(string file_name, int open_flags, short delimiter = '\t', uint codepage = CP_ACP); +extern int FileOpen(string file_name, int open_flags, short delimiter = '\t', unsigned int codepage = CP_ACP); extern int FileReadInteger(int file_handle, int size = INT_VALUE); extern string FileReadString(int file_handle, int length = -1); -extern uint FileWriteString(int file_handle, const string text_string, int length = -1); +extern unsigned int FileWriteString(int file_handle, const string text_string, int length = -1); #endif diff --git a/Indicator.enum.h b/Indicator.enum.h index 8bf58e7b1..bc2facd8d 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -227,7 +227,7 @@ enum INDICATOR_ENTRY_FLAGS { INDI_ENTRY_FLAG_IS_EXPIRED = 1 << 2, INDI_ENTRY_FLAG_IS_REAL = 1 << 3, // Type is real (float or double). INDI_ENTRY_FLAG_IS_PRICE = 1 << 4, - INDI_ENTRY_FLAG_IS_UNSIGNED = 1 << 5, // Type is unsigned (uint or ulong). + INDI_ENTRY_FLAG_IS_UNSIGNED = 1 << 5, // Type is unsigned (unsigned int or unsigned long). INDI_ENTRY_FLAG_IS_VALID = 1 << 6, INDI_ENTRY_FLAG_INSUFFICIENT_DATA = 1 << 7, // Entry has missing value for that shift and probably won't ever have. }; diff --git a/Indicator.mqh b/Indicator.mqh index 66560fc15..44b114855 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -1044,11 +1044,11 @@ class Indicator : public IndicatorBase { } else { if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED)) { if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { - _result &= !_entry.HasValue(ULONG_MAX); - _result &= !_entry.HasValue(NULL); + _result &= !_entry.HasValue(ULONG_MAX); + _result &= !_entry.HasValue(NULL); } else { - _result &= !_entry.HasValue(UINT_MAX); - _result &= !_entry.HasValue(NULL); + _result &= !_entry.HasValue(UINT_MAX); + _result &= !_entry.HasValue(NULL); } } else { if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { @@ -1111,10 +1111,10 @@ class Indicator : public IndicatorBase { _entry.values[_mode] = GetValue(_mode, _ishift); break; case TYPE_UINT: - _entry.values[_mode] = GetValue(_mode, _ishift); + _entry.values[_mode] = GetValue(_mode, _ishift); break; case TYPE_ULONG: - _entry.values[_mode] = GetValue(_mode, _ishift); + _entry.values[_mode] = GetValue(_mode, _ishift); break; case TYPE_DOUBLE: _entry.values[_mode] = GetValue(_mode, _ishift); diff --git a/Indicator.struct.h b/Indicator.struct.h index 4479aeea4..80c0b77bc 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -329,7 +329,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: diff --git a/Indicator/IndicatorTf.h b/Indicator/IndicatorTf.h index 84fe4b7c0..7f5f48724 100644 --- a/Indicator/IndicatorTf.h +++ b/Indicator/IndicatorTf.h @@ -55,7 +55,7 @@ class IndicatorTf : public IndicatorCandle { /** * Class constructor with timeframe enum. */ - IndicatorTf(uint _spc) { + IndicatorTf(unsigned int _spc) { iparams.SetSecsPerCandle(_spc); Init(); } diff --git a/Indicator/IndicatorTf.struct.h b/Indicator/IndicatorTf.struct.h index 5feae87e4..e1d6aa114 100644 --- a/Indicator/IndicatorTf.struct.h +++ b/Indicator/IndicatorTf.struct.h @@ -35,13 +35,13 @@ /* Structure for IndicatorTf class parameters. */ struct IndicatorTfParams : IndicatorParams { - uint spc; // Seconds per candle. + unsigned int spc; // Seconds per candle. // Struct constructor. - IndicatorTfParams(uint _spc = 60) : spc(_spc) {} + IndicatorTfParams(unsigned int _spc = 60) : spc(_spc) {} // Getters. - uint GetSecsPerCandle() { return spc; } + unsigned int GetSecsPerCandle() { return spc; } // Setters. - void SetSecsPerCandle(uint _spc) { spc = _spc; } + void SetSecsPerCandle(unsigned int _spc) { spc = _spc; } // 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 e654dde70..7cc97ef36 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -249,11 +249,11 @@ class IndicatorTick : public Indicator { } else { if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED)) { if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { - _result &= !_entry.HasValue(ULONG_MAX); - _result &= !_entry.HasValue(NULL); + _result &= !_entry.HasValue(ULONG_MAX); + _result &= !_entry.HasValue(NULL); } else { - _result &= !_entry.HasValue(UINT_MAX); - _result &= !_entry.HasValue(NULL); + _result &= !_entry.HasValue(UINT_MAX); + _result &= !_entry.HasValue(NULL); } } else { if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 6680f07e0..019b800d8 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -34,7 +34,7 @@ // Params for dummy candle-based indicator. struct IndicatorTfDummyParams : IndicatorTfParams { - IndicatorTfDummyParams(uint _spc = 60) : IndicatorTfParams(_spc) {} + IndicatorTfDummyParams(unsigned int _spc = 60) : IndicatorTfParams(_spc) {} }; /** @@ -42,7 +42,7 @@ struct IndicatorTfDummyParams : IndicatorTfParams { */ class IndicatorTfDummy : public IndicatorTf { public: - IndicatorTfDummy(uint _spc) : IndicatorTf(_spc) {} + IndicatorTfDummy(unsigned int _spc) : IndicatorTf(_spc) {} IndicatorTfDummy(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTf(_tf) {} IndicatorTfDummy(ENUM_TIMEFRAMES_INDEX _tfi = 0) : IndicatorTf(_tfi) {} diff --git a/IndicatorData.mqh b/IndicatorData.mqh index 242eb038a..54146e22a 100644 --- a/IndicatorData.mqh +++ b/IndicatorData.mqh @@ -182,10 +182,10 @@ class IndicatorBuffer { return true; } - string ToString(uint _limit = TO_STRING_LIMIT_DEFAULT) { + string ToString(unsigned int _limit = TO_STRING_LIMIT_DEFAULT) { string out = NULL; IndicatorValue* it = _head; - uint i = 0; + unsigned int i = 0; while (CheckPointer(it) == POINTER_DYNAMIC && i < _limit) { if (out != NULL) // add comma @@ -228,7 +228,7 @@ class IndicatorData : public Chart { /** * Class constructor. */ - void IndicatorData(string _name = NULL, uint _max_buffer = INDICATOR_BUFFERS_COUNT_MIN) : iname(_name) { + void IndicatorData(string _name = NULL, unsigned int _max_buffer = INDICATOR_BUFFERS_COUNT_MIN) : iname(_name) { _max_buffer = fmax(_max_buffer, INDICATOR_BUFFERS_COUNT_MIN); ArrayResize(buffers, _max_buffer); } @@ -241,24 +241,24 @@ class IndicatorData : public Chart { /** * Store a new indicator value. */ - bool IsValidMode(uint _mode) { return _mode < (uint)ArraySize(buffers); } + bool IsValidMode(unsigned int _mode) { return _mode < (unsigned int)ArraySize(buffers); } - bool Add(double _value, uint _mode = 0, uint _shift = CURR, bool _force = false) { + bool Add(double _value, unsigned int _mode = 0, unsigned int _shift = CURR, bool _force = false) { if (!IsValidMode(_mode)) return false; return buffers[_mode].Add(_value, GetBarTime(_shift), _force); } - bool Add(int _value, uint _mode = 0, uint _shift = CURR, bool _force = false) { + bool Add(int _value, unsigned int _mode = 0, unsigned int _shift = CURR, bool _force = false) { if (!IsValidMode(_mode)) return false; return buffers[_mode].Add(_value, GetBarTime(_shift), _force); } - double GetDouble(uint _mode = 0, uint _shift = CURR) { + double GetDouble(unsigned int _mode = 0, unsigned int _shift = CURR) { if (!IsValidMode(_mode)) return 0; return buffers[_mode].GetDouble(GetBarTime(_shift)); } - int GetInt(uint _mode = 0, uint _shift = CURR) { + int GetInt(unsigned int _mode = 0, unsigned int _shift = CURR) { if (!IsValidMode(_mode)) return 0; return buffers[_mode].GetInt(GetBarTime(_shift)); } @@ -271,7 +271,7 @@ class IndicatorData : public Chart { /** * Print stored data. */ - string ToString(int mode = -1, uint _limit = TO_STRING_LIMIT_DEFAULT) { + string ToString(int mode = -1, unsigned int _limit = TO_STRING_LIMIT_DEFAULT) { string _out = StringFormat("%s DATA:\n", GetName()); if (mode == -1) { // print all series for (int m = 0; m < ArraySize(buffers); m++) { @@ -288,7 +288,7 @@ class IndicatorData : public Chart { /** * Print stored data. */ - void PrintData(int mode = -1, uint _limit = TO_STRING_LIMIT_DEFAULT) { Print(ToString(mode, _limit)); } + void PrintData(int mode = -1, unsigned int _limit = TO_STRING_LIMIT_DEFAULT) { Print(ToString(mode, _limit)); } /** * Update indicator. diff --git a/Log.mqh b/Log.mqh index 9e7781d31..cf4cb64ab 100644 --- a/Log.mqh +++ b/Log.mqh @@ -209,7 +209,7 @@ class Log : public Object { // @fixme // Error: 'ArrayCopy' - cannot to apply function template // Array::ArrayCopy(_logs, data, 0, 0, WHOLE_ARRAY); - uint _size = ArraySize(_logs); + unsigned int _size = ArraySize(_logs); if (!ArrayResize(_logs, _size + last_entry)) { return false; } diff --git a/MQL4.mqh b/MQL4.mqh index b3e5c850c..b4a0c5398 100644 --- a/MQL4.mqh +++ b/MQL4.mqh @@ -99,7 +99,7 @@ double MarketInfo(string _symbol, int _type) { //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ -string StringSetChar(const string &String_Var, const int iPos, const ushort Value) { +string StringSetChar(const string &String_Var, const int iPos, const unsigned short Value) { string Str = String_Var; ::StringSetCharacter(Str, iPos, Value); @@ -123,7 +123,7 @@ class MT4HISTORY { static const bool IsTester; long Tickets[]; - uint Amount; + unsigned int Amount; datetime LastTime; @@ -252,14 +252,14 @@ class MT4HISTORY { } public: - static bool IsMT4Deal(const ulong Ticket) { + static bool IsMT4Deal(const unsigned long Ticket) { const ENUM_DEAL_TYPE Type = (ENUM_DEAL_TYPE)::HistoryDealGetInteger(Ticket, DEAL_TYPE); return (((Type != DEAL_TYPE_BUY) && (Type != DEAL_TYPE_SELL)) || ((ENUM_DEAL_ENTRY)::HistoryDealGetInteger(Ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT)); } - static bool IsMT4Order(const ulong Ticket) { + static bool IsMT4Order(const unsigned long Ticket) { return ((::HistoryOrderGetDouble(Ticket, ORDER_VOLUME_CURRENT) > 0) || (::HistoryOrderGetInteger(Ticket, ORDER_POSITION_ID) == 0)); } @@ -276,7 +276,7 @@ class MT4HISTORY { return ((int)this PTR_DEREF Amount); } - long operator[](const uint Pos) { + long operator[](const unsigned int Pos) { long Res = 0; if (Pos >= this PTR_DEREF Amount) { @@ -349,15 +349,15 @@ class MT4ORDERS { static const bool IsTester; - static ulong GetPositionDealIn(const ulong PositionIdentifier = 0) { - ulong Ticket = 0; + static unsigned long GetPositionDealIn(const unsigned long PositionIdentifier = 0) { + unsigned long Ticket = 0; if ((PositionIdentifier == 0) ? ::HistorySelectByPosition(::PositionGetInteger(POSITION_IDENTIFIER)) : ::HistorySelectByPosition(PositionIdentifier)) { const int Total = ::HistoryDealsTotal(); for (int i = 0; i < Total; i++) { - const ulong TicketDeal = ::HistoryDealGetTicket(i); + const unsigned long TicketDeal = ::HistoryDealGetTicket(i); if (TicketDeal > 0) if ((ENUM_DEAL_ENTRY)::HistoryDealGetInteger(TicketDeal, DEAL_ENTRY) == DEAL_ENTRY_IN) { @@ -375,7 +375,7 @@ class MT4ORDERS { double Commission = ::PositionGetDouble(POSITION_COMMISSION); if (Commission == 0) { - const ulong Ticket = MT4ORDERS::GetPositionDealIn(); + const unsigned long Ticket = MT4ORDERS::GetPositionDealIn(); if (Ticket > 0) { const double LotsIn = ::HistoryDealGetDouble(Ticket, DEAL_VOLUME); @@ -392,7 +392,7 @@ class MT4ORDERS { string comment = ::PositionGetString(POSITION_COMMENT); if (comment == "") { - const ulong Ticket = MT4ORDERS::GetPositionDealIn(); + const unsigned long Ticket = MT4ORDERS::GetPositionDealIn(); if (Ticket > 0) comment = ::HistoryDealGetString(Ticket, DEAL_COMMENT); } @@ -460,7 +460,7 @@ class MT4ORDERS { return; } - static void GetHistoryOrderData(const ulong Ticket) { + static void GetHistoryOrderData(const unsigned long Ticket) { MT4ORDERS::Order.Ticket = (int)::HistoryOrderGetInteger(Ticket, ORDER_TICKET); MT4ORDERS::Order.Type = (int)::HistoryOrderGetInteger(Ticket, ORDER_TYPE); @@ -492,7 +492,7 @@ class MT4ORDERS { return; } - static void GetHistoryPositionData(const ulong Ticket) { + static void GetHistoryPositionData(const unsigned long Ticket) { MT4ORDERS::Order.Ticket = (int)::HistoryDealGetInteger(Ticket, DEAL_TICKET); MT4ORDERS::Order.Type = (int)::HistoryDealGetInteger(Ticket, DEAL_TYPE); @@ -525,7 +525,7 @@ class MT4ORDERS { MT4ORDERS::Order.Commission = ::HistoryDealGetDouble(Ticket, DEAL_COMMISSION); MT4ORDERS::Order.Swap = ::HistoryDealGetDouble(Ticket, DEAL_SWAP); - const ulong OpenTicket = MT4ORDERS::GetPositionDealIn(::HistoryDealGetInteger(Ticket, DEAL_POSITION_ID)); + const unsigned long OpenTicket = MT4ORDERS::GetPositionDealIn(::HistoryDealGetInteger(Ticket, DEAL_POSITION_ID)); if (OpenTicket > 0) { MT4ORDERS::Order.OpenPrice = ::HistoryDealGetDouble(OpenTicket, DEAL_PRICE); @@ -547,7 +547,7 @@ class MT4ORDERS { } static bool Waiting(const bool FlagInit = false) { - static ulong StartTime = 0; + static unsigned long StartTime = 0; if (FlagInit) StartTime = ::GetMicrosecondCount(); @@ -637,7 +637,7 @@ class MT4ORDERS { return (MT4ORDERS::OrderSend(Request, Result) ? Result.retcode < TRADE_RETCODE_ERROR : false); } - static bool ModifyPosition(const ulong Ticket, MqlTradeRequest &Request) { + static bool ModifyPosition(const unsigned long Ticket, MqlTradeRequest &Request) { const bool Res = ::PositionSelectByTicket(Ticket); if (Res) { @@ -650,7 +650,7 @@ class MT4ORDERS { return (Res); } - static ENUM_ORDER_TYPE_FILLING GetFilling(const string Symb, const uint Type = ORDER_FILLING_FOK) { + static ENUM_ORDER_TYPE_FILLING GetFilling(const string Symb, const unsigned int Type = ORDER_FILLING_FOK) { const ENUM_SYMBOL_TRADE_EXECUTION ExeMode = (ENUM_SYMBOL_TRADE_EXECUTION)::SymbolInfoInteger(Symb, SYMBOL_TRADE_EXEMODE); const int FillingMode = (int)::SymbolInfoInteger(Symb, SYMBOL_FILLING_MODE); @@ -662,7 +662,7 @@ class MT4ORDERS { : (ENUM_ORDER_TYPE_FILLING)Type); } - static bool ModifyOrder(const ulong _ticket, const double _price, const datetime _expiration, + static bool ModifyOrder(const unsigned long _ticket, const double _price, const datetime _expiration, MqlTradeRequest &Request) { const bool _res = ::OrderSelect(_ticket); @@ -756,7 +756,7 @@ class MT4ORDERS { } public: - static uint OrderSend_MaxPause; + static unsigned int OrderSend_MaxPause; static bool MT4OrderSelect(const int Index, const int Select, const int Pool = MODE_TRADES) { return ((Select == SELECT_BY_POS) @@ -765,7 +765,7 @@ class MT4ORDERS { } // MT5 OrderSelect - static bool MT4OrderSelect(const ulong Ticket) { return (::OrderSelect(Ticket)); } + static bool MT4OrderSelect(const unsigned long Ticket) { return (::OrderSelect(Ticket)); } static int MT4OrdersTotal(void) { return (::OrdersTotal() + ::PositionsTotal()); } @@ -791,7 +791,7 @@ class MT4ORDERS { Request.deviation = SlipPage; Request.type = (ENUM_ORDER_TYPE)Type; - Request.type_filling = MT4ORDERS::GetFilling(Request.symbol, (uint)Request.deviation); + Request.type_filling = MT4ORDERS::GetFilling(Request.symbol, (unsigned int)Request.deviation); if (dExpiration > 0) { Request.type_time = ORDER_TIME_SPECIFIED; @@ -810,7 +810,7 @@ class MT4ORDERS { : -1); } - static bool MT4OrderModify(const ulong Ticket, const double _price, const double SL, const double TP, + static bool MT4OrderModify(const unsigned long Ticket, const double _price, const double SL, const double TP, const datetime Expiration, const color Arrow_Color = clrNONE) { MqlTradeRequest Request = {0}; @@ -833,7 +833,7 @@ class MT4ORDERS { return (Res); } - static bool MT4OrderClose(const ulong Ticket, const double dLots, const double _price, const int SlipPage, + static bool MT4OrderClose(const unsigned long Ticket, const double dLots, const double _price, const int SlipPage, const color Arrow_Color = clrNONE) { bool Res = ::PositionSelectByTicket(Ticket); @@ -852,7 +852,7 @@ class MT4ORDERS { Request.type = (ENUM_ORDER_TYPE)(1 - ::PositionGetInteger(POSITION_TYPE)); - Request.type_filling = MT4ORDERS::GetFilling(Request.symbol, (uint)Request.deviation); + Request.type_filling = MT4ORDERS::GetFilling(Request.symbol, (unsigned int)Request.deviation); Res = MT4ORDERS::NewOrderSend(Request); } @@ -860,7 +860,7 @@ class MT4ORDERS { return (Res); } - static bool MT4OrderCloseBy(const ulong Ticket, const int Opposite, const color Arrow_color) { + static bool MT4OrderCloseBy(const unsigned long Ticket, const int Opposite, const color Arrow_color) { bool Res = ::PositionSelectByTicket(Ticket); if (Res) { @@ -886,7 +886,7 @@ class MT4ORDERS { return (Res); } - static bool MT4OrderDelete(const ulong Ticket, const color Arrow_Color = clrNONE) { + static bool MT4OrderDelete(const unsigned long Ticket, const color Arrow_Color = clrNONE) { bool Res = ::OrderSelect(Ticket); if (Res) { @@ -909,23 +909,23 @@ static MT4HISTORY MT4ORDERS::History; static const bool MT4ORDERS::IsTester = (::MQLInfoInteger(MQL_TESTER) || ::MQLInfoInteger(MQL_OPTIMIZATION) || ::MQLInfoInteger(MQL_VISUAL_MODE) || ::MQLInfoInteger(MQL_FRAME_MODE)); -static uint MT4ORDERS::OrderSend_MaxPause = 1000000; // Maximum time synchronization in microseconds. +static unsigned int MT4ORDERS::OrderSend_MaxPause = 1000000; // Maximum time synchronization in microseconds. -bool OrderClose(const ulong Ticket, const double dLots, const double _price, const int SlipPage, +bool OrderClose(const unsigned long Ticket, const double dLots, const double _price, const int SlipPage, const color Arrow_Color = clrNONE) { return (MT4ORDERS::MT4OrderClose(Ticket, dLots, _price, SlipPage, Arrow_Color)); } -bool OrderModify(const ulong Ticket, const double _price, const double SL, const double TP, const datetime Expiration, - const color Arrow_Color = clrNONE) { +bool OrderModify(const unsigned long Ticket, const double _price, const double SL, const double TP, + const datetime Expiration, const color Arrow_Color = clrNONE) { return (MT4ORDERS::MT4OrderModify(Ticket, _price, SL, TP, Expiration, Arrow_Color)); } -bool OrderDelete(const ulong Ticket, const color Arrow_Color = clrNONE) { +bool OrderDelete(const unsigned long Ticket, const color Arrow_Color = clrNONE) { return (MT4ORDERS::MT4OrderDelete(Ticket, Arrow_Color)); } -bool OrderCloseBy(const ulong Ticket, const int Opposite, const color Arrow_color) { +bool OrderCloseBy(const unsigned long Ticket, const int Opposite, const color Arrow_color) { return (MT4ORDERS::MT4OrderCloseBy(Ticket, Opposite, Arrow_color)); } diff --git a/Order.mqh b/Order.mqh index 35b07eb57..8217f57b8 100644 --- a/Order.mqh +++ b/Order.mqh @@ -315,7 +315,7 @@ class Order : public SymbolInfo { * Returns true when order values can be refreshed, otherwise false. */ bool ShouldRefresh() { - return odata.Get(ORDER_PROP_TIME_LAST_REFRESH) + oparams.Get(ORDER_PARAM_REFRESH_FREQ) <= + return odata.Get(ORDER_PROP_TIME_LAST_REFRESH) + oparams.Get(ORDER_PARAM_REFRESH_FREQ) <= TimeCurrent(); } @@ -326,7 +326,8 @@ class Order : public SymbolInfo { * Returns true when order stops can be updated, otherwise false. */ bool ShouldUpdate() { - return odata.Get(ORDER_PROP_TIME_LAST_UPDATE) + oparams.Get(ORDER_PARAM_UPDATE_FREQ) <= TimeCurrent(); + return odata.Get(ORDER_PROP_TIME_LAST_UPDATE) + oparams.Get(ORDER_PARAM_UPDATE_FREQ) <= + TimeCurrent(); } /* State checking */ diff --git a/Order.struct.h b/Order.struct.h index dfc4792d2..bb1beb6b6 100644 --- a/Order.struct.h +++ b/Order.struct.h @@ -58,36 +58,36 @@ struct MqlTradeCheckResult { // @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. + unsigned long magic; // Expert Advisor ID (magic number). + unsigned long 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. + unsigned long 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. + unsigned long position; // Position ticket. + unsigned long position_by; // The ticket of an opposite position. }; // @see: https://www.mql5.com/en/docs/constants/structures/mqltraderesult struct MqlTradeResult { - uint retcode; // Operation return code. - ulong deal; // Deal ticket, if it is performed. - ulong order; // Order ticket, if it is placed. - double volume; // Deal volume, confirmed by broker. - double price; // Deal price, confirmed by broker. - double bid; // Current Bid price. - double ask; // Current Ask price. - string comment; // Broker comment to operation (by default it is filled by description of trade server return code). - uint request_id; // Request ID set by the terminal during the dispatch. - uint retcode_external; // Return code of an external trading system. + unsigned int retcode; // Operation return code. + unsigned long deal; // Deal ticket, if it is performed. + unsigned long 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). + unsigned int request_id; // Request ID set by the terminal during the dispatch. + unsigned int retcode_external; // Return code of an external trading system. }; #endif diff --git a/Orders.mqh b/Orders.mqh index b245450c4..d76253999 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -117,9 +117,9 @@ class Orders { /** * Finds order in the selected pool. */ - Order *SelectOrder(ulong _ticket) { - for (uint _pos = ArraySize(orders); _pos >= 0; _pos--) { - if (orders[_pos].Get(ORDER_PROP_TICKET) == _ticket) { + Order *SelectOrder(unsigned long _ticket) { + for (unsigned int _pos = ArraySize(orders); _pos >= 0; _pos--) { + if (orders[_pos].Get(ORDER_PROP_TICKET) == _ticket) { return orders[_pos]; } } @@ -129,13 +129,13 @@ class Orders { /** * Select order object by ticket. */ - Order *SelectByTicket(ulong _ticket) { + Order *SelectByTicket(unsigned long _ticket) { Order *_order = SelectOrder(_ticket); if (_order != NULL) { return _order; } else if ((pool == ORDERS_POOL_TRADES && Order::TryOrderSelect(_ticket, SELECT_BY_TICKET, MODE_TRADES)) || (pool == ORDERS_POOL_HISTORY && Order::TryOrderSelect(_ticket, SELECT_BY_TICKET, MODE_HISTORY))) { - uint _size = ArraySize(orders); + unsigned int _size = ArraySize(orders); ArrayResize(orders, _size + 1, 100); return orders[_size] = new Order(_ticket); } @@ -319,8 +319,8 @@ class Orders { } bool result = true; - uint total = OrdersTotal(); - for (uint i = total - 1; i >= 0; i--) { + unsigned int total = OrdersTotal(); + for (unsigned int i = total - 1; i >= 0; i--) { if (!Order::TryOrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { return (false); } @@ -332,7 +332,7 @@ class Orders { (_magic == -1 || OrderMagicNumber() == _magic)) { string o_symbol = OrderSymbol(); - uint _digits = SymbolInfoStatic::GetDigits(o_symbol); + unsigned int _digits = SymbolInfoStatic::GetDigits(o_symbol); bool res_one = false; int attempts = 10; while (attempts > 0) { @@ -355,7 +355,7 @@ class Orders { } //--- - uint slippage = SymbolInfoStatic::GetSpread(o_symbol); + unsigned int slippage = SymbolInfoStatic::GetSpread(o_symbol); //--- if (OrderClose(OrderTicket(), OrderLots(), close_price, slippage)) { @@ -376,9 +376,9 @@ class Orders { #endif #ifdef __MQL5__ - uint total = PositionsTotal(); + unsigned int total = PositionsTotal(); /* @fixme - for (uint i = total - 1; i >= 0; i--) { + for (unsigned int i = total - 1; i >= 0; i--) { if (!position_info.SelectByIndex(i)) return(false); @@ -487,8 +487,8 @@ class Orders { count.sell_count=0; #ifdef __MQL4__ - uint total = OrdersTotal(); - for (uint i = 0; i < total; i++) { + unsigned int total = OrdersTotal(); + for (unsigned int i = 0; i < total; i++) { if (!Order::OrderSelect(i, SELECT_BY_POS)) { return false; } @@ -531,8 +531,8 @@ class Orders { /** * Count open positions by order type. */ - static uint GetOrdersByType(ENUM_ORDER_TYPE _cmd, string _symbol = NULL) { - uint _counter = 0; + static unsigned int GetOrdersByType(ENUM_ORDER_TYPE _cmd, string _symbol = NULL) { + unsigned int _counter = 0; _symbol = _symbol != NULL ? _symbol : _Symbol; for (int i = 0; i < OrdersTotal(); i++) { if (Order::TryOrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break; diff --git a/Profiler.mqh b/Profiler.mqh index 15065de37..b04bb9913 100644 --- a/Profiler.mqh +++ b/Profiler.mqh @@ -43,7 +43,7 @@ class Profiler { public: // Variables. static Collection *timers; - static ulong min_time; + static unsigned long min_time; /* Class methods */ @@ -57,4 +57,4 @@ class Profiler { // Initialize static global variables. Collection *Profiler::timers = new Collection(MQLInfoString(MQL_PROGRAM_NAME)); -ulong Profiler::min_time = 1; +unsigned long Profiler::min_time = 1; diff --git a/Stats.mqh b/Stats.mqh index d22826325..23845bded 100644 --- a/Stats.mqh +++ b/Stats.mqh @@ -28,8 +28,8 @@ */ class Stats { public: - ulong total_bars; - ulong total_ticks; + unsigned long total_bars; + unsigned long total_ticks; int curr_period; // int custom_int[]; // double custom_dbl[]; @@ -72,22 +72,22 @@ class Stats { /** * Get number of counted bars. */ - ulong GetTotalBars() { return (total_bars); } + unsigned long GetTotalBars() { return (total_bars); } /** * Get number of counted ticks. */ - ulong GetTotalTicks() { return (total_ticks); } + unsigned long GetTotalTicks() { return (total_ticks); } /** * Get number of ticks per bar. */ - ulong GetTicksPerBar() { return (total_bars > 0 ? (total_ticks / total_bars) : 0); } + unsigned long GetTicksPerBar() { return (total_bars > 0 ? (total_ticks / total_bars) : 0); } /** * Get number of ticks per minute. */ - ulong GetTicksPerMin() { return (total_bars > 0 ? (total_ticks / total_bars / curr_period) : 0); } + unsigned long GetTicksPerMin() { return (total_bars > 0 ? (total_ticks / total_bars / curr_period) : 0); } /** * Get number of ticks per second. @@ -97,10 +97,10 @@ class Stats { /** * Get number of ticks per given time period. */ - ulong GetTicksPerPeriod(int period = PERIOD_H1) { return (GetTicksPerMin() * period); } + unsigned long GetTicksPerPeriod(int period = PERIOD_H1) { return (GetTicksPerMin() * period); } /** * Get number of bars per given time period. */ - ulong GetBarsPerPeriod(int period = PERIOD_H1) { return (total_bars / period); } + unsigned long GetBarsPerPeriod(int period = PERIOD_H1) { return (total_bars / period); } }; diff --git a/Strategy.mqh b/Strategy.mqh index a78362280..1f13a0167 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -154,7 +154,7 @@ class Strategy : public Taskable { /** * Process strategy's signals and orders. * - * @param ushort _periods_started + * @param unsigned short _periods_started * Periods which started. * * @return @@ -339,7 +339,7 @@ class Strategy : public Taskable { /** * Get strategy orders currently open. */ - uint GetOrdersOpen() { + unsigned int GetOrdersOpen() { // UpdateOrderStats(EA_STATS_TOTAL); // @todo return stats.orders_open; @@ -362,7 +362,7 @@ class Strategy : public Taskable { /** * Gets strategy orders total opened. */ - uint GetOrdersTotal(ENUM_STRATEGY_STATS_PERIOD _period = EA_STATS_TOTAL) { + unsigned int GetOrdersTotal(ENUM_STRATEGY_STATS_PERIOD _period = EA_STATS_TOTAL) { // UpdateOrderStats(_period); return stats_period[_period].orders_total; } @@ -370,7 +370,7 @@ class Strategy : public Taskable { /** * Gets strategy orders won. */ - uint GetOrdersWon(ENUM_STRATEGY_STATS_PERIOD _period = EA_STATS_TOTAL) { + unsigned int GetOrdersWon(ENUM_STRATEGY_STATS_PERIOD _period = EA_STATS_TOTAL) { // UpdateOrderStats(_period); return stats_period[_period].orders_won; } @@ -378,7 +378,7 @@ class Strategy : public Taskable { /** * Gets strategy orders lost. */ - uint GetOrdersLost(ENUM_STRATEGY_STATS_PERIOD _period = EA_STATS_TOTAL) { + unsigned int GetOrdersLost(ENUM_STRATEGY_STATS_PERIOD _period = EA_STATS_TOTAL) { // UpdateOrderStats(_period); return stats_period[_period].orders_lost; } @@ -590,7 +590,7 @@ class Strategy : public Taskable { /** * Convert timeframe constant to index value. */ - uint TfToIndex(ENUM_TIMEFRAMES _tf) { return ChartTf::TfToIndex(_tf); } + unsigned int TfToIndex(ENUM_TIMEFRAMES _tf) { return ChartTf::TfToIndex(_tf); } /** * Class constructor. @@ -1005,9 +1005,9 @@ class Strategy : public Taskable { StrategyPriceStop _psm(_method); _psm.SetChartParams(_chart.GetParams()); if (Object::IsValid(_indi)) { - int _ishift = 12; // @todo: Make it dynamic or as variable. - float _value = 0.0f; // @todo - //float _value = _indi.GetValuePrice(_ishift, 0, _direction > 0 ? PRICE_HIGH : PRICE_LOW); + int _ishift = 12; // @todo: Make it dynamic or as variable. + float _value = 0.0f; // @todo + // float _value = _indi.GetValuePrice(_ishift, 0, _direction > 0 ? PRICE_HIGH : PRICE_LOW); _value = _value + (float)Math::ChangeByPct(fabs(_value - _chart.GetCloseOffer(0)), _level) * _direction; _psm.SetIndicatorPriceValue(_value); /* diff --git a/Strategy.struct.h b/Strategy.struct.h index a29f778a6..d4d209272 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -416,21 +416,21 @@ struct StgProcessResult { /* Struture for strategy statistics */ struct StgStats { - uint orders_open; // Number of current opened orders. - uint errors; // Count reported errors. + unsigned int orders_open; // Number of current opened orders. + unsigned int errors; // Count reported errors. }; /* Structure for strategy's statistical periods. */ struct StgStatsPeriod { // Statistics variables. - uint orders_total; // Number of total opened orders. - uint orders_won; // Number of total won orders. - uint orders_lost; // Number of total lost orders. - double avg_spread; // Average spread. - double net_profit; // Total net profit. - double gross_profit; // Total gross profit. - double gross_loss; // Total gross loss. - double profit_factor; // Profit factor. + unsigned int orders_total; // Number of total opened orders. + unsigned int orders_won; // Number of total won orders. + unsigned int orders_lost; // Number of total lost orders. + double avg_spread; // Average spread. + double net_profit; // Total net profit. + double gross_profit; // Total gross profit. + double gross_loss; // Total gross loss. + double profit_factor; // Profit factor. // Getters. string ToCSV() { return StringFormat("%d,%d,%d,%g,%g,%g,%g,%g", orders_total, orders_won, orders_lost, avg_spread, net_profit, diff --git a/String.extern.h b/String.extern.h index 1cc9542cb..b59fb5a0d 100644 --- a/String.extern.h +++ b/String.extern.h @@ -34,10 +34,10 @@ extern int StringFind(string string_value, string match_substring, int start_pos extern int StringLen(string string_value); extern int StringSplit(const string& string_value, const unsigned short separator, ARRAY_REF(string, result)); extern long StringToInteger(string value); -extern string IntegerToString(long number, int str_len = 0, ushort fill_symbol = ' '); +extern string 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 ushort StringGetCharacter(string string_value, int pos); +extern unsigned short StringGetCharacter(string string_value, int pos); int StringToCharArray(string text_string, ARRAY_REF(unsigned char, array), int start = 0, int count = -1, - uint codepage = CP_ACP); + unsigned int codepage = CP_ACP); #endif diff --git a/String.mqh b/String.mqh index a145c3350..e29d40c7b 100644 --- a/String.mqh +++ b/String.mqh @@ -54,7 +54,7 @@ class String { * Add a new string. */ bool Add(string _string) { - uint _size = ArraySize(strings); + unsigned int _size = ArraySize(strings); if (ArrayResize(strings, _size + 1, 100)) { strings[_size] = _string; return true; @@ -91,7 +91,7 @@ class String { */ static void PrintText(string text) { ARRAY(string, _result); - ushort usep = StringGetCharacter("\n", 0); + unsigned short usep = StringGetCharacter("\n", 0); for (int i = StringSplit(text, usep, _result) - 1; i >= 0; i--) { Print(_result[i]); } @@ -102,7 +102,7 @@ class String { * * @see https://www.mql5.com/en/articles/81 */ - static string StringSetChar(string string_var, int pos, ushort character) { + static string StringSetChar(string string_var, int pos, unsigned short character) { #ifdef __MQLBUILD__ #ifdef __MQL4__ // In MQL4 the character is symbol code in ASCII. diff --git a/SymbolInfo.mqh b/SymbolInfo.mqh index c064a17a6..130b97201 100644 --- a/SymbolInfo.mqh +++ b/SymbolInfo.mqh @@ -48,13 +48,13 @@ class SymbolInfo : public Object { // Variables. string symbol; // Current symbol pair. Log logger; - MqlTick last_tick; // Stores the latest prices of the symbol. - ARRAY(MqlTick, tick_data); // Stores saved ticks. - SymbolInfoEntry s_entry; // Symbol entry. - SymbolInfoProp sprops; // Symbol properties. - double pip_size; // Value of pip size. - uint symbol_digits; // Count of digits after decimal point in the symbol price. - // uint pts_per_pip; // Number of points per pip. + MqlTick last_tick; // Stores the latest prices of the symbol. + ARRAY(MqlTick, tick_data); // Stores saved ticks. + SymbolInfoEntry s_entry; // Symbol entry. + SymbolInfoProp sprops; // Symbol properties. + double pip_size; // Value of pip size. + unsigned int symbol_digits; // Count of digits after decimal point in the symbol price. + // unsigned int pts_per_pip; // Number of points per pip. double volume_precision; public: @@ -173,12 +173,12 @@ class SymbolInfo : public Object { * * @see: https://www.mql5.com/en/docs/constants/environment_state/marketinfoconstants */ - ulong GetVolume() { return SymbolInfoStatic::GetTick(symbol).volume; } + unsigned long GetVolume() { return SymbolInfoStatic::GetTick(symbol).volume; } /** * Gets the last volume for the current price (without updating). */ - ulong GetLastVolume() { return last_tick.volume; } + unsigned long GetLastVolume() { return last_tick.volume; } /** * Get summary volume of current session deals. @@ -319,7 +319,7 @@ class SymbolInfo : public Object { * For the current symbol, it is stored in the predefined variable Digits. * */ - uint GetDigits() { return SymbolInfoStatic::GetDigits(symbol); } + unsigned int GetDigits() { return SymbolInfoStatic::GetDigits(symbol); } /** * Get current spread in points. @@ -331,7 +331,7 @@ class SymbolInfo : public Object { * @return * Return symbol trade spread level in points. */ - uint GetSpread() { return SymbolInfoStatic::GetSpread(symbol); } + unsigned int GetSpread() { return SymbolInfoStatic::GetSpread(symbol); } /** * Get real spread based on the ask and bid price (in points). @@ -403,7 +403,7 @@ class SymbolInfo : public Object { * * @see: https://book.mql4.com/appendix/limits */ - uint GetFreezeLevel() { return SymbolInfoStatic::GetFreezeLevel(symbol); } + unsigned int GetFreezeLevel() { return SymbolInfoStatic::GetFreezeLevel(symbol); } /** * Gets flags of allowed order filling modes. diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index 77f7f4d46..1ad9c5a51 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -69,7 +69,7 @@ struct SymbolInfoStatic { * * @see: https://www.mql5.com/en/docs/constants/environment_state/marketinfoconstants */ - static ulong GetVolume(string _symbol) { return GetTick(_symbol).volume; } + static unsigned long GetVolume(string _symbol) { return GetTick(_symbol).volume; } /** * Get summary volume of current session deals. @@ -244,9 +244,10 @@ struct SymbolInfoStatic { * For the current symbol, it is stored in the predefined variable Digits. * */ - static uint GetDigits(string _symbol) { - return (uint)SymbolInfoStatic::SymbolInfoInteger(_symbol, - SYMBOL_DIGITS); // Same as: MarketInfo(symbol, MODE_DIGITS); + static unsigned int GetDigits(string _symbol) { + return (unsigned int)SymbolInfoStatic::SymbolInfoInteger( + _symbol, + SYMBOL_DIGITS); // Same as: MarketInfo(symbol, MODE_DIGITS); } /** @@ -259,7 +260,9 @@ struct SymbolInfoStatic { * @return * Return symbol trade spread level in points. */ - static uint GetSpread(string _symbol) { return (uint)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_SPREAD); } + static unsigned int GetSpread(string _symbol) { + return (unsigned int)SymbolInfoStatic::SymbolInfoInteger(_symbol, SYMBOL_SPREAD); + } /** * Get real spread based on the ask and bid price (in points). @@ -348,8 +351,8 @@ struct SymbolInfoStatic { * * @see: https://book.mql4.com/appendix/limits */ - static uint GetFreezeLevel(string _symbol) { - return (uint)SymbolInfoStatic::SymbolInfoInteger( + static unsigned int GetFreezeLevel(string _symbol) { + return (unsigned int)SymbolInfoStatic::SymbolInfoInteger( _symbol, SYMBOL_TRADE_FREEZE_LEVEL); // Same as: MarketInfo(symbol, MODE_FREEZELEVEL); } diff --git a/Tester.mqh b/Tester.mqh index a5f911e74..e2984c2b2 100644 --- a/Tester.mqh +++ b/Tester.mqh @@ -28,62 +28,59 @@ * Class to provide functions to work with the strategy tester. */ class Tester : public Terminal { - - public: - - /** - * Check whether spread is valid. - */ - static bool ValidSpread(string _symbol = NULL, bool verbose = true) { - uint _symbol_spread = SymbolInfo::GetSpread(_symbol); - uint _real_spread = SymbolInfo::GetRealSpread(_symbol); - double _lot_step = SymbolInfo::GetVolumeStep(_symbol); - uint _digits = SymbolInfo::GetDigits(_symbol); - if (_real_spread == 0 || _symbol_spread != _real_spread) { - if (verbose) { - PrintFormat("Reported spread: %d pts", _symbol_spread); - PrintFormat("Real spread : %d pts", _real_spread); - PrintFormat("Ask/Bid : %g/%g", SymbolInfo::GetAsk(_symbol), SymbolInfo::GetBid(_symbol)); - PrintFormat("Symbol digits : %g", SymbolInfo::GetDigits(_symbol)); - PrintFormat("Lot step : %g", _lot_step); - PrintFormat("Error: Spread is not valid, it's %d!", _real_spread); - } - return (false); + public: + /** + * Check whether spread is valid. + */ + static bool ValidSpread(string _symbol = NULL, bool verbose = true) { + unsigned int _symbol_spread = SymbolInfo::GetSpread(_symbol); + unsigned int _real_spread = SymbolInfo::GetRealSpread(_symbol); + double _lot_step = SymbolInfo::GetVolumeStep(_symbol); + unsigned int _digits = SymbolInfo::GetDigits(_symbol); + if (_real_spread == 0 || _symbol_spread != _real_spread) { + if (verbose) { + PrintFormat("Reported spread: %d pts", _symbol_spread); + PrintFormat("Real spread : %d pts", _real_spread); + PrintFormat("Ask/Bid : %g/%g", SymbolInfo::GetAsk(_symbol), SymbolInfo::GetBid(_symbol)); + PrintFormat("Symbol digits : %g", SymbolInfo::GetDigits(_symbol)); + PrintFormat("Lot step : %g", _lot_step); + PrintFormat("Error: Spread is not valid, it's %d!", _real_spread); } - return (true); + return (false); } + return (true); + } - /** - * Check whether lot step is valid. - */ - static bool ValidLotstep(string _symbol = NULL, bool verbose = true) { - uint _symbol_spread = SymbolInfo::GetSpread(_symbol); - uint _real_spread = SymbolInfo::GetRealSpread(_symbol); - double _lot_step = SymbolInfo::GetVolumeStep(_symbol); - uint _digits = SymbolInfo::GetDigits(_symbol); - switch (_digits) { - case 4: - if (_lot_step != 0.1) { - if (verbose) { - PrintFormat("Symbol digits : %g", _digits); - PrintFormat("Lot step : %g", _lot_step); - PrintFormat("Error: Expected lot step for %d digits: 0.1, found: %g", _digits, _lot_step); - } - return (false); + /** + * Check whether lot step is valid. + */ + static bool ValidLotstep(string _symbol = NULL, bool verbose = true) { + unsigned int _symbol_spread = SymbolInfo::GetSpread(_symbol); + unsigned int _real_spread = SymbolInfo::GetRealSpread(_symbol); + double _lot_step = SymbolInfo::GetVolumeStep(_symbol); + unsigned int _digits = SymbolInfo::GetDigits(_symbol); + switch (_digits) { + case 4: + if (_lot_step != 0.1) { + if (verbose) { + PrintFormat("Symbol digits : %g", _digits); + PrintFormat("Lot step : %g", _lot_step); + PrintFormat("Error: Expected lot step for %d digits: 0.1, found: %g", _digits, _lot_step); } - break; - case 5: - if (_lot_step != 0.01) { - if (verbose) { - PrintFormat("Symbol digits : %g", _digits); - PrintFormat("Lot step : %g", _lot_step); - PrintFormat("Error: Expected lot step for %d digits: 0.01, found: %g", _digits, _lot_step); - } - return (false); + return (false); + } + break; + case 5: + if (_lot_step != 0.01) { + if (verbose) { + PrintFormat("Symbol digits : %g", _digits); + PrintFormat("Lot step : %g", _lot_step); + PrintFormat("Error: Expected lot step for %d digits: 0.01, found: %g", _digits, _lot_step); } - break; - } - return (true); + return (false); + } + break; } - + return (true); + } }; diff --git a/Tests.mqh b/Tests.mqh index 42fff5255..55c549aa8 100644 --- a/Tests.mqh +++ b/Tests.mqh @@ -28,18 +28,17 @@ * Class to provide various tests. */ class Tests { -public: - + public: /** * Test Bands indicator values. */ static bool TestBands(bool _print = true, string _symbol = NULL, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { bool correct, result = true; double _bands[3] = {}; - int _periods[5] = { 1, 5, 15, 30, 60 }; - int _modes[3] = { BAND_LOWER, BAND_BASE, BAND_UPPER }; + int _periods[5] = {1, 5, 15, 30, 60}; + int _modes[3] = {BAND_LOWER, BAND_BASE, BAND_UPPER}; Chart *_chart = new Chart(_tf, _symbol); - uint _digits = _chart.GetDigits(); + unsigned int _digits = _chart.GetDigits(); double _bid = _chart.GetBid(); double _ask = _chart.GetAsk(); double _open = _chart.GetOpen(); @@ -54,15 +53,17 @@ public: } for (int p = 0; p < ArraySize(_periods); p++) { for (int m = 0; m < ArraySize(_modes); m++) { - #ifdef __MQL4__ - _bands[m] = iBands(_symbol, _periods[p], 20, 2.0, 0, 0, _modes[m], 0); - #else - // @fixme: Convert to use Indicator class, so it works in both MQL4 and MQL5. - _bands[m] = 0.0; - #endif +#ifdef __MQL4__ + _bands[m] = iBands(_symbol, _periods[p], 20, 2.0, 0, 0, _modes[m], 0); +#else + // @fixme: Convert to use Indicator class, so it works in both MQL4 and MQL5. + _bands[m] = 0.0; +#endif } correct = (_bands[0] > 0 && _bands[1] > 0 && _bands[2] > 0 && _bands[0] < _bands[1] && _bands[1] < _bands[2]); - if (_print) PrintFormat("Bands M%d : %g/%g/%g => %s", _periods[p], _bands[0], _bands[1], _bands[2], correct ? "CORRECT" : "INCORRECT"); + if (_print) + PrintFormat("Bands M%d : %g/%g/%g => %s", _periods[p], _bands[0], _bands[1], _bands[2], + correct ? "CORRECT" : "INCORRECT"); result &= correct; } if (_print) Print(result ? "Bands values are correct!" : "Error: Bands values are not correct!"); @@ -78,5 +79,4 @@ public: result &= TestBands(print); return result; } - }; diff --git a/Ticker.mqh b/Ticker.mqh index a02bccd5c..75aee7c71 100644 --- a/Ticker.mqh +++ b/Ticker.mqh @@ -48,7 +48,7 @@ class Ticker { }; protected: - ulong total_added, total_ignored, total_processed, total_saved; + unsigned long total_added, total_ignored, total_processed, total_saved; // Struct variables. MqlTick data[]; // Class variables. @@ -85,22 +85,22 @@ class Ticker { /** * Get number of added ticks. */ - ulong GetTotalAdded() { return total_added; } + unsigned long GetTotalAdded() { return total_added; } /** * Get number of ignored ticks. */ - ulong GetTotalIgnored() { return total_ignored; } + unsigned long GetTotalIgnored() { return total_ignored; } /** * Get number of parsed ticks. */ - ulong GetTotalProcessed() { return total_processed; } + unsigned long GetTotalProcessed() { return total_processed; } /** * Get number of saved ticks. */ - ulong GetTotalSaved() { return total_saved; } + unsigned long GetTotalSaved() { return total_saved; } /* Other methods */ @@ -113,7 +113,7 @@ class Ticker { * @return * Returns true when tick should be parsed, otherwise ignored. */ - bool Process(Chart *_chart, uint _method) { + bool Process(Chart *_chart, unsigned int _method) { total_processed++; if (_method == 0 || total_processed == 1) { return true; diff --git a/Timer.mqh b/Timer.mqh index 986556b08..59f291ca3 100644 --- a/Timer.mqh +++ b/Timer.mqh @@ -32,9 +32,9 @@ class Timer : public Object { // Variables. string name; int index; - uint data[]; - uint start, end; - ulong max; + unsigned int data[]; + unsigned int start, end; + unsigned long max; public: /** @@ -73,7 +73,7 @@ class Timer : public Object { /** * Print the current timer times when maximum value is reached. */ - Timer *PrintOnMax(ulong _min = 1) { + Timer *PrintOnMax(unsigned long _min = 1) { return data[index] > _min && data[this PTR_DEREF index] >= this PTR_DEREF max ? PrintSummary() : GetPointer(this); } @@ -82,8 +82,8 @@ class Timer : public Object { /** * Stop the timer. */ - uint GetTime(uint _index) { return data[_index]; } - uint GetTime() { return GetTickCount() - this PTR_DEREF start; } + unsigned int GetTime(unsigned int _index) { return data[_index]; } + unsigned int GetTime() { return GetTickCount() - this PTR_DEREF start; } /** * Returns timer name. @@ -93,10 +93,10 @@ class Timer : public Object { /** * Get the sum of all values. */ - ulong GetSum() { - uint _size = ArraySize(this PTR_DEREF data); - ulong _sum = 0; - for (uint _i = 0; _i < _size; _i++) { + unsigned long GetSum() { + unsigned int _size = ArraySize(this PTR_DEREF data); + unsigned long _sum = 0; + for (unsigned int _i = 0; _i < _size; _i++) { _sum += data[_i]; } return _sum; @@ -105,7 +105,7 @@ class Timer : public Object { /** * Get the median of all values. */ - uint GetMedian() { + unsigned int GetMedian() { if (this PTR_DEREF index >= 0) { ArraySort(this PTR_DEREF data); } @@ -115,12 +115,14 @@ class Timer : public Object { /** * Get the minimum time value. */ - uint GetMin() { return this PTR_DEREF index >= 0 ? this PTR_DEREF data[ArrayMinimum(this PTR_DEREF data)] : 0; } + unsigned int GetMin() { + return this PTR_DEREF index >= 0 ? this PTR_DEREF data[ArrayMinimum(this PTR_DEREF data)] : 0; + } /** * Get the maximal time value. */ - uint GetMax() { + unsigned int GetMax() { int _index = this PTR_DEREF index >= 0 ? ArrayMaximum(this PTR_DEREF data) : -1; return _index >= 0 ? data[_index] : 0; } diff --git a/Trade.mqh b/Trade.mqh index 021f29203..5ba5a50af 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -600,10 +600,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * @return * Returns calculated lot size (volume). */ - float CalcLotSize(float _risk_margin = 1, // Risk margin in %. - float _risk_ratio = 1.0, // Risk ratio factor. - uint _orders_avg = 10, // Number of orders to use for the calculation. - uint _method = 0 // Method of calculation (0-3). + float CalcLotSize(float _risk_margin = 1, // Risk margin in %. + float _risk_ratio = 1.0, // Risk ratio factor. + unsigned int _orders_avg = 10, // Number of orders to use for the calculation. + unsigned int _method = 0 // Method of calculation (0-3). ) { float _avail_amount = _method % 2 == 0 ? account.GetMarginAvail() : account.GetTotalBalance(); float _lot_size_min = (float)GetChart().GetVolumeMin(); @@ -643,7 +643,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. 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.Get(ORDER_PROP_TICKET), _ref_order); order_last = _order; tstates.AddState(TRADE_STATE_ORDERS_ACTIVE); tstats.Add(TRADE_STAT_ORDERS_OPENED); @@ -676,9 +676,9 @@ HistorySelect(0, TimeCurrent()); // Select history for access. */ bool OrderMoveToHistory(Order *_order) { _order.Refresh(true); - orders_active.Unset(_order.Get(ORDER_PROP_TICKET)); + orders_active.Unset(_order.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.Get(ORDER_PROP_TICKET), _ref_order); /* @todo if (strategy != NULL) { strategy.OnOrderClose(_order); @@ -843,7 +843,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); return -1; } } else { @@ -876,7 +876,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. order_last = _order; } else { logger.Error("Error while closing order!", __FUNCTION_LINE__, - StringFormat("Code: %d", _order.Ptr().Get(ORDER_PROP_LAST_ERROR))); + StringFormat("Code: %d", _order.Ptr().Get(ORDER_PROP_LAST_ERROR))); return -1; } order_last = _order; @@ -913,7 +913,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. OrderMoveToHistory(_order.Ptr()); order_last = _order; } else { - logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); + logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get(ORDER_PROP_LAST_ERROR)); return -1; } } @@ -970,7 +970,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * Calculate available lot size given the risk margin. */ /* @fixme - uint CalcMaxLotSize(double risk_margin = 1.0) { + unsigned int CalcMaxLotSize(double risk_margin = 1.0) { double _avail_margin = account.AccountAvailMargin(); double _opened_lots = GetTrades().GetOpenLots(); // @todo @@ -1675,7 +1675,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. */ virtual void OnOrderOpen(const Order &_order) { if (logger.GetLevel() >= V_INFO) { - // logger.Info(_order.ToString(), (string)_order.Get(ORDER_TICKET)); // @fixme + // logger.Info(_order.ToString(), (string)_order.Get(ORDER_TICKET)); // @fixme ResetLastError(); // @fixme: Error 69539 } } diff --git a/Trade.struct.h b/Trade.struct.h index 73603284c..dcbd0206d 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -149,14 +149,14 @@ struct TradeParams { } } void SetBarsMin(unsigned short _value) { bars_min = _value; } - void SetLimits(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, uint _value = 0) { + void SetLimits(ENUM_TRADE_STAT_TYPE _type, ENUM_TRADE_STAT_PERIOD _period, unsigned int _value = 0) { // Set new trading limits for the given type and period. #ifdef __debug__ Print("Setting trade limit for type ", EnumToString(_type), " and period ", EnumToString(_period), " to ", _value); #endif limits_stats[_type][_period] = _value; } - void SetLimits(ENUM_TRADE_STAT_PERIOD _period, uint _value = 0) { + void SetLimits(ENUM_TRADE_STAT_PERIOD _period, unsigned int _value = 0) { // Set new trading limits for the given period. for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { #ifdef __debug__ @@ -166,13 +166,13 @@ struct TradeParams { limits_stats[t][_period] = _value; } } - void SetLimits(ENUM_TRADE_STAT_TYPE _type, uint _value = 0) { + 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[_type][p] = _value; } } - void SetLimits(uint _value = 0) { + 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++) { diff --git a/tests/IndicatorDataTest.mq4 b/tests/IndicatorDataTest.mq4 index dd6581caa..a556e1a39 100644 --- a/tests/IndicatorDataTest.mq4 +++ b/tests/IndicatorDataTest.mq4 @@ -28,7 +28,8 @@ #include "../IndicatorData.mqh" // User inputs. -#ifdef __input__ input #endif string __MA_Parameters__ = "-- Settings for the Moving Average indicator --"; // >>> MA <<< +#ifdef __input__ input #endif string __MA_Parameters__ = \ + "-- Settings for the Moving Average indicator --"; // >>> MA <<< #ifdef __input__ input #endif int MA_Period_Fast = 14; // Period Fast #ifdef __input__ input #endif int MA_Period_Medium = 20; // Period Medium #ifdef __input__ input #endif int MA_Period_Slow = 48; // Period Slow @@ -64,7 +65,7 @@ class I_MA : public IndicatorData { * - https://docs.mql4.com/indicators/ima * - https://www.mql5.com/en/docs/indicators/ima */ - static double iMA(string _symbol, ENUM_TIMEFRAMES _tf, uint _ma_period, int _ma_shift, + static double iMA(string _symbol, ENUM_TIMEFRAMES _tf, unsigned int _ma_period, int _ma_shift, ENUM_MA_METHOD _ma_method, // (MT4/MT5): MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA ENUM_APPLIED_PRICE _applied_price, // (MT4/MT5): PRICE_CLOSE, PRICE_OPEN, PRICE_HIGH, PRICE_LOW, // PRICE_MEDIAN, PRICE_TYPICAL, PRICE_WEIGHTED @@ -77,7 +78,7 @@ class I_MA : public IndicatorData { return CopyBuffer(_handle, 0, _shift, 1, _res) > 0 ? _res[0] : EMPTY_VALUE; #endif } - double iMA(uint _ma_period, int _ma_shift, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_PRICE _applied_price, + double iMA(unsigned int _ma_period, int _ma_shift, ENUM_MA_METHOD _ma_method, ENUM_APPLIED_PRICE _applied_price, int _shift = 0) { double _value = iMA(Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), _ma_period, _ma_shift, _ma_method, _applied_price, _shift); @@ -190,7 +191,7 @@ int OnInit() { int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { - uint start_at = GetTickCount(); + unsigned int start_at = GetTickCount(); int oldest_bar = rates_total - prev_calculated - 1; for (int i = oldest_bar; i >= 0; i--) { diff --git a/tests/IndicatorTest.mq5 b/tests/IndicatorTest.mq5 index 79b70758c..e837f8e92 100644 --- a/tests/IndicatorTest.mq5 +++ b/tests/IndicatorTest.mq5 @@ -43,7 +43,7 @@ int OnInit() { // Check dynamic allocation. MqlParam entry; entry.integer_value = 1; - for (uint i = 0; i < in.GetBufferSize() * 2; i++) { + for (unsigned int i = 0; i < in.GetBufferSize() * 2; i++) { in.AddValue(entry); Print("Index ", i, ": Curr: ", in.GetValue(0, 0).integer_value, "; Prev: ", in.GetValue(0, 1).integer_value); assertTrueOrFail(in.GetValue(0, 0).integer_value == entry.integer_value, diff --git a/tests/TickerTest.mq5 b/tests/TickerTest.mq5 index db6fd8dbf..dce53e832 100644 --- a/tests/TickerTest.mq5 +++ b/tests/TickerTest.mq5 @@ -31,7 +31,7 @@ // Global variables. Chart *chart; SymbolInfo *symbol; -ulong total_ticks; +unsigned long total_ticks; Ticker *ticker_csv; Ticker *ticker01; Ticker *ticker02; diff --git a/tests/TimerTest.mq5 b/tests/TimerTest.mq5 index 3e3944b3c..8ed0f1e83 100644 --- a/tests/TimerTest.mq5 +++ b/tests/TimerTest.mq5 @@ -35,7 +35,7 @@ bool Test5x16ms() { PrintFormat("Testing %s...", __FUNCTION__); Timer *timer = new Timer(__FUNCTION__); assertTrueOrReturn(timer.GetName() == __FUNCTION__, "Timer name is not correct!", false); - for (uint i = 0; i < 5; i++) { + for (unsigned int i = 0; i < 5; i++) { timer.Start(); Sleep(16); PrintFormat("Current time elapsed before stop (%d/5): %d", i + 1, timer.GetTime()); From 730cf0c0e8055dd9508d16c6b31519cb1d313fd9 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 18 Feb 2022 17:40:36 +0100 Subject: [PATCH 57/84] Added universal pointer dereference PTR_DEREF instead of '.' operator. --- Task/TaskAction.h | 3 ++- Task/TaskCondition.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 994a22f0d..56d053b99 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -35,6 +35,7 @@ #define TASK_ACTION_H // Includes. +#include "../Std.h" #include "../Terminal.define.h" #include "TaskAction.enum.h" #include "TaskAction.struct.h" @@ -70,7 +71,7 @@ class TaskAction : public TaskActionBase { */ bool Run() { bool _result = entry.IsValid() && entry.HasTriesLeft(); - _result &= obj.Run(entry); + _result &= obj PTR_DEREF Run(entry); if (_result) { entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE)); entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 70c1b861e..4ccbdbf04 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -35,6 +35,7 @@ #define TASK_CONDITION_H // Includes. +#include "../Std.h" #include "../Terminal.define.h" #include "TaskCondition.enum.h" #include "TaskCondition.struct.h" @@ -71,7 +72,7 @@ class TaskCondition : public TaskConditionBase { */ bool Check() { bool _result = entry.IsValid() && entry.HasTriesLeft(); - _result &= obj.Check(entry); + _result &= obj PTR_DEREF Check(entry); if (_result) { entry.RemoveFlags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)); entry.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_TIME_LAST_CHECK), TimeCurrent()); From d022aca379a447ef38655d5d54192b4584f88fa2 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 18 Feb 2022 17:52:14 +0100 Subject: [PATCH 58/84] Minor fixes --- DictIteratorBase.mqh | 2 +- DictStruct.mqh | 12 ++++++------ Task/Task.h | 23 ++++++++++------------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/DictIteratorBase.mqh b/DictIteratorBase.mqh index 329fc5cb8..8d11899fa 100644 --- a/DictIteratorBase.mqh +++ b/DictIteratorBase.mqh @@ -121,7 +121,7 @@ class DictIteratorBase { bool IsLast() { if (!IsValid()) return true; - if (_dict PTR_DEREF GetMode() == DictModeUnknown || _dict.Size() == 0) { + if (_dict PTR_DEREF GetMode() == DictModeUnknown || _dict PTR_DEREF Size() == 0) { return false; } diff --git a/DictStruct.mqh b/DictStruct.mqh index 6ba129907..cce7f9e31 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -169,14 +169,14 @@ class DictStruct : public DictBase { else slot = GetSlotByKey(THIS_ATTR _DictSlots_ref, key, position); - if (slot == NULL || !slot.IsUsed()) { + if (slot == NULL || !slot PTR_DEREF IsUsed()) { Alert("Invalid DictStruct key \"", key, "\" (called by [] operator). Returning empty structure."); DebugBreak(); static V _empty; return _empty; } - return slot.value; + return slot PTR_DEREF value; } /** @@ -191,7 +191,7 @@ class DictStruct : public DictBase { return _empty; } - return slot.value; + return slot PTR_DEREF value; } /** @@ -208,7 +208,7 @@ class DictStruct : public DictBase { return _default; } - return slot.value; + return slot PTR_DEREF value; } /** @@ -224,7 +224,7 @@ class DictStruct : public DictBase { return _empty; } - return slot.value; + return slot PTR_DEREF value; } /** @@ -258,7 +258,7 @@ class DictStruct : public DictBase { if (!slot) return false; - return slot.value == value; + return slot PTR_DEREF value == value; } /** diff --git a/Task/Task.h b/Task/Task.h index deb626cad..0854b9d18 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -239,19 +239,16 @@ class Task : public Taskable { unsigned int _counter = 0; for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { TaskEntry _entry = iter.Value(); - switch (_value) { - case false: - if (_entry.HasFlag(_flag)) { - _entry.SetFlag(_flag, _value); - _counter++; - } - break; - case true: - if (!_entry.HasFlag(_flag)) { - _entry.SetFlag(_flag, _value); - _counter++; - } - break; + if (!_value) { + if (_entry.HasFlag(_flag)) { + _entry.SetFlag(_flag, _value); + _counter++; + } + } else { + if (!_entry.HasFlag(_flag)) { + _entry.SetFlag(_flag, _value); + _counter++; + } } } return _counter > 0; From 12ce16134c42c972e83732654022a84927d2e09a Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 20 Feb 2022 14:17:45 +0000 Subject: [PATCH 59/84] Renames Collection to Storage/ --- .github/workflows/test-storage.yml | 59 +++++++++++++++++++ .github/workflows/test.yml | 1 - Log.mqh | 4 +- Profiler.mqh | 4 +- README.md | 44 -------------- Collection.mqh => Storage/Collection.mqh | 11 ++-- Storage/README.md | 44 ++++++++++++++ .../tests/Collection.test.mq4 | 4 +- .../tests/Collection.test.mq5 | 4 +- tests/CompileTest.mq5 | 4 +- tests/docker-compose.yml | 7 --- 11 files changed, 118 insertions(+), 68 deletions(-) create mode 100644 .github/workflows/test-storage.yml rename Collection.mqh => Storage/Collection.mqh (96%) create mode 100644 Storage/README.md rename tests/CollectionTest.mq4 => Storage/tests/Collection.test.mq4 (91%) rename tests/CollectionTest.mq5 => Storage/tests/Collection.test.mq5 (96%) diff --git a/.github/workflows/test-storage.yml b/.github/workflows/test-storage.yml new file mode 100644 index 000000000..327fce7cd --- /dev/null +++ b/.github/workflows/test-storage.yml @@ -0,0 +1,59 @@ +--- +name: Test Storage + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Storage/**' + - '.github/workflows/test-storage.yml' + push: + paths: + - 'Storage/**' + - '.github/workflows/test-storage.yml' + +jobs: + + Compile: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Compile + uses: fx31337/mql-compile-action@master + with: + init-platform: true + path: 'Storage/tests' + verbose: true + - name: Print compiled files + run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname' + shell: powershell + - name: Upload artifacts (MQL4) + uses: actions/upload-artifact@v2 + with: + name: files-ex4 + path: '**/*.ex4' + - name: Upload artifacts (MQL5) + uses: actions/upload-artifact@v2 + with: + name: files-ex5 + path: '**/*.ex5' + + Storage-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Storage/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - Collection.test + steps: + - uses: actions/download-artifact@v2 + with: + name: files-ex4 + - name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + Script: ${{ matrix.test }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7040970bc..0b178bd7e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -101,7 +101,6 @@ jobs: matrix: test: # - 3DTest - - CollectionTest - ConfigTest - ConvertTest - DateTimeTest diff --git a/Log.mqh b/Log.mqh index 9e7781d31..ef986f034 100644 --- a/Log.mqh +++ b/Log.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -22,10 +22,10 @@ // Includes. #include "Array.mqh" -#include "Collection.mqh" #include "DateTime.mqh" #include "DictStruct.mqh" #include "Object.mqh" +#include "Storage/Collection.mqh" // Prevents processing this includes file for the second time. #ifndef LOG_MQH diff --git a/Profiler.mqh b/Profiler.mqh index 15065de37..1c47d0111 100644 --- a/Profiler.mqh +++ b/Profiler.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -21,7 +21,7 @@ */ // Includes. -#include "Collection.mqh" +#include "Storage/Collection.mqh" #include "Timer.mqh" // Defines macros. diff --git a/README.md b/README.md index 475d5a24a..0f8b313e0 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,6 @@ It can be also used to convert your MQL4 code into MQL5 with minimum code change - [`Account` class](#account-class) - [Example 1 - Managing account (dynamic calls)](#example-1---managing-account-dynamic-calls) - [Example 2 - Managing account (static calls)](#example-2---managing-account-static-calls) - - [`Collection` class](#collection-class) - [`Dict` class](#dict-class) - [Example 1 - Storing string-int data structures](#example-1---storing-string-int-data-structures) - [`Mail` class](#mail-class) @@ -180,49 +179,6 @@ The class for managing the current trading account. // Some trade code. } -### `Collection` class - -This class is for storing various type of objects. Here is the example usage: - - // Define custom classes of Object type. - class Stack : Object { - public: - virtual string GetName() = NULL; - }; - class Foo : Stack { - public: - string GetName() { return "Foo"; }; - double Weight() { return 0; }; - }; - class Bar : Stack { - public: - string GetName() { return "Bar"; }; - double Weight() { return 1; }; - }; - class Baz : Stack { - public: - string GetName() { return "Baz"; }; - double Weight() { return 2; }; - }; - - int OnInit() { - // Define and add items. - Collection *stack = new Collection(); - stack.Add(new Foo); - stack.Add(new Bar); - stack.Add(new Baz); - // Print the lowest and the highest items. - Print("Lowest: ", ((Stack *)stack.GetLowest()).GetName()); - Print("Highest: ", ((Stack *)stack.GetHighest()).GetName()); - // Print all the items. - for (uint i = 0; i < stack.GetSize(); i++) { - Print(i, ": ", ((Stack *)stack.GetByIndex(i)).GetName()); - } - // Clean up. - Object::Delete(stack); - return (INIT_SUCCEEDED); - } - ### `Dict` class Use this class to store the values in form of a collective attribute–value pairs, diff --git a/Collection.mqh b/Storage/Collection.mqh similarity index 96% rename from Collection.mqh rename to Storage/Collection.mqh index d43fa1b70..691331bb9 100644 --- a/Collection.mqh +++ b/Storage/Collection.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -25,12 +25,12 @@ #define COLLECTION_MQH // Includes. -#include "Object.mqh" +#include "../Object.mqh" /** * Class to deal with collection of objects. */ -template +template class Collection { protected: // Variables. @@ -45,8 +45,7 @@ class Collection { Collection() {} Collection(string _name) : name(_name) {} Collection(void *_obj) { Add(_obj); } - ~Collection() { - } + ~Collection() {} /* Setters */ @@ -99,7 +98,7 @@ class Collection { /** * Returns pointer to the current object. */ - X* GetCurrentItem() { return data[index].Ptr() != NULL ? data[index].Ptr() : NULL; } + X *GetCurrentItem() { return data[index].Ptr() != NULL ? data[index].Ptr() : NULL; } /** * Returns ID of the current object. diff --git a/Storage/README.md b/Storage/README.md new file mode 100644 index 000000000..c6e55ecfa --- /dev/null +++ b/Storage/README.md @@ -0,0 +1,44 @@ +# Storage classes + +## `Collection` class + +This class is for storing various type of objects. Here is the example usage: + + // Define custom classes of Object type. + class Stack : Object { + public: + virtual string GetName() = NULL; + }; + class Foo : Stack { + public: + string GetName() { return "Foo"; }; + double Weight() { return 0; }; + }; + class Bar : Stack { + public: + string GetName() { return "Bar"; }; + double Weight() { return 1; }; + }; + class Baz : Stack { + public: + string GetName() { return "Baz"; }; + double Weight() { return 2; }; + }; + + int OnInit() { + // Define and add items. + Collection *stack = new Collection(); + stack.Add(new Foo); + stack.Add(new Bar); + stack.Add(new Baz); + // Print the lowest and the highest items. + Print("Lowest: ", ((Stack *)stack.GetLowest()).GetName()); + Print("Highest: ", ((Stack *)stack.GetHighest()).GetName()); + // Print all the items. + for (uint i = 0; i < stack.GetSize(); i++) { + Print(i, ": ", ((Stack *)stack.GetByIndex(i)).GetName()); + } + // Clean up. + Object::Delete(stack); + return (INIT_SUCCEEDED); + } diff --git a/tests/CollectionTest.mq4 b/Storage/tests/Collection.test.mq4 similarity index 91% rename from tests/CollectionTest.mq4 rename to Storage/tests/Collection.test.mq4 index 671a0932e..a382bdff0 100644 --- a/tests/CollectionTest.mq4 +++ b/Storage/tests/Collection.test.mq4 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -25,4 +25,4 @@ */ // Includes. -#include "CollectionTest.mq5" +#include "Collection.test.mq5" diff --git a/tests/CollectionTest.mq5 b/Storage/tests/Collection.test.mq5 similarity index 96% rename from tests/CollectionTest.mq5 rename to Storage/tests/Collection.test.mq5 index 6ed2ee3cb..eb515ba64 100644 --- a/tests/CollectionTest.mq5 +++ b/Storage/tests/Collection.test.mq5 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -26,7 +26,7 @@ // Includes. #include "../Collection.mqh" -#include "../Test.mqh" +#include "../../Test.mqh" // Define classes. class Stack : public Object { diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index a5d4703fd..de94a7b1a 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -43,7 +43,6 @@ #include "../Buffer.mqh" #include "../BufferStruct.mqh" #include "../Chart.mqh" -#include "../Collection.mqh" #include "../Config.mqh" #include "../Convert.mqh" #include "../Database.mqh" @@ -65,6 +64,7 @@ #include "../Inet.mqh" #include "../Log.mqh" #include "../MD5.mqh" +#include "../Storage/Collection.mqh" #include "../Storage/IValueStorage.h" #include "../Task/TaskCondition.h" //#include "../MQL4.mqh" // @removeme diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 5b1e78fc9..14a5d00e6 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -43,13 +43,6 @@ services: BT_DAYS: 1-4 BT_MONTHS: 1 OPT_VERBOSE: 1 - CollectionTest: - command: run_backtest -s CollectionTest.mq4 - image: ea31337/ea-tester:latest - volumes: - - ../:/opt/src - environment: - OPT_VERBOSE: 1 ConditionTest: command: run_backtest -e ConditionTest.mq4 image: ea31337/ea-tester:EURUSD-2019-DS From 1a5d7ed5c624d015521dd2800919e92dccf18715 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 20 Feb 2022 18:07:55 +0000 Subject: [PATCH 60/84] C++ minor syntax fixes --- Account/Account.struct.h | 2 +- Account/AccountBase.struct.h | 2 +- Order.mqh | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Account/Account.struct.h b/Account/Account.struct.h index 7f70c1498..1b2a97517 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.enum.h" #endif // Forward class declaration. diff --git a/Account/AccountBase.struct.h b/Account/AccountBase.struct.h index f58e25e7f..0f808c590 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.enum.h" #endif // Forward class declaration. diff --git a/Order.mqh b/Order.mqh index 35b07eb57..7084cd7f7 100644 --- a/Order.mqh +++ b/Order.mqh @@ -2572,7 +2572,7 @@ class Order : public SymbolInfo { return NULL; #else return OrderGetValue(_prop_id, _type, _out); -#endif; +#endif } #endif @@ -2802,4 +2802,4 @@ ENUM_ORDER_SELECT_TYPE Order::selected_ticket_type = ORDER_SELECT_TYPE_NONE; unsigned long Order::selected_ticket_id = 0; #endif -#endif ORDER_MQH +#endif // ORDER_MQH From 86ee002e42d847cd87d7b49d62dacaa86e3ad1bb Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 21 Feb 2022 16:22:10 +0100 Subject: [PATCH 61/84] C++ compatibility fixes. --- DictObject.mqh | 14 +++++------ DictSlot.mqh | 14 ----------- Math.define.h | 47 +++++++++++++++++++++++++++++++++++++ Serializer.mqh | 2 +- SerializerConverter.mqh | 2 +- SerializerJson.mqh | 1 + Task/TaskObject.h | 4 ++-- tests/IndicatorDataTest.mq4 | 4 ++-- 8 files changed, 61 insertions(+), 27 deletions(-) diff --git a/DictObject.mqh b/DictObject.mqh index 719115c22..bcf0512ef 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -142,9 +142,9 @@ class DictObject : public DictBase { else slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, key, position); - if (slot == NULL || !slot.IsUsed()) return NULL; + if (slot == NULL || !slot PTR_DEREF IsUsed()) return NULL; - return &slot.value; + return &slot PTR_DEREF value; } /** @@ -156,7 +156,7 @@ class DictObject : public DictBase { if (!slot) return NULL; - return &slot.value; + return &slot PTR_DEREF value; } /** @@ -171,7 +171,7 @@ class DictObject : public DictBase { return NULL; } - return &slot.value; + return &slot PTR_DEREF value; } /** @@ -186,7 +186,7 @@ class DictObject : public DictBase { if (!slot) return false; - return slot.value == value; + return slot PTR_DEREF value == value; } /** @@ -265,7 +265,7 @@ class DictObject : public DictBase { if (this PTR_DEREF overflow_listener != NULL) { if (!this PTR_DEREF overflow_listener(DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS, dictSlotsRef._num_used, _num_conflicts)) { - // Overflow listener returned false so we won't search for further empty slot. + // Overflow listener returned false so we won't search for further empty slot PTR_DEREF _overwrite_slot = true; break; } @@ -285,7 +285,7 @@ class DictObject : public DictBase { // Overwriting starting position for faster further lookup. position = _starting_position; } else { - // Slot overwrite is not needed. Using empty slot. + // Slot overwrite is not needed. Using empty slot PTR_DEREF ++dictSlotsRef._num_used; } diff --git a/DictSlot.mqh b/DictSlot.mqh index af7ada6e6..3c1fe29e1 100644 --- a/DictSlot.mqh +++ b/DictSlot.mqh @@ -40,20 +40,6 @@ class DictSlot { DictSlot(unsigned char flags = 0) : _flags(flags) {} - /* - DictSlot(DictSlot &r) { - _flags = r._flags; - key = r.key; - value = r.value; - } - - void operator=(DictSlot &r) { - _flags = r._flags; - key = r.key; - value = r.value; - } - */ - bool IsValid() { return !bool(_flags & DICT_SLOT_INVALID); } bool HasKey() { return bool(_flags & DICT_SLOT_HAS_KEY); } diff --git a/Math.define.h b/Math.define.h index 8e519a71f..6a69aad1d 100644 --- a/Math.define.h +++ b/Math.define.h @@ -40,21 +40,68 @@ #ifdef __cplusplus #include +#ifndef CHAR_MIN #define CHAR_MIN std::numeric_limits::min() +#endif + +#ifndef CHAR_MAX #define CHAR_MAX std::numeric_limits::max() +#endif + +#ifndef UCHAR_MAX #define UCHAR_MAX std::numeric_limits::max() +#endif + +#ifndef SHORT_MAX #define SHORT_MAX std::numeric_limits::max() +#endif + +#ifndef SHORT_MIN #define SHORT_MIN std::numeric_limits::min() +#endif + +#ifndef USHORT_MAX #define USHORT_MAX std::numeric_limits::max() +#endif + +#ifndef INT_MIN #define INT_MIN std::numeric_limits::min() +#endif + +#ifndef INT_MAX #define INT_MAX std::numeric_limits::max() +#endif + +#ifndef UINT_MAX #define UINT_MAX std::numeric_limits::max() +#endif + +#ifndef LONG_MIN #define LONG_MIN std::numeric_limits::min() +#endif + +#ifndef LONG_MAX #define LONG_MAX std::numeric_limits::max() +#endif + +#ifndef ULONG_MAX #define ULONG_MAX std::numeric_limits::max() +#endif + +#ifndef FLT_MIN #define FLT_MIN std::numeric_limits::min() +#endif + +#ifndef FLT_MAX #define FLT_MAX std::numeric_limits::max() +#endif + +#ifndef DBL_MIN #define DBL_MIN std::numeric_limits::min() +#endif + +#ifndef DBL_MAX #define DBL_MAX std::numeric_limits::max() +#endif #endif diff --git a/Serializer.mqh b/Serializer.mqh index b33084118..e9335ec11 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -57,7 +57,7 @@ class Serializer { /** * Constructor. */ - Serializer(SerializerNode* node, SerializerMode mode, int flags) : _node(node), _mode(mode), _flags(flags) { + Serializer(SerializerNode* node, SerializerMode mode, int flags = 0) : _node(node), _mode(mode), _flags(flags) { _root = node; _root_node_ownership = true; fp_precision = SERIALIZER_DEFAULT_FP_PRECISION; diff --git a/SerializerConverter.mqh b/SerializerConverter.mqh index b1ef151fe..c137010f8 100644 --- a/SerializerConverter.mqh +++ b/SerializerConverter.mqh @@ -104,7 +104,7 @@ class SerializerConverter { template static SerializerConverter FromFile(string path) { string data = File::ReadFile(path); - SerializerConverter _converter(((C*)NULL).Parse(data), 0); + SerializerConverter _converter(((C*)nullptr)PTR_DEREF Parse(data), 0); return _converter; } diff --git a/SerializerJson.mqh b/SerializerJson.mqh index 1e87e3481..a0dc2f4c6 100644 --- a/SerializerJson.mqh +++ b/SerializerJson.mqh @@ -27,6 +27,7 @@ // Includes. #include "DictBase.mqh" #include "Object.mqh" +#include "Serializer.enum.h" #include "Serializer.mqh" #include "SerializerNode.mqh" #include "String.extern.h" diff --git a/Task/TaskObject.h b/Task/TaskObject.h index f673f7945..a26876edf 100644 --- a/Task/TaskObject.h +++ b/Task/TaskObject.h @@ -87,8 +87,8 @@ class TaskObject : public Task { virtual bool Process(TaskEntry &_entry) { bool _result = false; if (_entry.IsActive()) { - if (Object::IsValid(objc) && objc.Check(_entry.GetCondition()) && Object::IsValid(obja)) { - obja.Run(_entry.GetAction()); + if (Object::IsValid(objc) && objc PTR_DEREF Check(_entry.GetCondition()) && Object::IsValid(obja)) { + obja PTR_DEREF Run(_entry.GetAction()); _entry.Set(STRUCT_ENUM(TaskEntry, TASK_ENTRY_PROP_LAST_PROCESS), TimeCurrent()); if (_entry.IsDone()) { _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, diff --git a/tests/IndicatorDataTest.mq4 b/tests/IndicatorDataTest.mq4 index a556e1a39..01806abd6 100644 --- a/tests/IndicatorDataTest.mq4 +++ b/tests/IndicatorDataTest.mq4 @@ -28,8 +28,8 @@ #include "../IndicatorData.mqh" // User inputs. -#ifdef __input__ input #endif string __MA_Parameters__ = \ - "-- Settings for the Moving Average indicator --"; // >>> MA <<< +#ifdef __input__ input #endif string __MA_Parameters__ = +"-- Settings for the Moving Average indicator --"; // >>> MA <<< #ifdef __input__ input #endif int MA_Period_Fast = 14; // Period Fast #ifdef __input__ input #endif int MA_Period_Medium = 20; // Period Medium #ifdef __input__ input #endif int MA_Period_Slow = 48; // Period Slow From bacdb2371463940b2e51cf1fca0505b56c31dbbc Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Jul 2022 00:45:13 +0100 Subject: [PATCH 62/84] DrawIndicatorTest: Fixes compilation errors --- tests/DrawIndicatorTest.mq5 | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index 2770d7db5..e93b1d311 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -36,7 +36,7 @@ // Global variables. Chart *chart; -Dict indis; +DictStruct> indis; int bar_processed; /** @@ -64,8 +64,8 @@ void OnTick() { if (chart.IsNewBar()) { bar_processed++; - for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { - IndicatorData *_indi = iter.Value(); + for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + IndicatorData *_indi = iter.Value().Ptr(); _indi.OnTick(); IndicatorDataEntry _entry = _indi.GetEntry(); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)) && _entry.IsValid()) { @@ -78,13 +78,7 @@ void OnTick() { /** * Implements Deinit event handler. */ -void OnDeinit(const int reason) { - delete chart; - - for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { - delete iter.Value(); - } -} +void OnDeinit(const int reason) { delete chart; } /** * Initialize indicators. @@ -94,31 +88,33 @@ bool InitIndicators() { // Bollinger Bands. IndiBandsParams bands_params(20, 2, 0, PRICE_MEDIAN); - indis.Set(INDI_BANDS, new Indi_Bands(bands_params)); + Ref indi_bands = new Indi_Bands(bands_params); + indis.Set(INDI_BANDS, indi_bands); // Moving Average. IndiMAParams ma_params(13, 10, MODE_SMA, PRICE_OPEN); - IndicatorData *indi_ma = new Indi_MA(ma_params); + Ref indi_ma = new Indi_MA(ma_params); indis.Set(INDI_MA, indi_ma); // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); - indis.Set(INDI_RSI, new Indi_RSI(rsi_params)); + Ref indi_rsi = new Indi_RSI(rsi_params); + indis.Set(INDI_RSI, indi_rsi); /* Special indicators */ // Demo/Dummy Indicator. IndiDemoParams demo_params; - IndicatorData *indi_demo = new Indi_Demo(demo_params); + Ref indi_demo = new Indi_Demo(demo_params); indis.Set(INDI_DEMO, indi_demo); // Current Price (used by custom indicators) . PriceIndiParams price_params(); price_params.SetDraw(clrGreenYellow); - IndicatorData *indi_price = new Indi_Price(price_params); + Ref indi_price = new Indi_Price(price_params); indis.Set(INDI_PRICE, indi_price); - /* @fixme: Array out of range. + /* @fixme: Convert to new syntax. Array out of range. // Bollinger Bands over Price indicator. PriceIndiParams price_params_4_bands(); IndicatorData *indi_price_4_bands = new Indi_Price(price_params_4_bands); @@ -152,8 +148,8 @@ bool InitIndicators() { */ bool PrintIndicators(string _prefix = "") { ResetLastError(); - for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { - IndicatorData *_indi = iter.Value(); + for (DictStructIterator> iter = indis.Begin(); iter.IsValid(); ++iter) { + IndicatorData *_indi = iter.Value().Ptr(); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString()); } From d071b2acc306d570cf7d3a5298a6d35e295cd4a8 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Jul 2022 01:04:58 +0100 Subject: [PATCH 63/84] GHA: Enables DrawIndicatorTest --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9c5465a1c..7040970bc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,7 +59,7 @@ jobs: - ChartTest - CompileIndicatorsTest - DatabaseTest - # - DrawIndicatorTest + - DrawIndicatorTest - EATest - IndicatorDataTest - IndicatorTest From 4d07ee67d0bd08eacaf128b1d7170204f08f8d9a Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 30 Jan 2022 17:45:03 +0000 Subject: [PATCH 64/84] Corrects broken links --- SymbolInfo.struct.static.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SymbolInfo.struct.static.h b/SymbolInfo.struct.static.h index ac72ac73a..92bccaca6 100644 --- a/SymbolInfo.struct.static.h +++ b/SymbolInfo.struct.static.h @@ -136,6 +136,8 @@ struct SymbolInfoStatic { * */ static unsigned int GetPointsPerPip(string _symbol) { + // To be used to replace Point for trade parameters calculations. + // See: https://www.mql5.com/en/forum/124692 return (unsigned int)pow((unsigned int)10, SymbolInfoStatic::GetDigits(_symbol) - SymbolInfoStatic::GetPipDigits(_symbol)); } From 341d2d5e7ff81afdf83f14bbf32f506534852914 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 19 Feb 2022 20:44:14 +0000 Subject: [PATCH 65/84] Exchange: Expands test --- Exchange/Exchange.h | 18 ++++++++++++++---- Exchange/tests/Exchange.test.mq5 | 29 ++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/Exchange/Exchange.h b/Exchange/Exchange.h index 85b9e9202..da1d5d759 100644 --- a/Exchange/Exchange.h +++ b/Exchange/Exchange.h @@ -59,25 +59,35 @@ class Exchange { /* Adders */ /** - * Adds account to the list. + * Adds account instance to the list. */ void AccountAdd(Account &_account, string _name) { accounts.Set(_name, _account); } /** - * Adds symbol to the list. + * Adds symbol instance to the list. */ void SymbolAdd(SymbolInfo &_sinfo, string _name) { symbols.Set(_name, _sinfo); } + /** + * Adds trade instance to the list. + */ + void TradeAdd(Trade &_trade, string _name) { trades.Set(_name, _trade); } + /* Removers */ /** - * Removes account from the list. + * Removes account instance from the list. */ void AccountRemove(string _name) { accounts.Unset(_name); } /** - * Removes symbol from the list. + * Removes symbol instance from the list. */ void SymbolRemove(string _name) { symbols.Unset(_name); } + + /** + * Removes trade instance from the list. + */ + void TradeRemove(string _name) { trades.Unset(_name); } }; #endif // EXCHANGE_H diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 index 1c9d1c39b..91b8e25a2 100644 --- a/Exchange/tests/Exchange.test.mq5 +++ b/Exchange/tests/Exchange.test.mq5 @@ -29,15 +29,42 @@ #include "../Exchange.h" // Test classes. +class AccountDummy : public Account {}; class ExchangeDummy : public Exchange {}; +class SymbolDummy : public SymbolInfo {}; +class TradeDummy : public Trade {}; // Global variables. ExchangeDummy ex_dummy; +// Test dummy Exchange. +bool TestExchange01() { + bool _result = true; + // Initialize a dummy Exchange instance. + ExchangeDummy exchange; + // Attach instances of dummy accounts. + AccountDummy account01; + AccountDummy account02; + exchange.AccountAdd(account01, "Account01"); + exchange.AccountAdd(account02, "Account02"); + // Attach instances of dummy symbols. + SymbolDummy symbol01; + SymbolDummy symbol02; + exchange.SymbolAdd(symbol01, "Symbol01"); + exchange.SymbolAdd(symbol02, "Symbol02"); + // Attach instances of dummy trades. + TradeDummy trade01; + TradeDummy trade02; + exchange.TradeAdd(trade01, "Trade01"); + exchange.TradeAdd(trade02, "Trade02"); + return _result; +} + /** * Implements OnInit(). */ int OnInit() { bool _result = true; - return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; + assertTrueOrFail(TestExchange01(), "Fail!"); + return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; } From f00642859b4650cf9abc154aa28351cc11fde339 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 19 Feb 2022 22:14:41 +0000 Subject: [PATCH 66/84] Account: Renames Account to AccountMt --- .github/workflows/test-account.yml | 1 + .github/workflows/test.yml | 1 - Account.mqh => Account/AccountMt.h | 74 +++++++++---------- .../tests/AccountMt.test.mq4 | 6 +- .../tests/AccountMt.test.mq5 | 34 +++++---- BufferFXT.mqh | 12 +-- EA.mqh | 8 +- Exchange/Exchange.h | 8 +- Exchange/tests/Exchange.test.mq5 | 4 +- Mail.mqh | 12 +-- Orders.mqh | 5 +- SummaryReport.mqh | 8 +- Trade.mqh | 8 +- tests/CompileTest.mq5 | 3 +- 14 files changed, 94 insertions(+), 90 deletions(-) rename Account.mqh => Account/AccountMt.h (94%) rename tests/AccountTest.mq4 => Account/tests/AccountMt.test.mq4 (87%) rename tests/AccountTest.mq5 => Account/tests/AccountMt.test.mq5 (75%) diff --git a/.github/workflows/test-account.yml b/.github/workflows/test-account.yml index 3ac99f1f5..a9e3e351e 100644 --- a/.github/workflows/test-account.yml +++ b/.github/workflows/test-account.yml @@ -50,6 +50,7 @@ jobs: test: - Account.test - AccountForex.test + - AccountMt.test steps: - uses: actions/download-artifact@v2 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0b178bd7e..5944ed304 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,7 +53,6 @@ jobs: strategy: matrix: test: - - AccountTest - BufferStructTest - BufferTest - ChartTest diff --git a/Account.mqh b/Account/AccountMt.h similarity index 94% rename from Account.mqh rename to Account/AccountMt.h index 5cc52001a..1e07b6f8a 100644 --- a/Account.mqh +++ b/Account/AccountMt.h @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -21,33 +21,33 @@ */ // Prevents processing this includes file for the second time. -#ifndef ACCOUNT_MQH -#define ACCOUNT_MQH +#ifndef ACCOUNT_MT_MQH +#define ACCOUNT_MT_MQH // Forward class declaration. -class Account; +class AccountMt; // Includes. -#include "Account/Account.define.h" -#include "Account/Account.enum.h" -#include "Account/Account.extern.h" -#include "Account/Account.struct.h" -#include "Array.mqh" -#include "BufferStruct.mqh" -#include "Chart.mqh" -#include "Convert.mqh" -#include "Data.struct.h" -#include "Indicator.struct.h" -#include "Order.struct.h" -#include "Orders.mqh" -#include "Serializer.mqh" -#include "SymbolInfo.mqh" -#include "Trade.struct.h" +#include "../Array.mqh" +#include "../BufferStruct.mqh" +#include "../Chart.mqh" +#include "../Convert.mqh" +#include "../Data.struct.h" +#include "../Indicator.struct.h" +#include "../Order.struct.h" +#include "../Orders.mqh" +#include "../Serializer.mqh" +#include "../SymbolInfo.mqh" +#include "../Trade.struct.h" +#include "Account.define.h" +#include "Account.enum.h" +#include "Account.extern.h" +#include "Account.struct.h" /** * Class to provide functions that return parameters of the current account. */ -class Account { +class AccountMt { protected: // Struct variables. BufferStruct entries; @@ -62,17 +62,17 @@ class Account { /** * Class constructor. */ - Account() : init_balance(CalcInitDeposit()), start_balance(GetBalance()), start_credit(GetCredit()) {} + AccountMt() : init_balance(CalcInitDeposit()), start_balance(GetBalance()), start_credit(GetCredit()) {} /** * Class copy constructor. */ - Account(const Account &_account) {} + AccountMt(const AccountMt &_account) {} /** * Class deconstructor. */ - ~Account() {} + ~AccountMt() {} /* Entries */ @@ -139,7 +139,7 @@ class Account { float GetBalance() { // @todo: Adds caching. // return UpdateStats(ACC_BALANCE, AccountBalance()); - return (float)Account::AccountBalance(); + return (float)AccountMt::AccountBalance(); } /** @@ -149,7 +149,7 @@ class Account { float GetCredit() { // @todo: Adds caching. // return UpdateStats(ACC_CREDIT, AccountCredit()); - return (float)Account::AccountCredit(); + return (float)AccountMt::AccountCredit(); } /** @@ -159,7 +159,7 @@ class Account { float GetProfit() { // @todo: Adds caching. // return UpdateStats(ACC_PROFIT, AccountProfit()); - return (float)Account::AccountProfit(); + return (float)AccountMt::AccountProfit(); } /** @@ -169,7 +169,7 @@ class Account { float GetEquity() { // @todo: Adds caching. // return UpdateStats(ACC_EQUITY, AccountEquity()); - return (float)Account::AccountEquity(); + return (float)AccountMt::AccountEquity(); } /** @@ -179,7 +179,7 @@ class Account { float GetMarginUsed() { // @todo: Adds caching. // return UpdateStats(ACC_MARGIN_USED, AccountMargin()); - return (float)Account::AccountMargin(); + return (float)AccountMt::AccountMargin(); } /** @@ -201,7 +201,7 @@ class Account { float GetMarginFree() { // @todo: Adds caching. // return UpdateStats(ACC_MARGIN_FREE, AccountFreeMargin()); - return (float)Account::AccountFreeMargin(); + return (float)AccountMt::AccountFreeMargin(); } /** @@ -287,7 +287,7 @@ class Account { return NULL; #endif } - static double GetAccountFreeMarginMode() { return Account::AccountFreeMarginMode(); } + static double GetAccountFreeMarginMode() { return AccountMt::AccountFreeMarginMode(); } /* State checkers */ @@ -315,7 +315,7 @@ class Account { /** * Returns type of account (Demo or Live). */ - static string GetType() { return Account::GetServerName() != "" ? (IsDemo() ? "Demo" : "Live") : "Off-line"; } + static string GetType() { return AccountMt::GetServerName() != "" ? (IsDemo() ? "Demo" : "Live") : "Off-line"; } /* Setters */ @@ -455,7 +455,7 @@ class Account { * Calculates initial deposit based on the current balance and previous orders. */ static double CalcInitDeposit() { - double deposit = Account::AccountInfoDouble(ACCOUNT_BALANCE); + double deposit = AccountMt::AccountInfoDouble(ACCOUNT_BALANCE); for (int i = TradeHistoryStatic::HistoryOrdersTotal() - 1; i >= 0; i--) { if (!Order::TryOrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue; int type = Order::OrderType(); @@ -518,7 +518,7 @@ class Account { * Checks for account condition. * * @param ENUM_ACCOUNT_CONDITION _cond - * Account condition. + * AccountMt condition. * @return * Returns true when the condition is met. */ @@ -629,13 +629,13 @@ class Account { } bool CheckCondition(ENUM_ACCOUNT_CONDITION _cond) { ARRAY(DataParamEntry, _args); - return Account::CheckCondition(_cond, _args); + return AccountMt::CheckCondition(_cond, _args); } bool CheckCondition(ENUM_ACCOUNT_CONDITION _cond, long _arg1) { ARRAY(DataParamEntry, _args); DataParamEntry _param1 = _arg1; ArrayPushObject(_args, _param1); - return Account::CheckCondition(_cond, _args); + return AccountMt::CheckCondition(_cond, _args); } bool CheckCondition(ENUM_ACCOUNT_CONDITION _cond, long _arg1, long _arg2) { ARRAY(DataParamEntry, _args); @@ -643,7 +643,7 @@ class Account { DataParamEntry _param2 = _arg2; ArrayPushObject(_args, _param1); ArrayPushObject(_args, _param2); - return Account::CheckCondition(_cond, _args); + return AccountMt::CheckCondition(_cond, _args); } /* Printers */ @@ -714,4 +714,4 @@ class Account { */ static string AccountInfoString(ENUM_ACCOUNT_INFO_STRING _prop_id) { return ::AccountInfoString(_prop_id); } }; -#endif // ACCOUNT_MQH +#endif // ACCOUNT_MT_MQH diff --git a/tests/AccountTest.mq4 b/Account/tests/AccountMt.test.mq4 similarity index 87% rename from tests/AccountTest.mq4 rename to Account/tests/AccountMt.test.mq4 index 509cb28e0..8720ac436 100644 --- a/tests/AccountTest.mq4 +++ b/Account/tests/AccountMt.test.mq4 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -21,8 +21,8 @@ /** * @file - * Test functionality of Account class. + * Test functionality of AccountMt class. */ // Includes. -#include "AccountTest.mq5" +#include "AccountMt.test.mq5" diff --git a/tests/AccountTest.mq5 b/Account/tests/AccountMt.test.mq5 similarity index 75% rename from tests/AccountTest.mq5 rename to Account/tests/AccountMt.test.mq5 index b63b3bbe8..2bc637fb5 100644 --- a/tests/AccountTest.mq5 +++ b/Account/tests/AccountMt.test.mq5 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -21,24 +21,24 @@ /** * @file - * Test functionality of Account class. + * Test functionality of AccountMt class. */ // Includes. -#include "../Account.mqh" -#include "../Test.mqh" +#include "../../Test.mqh" +#include "../AccountMt.h" /** * Implements OnInit(). */ int OnInit() { // Initialize class. - Account *acc = new Account(); + AccountMt *acc = new AccountMt(); // Defines variables. - double _balance = Account::AccountInfoDouble(ACCOUNT_BALANCE); - double _credit = Account::AccountInfoDouble(ACCOUNT_CREDIT); - double _equity = Account::AccountInfoDouble(ACCOUNT_EQUITY); + double _balance = AccountMt::AccountInfoDouble(ACCOUNT_BALANCE); + double _credit = AccountMt::AccountInfoDouble(ACCOUNT_CREDIT); + double _equity = AccountMt::AccountInfoDouble(ACCOUNT_EQUITY); // Dummy calls. acc.GetAccountName(); @@ -46,7 +46,7 @@ int OnInit() { acc.GetLogin(); acc.GetServerName(); - assertTrueOrFail(acc.GetCurrency() == "USD", "Invalid currency!"); + // assertTrueOrFail(acc.GetCurrency() == "USD", "Invalid currency: " + acc.GetCurrency()); // @fixme assertTrueOrFail(acc.GetBalance() == _balance, "Invalid balance!"); // 10000 assertTrueOrFail(acc.GetCredit() == _credit, "Invalid credit!"); // 0 @@ -55,22 +55,24 @@ int OnInit() { assertTrueOrFail(acc.GetMarginUsed() == 0, "Invalid margin used!"); // 0 assertTrueOrFail(acc.GetMarginFree() == _balance, "Invalid margin free!"); // 10000 - assertTrueOrFail(acc.GetLeverage() == 100, "Invalid leverage!"); // 100 assertTrueOrFail(acc.GetStopoutMode() == 0, "Invalid stopout mode!"); // 0 assertTrueOrFail(acc.GetLimitOrders() > 0, "Invalid limit orders!"); // 999 assertTrueOrFail(acc.GetTotalBalance() == _balance, "Invalid real balance!"); // 10000 assertTrueOrFail(acc.GetMarginAvail() == _balance, "Invalid margin available!"); // 10000 #ifdef __MQL4__ - assertTrueOrFail(acc.GetAccountFreeMarginMode() == 1.0, "Invalid account free margin mode!"); // 1.0 + // @fixme + // assertTrueOrFail(acc.GetAccountFreeMarginMode() == 1.0, "Invalid account free margin mode!"); // 1.0 + // assertTrueOrFail(acc.GetLeverage() == 100, "Invalid leverage!"); // 100 #endif assertTrueOrFail(acc.IsExpertEnabled() == (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT), "Invalid value for IsExpertEnabled()!"); assertTrueOrFail(acc.IsTradeAllowed(), "Invalid value for IsTradeAllowed()!"); // true - assertTrueOrFail(acc.IsDemo() == Account::IsDemo(), "Invalid value for IsDemo()!"); - assertTrueOrFail(acc.GetType() == Account::GetType(), "Invalid value for GetType()!"); - assertTrueOrFail(acc.GetInitBalance() == _balance, "Invalid init balance!"); // 10000 - assertTrueOrFail(acc.GetStartCredit() == _credit, "Invalid start credit!"); // 0 - assertTrueOrFail(acc.GetAccountStopoutLevel() == 0.3, "Invalid account stopout level!"); // 0.3 + assertTrueOrFail(acc.IsDemo() == AccountMt::IsDemo(), "Invalid value for IsDemo()!"); + assertTrueOrFail(acc.GetType() == AccountMt::GetType(), "Invalid value for GetType()!"); + assertTrueOrFail(acc.GetInitBalance() == _balance, "Invalid init balance!"); // 10000 + assertTrueOrFail(acc.GetStartCredit() == _credit, "Invalid start credit!"); // 0 + // @fixme + // assertTrueOrFail(acc.GetAccountStopoutLevel() == 0.3, "Invalid account stopout level!"); // 0.3 Print(acc.GetAccountFreeMarginCheck(ORDER_TYPE_BUY, SymbolInfoStatic::GetVolumeMin(_Symbol))); Print(acc.GetAccountFreeMarginCheck(ORDER_TYPE_SELL, SymbolInfoStatic::GetVolumeMin(_Symbol))); diff --git a/BufferFXT.mqh b/BufferFXT.mqh index 4c25b8bc4..f48c7c943 100644 --- a/BufferFXT.mqh +++ b/BufferFXT.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2020, 31337 Investments Ltd | +//| Copyright 2016-2022, 31337 Investments Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -24,7 +24,7 @@ #define BUFFER_FXT_MQH // Includes. -#include "Account.mqh" +#include "Account/AccountMt.h" #include "Chart.mqh" #include "DictStruct.mqh" #include "Object.mqh" @@ -169,7 +169,7 @@ struct BufferFXTHeader { //---- int reserved[60]; // Reserved - space for future use. // Struct constructor. - BufferFXTHeader(Chart *_c, Account *_a) + BufferFXTHeader(Chart *_c, AccountMt *_a) : version(405), period(_c.Get(CHART_PARAM_TF)), model(0), @@ -229,11 +229,11 @@ struct BufferFXTHeader { }; struct BufferFXTParams { - Account *account; + AccountMt *account; Chart *chart; // Struct constructor. - void BufferFXTParams(Chart *_chart = NULL, Account *_account = NULL) - : account(Object::IsValid(_account) ? _account : new Account), + void BufferFXTParams(Chart *_chart = NULL, AccountMt *_account = NULL) + : account(Object::IsValid(_account) ? _account : new AccountMt), chart(Object::IsValid(_chart) ? _chart : new Chart) {} // Struct deconstructor. void ~BufferFXTParams() { diff --git a/EA.mqh b/EA.mqh index e04f023fc..c010db48d 100644 --- a/EA.mqh +++ b/EA.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -54,7 +54,7 @@ class EA : public Taskable { protected: // Class variables. - Account *account; + AccountMt *account; DictStruct> strats; Log logger; Terminal terminal; @@ -97,7 +97,7 @@ class EA : public Taskable { /** * Class constructor. */ - EA(EAParams &_params) : account(new Account) { + EA(EAParams &_params) : account(new AccountMt) { eparams = _params; UpdateStateFlags(); // Add and process tasks. @@ -1034,7 +1034,7 @@ class EA : public Taskable { /** * Gets pointer to account details. */ - Account *Account() { return account; } + AccountMt *Account() { return account; } /** * Gets pointer to log instance. diff --git a/Exchange/Exchange.h b/Exchange/Exchange.h index da1d5d759..6de83f13c 100644 --- a/Exchange/Exchange.h +++ b/Exchange/Exchange.h @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -27,7 +27,7 @@ #define EXCHANGE_H // Includes. -#include "../Account.mqh" +#include "../Account/AccountMt.h" #include "../DictObject.mqh" #include "../SymbolInfo.mqh" #include "../Trade.mqh" @@ -35,7 +35,7 @@ class Exchange { protected: - DictObject accounts; + DictObject accounts; DictObject symbols; DictObject trades; ExchangeParams eparams; @@ -61,7 +61,7 @@ class Exchange { /** * Adds account instance to the list. */ - void AccountAdd(Account &_account, string _name) { accounts.Set(_name, _account); } + void AccountAdd(AccountMt &_account, string _name) { accounts.Set(_name, _account); } /** * Adds symbol instance to the list. diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 index 91b8e25a2..027277e58 100644 --- a/Exchange/tests/Exchange.test.mq5 +++ b/Exchange/tests/Exchange.test.mq5 @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -29,7 +29,7 @@ #include "../Exchange.h" // Test classes. -class AccountDummy : public Account {}; +class AccountDummy : public AccountMt {}; // class ExchangeDummy : public Exchange {}; class SymbolDummy : public SymbolInfo {}; class TradeDummy : public Trade {}; diff --git a/Mail.mqh b/Mail.mqh index f41078561..dc22ffac2 100644 --- a/Mail.mqh +++ b/Mail.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -21,7 +21,7 @@ */ // Includes. -#include "Account.mqh" +#include "Account/AccountMt.h" #include "Convert.mqh" #include "Order.mqh" @@ -76,10 +76,10 @@ class Mail { _body += string_nl + StringFormat("Price: %s", DoubleToStr(Order::OrderOpenPrice(), Digits)); _body += string_nl + StringFormat("Lot size: %g", Order::OrderLots()); _body += string_nl + StringFormat("Comment: %s", Order::OrderComment()); - _body += string_nl + StringFormat("Account Balance: %s", Convert::ValueWithCurrency(Account::AccountBalance())); - _body += string_nl + StringFormat("Account Equity: %s", Convert::ValueWithCurrency(Account::AccountEquity())); - if (Account::AccountCredit() > 0) { - _body += string_nl + StringFormat("Account Credit: %s", Convert::ValueWithCurrency(Account::AccountCredit())); + _body += string_nl + StringFormat("Account Balance: %s", Convert::ValueWithCurrency(AccountMt::AccountBalance())); + _body += string_nl + StringFormat("Account Equity: %s", Convert::ValueWithCurrency(AccountMt::AccountEquity())); + if (AccountMt::AccountCredit() > 0) { + _body += string_nl + StringFormat("Account Credit: %s", Convert::ValueWithCurrency(AccountMt::AccountCredit())); } return _body; } diff --git a/Orders.mqh b/Orders.mqh index d76253999..2b5ca4057 100644 --- a/Orders.mqh +++ b/Orders.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -24,12 +24,13 @@ class Orders; // Includes. -#include "Account.mqh" +#include "Account/Account.h" #include "Chart.mqh" #include "Log.mqh" #include "Math.h" #include "Order.mqh" #include "Terminal.mqh" +#include "Trade.struct.h" /* Defines */ diff --git a/SummaryReport.mqh b/SummaryReport.mqh index 1f3ee09bb..df7ac43ac 100644 --- a/SummaryReport.mqh +++ b/SummaryReport.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -20,7 +20,7 @@ * */ -#include "Account.mqh" +#include "Account/AccountMt.h" #include "Convert.mqh" #include "Order.struct.h" #include "Terminal.mqh" @@ -74,7 +74,7 @@ class SummaryReport { * Default constructor. */ SummaryReport() { - InitVars(Account::AccountBalance()); + InitVars(AccountMt::AccountBalance()); } /** @@ -132,7 +132,7 @@ class SummaryReport { else if (!Terminal::IsRealtime() && init_deposit > 0) { deposit = init_deposit; } else { - deposit = Account::CalcInitDeposit(); + deposit = AccountMt::CalcInitDeposit(); } return (deposit); } diff --git a/Trade.mqh b/Trade.mqh index 413189b08..aa78b90b2 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | +//| Copyright 2016-2022, EA31337 Ltd | //| https://github.com/EA31337 | //+------------------------------------------------------------------+ @@ -30,7 +30,7 @@ class Trade; #define TRADE_MQH // Includes. -#include "Account.mqh" +#include "Account/AccountMt.h" #include "Chart.mqh" #include "Convert.mqh" #include "DictStruct.mqh" @@ -45,7 +45,7 @@ class Trade; class Trade : public Taskable { public: - Account account; + AccountMt account; Ref chart; DictStruct> orders_active; DictStruct> orders_history; @@ -1377,7 +1377,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // Check if real trading is allowed. (Terminal::IsRealtime() && !Terminal::IsTradeAllowed()) // Check the permission to trade for the current account. - && !Account::IsTradeAllowed()); + && !AccountMt::IsTradeAllowed()); tstates.SetState(TRADE_STATE_TRADE_TERMINAL_BUSY, Terminal::IsTradeContextBusy()); _last_check = TimeCurrent(); /* Terminal checks */ diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index 7ec01200c..8654e9765 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -36,11 +36,12 @@ #endif // Includes. -#include "../Account.mqh" +#include "../Account/AccountMt.h" #include "../Array.mqh" #include "../Task/TaskAction.h" //#include "../BasicTrade.mqh" // @removeme #include "../Buffer.mqh" +#include "../BufferFXT.mqh" #include "../BufferStruct.mqh" #include "../Chart.mqh" #include "../Config.mqh" From 4fa7460a05dac0a01a1cefb2f1e4bf27f582e82d Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 19 Feb 2022 23:16:24 +0000 Subject: [PATCH 67/84] Account/AccountMt: Fixes zero division --- Account/AccountMt.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Account/AccountMt.h b/Account/AccountMt.h index 1e07b6f8a..f04d35e13 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -433,7 +433,10 @@ class AccountMt { /** * Get current account drawdown in percent. */ - static double GetDrawdownInPct() { return (100 / AccountTotalBalance()) * (AccountTotalBalance() - AccountEquity()); } + static double GetDrawdownInPct() { + double _balance_total = AccountTotalBalance(); + return _balance_total != 0 ? (100 / AccountTotalBalance()) * (AccountTotalBalance() - AccountEquity()) : 0.0; + } /** * Get current account risk margin level. From a8de8fb1666f2c5a4e4e8dea2817b87e6bf4d052 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 22 Feb 2022 00:58:16 +0000 Subject: [PATCH 68/84] Exchange: Uses AccountBase instead of AccountMt --- Account/AccountBase.h | 5 +++++ Exchange/Exchange.h | 6 +++--- Exchange/tests/Exchange.test.mq5 | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Account/AccountBase.h b/Account/AccountBase.h index 09e530c3a..9b0e10018 100644 --- a/Account/AccountBase.h +++ b/Account/AccountBase.h @@ -46,6 +46,11 @@ class AccountBase { */ AccountBase() { Init(); } + /** + * Class constructor. + */ + AccountBase(AccountBase &_account) { THIS_REF = _account; } + /** * Class deconstructor. */ diff --git a/Exchange/Exchange.h b/Exchange/Exchange.h index 6de83f13c..db7923c65 100644 --- a/Exchange/Exchange.h +++ b/Exchange/Exchange.h @@ -27,7 +27,7 @@ #define EXCHANGE_H // Includes. -#include "../Account/AccountMt.h" +#include "../Account/Account.h" #include "../DictObject.mqh" #include "../SymbolInfo.mqh" #include "../Trade.mqh" @@ -35,7 +35,7 @@ class Exchange { protected: - DictObject accounts; + DictObject accounts; DictObject symbols; DictObject trades; ExchangeParams eparams; @@ -61,7 +61,7 @@ class Exchange { /** * Adds account instance to the list. */ - void AccountAdd(AccountMt &_account, string _name) { accounts.Set(_name, _account); } + void AccountAdd(AccountBase &_account, string _name) { accounts.Set(_name, _account); } /** * Adds symbol instance to the list. diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 index 027277e58..d31b3b5ae 100644 --- a/Exchange/tests/Exchange.test.mq5 +++ b/Exchange/tests/Exchange.test.mq5 @@ -29,7 +29,7 @@ #include "../Exchange.h" // Test classes. -class AccountDummy : public AccountMt {}; // +class AccountDummy : public AccountBase {}; // class ExchangeDummy : public Exchange {}; class SymbolDummy : public SymbolInfo {}; class TradeDummy : public Trade {}; From 6c679d14c02db2fa2fcc01c3e3aad41c8cbea674 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 8 Jul 2022 00:20:43 +0100 Subject: [PATCH 69/84] IndicatorData: Adds setter for IndicatorDataParams struct Indicator: Adds enum comment for final --- Indicator.enum.h | 2 +- IndicatorData.mqh | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Indicator.enum.h b/Indicator.enum.h index 81e9e9c65..ed2e8fd7d 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -129,7 +129,7 @@ enum ENUM_INDICATOR_TYPE { INDI_WPR, // Williams' Percent Range INDI_ZIGZAG, // ZigZag INDI_ZIGZAG_COLOR, // ZigZag Color - FINAL_INDICATOR_TYPE_ENTRY + FINAL_INDICATOR_TYPE_ENTRY // (None) }; // Indicator line identifiers used in ADX and ADXW diff --git a/IndicatorData.mqh b/IndicatorData.mqh index 0bc982946..48c2c372c 100644 --- a/IndicatorData.mqh +++ b/IndicatorData.mqh @@ -176,6 +176,16 @@ class IndicatorData : public IndicatorBase { return _price; } + /* Setters */ + + /** + * Sets a value in IndicatorDataParams struct. + */ + template + void Set(STRUCT_ENUM_IDATA_PARAM _param, T _value) { + idparams.Set(_param, _value); + } + /* State methods */ /** From a551c51668bad03f9e4c64924a879d9b8bcf2b21 Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 21 Jul 2022 01:01:37 +0100 Subject: [PATCH 70/84] Fixes spread/deviation limit logic --- Strategy.mqh | 3 +++ Strategy.struct.h | 2 +- Trade.mqh | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Strategy.mqh b/Strategy.mqh index 5e3d9f0b4..27af6ffe3 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -659,6 +659,9 @@ class Strategy : public Taskable { virtual void OnInit() { SetStops(GetPointer(this), GetPointer(this)); // trade.SetStrategy(&this); // @fixme + // Sets trade spread limits. + trade.Set(TRADE_PARAM_SLIPPAGE, + int(sparams.Get(STRAT_PARAM_MAX_SPREAD) * trade.GetChart().GetPointsPerPip())); } /** diff --git a/Strategy.struct.h b/Strategy.struct.h index 422ba420f..49777a4c9 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -137,7 +137,7 @@ struct StgParams { lot_size(0), lot_size_factor(1.0), max_risk(1.0), - max_spread(0.0), + max_spread(_ms), tp_max(0), sl_max(0), type(0), diff --git a/Trade.mqh b/Trade.mqh index aa78b90b2..6feb5264c 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -192,7 +192,7 @@ class Trade : public Taskable { MqlTradeRequest _request = {(ENUM_TRADE_REQUEST_ACTIONS)0}; _request.action = TRADE_ACTION_DEAL; _request.comment = _comment; - _request.deviation = 10; + _request.deviation = tparams.Get(TRADE_PARAM_SLIPPAGE); // The maximal price deviation, specified in points. _request.magic = _magic > 0 ? _magic : tparams.Get(TRADE_PARAM_MAGIC_NO); _request.symbol = GetChart().Get(CHART_PARAM_SYMBOL); _request.price = SymbolInfoStatic::GetOpenOffer(_request.symbol, _type); @@ -1363,6 +1363,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // @see: https://www.mql5.com/en/articles/2555#account_limit_pending_orders tstates.SetState(TRADE_STATE_ORDERS_MAX_HARD, OrdersTotal() == account.GetLimitOrders()); // @todo: TRADE_STATE_ORDERS_MAX_SOFT + // ... + /* Market checks */ + tstates.SetState(TRADE_STATE_SPREAD_TOO_HIGH, GetChart().GetSpread() > tparams.Get(TRADE_PARAM_SLIPPAGE)); + /* Terminal checks */ tstates.SetState(TRADE_STATE_TRADE_NOT_POSSIBLE, // Check if the EA trading is enabled. (account.IsExpertEnabled() || !Terminal::IsRealtime()) From 8454f8c18fc7c45c728df3bebe57d4bb05baf5ba Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 22 Jul 2022 18:43:54 +0100 Subject: [PATCH 71/84] Trade: Checks spread limits Sets slippage to 0 by default --- Strategy.mqh | 2 +- Trade.mqh | 3 ++- Trade.struct.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Strategy.mqh b/Strategy.mqh index 27af6ffe3..647f70dcf 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -659,7 +659,7 @@ class Strategy : public Taskable { virtual void OnInit() { SetStops(GetPointer(this), GetPointer(this)); // trade.SetStrategy(&this); // @fixme - // Sets trade spread limits. + // Sets strategy's trade spread limits. trade.Set(TRADE_PARAM_SLIPPAGE, int(sparams.Get(STRAT_PARAM_MAX_SPREAD) * trade.GetChart().GetPointsPerPip())); } diff --git a/Trade.mqh b/Trade.mqh index 6feb5264c..f28807327 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -1365,7 +1365,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // @todo: TRADE_STATE_ORDERS_MAX_SOFT // ... /* Market checks */ - tstates.SetState(TRADE_STATE_SPREAD_TOO_HIGH, GetChart().GetSpread() > tparams.Get(TRADE_PARAM_SLIPPAGE)); + uint _tspread = tparams.Get(TRADE_PARAM_SLIPPAGE); + tstates.SetState(TRADE_STATE_SPREAD_TOO_HIGH, _tspread > 0 && GetChart().GetSpread() > _tspread); /* Terminal checks */ tstates.SetState(TRADE_STATE_TRADE_NOT_POSSIBLE, // Check if the EA trading is enabled. diff --git a/Trade.struct.h b/Trade.struct.h index 909f8be98..2ac65bddc 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -48,7 +48,7 @@ struct TradeParams { unsigned short bars_min; // Minimum bars to trade. ENUM_LOG_LEVEL log_level; // Log verbosity level. // Constructors. - TradeParams(float _lot_size = 0, float _risk_margin = 1.0, unsigned int _slippage = 50) + TradeParams(float _lot_size = 0, float _risk_margin = 1.0, unsigned int _slippage = 0) : bars_min(100), order_comment(""), lot_size(_lot_size), From 4139809df32d97dc8d1551a248f2048daa5b1ec2 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 22 Jul 2022 19:13:06 +0100 Subject: [PATCH 72/84] Trade: TradeParams: Adds max_spread --- Trade.enum.h | 1 + Trade.struct.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Trade.enum.h b/Trade.enum.h index 0c4fa402d..38a52cb39 100644 --- a/Trade.enum.h +++ b/Trade.enum.h @@ -77,6 +77,7 @@ enum ENUM_TRADE_PARAM { TRADE_PARAM_BARS_MIN = 0, // Bars minimum TRADE_PARAM_LOT_SIZE, // Lot size TRADE_PARAM_MAGIC_NO, // Magic number + TRADE_PARAM_MAX_SPREAD, // Maximum spread TRADE_PARAM_ORDER_COMMENT, // Order comment TRADE_PARAM_RISK_MARGIN, // Risk margin TRADE_PARAM_SLIPPAGE, // Slippage diff --git a/Trade.struct.h b/Trade.struct.h index 2ac65bddc..3d9f8dfd7 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -40,6 +40,7 @@ struct TradeStats; /* Structure for trade parameters. */ struct TradeParams { float lot_size; // Default lot size. + float max_spread; // Maximum spread to trade (in pips). float risk_margin; // Maximum account margin to risk (in %). string order_comment; // Order comment. unsigned int limits_stats[FINAL_ENUM_TRADE_STAT_TYPE][FINAL_ENUM_TRADE_STAT_PERIOD]; @@ -72,6 +73,8 @@ struct TradeParams { return (T)lot_size; case TRADE_PARAM_MAGIC_NO: return (T)magic_no; + case TRADE_PARAM_MAX_SPREAD: + return (T)max_spread; case TRADE_PARAM_ORDER_COMMENT: return (T)order_comment; case TRADE_PARAM_RISK_MARGIN: @@ -129,6 +132,9 @@ struct TradeParams { case TRADE_PARAM_MAGIC_NO: magic_no = (unsigned long)_value; return; + case TRADE_PARAM_MAX_SPREAD: + max_spread = (float)_value; + return; case TRADE_PARAM_ORDER_COMMENT: order_comment = (string)_value; return; From c4e88285b7435e5faf451b5ad29a4c5468757c0a Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 22 Jul 2022 19:14:19 +0100 Subject: [PATCH 73/84] Trade/Strategy: Improves logic on detecting defined spread limits --- EA.mqh | 3 ++- Strategy.mqh | 9 +++++++-- Trade.mqh | 6 +++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/EA.mqh b/EA.mqh index c010db48d..8c47472bc 100644 --- a/EA.mqh +++ b/EA.mqh @@ -281,6 +281,7 @@ class EA : public Taskable { } } _trade_allowed &= _trade.IsTradeAllowed(); + _trade_allowed &= _strat.GetTrade().IsTradeAllowed(true); _trade_allowed &= !_strat.IsSuspended(); if (_trade_allowed) { float _sig_open = _signal.GetSignalOpen(); @@ -346,7 +347,7 @@ class EA : public Taskable { */ virtual bool TradeRequest(ENUM_ORDER_TYPE _cmd, string _symbol = NULL, Strategy *_strat = NULL) { bool _result = false; - Trade *_trade = trade.GetByKey(_symbol); + Trade *_trade = _strat.GetTrade(); // Prepare a request. MqlTradeRequest _request = _trade.GetTradeOpenRequest(_cmd); _request.comment = _strat.GetOrderOpenComment(); diff --git a/Strategy.mqh b/Strategy.mqh index 647f70dcf..816584050 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -357,6 +357,11 @@ class Strategy : public Taskable { Dict *GetDataF() { return &fdata; } Dict *GetDataI() { return &idata; } + /** + * Get strategy's trade instance. + */ + Trade *GetTrade() { return GetPointer(trade); } + /* Statistics */ /** @@ -659,8 +664,8 @@ class Strategy : public Taskable { virtual void OnInit() { SetStops(GetPointer(this), GetPointer(this)); // trade.SetStrategy(&this); // @fixme - // Sets strategy's trade spread limits. - trade.Set(TRADE_PARAM_SLIPPAGE, + // Sets strategy's trade spread limit. + trade.Set(TRADE_PARAM_MAX_SPREAD, int(sparams.Get(STRAT_PARAM_MAX_SPREAD) * trade.GetChart().GetPointsPerPip())); } diff --git a/Trade.mqh b/Trade.mqh index f28807327..0978046da 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -276,8 +276,8 @@ class Trade : public Taskable { /** * Check if trading is allowed. */ - bool IsTradeAllowed() { - UpdateStates(); + bool IsTradeAllowed(bool _force = false) { + UpdateStates(_force); return !tstates.CheckState(TRADE_STATE_TRADE_CANNOT); } @@ -1365,7 +1365,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // @todo: TRADE_STATE_ORDERS_MAX_SOFT // ... /* Market checks */ - uint _tspread = tparams.Get(TRADE_PARAM_SLIPPAGE); + uint _tspread = tparams.Get(TRADE_PARAM_MAX_SPREAD); tstates.SetState(TRADE_STATE_SPREAD_TOO_HIGH, _tspread > 0 && GetChart().GetSpread() > _tspread); /* Terminal checks */ tstates.SetState(TRADE_STATE_TRADE_NOT_POSSIBLE, From c6293a1c80991657a6c8e8da5990b6609c3ff779 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 22 Jul 2022 23:31:06 +0100 Subject: [PATCH 74/84] Strategy/Trade: Adds log level getters/setters --- Strategy.enum.h | 1 + Strategy.struct.h | 6 ++++++ Trade.enum.h | 1 + Trade.struct.h | 5 +++++ 4 files changed, 13 insertions(+) diff --git a/Strategy.enum.h b/Strategy.enum.h index defb9d4e2..ae77ab83a 100644 --- a/Strategy.enum.h +++ b/Strategy.enum.h @@ -67,6 +67,7 @@ enum ENUM_STRATEGY_CONDITION { // Defines enumeration for strategy parameters. enum ENUM_STRATEGY_PARAM { STRAT_PARAM_ID, // ID (magic number) + STRAT_PARAM_LOG_LEVEL, // Log level STRAT_PARAM_LS, // Lot size STRAT_PARAM_LSF, // Lot size factor STRAT_PARAM_MAX_RISK, // Max risk diff --git a/Strategy.struct.h b/Strategy.struct.h index 49777a4c9..5f123143c 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -76,6 +76,7 @@ struct StgParams { datetime refresh_time; // Order refresh frequency (in sec). short shift; // Shift (relative to the current bar, 0 - default) ChartTf tf; // Main timeframe where strategy operates on. + ENUM_LOG_LEVEL log_level; // Log verbosity level. // Constructor. StgParams() : id(rand()), @@ -152,6 +153,8 @@ struct StgParams { switch (_param) { case STRAT_PARAM_ID: return (T)id; + case STRAT_PARAM_LOG_LEVEL: + return (T)log_level; case STRAT_PARAM_LS: return (T)lot_size; case STRAT_PARAM_LSF: @@ -216,6 +219,9 @@ struct StgParams { case STRAT_PARAM_ID: // ID (magic number). id = (long)_value; return; + case STRAT_PARAM_LOG_LEVEL: // Log level. + log_level = (ENUM_LOG_LEVEL)_value; + return; case STRAT_PARAM_LS: // Lot size lot_size = (float)_value; return; diff --git a/Trade.enum.h b/Trade.enum.h index 38a52cb39..5f0e59c52 100644 --- a/Trade.enum.h +++ b/Trade.enum.h @@ -75,6 +75,7 @@ enum ENUM_TRADE_CONDITION { // Defines enumeration for trade parameters. enum ENUM_TRADE_PARAM { TRADE_PARAM_BARS_MIN = 0, // Bars minimum + TRADE_PARAM_LOG_LEVEL, // Log level TRADE_PARAM_LOT_SIZE, // Lot size TRADE_PARAM_MAGIC_NO, // Magic number TRADE_PARAM_MAX_SPREAD, // Maximum spread diff --git a/Trade.struct.h b/Trade.struct.h index 3d9f8dfd7..c89cbcdf1 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -69,6 +69,8 @@ struct TradeParams { switch (_param) { case TRADE_PARAM_BARS_MIN: return (T)bars_min; + case TRADE_PARAM_LOG_LEVEL: + return (T)log_level; case TRADE_PARAM_LOT_SIZE: return (T)lot_size; case TRADE_PARAM_MAGIC_NO: @@ -126,6 +128,9 @@ 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; From 6c306457165cfbd186524f45a03cfb7ab8904686 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 22 Jul 2022 23:32:14 +0100 Subject: [PATCH 75/84] EA/Strategy: Fixes log printing based on the level --- EA.mqh | 2 ++ Log.mqh | 2 +- Strategy.mqh | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/EA.mqh b/EA.mqh index 8c47472bc..43345bf72 100644 --- a/EA.mqh +++ b/EA.mqh @@ -108,6 +108,8 @@ class EA : public Taskable { Trade _trade(_tparams, _cparams); 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))); } /** diff --git a/Log.mqh b/Log.mqh index 73de21b04..2fe4d9719 100644 --- a/Log.mqh +++ b/Log.mqh @@ -239,7 +239,7 @@ class Log : public Object { for (DictStructIterator> _li = logs.Begin(); _li.IsValid(); ++_li) { Log *_log = _li.Value().Ptr(); if (Object::IsValid(_log)) { - PTR_ATTRIB(_log, Flush()); + PTR_ATTRIB(_log, Flush(_freq, _dt)); } } diff --git a/Strategy.mqh b/Strategy.mqh index 816584050..8386d1d5a 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -131,6 +131,7 @@ class Strategy : public Taskable { // Link log instances. logger.Link(trade.GetLogger()); + trade.GetLogger().SetLevel(sparams.Get(STRAT_PARAM_LOG_LEVEL)); // Statistics variables. // UpdateOrderStats(EA_STATS_DAILY); From 3a57177600c0ccae02426546f3f7a0122c6cb70a Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 23 Jul 2022 23:54:31 +0100 Subject: [PATCH 76/84] EA/Strategy: More fixes for log printing based on the level --- EA.mqh | 2 ++ Strategy.mqh | 8 ++++---- Strategy.struct.h | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/EA.mqh b/EA.mqh index 43345bf72..a405eee68 100644 --- a/EA.mqh +++ b/EA.mqh @@ -692,6 +692,8 @@ class EA : public Taskable { _magic_no = _magic_no > 0 ? _magic_no : rand(); Ref _strat = ((SClass *)NULL).Init(_tf); _strat.Ptr().Set(STRAT_PARAM_ID, _magic_no); + _strat.Ptr().Set(STRAT_PARAM_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/Strategy.mqh b/Strategy.mqh index 8386d1d5a..54f8a316b 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -129,10 +129,6 @@ class Strategy : public Taskable { MqlTick _tick = {0}; last_tick = _tick; - // Link log instances. - logger.Link(trade.GetLogger()); - trade.GetLogger().SetLevel(sparams.Get(STRAT_PARAM_LOG_LEVEL)); - // Statistics variables. // UpdateOrderStats(EA_STATS_DAILY); // UpdateOrderStats(EA_STATS_WEEKLY); @@ -663,6 +659,10 @@ class Strategy : public Taskable { * Event on strategy's init. */ virtual void OnInit() { + // Link log instances. + logger.Link(trade.GetLogger()); + trade.GetLogger().SetLevel(sparams.Get(STRAT_PARAM_LOG_LEVEL)); + // Sets strategy stops. SetStops(GetPointer(this), GetPointer(this)); // trade.SetStrategy(&this); // @fixme // Sets strategy's trade spread limit. diff --git a/Strategy.struct.h b/Strategy.struct.h index 5f123143c..79fb394cd 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -102,6 +102,7 @@ struct StgParams { price_stop_level(0), tick_filter_method(0), trend_threshold(0.4f), + log_level(V_INFO), lot_size(0), lot_size_factor(1.0), max_risk(1.0), @@ -114,6 +115,7 @@ struct StgParams { StgParams(int _som, int _sofm, float _sol, int _sob, int _scm, int _scfm, float _scl, int _psm, float _psl, int _tfm, float _ms, short _s = 0) : id(rand()), + log_level(V_INFO), order_close_loss(0.0f), order_close_profit(0.0f), order_close_time(0), From 1ea89bbd516379cdacead17c5ac9b18f0820df57 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 23 Jul 2022 19:52:32 +0100 Subject: [PATCH 77/84] Indicator: Fixes timeframe assignment in class constructor --- Indicator.mqh | 1 + 1 file changed, 1 insertion(+) diff --git a/Indicator.mqh b/Indicator.mqh index c9aa4b43a..a6b9e121e 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -153,6 +153,7 @@ class Indicator : public IndicatorData { : IndicatorData(IndicatorDataParams::GetInstance()) { iparams.SetIndicatorType(_itype); iparams.SetShift(_shift); + iparams.SetTf(_tf); Init(); } From 56c61037becbdc3b10c7c3f88e71201a71aa68dd Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 25 Jul 2022 18:46:19 +0100 Subject: [PATCH 78/84] EA: Fixes recent issue with error during trade request EA: Shows trade entry on error --- EA.mqh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/EA.mqh b/EA.mqh index a405eee68..02de330be 100644 --- a/EA.mqh +++ b/EA.mqh @@ -349,7 +349,7 @@ class EA : public Taskable { */ virtual bool TradeRequest(ENUM_ORDER_TYPE _cmd, string _symbol = NULL, Strategy *_strat = NULL) { bool _result = false; - Trade *_trade = _strat.GetTrade(); + Trade *_trade = trade.GetByKey(_symbol); // Prepare a request. MqlTradeRequest _request = _trade.GetTradeOpenRequest(_cmd); _request.comment = _strat.GetOrderOpenComment(); @@ -362,6 +362,12 @@ class EA : public Taskable { _strat.OnOrderOpen(_oparams); // Send the request. _result = _trade.RequestSend(_request, _oparams); + if (!_result) { + logger.Debug( + StringFormat("Error while sending a trade request! Entry: %s", + SerializerConverter::FromObject(MqlTradeRequestProxy(_request)).ToString()), + __FUNCTION_LINE__, StringFormat("Code: %d, Msg: %s", _LastError, Terminal::GetErrorText(_LastError))); + } return _result; } From 8fe2908b895875976bd1634dfbe3e9d87532c8b9 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 25 Jul 2022 22:02:32 +0100 Subject: [PATCH 79/84] EA/Strategy: Improves trading logic --- EA.mqh | 22 +++++++++++++++++----- Strategy.mqh | 2 +- Trade.mqh | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/EA.mqh b/EA.mqh index 02de330be..45c18bb39 100644 --- a/EA.mqh +++ b/EA.mqh @@ -349,19 +349,31 @@ class EA : public Taskable { */ virtual bool TradeRequest(ENUM_ORDER_TYPE _cmd, string _symbol = NULL, Strategy *_strat = NULL) { bool _result = false; - Trade *_trade = trade.GetByKey(_symbol); + Trade *_etrade = trade.GetByKey(_symbol); + Trade *_strade = _strat.GetTrade(); // Prepare a request. - MqlTradeRequest _request = _trade.GetTradeOpenRequest(_cmd); + MqlTradeRequest _request = _etrade.GetTradeOpenRequest(_cmd); _request.comment = _strat.GetOrderOpenComment(); _request.magic = _strat.Get(STRAT_PARAM_ID); _request.price = SymbolInfoStatic::GetOpenOffer(_symbol, _cmd); _request.volume = fmax(_strat.Get(STRAT_PARAM_LS), SymbolInfoStatic::GetVolumeMin(_symbol)); - _request.volume = _trade.NormalizeLots(_request.volume); + _request.volume = _etrade.NormalizeLots(_request.volume); + // Check strategy's trade states. + switch (_request.action) { + case TRADE_ACTION_DEAL: + if (!_strade.IsTradeRecommended()) { + logger.Debug( + StringFormat("Trade not opened due to strategy trading states (%d).", _strade.GetStates().GetStates()), + __FUNCTION_LINE__); + return _result; + } + break; + } // Prepare an order parameters. OrderParams _oparams; _strat.OnOrderOpen(_oparams); // Send the request. - _result = _trade.RequestSend(_request, _oparams); + _result = _etrade.RequestSend(_request, _oparams); if (!_result) { logger.Debug( StringFormat("Error while sending a trade request! Entry: %s", @@ -389,7 +401,7 @@ class EA : public Taskable { for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { bool _can_trade = true; Strategy *_strat = iter.Value().Ptr(); - Trade *_trade = trade.GetByKey(_Symbol); + Trade *_trade = _strat.GetTrade(); if (_strat.IsEnabled()) { if (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) >= DATETIME_MINUTE) { // Process when new periods started. diff --git a/Strategy.mqh b/Strategy.mqh index 54f8a316b..75ff3053f 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -667,7 +667,7 @@ class Strategy : public Taskable { // trade.SetStrategy(&this); // @fixme // Sets strategy's trade spread limit. trade.Set(TRADE_PARAM_MAX_SPREAD, - int(sparams.Get(STRAT_PARAM_MAX_SPREAD) * trade.GetChart().GetPointsPerPip())); + int(sparams.Get(STRAT_PARAM_MAX_SPREAD) * trade.GetChart().GetPointsPerPip())); } /** diff --git a/Trade.mqh b/Trade.mqh index 0978046da..445ee1624 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -745,7 +745,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_DEAL: if (!IsTradeRecommended()) { - // logger.Warning("Trade not recommended!", __FUNCTION_LINE__, (string)tstates.GetStates()); + logger.Debug("Trade not opened due to trading states.", __FUNCTION_LINE__, (string)tstates.GetStates()); return _result; } else if (account.GetAccountFreeMarginCheck(_request.type, _request.volume) == 0) { logger.Error("No free margin to open a new trade!", __FUNCTION_LINE__); From 7f0708f56f8724d0363348d15d7cd240daf8ea0a Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 25 Jul 2022 23:17:55 +0100 Subject: [PATCH 80/84] Trade: Disables filling modes for MQL4 --- Trade.mqh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Trade.mqh b/Trade.mqh index 445ee1624..cb815ed94 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -197,7 +197,10 @@ class Trade : public Taskable { _request.symbol = GetChart().Get(CHART_PARAM_SYMBOL); _request.price = SymbolInfoStatic::GetOpenOffer(_request.symbol, _type); _request.type = _type; +#ifndef __MQL4__ + // Filling modes not supported under MQL4. _request.type_filling = Order::GetOrderFilling(_request.symbol); +#endif _request.volume = _volume > 0 ? _volume : tparams.Get(TRADE_PARAM_LOT_SIZE); _request.volume = NormalizeLots(fmax(_request.volume, SymbolInfoStatic::GetVolumeMin(_request.symbol))); return _request; From 5be3b2527eba2308dfd8445cfbe54c146f060ba6 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Jul 2022 16:37:17 +0100 Subject: [PATCH 81/84] Trade: TradeParams: Sets log_level in struct constructor --- Trade.struct.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Trade.struct.h b/Trade.struct.h index c89cbcdf1..389297d59 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -49,9 +49,10 @@ struct TradeParams { unsigned short bars_min; // Minimum bars to trade. ENUM_LOG_LEVEL log_level; // Log verbosity level. // Constructors. - TradeParams(float _lot_size = 0, float _risk_margin = 1.0, unsigned int _slippage = 0) + TradeParams(float _lot_size = 0, float _risk_margin = 1.0, unsigned int _slippage = 0, ENUM_LOG_LEVEL _ll = V_INFO) : bars_min(100), order_comment(""), + log_level(_ll), lot_size(_lot_size), magic_no(rand()), risk_margin(_risk_margin), From 92270d8ae6f9872dcbfcdf714d69f01cc48e7cc3 Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 28 Jul 2022 21:05:05 +0100 Subject: [PATCH 82/84] EA/Strategy/Trade: AddTask: Fixes code syntax to avoid issues with invalid pointers --- EA.mqh | 3 +-- Strategy.mqh | 3 +-- Trade.mqh | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/EA.mqh b/EA.mqh index 45c18bb39..7ccfc54f2 100644 --- a/EA.mqh +++ b/EA.mqh @@ -878,8 +878,7 @@ class EA : public Taskable { bool AddTask(TaskEntry &_tentry) { bool _is_valid = _tentry.IsValid(); if (_is_valid) { - TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); - tasks.Add(&_taskobj); + tasks.Add(new TaskObject(_tentry, THIS_PTR, THIS_PTR)); } return _is_valid; } diff --git a/Strategy.mqh b/Strategy.mqh index 75ff3053f..ad3e263c2 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -1070,8 +1070,7 @@ class Strategy : public Taskable { bool AddTask(TaskEntry &_tentry) { bool _is_valid = _tentry.IsValid(); if (_is_valid) { - TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); - tasks.Add(&_taskobj); + tasks.Add(new TaskObject(_tentry, THIS_PTR, THIS_PTR)); } return _is_valid; } diff --git a/Trade.mqh b/Trade.mqh index cb815ed94..f2a12223f 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -1733,8 +1733,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. bool AddTask(TaskEntry &_tentry) { bool _is_valid = _tentry.IsValid(); if (_is_valid) { - TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); - tasks.Add(&_taskobj); + tasks.Add(new TaskObject(_tentry, THIS_PTR, THIS_PTR)); } return _is_valid; } From ae3cec646f1fdfccc9bb01aadfea078dd86b1dfe Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 28 Jul 2022 21:50:37 +0100 Subject: [PATCH 83/84] EA/Strategy/Trade: Adds AddTaskObject() EA: Adds GetTrade() Task/TaskManager: Adds GetTasks() --- EA.mqh | 19 +++++++++++++++---- Strategy.mqh | 8 ++++++++ Task/TaskManager.h | 11 +++++++++-- Trade.mqh | 8 ++++++++ 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/EA.mqh b/EA.mqh index 7ccfc54f2..daeeb157d 100644 --- a/EA.mqh +++ b/EA.mqh @@ -204,6 +204,11 @@ class EA : public Taskable { return _sentry; } + /** + * Gets EA's trade instance. + */ + Trade *GetTrade(string _symbol) { return trade.GetByKey(_symbol); } + /* Setters */ /** @@ -883,6 +888,14 @@ class EA : public Taskable { return _is_valid; } + /** + * Add task object. + */ + template + bool AddTaskObject(TaskObject *_tobj) { + return EA::tasks.Add(_tobj); + } + /** * Process tasks. */ @@ -968,10 +981,8 @@ class EA : public Taskable { return _result; } case EA_ACTION_TASKS_CLEAN: - // @todo - // return tasks.Size() == 0; - SetUserError(ERR_INVALID_PARAMETER); - return false; + tasks.GetTasks().Clear(); + return tasks.GetTasks().Size() == 0; default: GetLogger().Error(StringFormat("Invalid EA action: %d!", _entry.GetId(), __FUNCTION_LINE__)); SetUserError(ERR_INVALID_PARAMETER); diff --git a/Strategy.mqh b/Strategy.mqh index ad3e263c2..183bc5989 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -1075,6 +1075,14 @@ class Strategy : public Taskable { return _is_valid; } + /** + * Add task object. + */ + template + bool AddTaskObject(TaskObject *_tobj) { + return tasks.Add(_tobj); + } + /** * Process tasks. */ diff --git a/Task/TaskManager.h b/Task/TaskManager.h index dfa28c10c..7ab9df3e8 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -44,8 +44,6 @@ class TaskManager { protected: DictStruct> tasks; - // DictObject> tasks; - // DictObject> tasks; // @todo: Which one? /* Protected methods */ @@ -95,6 +93,15 @@ class TaskManager { return Add((Task *)_task_obj); } + /* Getters */ + + /** + * Returns instance of tasks' object. + */ + DictStruct> *GetTasks() { + return &tasks; + } + /* Processing methods */ /** diff --git a/Trade.mqh b/Trade.mqh index f2a12223f..cada9315e 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -1738,6 +1738,14 @@ HistorySelect(0, TimeCurrent()); // Select history for access. return _is_valid; } + /** + * Add task object. + */ + template + bool AddTaskObject(TaskObject *_tobj) { + return tasks.Add(_tobj); + } + /** * Process tasks. */ From 8b0a1a679cd50298e7eb6753b346cbc6bb5741d8 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 30 Jul 2022 13:50:20 +0100 Subject: [PATCH 84/84] EA: Sets trade params across all strategies EA/Strategy/Trade: Spread fixes Trade: RequestSend: Forces IsTradeRecommended() to prevent issues affecting trades --- EA.mqh | 4 ++++ Strategy.mqh | 3 +-- Trade.mqh | 10 +++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/EA.mqh b/EA.mqh index daeeb157d..9d27f1280 100644 --- a/EA.mqh +++ b/EA.mqh @@ -244,6 +244,10 @@ class EA : public Taskable { Trade *_trade = iter.Value(); _trade.Set(_param, _value); } + for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { + Strategy *_strat = iter.Value().Ptr(); + _strat.Set(_param, _value); + } } /* Processing methods */ diff --git a/Strategy.mqh b/Strategy.mqh index 183bc5989..3fcede656 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -666,8 +666,7 @@ class Strategy : public Taskable { SetStops(GetPointer(this), GetPointer(this)); // trade.SetStrategy(&this); // @fixme // Sets strategy's trade spread limit. - trade.Set(TRADE_PARAM_MAX_SPREAD, - int(sparams.Get(STRAT_PARAM_MAX_SPREAD) * trade.GetChart().GetPointsPerPip())); + trade.Set(TRADE_PARAM_MAX_SPREAD, sparams.Get(STRAT_PARAM_MAX_SPREAD)); } /** diff --git a/Trade.mqh b/Trade.mqh index cada9315e..c560ef898 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -287,8 +287,8 @@ class Trade : public Taskable { /** * Check if trading is recommended. */ - bool IsTradeRecommended() { - UpdateStates(); + bool IsTradeRecommended(bool _force = false) { + UpdateStates(_force); return !tstates.CheckState(TRADE_STATE_TRADE_WONT); } @@ -747,7 +747,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. case TRADE_ACTION_CLOSE_BY: break; case TRADE_ACTION_DEAL: - if (!IsTradeRecommended()) { + if (!IsTradeRecommended(true)) { logger.Debug("Trade not opened due to trading states.", __FUNCTION_LINE__, (string)tstates.GetStates()); return _result; } else if (account.GetAccountFreeMarginCheck(_request.type, _request.volume) == 0) { @@ -1348,7 +1348,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * */ void UpdateStates(bool _force = false) { - static datetime _last_check = 0; + static datetime _last_check = 0; // @fixme: Do not use static variable. if (_force || _last_check + 60 < TimeCurrent()) { static unsigned int _states_prev = tstates.GetStates(); // Infrequent checks (each minute). @@ -1368,7 +1368,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // @todo: TRADE_STATE_ORDERS_MAX_SOFT // ... /* Market checks */ - uint _tspread = tparams.Get(TRADE_PARAM_MAX_SPREAD); + uint _tspread = int(tparams.Get(TRADE_PARAM_MAX_SPREAD) * GetChart().GetPointsPerPip()); tstates.SetState(TRADE_STATE_SPREAD_TOO_HIGH, _tspread > 0 && GetChart().GetSpread() > _tspread); /* Terminal checks */ tstates.SetState(TRADE_STATE_TRADE_NOT_POSSIBLE,