forked from rosh/MQL5Book
173 lines
5.9 KiB
MQL5
173 lines
5.9 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| TradeState.mqh |
| |
//| Copyright 2022, MetaQuotes Ltd. |
| |
//| https://www.mql5.com |
| |
//+------------------------------------------------------------------+
| |
#include "PositionMonitor.mqh"
| |
#include "OrderMonitor.mqh"
| |
#include "DealMonitor.mqh"
| |
| |
//+------------------------------------------------------------------+
| |
//| In-memory storage for orders/deals/positions with all properties |
| |
//| Type M should be one of monitors: |
| |
//| #include "PositionMonitor.mqh" |
| |
//| #include "DealMonitor.mqh" |
| |
//| #include "OrderMonitor.mqh" |
| |
//| Types I, D, S stand for 3 ENUM-types of properties |
| |
//| I - integers, D - doubles, S - strings |
| |
//+------------------------------------------------------------------+
| |
template<typename M,typename I,typename D,typename S>
| |
class TradeBaseState: public M
| |
{
| |
M::TradeState state;
| |
bool cached;
| |
| |
public:
| |
TradeBaseState(const ulong t) : M(t), state(&this), cached(ready)
| |
{
| |
}
| |
| |
void passthrough(const bool b) // enable/disable caching ad hoc
| |
{
| |
cached = b;
| |
}
| |
| |
string stringifyRaw(const int i) // get property 'i' as a string bypassing the cache
| |
{
| |
const bool previous = cached;
| |
cached = false;
| |
const string s = stringify(i);
| |
cached = previous;
| |
return s;
| |
}
| |
| |
bool update()
| |
{
| |
if(refresh())
| |
{
| |
cached = false; // disable reading from cache
| |
state.cache(); // read real properties into cache
| |
cached = true; // enable cache back
| |
return true;
| |
}
| |
return false;
| |
}
| |
| |
// NB! The 'ready' state change (when element becomes not selectable anymore)
| |
// will happen only once from true to false during the calls to 'getChanges'/'isChanged'.
| |
// The 'ready' state is not a normal property. Changes in all standard properties are applied
| |
// to the cache only after explicit 'update' method call. Until 'update' is called,
| |
// all successive invocations of 'getChanges'/'isChanged' will detect the same changes
| |
// (and probably new additional).
| |
| |
bool getChanges(int &changes[])
| |
{
| |
const bool previous = ready;
| |
if(refresh())
| |
{
| |
// object selected = ready to read and compare
| |
cached = false;
| |
const bool result = M::diff(state, changes);
| |
cached = true;
| |
return result;
| |
}
| |
// became not ready = removed or gone out of the selected context
| |
return previous != ready; // ready changed
| |
}
| |
| |
bool isChanged()
| |
{
| |
const bool previous = ready;
| |
if(refresh())
| |
{
| |
// object selected = ready to read and compare
| |
cached = false;
| |
const bool result = this == state; // use overloaded operator '=='
| |
cached = true;
| |
return result;
| |
}
| |
// became not ready = removed
| |
return previous != ready; // ready changed
| |
}
| |
| |
void reset()
| |
{
| |
state.reset();
| |
}
| |
| |
virtual long get(const I property) const override
| |
{
| |
return cached ? state.ulongs[M::TradeState::offset(property)] : M::get(property);
| |
}
| |
| |
virtual double get(const D property) const override
| |
{
| |
return cached ? state.doubles[M::TradeState::offset(property)] : M::get(property);
| |
}
| |
| |
virtual string get(const S property) const override
| |
{
| |
return cached ? state.strings[M::TradeState::offset(property)] : M::get(property);
| |
}
| |
| |
virtual long get(const int property, const long) const override
| |
{
| |
return cached ? state.ulongs[M::TradeState::offset(property)] : M::get((I)property);
| |
}
| |
| |
virtual double get(const int property, const double) const override
| |
{
| |
return cached ? state.doubles[M::TradeState::offset(property)] : M::get((D)property);
| |
}
| |
| |
virtual string get(const int property, const string) const override
| |
{
| |
return cached ? state.strings[M::TradeState::offset(property)] : M::get((S)property);
| |
}
| |
};
| |
| |
//+------------------------------------------------------------------+
| |
//| Concrete in-memory storage for orders properties |
| |
//+------------------------------------------------------------------+
| |
class OrderState: public TradeBaseState<ActiveOrderMonitor,
| |
ENUM_ORDER_PROPERTY_INTEGER,
| |
ENUM_ORDER_PROPERTY_DOUBLE,
| |
ENUM_ORDER_PROPERTY_STRING>
| |
{
| |
public:
| |
OrderState(const long t): TradeBaseState(t) { }
| |
};
| |
| |
class HistoryOrderState: public TradeBaseState<HistoryOrderMonitor,
| |
ENUM_ORDER_PROPERTY_INTEGER,
| |
ENUM_ORDER_PROPERTY_DOUBLE,
| |
ENUM_ORDER_PROPERTY_STRING>
| |
{
| |
public:
| |
HistoryOrderState(const long t): TradeBaseState(t) { }
| |
};
| |
| |
//+------------------------------------------------------------------+
| |
//| Concrete in-memory storage for deal properties |
| |
//+------------------------------------------------------------------+
| |
class DealState: public TradeBaseState<DealMonitor,
| |
ENUM_DEAL_PROPERTY_INTEGER,
| |
ENUM_DEAL_PROPERTY_DOUBLE,
| |
ENUM_DEAL_PROPERTY_STRING>
| |
{
| |
public:
| |
DealState(const long t): TradeBaseState(t) { }
| |
};
| |
| |
//+------------------------------------------------------------------+
| |
//| Concrete in-memory storage for positions properties |
| |
//+------------------------------------------------------------------+
| |
class PositionState: public TradeBaseState<PositionMonitor,
| |
ENUM_POSITION_PROPERTY_INTEGER,
| |
ENUM_POSITION_PROPERTY_DOUBLE,
| |
ENUM_POSITION_PROPERTY_STRING>
| |
{
| |
public:
| |
PositionState(const long t): TradeBaseState(t) { }
| |
};
| |
//+------------------------------------------------------------------+
|