diff --git a/Account/Account.h b/Account/Account.h index 5e50510d5..a42e5822c 100644 --- a/Account/Account.h +++ b/Account/Account.h @@ -56,4 +56,5 @@ class Account : public AccountBase { */ ~Account() {} }; + #endif // ACCOUNT_H diff --git a/Account/AccountBase.h b/Account/AccountBase.h index 9d3ae7253..187649570 100644 --- a/Account/AccountBase.h +++ b/Account/AccountBase.h @@ -56,6 +56,46 @@ class AccountBase : public Dynamic { * Class deconstructor. */ ~AccountBase() {} + + /** + * Returns balance value of the current account. + */ + virtual datetime GetDateTime() { return TimeCurrent(); }; + + /** + * Returns balance value of the current account. + */ + virtual float GetBalance() = 0; + + /** + * Returns credit value of the current account. + */ + virtual float GetCredit() = 0; + + /** + * Returns profit value of the current account. + */ + virtual float GetProfit() = 0; + + /** + * Returns equity value of the current account. + */ + virtual float GetEquity() = 0; + + /** + * Returns margin value of the current account. + */ + virtual float GetMarginUsed() = 0; + + /** + * Returns free margin value of the current account. + */ + virtual float GetMarginFree() = 0; + + /** + * Get account available margin. + */ + virtual float GetMarginAvail() = 0; }; #endif // ACCOUNTBASE_H diff --git a/Account/AccountMt.h b/Account/AccountMt.h index c03c300f9..66f053591 100644 --- a/Account/AccountMt.h +++ b/Account/AccountMt.h @@ -42,12 +42,13 @@ class AccountMt; #include "Account.define.h" #include "Account.enum.h" #include "Account.extern.h" +#include "Account.h" #include "Account.struct.h" /** * Class to provide functions that return parameters of the current account. */ -class AccountMt { +class AccountMt : public AccountBase { protected: // Struct variables. BufferStruct entries; @@ -136,7 +137,7 @@ class AccountMt { * Returns balance value of the current account. */ static double AccountBalance() { return AccountInfoDouble(ACCOUNT_BALANCE); } - float GetBalance() { + float GetBalance() override { // @todo: Adds caching. // return UpdateStats(ACC_BALANCE, AccountBalance()); return (float)AccountMt::AccountBalance(); @@ -146,7 +147,7 @@ class AccountMt { * Returns credit value of the current account. */ static double AccountCredit() { return AccountInfoDouble(ACCOUNT_CREDIT); } - float GetCredit() { + float GetCredit() override { // @todo: Adds caching. // return UpdateStats(ACC_CREDIT, AccountCredit()); return (float)AccountMt::AccountCredit(); @@ -156,7 +157,7 @@ class AccountMt { * Returns profit value of the current account. */ static double AccountProfit() { return AccountInfoDouble(ACCOUNT_PROFIT); } - float GetProfit() { + float GetProfit() override { // @todo: Adds caching. // return UpdateStats(ACC_PROFIT, AccountProfit()); return (float)AccountMt::AccountProfit(); @@ -166,7 +167,7 @@ class AccountMt { * Returns equity value of the current account. */ static double AccountEquity() { return AccountInfoDouble(ACCOUNT_EQUITY); } - float GetEquity() { + float GetEquity() override { // @todo: Adds caching. // return UpdateStats(ACC_EQUITY, AccountEquity()); return (float)AccountMt::AccountEquity(); @@ -198,7 +199,7 @@ class AccountMt { * Returns free margin value of the current account. */ static double AccountFreeMargin() { return AccountInfoDouble(ACCOUNT_MARGIN_FREE); } - float GetMarginFree() { + float GetMarginFree() override { // @todo: Adds caching. // return UpdateStats(ACC_MARGIN_FREE, AccountFreeMargin()); return (float)AccountMt::AccountFreeMargin(); @@ -267,7 +268,7 @@ class AccountMt { * Get account available margin. */ static double AccountAvailMargin() { return fmin(AccountFreeMargin(), AccountTotalBalance()); } - float GetMarginAvail() { return (float)AccountAvailMargin(); } + float GetMarginAvail() override { return (float)AccountAvailMargin(); } /** * Returns the calculation mode of free margin allowed to open orders on the current account. diff --git a/Indicator.enum.h b/Indicator.enum.h index b2b07a3a4..c20b4e8b6 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -44,6 +44,7 @@ enum ENUM_INDICATOR_ACTION { enum ENUM_INDICATOR_TYPE { INDI_NONE = 0, // (None) INDI_AC, // Accelerator Oscillator + INDI_ACCOUNT_STATS, // Account Stats INDI_AD, // Accumulation/Distribution INDI_ADX, // Average Directional Index INDI_ADXW, // ADX by Welles Wilder @@ -237,9 +238,24 @@ enum ENUM_INDI_VS_TYPE { INDI_VS_TYPE_INDEX_8, INDI_VS_TYPE_INDEX_9, INDI_VS_TYPE_INDEX_FIRST = INDI_VS_TYPE_INDEX_0, - INDI_VS_TYPE_INDEX_LAST = INDI_VS_TYPE_INDEX_9 + INDI_VS_TYPE_INDEX_LAST = INDI_VS_TYPE_INDEX_9, + + // Account Stats. + INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME, + INDI_VS_TYPE_ACCOUNT_STATS_BALANCE, + INDI_VS_TYPE_ACCOUNT_STATS_CREDIT, + INDI_VS_TYPE_ACCOUNT_STATS_EQUITY, + INDI_VS_TYPE_ACCOUNT_STATS_PROFIT, + INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED, + INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE, + INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL, + INDI_VS_TYPE_ACCOUNT_STATS_INDEX_FIRST = INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME, + INDI_VS_TYPE_ACCOUNT_STATS_INDEX_LAST = INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL, }; +#define INDI_VS_TYPE_ACCOUNT_STATS_BUFFERS_COUNT \ + (INDI_VS_TYPE_ACCOUNT_STATS_INDEX_LAST - INDI_VS_TYPE_ACCOUNT_STATS_INDEX_FIRST + 1) + // Indicator flags. enum ENUM_INDI_FLAGS { INDI_FLAG_INDEXABLE_BY_SHIFT, // Indicator supports indexation by shift. @@ -269,4 +285,11 @@ enum ENUM_INDI_DS_MODE_KIND { INDI_DS_MODE_KIND_AP, // Mode is a value from ENUM_APPLIED_PRICE enumeration. It is used to retrieve value storage // based on ENUM_INDI_VS_TYPE enumeration, e.g., PRICE_OPEN becomes ENUM_INDI_VS_PRICE_OPEN. }; + +// Type of entry +enum ENUM_INDI_EMITTED_ENTRY_TYPE { + INDI_EMITTED_ENTRY_TYPE_PARENT, // Undetermined type of entry from direct parent indicator. + INDI_EMITTED_ENTRY_TYPE_TICK, + INDI_EMITTED_ENTRY_TYPE_CANDLE, +}; //+------------------------------------------------------------------+ diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 8221afe82..da34844ca 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -32,6 +32,7 @@ // Includes. #include "../Buffer/BufferCandle.h" #include "../Candle.struct.h" +#include "../Indicator.enum.h" #include "../Indicator.mqh" #include "../Storage/ValueStorage.price_median.h" #include "../Storage/ValueStorage.price_typical.h" @@ -310,7 +311,7 @@ class IndicatorCandle : public Indicator { void EmitHistory() override { for (DictStructIterator> iter(icdata.Begin()); iter.IsValid(); ++iter) { IndicatorDataEntry _entry = CandleToEntry(iter.Key(), iter.Value()); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_CANDLE); } } @@ -342,7 +343,7 @@ class IndicatorCandle : public Indicator { /** * Adds tick's price to the matching candle and updates its OHLC values. */ - void UpdateCandle(long _tick_timestamp, double _price) { + CandleOCTOHLC UpdateCandle(long _tick_timestamp, double _price) { long _candle_timestamp = CalcCandleTimestamp(_tick_timestamp); #ifdef __debug_verbose__ @@ -368,6 +369,8 @@ class IndicatorCandle : public Indicator { } icdata.Add(_candle, _candle_timestamp); + + return _candle; } /** @@ -380,12 +383,25 @@ class IndicatorCandle : public Indicator { /** * Called when data source emits new entry (historic or future one). */ - void OnDataSourceEntry(IndicatorDataEntry& entry) override { - // Updating candle from bid price. - UpdateCandle(entry.timestamp, entry[1]); + void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + Indicator::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } + + long _candle_timestamp = CalcCandleTimestamp(entry.timestamp); // Updating tick & bar indices. - counter.OnTick(CalcCandleTimestamp(entry.timestamp)); + counter.OnTick(_candle_timestamp); + + // Updating candle from bid price. + CandleOCTOHLC _candle = UpdateCandle(entry.timestamp, entry[1]); + + // Emitting candle for children. + IndicatorDataEntry _candle_entry = CandleToEntry(_candle_timestamp, _candle); + EmitEntry(_candle_entry, INDI_EMITTED_ENTRY_TYPE_CANDLE); }; /** diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 5438923cb..cf01dfe83 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -164,7 +164,7 @@ class IndicatorTick : public Indicator { void EmitHistory() override { for (DictStructIterator> iter(itdata.Begin()); iter.IsValid(); ++iter) { IndicatorDataEntry _entry = TickToEntry(iter.Key(), iter.Value()); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); } } diff --git a/Indicator/tests/classes/IndicatorTfDummy.h b/Indicator/tests/classes/IndicatorTfDummy.h index 019b800d8..f49a8161d 100644 --- a/Indicator/tests/classes/IndicatorTfDummy.h +++ b/Indicator/tests/classes/IndicatorTfDummy.h @@ -48,11 +48,13 @@ class IndicatorTfDummy : public IndicatorTf { string GetName() override { return "IndicatorTfDummy(" + IntegerToString(iparams.spc) + ")"; } - void OnDataSourceEntry(IndicatorDataEntry& entry) override { - // When overriding OnDataSourceEntry() we have to remember to call parent - // method, because IndicatorCandle also need to invoke it in order to - // create/update matching candle. - IndicatorTf::OnDataSourceEntry(entry); + void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) override { + IndicatorTf::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_TICK) { + return; + } #ifdef __debug_indicator__ Print(GetFullName(), " got new tick at ", entry.timestamp, diff --git a/Indicator/tests/classes/IndicatorTickDummy.h b/Indicator/tests/classes/IndicatorTickDummy.h index dfd59e9a3..3e6bab0ab 100644 --- a/Indicator/tests/classes/IndicatorTickDummy.h +++ b/Indicator/tests/classes/IndicatorTickDummy.h @@ -59,13 +59,13 @@ class IndicatorTickDummy : public IndicatorTick _t7(4.2f, 4.21f); TickAB _t8(4.8f, 4.81f); - EmitEntry(TickToEntry(1000, _t1)); - EmitEntry(TickToEntry(1500, _t2)); - EmitEntry(TickToEntry(2000, _t3)); - EmitEntry(TickToEntry(3000, _t4)); - EmitEntry(TickToEntry(4000, _t5)); - EmitEntry(TickToEntry(4100, _t6)); - EmitEntry(TickToEntry(4200, _t7)); - EmitEntry(TickToEntry(4800, _t8)); + EmitEntry(TickToEntry(1000, _t1), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(1500, _t2), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(2000, _t3), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(3000, _t4), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4000, _t5), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4100, _t6), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4200, _t7), INDI_EMITTED_ENTRY_TYPE_TICK); + EmitEntry(TickToEntry(4800, _t8), INDI_EMITTED_ENTRY_TYPE_TICK); }; }; diff --git a/IndicatorData.mqh b/IndicatorData.mqh index 46225b8d3..bc0c498b1 100644 --- a/IndicatorData.mqh +++ b/IndicatorData.mqh @@ -1616,10 +1616,10 @@ class IndicatorData : public IndicatorBase { /** * Sends entry to listening indicators. */ - void EmitEntry(IndicatorDataEntry& entry) { + void EmitEntry(IndicatorDataEntry& entry, ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) { for (int i = 0; i < ArraySize(listeners); ++i) { if (listeners[i].ObjectExists()) { - listeners[i].Ptr().OnDataSourceEntry(entry); + listeners[i].Ptr().OnDataSourceEntry(entry, type); } } } @@ -1683,7 +1683,11 @@ class IndicatorData : public IndicatorBase { /** * Called when data source emits new entry (historic or future one). */ - virtual void OnDataSourceEntry(IndicatorDataEntry& entry){}; + virtual void OnDataSourceEntry(IndicatorDataEntry& entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) { + // Sending entry to all chilren listeners (from highest parent to lowest child). + EmitEntry(entry, type); + }; virtual void OnTick() {} diff --git a/Indicators/Account/Indi_AccountStats.mqh b/Indicators/Account/Indi_AccountStats.mqh new file mode 100644 index 000000000..da45fef7d --- /dev/null +++ b/Indicators/Account/Indi_AccountStats.mqh @@ -0,0 +1,207 @@ +//+------------------------------------------------------------------+ +//| 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 . + * + */ + +// Includes. +#include "../../Account/AccountBase.h" +#include "../../BufferStruct.mqh" +#include "../../Indicator.mqh" +#include "../../Platform.h" +#include "../../Storage/Objects.h" + +// Structs. +struct Indi_AccountStats_Params : IndicatorParams { + // Applied price. + ENUM_APPLIED_PRICE ap; + + // Account to use. + Ref account; + + // Struct constructor. + Indi_AccountStats_Params(AccountBase *_account = nullptr, int _shift = 0) + : IndicatorParams(INDI_ACCOUNT_STATS), account(_account) { + SetShift(_shift); + }; + Indi_AccountStats_Params(Indi_AccountStats_Params &_params) { THIS_REF = _params; }; + + // Getters. + AccountBase *GetAccount() { return account.Ptr(); } + ENUM_APPLIED_PRICE GetAppliedPrice() override { return ap; } + + // Setters. + void SetAccount(AccountBase *_account) { account = _account; } + void SetAppliedPrice(ENUM_APPLIED_PRICE _ap) { ap = _ap; } +}; + +/** + * Price Indicator. + */ +class Indi_AccountStats : public Indicator { + Ref> buffer_date_time; + Ref> buffer_balance; + Ref> buffer_credit; + Ref> buffer_equity; + Ref> buffer_profit; + Ref> buffer_margin_used; + Ref> buffer_margin_free; + Ref> buffer_margin_avail; + + public: + /** + * Class constructor. + */ + Indi_AccountStats(Indi_AccountStats_Params &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, + IndicatorData *_indi_src = NULL, int _indi_src_mode = 0) + : Indicator(_p, + IndicatorDataParams::GetInstance(INDI_VS_TYPE_ACCOUNT_STATS_BUFFERS_COUNT, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + InitAccountStats(); + }; + Indi_AccountStats(int _shift = 0, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL, + int _indi_src_mode = 0) + : Indicator(Indi_AccountStats_Params(), + IndicatorDataParams::GetInstance(INDI_VS_TYPE_ACCOUNT_STATS_BUFFERS_COUNT, TYPE_DOUBLE, _idstype, + IDATA_RANGE_PRICE, _indi_src_mode), + _indi_src) { + InitAccountStats(); + }; + void InitAccountStats() { + buffer_date_time = new NativeValueStorage(); + buffer_balance = new NativeValueStorage(); + buffer_credit = new NativeValueStorage(); + buffer_equity = new NativeValueStorage(); + buffer_profit = new NativeValueStorage(); + buffer_margin_used = new NativeValueStorage(); + buffer_margin_free = new NativeValueStorage(); + buffer_margin_avail = new NativeValueStorage(); + } + + /** + * Returns possible data source types. It is a bit mask of ENUM_INDI_SUITABLE_DS_TYPE. + */ + virtual unsigned int GetSuitableDataSourceTypes() { + // We require that candle indicator is attached. + return INDI_SUITABLE_DS_TYPE_CANDLE; + } + + /** + * Returns possible data source modes. It is a bit mask of ENUM_IDATA_SOURCE_TYPE. + */ + unsigned int GetPossibleDataModes() override { return IDATA_BUILTIN; } + + /** + * Checks whether indicator has a valid value for a given shift. + */ + virtual bool HasValidEntry(int _shift = 0) { return GetBarTime(_shift) != 0; } + + /** + * Returns the indicator's value. + */ + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + + // Converting mode into value storage type. + ENUM_INDI_VS_TYPE _vs_type = (ENUM_INDI_VS_TYPE)(INDI_VS_TYPE_ACCOUNT_STATS_INDEX_FIRST + _mode); + + // Retrieving data from specific value storage. + switch (_vs_type) { + case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: + return ((ValueStorage *)GetSpecificValueStorage(_vs_type))PTR_DEREF FetchSeries(_ishift); + case INDI_VS_TYPE_ACCOUNT_STATS_BALANCE: + case INDI_VS_TYPE_ACCOUNT_STATS_CREDIT: + case INDI_VS_TYPE_ACCOUNT_STATS_EQUITY: + case INDI_VS_TYPE_ACCOUNT_STATS_PROFIT: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL: + return ((ValueStorage *)GetSpecificValueStorage(_vs_type))PTR_DEREF FetchSeries(_ishift); + default: + Alert("Error: Indi_AccountStats: Invalid mode passed to GetEntryValue()!"); + DebugBreak(); + return EMPTY_VALUE; + } + } + + /** + * Returns value storage of given kind. + */ + IValueStorage *GetSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + // Returning Price indicator which provides applied price in the only buffer #0. + switch (_type) { + case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: + return buffer_date_time.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_BALANCE: + return buffer_balance.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_CREDIT: + return buffer_credit.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_EQUITY: + return buffer_equity.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_PROFIT: + return buffer_profit.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED: + return buffer_margin_used.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE: + return buffer_margin_free.Ptr(); + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL: + return buffer_margin_avail.Ptr(); + default: + // Trying in parent class. + return Indicator::GetSpecificValueStorage(_type); + } + } + + /** + * Checks whether indicator support given value storage type. + */ + bool HasSpecificValueStorage(ENUM_INDI_VS_TYPE _type) override { + switch (_type) { + case INDI_VS_TYPE_ACCOUNT_STATS_DATE_TIME: + case INDI_VS_TYPE_ACCOUNT_STATS_BALANCE: + case INDI_VS_TYPE_ACCOUNT_STATS_CREDIT: + case INDI_VS_TYPE_ACCOUNT_STATS_EQUITY: + case INDI_VS_TYPE_ACCOUNT_STATS_PROFIT: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_USED: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_FREE: + case INDI_VS_TYPE_ACCOUNT_STATS_MARGIN_AVAIL: + return true; + default: + // Trying in parent class. + return Indicator::HasSpecificValueStorage(_type); + } + } + + /** + * Called when data source emits new entry (historic or future one). + */ + virtual void OnDataSourceEntry(IndicatorDataEntry &entry, + ENUM_INDI_EMITTED_ENTRY_TYPE type = INDI_EMITTED_ENTRY_TYPE_PARENT) { + Indicator::OnDataSourceEntry(entry, type); + + if (type != INDI_EMITTED_ENTRY_TYPE_CANDLE) { + return; + } + + // Adding new account stats entry. + + Print("New candle: ", entry.ToString()); + } +}; diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq4 b/Indicators/Account/tests/Indi_AccountStats.test.mq4 new file mode 100644 index 000000000..8356c50b5 --- /dev/null +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq4 @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| 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 Indi_AC indicator class. + */ + +#include "Indi_AC.test.mq5" diff --git a/Indicators/Account/tests/Indi_AccountStats.test.mq5 b/Indicators/Account/tests/Indi_AccountStats.test.mq5 new file mode 100644 index 000000000..c81e0da79 --- /dev/null +++ b/Indicators/Account/tests/Indi_AccountStats.test.mq5 @@ -0,0 +1,61 @@ +//+------------------------------------------------------------------+ +//| 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 . + */ + +// Includes. +#include "../../../Account/AccountMt.h" +#include "../../../Platform.h" +#include "../../../Test.mqh" +#include "../Indi_AccountStats.mqh" + +/** + * @file + * Test functionality of Indi_AccountStats indicator class. + */ + +Ref indi_account_mt; + +int OnInit() { + Ref account_mt = new AccountMt(); + Indi_AccountStats_Params indi_params(account_mt.Ptr()); + indi_account_mt = new Indi_AccountStats(indi_params); + + Platform::Init(); + + Platform::AddWithDefaultBindings(indi_account_mt.Ptr()); + + bool _result = true; + assertTrueOrFail(indi_account_mt REF_DEREF IsValid(), "Error on IsValid!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +void OnTick() { + Platform::Tick(); + if (Platform::IsNewHour()) { + IndicatorDataEntry _entry = indi_account_mt REF_DEREF GetEntry(); + bool _is_ready = indi_account_mt REF_DEREF Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)); + bool _is_valid = _entry.IsValid(); + Print(indi_account_mt REF_DEREF ToString(), _is_ready ? "" : " (Not yet ready)"); + if (_is_ready && !_is_valid) { + Print(indi_account_mt REF_DEREF ToString(), " (Invalid entry!)"); + assertTrueOrExit(_entry.IsValid(), "Invalid entry!"); + } + } +} \ No newline at end of file diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index ec615c8ac..4fde34ef7 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -256,14 +256,6 @@ class Indi_AMA : public Indicator { return _value; } - /** - * Called when data source emits new entry (historic or future one). - */ - void OnDataSourceEntry(IndicatorDataEntry &entry) override { - // Just to be able to make a breakpoint here. - int x = 4; - }; - /** * Called if data source is requested, but wasn't yet set. May be used to initialize indicators that must operate on * some data source. diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 726004fff..b60ee2d04 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -159,7 +159,7 @@ class Indi_TickMt : public IndicatorTick { _tmp_ticks[i].ask, ", ", _tmp_ticks[i].bid); #endif - EmitEntry(TickToEntry(_tmp_ticks[i].time, _tick)); + EmitEntry(TickToEntry(_tmp_ticks[i].time, _tick), INDI_EMITTED_ENTRY_TYPE_TICK); if (_num_yet_to_copy <= 0) { break; @@ -205,7 +205,7 @@ class Indi_TickMt : public IndicatorTick { // DebugBreak(); // Just emitting zeroes in case of error. TickAB _tick(0, 0); - EmitEntry(TickToEntry(TimeCurrent(), _tick)); + EmitEntry(TickToEntry(TimeCurrent(), _tick), INDI_EMITTED_ENTRY_TYPE_TICK); return; } @@ -224,6 +224,6 @@ class Indi_TickMt : public IndicatorTick { TickAB _tick(_ask, _bid); IndicatorDataEntry _entry(TickToEntry(_time, _tick)); StoreEntry(_entry); - EmitEntry(_entry); + EmitEntry(_entry, INDI_EMITTED_ENTRY_TYPE_TICK); } }; diff --git a/Storage/IValueStorage.h b/Storage/IValueStorage.h index 290c2552d..6f4897bf6 100644 --- a/Storage/IValueStorage.h +++ b/Storage/IValueStorage.h @@ -72,6 +72,11 @@ class IValueStorage : public Dynamic { DebugBreak(); return false; } + + /** + * Returns real array index for this given shift. + **/ + virtual int GetRealIndex(int _shift) { return IsSeries() ? (Size() - 1 - _shift) : _shift; } }; /** diff --git a/Storage/ValueStorage.h b/Storage/ValueStorage.h index 6c7979ba0..865b2d651 100644 --- a/Storage/ValueStorage.h +++ b/Storage/ValueStorage.h @@ -181,6 +181,15 @@ class ValueStorage : public IValueStorage { DebugBreak(); } + /** + * Inserts new value at the end of the buffer. If buffer works as As-Series, + * then new value will act as the one at index 0. + */ + virtual void Append(C _value) { + Alert(__FUNCSIG__, " does not implement Append()!"); + DebugBreak(); + } + /** * Sets buffer drawing attributes. Currently does nothing. */ diff --git a/Storage/ValueStorage.native.h b/Storage/ValueStorage.native.h index 46ca12565..0c6180881 100644 --- a/Storage/ValueStorage.native.h +++ b/Storage/ValueStorage.native.h @@ -60,19 +60,28 @@ class NativeValueStorage : public ValueStorage { * Fetches value from a given shift. Takes into consideration as-series flag. */ C Fetch(int _shift) override { - if (_shift < 0 || _shift >= ArraySize(_values)) { + if (_shift < 0 || _shift >= Size()) { return (C)EMPTY_VALUE; - // Print("Invalid buffer data index: ", _shift, ". Buffer size: ", ArraySize(_values)); - // DebugBreak(); } - return _values[_shift]; + int _index = GetRealIndex(_shift); + + return _values[_index]; } /** * Stores value at a given shift. Takes into consideration as-series flag. */ - void Store(int _shift, C _value) override { Array::ArrayStore(_values, _shift, _value, 4096); } + void Store(int _shift, C _value) override { + if (_shift < 0 || _shift >= Size()) { + Alert("Error: NativeValueStorage: Invalid buffer data index: ", _shift, ". Buffer size: ", Size()); + DebugBreak(); + } + + int _index = GetRealIndex(_shift); + + Array::ArrayStore(_values, _index, _value, 4096); + } /** * Returns number of values available to fetch (size of the values buffer).