173 行
5.9 KiB
MQL5
173 行
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) { }
| |||
};
| |||
//+------------------------------------------------------------------+
|