Add files via upload
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,715 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ExpertBase.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Trade\SymbolInfo.mqh>
|
||||
#include <Trade\AccountInfo.mqh>
|
||||
#include <Trade\PositionInfo.mqh>
|
||||
#include <Trade\OrderInfo.mqh>
|
||||
#include <Trade\DealInfo.mqh>
|
||||
#include <Trade\HistoryOrderInfo.mqh>
|
||||
#include <Indicators\Indicators.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| enumerations |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- constants of identification of trend
|
||||
enum ENUM_TYPE_TREND
|
||||
{
|
||||
TYPE_TREND_HARD_DOWN =0, // strong down trend
|
||||
TYPE_TREND_DOWN =1, // down trend
|
||||
TYPE_TREND_SOFT_DOWN =2, // weak down trend
|
||||
TYPE_TREND_FLAT =3, // no trend
|
||||
TYPE_TREND_SOFT_UP =4, // weak up trend
|
||||
TYPE_TREND_UP =5, // up trend
|
||||
TYPE_TREND_HARD_UP =6 // strong up trend
|
||||
};
|
||||
//--- flags of used timeseries
|
||||
enum ENUM_USED_SERIES
|
||||
{
|
||||
USE_SERIES_OPEN =0x1,
|
||||
USE_SERIES_HIGH =0x2,
|
||||
USE_SERIES_LOW =0x4,
|
||||
USE_SERIES_CLOSE =0x8,
|
||||
USE_SERIES_SPREAD =0x10,
|
||||
USE_SERIES_TIME =0x20,
|
||||
USE_SERIES_TICK_VOLUME=0x40,
|
||||
USE_SERIES_REAL_VOLUME=0x80
|
||||
};
|
||||
//--- phases of initialization of an object
|
||||
enum ENUM_INIT_PHASE
|
||||
{
|
||||
INIT_PHASE_FIRST =0, // start phase (only Init(...) can be called)
|
||||
INIT_PHASE_TUNING =1, // phase of tuning (set in Init(...))
|
||||
INIT_PHASE_VALIDATION =2, // phase of checking of parameters(set in ValidationSettings(...))
|
||||
INIT_PHASE_COMPLETE =3 // end phase (set in InitIndicators(...))
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Macro definitions. |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- check the use of timeseries
|
||||
#define IS_OPEN_SERIES_USAGE ((m_used_series&USE_SERIES_OPEN)!=0)
|
||||
#define IS_HIGH_SERIES_USAGE ((m_used_series&USE_SERIES_HIGH)!=0)
|
||||
#define IS_LOW_SERIES_USAGE ((m_used_series&USE_SERIES_LOW)!=0)
|
||||
#define IS_CLOSE_SERIES_USAGE ((m_used_series&USE_SERIES_CLOSE)!=0)
|
||||
#define IS_SPREAD_SERIES_USAGE ((m_used_series&USE_SERIES_SPREAD)!=0)
|
||||
#define IS_TIME_SERIES_USAGE ((m_used_series&USE_SERIES_TIME)!=0)
|
||||
#define IS_TICK_VOLUME_SERIES_USAGE ((m_used_series&USE_SERIES_TICK_VOLUME)!=0)
|
||||
#define IS_REAL_VOLUME_SERIES_USAGE ((m_used_series&USE_SERIES_REAL_VOLUME)!=0)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CExpertBase. |
|
||||
//| Purpose: Base class of component of Expert Advisor. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CExpertBase : public CObject
|
||||
{
|
||||
protected:
|
||||
//--- variables
|
||||
ulong m_magic; // expert magic number
|
||||
ENUM_INIT_PHASE m_init_phase; // the phase (stage) of initialization of object
|
||||
bool m_other_symbol; // flag of a custom work symbols (different from one of the Expert Advisor)
|
||||
CSymbolInfo *m_symbol; // pointer to the object-symbol
|
||||
bool m_other_period; // flag of a custom timeframe (different from one of the Expert Advisor)
|
||||
ENUM_TIMEFRAMES m_period; // work timeframe
|
||||
double m_adjusted_point; // "weight" 2/4 of a point
|
||||
CAccountInfo m_account; // object-deposit
|
||||
ENUM_ACCOUNT_MARGIN_MODE m_margin_mode; // netting or hedging
|
||||
ENUM_TYPE_TREND m_trend_type; // identifier of trend
|
||||
bool m_every_tick; // flag of starting the analysis from current (incomplete) bar
|
||||
//--- timeseries
|
||||
int m_used_series; // flags of using of series
|
||||
CiOpen *m_open; // pointer to the object for access to open prices of bars
|
||||
CiHigh *m_high; // pointer to the object for access to high prices of bars
|
||||
CiLow *m_low; // pointer to the object for access to low prices of bars
|
||||
CiClose *m_close; // pointer to the object for access to close prices of bars
|
||||
CiSpread *m_spread; // pointer to the object for access to spreads
|
||||
CiTime *m_time; // pointer to the object for access to time of closing of bars
|
||||
CiTickVolume *m_tick_volume; // pointer to the object for access to tick volumes of bars
|
||||
CiRealVolume *m_real_volume; // pointer to the object for access to real volumes of bars
|
||||
|
||||
public:
|
||||
CExpertBase(void);
|
||||
~CExpertBase(void);
|
||||
//--- methods of access to protected data
|
||||
ENUM_INIT_PHASE InitPhase(void) const { return(m_init_phase); }
|
||||
void TrendType(ENUM_TYPE_TREND value) { m_trend_type=value; }
|
||||
int UsedSeries(void) const;
|
||||
void EveryTick(bool value) { m_every_tick=value; }
|
||||
//--- methods of access to protected data
|
||||
double Open(int ind) const;
|
||||
double High(int ind) const;
|
||||
double Low(int ind) const;
|
||||
double Close(int ind) const;
|
||||
int Spread(int ind) const;
|
||||
datetime Time(int ind) const;
|
||||
long TickVolume(int ind) const;
|
||||
long RealVolume(int ind) const;
|
||||
//--- methods of initialization of the object
|
||||
virtual bool Init(CSymbolInfo *symbol,ENUM_TIMEFRAMES period,double point);
|
||||
bool Symbol(string name);
|
||||
bool Period(ENUM_TIMEFRAMES value);
|
||||
void Magic(ulong value) { m_magic=value; }
|
||||
void SetMarginMode(void) { m_margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings();
|
||||
//--- methods of creating the indicator and timeseries
|
||||
virtual bool SetPriceSeries(CiOpen *open,CiHigh *high,CiLow *low,CiClose *close);
|
||||
virtual bool SetOtherSeries(CiSpread *spread,CiTime *time,CiTickVolume *tick_volume,CiRealVolume *real_volume);
|
||||
virtual bool InitIndicators(CIndicators *indicators=NULL);
|
||||
|
||||
protected:
|
||||
//--- methods initialization of timeseries
|
||||
bool InitOpen(CIndicators *indicators);
|
||||
bool InitHigh(CIndicators *indicators);
|
||||
bool InitLow(CIndicators *indicators);
|
||||
bool InitClose(CIndicators *indicators);
|
||||
bool InitSpread(CIndicators *indicators);
|
||||
bool InitTime(CIndicators *indicators);
|
||||
bool InitTickVolume(CIndicators *indicators);
|
||||
bool InitRealVolume(CIndicators *indicators);
|
||||
//--- method of getting the measure units of price levels
|
||||
virtual double PriceLevelUnit(void) { return(m_adjusted_point); }
|
||||
//--- method of getting index of bar the analysis starts with
|
||||
virtual int StartIndex(void) { return((m_every_tick?0:1)); }
|
||||
virtual bool CompareMagic(ulong magic) { return(m_magic==magic); }
|
||||
bool IsHedging(void) const { return(m_margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CExpertBase::CExpertBase(void) : m_magic(0),
|
||||
m_margin_mode(ACCOUNT_MARGIN_MODE_RETAIL_NETTING),
|
||||
m_init_phase(INIT_PHASE_FIRST),
|
||||
m_other_symbol(false),
|
||||
m_symbol(NULL),
|
||||
m_other_period(false),
|
||||
m_period(PERIOD_CURRENT),
|
||||
m_adjusted_point(1.0),
|
||||
m_trend_type(TYPE_TREND_FLAT),
|
||||
m_every_tick(false),
|
||||
m_used_series(0),
|
||||
m_open(NULL),
|
||||
m_high(NULL),
|
||||
m_low(NULL),
|
||||
m_close(NULL),
|
||||
m_spread(NULL),
|
||||
m_time(NULL),
|
||||
m_tick_volume(NULL),
|
||||
m_real_volume(NULL)
|
||||
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CExpertBase::~CExpertBase(void)
|
||||
{
|
||||
//--- if the symbol is "custom", delete it
|
||||
if(m_other_symbol && m_symbol!=NULL)
|
||||
delete m_symbol;
|
||||
//--- release of "custom" timeseries
|
||||
if(m_other_symbol || m_other_period)
|
||||
{
|
||||
if(IS_OPEN_SERIES_USAGE && CheckPointer(m_open)==POINTER_DYNAMIC)
|
||||
delete m_open;
|
||||
if(IS_HIGH_SERIES_USAGE && CheckPointer(m_high)==POINTER_DYNAMIC)
|
||||
delete m_high;
|
||||
if(IS_LOW_SERIES_USAGE && CheckPointer(m_low)==POINTER_DYNAMIC)
|
||||
delete m_low;
|
||||
if(IS_CLOSE_SERIES_USAGE && CheckPointer(m_close)==POINTER_DYNAMIC)
|
||||
delete m_close;
|
||||
if(IS_SPREAD_SERIES_USAGE && CheckPointer(m_spread)==POINTER_DYNAMIC)
|
||||
delete m_spread;
|
||||
if(IS_TIME_SERIES_USAGE && CheckPointer(m_time)==POINTER_DYNAMIC)
|
||||
delete m_time;
|
||||
if(IS_TICK_VOLUME_SERIES_USAGE && CheckPointer(m_tick_volume)==POINTER_DYNAMIC)
|
||||
delete m_tick_volume;
|
||||
if(IS_REAL_VOLUME_SERIES_USAGE && CheckPointer(m_real_volume)==POINTER_DYNAMIC)
|
||||
delete m_real_volume;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get flags of used timeseries |
|
||||
//+------------------------------------------------------------------+
|
||||
int CExpertBase::UsedSeries(void) const
|
||||
{
|
||||
if(m_other_symbol || m_other_period)
|
||||
return(0);
|
||||
//---
|
||||
return(m_used_series);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of object. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::Init(CSymbolInfo *symbol,ENUM_TIMEFRAMES period,double point)
|
||||
{
|
||||
//--- check the initialization phase
|
||||
if(m_init_phase!=INIT_PHASE_FIRST)
|
||||
{
|
||||
Print(__FUNCTION__+": attempt of re-initialization");
|
||||
return(false);
|
||||
}
|
||||
//--- check of pointer
|
||||
if(symbol==NULL)
|
||||
{
|
||||
Print(__FUNCTION__+": error initialization");
|
||||
return(false);
|
||||
}
|
||||
//--- initialization
|
||||
m_symbol =symbol;
|
||||
m_period =period;
|
||||
m_adjusted_point=point;
|
||||
m_other_symbol =false;
|
||||
m_other_period =false;
|
||||
SetMarginMode();
|
||||
//--- primary initialization is successful, pass to the phase of tuning
|
||||
m_init_phase=INIT_PHASE_TUNING;
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Changing work symbol. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::Symbol(string name)
|
||||
{
|
||||
//--- check the initialization phase
|
||||
if(m_init_phase!=INIT_PHASE_TUNING)
|
||||
{
|
||||
Print(__FUNCTION__+": changing of symbol is forbidden");
|
||||
return(false);
|
||||
}
|
||||
if(m_symbol!=NULL)
|
||||
{
|
||||
//--- symbol has been already set
|
||||
if(m_symbol.Name()==name)
|
||||
return(true);
|
||||
//--- symbol is not the one required, but is already "custom"
|
||||
if(m_other_symbol)
|
||||
{
|
||||
if(!m_symbol.Name(name))
|
||||
{
|
||||
//--- failed to initialize the symbol
|
||||
delete m_symbol;
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
m_symbol=new CSymbolInfo;
|
||||
//--- check of pointer
|
||||
if(m_symbol==NULL)
|
||||
{
|
||||
Print(__FUNCTION__+": error of changing of symbol");
|
||||
return(false);
|
||||
}
|
||||
if(!m_symbol.Name(name))
|
||||
{
|
||||
//--- failed to initialize the symbol
|
||||
delete m_symbol;
|
||||
return(false);
|
||||
}
|
||||
m_other_symbol=true;
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Changing work timeframe. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::Period(ENUM_TIMEFRAMES value)
|
||||
{
|
||||
//--- check the initialization phase
|
||||
if(m_init_phase!=INIT_PHASE_TUNING)
|
||||
{
|
||||
Print(__FUNCTION__+": changing of timeframe is forbidden");
|
||||
return(false);
|
||||
}
|
||||
if(m_period==value)
|
||||
return(true);
|
||||
//--- change work timeframe
|
||||
m_period=value;
|
||||
m_other_period=true;
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking adjustable parameters |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::ValidationSettings()
|
||||
{
|
||||
//--- rechecking parameters
|
||||
if(m_init_phase==INIT_PHASE_VALIDATION)
|
||||
return(true);
|
||||
//--- check the initialization phase
|
||||
if(m_init_phase!=INIT_PHASE_TUNING)
|
||||
{
|
||||
Print(__FUNCTION__+": not the right time to check parameters");
|
||||
return(false);
|
||||
}
|
||||
//--- initial check of parameters is successful, phase of tuning is over
|
||||
m_init_phase=INIT_PHASE_VALIDATION;
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Setting pointers of price timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::SetPriceSeries(CiOpen *open,CiHigh *high,CiLow *low,CiClose *close)
|
||||
{
|
||||
//--- check the initialization phase
|
||||
if(m_init_phase!=INIT_PHASE_VALIDATION)
|
||||
{
|
||||
Print(__FUNCTION__+": changing of timeseries is forbidden");
|
||||
return(false);
|
||||
}
|
||||
//--- check pointers
|
||||
if((IS_OPEN_SERIES_USAGE && open==NULL) ||
|
||||
(IS_HIGH_SERIES_USAGE && high==NULL) ||
|
||||
(IS_LOW_SERIES_USAGE && low==NULL) ||
|
||||
(IS_CLOSE_SERIES_USAGE && close==NULL))
|
||||
{
|
||||
Print(__FUNCTION__+": NULL pointer");
|
||||
return(false);
|
||||
}
|
||||
m_open =open;
|
||||
m_high =high;
|
||||
m_low =low;
|
||||
m_close=close;
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Setting pointers of other timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::SetOtherSeries(CiSpread *spread,CiTime *time,CiTickVolume *tick_volume,CiRealVolume *real_volume)
|
||||
{
|
||||
//--- check the initialization phase
|
||||
if(m_init_phase!=INIT_PHASE_VALIDATION)
|
||||
{
|
||||
Print(__FUNCTION__+": changing of timeseries is forbidden");
|
||||
return(false);
|
||||
}
|
||||
//--- check pointers
|
||||
if((IS_SPREAD_SERIES_USAGE && spread==NULL) ||
|
||||
(IS_TIME_SERIES_USAGE && time==NULL) ||
|
||||
(IS_TICK_VOLUME_SERIES_USAGE && tick_volume==NULL) ||
|
||||
(IS_REAL_VOLUME_SERIES_USAGE && real_volume==NULL))
|
||||
{
|
||||
Print(__FUNCTION__+": NULL pointer");
|
||||
return(false);
|
||||
}
|
||||
m_spread =spread;
|
||||
m_time =time;
|
||||
m_tick_volume=tick_volume;
|
||||
m_real_volume=real_volume;
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of indicators and timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- this call is for compatibility with the previous version
|
||||
if(!ValidationSettings())
|
||||
return(false);
|
||||
//--- check the initialization phase
|
||||
if(m_init_phase!=INIT_PHASE_VALIDATION)
|
||||
{
|
||||
Print(__FUNCTION__+": parameters of setting are not checked");
|
||||
return(false);
|
||||
}
|
||||
if(!m_other_symbol && !m_other_period)
|
||||
return(true);
|
||||
//--- check pointers
|
||||
if(m_symbol==NULL)
|
||||
return(false);
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of required timeseries
|
||||
if(IS_OPEN_SERIES_USAGE && !InitOpen(indicators))
|
||||
return(false);
|
||||
if(IS_HIGH_SERIES_USAGE && !InitHigh(indicators))
|
||||
return(false);
|
||||
if(IS_LOW_SERIES_USAGE && !InitLow(indicators))
|
||||
return(false);
|
||||
if(IS_CLOSE_SERIES_USAGE && !InitClose(indicators))
|
||||
return(false);
|
||||
if(IS_SPREAD_SERIES_USAGE && !InitSpread(indicators))
|
||||
return(false);
|
||||
if(IS_TIME_SERIES_USAGE && !InitTime(indicators))
|
||||
return(false);
|
||||
if(IS_TICK_VOLUME_SERIES_USAGE && !InitTickVolume(indicators))
|
||||
return(false);
|
||||
if(IS_REAL_VOLUME_SERIES_USAGE && !InitRealVolume(indicators))
|
||||
return(false);
|
||||
//--- initialization of object (from the point of view of the base class) has been performed successfully
|
||||
//--- now it's impossible to change anything in the settings
|
||||
m_init_phase=INIT_PHASE_COMPLETE;
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data of the Open timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CExpertBase::Open(int ind) const
|
||||
{
|
||||
//--- check pointer
|
||||
if(m_open==NULL)
|
||||
return(EMPTY_VALUE);
|
||||
//--- return the result
|
||||
return(m_open.GetData(ind));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data of the High timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CExpertBase::High(int ind) const
|
||||
{
|
||||
//--- check pointer
|
||||
if(m_high==NULL)
|
||||
return(EMPTY_VALUE);
|
||||
//--- return the result
|
||||
return(m_high.GetData(ind));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data of the Low timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CExpertBase::Low(int ind) const
|
||||
{
|
||||
//--- check pointer
|
||||
if(m_low==NULL)
|
||||
return(EMPTY_VALUE);
|
||||
//--- return the result
|
||||
return(m_low.GetData(ind));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data of the Close timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CExpertBase::Close(int ind) const
|
||||
{
|
||||
//--- check pointer
|
||||
if(m_close==NULL)
|
||||
return(EMPTY_VALUE);
|
||||
//--- return the result
|
||||
return(m_close.GetData(ind));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data of the Spread timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CExpertBase::Spread(int ind) const
|
||||
{
|
||||
//--- check pointer
|
||||
if(m_spread==NULL)
|
||||
return(INT_MAX);
|
||||
//--- return the result
|
||||
return(m_spread.GetData(ind));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data of the Time timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime CExpertBase::Time(int ind) const
|
||||
{
|
||||
//--- check pointer
|
||||
if(m_time==NULL)
|
||||
return(0);
|
||||
//--- return the result
|
||||
return(m_time.GetData(ind));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data of the TickVolume timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
long CExpertBase::TickVolume(int ind) const
|
||||
{
|
||||
//--- check pointer
|
||||
if(m_tick_volume==NULL)
|
||||
return(0);
|
||||
//--- return the result
|
||||
return(m_tick_volume.GetData(ind));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data of the RealVolume timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
long CExpertBase::RealVolume(int ind) const
|
||||
{
|
||||
//--- check pointer
|
||||
if(m_real_volume==NULL)
|
||||
return(0);
|
||||
//--- return the result
|
||||
return(m_real_volume.GetData(ind));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of the Open timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::InitOpen(CIndicators *indicators)
|
||||
{
|
||||
//--- create object
|
||||
if((m_open=new CiOpen)==NULL)
|
||||
{
|
||||
Print(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(m_open))
|
||||
{
|
||||
Print(__FUNCTION__+": error adding object");
|
||||
delete m_open;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_open.Create(m_symbol.Name(),m_period))
|
||||
{
|
||||
Print(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of the High timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::InitHigh(CIndicators *indicators)
|
||||
{
|
||||
//--- create object
|
||||
if((m_high=new CiHigh)==NULL)
|
||||
{
|
||||
Print(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(m_high))
|
||||
{
|
||||
Print(__FUNCTION__+": error adding object");
|
||||
delete m_high;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_high.Create(m_symbol.Name(),m_period))
|
||||
{
|
||||
Print(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of the Low timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::InitLow(CIndicators *indicators)
|
||||
{
|
||||
//--- create object
|
||||
if((m_low=new CiLow)==NULL)
|
||||
{
|
||||
Print(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(m_low))
|
||||
{
|
||||
Print(__FUNCTION__+": error adding object");
|
||||
delete m_low;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_low.Create(m_symbol.Name(),m_period))
|
||||
{
|
||||
Print(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of the Close timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::InitClose(CIndicators *indicators)
|
||||
{
|
||||
//--- create object
|
||||
if((m_close=new CiClose)==NULL)
|
||||
{
|
||||
Print(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(m_close))
|
||||
{
|
||||
Print(__FUNCTION__+": error adding object");
|
||||
delete m_close;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_close.Create(m_symbol.Name(),m_period))
|
||||
{
|
||||
Print(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of the Spread timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::InitSpread(CIndicators *indicators)
|
||||
{
|
||||
//--- create object
|
||||
if((m_spread=new CiSpread)==NULL)
|
||||
{
|
||||
Print(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(m_spread))
|
||||
{
|
||||
Print(__FUNCTION__+": error adding object");
|
||||
delete m_spread;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_spread.Create(m_symbol.Name(),m_period))
|
||||
{
|
||||
Print(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of the Time timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::InitTime(CIndicators *indicators)
|
||||
{
|
||||
//--- create object
|
||||
if((m_time=new CiTime)==NULL)
|
||||
{
|
||||
Print(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(m_time))
|
||||
{
|
||||
Print(__FUNCTION__+": error adding object");
|
||||
delete m_time;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_time.Create(m_symbol.Name(),m_period))
|
||||
{
|
||||
Print(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of the TickVolume timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::InitTickVolume(CIndicators *indicators)
|
||||
{
|
||||
//--- create object
|
||||
if((m_tick_volume=new CiTickVolume)==NULL)
|
||||
{
|
||||
Print(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(m_tick_volume))
|
||||
{
|
||||
Print(__FUNCTION__+": error adding object");
|
||||
delete m_tick_volume;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_tick_volume.Create(m_symbol.Name(),m_period))
|
||||
{
|
||||
Print(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of the RealVolume timeseries. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertBase::InitRealVolume(CIndicators *indicators)
|
||||
{
|
||||
//--- create object
|
||||
if((m_real_volume=new CiRealVolume)==NULL)
|
||||
{
|
||||
Print(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(m_real_volume))
|
||||
{
|
||||
Print(__FUNCTION__+": error adding object");
|
||||
delete m_real_volume;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_real_volume.Create(m_symbol.Name(),m_period))
|
||||
{
|
||||
Print(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,124 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ExpertMoney.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ExpertBase.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CExpertMoney. |
|
||||
//| Purpose: Base class money managment. |
|
||||
//| Derives from class CExpertBase. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CExpertMoney : public CExpertBase
|
||||
{
|
||||
protected:
|
||||
//--- input parameters
|
||||
double m_percent;
|
||||
|
||||
public:
|
||||
CExpertMoney(void);
|
||||
~CExpertMoney(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void Percent(double percent) { m_percent=percent; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings();
|
||||
//---
|
||||
virtual double CheckOpenLong(double price,double sl);
|
||||
virtual double CheckOpenShort(double price,double sl);
|
||||
virtual double CheckReverse(CPositionInfo *position,double sl);
|
||||
virtual double CheckClose(CPositionInfo *position);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CExpertMoney::CExpertMoney(void) : m_percent(10.0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CExpertMoney::~CExpertMoney(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertMoney::ValidationSettings()
|
||||
{
|
||||
if(!CExpertBase::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_percent<0.0 || m_percent>100.0)
|
||||
{
|
||||
printf(__FUNCTION__+": percentage of risk should be in the range from 0 to 100 inclusive");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for open long position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CExpertMoney::CheckOpenLong(double price,double sl)
|
||||
{
|
||||
if(m_symbol==NULL)
|
||||
return(0.0);
|
||||
//---
|
||||
double lot;
|
||||
if(price==0.0)
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,m_symbol.Ask(),m_percent);
|
||||
else
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,price,m_percent);
|
||||
if(lot<m_symbol.LotsMin())
|
||||
return(0.0);
|
||||
//---
|
||||
return(m_symbol.LotsMin());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for open short position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CExpertMoney::CheckOpenShort(double price,double sl)
|
||||
{
|
||||
if(m_symbol==NULL)
|
||||
return(0.0);
|
||||
//---
|
||||
double lot;
|
||||
if(price==0.0)
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,m_symbol.Bid(),m_percent);
|
||||
else
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,price,m_percent);
|
||||
if(lot<m_symbol.LotsMin())
|
||||
return(0.0);
|
||||
//---
|
||||
return(m_symbol.LotsMin());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for reverse. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CExpertMoney::CheckReverse(CPositionInfo *position,double sl)
|
||||
{
|
||||
double lots=0.0;
|
||||
//---
|
||||
if(position.PositionType()==POSITION_TYPE_BUY)
|
||||
lots=CheckOpenShort(m_symbol.Bid(),sl);
|
||||
if(position.PositionType()==POSITION_TYPE_SELL)
|
||||
lots=CheckOpenLong(m_symbol.Ask(),sl);
|
||||
//---
|
||||
if(lots!=0.0) lots+=position.Volume();
|
||||
//---
|
||||
return(lots);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for close. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CExpertMoney::CheckClose(CPositionInfo *position)
|
||||
{
|
||||
if(m_percent==0.0)
|
||||
return(0.0);
|
||||
//---
|
||||
if(-position.Profit()>m_account.Balance()*m_percent/100.0)
|
||||
return(position.Volume());
|
||||
//---
|
||||
return(0.0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,464 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ExpertSignal.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ExpertBase.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Macro definitions. |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- check if a market model is used
|
||||
#define IS_PATTERN_USAGE(p) ((m_patterns_usage&(((int)1)<<p))!=0)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CExpertSignal. |
|
||||
//| Purpose: Base class trading signals. |
|
||||
//| Derives from class CExpertBase. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CExpertSignal : public CExpertBase
|
||||
{
|
||||
protected:
|
||||
//--- variables
|
||||
double m_base_price; // base price for detection of level of entering (and/or exit?)
|
||||
//--- variables for working with additional filters
|
||||
CArrayObj m_filters; // array of additional filters (maximum number of fileter is 64)
|
||||
//--- Adjusted parameters
|
||||
double m_weight; // "weight" of a signal in a combined filter
|
||||
int m_patterns_usage; // bit mask of using of the market models of signals
|
||||
int m_general; // index of the "main" signal (-1 - no)
|
||||
long m_ignore; // bit mask of "ignoring" the additional filter
|
||||
long m_invert; // bit mask of "inverting" the additional filter
|
||||
int m_threshold_open; // threshold value for opening
|
||||
int m_threshold_close;// threshold level for closing
|
||||
double m_price_level; // level of placing a pending orders relatively to the base price
|
||||
double m_stop_level; // level of placing of the "stop loss" order relatively to the open price
|
||||
double m_take_level; // level of placing of the "take profit" order relatively to the open price
|
||||
int m_expiration; // time of expiration of a pending order in bars
|
||||
double m_direction; // weighted direction
|
||||
|
||||
public:
|
||||
CExpertSignal(void);
|
||||
~CExpertSignal(void);
|
||||
//--- methods of access to protected data
|
||||
void BasePrice(double value) { m_base_price=value; }
|
||||
int UsedSeries(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void Weight(double value) { m_weight=value; }
|
||||
void PatternsUsage(int value) { m_patterns_usage=value; }
|
||||
void General(int value) { m_general=value; }
|
||||
void Ignore(long value) { m_ignore=value; }
|
||||
void Invert(long value) { m_invert=value; }
|
||||
void ThresholdOpen(int value) { m_threshold_open=value; }
|
||||
void ThresholdClose(int value) { m_threshold_close=value; }
|
||||
void PriceLevel(double value) { m_price_level=value; }
|
||||
void StopLevel(double value) { m_stop_level=value; }
|
||||
void TakeLevel(double value) { m_take_level=value; }
|
||||
void Expiration(int value) { m_expiration=value; }
|
||||
//--- method of initialization of the object
|
||||
void Magic(ulong value);
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods for working with additional filters
|
||||
virtual bool AddFilter(CExpertSignal *filter);
|
||||
//--- methods for generating signals of entering the market
|
||||
virtual bool CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration);
|
||||
virtual bool CheckOpenShort(double &price,double &sl,double &tp,datetime &expiration);
|
||||
//--- methods for detection of levels of entering the market
|
||||
virtual bool OpenLongParams(double &price,double &sl,double &tp,datetime &expiration);
|
||||
virtual bool OpenShortParams(double &price,double &sl,double &tp,datetime &expiration);
|
||||
//--- methods for generating signals of exit from the market
|
||||
virtual bool CheckCloseLong(double &price);
|
||||
virtual bool CheckCloseShort(double &price);
|
||||
//--- methods for detection of levels of exit from the market
|
||||
virtual bool CloseLongParams(double &price);
|
||||
virtual bool CloseShortParams(double &price);
|
||||
//--- methods for generating signals of reversal of positions
|
||||
virtual bool CheckReverseLong(double &price,double &sl,double &tp,datetime &expiration);
|
||||
virtual bool CheckReverseShort(double &price,double &sl,double &tp,datetime &expiration);
|
||||
//--- methods for generating signals of modification of pending orders
|
||||
virtual bool CheckTrailingOrderLong(COrderInfo *order,double &price) { return(false); }
|
||||
virtual bool CheckTrailingOrderShort(COrderInfo *order,double &price) { return(false); }
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void) { return(0); }
|
||||
virtual int ShortCondition(void) { return(0); }
|
||||
virtual double Direction(void);
|
||||
void SetDirection(void) { m_direction=Direction(); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CExpertSignal::CExpertSignal(void) : m_base_price(0.0),
|
||||
m_general(-1), // no "main" signal
|
||||
m_weight(1.0),
|
||||
m_patterns_usage(-1), // all models are used
|
||||
m_ignore(0), // all additional filters are used
|
||||
m_invert(0),
|
||||
m_threshold_open(50),
|
||||
m_threshold_close(100),
|
||||
m_price_level(0.0),
|
||||
m_stop_level(0.0),
|
||||
m_take_level(0.0),
|
||||
m_expiration(0),
|
||||
m_direction(EMPTY_VALUE)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CExpertSignal::~CExpertSignal(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get flags of used timeseries |
|
||||
//+------------------------------------------------------------------+
|
||||
int CExpertSignal::UsedSeries(void)
|
||||
{
|
||||
if(m_other_symbol || m_other_period)
|
||||
return(0);
|
||||
//--- check of the flags of using timeseries in the additional filters
|
||||
int total=m_filters.Total();
|
||||
//--- loop by the additional filters
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CExpertSignal *filter=m_filters.At(i);
|
||||
//--- check pointer
|
||||
if(filter==NULL)
|
||||
return(false);
|
||||
m_used_series|=filter.UsedSeries();
|
||||
}
|
||||
//---
|
||||
return(m_used_series);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets magic number for object and its dependent objects |
|
||||
//+------------------------------------------------------------------+
|
||||
void CExpertSignal::Magic(ulong value)
|
||||
{
|
||||
int total=m_filters.Total();
|
||||
//--- loop by the additional filters
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CExpertSignal *filter=m_filters.At(i);
|
||||
//--- check pointer
|
||||
if(filter==NULL)
|
||||
continue;
|
||||
filter.Magic(value);
|
||||
}
|
||||
//---
|
||||
CExpertBase::Magic(value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::ValidationSettings(void)
|
||||
{
|
||||
if(!CExpertBase::ValidationSettings())
|
||||
return(false);
|
||||
//--- check of parameters in the additional filters
|
||||
int total=m_filters.Total();
|
||||
//--- loop by the additional filters
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CExpertSignal *filter=m_filters.At(i);
|
||||
//--- check pointer
|
||||
if(filter==NULL)
|
||||
return(false);
|
||||
if(!filter.ValidationSettings())
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//---
|
||||
CExpertSignal *filter;
|
||||
int total=m_filters.Total();
|
||||
//--- gather information about using of timeseries
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
filter=m_filters.At(i);
|
||||
m_used_series|=filter.UsedSeries();
|
||||
}
|
||||
//--- create required timeseries
|
||||
if(!CExpertBase::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries in the additional filters
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
filter=m_filters.At(i);
|
||||
filter.SetPriceSeries(m_open,m_high,m_low,m_close);
|
||||
filter.SetOtherSeries(m_spread,m_time,m_tick_volume,m_real_volume);
|
||||
if(!filter.InitIndicators(indicators))
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Setting an additional filter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::AddFilter(CExpertSignal *filter)
|
||||
{
|
||||
//--- check pointer
|
||||
if(filter==NULL)
|
||||
return(false);
|
||||
//--- primary initialization of the filter
|
||||
if(!filter.Init(m_symbol,m_period,m_adjusted_point))
|
||||
return(false);
|
||||
//--- add the filter to the array of filters
|
||||
if(!m_filters.Add(filter))
|
||||
return(false);
|
||||
filter.EveryTick(m_every_tick);
|
||||
filter.Magic(m_magic);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Generating a buy signal |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration)
|
||||
{
|
||||
bool result =false;
|
||||
//--- the "prohibition" signal
|
||||
if(m_direction==EMPTY_VALUE)
|
||||
return(false);
|
||||
//--- check of exceeding the threshold value
|
||||
if(m_direction>=m_threshold_open)
|
||||
{
|
||||
//--- there's a signal
|
||||
result=true;
|
||||
//--- try to get the levels of opening
|
||||
if(!OpenLongParams(price,sl,tp,expiration))
|
||||
result=false;
|
||||
}
|
||||
//--- zeroize the base price
|
||||
m_base_price=0.0;
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Generating a sell signal |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::CheckOpenShort(double &price,double &sl,double &tp,datetime &expiration)
|
||||
{
|
||||
bool result =false;
|
||||
//--- the "prohibition" signal
|
||||
if(m_direction==EMPTY_VALUE)
|
||||
return(false);
|
||||
//--- check of exceeding the threshold value
|
||||
if(-m_direction>=m_threshold_open)
|
||||
{
|
||||
//--- there's a signal
|
||||
result=true;
|
||||
//--- try to get the levels of opening
|
||||
if(!OpenShortParams(price,sl,tp,expiration))
|
||||
result=false;
|
||||
}
|
||||
//--- zeroize the base price
|
||||
m_base_price=0.0;
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detecting the levels for buying |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::OpenLongParams(double &price,double &sl,double &tp,datetime &expiration)
|
||||
{
|
||||
CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL;
|
||||
//---
|
||||
if(general==NULL)
|
||||
{
|
||||
//--- if a base price is not specified explicitly, take the current market price
|
||||
double base_price=(m_base_price==0.0) ? m_symbol.Ask() : m_base_price;
|
||||
price =m_symbol.NormalizePrice(base_price-m_price_level*PriceLevelUnit());
|
||||
sl =(m_stop_level==0.0) ? 0.0 : m_symbol.NormalizePrice(price-m_stop_level*PriceLevelUnit());
|
||||
tp =(m_take_level==0.0) ? 0.0 : m_symbol.NormalizePrice(price+m_take_level*PriceLevelUnit());
|
||||
expiration+=m_expiration*PeriodSeconds(m_period);
|
||||
return(true);
|
||||
}
|
||||
//---
|
||||
return(general.OpenLongParams(price,sl,tp,expiration));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detecting the levels for selling |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::OpenShortParams(double &price,double &sl,double &tp,datetime &expiration)
|
||||
{
|
||||
CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL;
|
||||
//---
|
||||
if(general==NULL)
|
||||
{
|
||||
//--- if a base price is not specified explicitly, take the current market price
|
||||
double base_price=(m_base_price==0.0) ? m_symbol.Bid() : m_base_price;
|
||||
price =m_symbol.NormalizePrice(base_price+m_price_level*PriceLevelUnit());
|
||||
sl =(m_stop_level==0.0) ? 0.0 : m_symbol.NormalizePrice(price+m_stop_level*PriceLevelUnit());
|
||||
tp =(m_take_level==0.0) ? 0.0 : m_symbol.NormalizePrice(price-m_take_level*PriceLevelUnit());
|
||||
expiration+=m_expiration*PeriodSeconds(m_period);
|
||||
return(true);
|
||||
}
|
||||
//---
|
||||
return(general.OpenShortParams(price,sl,tp,expiration));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Generating a signal for closing of a long position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::CheckCloseLong(double &price)
|
||||
{
|
||||
bool result =false;
|
||||
//--- the "prohibition" signal
|
||||
if(m_direction==EMPTY_VALUE)
|
||||
return(false);
|
||||
//--- check of exceeding the threshold value
|
||||
if(-m_direction>=m_threshold_close)
|
||||
{
|
||||
//--- there's a signal
|
||||
result=true;
|
||||
//--- try to get the level of closing
|
||||
if(!CloseLongParams(price))
|
||||
result=false;
|
||||
}
|
||||
//--- zeroize the base price
|
||||
m_base_price=0.0;
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Generating a signal for closing a short position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::CheckCloseShort(double &price)
|
||||
{
|
||||
bool result =false;
|
||||
//--- the "prohibition" signal
|
||||
if(m_direction==EMPTY_VALUE)
|
||||
return(false);
|
||||
//--- check of exceeding the threshold value
|
||||
if(m_direction>=m_threshold_close)
|
||||
{
|
||||
//--- there's a signal
|
||||
result=true;
|
||||
//--- try to get the level of closing
|
||||
if(!CloseShortParams(price))
|
||||
result=false;
|
||||
}
|
||||
//--- zeroize the base price
|
||||
m_base_price=0.0;
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detecting the levels for closing a long position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::CloseLongParams(double &price)
|
||||
{
|
||||
CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL;
|
||||
//---
|
||||
if(general==NULL)
|
||||
{
|
||||
//--- if a base price is not specified explicitly, take the current market price
|
||||
price=(m_base_price==0.0) ? m_symbol.Bid() : m_base_price;
|
||||
return(true);
|
||||
}
|
||||
//---
|
||||
return(general.CloseLongParams(price));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detecting the levels for closing a short position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::CloseShortParams(double &price)
|
||||
{
|
||||
CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL;
|
||||
//---
|
||||
if(general==NULL)
|
||||
{
|
||||
//--- if a base price is not specified explicitly, take the current market price
|
||||
price=(m_base_price==0.0)?m_symbol.Ask():m_base_price;
|
||||
return(true);
|
||||
}
|
||||
//--- ok
|
||||
return(general.CloseShortParams(price));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Generating a signal for reversing a long position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::CheckReverseLong(double &price,double &sl,double &tp,datetime &expiration)
|
||||
{
|
||||
double c_price;
|
||||
//--- check the signal of closing a long position
|
||||
if(!CheckCloseLong(c_price))
|
||||
return(false);
|
||||
//--- check the signal of opening a short position
|
||||
if(!CheckOpenShort(price,sl,tp,expiration))
|
||||
return(false);
|
||||
//--- difference between the close and open prices must not exceed two spreads
|
||||
if(c_price!=price)
|
||||
return(false);
|
||||
//--- there's a signal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Generating a signal for reversing a short position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertSignal::CheckReverseShort(double &price,double &sl,double &tp,datetime &expiration)
|
||||
{
|
||||
double c_price;
|
||||
//--- check the signal of closing a short position
|
||||
if(!CheckCloseShort(c_price))
|
||||
return(false);
|
||||
//--- check the signal of opening a long position
|
||||
if(!CheckOpenLong(price,sl,tp,expiration))
|
||||
return(false);
|
||||
//--- difference between the close and open prices must not exceed two spreads
|
||||
if(c_price!=price)
|
||||
return(false);
|
||||
//--- there's a signal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detecting the "weighted" direction |
|
||||
//+------------------------------------------------------------------+
|
||||
double CExpertSignal::Direction(void)
|
||||
{
|
||||
long mask;
|
||||
double direction;
|
||||
double result=m_weight*(LongCondition()-ShortCondition());
|
||||
int number=(result==0.0)? 0 : 1; // number of "voted"
|
||||
//---
|
||||
int total=m_filters.Total();
|
||||
//--- loop by filters
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
//--- mask for bit maps
|
||||
mask=((long)1)<<i;
|
||||
//--- check of the flag of ignoring the signal of filter
|
||||
if((m_ignore&mask)!=0)
|
||||
continue;
|
||||
CExpertSignal *filter=m_filters.At(i);
|
||||
//--- check pointer
|
||||
if(filter==NULL)
|
||||
continue;
|
||||
direction=filter.Direction();
|
||||
//--- the "prohibition" signal
|
||||
if(direction==EMPTY_VALUE)
|
||||
return(EMPTY_VALUE);
|
||||
//--- check of flag of inverting the signal of filter
|
||||
if((m_invert&mask)!=0)
|
||||
result-=direction;
|
||||
else
|
||||
result+=direction;
|
||||
number++;
|
||||
}
|
||||
//--- normalization
|
||||
if(number!=0)
|
||||
result/=number;
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,171 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ExpertTrade.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Trade\SymbolInfo.mqh>
|
||||
#include <Trade\PositionInfo.mqh>
|
||||
#include <Trade\OrderInfo.mqh>
|
||||
#include <Trade\AccountInfo.mqh>
|
||||
#include <Trade\Trade.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CExpertTrade. |
|
||||
//| Appointment: Class simple trade operations. |
|
||||
//| Derives from class CTrade. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CExpertTrade : public CTrade
|
||||
{
|
||||
protected:
|
||||
ENUM_ORDER_TYPE_TIME m_order_type_time;
|
||||
datetime m_order_expiration;
|
||||
CSymbolInfo *m_symbol; // symbol object
|
||||
CAccountInfo m_account; // account object
|
||||
|
||||
public:
|
||||
CExpertTrade(void);
|
||||
~CExpertTrade(void);
|
||||
//--- methods for easy trade
|
||||
bool SetSymbol(CSymbolInfo *symbol);
|
||||
bool SetOrderTypeTime(ENUM_ORDER_TYPE_TIME order_type_time);
|
||||
bool SetOrderExpiration(datetime order_expiration);
|
||||
bool Buy(double volume,double price,double sl,double tp,const string comment="");
|
||||
bool Sell(double volume,double price,double sl,double tp,const string comment="");
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CExpertTrade::CExpertTrade(void) : m_symbol(NULL),
|
||||
m_order_type_time(ORDER_TIME_GTC),
|
||||
m_order_expiration(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CExpertTrade::~CExpertTrade(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Setting working symbol for easy trade operations. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertTrade::SetSymbol(CSymbolInfo *symbol)
|
||||
{
|
||||
if(symbol!=NULL)
|
||||
{
|
||||
m_symbol=symbol;
|
||||
return(true);
|
||||
}
|
||||
//---
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Setting order expiration type for easy trade operations |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertTrade::SetOrderTypeTime(ENUM_ORDER_TYPE_TIME order_type_time)
|
||||
{
|
||||
if(m_symbol==NULL)
|
||||
return(false);
|
||||
//---
|
||||
if(order_type_time==ORDER_TIME_SPECIFIED)
|
||||
{
|
||||
if((m_symbol.TradeTimeFlags()&SYMBOL_EXPIRATION_SPECIFIED)==0)
|
||||
{
|
||||
m_order_type_time =ORDER_TIME_GTC;
|
||||
m_order_expiration=0;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
//---
|
||||
m_order_type_time=order_type_time;
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Setting order expiration time for easy trade operations |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertTrade::SetOrderExpiration(datetime order_expiration)
|
||||
{
|
||||
if(m_symbol==NULL)
|
||||
return(false);
|
||||
//--- check expiration
|
||||
if(order_expiration>=TimeCurrent()+60)
|
||||
{
|
||||
if(!SetOrderTypeTime(ORDER_TIME_SPECIFIED))
|
||||
return(false);
|
||||
m_order_expiration=order_expiration;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_order_type_time=ORDER_TIME_GTC;
|
||||
m_order_expiration=0;
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Easy LONG trade operation |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertTrade::Buy(double volume,double price,double sl,double tp,const string comment="")
|
||||
{
|
||||
double ask,stops_level;
|
||||
//--- checking
|
||||
if(m_symbol==NULL)
|
||||
return(false);
|
||||
string symbol=m_symbol.Name();
|
||||
if(symbol=="")
|
||||
return(false);
|
||||
//---
|
||||
ask=m_symbol.Ask();
|
||||
stops_level=m_symbol.StopsLevel()*m_symbol.Point();
|
||||
if(price!=0.0)
|
||||
{
|
||||
if(price>ask+stops_level)
|
||||
{
|
||||
//--- send "BUY_STOP" order
|
||||
return(OrderOpen(symbol,ORDER_TYPE_BUY_STOP,volume,0.0,price,sl,tp,
|
||||
m_order_type_time,m_order_expiration,comment));
|
||||
}
|
||||
if(price<ask-stops_level)
|
||||
{
|
||||
//--- send "BUY_LIMIT" order
|
||||
return(OrderOpen(symbol,ORDER_TYPE_BUY_LIMIT,volume,0.0,price,sl,tp,
|
||||
m_order_type_time,m_order_expiration,comment));
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(PositionOpen(symbol,ORDER_TYPE_BUY,volume,ask,sl,tp,comment));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Easy SHORT trade operation |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CExpertTrade::Sell(double volume,double price,double sl,double tp,const string comment="")
|
||||
{
|
||||
double bid,stops_level;
|
||||
//--- checking
|
||||
if(m_symbol==NULL)
|
||||
return(false);
|
||||
string symbol=m_symbol.Name();
|
||||
if(symbol=="")
|
||||
return(false);
|
||||
//---
|
||||
bid=m_symbol.Bid();
|
||||
stops_level=m_symbol.StopsLevel()*m_symbol.Point();
|
||||
if(price!=0.0)
|
||||
{
|
||||
if(price>bid+stops_level)
|
||||
{
|
||||
//--- send "SELL_LIMIT" order
|
||||
return(OrderOpen(symbol,ORDER_TYPE_SELL_LIMIT,volume,0.0,price,sl,tp,
|
||||
m_order_type_time,m_order_expiration,comment));
|
||||
}
|
||||
if(price<bid-stops_level)
|
||||
{
|
||||
//--- send "SELL_STOP" order
|
||||
return(OrderOpen(symbol,ORDER_TYPE_SELL_STOP,volume,0.0,price,sl,tp,
|
||||
m_order_type_time,m_order_expiration,comment));
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(PositionOpen(symbol,ORDER_TYPE_SELL,volume,bid,sl,tp,comment));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,33 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ExpertTrailing.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ExpertBase.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CExpertTrailing. |
|
||||
//| Purpose: Base class traling stops. |
|
||||
//| Derives from class CExpertBase. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CExpertTrailing : public CExpertBase
|
||||
{
|
||||
public:
|
||||
CExpertTrailing(void);
|
||||
~CExpertTrailing(void);
|
||||
//---
|
||||
virtual bool CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp) { return(false); }
|
||||
virtual bool CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp) { return(false); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CExpertTrailing::CExpertTrailing(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CExpertTrailing::~CExpertTrailing(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,73 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MoneyFixedLot.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertMoney.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Trading with fixed trade volume |
|
||||
//| Type=Money |
|
||||
//| Name=FixLot |
|
||||
//| Class=CMoneyFixedLot |
|
||||
//| Page= |
|
||||
//| Parameter=Percent,double,10.0,Percent |
|
||||
//| Parameter=Lots,double,0.1,Fixed volume |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CMoneyFixedLot. |
|
||||
//| Purpose: Class of money management with fixed lot. |
|
||||
//| Derives from class CExpertMoney. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CMoneyFixedLot : public CExpertMoney
|
||||
{
|
||||
protected:
|
||||
//--- input parameters
|
||||
double m_lots;
|
||||
|
||||
public:
|
||||
CMoneyFixedLot(void);
|
||||
~CMoneyFixedLot(void);
|
||||
//---
|
||||
void Lots(double lots) { m_lots=lots; }
|
||||
virtual bool ValidationSettings(void);
|
||||
//---
|
||||
virtual double CheckOpenLong(double price,double sl) { return(m_lots); }
|
||||
virtual double CheckOpenShort(double price,double sl) { return(m_lots); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CMoneyFixedLot::CMoneyFixedLot(void) : m_lots(0.1)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CMoneyFixedLot::~CMoneyFixedLot(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CMoneyFixedLot::ValidationSettings(void)
|
||||
{
|
||||
if(!CExpertMoney::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_lots<m_symbol.LotsMin() || m_lots>m_symbol.LotsMax())
|
||||
{
|
||||
printf(__FUNCTION__+": lots amount must be in the range from %f to %f",m_symbol.LotsMin(),m_symbol.LotsMax());
|
||||
return(false);
|
||||
}
|
||||
if(MathAbs(m_lots/m_symbol.LotsStep()-MathRound(m_lots/m_symbol.LotsStep()))>1.0E-10)
|
||||
{
|
||||
printf(__FUNCTION__+": lots amount is not corresponding with lot step %f",m_symbol.LotsStep());
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,76 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MoneyFixedMargin.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertMoney.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Trading with fixed margin |
|
||||
//| Type=Money |
|
||||
//| Name=FixMargin |
|
||||
//| Class=CMoneyFixedMargin |
|
||||
//| Page= |
|
||||
//| Parameter=Percent,double,10.0,Percentage of margin |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CMoneyFixedMargin. |
|
||||
//| Purpose: Class of money management with fixed percent margin. |
|
||||
//| Derives from class CExpertMoney. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CMoneyFixedMargin : public CExpertMoney
|
||||
{
|
||||
public:
|
||||
CMoneyFixedMargin(void);
|
||||
~CMoneyFixedMargin(void);
|
||||
//---
|
||||
virtual double CheckOpenLong(double price,double sl);
|
||||
virtual double CheckOpenShort(double price,double sl);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CMoneyFixedMargin::CMoneyFixedMargin(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CMoneyFixedMargin::~CMoneyFixedMargin(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for open long position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CMoneyFixedMargin::CheckOpenLong(double price,double sl)
|
||||
{
|
||||
if(m_symbol==NULL)
|
||||
return(0.0);
|
||||
//--- select lot size
|
||||
double lot;
|
||||
if(price==0.0)
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,m_symbol.Ask(),m_percent);
|
||||
else
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,price,m_percent);
|
||||
//--- return trading volume
|
||||
return(lot);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for open short position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CMoneyFixedMargin::CheckOpenShort(double price,double sl)
|
||||
{
|
||||
if(m_symbol==NULL)
|
||||
return(0.0);
|
||||
//--- select lot size
|
||||
double lot;
|
||||
if(price==0.0)
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,m_symbol.Bid(),m_percent);
|
||||
else
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,price,m_percent);
|
||||
//--- return trading volume
|
||||
return(lot);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,109 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MoneyFixedRisk.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertMoney.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Trading with fixed risk |
|
||||
//| Type=Money |
|
||||
//| Name=FixRisk |
|
||||
//| Class=CMoneyFixedRisk |
|
||||
//| Page= |
|
||||
//| Parameter=Percent,double,10.0,Risk percentage |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CMoneyFixedRisk. |
|
||||
//| Purpose: Class of money management with fixed percent risk. |
|
||||
//| Derives from class CExpertMoney. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CMoneyFixedRisk : public CExpertMoney
|
||||
{
|
||||
public:
|
||||
CMoneyFixedRisk(void);
|
||||
~CMoneyFixedRisk(void);
|
||||
//---
|
||||
virtual double CheckOpenLong(double price,double sl);
|
||||
virtual double CheckOpenShort(double price,double sl);
|
||||
virtual double CheckClose(CPositionInfo *position) { return(0.0); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CMoneyFixedRisk::CMoneyFixedRisk(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CMoneyFixedRisk::~CMoneyFixedRisk(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for open long position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CMoneyFixedRisk::CheckOpenLong(double price,double sl)
|
||||
{
|
||||
if(m_symbol==NULL)
|
||||
return(0.0);
|
||||
//--- select lot size
|
||||
double lot;
|
||||
double minvol=m_symbol.LotsMin();
|
||||
if(sl==0.0)
|
||||
lot=minvol;
|
||||
else
|
||||
{
|
||||
double loss;
|
||||
if(price==0.0)
|
||||
loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_BUY,1.0,m_symbol.Ask(),sl);
|
||||
else
|
||||
loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_BUY,1.0,price,sl);
|
||||
double stepvol=m_symbol.LotsStep();
|
||||
lot=MathFloor(m_account.Balance()*m_percent/loss/100.0/stepvol)*stepvol;
|
||||
}
|
||||
//---
|
||||
if(lot<minvol)
|
||||
lot=minvol;
|
||||
//---
|
||||
double maxvol=m_symbol.LotsMax();
|
||||
if(lot>maxvol)
|
||||
lot=maxvol;
|
||||
//--- return trading volume
|
||||
return(lot);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for open short position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CMoneyFixedRisk::CheckOpenShort(double price,double sl)
|
||||
{
|
||||
if(m_symbol==NULL)
|
||||
return(0.0);
|
||||
//--- select lot size
|
||||
double lot;
|
||||
double minvol=m_symbol.LotsMin();
|
||||
if(sl==0.0)
|
||||
lot=minvol;
|
||||
else
|
||||
{
|
||||
double loss;
|
||||
if(price==0.0)
|
||||
loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_SELL,1.0,m_symbol.Bid(),sl);
|
||||
else
|
||||
loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_SELL,1.0,price,sl);
|
||||
double stepvol=m_symbol.LotsStep();
|
||||
lot=MathFloor(m_account.Balance()*m_percent/loss/100.0/stepvol)*stepvol;
|
||||
}
|
||||
//---
|
||||
if(lot<minvol)
|
||||
lot=minvol;
|
||||
//---
|
||||
double maxvol=m_symbol.LotsMax();
|
||||
if(lot>maxvol)
|
||||
lot=maxvol;
|
||||
//--- return trading volume
|
||||
return(lot);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,71 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MoneyNone.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertMoney.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Trading with minimal allowed trade volume |
|
||||
//| Type=Money |
|
||||
//| Name=MinLot |
|
||||
//| Class=CMoneyNone |
|
||||
//| Page= |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CMoneyNone. |
|
||||
//| Appointment: Class no money managment. |
|
||||
//| Derives from class CExpertMoney. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CMoneyNone : public CExpertMoney
|
||||
{
|
||||
public:
|
||||
CMoneyNone(void);
|
||||
~CMoneyNone(void);
|
||||
//---
|
||||
virtual bool ValidationSettings(void);
|
||||
//---
|
||||
virtual double CheckOpenLong(double price,double sl);
|
||||
virtual double CheckOpenShort(double price,double sl);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CMoneyNone::CMoneyNone(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CMoneyNone::~CMoneyNone(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CMoneyNone::ValidationSettings(void)
|
||||
{
|
||||
Percent(100.0);
|
||||
//--- initial data checks
|
||||
if(!CExpertMoney::ValidationSettings())
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for open long position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CMoneyNone::CheckOpenLong(double price,double sl)
|
||||
{
|
||||
return(m_symbol.LotsMin());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for open short position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CMoneyNone::CheckOpenShort(double price,double sl)
|
||||
{
|
||||
return(m_symbol.LotsMin());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,155 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MoneySizeOptimized.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertMoney.mqh>
|
||||
#include <Trade\DealInfo.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Trading with optimized trade volume |
|
||||
//| Type=Money |
|
||||
//| Name=SizeOptimized |
|
||||
//| Class=CMoneySizeOptimized |
|
||||
//| Page= |
|
||||
//| Parameter=DecreaseFactor,double,3.0,Decrease factor |
|
||||
//| Parameter=Percent,double,10.0,Percent |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CMoneySizeOptimized. |
|
||||
//| Purpose: Class of money management with size optimized. |
|
||||
//| Derives from class CExpertMoney. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CMoneySizeOptimized : public CExpertMoney
|
||||
{
|
||||
protected:
|
||||
double m_decrease_factor;
|
||||
|
||||
public:
|
||||
CMoneySizeOptimized(void);
|
||||
~CMoneySizeOptimized(void);
|
||||
//---
|
||||
void DecreaseFactor(double decrease_factor) { m_decrease_factor=decrease_factor; }
|
||||
virtual bool ValidationSettings(void);
|
||||
//---
|
||||
virtual double CheckOpenLong(double price,double sl);
|
||||
virtual double CheckOpenShort(double price,double sl);
|
||||
|
||||
protected:
|
||||
double Optimize(double lots);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CMoneySizeOptimized::CMoneySizeOptimized(void) : m_decrease_factor(3.0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CMoneySizeOptimized::~CMoneySizeOptimized(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CMoneySizeOptimized::ValidationSettings(void)
|
||||
{
|
||||
if(!CExpertMoney::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_decrease_factor<=0.0)
|
||||
{
|
||||
printf(__FUNCTION__+": decrease factor must be greater then 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for open long position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CMoneySizeOptimized::CheckOpenLong(double price,double sl)
|
||||
{
|
||||
if(m_symbol==NULL)
|
||||
return(0.0);
|
||||
//--- select lot size
|
||||
double lot;
|
||||
if(price==0.0)
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,m_symbol.Ask(),m_percent);
|
||||
else
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,price,m_percent);
|
||||
//--- return trading volume
|
||||
return(Optimize(lot));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Getting lot size for open short position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CMoneySizeOptimized::CheckOpenShort(double price,double sl)
|
||||
{
|
||||
if(m_symbol==NULL)
|
||||
return(0.0);
|
||||
//--- select lot size
|
||||
double lot;
|
||||
if(price==0.0)
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,m_symbol.Bid(),m_percent);
|
||||
else
|
||||
lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,price,m_percent);
|
||||
//--- return trading volume
|
||||
return(Optimize(lot));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Optimizing lot size for open. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CMoneySizeOptimized::Optimize(double lots)
|
||||
{
|
||||
double lot=lots;
|
||||
//--- calculate number of losses orders without a break
|
||||
if(m_decrease_factor>0)
|
||||
{
|
||||
//--- select history for access
|
||||
HistorySelect(0,TimeCurrent());
|
||||
//---
|
||||
int orders=HistoryDealsTotal(); // total history deals
|
||||
int losses=0; // number of consequent losing orders
|
||||
CDealInfo deal;
|
||||
//---
|
||||
for(int i=orders-1;i>=0;i--)
|
||||
{
|
||||
deal.Ticket(HistoryDealGetTicket(i));
|
||||
if(deal.Ticket()==0)
|
||||
{
|
||||
Print("CMoneySizeOptimized::Optimize: HistoryDealGetTicket failed, no trade history");
|
||||
break;
|
||||
}
|
||||
//--- check symbol
|
||||
if(deal.Symbol()!=m_symbol.Name())
|
||||
continue;
|
||||
//--- check profit
|
||||
double profit=deal.Profit();
|
||||
if(profit>0.0)
|
||||
break;
|
||||
if(profit<0.0)
|
||||
losses++;
|
||||
}
|
||||
//---
|
||||
if(losses>1)
|
||||
lot=NormalizeDouble(lot-lot*losses/m_decrease_factor,2);
|
||||
}
|
||||
//--- normalize and check limits
|
||||
double stepvol=m_symbol.LotsStep();
|
||||
lot=stepvol*NormalizeDouble(lot/stepvol,0);
|
||||
//---
|
||||
double minvol=m_symbol.LotsMin();
|
||||
if(lot<minvol)
|
||||
lot=minvol;
|
||||
//---
|
||||
double maxvol=m_symbol.LotsMax();
|
||||
if(lot>maxvol)
|
||||
lot=maxvol;
|
||||
//---
|
||||
return(lot);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,173 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalAC.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of indicator 'Accelerator Oscillator' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Accelerator Oscillator |
|
||||
//| ShortName=AC |
|
||||
//| Class=CSignalAC |
|
||||
//| Page=signal_ac |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalAC. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Accelerator Oscillator' indicator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalAC : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiAC m_ac; // object-indicator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "first analyzed bar has required color"
|
||||
int m_pattern_1; // model 1 "there is a condition for entering the market"
|
||||
int m_pattern_2; // model 2 "condition for entering the market has just appeared"
|
||||
|
||||
public:
|
||||
CSignalAC(void);
|
||||
~CSignalAC(void);
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the indicator
|
||||
bool InitAC(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double AC(int ind) { return(m_ac.Main(ind)); }
|
||||
double DiffAC(int ind) { return(AC(ind)-AC(ind+1)); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalAC::CSignalAC(void) : m_pattern_0(90),
|
||||
m_pattern_1(50),
|
||||
m_pattern_2(30)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalAC::~CSignalAC(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalAC::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize AC indicator
|
||||
if(!InitAC(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize AC indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalAC::InitAC(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_ac)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_ac.Create(m_symbol.Name(),m_period))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalAC::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- if the first analyzed bar is "red", don't "vote" for buying
|
||||
if(DiffAC(idx++)<0.0)
|
||||
return(result);
|
||||
//--- first analyzed bar is "green" (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the second analyzed bar is "red", there is no condition for buying
|
||||
if(DiffAC(idx)<0.0)
|
||||
return(result);
|
||||
//--- second analyzed bar is "green" (the condition for buying may be fulfilled)
|
||||
//--- if the second analyzed bar is less than zero, we need to analyzed the third bar
|
||||
if(AC(idx++)<0.0)
|
||||
{
|
||||
//--- if the third analyzed bar is "red", there is no condition for buying
|
||||
if(DiffAC(idx++)<0.0)
|
||||
return(result);
|
||||
}
|
||||
//--- there is a condition for buying
|
||||
if(IS_PATTERN_USAGE(1))
|
||||
result=m_pattern_1;
|
||||
//--- if the previously analyzed bar is "red", the condition for buying has just been fulfilled
|
||||
if(IS_PATTERN_USAGE(2) && DiffAC(idx)<0.0)
|
||||
result=m_pattern_2;
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalAC::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- if the first analyzed bar is "green", don't "vote" for selling
|
||||
if(DiffAC(idx++)>0.0)
|
||||
return(result);
|
||||
//--- first analyzed bar is "red" (the indicator has no objections to selling)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the second analyzed bar is "green", there is no condition for selling
|
||||
if(DiffAC(idx)>0.0)
|
||||
return(result);
|
||||
//--- second analyzed bar is "red" (the condition for selling may be fulfilled)
|
||||
//--- if the second analyzed bar is greater than zero, we need to analyze the third bar
|
||||
if(AC(idx++)>0.0)
|
||||
{
|
||||
//--- if the third analyzed bar is "green", there is no condition for selling
|
||||
if(DiffAC(idx++)>0.0)
|
||||
return(result);
|
||||
}
|
||||
//--- there us a condition for selling
|
||||
if(IS_PATTERN_USAGE(1))
|
||||
result=m_pattern_1;
|
||||
//--- if the previously analyzed bar is "green", the condition for selling has just been fulfilled
|
||||
if(IS_PATTERN_USAGE(2) && DiffAC(idx)>0.0)
|
||||
result=m_pattern_2;
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,265 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalAMA.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of indicator 'Adaptive Moving Average' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Adaptive Moving Average |
|
||||
//| ShortName=AMA |
|
||||
//| Class=CSignalAMA |
|
||||
//| Page=signal_ama |
|
||||
//| Parameter=PeriodMA,int,10,Period of averaging |
|
||||
//| Parameter=PeriodFast,int,2,Period of fast EMA |
|
||||
//| Parameter=PeriodSlow,int,30,Period of slow EMA |
|
||||
//| Parameter=Shift,int,0,Time shift |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalAMA. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Adaptive Moving Average' indicator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalAMA : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiAMA m_ma; // object-indicator
|
||||
//--- adjusted parameters
|
||||
int m_ma_period; // the "period of averaging" parameter of the indicator
|
||||
int m_period_fast; // the "period of fast EMA" parameter of the indicator
|
||||
int m_period_slow; // the "period of slow EMA" parameter of the indicator
|
||||
int m_ma_shift; // the "time shift" parameter of the indicator
|
||||
ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter" of the indicator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "price is on the necessary side from the indicator"
|
||||
int m_pattern_1; // model 1 "price crossed the indicator with opposite direction"
|
||||
int m_pattern_2; // model 2 "price crossed the indicator with the same direction"
|
||||
int m_pattern_3; // model 3 "piercing"
|
||||
|
||||
public:
|
||||
CSignalAMA(void);
|
||||
~CSignalAMA(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodMA(int value) { m_ma_period=value; }
|
||||
void PeriodFast(int value) { m_period_fast=value; }
|
||||
void PeriodSlow(int value) { m_period_slow=value; }
|
||||
void Shift(int value) { m_ma_shift=value; }
|
||||
void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the indicator
|
||||
bool InitMA(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double MA(int ind) { return(m_ma.Main(ind)); }
|
||||
double DiffMA(int ind) { return(MA(ind)-MA(ind+1)); }
|
||||
double DiffOpenMA(int ind) { return(Open(ind)-MA(ind)); }
|
||||
double DiffHighMA(int ind) { return(High(ind)-MA(ind)); }
|
||||
double DiffLowMA(int ind) { return(Low(ind)-MA(ind)); }
|
||||
double DiffCloseMA(int ind) { return(Close(ind)-MA(ind)); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalAMA::CSignalAMA(void) : m_ma_period(10),
|
||||
m_ma_shift(0),
|
||||
m_period_fast(2),
|
||||
m_period_slow(30),
|
||||
m_ma_applied(PRICE_CLOSE),
|
||||
m_pattern_0(10),
|
||||
m_pattern_1(70),
|
||||
m_pattern_2(100),
|
||||
m_pattern_3(60)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalAMA::~CSignalAMA(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalAMA::ValidationSettings(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_ma_period<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period MA must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalAMA::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize AMA indicator
|
||||
if(!InitMA(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create MA indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalAMA::InitMA(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_ma)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_ma.Create(m_symbol.Name(),m_period,m_ma_period,m_period_fast,m_period_slow,m_ma_shift,m_ma_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalAMA::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- analyze positional relationship of the close price and the indicator at the first analyzed bar
|
||||
if(DiffCloseMA(idx)<0.0)
|
||||
{
|
||||
//--- the close price is below the indicator
|
||||
if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)>0.0 && DiffMA(idx)>0.0)
|
||||
{
|
||||
//--- the open price is above the indicator (i.e. there was an intersection), but the indicator is directed upwards
|
||||
result=m_pattern_1;
|
||||
//--- consider that this is an unformed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- the close price is above the indicator (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the indicator is directed upwards
|
||||
if(DiffMA(idx)>0.0)
|
||||
{
|
||||
if(DiffOpenMA(idx)<0.0)
|
||||
{
|
||||
//--- if the model 2 is used
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- the open price is below the indicator (i.e. there was an intersection)
|
||||
result=m_pattern_2;
|
||||
//--- suggest to enter the market at the "roll back"
|
||||
m_base_price=m_symbol.NormalizePrice(MA(idx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- if the model 3 is used and the open price is above the indicator
|
||||
if(IS_PATTERN_USAGE(3) && DiffLowMA(idx)<0.0)
|
||||
{
|
||||
//--- the low price is below the indicator
|
||||
result=m_pattern_3;
|
||||
//--- consider that this is a formed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalAMA::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- analyze positional relationship of the close price and the indicator at the first analyzed bar
|
||||
if(DiffCloseMA(idx)>0.0)
|
||||
{
|
||||
//--- the close price is above the indicator
|
||||
if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)<0.0 && DiffMA(idx)<0.0)
|
||||
{
|
||||
//--- the open price is below the indicator (i.e. there was an intersection), but the indicator is directed downwards
|
||||
result=m_pattern_1;
|
||||
//--- consider that this is an unformed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- the close price is below the indicator (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- the indicator is directed downwards
|
||||
if(DiffMA(idx)<0.0)
|
||||
{
|
||||
if(DiffOpenMA(idx)>0.0)
|
||||
{
|
||||
//--- if the model 2 is used
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- the open price is above the indicator (i.e. there was an intersection)
|
||||
result=m_pattern_2;
|
||||
//--- suggest to enter the market at the "roll back"
|
||||
m_base_price=m_symbol.NormalizePrice(MA(idx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- if the model 3 is used and the open price is below the indicator
|
||||
if(IS_PATTERN_USAGE(3) && DiffHighMA(idx)>0.0)
|
||||
{
|
||||
//--- the high price is above the indicator
|
||||
result=m_pattern_3;
|
||||
//--- consider that this is a formed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,339 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalAO.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of indicator 'Awesome Oscillator' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Awesome Oscillator |
|
||||
//| ShortName=AO |
|
||||
//| Class=CSignalAO |
|
||||
//| Page=signal_ao |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalAO. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Awesome Oscillator' indicator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalAO : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiAO m_ao; // object-indicator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "first analyzed bar has required color"
|
||||
int m_pattern_1; // model 1 "the 'saucer' signal"
|
||||
int m_pattern_2; // model 2 "the 'crossing of the zero line' signal"
|
||||
int m_pattern_3; // model 2 "the 'divergence' signal"
|
||||
//--- variables
|
||||
double m_extr_osc[10]; // array of values of extremums of the oscillator
|
||||
double m_extr_pr[10]; // array of values of the corresponding extremums of price
|
||||
int m_extr_pos[10]; // array of shifts of extremums (in bars)
|
||||
uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price
|
||||
|
||||
public:
|
||||
CSignalAO(void);
|
||||
~CSignalAO(void);
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the indicator
|
||||
bool InitAO(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double AO(int ind) { return(m_ao.Main(ind)); }
|
||||
double DiffAO(int ind) { return(AO(ind)-AO(ind+1)); }
|
||||
int StateAO(int ind);
|
||||
bool ExtStateAO(int ind);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalAO::CSignalAO(void) : m_pattern_0(30),
|
||||
m_pattern_1(20),
|
||||
m_pattern_2(70),
|
||||
m_pattern_3(90)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalAO::~CSignalAO(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalAO::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize AO indicator
|
||||
if(!InitAO(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize AO indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalAO::InitAO(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_ao)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_ao.Create(m_symbol.Name(),m_period))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check of the indicator state. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalAO::StateAO(int ind)
|
||||
{
|
||||
int res=0;
|
||||
double var;
|
||||
//---
|
||||
for(int i=ind;;i++)
|
||||
{
|
||||
if(AO(i+1)==EMPTY_VALUE)
|
||||
break;
|
||||
var=DiffAO(i);
|
||||
if(res>0)
|
||||
{
|
||||
if(var<0)
|
||||
break;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if(res<0)
|
||||
{
|
||||
if(var>0)
|
||||
break;
|
||||
res--;
|
||||
continue;
|
||||
}
|
||||
if(var>0)
|
||||
res++;
|
||||
if(var<0)
|
||||
res--;
|
||||
}
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Extended check of the oscillator state consists |
|
||||
//| in forming a bit-map according to certain rules, |
|
||||
//| which shows ratios of extremums of the oscillator and price. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalAO::ExtStateAO(int ind)
|
||||
{
|
||||
//--- operation of this method results in a bit-map of extremums
|
||||
//--- practically, the bit-map of extremums is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an element of the analyzed bit-map
|
||||
//--- bit 3 - not used (always 0)
|
||||
//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- bit 1 - not used (always 0)
|
||||
//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- in addition to them, the following is formed:
|
||||
//--- array of values of extremums of the oscillator,
|
||||
//--- array of values of price extremums and
|
||||
//--- array of "distances" between extremums of the oscillator (in bars)
|
||||
//--- it should be noted that when using the results of the extended check of state,
|
||||
//--- you should consider, which extremum of the oscillator (peak or valley)
|
||||
//--- is the "reference point" (i.e. was detected first during the analysis)
|
||||
//--- if a peak is detected first then even elements of all arrays
|
||||
//--- will contain information about peaks, and odd elements will contain information about valleys
|
||||
//--- if a valley is detected first, then respectively in reverse
|
||||
int pos=ind,off,index;
|
||||
uint map; // intermediate bit-map for one extremum
|
||||
//---
|
||||
m_extr_map=0;
|
||||
for(int i=0;i<10;i++)
|
||||
{
|
||||
off=StateAO(pos);
|
||||
if(off>0)
|
||||
{
|
||||
//--- minimum of the oscillator is detected
|
||||
pos+=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=AO(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_low.MinValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]<m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]<m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_low.MinValue(pos-1,4,index);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- maximum of the oscillator is detected
|
||||
pos-=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=AO(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]>m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]>m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-1,4,index);
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalAO::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- if the first analyzed bar is "red", don't "vote" for buying
|
||||
if(DiffAO(idx)<0.0)
|
||||
return(result);
|
||||
//--- first analyzed bar is "green" (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
if(AO(idx++)>0.0)
|
||||
{
|
||||
//--- first analyzed bar is greater than zero, search for the "saucer" and "crosing of the zero line" signals
|
||||
if(IS_PATTERN_USAGE(1) && DiffAO(idx)<0.0)
|
||||
{
|
||||
//--- the "saucer" signal
|
||||
//--- there is a condition for buying
|
||||
return(m_pattern_1);
|
||||
}
|
||||
if(IS_PATTERN_USAGE(2) && AO(idx)<0.0)
|
||||
{
|
||||
//--- the "crossing of the zero line" signal
|
||||
//--- there is a condition for buying
|
||||
return(m_pattern_2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- first analyzed bar is less than zero, search for the "divergence" signal
|
||||
//--- if the second analyzed bar is "red", the condition for buying may be fulfilled
|
||||
if(IS_PATTERN_USAGE(3) && DiffAO(idx)<0.0)
|
||||
{
|
||||
idx=StartIndex();
|
||||
//--- search for the "divergence" signal
|
||||
ExtStateAO(idx);
|
||||
if((m_extr_map&0xF)==1)
|
||||
{
|
||||
if(m_extr_osc[0]<0.0 && m_extr_osc[1]<0.0 && m_extr_osc[2]<0.0)
|
||||
{
|
||||
//--- both valleys are below zero, the peak is between them and it hasn't raised above zero
|
||||
//--- we suppose that this is "divergence"
|
||||
return(m_pattern_3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalAO::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- if the first analyzed bar is "green", don't "vote" for selling
|
||||
if(DiffAO(idx)>0.0)
|
||||
return(result);
|
||||
//--- first analyzed bar is "red" (the indicator has no objections to selling)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
if(AO(idx++)<0.0)
|
||||
{
|
||||
//--- first analyzed bar is below zero, search for the "saucer" and "crossing of the zero line" signals
|
||||
if(IS_PATTERN_USAGE(1) && DiffAO(idx)>0.0)
|
||||
{
|
||||
//--- the "saucer" signal
|
||||
//--- there is a condition for buying
|
||||
return(m_pattern_1);
|
||||
}
|
||||
if(IS_PATTERN_USAGE(2) && AO(idx)>0.0)
|
||||
{
|
||||
//--- the "crossing of the zero line" signal
|
||||
//--- there is a condition for buying
|
||||
return(m_pattern_2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- first analyzed bar is above zero, search for the "divergence" signal
|
||||
//--- if the second analyzed bar is "green", the condition for buying may be fulfilled
|
||||
if(IS_PATTERN_USAGE(3) && DiffAO(idx)>0.0)
|
||||
{
|
||||
idx=StartIndex();
|
||||
//--- search for the "divergence" signal
|
||||
ExtStateAO(idx);
|
||||
if((m_extr_map&0xF)==1)
|
||||
{
|
||||
if(m_extr_osc[0]>0.0 && m_extr_osc[1]>0.0 && m_extr_osc[2]>0.0)
|
||||
{
|
||||
//--- both peaks are above zero and the valley between them hasn't fallen below zero
|
||||
//--- we suppose that this is "divergence"
|
||||
return(m_pattern_3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,289 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalBearsPower.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of oscillator 'Bears Power' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Bears Power |
|
||||
//| ShortName=BearsPower |
|
||||
//| Class=CSignalBearsPower |
|
||||
//| Page=signal_bears |
|
||||
//| Parameter=PeriodBears,int,13,Period of calculation |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalBearsPower. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Bears Power' oscillator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalBearsPower : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiBearsPower m_bears; // object-oscillator
|
||||
//--- adjusted parameters
|
||||
int m_period_bears; // the "period of calculation" parameter of the oscillator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "reverse of the oscillator to required direction"
|
||||
int m_pattern_1; // model 1 "divergence of the oscillator and price"
|
||||
//--- variables
|
||||
double m_extr_osc[10]; // array of values of extremums of the oscillator
|
||||
double m_extr_pr[10]; // array of values of the corresponding extremums of price
|
||||
int m_extr_pos[10]; // array of shifts of extremums (in bars)
|
||||
uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price
|
||||
|
||||
public:
|
||||
CSignalBearsPower(void);
|
||||
~CSignalBearsPower(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodBears(int value) { m_period_bears=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
//--- the oscillator doesn't identify conditions for selling
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the oscillator
|
||||
bool InitBears(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double Bears(int ind) { return(m_bears.Main(ind)); }
|
||||
double DiffBears(int ind) { return(Bears(ind)-Bears(ind+1)); }
|
||||
int StateBears(int ind);
|
||||
bool ExtStateBears(int ind);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalBearsPower::CSignalBearsPower(void) : m_period_bears(13),
|
||||
m_pattern_0(20),
|
||||
m_pattern_1(80)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalBearsPower::~CSignalBearsPower(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalBearsPower::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_period_bears<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period Bears must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalBearsPower::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize BearsPower oscillator
|
||||
if(!InitBears(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize BearsPower oscillators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalBearsPower::InitBears(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_bears)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_bears.Create(m_symbol.Name(),m_period,m_period_bears))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check of the oscillator state. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalBearsPower::StateBears(int ind)
|
||||
{
|
||||
int res=0;
|
||||
double var;
|
||||
//---
|
||||
for(int i=ind;;i++)
|
||||
{
|
||||
if(Bears(i+1)==EMPTY_VALUE)
|
||||
break;
|
||||
var=DiffBears(i);
|
||||
if(res>0)
|
||||
{
|
||||
if(var<0)
|
||||
break;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if(res<0)
|
||||
{
|
||||
if(var>0)
|
||||
break;
|
||||
res--;
|
||||
continue;
|
||||
}
|
||||
if(var>0)
|
||||
res++;
|
||||
if(var<0)
|
||||
res--;
|
||||
}
|
||||
//--- return the result
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Extended check of the oscillator state consists |
|
||||
//| in forming a bit-map according to certain rules, |
|
||||
//| which shows ratios of extremums of the oscillator and price. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalBearsPower::ExtStateBears(int ind)
|
||||
{
|
||||
//--- operation of this method results in a bit-map of extremums
|
||||
//--- practically, the bit-map of extremums is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an element of the analyzed bit-map
|
||||
//--- bit 3 - not used (always 0)
|
||||
//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- bit 1 - not used (always 0)
|
||||
//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- in addition to them, the following is formed:
|
||||
//--- array of values of extremums of the oscillator,
|
||||
//--- array of values of price extremums and
|
||||
//--- array of "distances" between extremums of the oscillator (in bars)
|
||||
//--- it should be noted that when using the results of the extended check of state,
|
||||
//--- you should consider, which extremum of the oscillator (peak or valley)
|
||||
//--- is the "reference point" (i.e. was detected first during the analysis)
|
||||
//--- if a peak is detected first then even elements of all arrays
|
||||
//--- will contain information about peaks, and odd elements will contain information about valleys
|
||||
//--- if a valley is detected first, then respectively in reverse
|
||||
int pos=ind,off,index;
|
||||
uint map; // intermediate bit-map for one extremum
|
||||
//---
|
||||
m_extr_map=0;
|
||||
for(int i=0;i<10;i++)
|
||||
{
|
||||
off=StateBears(pos);
|
||||
if(off>0)
|
||||
{
|
||||
//--- minimum of the oscillator is detected
|
||||
pos+=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=Bears(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_low.MinValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]<m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]<m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_low.MinValue(pos-1,4,index);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- maximum of the oscillator is detected
|
||||
pos-=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=Bears(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]>m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]>m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-1,4,index);
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalBearsPower::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- if the oscillator is above zero, don't "vote" for buying
|
||||
if(Bears(idx)>0.0)
|
||||
return(result);
|
||||
//--- the oscillator is below zero
|
||||
if(StateBears(idx)>0)
|
||||
{
|
||||
//--- the oscillator has turned upwards at a previous bar
|
||||
//--- there is a condition for buying
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the model 1 is used, search for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(1))
|
||||
{
|
||||
ExtStateBears(idx);
|
||||
if((m_extr_map&0xF)==1)
|
||||
{
|
||||
if(m_extr_osc[0]<0.0 && m_extr_osc[2]<0.0)
|
||||
{
|
||||
//--- both valleys are below zero
|
||||
//--- we suppose that this is "divergence"
|
||||
result=m_pattern_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,289 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalBullsPower.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of oscillator 'Bulls Power' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Bulls Power |
|
||||
//| ShortName=BullsPower |
|
||||
//| Class=CSignalBullsPower |
|
||||
//| Page=signal_bulls |
|
||||
//| Parameter=PeriodBulls,int,13,Period of calculation |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalBullsPower. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Bulls Power' oscillator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalBullsPower : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiBullsPower m_bulls; // object-oscillator
|
||||
//--- adjusted parameters
|
||||
int m_period_bulls; // the "period of calculation" parameter of the oscillator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "reverse of the oscillator to required direction"
|
||||
int m_pattern_1; // model 1 "divergence of the oscillator and price"
|
||||
//--- variables
|
||||
double m_extr_osc[10]; // array of values of extremums of the oscillator
|
||||
double m_extr_pr[10]; // array of values of the corresponding extremums of price
|
||||
int m_extr_pos[10]; // array of shifts of extremums (in bars)
|
||||
uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price
|
||||
|
||||
public:
|
||||
CSignalBullsPower(void);
|
||||
~CSignalBullsPower(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodBulls(int value) { m_period_bulls=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int ShortCondition(void);
|
||||
//--- the oscillator doesn't identify conditions for buying
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the oscillator
|
||||
bool InitBears(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double Bulls(int ind) { return(m_bulls.Main(ind)); }
|
||||
double DiffBulls(int ind) { return(Bulls(ind)-Bulls(ind+1)); }
|
||||
int StateBulls(int ind);
|
||||
bool ExtStateBulls(int ind);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalBullsPower::CSignalBullsPower(void) : m_period_bulls(13),
|
||||
m_pattern_0(20),
|
||||
m_pattern_1(80)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalBullsPower::~CSignalBullsPower(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalBullsPower::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_period_bulls<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period Bulls must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalBullsPower::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize BullsPower oscillator
|
||||
if(!InitBears(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize BearsPower oscillators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalBullsPower::InitBears(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_bulls)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_bulls.Create(m_symbol.Name(),m_period,m_period_bulls))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check of the oscillator state. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalBullsPower::StateBulls(int ind)
|
||||
{
|
||||
int res=0;
|
||||
double var;
|
||||
//---
|
||||
for(int i=ind;;i++)
|
||||
{
|
||||
if(Bulls(i+1)==EMPTY_VALUE)
|
||||
break;
|
||||
var=DiffBulls(i);
|
||||
if(res>0)
|
||||
{
|
||||
if(var<0)
|
||||
break;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if(res<0)
|
||||
{
|
||||
if(var>0)
|
||||
break;
|
||||
res--;
|
||||
continue;
|
||||
}
|
||||
if(var>0)
|
||||
res++;
|
||||
if(var<0)
|
||||
res--;
|
||||
}
|
||||
//--- return the result
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Extended check of the oscillator state consists |
|
||||
//| in forming a bit-map according to certain rules, |
|
||||
//| which shows ratios of extremums of the oscillator and price. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalBullsPower::ExtStateBulls(int ind)
|
||||
{
|
||||
//--- operation of this method results in a bit-map of extremums
|
||||
//--- practically, the bit-map of extremums is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an element of the analyzed bit-map
|
||||
//--- bit 3 - not used (always 0)
|
||||
//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- bit 1 - not used (always 0)
|
||||
//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- in addition to them, the following is formed:
|
||||
//--- array of values of extremums of the oscillator,
|
||||
//--- array of values of price extremums and
|
||||
//--- array of "distances" between extremums of the oscillator (in bars)
|
||||
//--- it should be noted that when using the results of the extended check of state,
|
||||
//--- you should consider, which extremum of the oscillator (peak or valley)
|
||||
//--- is the "reference point" (i.e. was detected first during the analysis)
|
||||
//--- if a peak is detected first then even elements of all arrays
|
||||
//--- will contain information about peaks, and odd elements will contain information about valleys
|
||||
//--- if a valley is detected first, then respectively in reverse
|
||||
int pos=ind,off,index;
|
||||
uint map; // intermediate bit-map for one extremum
|
||||
//---
|
||||
m_extr_map=0;
|
||||
for(int i=0;i<10;i++)
|
||||
{
|
||||
off=StateBulls(pos);
|
||||
if(off>0)
|
||||
{
|
||||
//--- minimum of the oscillator is detected
|
||||
pos+=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=Bulls(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_low.MinValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]<m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]<m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_low.MinValue(pos-1,4,index);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- maximum of the oscillator is detected
|
||||
pos-=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=Bulls(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]>m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]>m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-1,4,index);
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalBullsPower::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- if the oscillator is below zero, don't "vote" for selling
|
||||
if(Bulls(idx)<0.0)
|
||||
return(result);
|
||||
//--- the oscillator is above zero
|
||||
if(StateBulls(idx)<0)
|
||||
{
|
||||
//--- the oscillator has turned downwards at a previous bar
|
||||
//--- there us a condition for selling
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the model 1 is used, search for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(1))
|
||||
{
|
||||
ExtStateBulls(idx);
|
||||
if((m_extr_map&0xF)==1)
|
||||
{
|
||||
if(m_extr_osc[0]>0.0 && m_extr_osc[2]>0.0)
|
||||
{
|
||||
//--- both peaks are above zero
|
||||
//--- we suppose that this is "divergence"
|
||||
result=m_pattern_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,382 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalCCI.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of oscilator 'Commodity Channel Index' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Commodity Channel Index |
|
||||
//| ShortName=CCI |
|
||||
//| Class=CSignalCCI |
|
||||
//| Page=signal_cci |
|
||||
//| Parameter=PeriodCCI,int,8,Period of calculation |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalCCI. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Commodity Channel Index' oscillator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalCCI : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiCCI m_cci; // object-oscillator
|
||||
//--- adjusted parameters
|
||||
int m_periodCCI; // the "period of calculation" parameter of the oscillator
|
||||
ENUM_APPLIED_PRICE m_applied; // the "prices series" parameter of the oscillator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "the oscillator has required direction"
|
||||
int m_pattern_1; // model 1 "reverse behind the level of overbuying/overselling"
|
||||
int m_pattern_2; // model 2 "divergence of the oscillator and price"
|
||||
int m_pattern_3; // model 3 "double divergence of the oscillator and price"
|
||||
//--- variables
|
||||
double m_extr_osc[10]; // array of values of extremums of the oscillator
|
||||
double m_extr_pr[10]; // array of values of the corresponding extremums of price
|
||||
int m_extr_pos[10]; // array of shifts of extremums (in bars)
|
||||
uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price
|
||||
|
||||
public:
|
||||
CSignalCCI(void);
|
||||
~CSignalCCI(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodCCI(int value) { m_periodCCI=value; }
|
||||
void Applied(ENUM_APPLIED_PRICE value) { m_applied=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the oscillator
|
||||
bool InitStoch(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double CCI(int ind) { return(m_cci.Main(ind)); }
|
||||
double Diff(int ind) { return(CCI(ind)-CCI(ind+1)); }
|
||||
int State(int ind);
|
||||
bool ExtState(int ind);
|
||||
bool CompareMaps(int map,int count,bool minimax=false,int start=0);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalCCI::CSignalCCI(void) : m_periodCCI(14),
|
||||
m_applied(PRICE_CLOSE),
|
||||
m_pattern_0(90),
|
||||
m_pattern_1(60),
|
||||
m_pattern_2(100),
|
||||
m_pattern_3(50)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalCCI::~CSignalCCI(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCCI::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_periodCCI<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period of the CCI oscillator must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCCI::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize CCI oscillator
|
||||
if(!InitStoch(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize CCI oscillators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCCI::InitStoch(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_cci)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_cci.Create(m_symbol.Name(),m_period,m_periodCCI,m_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check of the oscillator state. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalCCI::State(int ind)
|
||||
{
|
||||
int res=0;
|
||||
double var;
|
||||
//---
|
||||
for(int i=ind;;i++)
|
||||
{
|
||||
if(CCI(i+1)==EMPTY_VALUE)
|
||||
break;
|
||||
var=Diff(i);
|
||||
if(res>0)
|
||||
{
|
||||
if(var<0)
|
||||
break;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if(res<0)
|
||||
{
|
||||
if(var>0)
|
||||
break;
|
||||
res--;
|
||||
continue;
|
||||
}
|
||||
if(var>0)
|
||||
res++;
|
||||
if(var<0)
|
||||
res--;
|
||||
}
|
||||
//--- return the result
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Extended check of the oscillator state consists |
|
||||
//| in forming a bit-map according to certain rules, |
|
||||
//| which shows ratios of extremums of the oscillator and price. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCCI::ExtState(int ind)
|
||||
{
|
||||
//--- operation of this method results in a bit-map of extremums
|
||||
//--- practically, the bit-map of extremums is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an element of the analyzed bit-map
|
||||
//--- bit 3 - not used (always 0)
|
||||
//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- bit 1 - not used (always 0)
|
||||
//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- in addition to them, the following is formed:
|
||||
//--- array of values of extremums of the oscillator,
|
||||
//--- array of values of price extremums and
|
||||
//--- array of "distances" between extremums of the oscillator (in bars)
|
||||
//--- it should be noted that when using the results of the extended check of state,
|
||||
//--- you should consider, which extremum of the oscillator (peak or valley)
|
||||
//--- is the "reference point" (i.e. was detected first during the analysis)
|
||||
//--- if a peak is detected first then even elements of all arrays
|
||||
//--- will contain information about peaks, and odd elements will contain information about valleys
|
||||
//--- if a valley is detected first, then respectively in reverse
|
||||
int pos=ind,off,index;
|
||||
uint map; // intermediate bit-map for one extremum
|
||||
//---
|
||||
m_extr_map=0;
|
||||
for(int i=0;i<10;i++)
|
||||
{
|
||||
off=State(pos);
|
||||
if(off>0)
|
||||
{
|
||||
//--- minimum of the oscillator is detected
|
||||
pos+=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=CCI(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_low.MinValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]<m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]<m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_low.MinValue(pos-1,3,index);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- maximum of the oscillator is detected
|
||||
pos-=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=CCI(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]>m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]>m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-1,3,index);
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparing the bit-map of extremums with pattern. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCCI::CompareMaps(int map,int count,bool minimax,int start)
|
||||
{
|
||||
int step =(minimax)?4:8;
|
||||
int total=step*(start+count);
|
||||
//--- check input parameters for a possible going out of range of the bit-map
|
||||
if(total>32)
|
||||
return(false);
|
||||
//--- bit-map of the patter is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the desired ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an elements of the pattern of the bit-map pattern
|
||||
//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us
|
||||
//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2
|
||||
//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us
|
||||
//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0
|
||||
//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
uint inp_map,check_map;
|
||||
int i,j;
|
||||
//--- loop by extremums (4 minimums and 4 maximums)
|
||||
//--- price and the oscillator are checked separately (thus, there are 16 checks)
|
||||
for(i=step*start,j=0;i<total;i+=step,j+=4)
|
||||
{
|
||||
//--- "take" two bits - patter of the corresponding extremum of the price
|
||||
inp_map=(map>>j)&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map<2)
|
||||
{
|
||||
//--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>i)&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- "take" two bits - pattern of the corresponding oscillator extremum
|
||||
inp_map=(map>>(j+2))&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map>=2)
|
||||
continue;
|
||||
//--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>(i+2))&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalCCI::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//---
|
||||
if(Diff(idx)>0.0)
|
||||
{
|
||||
//--- the oscillator is directed upwards confirming the possibility of price growth
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, search for a reverse of the oscillator upwards behind the level of overselling
|
||||
if(IS_PATTERN_USAGE(1) && Diff(idx+1)<0.0 && CCI(idx+1)<-100.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 or 3 is used, perform the extended analysis of the oscillator state
|
||||
if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3))
|
||||
{
|
||||
ExtState(idx);
|
||||
//--- if the model 2 is used, search for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(2) && CompareMaps(1,1)) // 00000001b
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- if the model 3 is used, search for the "double divergence" signal
|
||||
if(IS_PATTERN_USAGE(3) && CompareMaps(0x11,2)) // 00010001b
|
||||
return(m_pattern_3); // signal number 3
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalCCI::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//---
|
||||
if(Diff(idx)<0.0)
|
||||
{
|
||||
//--- the oscillator is directed downwards confirming the possibility of falling of price
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, search for a reverse of the oscillator downwards behind the level of overbuying
|
||||
if(IS_PATTERN_USAGE(1) && Diff(idx+1)>0.0 && CCI(idx+1)>100.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 or 3 is used, perform the extended analysis of the oscillator state
|
||||
if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3))
|
||||
{
|
||||
ExtState(idx);
|
||||
//--- if the model 2 is used, search for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(2) && CompareMaps(1,1)) // 00000001b
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- if the model 3 is used, search for the "double divergence" signal
|
||||
if(IS_PATTERN_USAGE(3) && CompareMaps(0x11,2)) // 00010001b
|
||||
return(m_pattern_3); // signal number 3
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,257 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalDEMA.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of indicator 'Double Exponential Moving Average' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Double Exponential Moving Average |
|
||||
//| ShortName=DEMA |
|
||||
//| Class=CSignalDEMA |
|
||||
//| Page=signal_dema |
|
||||
//| Parameter=PeriodMA,int,12,Period of averaging |
|
||||
//| Parameter=Shift,int,0,Time shift |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalDEMA. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Double Exponential Moving Average' indicator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalDEMA : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiDEMA m_ma; // object-indicator
|
||||
//--- adjusted parameters
|
||||
int m_ma_period; // the "period of averaging" parameter of the indicator
|
||||
int m_ma_shift; // the "time shift" parameter of the indicator
|
||||
ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter" of the indicator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "price is on the necessary side from the indicator"
|
||||
int m_pattern_1; // model 1 "price crossed the indicator with opposite direction"
|
||||
int m_pattern_2; // model 2 "price crossed the indicator with the same direction"
|
||||
int m_pattern_3; // model 3 "piercing"
|
||||
|
||||
public:
|
||||
CSignalDEMA(void);
|
||||
~CSignalDEMA(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodMA(int value) { m_ma_period=value; }
|
||||
void Shift(int value) { m_ma_shift=value; }
|
||||
void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the indicator
|
||||
bool InitMA(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double MA(int ind) { return(m_ma.Main(ind)); }
|
||||
double DiffMA(int ind) { return(MA(ind)-MA(ind+1)); }
|
||||
double DiffOpenMA(int ind) { return(Open(ind)-MA(ind)); }
|
||||
double DiffHighMA(int ind) { return(High(ind)-MA(ind)); }
|
||||
double DiffLowMA(int ind) { return(Low(ind)-MA(ind)); }
|
||||
double DiffCloseMA(int ind) { return(Close(ind)-MA(ind)); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalDEMA::CSignalDEMA(void) : m_ma_period(12),
|
||||
m_ma_shift(0),
|
||||
m_ma_applied(PRICE_CLOSE),
|
||||
m_pattern_0(20),
|
||||
m_pattern_1(60),
|
||||
m_pattern_2(80),
|
||||
m_pattern_3(60)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalDEMA::~CSignalDEMA(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalDEMA::ValidationSettings(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_ma_period<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period MA must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalDEMA::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize DEMA indicator
|
||||
if(!InitMA(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create MA indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalDEMA::InitMA(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add indicator to collection
|
||||
if(!indicators.Add(GetPointer(m_ma)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize indicator
|
||||
if(!m_ma.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalDEMA::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- analyze positional relationship of the close price and the indicator at the first analyzed bar
|
||||
if(DiffCloseMA(idx)<0.0)
|
||||
{
|
||||
//--- the close price is below the indicator
|
||||
if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)>0.0 && DiffMA(idx)>0.0)
|
||||
{
|
||||
//--- the open price is above the indicator (i.e. there was an intersection), but the indicator is directed upwards
|
||||
result=m_pattern_1;
|
||||
//--- consider that this is an unformed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- the close price is above the indicator (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the indicator is directed upwards
|
||||
if(DiffMA(idx)>0.0)
|
||||
{
|
||||
if(DiffOpenMA(idx)<0.0)
|
||||
{
|
||||
//--- if the model 2 is used
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- the open price is below the indicator (i.e. there was an intersection)
|
||||
result=m_pattern_2;
|
||||
//--- suggest to enter the market at the "roll back"
|
||||
m_base_price=m_symbol.NormalizePrice(MA(idx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- if the model 3 is used and the open price is above the indicator
|
||||
if(IS_PATTERN_USAGE(3) && DiffLowMA(idx)<0.0)
|
||||
{
|
||||
//--- the low price is below the indicator
|
||||
result=m_pattern_3;
|
||||
//--- consider that this is a formed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalDEMA::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- analyze positional relationship of the close price and the indicator at the first analyzed bar
|
||||
if(DiffCloseMA(idx)>0.0)
|
||||
{
|
||||
//--- the close price is above the indicator
|
||||
if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)<0.0 && DiffMA(idx)<0.0)
|
||||
{
|
||||
//--- the open price is below the indicator (i.e. there was an intersection), but the indicator is directed downwards
|
||||
result=m_pattern_1;
|
||||
//--- consider that this is an unformed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- the close price is below the indicator (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- the indicator is directed downwards
|
||||
if(DiffMA(idx)<0.0)
|
||||
{
|
||||
if(DiffOpenMA(idx)>0.0)
|
||||
{
|
||||
//--- if the model 2 is used
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- the open price is above the indicator (i.e. there was an intersection)
|
||||
result=m_pattern_2;
|
||||
//--- suggest to enter the market at the "roll back"
|
||||
m_base_price=m_symbol.NormalizePrice(MA(idx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- if the model 3 is used and the open price is below the indicator
|
||||
if(IS_PATTERN_USAGE(3) && DiffHighMA(idx)>0.0)
|
||||
{
|
||||
//--- the high price is above the indicator
|
||||
result=m_pattern_3;
|
||||
//--- consider that this is a formed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,378 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalDeMarker.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of oscillator 'DeMarker' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=DeMarker |
|
||||
//| ShortName=DeM |
|
||||
//| Class=CSignalDeM |
|
||||
//| Page=signal_demarker |
|
||||
//| Parameter=PeriodDeM,int,8,Period of calculation |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalDeM. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Commodity Channel Index' oscillator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalDeM : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiDeMarker m_dem; // object-oscillator
|
||||
//--- adjusted parameters
|
||||
int m_periodDeM; // the "period of calculation" parameter of the oscillator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "the oscillator has required direction"
|
||||
int m_pattern_1; // model 1 "reverse behind the level of overbuying/overselling"
|
||||
int m_pattern_2; // model 2 "divergence of the oscillator and price"
|
||||
int m_pattern_3; // model 3 "double divergence of the oscillator and price"
|
||||
//--- variables
|
||||
double m_extr_osc[10]; // array of values of extremums of the oscillator
|
||||
double m_extr_pr[10]; // array of values of the corresponding extremums of price
|
||||
int m_extr_pos[10]; // array of shifts of extremums (in bars)
|
||||
uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price
|
||||
|
||||
public:
|
||||
CSignalDeM(void);
|
||||
~CSignalDeM(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodDeM(int value) { m_periodDeM=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the oscillator
|
||||
bool InitStoch(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double DeM(int ind) { return(m_dem.Main(ind)); }
|
||||
double DiffDeM(int ind) { return(DeM(ind)-DeM(ind+1)); }
|
||||
int StateDeM(int ind);
|
||||
bool ExtStateDeM(int ind);
|
||||
bool CompareMaps(int map,int count,bool minimax=false,int start=0);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalDeM::CSignalDeM(void) : m_periodDeM(14),
|
||||
m_pattern_0(90),
|
||||
m_pattern_1(60),
|
||||
m_pattern_2(100),
|
||||
m_pattern_3(80)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalDeM::~CSignalDeM(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalDeM::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_periodDeM<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period of the DeMarker oscillator must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalDeM::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize DeMarker oscillator
|
||||
if(!InitStoch(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize DeMarker oscillators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalDeM::InitStoch(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_dem)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_dem.Create(m_symbol.Name(),m_period,m_periodDeM))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check of the oscillator state. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalDeM::StateDeM(int ind)
|
||||
{
|
||||
int res=0;
|
||||
double var;
|
||||
//---
|
||||
for(int i=ind;;i++)
|
||||
{
|
||||
if(DeM(i+1)==EMPTY_VALUE)
|
||||
break;
|
||||
var=DiffDeM(i);
|
||||
if(res>0)
|
||||
{
|
||||
if(var<0)
|
||||
break;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if(res<0)
|
||||
{
|
||||
if(var>0)
|
||||
break;
|
||||
res--;
|
||||
continue;
|
||||
}
|
||||
if(var>0)
|
||||
res++;
|
||||
if(var<0)
|
||||
res--;
|
||||
}
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Extended check of the oscillator state consists |
|
||||
//| in forming a bit-map according to certain rules, |
|
||||
//| which shows ratios of extremums of the oscillator and price. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalDeM::ExtStateDeM(int ind)
|
||||
{
|
||||
//--- operation of this method results in a bit-map of extremums
|
||||
//--- practically, the bit-map of extremums is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an element of the analyzed bit-map
|
||||
//--- bit 3 - not used (always 0)
|
||||
//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- bit 1 - not used (always 0)
|
||||
//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- in addition to them, the following is formed:
|
||||
//--- array of values of extremums of the oscillator,
|
||||
//--- array of values of price extremums and
|
||||
//--- array of "distances" between extremums of the oscillator (in bars)
|
||||
//--- it should be noted that when using the results of the extended check of state,
|
||||
//--- you should consider, which extremum of the oscillator (peak or valley)
|
||||
//--- is the "reference point" (i.e. was detected first during the analysis)
|
||||
//--- if a peak is detected first then even elements of all arrays
|
||||
//--- will contain information about peaks, and odd elements will contain information about valleys
|
||||
//--- if a valley is detected first, then respectively in reverse
|
||||
int pos=ind,off,index;
|
||||
uint map; // intermediate bit-map for one extremum
|
||||
//---
|
||||
m_extr_map=0;
|
||||
for(int i=0;i<10;i++)
|
||||
{
|
||||
off=StateDeM(pos);
|
||||
if(off>0)
|
||||
{
|
||||
//--- minimum of the oscillator is detected
|
||||
pos+=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=DeM(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_low.MinValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]<m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]<m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_low.MinValue(pos-1,4,index);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- maximum of the oscillator is detected
|
||||
pos-=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=DeM(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]>m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]>m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-1,4,index);
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparing the bit-map of extremums with pattern. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalDeM::CompareMaps(int map,int count,bool minimax,int start)
|
||||
{
|
||||
int step =(minimax)?4:8;
|
||||
int total=step*(start+count);
|
||||
//--- check input parameters for a possible going out of range of the bit-map
|
||||
if(total>32)
|
||||
return(false);
|
||||
//--- bit-map of the patter is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the desired ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an elements of the pattern of the bit-map pattern
|
||||
//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us
|
||||
//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2
|
||||
//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us
|
||||
//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0
|
||||
//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
uint inp_map,check_map;
|
||||
int i,j;
|
||||
//--- loop by extremums (4 minimums and 4 maximums)
|
||||
//--- price and the oscillator are checked separately (thus, there are 16 checks)
|
||||
for(i=step*start,j=0;i<total;i+=step,j+=4)
|
||||
{
|
||||
//--- "take" two bits - patter of the corresponding extremum of the price
|
||||
inp_map=(map>>j)&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map<2)
|
||||
{
|
||||
//--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>i)&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- "take" two bits - pattern of the corresponding oscillator extremum
|
||||
inp_map=(map>>(j+2))&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map>=2)
|
||||
continue;
|
||||
//--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>(i+2))&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalDeM::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- check direction of the main line
|
||||
if(DiffDeM(idx)>0.0)
|
||||
{
|
||||
//--- the oscillator is directed upwards confirming the possibility of price growth
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, search for a reverse of the oscillator upwards behind the level of overselling
|
||||
if(IS_PATTERN_USAGE(1) && DiffDeM(idx+1)<0.0 && DeM(idx+1)<0.3)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 or 3 is used, perform the extended analysis of the oscillator state
|
||||
if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3))
|
||||
{
|
||||
ExtStateDeM(idx);
|
||||
//--- if the model 2 is used, search for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(2) && CompareMaps(1,1)) // 00000001b
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- if the model 3 is used, search for the "double divergence" signal
|
||||
if(IS_PATTERN_USAGE(3) && CompareMaps(0x11,2)) // 00010001b
|
||||
return(m_pattern_3); // signal number 3
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalDeM::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- check direction of the main line
|
||||
if(DiffDeM(idx)<0.0)
|
||||
{
|
||||
//--- the oscillator is directed downwards confirming the possibility of falling of price
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, search for a reverse of the oscillator downwards behind the level of overbuying
|
||||
if(IS_PATTERN_USAGE(1) && DiffDeM(idx+1)>0.0 && DeM(idx+1)>0.7)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 or 3 is used, perform the extended analysis of the oscillator state
|
||||
if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3))
|
||||
{
|
||||
ExtStateDeM(idx);
|
||||
//--- if the model 2 is used, search for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(2) && CompareMaps(1,1)) // 00000001b
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- if the model 3 is used, search for the "double divergence" signal
|
||||
if(IS_PATTERN_USAGE(3) && CompareMaps(0x11,2)) // 00010001b
|
||||
return(m_pattern_3); // signal number 3
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,193 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalEnvelopes.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of indicator 'Envelopes' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Envelopes |
|
||||
//| ShortName=Envelopes |
|
||||
//| Class=CSignalEnvelopes |
|
||||
//| Page=signal_envelopes |
|
||||
//| Parameter=PeriodMA,int,45,Period of averaging |
|
||||
//| Parameter=Shift,int,0,Time shift |
|
||||
//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//| Parameter=Deviation,double,0.15,Deviation |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalEnvelopes. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Envelopes' indicator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalEnvelopes : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiEnvelopes m_env; // object-indicator
|
||||
//--- adjusted parameters
|
||||
int m_ma_period; // the "period of averaging" parameter of the indicator
|
||||
int m_ma_shift; // the "time shift" parameter of the indicator
|
||||
ENUM_MA_METHOD m_ma_method; // the "method of averaging" parameter of the indicator
|
||||
ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter of the indicator
|
||||
double m_deviation; // the "deviation" parameter of the indicator
|
||||
double m_limit_in; // threshold sensitivity of the 'rollback zone'
|
||||
double m_limit_out; // threshold sensitivity of the 'break through zone'
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "price is near the necessary border of the envelope"
|
||||
int m_pattern_1; // model 1 "price crossed a border of the envelope"
|
||||
|
||||
public:
|
||||
CSignalEnvelopes(void);
|
||||
~CSignalEnvelopes(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodMA(int value) { m_ma_period=value; }
|
||||
void Shift(int value) { m_ma_shift=value; }
|
||||
void Method(ENUM_MA_METHOD value) { m_ma_method=value; }
|
||||
void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; }
|
||||
void Deviation(double value) { m_deviation=value; }
|
||||
void LimitIn(double value) { m_limit_in=value; }
|
||||
void LimitOut(double value) { m_limit_out=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the indicator
|
||||
bool InitMA(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double Upper(int ind) { return(m_env.Upper(ind)); }
|
||||
double Lower(int ind) { return(m_env.Lower(ind)); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalEnvelopes::CSignalEnvelopes(void) : m_ma_period(45),
|
||||
m_ma_shift(0),
|
||||
m_ma_method(MODE_SMA),
|
||||
m_ma_applied(PRICE_CLOSE),
|
||||
m_deviation(0.15),
|
||||
m_limit_in(0.2),
|
||||
m_limit_out(0.2),
|
||||
m_pattern_0(90),
|
||||
m_pattern_1(70)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalEnvelopes::~CSignalEnvelopes(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalEnvelopes::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_ma_period<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period MA must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalEnvelopes::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize MA indicator
|
||||
if(!InitMA(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize MA indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalEnvelopes::InitMA(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_env)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalEnvelopes::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
double close=Close(idx);
|
||||
double upper=Upper(idx);
|
||||
double lower=Lower(idx);
|
||||
double width=upper-lower;
|
||||
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying
|
||||
if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width)
|
||||
result=m_pattern_0;
|
||||
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying
|
||||
if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width)
|
||||
result=m_pattern_1;
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalEnvelopes::ShortCondition(void)
|
||||
{
|
||||
int result =0;
|
||||
int idx =StartIndex();
|
||||
double close=Close(idx);
|
||||
double upper=Upper(idx);
|
||||
double lower=Lower(idx);
|
||||
double width=upper-lower;
|
||||
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling
|
||||
if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width)
|
||||
result=m_pattern_0;
|
||||
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling
|
||||
if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width)
|
||||
result=m_pattern_1;
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,257 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalFrAMA.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of indicator 'Fractal Adaptive Moving Average' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Fractal Adaptive Moving Average |
|
||||
//| ShortName=FraMA |
|
||||
//| Class=CSignalFrAMA |
|
||||
//| Page=signal_frama |
|
||||
//| Parameter=PeriodMA,int,12,Period of averaging |
|
||||
//| Parameter=Shift,int,0,Time shift |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalFrAMA. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Fractal Adaptive Moving Average' indicator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalFrAMA : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiFrAMA m_ma; // object-indicator
|
||||
//--- adjusted parameters
|
||||
int m_ma_period; // the "period of averaging" parameter of the indicator
|
||||
int m_ma_shift; // the "time shift" parameter of the indicator
|
||||
ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter" of the indicator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "price is on the necessary side from the indicator"
|
||||
int m_pattern_1; // model 1 "price crossed the indicator with opposite direction"
|
||||
int m_pattern_2; // model 2 "price crossed the indicator with the same direction"
|
||||
int m_pattern_3; // model 3 "piercing"
|
||||
|
||||
public:
|
||||
CSignalFrAMA(void);
|
||||
~CSignalFrAMA(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodMA(int value) { m_ma_period=value; }
|
||||
void Shift(int value) { m_ma_shift=value; }
|
||||
void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the indicator
|
||||
bool InitMA(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double MA(int ind) { return(m_ma.Main(ind)); }
|
||||
double DiffMA(int ind) { return(MA(ind)-MA(ind+1)); }
|
||||
double DiffOpenMA(int ind) { return(Open(ind)-MA(ind)); }
|
||||
double DiffHighMA(int ind) { return(High(ind)-MA(ind)); }
|
||||
double DiffLowMA(int ind) { return(Low(ind)-MA(ind)); }
|
||||
double DiffCloseMA(int ind) { return(Close(ind)-MA(ind)); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalFrAMA::CSignalFrAMA(void) : m_ma_period(12),
|
||||
m_ma_shift(0),
|
||||
m_ma_applied(PRICE_CLOSE),
|
||||
m_pattern_0(90),
|
||||
m_pattern_1(100),
|
||||
m_pattern_2(80),
|
||||
m_pattern_3(60)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalFrAMA::~CSignalFrAMA(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalFrAMA::ValidationSettings(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_ma_period<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period MA must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalFrAMA::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize FrAMA indicator
|
||||
if(!InitMA(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create MA indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalFrAMA::InitMA(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add indicator to collection
|
||||
if(!indicators.Add(GetPointer(m_ma)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize indicator
|
||||
if(!m_ma.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalFrAMA::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- analyze positional relationship of the close price and the indicator at the first analyzed bar
|
||||
if(DiffCloseMA(idx)<0.0)
|
||||
{
|
||||
//--- the close price is below the indicator
|
||||
if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)>0.0 && DiffMA(idx)>0.0)
|
||||
{
|
||||
//--- the open price is above the indicator (i.e. there was an intersection), but the indicator is directed upwards
|
||||
result=m_pattern_1;
|
||||
//--- consider that this is an unformed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- the close price is above the indicator (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the indicator is directed upwards
|
||||
if(DiffMA(idx)>0.0)
|
||||
{
|
||||
if(DiffOpenMA(idx)<0.0)
|
||||
{
|
||||
//--- if the model 2 is used
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- the open price is below the indicator (i.e. there was an intersection)
|
||||
result=m_pattern_2;
|
||||
//--- suggest to enter the market at the "roll back"
|
||||
m_base_price=m_symbol.NormalizePrice(MA(idx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- if the model 3 is used and the open price is above the indicator
|
||||
if(IS_PATTERN_USAGE(3) && DiffLowMA(idx)<0.0)
|
||||
{
|
||||
//--- the low price is below the indicator
|
||||
result=m_pattern_3;
|
||||
//--- consider that this is a formed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalFrAMA::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- analyze positional relationship of the close price and the indicator at the first analyzed bar
|
||||
if(DiffCloseMA(idx)>0.0)
|
||||
{
|
||||
//--- the close price is above the indicator
|
||||
if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)<0.0 && DiffMA(idx)<0.0)
|
||||
{
|
||||
//--- the open price is below the indicator (i.e. there was an intersection), but the indicator is directed downwards
|
||||
result=m_pattern_1;
|
||||
//--- consider that this is an unformed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- the close price is below the indicator (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- the indicator is directed downwards
|
||||
if(DiffMA(idx)<0.0)
|
||||
{
|
||||
if(DiffOpenMA(idx)>0.0)
|
||||
{
|
||||
//--- if the model 2 is used
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- the open price is above the indicator (i.e. there was an intersection)
|
||||
result=m_pattern_2;
|
||||
//--- suggest to enter the market at the "roll back"
|
||||
m_base_price=m_symbol.NormalizePrice(MA(idx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- if the model 3 is used and the open price is below the indicator
|
||||
if(IS_PATTERN_USAGE(3) && DiffHighMA(idx)>0.0)
|
||||
{
|
||||
//--- the high price is above the indicator
|
||||
result=m_pattern_3;
|
||||
//--- consider that this is a formed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,91 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalITF.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of intraday time filter |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=IntradayTimeFilter |
|
||||
//| ShortName=ITF |
|
||||
//| Class=CSignalITF |
|
||||
//| Page=signal_time_filter |
|
||||
//| Parameter=GoodHourOfDay,int,-1,Good hour |
|
||||
//| Parameter=BadHoursOfDay,int,0,Bad hours (bit-map) |
|
||||
//| Parameter=GoodDayOfWeek,int,-1,Good day of week |
|
||||
//| Parameter=BadDaysOfWeek,int,0,Bad days of week (bit-map) |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalITF. |
|
||||
//| Appointment: Class trading signals time filter. |
|
||||
//| Derives from class CExpertSignal. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalITF : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
//--- input parameters
|
||||
int m_good_minute_of_hour;
|
||||
long m_bad_minutes_of_hour;
|
||||
int m_good_hour_of_day;
|
||||
int m_bad_hours_of_day;
|
||||
int m_good_day_of_week;
|
||||
int m_bad_days_of_week;
|
||||
|
||||
public:
|
||||
CSignalITF(void);
|
||||
~CSignalITF(void);
|
||||
//--- methods initialize protected data
|
||||
void GoodMinuteOfHour(int value) { m_good_minute_of_hour=value; }
|
||||
void BadMinutesOfHour(long value) { m_bad_minutes_of_hour=value; }
|
||||
void GoodHourOfDay(int value) { m_good_hour_of_day=value; }
|
||||
void BadHoursOfDay(int value) { m_bad_hours_of_day=value; }
|
||||
void GoodDayOfWeek(int value) { m_good_day_of_week=value; }
|
||||
void BadDaysOfWeek(int value) { m_bad_days_of_week=value; }
|
||||
//--- methods of checking conditions of entering the market
|
||||
virtual double Direction(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalITF::CSignalITF(void) : m_good_minute_of_hour(-1),
|
||||
m_bad_minutes_of_hour(0),
|
||||
m_good_hour_of_day(-1),
|
||||
m_bad_hours_of_day(0),
|
||||
m_good_day_of_week(-1),
|
||||
m_bad_days_of_week(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalITF::~CSignalITF(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check conditions for time filter. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSignalITF::Direction(void)
|
||||
{
|
||||
MqlDateTime s_time;
|
||||
//---
|
||||
TimeCurrent(s_time);
|
||||
//--- check days conditions
|
||||
if(!((m_good_day_of_week==-1 || m_good_day_of_week==s_time.day_of_week) &&
|
||||
!(m_bad_days_of_week&(1<<s_time.day_of_week))))
|
||||
return(EMPTY_VALUE);
|
||||
//--- check hours conditions
|
||||
if(!((m_good_hour_of_day==-1 || m_good_hour_of_day==s_time.hour) &&
|
||||
!(m_bad_hours_of_day&(1<<s_time.hour))))
|
||||
return(EMPTY_VALUE);
|
||||
//--- check minutes conditions
|
||||
if(!((m_good_minute_of_hour==-1 || m_good_minute_of_hour==s_time.min) &&
|
||||
!(m_bad_minutes_of_hour&(1<<s_time.min))))
|
||||
return(EMPTY_VALUE);
|
||||
//--- condition OK
|
||||
return(0.0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,261 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalMA.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of indicator 'Moving Average' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Moving Average |
|
||||
//| ShortName=MA |
|
||||
//| Class=CSignalMA |
|
||||
//| Page=signal_ma |
|
||||
//| Parameter=PeriodMA,int,12,Period of averaging |
|
||||
//| Parameter=Shift,int,0,Time shift |
|
||||
//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalMA. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Moving Average' indicator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalMA : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiMA m_ma; // object-indicator
|
||||
//--- adjusted parameters
|
||||
int m_ma_period; // the "period of averaging" parameter of the indicator
|
||||
int m_ma_shift; // the "time shift" parameter of the indicator
|
||||
ENUM_MA_METHOD m_ma_method; // the "method of averaging" parameter of the indicator
|
||||
ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter of the indicator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "price is on the necessary side from the indicator"
|
||||
int m_pattern_1; // model 1 "price crossed the indicator with opposite direction"
|
||||
int m_pattern_2; // model 2 "price crossed the indicator with the same direction"
|
||||
int m_pattern_3; // model 3 "piercing"
|
||||
|
||||
public:
|
||||
CSignalMA(void);
|
||||
~CSignalMA(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodMA(int value) { m_ma_period=value; }
|
||||
void Shift(int value) { m_ma_shift=value; }
|
||||
void Method(ENUM_MA_METHOD value) { m_ma_method=value; }
|
||||
void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the indicator
|
||||
bool InitMA(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double MA(int ind) { return(m_ma.Main(ind)); }
|
||||
double DiffMA(int ind) { return(MA(ind)-MA(ind+1)); }
|
||||
double DiffOpenMA(int ind) { return(Open(ind)-MA(ind)); }
|
||||
double DiffHighMA(int ind) { return(High(ind)-MA(ind)); }
|
||||
double DiffLowMA(int ind) { return(Low(ind)-MA(ind)); }
|
||||
double DiffCloseMA(int ind) { return(Close(ind)-MA(ind)); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalMA::CSignalMA(void) : m_ma_period(12),
|
||||
m_ma_shift(0),
|
||||
m_ma_method(MODE_SMA),
|
||||
m_ma_applied(PRICE_CLOSE),
|
||||
m_pattern_0(80),
|
||||
m_pattern_1(10),
|
||||
m_pattern_2(60),
|
||||
m_pattern_3(60)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalMA::~CSignalMA(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalMA::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_ma_period<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period MA must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalMA::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize MA indicator
|
||||
if(!InitMA(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize MA indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalMA::InitMA(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_ma)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_ma.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalMA::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- analyze positional relationship of the close price and the indicator at the first analyzed bar
|
||||
if(DiffCloseMA(idx)<0.0)
|
||||
{
|
||||
//--- the close price is below the indicator
|
||||
if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)>0.0 && DiffMA(idx)>0.0)
|
||||
{
|
||||
//--- the open price is above the indicator (i.e. there was an intersection), but the indicator is directed upwards
|
||||
result=m_pattern_1;
|
||||
//--- consider that this is an unformed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- the close price is above the indicator (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the indicator is directed upwards
|
||||
if(DiffMA(idx)>0.0)
|
||||
{
|
||||
if(DiffOpenMA(idx)<0.0)
|
||||
{
|
||||
//--- if the model 2 is used
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- the open price is below the indicator (i.e. there was an intersection)
|
||||
result=m_pattern_2;
|
||||
//--- suggest to enter the market at the "roll back"
|
||||
m_base_price=m_symbol.NormalizePrice(MA(idx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- if the model 3 is used and the open price is above the indicator
|
||||
if(IS_PATTERN_USAGE(3) && DiffLowMA(idx)<0.0)
|
||||
{
|
||||
//--- the low price is below the indicator
|
||||
result=m_pattern_3;
|
||||
//--- consider that this is a formed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalMA::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- analyze positional relationship of the close price and the indicator at the first analyzed bar
|
||||
if(DiffCloseMA(idx)>0.0)
|
||||
{
|
||||
//--- the close price is above the indicator
|
||||
if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)<0.0 && DiffMA(idx)<0.0)
|
||||
{
|
||||
//--- the open price is below the indicator (i.e. there was an intersection), but the indicator is directed downwards
|
||||
result=m_pattern_1;
|
||||
//--- consider that this is an unformed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- the close price is below the indicator (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- the indicator is directed downwards
|
||||
if(DiffMA(idx)<0.0)
|
||||
{
|
||||
if(DiffOpenMA(idx)>0.0)
|
||||
{
|
||||
//--- if the model 2 is used
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- the open price is above the indicator (i.e. there was an intersection)
|
||||
result=m_pattern_2;
|
||||
//--- suggest to enter the market at the "roll back"
|
||||
m_base_price=m_symbol.NormalizePrice(MA(idx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- if the model 3 is used and the open price is below the indicator
|
||||
if(IS_PATTERN_USAGE(3) && DiffHighMA(idx)>0.0)
|
||||
{
|
||||
//--- the high price is above the indicator
|
||||
result=m_pattern_3;
|
||||
//--- consider that this is a formed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,408 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalMACD.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of oscillator 'MACD' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=MACD |
|
||||
//| ShortName=MACD |
|
||||
//| Class=CSignalMACD |
|
||||
//| Page=signal_macd |
|
||||
//| Parameter=PeriodFast,int,12,Period of fast EMA |
|
||||
//| Parameter=PeriodSlow,int,24,Period of slow EMA |
|
||||
//| Parameter=PeriodSignal,int,9,Period of averaging of difference |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalMACD. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Moving Average Convergence/Divergence' oscillator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalMACD : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiMACD m_MACD; // object-oscillator
|
||||
//--- adjusted parameters
|
||||
int m_period_fast; // the "period of fast EMA" parameter of the oscillator
|
||||
int m_period_slow; // the "period of slow EMA" parameter of the oscillator
|
||||
int m_period_signal; // the "period of averaging of difference" parameter of the oscillator
|
||||
ENUM_APPLIED_PRICE m_applied; // the "price series" parameter of the oscillator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "the oscillator has required direction"
|
||||
int m_pattern_1; // model 1 "reverse of the oscillator to required direction"
|
||||
int m_pattern_2; // model 2 "crossing of main and signal line"
|
||||
int m_pattern_3; // model 3 "crossing of main line an the zero level"
|
||||
int m_pattern_4; // model 4 "divergence of the oscillator and price"
|
||||
int m_pattern_5; // model 5 "double divergence of the oscillator and price"
|
||||
//--- variables
|
||||
double m_extr_osc[10]; // array of values of extremums of the oscillator
|
||||
double m_extr_pr[10]; // array of values of the corresponding extremums of price
|
||||
int m_extr_pos[10]; // array of shifts of extremums (in bars)
|
||||
uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price
|
||||
|
||||
public:
|
||||
CSignalMACD(void);
|
||||
~CSignalMACD(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodFast(int value) { m_period_fast=value; }
|
||||
void PeriodSlow(int value) { m_period_slow=value; }
|
||||
void PeriodSignal(int value) { m_period_signal=value; }
|
||||
void Applied(ENUM_APPLIED_PRICE value) { m_applied=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
void Pattern_4(int value) { m_pattern_4=value; }
|
||||
void Pattern_5(int value) { m_pattern_5=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the oscillator
|
||||
bool InitMACD(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double Main(int ind) { return(m_MACD.Main(ind)); }
|
||||
double Signal(int ind) { return(m_MACD.Signal(ind)); }
|
||||
double DiffMain(int ind) { return(Main(ind)-Main(ind+1)); }
|
||||
int StateMain(int ind);
|
||||
double State(int ind) { return(Main(ind)-Signal(ind)); }
|
||||
bool ExtState(int ind);
|
||||
bool CompareMaps(int map,int count,bool minimax=false,int start=0);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalMACD::CSignalMACD(void) : m_period_fast(12),
|
||||
m_period_slow(24),
|
||||
m_period_signal(9),
|
||||
m_applied(PRICE_CLOSE),
|
||||
m_pattern_0(10),
|
||||
m_pattern_1(30),
|
||||
m_pattern_2(80),
|
||||
m_pattern_3(50),
|
||||
m_pattern_4(60),
|
||||
m_pattern_5(100)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalMACD::~CSignalMACD(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalMACD::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_period_fast>=m_period_slow)
|
||||
{
|
||||
printf(__FUNCTION__+": slow period must be greater than fast period");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalMACD::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check of pointer is performed in the method of the parent class
|
||||
//---
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize MACD oscilator
|
||||
if(!InitMACD(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize MACD oscillators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalMACD::InitMACD(CIndicators *indicators)
|
||||
{
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_MACD)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_MACD.Create(m_symbol.Name(),m_period,m_period_fast,m_period_slow,m_period_signal,m_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check of the oscillator state. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalMACD::StateMain(int ind)
|
||||
{
|
||||
int res=0;
|
||||
double var;
|
||||
//---
|
||||
for(int i=ind;;i++)
|
||||
{
|
||||
if(Main(i+1)==EMPTY_VALUE)
|
||||
break;
|
||||
var=DiffMain(i);
|
||||
if(res>0)
|
||||
{
|
||||
if(var<0)
|
||||
break;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if(res<0)
|
||||
{
|
||||
if(var>0)
|
||||
break;
|
||||
res--;
|
||||
continue;
|
||||
}
|
||||
if(var>0)
|
||||
res++;
|
||||
if(var<0)
|
||||
res--;
|
||||
}
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Extended check of the oscillator state consists |
|
||||
//| in forming a bit-map according to certain rules, |
|
||||
//| which shows ratios of extremums of the oscillator and price. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalMACD::ExtState(int ind)
|
||||
{
|
||||
//--- operation of this method results in a bit-map of extremums
|
||||
//--- practically, the bit-map of extremums is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an element of the analyzed bit-map
|
||||
//--- bit 3 - not used (always 0)
|
||||
//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- bit 1 - not used (always 0)
|
||||
//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- in addition to them, the following is formed:
|
||||
//--- array of values of extremums of the oscillator,
|
||||
//--- array of values of price extremums and
|
||||
//--- array of "distances" between extremums of the oscillator (in bars)
|
||||
//--- it should be noted that when using the results of the extended check of state,
|
||||
//--- you should consider, which extremum of the oscillator (peak or valley)
|
||||
//--- is the "reference point" (i.e. was detected first during the analysis)
|
||||
//--- if a peak is detected first then even elements of all arrays
|
||||
//--- will contain information about peaks, and odd elements will contain information about valleys
|
||||
//--- if a valley is detected first, then respectively in reverse
|
||||
int pos=ind,off,index;
|
||||
uint map; // intermediate bit-map for one extremum
|
||||
//---
|
||||
m_extr_map=0;
|
||||
for(int i=0;i<10;i++)
|
||||
{
|
||||
off=StateMain(pos);
|
||||
if(off>0)
|
||||
{
|
||||
//--- minimum of the oscillator is detected
|
||||
pos+=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=Main(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_low.MinValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]<m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]<m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_low.MinValue(pos-1,4,index);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- maximum of the oscillator is detected
|
||||
pos-=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=Main(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]>m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]>m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-1,4,index);
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparing the bit-map of extremums with pattern. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalMACD::CompareMaps(int map,int count,bool minimax,int start)
|
||||
{
|
||||
int step =(minimax)?4:8;
|
||||
int total=step*(start+count);
|
||||
//--- check input parameters for a possible going out of range of the bit-map
|
||||
if(total>32)
|
||||
return(false);
|
||||
//--- bit-map of the patter is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the desired ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an elements of the pattern of the bit-map pattern
|
||||
//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us
|
||||
//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2
|
||||
//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us
|
||||
//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0
|
||||
//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
uint inp_map,check_map;
|
||||
int i,j;
|
||||
//--- loop by extremums (4 minimums and 4 maximums)
|
||||
//--- price and the oscillator are checked separately (thus, there are 16 checks)
|
||||
for(i=step*start,j=0;i<total;i+=step,j+=4)
|
||||
{
|
||||
//--- "take" two bits - patter of the corresponding extremum of the price
|
||||
inp_map=(map>>j)&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map<2)
|
||||
{
|
||||
//--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>i)&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- "take" two bits - pattern of the corresponding oscillator extremum
|
||||
inp_map=(map>>(j+2))&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map>=2)
|
||||
continue;
|
||||
//--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>(i+2))&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalMACD::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- check direction of the main line
|
||||
if(DiffMain(idx)>0.0)
|
||||
{
|
||||
//--- the main line is directed upwards, and it confirms the possibility of price growth
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, look for a reverse of the main line
|
||||
if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)<0.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 is used, look for an intersection of the main and signal line
|
||||
if(IS_PATTERN_USAGE(2) && State(idx)>0.0 && State(idx+1)<0.0)
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- if the model 3 is used, look for an intersection of the main line and the zero level
|
||||
if(IS_PATTERN_USAGE(3) && Main(idx)>0.0 && Main(idx+1)<0.0)
|
||||
result=m_pattern_3; // signal number 3
|
||||
//--- if the models 4 or 5 are used and the main line turned upwards below the zero level, look for divergences
|
||||
if((IS_PATTERN_USAGE(4) || IS_PATTERN_USAGE(5)) && Main(idx)<0.0)
|
||||
{
|
||||
//--- perform the extended analysis of the oscillator state
|
||||
ExtState(idx);
|
||||
//--- if the model 4 is used, look for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(4) && CompareMaps(1,1)) // 0000 0001b
|
||||
result=m_pattern_4; // signal number 4
|
||||
//--- if the model 5 is used, look for the "double divergence" signal
|
||||
if(IS_PATTERN_USAGE(5) && CompareMaps(0x11,2)) // 0001 0001b
|
||||
return(m_pattern_5); // signal number 5
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalMACD::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- check direction of the main line
|
||||
if(DiffMain(idx)<0.0)
|
||||
{
|
||||
//--- main line is directed downwards, confirming a possibility of falling of price
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, look for a reverse of the main line
|
||||
if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)>0.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 is used, look for an intersection of the main and signal line
|
||||
if(IS_PATTERN_USAGE(2) && State(idx)<0.0 && State(idx+1)>0.0)
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- if the model 3 is used, look for an intersection of the main line and the zero level
|
||||
if(IS_PATTERN_USAGE(3) && Main(idx)<0.0 && Main(idx+1)>0.0)
|
||||
result=m_pattern_3; // signal number 3
|
||||
//--- if the models 4 or 5 are used and the main line turned downwards above the zero level, look for divergences
|
||||
if((IS_PATTERN_USAGE(4) || IS_PATTERN_USAGE(5)) && Main(idx)>0.0)
|
||||
{
|
||||
//--- perform the extended analysis of the oscillator state
|
||||
ExtState(idx);
|
||||
//--- if the model 4 is used, look for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(4) && CompareMaps(1,1)) // 0000 0001b
|
||||
result=m_pattern_4; // signal number 4
|
||||
//--- if the model 5 is used, look for the "double divergence" signal
|
||||
if(IS_PATTERN_USAGE(5) && CompareMaps(0x11,2)) // 0001 0001b
|
||||
return(m_pattern_5); // signal number 5
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,400 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalRSI.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of oscillator 'Relative Strength Index' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Relative Strength Index |
|
||||
//| ShortName=RSI |
|
||||
//| Class=CSignalRSI |
|
||||
//| Page=signal_rsi |
|
||||
//| Parameter=PeriodRSI,int,8,Period of calculation |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalRSI. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Relative Strength Index' oscillator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalRSI : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiRSI m_rsi; // object-oscillator
|
||||
//--- adjusted parameters
|
||||
int m_periodRSI; // the "period of calculation" parameter of the oscillator
|
||||
ENUM_APPLIED_PRICE m_applied; // the "prices series" parameter of the oscillator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "the oscillator has required direction"
|
||||
int m_pattern_1; // model 1 "reverse behind the level of overbuying/overselling"
|
||||
int m_pattern_2; // model 2 "failed swing"
|
||||
int m_pattern_3; // model 3 "divergence of the oscillator and price"
|
||||
int m_pattern_4; // model 4 "double divergence of the oscillator and price"
|
||||
int m_pattern_5; // model 5 "head/shoulders"
|
||||
//--- variables
|
||||
double m_extr_osc[10]; // array of values of extremums of the oscillator
|
||||
double m_extr_pr[10]; // array of values of the corresponding extremums of price
|
||||
int m_extr_pos[10]; // array of shifts of extremums (in bars)
|
||||
uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price
|
||||
|
||||
public:
|
||||
CSignalRSI(void);
|
||||
~CSignalRSI(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodRSI(int value) { m_periodRSI=value; }
|
||||
void Applied(ENUM_APPLIED_PRICE value) { m_applied=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
void Pattern_4(int value) { m_pattern_4=value; }
|
||||
void Pattern_5(int value) { m_pattern_5=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the oscillator
|
||||
bool InitRSI(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double RSI(int ind) { return(m_rsi.Main(ind)); }
|
||||
double DiffRSI(int ind) { return(RSI(ind)-RSI(ind+1)); }
|
||||
int StateRSI(int ind);
|
||||
bool ExtStateRSI(int ind);
|
||||
bool CompareMaps(int map,int count,bool minimax=false,int start=0);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalRSI::CSignalRSI(void) : m_periodRSI(14),
|
||||
m_applied(PRICE_CLOSE),
|
||||
m_pattern_0(70),
|
||||
m_pattern_1(100),
|
||||
m_pattern_2(90),
|
||||
m_pattern_3(80),
|
||||
m_pattern_4(100),
|
||||
m_pattern_5(20)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalRSI::~CSignalRSI(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalRSI::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_periodRSI<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period of the RSI oscillator must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalRSI::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize RSI oscillator
|
||||
if(!InitRSI(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize RSI oscillators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalRSI::InitRSI(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_rsi)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_rsi.Create(m_symbol.Name(),m_period,m_periodRSI,m_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check of the oscillator state. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalRSI::StateRSI(int ind)
|
||||
{
|
||||
int res=0;
|
||||
double var;
|
||||
//---
|
||||
for(int i=ind;;i++)
|
||||
{
|
||||
if(RSI(i+1)==EMPTY_VALUE)
|
||||
break;
|
||||
var=DiffRSI(i);
|
||||
if(res>0)
|
||||
{
|
||||
if(var<0)
|
||||
break;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if(res<0)
|
||||
{
|
||||
if(var>0)
|
||||
break;
|
||||
res--;
|
||||
continue;
|
||||
}
|
||||
if(var>0)
|
||||
res++;
|
||||
if(var<0)
|
||||
res--;
|
||||
}
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Extended check of the oscillator state consists |
|
||||
//| in forming a bit-map according to certain rules, |
|
||||
//| which shows ratios of extremums of the oscillator and price. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalRSI::ExtStateRSI(int ind)
|
||||
{
|
||||
//--- operation of this method results in a bit-map of extremums
|
||||
//--- practically, the bit-map of extremums is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an element of the analyzed bit-map
|
||||
//--- bit 3 - not used (always 0)
|
||||
//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- bit 1 - not used (always 0)
|
||||
//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- in addition to them, the following is formed:
|
||||
//--- array of values of extremums of the oscillator,
|
||||
//--- array of values of price extremums and
|
||||
//--- array of "distances" between extremums of the oscillator (in bars)
|
||||
//--- it should be noted that when using the results of the extended check of state,
|
||||
//--- you should consider, which extremum of the oscillator (peak or valley)
|
||||
//--- is the "reference point" (i.e. was detected first during the analysis)
|
||||
//--- if a peak is detected first then even elements of all arrays
|
||||
//--- will contain information about peaks, and odd elements will contain information about valleys
|
||||
//--- if a valley is detected first, then respectively in reverse
|
||||
int pos=ind,off,index;
|
||||
uint map; // intermediate bit-map for one extremum
|
||||
//---
|
||||
m_extr_map=0;
|
||||
for(int i=0;i<10;i++)
|
||||
{
|
||||
off=StateRSI(pos);
|
||||
if(off>0)
|
||||
{
|
||||
//--- minimum of the oscillator is detected
|
||||
pos+=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=RSI(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_low.MinValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]<m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]<m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_low.MinValue(pos-1,4,index);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- maximum of the oscillator is detected
|
||||
pos-=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=RSI(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]>m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]>m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-1,4,index);
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparing the bit-map of extremums with pattern. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalRSI::CompareMaps(int map,int count,bool minimax,int start)
|
||||
{
|
||||
int step =(minimax)?4:8;
|
||||
int total=step*(start+count);
|
||||
//--- check input parameters for a possible going out of range of the bit-map
|
||||
if(total>32)
|
||||
return(false);
|
||||
//--- bit-map of the patter is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the desired ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an elements of the pattern of the bit-map pattern
|
||||
//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us
|
||||
//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2
|
||||
//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us
|
||||
//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0
|
||||
//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
uint inp_map,check_map;
|
||||
int i,j;
|
||||
//--- loop by extremums (4 minimums and 4 maximums)
|
||||
//--- price and the oscillator are checked separately (thus, there are 16 checks)
|
||||
for(i=step*start,j=0;i<total;i+=step,j+=4)
|
||||
{
|
||||
//--- "take" two bits - patter of the corresponding extremum of the price
|
||||
inp_map=(map>>j)&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map<2)
|
||||
{
|
||||
//--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>i)&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- "take" two bits - pattern of the corresponding oscillator extremum
|
||||
inp_map=(map>>(j+2))&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map>=2)
|
||||
continue;
|
||||
//--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>(i+2))&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalRSI::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//---
|
||||
if(DiffRSI(idx)>0.0)
|
||||
{
|
||||
//--- the oscillator is directed upwards confirming the possibility of price growth
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, search for a reverse of the oscillator upwards behind the level of overselling
|
||||
if(IS_PATTERN_USAGE(1) && DiffRSI(idx+1)<0.0 && RSI(idx+1)<30.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2, 3, 4 or 5 is used, perform the extended analysis of the oscillator state
|
||||
if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3) || IS_PATTERN_USAGE(4) || IS_PATTERN_USAGE(5))
|
||||
{
|
||||
ExtStateRSI(idx);
|
||||
//--- search for the "failed swing" signal
|
||||
if(IS_PATTERN_USAGE(2) && RSI(idx)>m_extr_osc[1])
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- search for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(3) && CompareMaps(1,1)) // 0000 0001b
|
||||
result=m_pattern_3; // signal number 3
|
||||
//--- search for the "double divergence" signal
|
||||
if(IS_PATTERN_USAGE(4) && CompareMaps(0x11,2)) // 0001 0001b
|
||||
return(m_pattern_4); // signal number 4
|
||||
//--- search for the "head/shoulders" signal
|
||||
if(IS_PATTERN_USAGE(5) && CompareMaps(0x62662,5,true) && RSI(idx)>m_extr_osc[1]) // 01100010011001100010b
|
||||
result=m_pattern_5; // signal number 5
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalRSI::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//---
|
||||
if(DiffRSI(idx)<0.0)
|
||||
{
|
||||
//--- the oscillator is directed downwards confirming the possibility of falling of price
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, search for a reverse of the oscillator downwards behind the level of overbuying
|
||||
if(IS_PATTERN_USAGE(1) && DiffRSI(idx+1)>0.0 && RSI(idx+1)>70.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2, 3, 4 or 5 is used, perform the extended analysis of the oscillator state
|
||||
if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3) || IS_PATTERN_USAGE(4) || IS_PATTERN_USAGE(5))
|
||||
{
|
||||
ExtStateRSI(idx);
|
||||
//--- search for the "failed swing" signal
|
||||
if(IS_PATTERN_USAGE(2) && RSI(idx)<m_extr_osc[1])
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- search for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(3) && CompareMaps(1,1)) // 0000 0001b
|
||||
result=m_pattern_3; // signal number 3
|
||||
//--- search for the "double divergence" signal
|
||||
if(IS_PATTERN_USAGE(4) && CompareMaps(0x11,2)) // 0001 0001b
|
||||
return(m_pattern_4); // signal number 4
|
||||
//--- search for the "head/shoulders" signal
|
||||
if(IS_PATTERN_USAGE(5) && CompareMaps(0x62662,5,true) && RSI(idx)<m_extr_osc[1]) // 01100010011001100010b
|
||||
result=m_pattern_5; // signal number 5
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,180 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalRVI.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of oscillator 'Relative Vigor Index' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Relative Vigor Index |
|
||||
//| ShortName=RVI |
|
||||
//| Class=CSignalRVI |
|
||||
//| Page=signal_rvi |
|
||||
//| Parameter=PeriodRVI,int,10,Period of calculation |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalRVI. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Relative Vigor Index' oscillator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalRVI : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiRVI m_rvi; // object-oscillator
|
||||
//--- adjusted parameters
|
||||
int m_periodRVI; // the "period of calculation" parameter of the oscillator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "the oscillator has required direction"
|
||||
int m_pattern_1; // model 1 "crossing of main and signal line"
|
||||
|
||||
public:
|
||||
CSignalRVI(void);
|
||||
~CSignalRVI(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodRVI(int value) { m_periodRVI=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the oscillator
|
||||
bool InitRVI(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double Main(int ind) { return(m_rvi.Main(ind)); }
|
||||
double DiffMain(int ind) { return(Main(ind)-Main(ind+1)); }
|
||||
double Signal(int ind) { return(m_rvi.Signal(ind)); }
|
||||
double DiffSignal(int ind) { return(Signal(ind)-Signal(ind+1)); }
|
||||
double DiffMainSignal(int ind) { return(Main(ind)-Signal(ind)); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalRVI::CSignalRVI(void) : m_periodRVI(10),
|
||||
m_pattern_0(60),
|
||||
m_pattern_1(100)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalRVI::~CSignalRVI(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalRVI::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_periodRVI<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": the period of calculation of the RVI oscillator must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalRVI::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize RVI oscillator
|
||||
if(!InitRVI(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize RVI oscillators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalRVI::InitRVI(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_rvi)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_rvi.Create(m_symbol.Name(),m_period,m_periodRVI))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalRVI::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//---
|
||||
if(DiffMain(idx)>0.0)
|
||||
{
|
||||
//--- the main line of the oscillator is directed upwards confirming the possibility of price growth
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal
|
||||
//--- if the main line crosses the signal line upwards, this is a signal for buying
|
||||
if(DiffMainSignal(idx)>0 && DiffMainSignal(idx+1)<0)
|
||||
{
|
||||
//--- the main line of the oscillator has crossed the signal line upwards (signal for buying)
|
||||
if(IS_PATTERN_USAGE(1))
|
||||
result=m_pattern_1; // signal number 1
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalRVI::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//---
|
||||
if(DiffMain(idx)<0.0)
|
||||
{
|
||||
//--- the main line of the oscillator is directed downwards confirming the possibility of falling of price
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal
|
||||
//--- if the main line crosses the signal line from top downwards, this is a signal for selling
|
||||
if(DiffMainSignal(idx)<0 && DiffMainSignal(idx+1)>0)
|
||||
{
|
||||
//--- the main line of the oscillator has crossed the signal line from top downwards (signal for selling)
|
||||
if(IS_PATTERN_USAGE(1))
|
||||
result=m_pattern_1; // signal number 1
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,168 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalSAR.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of indicator 'Parabolic SAR' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Parabolic SAR |
|
||||
//| ShortName=SAR |
|
||||
//| Class=CSignalSAR |
|
||||
//| Page=signal_sar |
|
||||
//| Parameter=Step,double,0.02,Speed increment |
|
||||
//| Parameter=Maximum,double,0.2,Maximum rate |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalSAR. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Parabolic SAR' indicator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalSAR : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiSAR m_sar; // object-indicator
|
||||
//--- adjusted parameters
|
||||
double m_step; // the "speed increment" parameter of the indicator
|
||||
double m_maximum; // the "maximum rate" parameter of the indicator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "the parabolic is on the necessary side from the price"
|
||||
int m_pattern_1; // model 1 "the parabolic has 'switched'"
|
||||
|
||||
public:
|
||||
CSignalSAR(void);
|
||||
~CSignalSAR(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void Step(double value) { m_step=value; }
|
||||
void Maximum(double value) { m_maximum=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the indicator
|
||||
bool InitSAR(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double SAR(int ind) { return(m_sar.Main(ind)); }
|
||||
double Close(int ind) { return(m_close.GetData(ind)); }
|
||||
double DiffClose(int ind) { return(Close(ind)-SAR(ind)); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalSAR::CSignalSAR(void) : m_step(0.02),
|
||||
m_maximum(0.2),
|
||||
m_pattern_0(40),
|
||||
m_pattern_1(90)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_CLOSE;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalSAR::~CSignalSAR(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalSAR::ValidationSettings(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalSAR::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize SAR indicator
|
||||
if(!InitSAR(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create SAR indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalSAR::InitSAR(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_sar)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_sar.Create(m_symbol.Name(),m_period,m_step,m_maximum))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalSAR::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- if the indicator is above the price at the first analyzed bar, don't 'vote' buying
|
||||
if(DiffClose(idx++)<0.0)
|
||||
return(result);
|
||||
//--- the indicator is below the price at the first analyzed bar (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the indicator is above the price at the second analyzed bar, then there is a condition for buying
|
||||
if(IS_PATTERN_USAGE(1) && DiffClose(idx)<0.0)
|
||||
return(m_pattern_1);
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalSAR::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- if the indicator is below the price at the first analyzed bar, don't "vote" for selling
|
||||
if(DiffClose(idx++)>0.0)
|
||||
return(result);
|
||||
//--- the indicator is above the price at the first analyzed bar (the indicator has no objections to selling)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the indicator is below the price at the second analyzed bar, then there is a condition for selling
|
||||
if(IS_PATTERN_USAGE(1) && DiffClose(idx)>0.0)
|
||||
return(m_pattern_1);
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,426 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalStoch.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of oscillator 'Stochastic' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Stochastic |
|
||||
//| ShortName=Stoch |
|
||||
//| Class=CSignalStoch |
|
||||
//| Page=signal_stochastic |
|
||||
//| Parameter=PeriodK,int,8,K-period |
|
||||
//| Parameter=PeriodD,int,3,D-period |
|
||||
//| Parameter=PeriodSlow,int,3,Period of slowing |
|
||||
//| Parameter=Applied,ENUM_STO_PRICE,STO_LOWHIGH,Prices to apply to |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalStoch. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Stochastic' oscillator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalStoch : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiStochastic m_stoch; // object-oscillator
|
||||
CPriceSeries *m_app_price_high; // pointer to the object-timeseries for determining divergences directed downwards
|
||||
CPriceSeries *m_app_price_low; // pointer to the object-timeseries for determining divergences directed upwards
|
||||
//--- adjusted parameters
|
||||
int m_periodK; // the "period %K" parameter of the oscillator
|
||||
int m_periodD; // the "period %D" parameter of the oscillator
|
||||
int m_period_slow; // the "period of slowing" parameter of the oscillator
|
||||
ENUM_STO_PRICE m_applied; // the "apply to" parameter of the oscillator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "the oscillator has required direction"
|
||||
int m_pattern_1; // model 1 "reverse of the oscillator to required direction"
|
||||
int m_pattern_2; // model 2 "crossing of main and signal line"
|
||||
int m_pattern_3; // model 3 "divergence of the oscillator and price"
|
||||
int m_pattern_4; // model 4 "double divergence of the oscillator and price"
|
||||
//--- variables
|
||||
double m_extr_osc[10]; // array of values of extremums of the oscillator
|
||||
double m_extr_pr[10]; // array of values of the corresponding extremums of price
|
||||
int m_extr_pos[10]; // array of shifts of extremums (in bars)
|
||||
uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price
|
||||
|
||||
public:
|
||||
CSignalStoch(void);
|
||||
~CSignalStoch(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodK(int value) { m_periodK=value; }
|
||||
void PeriodD(int value) { m_periodD=value; }
|
||||
void PeriodSlow(int value) { m_period_slow=value; }
|
||||
void Applied(ENUM_STO_PRICE value) { m_applied=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
void Pattern_4(int value) { m_pattern_4=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the oscillator
|
||||
bool InitStoch(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double Main(int ind) { return(m_stoch.Main(ind)); }
|
||||
double DiffMain(int ind) { return(Main(ind)-Main(ind+1)); }
|
||||
double Signal(int ind) { return(m_stoch.Signal(ind)); }
|
||||
double DiffSignal(int ind) { return(Signal(ind)-Signal(ind+1)); }
|
||||
double DiffMainSignal(int ind) { return(Main(ind)-Signal(ind)); }
|
||||
int StateStoch(int ind);
|
||||
bool ExtStateStoch(int ind);
|
||||
bool CompareMaps(int map,int count,bool minimax=false,int start=0);
|
||||
void DiverDebugPrint();
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalStoch::CSignalStoch(void) : m_periodK(8),
|
||||
m_periodD(3),
|
||||
m_period_slow(3),
|
||||
m_applied(STO_LOWHIGH),
|
||||
m_pattern_0(30),
|
||||
m_pattern_1(60),
|
||||
m_pattern_2(50),
|
||||
m_pattern_3(100),
|
||||
m_pattern_4(90)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalStoch::~CSignalStoch(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalStoch::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_periodK<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": the period %K of the Stochastic oscillator must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
if(m_periodD<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": the period %D of the Stochastic oscillator must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalStoch::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize Stochastic oscillator
|
||||
if(!InitStoch(indicators))
|
||||
return(false);
|
||||
if(m_applied==STO_CLOSECLOSE)
|
||||
{
|
||||
//--- copying the Close timeseries
|
||||
m_app_price_high=GetPointer(m_close);
|
||||
//--- copying the Close timeseries
|
||||
m_app_price_low=GetPointer(m_close);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copying the High timeseries
|
||||
m_app_price_high=GetPointer(m_high);
|
||||
//--- copying the Low timeseries
|
||||
m_app_price_low=GetPointer(m_low);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize Stochastic oscillators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalStoch::InitStoch(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_stoch)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_stoch.Create(m_symbol.Name(),m_period,m_periodK,m_periodD,m_period_slow,MODE_SMA,m_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check of the oscillator state. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalStoch::StateStoch(int ind)
|
||||
{
|
||||
int res=0;
|
||||
double var;
|
||||
//---
|
||||
for(int i=ind;;i++)
|
||||
{
|
||||
if(Main(i+1)==EMPTY_VALUE)
|
||||
break;
|
||||
var=DiffMain(i);
|
||||
if(res>0)
|
||||
{
|
||||
if(var<0)
|
||||
break;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if(res<0)
|
||||
{
|
||||
if(var>0)
|
||||
break;
|
||||
res--;
|
||||
continue;
|
||||
}
|
||||
if(var>0)
|
||||
res++;
|
||||
if(var<0)
|
||||
res--;
|
||||
}
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Extended check of the oscillator state consists |
|
||||
//| in forming a bit-map according to certain rules, |
|
||||
//| which shows ratios of extremums of the oscillator and price. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalStoch::ExtStateStoch(int ind)
|
||||
{
|
||||
//--- operation of this method results in a bit-map of extremums
|
||||
//--- practically, the bit-map of extremums is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an element of the analyzed bit-map
|
||||
//--- bit 3 - not used (always 0)
|
||||
//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- bit 1 - not used (always 0)
|
||||
//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- in addition to them, the following is formed:
|
||||
//--- array of values of extremums of the oscillator,
|
||||
//--- array of values of price extremums and
|
||||
//--- array of "distances" between extremums of the oscillator (in bars)
|
||||
//--- it should be noted that when using the results of the extended check of state,
|
||||
//--- you should consider, which extremum of the oscillator (peak or valley)
|
||||
//--- is the "reference point" (i.e. was detected first during the analysis)
|
||||
//--- if a peak is detected first then even elements of all arrays
|
||||
//--- will contain information about peaks, and odd elements will contain information about valleys
|
||||
//--- if a valley is detected first, then respectively in reverse
|
||||
int pos=ind,off,index;
|
||||
uint map; // intermediate bit-map for one extremum
|
||||
//---
|
||||
m_extr_map=0;
|
||||
for(int i=0;i<10;i++)
|
||||
{
|
||||
off=StateStoch(pos);
|
||||
if(off>0)
|
||||
{
|
||||
//--- minimum of the oscillator is detected
|
||||
pos+=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=Main(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_low.MinValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]<m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]<m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_low.MinValue(pos-1,4,index);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- maximum of the oscillator is detected
|
||||
pos-=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=Main(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]>m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]>m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-1,4,index);
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparing the bit-map of extremums with pattern. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalStoch::CompareMaps(int map,int count,bool minimax=false,int start=0)
|
||||
{
|
||||
int step =(minimax)?4:8;
|
||||
int total=step*(start+count);
|
||||
//--- check input parameters for a possible going out of range of the bit-map
|
||||
if(total>32)
|
||||
return(false);
|
||||
//--- bit-map of the patter is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the desired ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an elements of the pattern of the bit-map pattern
|
||||
//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us
|
||||
//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2
|
||||
//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us
|
||||
//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0
|
||||
//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
uint inp_map,check_map;
|
||||
int i,j;
|
||||
//--- loop by extremums (4 minimums and 4 maximums)
|
||||
//--- price and the oscillator are checked separately (thus, there are 16 checks)
|
||||
for(i=step*start,j=0;i<total;i+=step,j+=4)
|
||||
{
|
||||
//--- "take" two bits - patter of the corresponding extremum of the price
|
||||
inp_map=(map>>j)&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map<2)
|
||||
{
|
||||
//--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>i)&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- "take" two bits - pattern of the corresponding oscillator extremum
|
||||
inp_map=(map>>(j+2))&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map>=2)
|
||||
continue;
|
||||
//--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>(i+2))&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalStoch::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- check direction of the main line
|
||||
if(DiffMain(idx)>0.0)
|
||||
{
|
||||
//--- the main line is directed upwards, and it confirms the possibility of price growth
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, look for a reverse of the main line
|
||||
if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)<0.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 is used, look for an intersection of the main and signal line
|
||||
if(IS_PATTERN_USAGE(2) && DiffMainSignal(idx)>0.0 && DiffMainSignal(idx+1)<0.0)
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- if the models 3 or 4 are used, look for divergences
|
||||
if((IS_PATTERN_USAGE(3) || IS_PATTERN_USAGE(4)))
|
||||
{
|
||||
//--- perform the extended analysis of the oscillator state
|
||||
ExtStateStoch(idx);
|
||||
//--- if the model 3 is used, look for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(3) && CompareMaps(1,1)) // 0000 0001b
|
||||
result=m_pattern_3; // signal number 3
|
||||
//--- if the model 4 is used, look for the "double divergence" signal
|
||||
if(IS_PATTERN_USAGE(4) && CompareMaps(0x11,2)) // 0001 0001b
|
||||
return(m_pattern_4); // signal number 4
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalStoch::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- check direction of the main line
|
||||
if(DiffMain(idx)<0.0)
|
||||
{
|
||||
//--- main line is directed downwards, confirming a possibility of falling of price
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, look for a reverse of the main line
|
||||
if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)>0.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 is used, look for an intersection of the main and signal line
|
||||
if(IS_PATTERN_USAGE(2) && DiffMainSignal(idx)<0.0 && DiffMainSignal(idx+1)>0.0)
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- if the models 3 or 4 are used, look for divergences
|
||||
if((IS_PATTERN_USAGE(3) || IS_PATTERN_USAGE(4)))
|
||||
{
|
||||
//--- perform the extended analysis of the oscillator state
|
||||
ExtStateStoch(idx);
|
||||
//--- if the model 3 is used, look for the "divergence" signal
|
||||
if(IS_PATTERN_USAGE(3) && CompareMaps(1,1)) // 0000 0001b
|
||||
result=m_pattern_3; // signal number 3
|
||||
//--- if the model 4 is used, look for the "double divergence" signal
|
||||
if(IS_PATTERN_USAGE(4) && CompareMaps(0x11,2)) // 0001 0001b
|
||||
return(m_pattern_4); // signal number 4
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,257 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalTEMA.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of indicator 'Triple Exponential Moving Average' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Triple Exponential Moving Average |
|
||||
//| ShortName=TEMA |
|
||||
//| Class=CSignalTEMA |
|
||||
//| Page=signal_tema |
|
||||
//| Parameter=PeriodMA,int,12,Period of averaging |
|
||||
//| Parameter=Shift,int,0,Time shift |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalTEMA. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Triple Exponential Moving Average' indicator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalTEMA : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiTEMA m_ma; // object-indicator
|
||||
//--- adjusted parameters
|
||||
int m_ma_period; // the "period of averaging" parameter of the indicator
|
||||
int m_ma_shift; // the "time shift" parameter of the indicator
|
||||
ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter" of the indicator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "price is on the necessary side from the indicator"
|
||||
int m_pattern_1; // model 1 "price crossed the indicator with opposite direction"
|
||||
int m_pattern_2; // model 2 "price crossed the indicator with the same direction"
|
||||
int m_pattern_3; // model 3 "piercing"
|
||||
|
||||
public:
|
||||
CSignalTEMA(void);
|
||||
~CSignalTEMA(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodMA(int value) { m_ma_period=value; }
|
||||
void Shift(int value) { m_ma_shift=value; }
|
||||
void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the indicator
|
||||
bool InitMA(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double MA(int ind) { return(m_ma.Main(ind)); }
|
||||
double DiffMA(int ind) { return(MA(ind)-MA(ind+1)); }
|
||||
double DiffOpenMA(int ind) { return(Open(ind)-MA(ind)); }
|
||||
double DiffHighMA(int ind) { return(High(ind)-MA(ind)); }
|
||||
double DiffLowMA(int ind) { return(Low(ind)-MA(ind)); }
|
||||
double DiffCloseMA(int ind) { return(Close(ind)-MA(ind)); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalTEMA::CSignalTEMA(void) : m_ma_period(12),
|
||||
m_ma_shift(0),
|
||||
m_ma_applied(PRICE_CLOSE),
|
||||
m_pattern_0(50),
|
||||
m_pattern_1(10),
|
||||
m_pattern_2(60),
|
||||
m_pattern_3(60)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalTEMA::~CSignalTEMA(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalTEMA::ValidationSettings(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_ma_period<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period MA must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalTEMA::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize TEMA indicator
|
||||
if(!InitMA(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create MA indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalTEMA::InitMA(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_ma)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_ma.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalTEMA::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- analyze positional relationship of the close price and the indicator at the first analyzed bar
|
||||
if(DiffCloseMA(idx)<0.0)
|
||||
{
|
||||
//--- the close price is below the indicator
|
||||
if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)>0.0 && DiffMA(idx)>0.0)
|
||||
{
|
||||
//--- the open price is above the indicator (i.e. there was an intersection), but the indicator is directed upwards
|
||||
result=m_pattern_1;
|
||||
//--- consider that this is an unformed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- the close price is above the indicator (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- if the indicator is directed upwards
|
||||
if(DiffMA(idx)>0.0)
|
||||
{
|
||||
if(DiffOpenMA(idx)<0.0)
|
||||
{
|
||||
//--- if the model 2 is used
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- the open price is below the indicator (i.e. there was an intersection)
|
||||
result=m_pattern_2;
|
||||
//--- suggest to enter the market at the "roll back"
|
||||
m_base_price=m_symbol.NormalizePrice(MA(idx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- if the model 3 is used and the open price is above the indicator
|
||||
if(IS_PATTERN_USAGE(3) && DiffLowMA(idx)<0.0)
|
||||
{
|
||||
//--- the low price is below the indicator
|
||||
result=m_pattern_3;
|
||||
//--- consider that this is a formed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalTEMA::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- analyze positional relationship of the close price and the indicator at the first analyzed bar
|
||||
if(DiffCloseMA(idx)>0.0)
|
||||
{
|
||||
//--- the close price is above the indicator
|
||||
if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)<0.0 && DiffMA(idx)<0.0)
|
||||
{
|
||||
//--- the open price is below the indicator (i.e. there was an intersection), but the indicator is directed downwards
|
||||
result=m_pattern_1;
|
||||
//--- consider that this is an unformed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- the close price is below the indicator (the indicator has no objections to buying)
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0;
|
||||
//--- the indicator is directed downwards
|
||||
if(DiffMA(idx)<0.0)
|
||||
{
|
||||
if(DiffOpenMA(idx)>0.0)
|
||||
{
|
||||
//--- if the model 2 is used
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- the open price is above the indicator (i.e. there was an intersection)
|
||||
result=m_pattern_2;
|
||||
//--- suggest to enter the market at the "roll back"
|
||||
m_base_price=m_symbol.NormalizePrice(MA(idx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- if the model 3 is used and the open price is below the indicator
|
||||
if(IS_PATTERN_USAGE(3) && DiffHighMA(idx)>0.0)
|
||||
{
|
||||
//--- the high price is above the indicator
|
||||
result=m_pattern_3;
|
||||
//--- consider that this is a formed "piercing" and suggest to enter the market at the current price
|
||||
m_base_price=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,395 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalTRIX.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of oscillator 'Triple Exponential Average' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Triple Exponential Average |
|
||||
//| ShortName=TriX |
|
||||
//| Class=CSignalTriX |
|
||||
//| Page=signal_trix |
|
||||
//| Parameter=PeriodTriX,int,14,Period of calculation |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalTriX. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Triple Exponential Average' oscillator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalTriX : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiTriX m_trix; // object-oscillator
|
||||
//--- adjusted parameters
|
||||
int m_period_trix; // the "period of calculation" parameter of the oscillator
|
||||
ENUM_APPLIED_PRICE m_applied; // the "price series" parameter of the oscillator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "the oscillator has required direction"
|
||||
int m_pattern_1; // model 1 "reverse of the oscillator to required direction"
|
||||
int m_pattern_2; // model 2 "crossing of main line an the zero level"
|
||||
int m_pattern_3; // model 3 "divergence of the oscillator and price"
|
||||
//--- variables
|
||||
double m_extr_osc[10]; // array of values of extremums of the oscillator
|
||||
double m_extr_pr[10]; // array of values of the corresponding extremums of price
|
||||
int m_extr_pos[10]; // array of shifts of extremums (in bars)
|
||||
uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price
|
||||
|
||||
public:
|
||||
CSignalTriX(void);
|
||||
~CSignalTriX(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodTriX(int value) { m_period_trix=value; }
|
||||
void Applied(ENUM_APPLIED_PRICE value) { m_applied=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
void Pattern_3(int value) { m_pattern_3=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the oscillator
|
||||
bool InitTriX(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
double TriX(int ind) { return(m_trix.Main(ind)); }
|
||||
double DiffTriX(int ind) { return(TriX(ind)-TriX(ind+1)); }
|
||||
int State(int ind);
|
||||
bool ExtState(int ind);
|
||||
bool CompareMaps(int map,int count,bool minimax=false,int start=0);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalTriX::CSignalTriX(void) : m_period_trix(12),
|
||||
m_applied(PRICE_CLOSE),
|
||||
m_pattern_0(20),
|
||||
m_pattern_1(80),
|
||||
m_pattern_2(100),
|
||||
m_pattern_3(70)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalTriX::~CSignalTriX(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalTriX::ValidationSettings(void)
|
||||
{
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//---
|
||||
if(m_period_trix<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalTriX::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize TriX oscilator
|
||||
if(!InitTriX(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize TriX oscillators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalTriX::InitTriX(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_trix)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_trix.Create(m_symbol.Name(),m_period,m_period_trix,m_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check of the oscillator state. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalTriX::State(int ind)
|
||||
{
|
||||
int res=0;
|
||||
double var;
|
||||
//---
|
||||
for(int i=ind;;i++)
|
||||
{
|
||||
if(TriX(i+1)==EMPTY_VALUE)
|
||||
break;
|
||||
var=DiffTriX(i);
|
||||
if(res>0)
|
||||
{
|
||||
if(var<0)
|
||||
break;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if(res<0)
|
||||
{
|
||||
if(var>0)
|
||||
break;
|
||||
res--;
|
||||
continue;
|
||||
}
|
||||
if(var>0)
|
||||
res++;
|
||||
if(var<0)
|
||||
res--;
|
||||
}
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Extended check of the oscillator state consists |
|
||||
//| in forming a bit-map according to certain rules, |
|
||||
//| which shows ratios of extremums of the oscillator and price. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalTriX::ExtState(int ind)
|
||||
{
|
||||
//--- operation of this method results in a bit-map of extremums
|
||||
//--- practically, the bit-map of extremums is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an element of the analyzed bit-map
|
||||
//--- bit 3 - not used (always 0)
|
||||
//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- bit 1 - not used (always 0)
|
||||
//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- in addition to them, the following is formed:
|
||||
//--- array of values of extremums of the oscillator,
|
||||
//--- array of values of price extremums and
|
||||
//--- array of "distances" between extremums of the oscillator (in bars)
|
||||
//--- it should be noted that when using the results of the extended check of state,
|
||||
//--- you should consider, which extremum of the oscillator (peak or valley)
|
||||
//--- is the "reference point" (i.e. was detected first during the analysis)
|
||||
//--- if a peak is detected first then even elements of all arrays
|
||||
//--- will contain information about peaks, and odd elements will contain information about valleys
|
||||
//--- if a valley is detected first, then respectively in reverse
|
||||
int pos=ind,off,index;
|
||||
uint map; // intermediate bit-map for one extremum
|
||||
//---
|
||||
m_extr_map=0;
|
||||
for(int i=0;i<10;i++)
|
||||
{
|
||||
off=State(pos);
|
||||
if(off>0)
|
||||
{
|
||||
//--- minimum of the oscillator is detected
|
||||
pos+=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=TriX(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_low.MinValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]<m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]<m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_low.MinValue(pos-1,4,index);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- maximum of the oscillator is detected
|
||||
pos-=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=TriX(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]>m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]>m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-1,4,index);
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparing the bit-map of extremums with pattern. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalTriX::CompareMaps(int map,int count,bool minimax,int start)
|
||||
{
|
||||
int step =(minimax)?4:8;
|
||||
int total=step*(start+count);
|
||||
//--- check input parameters for a possible going out of range of the bit-map
|
||||
if(total>32)
|
||||
return(false);
|
||||
//--- bit-map of the patter is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the desired ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an elements of the pattern of the bit-map pattern
|
||||
//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us
|
||||
//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2
|
||||
//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us
|
||||
//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0
|
||||
//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
uint inp_map,check_map;
|
||||
int i,j;
|
||||
//--- loop by extremums (4 minimums and 4 maximums)
|
||||
//--- price and the oscillator are checked separately (thus, there are 16 checks)
|
||||
for(i=step*start,j=0;i<total;i+=step,j+=4)
|
||||
{
|
||||
//--- "take" two bits - patter of the corresponding extremum of the price
|
||||
inp_map=(map>>j)&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map<2)
|
||||
{
|
||||
//--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>i)&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- "take" two bits - pattern of the corresponding oscillator extremum
|
||||
inp_map=(map>>(j+2))&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map>=2)
|
||||
continue;
|
||||
//--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>(i+2))&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalTriX::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- check direction of the oscillator
|
||||
if(DiffTriX(idx)>0.0)
|
||||
{
|
||||
//--- the oscillator is directed upwards confirming the possibility of price growth
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, search for a reverse of the oscillator
|
||||
if(IS_PATTERN_USAGE(1) && DiffTriX(idx)>0.0 && DiffTriX(idx+1)<0.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 is used, search for an intersection of the oscillator line and the zero level
|
||||
if(IS_PATTERN_USAGE(2) && TriX(idx)>0.0 && TriX(idx+1)<0.0)
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- if the model 3 is used, and the oscillator turned up below the zero level, search for the divergence
|
||||
if(IS_PATTERN_USAGE(3) && TriX(idx)<0.0)
|
||||
{
|
||||
//--- perform the extended analysis of the oscillator state
|
||||
ExtState(idx);
|
||||
//--- search for the "divergence" signal
|
||||
if(CompareMaps(1,1)) // 0000 0001b
|
||||
{
|
||||
if(m_extr_osc[0]<0.0 && m_extr_osc[1]<0.0 && m_extr_osc[2]<0.0)
|
||||
{
|
||||
//--- both valleys of the oscillator are below zero and the peak between them hasn't raised above zero
|
||||
result=m_pattern_3; // signal number 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalTriX::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//--- check direction of the main line
|
||||
if(DiffTriX(idx)<0.0)
|
||||
{
|
||||
//--- main line is directed downwards, confirming a possibility of falling of price
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, search for a reverse of the main line
|
||||
if(IS_PATTERN_USAGE(1) && DiffTriX(idx)<0.0 && DiffTriX(idx+1)>0.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 is used, search for an intersection of the main line and the zero level
|
||||
if(IS_PATTERN_USAGE(2) && TriX(idx)<0.0 && TriX(idx+1)>0.0)
|
||||
result=m_pattern_2; // signal number 2
|
||||
//--- if the model 3 is used and the main line turned down above the zero level, search for the divergence
|
||||
if(IS_PATTERN_USAGE(3) && TriX(idx)>0.0)
|
||||
{
|
||||
//--- perform the extended analysis of the oscillator state
|
||||
ExtState(idx);
|
||||
//--- search for the "divergence" signal
|
||||
if(CompareMaps(1,1)) // 0000 0001b
|
||||
{
|
||||
if(m_extr_osc[0]>0.0 && m_extr_osc[1]>0.0 && m_extr_osc[2]>0.0)
|
||||
{
|
||||
//--- both peaks of the oscillator are above zero and the valley between them hasn't fallen below zero
|
||||
result=m_pattern_3; // signal number 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,371 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalWPR.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals of oscillator 'Williams Percent Range' |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=Williams Percent Range |
|
||||
//| ShortName=WPR |
|
||||
//| Class=CSignalWPR |
|
||||
//| Page=signal_wpr |
|
||||
//| Parameter=PeriodWPR,int,8,Period of calculation |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalWPR. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| the 'Williams Percent Range' oscillator. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalWPR : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiWPR m_wpr; // object-oscillator
|
||||
//--- adjusted parameters
|
||||
int m_period_wpr; // the "period of calculation" parameter of the oscillator
|
||||
//--- "weights" of market models (0-100)
|
||||
int m_pattern_0; // model 0 "the oscillator has required direction"
|
||||
int m_pattern_1; // model 1 "reverse behind the level of overbuying/overselling"
|
||||
int m_pattern_2; // model 2 "divergence of the oscillator and price"
|
||||
//--- variables
|
||||
double m_extr_osc[10]; // array of values of extremums of the oscillator
|
||||
double m_extr_pr[10]; // array of values of the corresponding extremums of price
|
||||
int m_extr_pos[10]; // array of shifts of extremums (in bars)
|
||||
uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price
|
||||
|
||||
public:
|
||||
CSignalWPR(void);
|
||||
~CSignalWPR(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void PeriodWPR(int value) { m_period_wpr=value; }
|
||||
//--- methods of adjusting "weights" of market models
|
||||
void Pattern_0(int value) { m_pattern_0=value; }
|
||||
void Pattern_1(int value) { m_pattern_1=value; }
|
||||
void Pattern_2(int value) { m_pattern_2=value; }
|
||||
//--- method of verification of settings
|
||||
virtual bool ValidationSettings(void);
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//--- methods of checking if the market models are formed
|
||||
virtual int LongCondition(void);
|
||||
virtual int ShortCondition(void);
|
||||
|
||||
protected:
|
||||
//--- method of initialization of the oscillator
|
||||
bool InitWPR(CIndicators *indicators);
|
||||
//--- methods of getting data
|
||||
// double WPR(int ind);
|
||||
double WPR(int ind) { return(m_wpr.Main(ind)); }
|
||||
double Diff(int ind) { return(WPR(ind)-WPR(ind+1)); }
|
||||
int State(int ind);
|
||||
bool ExtState(int ind);
|
||||
bool CompareMaps(int map,int count,bool minimax=false,int start=0);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalWPR::CSignalWPR(void) : m_period_wpr(14),
|
||||
m_pattern_0(80),
|
||||
m_pattern_1(70),
|
||||
m_pattern_2(90)
|
||||
{
|
||||
//--- initialization of protected data
|
||||
m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSignalWPR::~CSignalWPR(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalWPR::ValidationSettings(void)
|
||||
{
|
||||
//--- validation settings of additional filters
|
||||
if(!CExpertSignal::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_period_wpr<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period of the WPR oscillator must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalWPR::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- initialization of indicators and timeseries of additional filters
|
||||
if(!CExpertSignal::InitIndicators(indicators))
|
||||
return(false);
|
||||
//--- create and initialize WPR oscillator
|
||||
if(!InitWPR(indicators))
|
||||
return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize WPR oscillators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalWPR::InitWPR(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL) return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_wpr)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_wpr.Create(m_symbol.Name(),m_period,m_period_wpr))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check of the oscillator state. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalWPR::State(int ind)
|
||||
{
|
||||
int res=0;
|
||||
double var;
|
||||
//---
|
||||
for(int i=ind;;i++)
|
||||
{
|
||||
if(WPR(i+1)==EMPTY_VALUE)
|
||||
break;
|
||||
var=Diff(i);
|
||||
if(res>0)
|
||||
{
|
||||
if(var<0)
|
||||
break;
|
||||
res++;
|
||||
continue;
|
||||
}
|
||||
if(res<0)
|
||||
{
|
||||
if(var>0)
|
||||
break;
|
||||
res--;
|
||||
continue;
|
||||
}
|
||||
if(var>0)
|
||||
res++;
|
||||
if(var<0)
|
||||
res--;
|
||||
}
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Extended check of the oscillator state consists |
|
||||
//| in forming a bit-map according to certain rules, |
|
||||
//| which shows ratios of extremums of the oscillator and price. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalWPR::ExtState(int ind)
|
||||
{
|
||||
//--- operation of this method results in a bit-map of extremums
|
||||
//--- practically, the bit-map of extremums is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an element of the analyzed bit-map
|
||||
//--- bit 3 - not used (always 0)
|
||||
//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- bit 1 - not used (always 0)
|
||||
//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one
|
||||
//--- (a higher peak or a deeper valley), otherwise - 0
|
||||
//--- in addition to them, the following is formed:
|
||||
//--- array of values of extremums of the oscillator,
|
||||
//--- array of values of price extremums and
|
||||
//--- array of "distances" between extremums of the oscillator (in bars)
|
||||
//--- it should be noted that when using the results of the extended check of state,
|
||||
//--- you should consider, which extremum of the oscillator (peak or valley)
|
||||
//--- is the "reference point" (i.e. was detected first during the analysis)
|
||||
//--- if a peak is detected first then even elements of all arrays
|
||||
//--- will contain information about peaks, and odd elements will contain information about valleys
|
||||
//--- if a valley is detected first, then respectively in reverse
|
||||
int pos=ind,off,index;
|
||||
uint map; // intermediate bit-map for one extremum
|
||||
//---
|
||||
m_extr_map=0;
|
||||
for(int i=0;i<10;i++)
|
||||
{
|
||||
off=State(pos);
|
||||
if(off>0)
|
||||
{
|
||||
//--- minimum of the oscillator is detected
|
||||
pos+=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=WPR(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_low.MinValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]<m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]<m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_low.MinValue(pos-1,4,index);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- maximum of the oscillator is detected
|
||||
pos-=off;
|
||||
m_extr_pos[i]=pos;
|
||||
m_extr_osc[i]=WPR(pos);
|
||||
if(i>1)
|
||||
{
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-2,5,index);
|
||||
//--- form the intermediate bit-map
|
||||
map=0;
|
||||
if(m_extr_pr[i-2]>m_extr_pr[i])
|
||||
map+=1; // set bit 0
|
||||
if(m_extr_osc[i-2]>m_extr_osc[i])
|
||||
map+=4; // set bit 2
|
||||
//--- add the result
|
||||
m_extr_map+=map<<(4*(i-2));
|
||||
}
|
||||
else
|
||||
m_extr_pr[i]=m_high.MaxValue(pos-1,4,index);
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparing the bit-map of extremums with pattern. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalWPR::CompareMaps(int map,int count,bool minimax,int start)
|
||||
{
|
||||
int step =(minimax)?4:8;
|
||||
int total=step*(start+count);
|
||||
//--- check input parameters for a possible going out of range of the bit-map
|
||||
if(total>32)
|
||||
return(false);
|
||||
//--- bit-map of the patter is an "array" of 4-bit fields
|
||||
//--- each "element of the array" definitely describes the desired ratio
|
||||
//--- of current extremums of the oscillator and the price with previous ones
|
||||
//--- purpose of bits of an elements of the pattern of the bit-map pattern
|
||||
//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us
|
||||
//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2
|
||||
//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us
|
||||
//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0
|
||||
//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one
|
||||
//--- (current peak is higher or current valley is deeper)
|
||||
//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one
|
||||
//--- (current peak is lower or current valley is less deep)
|
||||
uint inp_map,check_map;
|
||||
int i,j;
|
||||
//--- loop by extremums (4 minimums and 4 maximums)
|
||||
//--- price and the oscillator are checked separately (thus, there are 16 checks)
|
||||
for(i=step*start,j=0;i<total;i+=step,j+=4)
|
||||
{
|
||||
//--- "take" two bits - patter of the corresponding extremum of the oscillator
|
||||
inp_map=(map>>i)&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map<2)
|
||||
{
|
||||
//--- "take" two bits of the corresponding extremum of the oscillator (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>j)&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- "take" two bits - pattern of the corresponding price extremum
|
||||
inp_map=(map>>(i+2))&3;
|
||||
//--- if the higher-order bit=1, then any ratio is suitable for us
|
||||
if(inp_map>=2)
|
||||
continue;
|
||||
//--- "take" two bits of the corresponding price extremum (higher-order bit is always 0)
|
||||
check_map=(m_extr_map>>(j+2))&3;
|
||||
if(inp_map!=check_map)
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will grow. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalWPR::LongCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//---
|
||||
if(Diff(idx)>0.0)
|
||||
{
|
||||
//--- the oscillator is directed upwards confirming the possibility of price growth
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, search for a reverse of the oscillator upwards behind the level of overselling
|
||||
if(IS_PATTERN_USAGE(1) && Diff(idx+1)<0.0 && WPR(idx+1)>-80.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 or 3 is used, search for the divergences
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- perform the extended analysis of the oscillator state
|
||||
ExtState(idx);
|
||||
//--- if the model 2 is used, search for the "divergence" signal
|
||||
if(CompareMaps(1,1)) // 00000001b
|
||||
result=m_pattern_2; // signal number 2
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| "Voting" that price will fall. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSignalWPR::ShortCondition(void)
|
||||
{
|
||||
int result=0;
|
||||
int idx =StartIndex();
|
||||
//---
|
||||
if(Diff(idx)<0.0)
|
||||
{
|
||||
//--- the oscillator is directed downwards confirming the possibility of falling of price
|
||||
if(IS_PATTERN_USAGE(0))
|
||||
result=m_pattern_0; // "confirming" signal number 0
|
||||
//--- if the model 1 is used, search for a reverse of the oscillator downwards behind the level of overbuying
|
||||
if(IS_PATTERN_USAGE(1) && Diff(idx+1)>0.0 && WPR(idx+1)<-20.0)
|
||||
result=m_pattern_1; // signal number 1
|
||||
//--- if the model 2 or 3 is used, search for the divergences
|
||||
if(IS_PATTERN_USAGE(2))
|
||||
{
|
||||
//--- perform the extended analysis of the oscillator state
|
||||
ExtState(idx);
|
||||
//--- if the model 2 is used, search for the "divergence" signal
|
||||
if(CompareMaps(1,1)) // 00000001b
|
||||
result=m_pattern_2; // signal number 2
|
||||
}
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,278 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SuperTrendSignal.mqh |
|
||||
//| Copyright © 2011, Nikolay Kositsin |
|
||||
//| Khabarovsk, farria@mail.redcom.ru |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright © 2011, Nikolay Kositsin"
|
||||
#property link "farria@mail.redcom.ru"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Included files |
|
||||
//+------------------------------------------------------------------+
|
||||
#property tester_indicator "SuperTrend.ex5"
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
//--- wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Declaration of constants |
|
||||
//+------------------------------------------------------------------+
|
||||
#define OPEN_LONG 80 // The constant for returning the buy command to the Expert Advisor
|
||||
#define OPEN_SHORT 80 // The constant for returning the sell command to the Expert Advisor
|
||||
#define CLOSE_LONG 40 // The constant for returning the command to close a long position to the Expert Advisor
|
||||
#define CLOSE_SHORT 40 // The constant for returning the command to close a short position to the Expert Advisor
|
||||
#define REVERSE_LONG 100 // The constant for returning the command to reverse a long position to the Expert Advisor
|
||||
#define REVERSE_SHORT 100 // The constant for returning the command to reverse a short position to the Expert Advisor
|
||||
#define NO_SIGNAL 0 // The constant for returning the absence of a signal to the Expert Advisor
|
||||
//+---------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=The signals based on SuperTrend indicator |
|
||||
//| Type=SignalAdvanced |
|
||||
//| Name=SuperTrend |
|
||||
//| Class=CSuperTrendSignal |
|
||||
//| Page= |
|
||||
//| Parameter=BuyPosOpen,bool,true,Permission to buy |
|
||||
//| Parameter=SellPosOpen,bool,true,Permission to sell |
|
||||
//| Parameter=BuyPosClose,bool,true,Permission to exit a long position |
|
||||
//| Parameter=SellPosClose,bool,true,Permission to exit a short position|
|
||||
//| Parameter=Ind_Timeframe,ENUM_TIMEFRAMES,PERIOD_H4,Timeframe |
|
||||
//| Parameter=CCIPeriod,uint,50, CCI indicator period |
|
||||
//| Parameter=ATRPeriod,uint,5,ATR indicator period |
|
||||
//| Parameter=Level,uint,0,CCI activation level |
|
||||
//| Parameter=SignalBar,uint,1,Bar index for entry signal |
|
||||
//+---------------------------------------------------------------------+
|
||||
//--- wizard description end
|
||||
//+---------------------------------------------------------------------+
|
||||
//| CSuperTrendSignal class. |
|
||||
//| Purpose: Class of generator of trade signals based on |
|
||||
//| SuperTrend indicator values http://www.mql5.com/ru/code/527/. |
|
||||
//| Is derived from the CExpertSignal class. |
|
||||
//+---------------------------------------------------------------------+
|
||||
class CSuperTrendSignal : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiCustom m_indicator; // the object for access to SuperTrend values
|
||||
|
||||
//--- adjusted parameters
|
||||
bool m_BuyPosOpen; // permission to buy
|
||||
bool m_SellPosOpen; // permission to sell
|
||||
bool m_BuyPosClose; // permission to exit a long position
|
||||
bool m_SellPosClose; // permission to exit a short position
|
||||
ENUM_TIMEFRAMES m_Ind_Timeframe; // indicator chart timeframe
|
||||
uint m_CCIPeriod; // CCI indicator period
|
||||
uint m_ATRPeriod; // ATR indicator period
|
||||
uint m_Level; // CCI activation level
|
||||
uint m_SignalBar; // bar index for getting entry signal
|
||||
|
||||
public:
|
||||
CSuperTrendSignal();
|
||||
|
||||
//--- methods of setting adjustable parameters
|
||||
void BuyPosOpen(bool value) { m_BuyPosOpen=value; }
|
||||
void SellPosOpen(bool value) { m_SellPosOpen=value; }
|
||||
void BuyPosClose(bool value) { m_BuyPosClose=value; }
|
||||
void SellPosClose(bool value) { m_SellPosClose=value; }
|
||||
//--- indicator input parameters
|
||||
void Ind_Timeframe(ENUM_TIMEFRAMES value) { m_Ind_Timeframe=value; }
|
||||
void CCIPeriod(uint value) { m_CCIPeriod=value; }
|
||||
void ATRPeriod(uint value) { m_ATRPeriod=value; }
|
||||
void Level(uint value) { m_Level=value; }
|
||||
//---
|
||||
void SignalBar(uint value) { m_SignalBar=value; }
|
||||
|
||||
//--- adjustable parameters validation method
|
||||
virtual bool ValidationSettings();
|
||||
//--- adjustable parameters validation method
|
||||
virtual bool InitIndicators(CIndicators *indicators); // indicators initialization
|
||||
//--- market entry signals generation method
|
||||
virtual int LongCondition();
|
||||
virtual int ShortCondition();
|
||||
|
||||
bool InitSuperTrend(CIndicators *indicators); // SuperTrend indicator initializing method
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| CSuperTrendSignal constructor. |
|
||||
//| INPUT: no. |
|
||||
//| OUTPUT: no. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
void CSuperTrendSignal::CSuperTrendSignal()
|
||||
{
|
||||
//--- setting default parameters
|
||||
m_BuyPosOpen=true;
|
||||
m_SellPosOpen=true;
|
||||
m_BuyPosClose=true;
|
||||
m_SellPosClose=true;
|
||||
|
||||
//--- indicator input parameters
|
||||
m_Ind_Timeframe=PERIOD_H4;
|
||||
m_CCIPeriod=50;
|
||||
m_ATRPeriod=5;
|
||||
m_Level=0;
|
||||
//---
|
||||
m_SignalBar=1;
|
||||
m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking adjustable parameters. |
|
||||
//| INPUT: no. |
|
||||
//| OUTPUT: true if the settings are valid, false - if not. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSuperTrendSignal::ValidationSettings()
|
||||
{
|
||||
//--- checking parameters
|
||||
if(m_CCIPeriod<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": CCI indicator period must be greater than zero");
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(m_ATRPeriod<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": ATR indicator period must be greater than zero");
|
||||
return(false);
|
||||
}
|
||||
//--- successful completion
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialization of indicators and time series. |
|
||||
//| INPUT: indicators - pointer to an object-collection |
|
||||
//| of indicators and time series. |
|
||||
//| OUTPUT: true - in case of successful, otherwise - false. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSuperTrendSignal::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check of pointer
|
||||
if(indicators==NULL) return(false);
|
||||
|
||||
//--- indicator initialization
|
||||
if(!InitSuperTrend(indicators)) return(false);
|
||||
|
||||
//--- successful completion
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| SuperTrend indicator initialization. |
|
||||
//| INPUT: indicators - pointer to an object-collection |
|
||||
//| of indicators and time series. |
|
||||
//| OUTPUT: true - in case of successful, otherwise - false. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSuperTrendSignal::InitSuperTrend(CIndicators *indicators)
|
||||
{
|
||||
//--- check of pointer
|
||||
if(indicators==NULL) return(false);
|
||||
|
||||
//--- adding an object to the collection
|
||||
if(!indicators.Add(GetPointer(m_indicator)))
|
||||
{
|
||||
printf(__FUNCTION__+": error of adding the object");
|
||||
return(false);
|
||||
}
|
||||
|
||||
//--- setting the indicator parameters
|
||||
MqlParam parameters[5];
|
||||
|
||||
parameters[0].type=TYPE_STRING;
|
||||
parameters[0].string_value="SuperTrend.ex5";
|
||||
|
||||
parameters[1].type=TYPE_UINT;
|
||||
parameters[1].integer_value=m_CCIPeriod;
|
||||
|
||||
parameters[2].type=TYPE_UINT;
|
||||
parameters[2].integer_value=m_ATRPeriod;
|
||||
|
||||
parameters[3].type=TYPE_UINT;
|
||||
parameters[3].integer_value=m_Level;
|
||||
|
||||
parameters[4].type=TYPE_UINT;
|
||||
parameters[4].integer_value=m_Level;
|
||||
//---
|
||||
if(!m_indicator.Create(m_symbol.Name(),m_Ind_Timeframe,IND_CUSTOM,5,parameters))
|
||||
{
|
||||
printf(__FUNCTION__+": object initialization error");
|
||||
return(false);
|
||||
}
|
||||
|
||||
//--- number of buffers
|
||||
if(!m_indicator.NumBuffers(4)) return(false);
|
||||
|
||||
//--- SuperTrend indicator initialized successfully
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking conditions for opening a long position and |
|
||||
//| closing a short one |
|
||||
//| INPUT: no |
|
||||
//| OUTPUT: Vote weight from 0 to 100 |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSuperTrendSignal::LongCondition()
|
||||
{
|
||||
//--- buy signal is determined by buffer 2 of the SuperTrend indicator
|
||||
double Signal=m_indicator.GetData(2,m_SignalBar);
|
||||
|
||||
//--- getting a trading signal
|
||||
if(Signal && Signal!=EMPTY_VALUE)
|
||||
{
|
||||
if(m_BuyPosOpen)
|
||||
{
|
||||
if(m_SellPosClose) return(REVERSE_SHORT);
|
||||
else return(OPEN_LONG);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_SellPosClose) return(CLOSE_SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
//--- searching for signals for closing a short position
|
||||
if(!m_SellPosClose) return(NO_SIGNAL);
|
||||
|
||||
//--- trend signal is determined by buffer 0 of the SuperTrend indicator
|
||||
Signal=m_indicator.GetData(0,m_SignalBar);
|
||||
if(Signal && Signal!=EMPTY_VALUE) return(CLOSE_SHORT);
|
||||
|
||||
//--- no trading signal
|
||||
return(NO_SIGNAL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking conditions for opening a short position and |
|
||||
//| closing a long one |
|
||||
//| INPUT: no |
|
||||
//| OUTPUT: Vote weight from 0 to 100 |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSuperTrendSignal::ShortCondition()
|
||||
{
|
||||
//--- sell signal is determined by buffer 3 of the SuperTrend indicator
|
||||
double Signal=m_indicator.GetData(3,m_SignalBar);
|
||||
|
||||
//--- getting a trading signal
|
||||
if(Signal && Signal!=EMPTY_VALUE)
|
||||
{
|
||||
if(m_SellPosOpen)
|
||||
{
|
||||
if(m_BuyPosClose) return(REVERSE_LONG);
|
||||
else return(OPEN_SHORT);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_BuyPosClose) return(CLOSE_LONG);
|
||||
}
|
||||
}
|
||||
|
||||
//--- searching for signals for closing a short position
|
||||
if(!m_BuyPosClose) return(NO_SIGNAL);
|
||||
|
||||
//--- trend signal is determined by buffer 1 of the SuperTrend indicator
|
||||
Signal=m_indicator.GetData(1,m_SignalBar);
|
||||
if(Signal && Signal!=EMPTY_VALUE) return(CLOSE_LONG);
|
||||
|
||||
//--- no trading signal
|
||||
return(NO_SIGNAL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,246 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SignalCrossEMA.mqh |
|
||||
//| Copyright © 2010, MetaQuotes Software Corp. |
|
||||
//| http://www.metaquotes.net |
|
||||
//| Revision 2010.10.12 |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertSignal.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Signals based on crossover of two EMA |
|
||||
//| Type=Signal |
|
||||
//| Name=CrossEMA |
|
||||
//| Class=CSignalCrossEMA |
|
||||
//| Page= |
|
||||
//| Parameter=FastPeriod,int,12 |
|
||||
//| Parameter=SlowPeriod,int,24 |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSignalCrossEMA. |
|
||||
//| Appointment: Class trading signals cross two EMA. |
|
||||
//| Derives from class CExpertSignal. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSignalCrossEMA : public CExpertSignal
|
||||
{
|
||||
protected:
|
||||
CiMA *m_FastEMA;
|
||||
CiMA *m_SlowEMA;
|
||||
//--- input parameters
|
||||
int m_fast_period;
|
||||
int m_slow_period;
|
||||
|
||||
public:
|
||||
CSignalCrossEMA();
|
||||
~CSignalCrossEMA();
|
||||
//--- methods initialize protected data
|
||||
void FastPeriod(int period) { m_fast_period=period; }
|
||||
void SlowPeriod(int period) { m_slow_period=period; }
|
||||
virtual bool InitIndicators(CIndicators* indicators);
|
||||
virtual bool ValidationSettings();
|
||||
//---
|
||||
virtual bool CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
|
||||
virtual bool CheckCloseLong(double& price);
|
||||
virtual bool CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
|
||||
virtual bool CheckCloseShort(double& price);
|
||||
|
||||
protected:
|
||||
bool InitFastEMA(CIndicators* indicators);
|
||||
bool InitSlowEMA(CIndicators* indicators);
|
||||
//---
|
||||
double FastEMA(int ind) { return(m_FastEMA.Main(ind)); }
|
||||
double SlowEMA(int ind) { return(m_SlowEMA.Main(ind)); }
|
||||
double StateFastEMA(int ind) { return(FastEMA(ind)-FastEMA(ind+1)); }
|
||||
double StateSlowEMA(int ind) { return(SlowEMA(ind)-SlowEMA(ind+1)); }
|
||||
double StateEMA(int ind) { return(FastEMA(ind)-SlowEMA(ind)); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor CSignalCrossEMA. |
|
||||
//| INPUT: no. |
|
||||
//| OUTPUT: no. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
void CSignalCrossEMA::CSignalCrossEMA()
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_FastEMA =NULL;
|
||||
m_SlowEMA =NULL;
|
||||
//--- set default inputs
|
||||
m_fast_period =12;
|
||||
m_slow_period =24;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor CSignalCrossEMA. |
|
||||
//| INPUT: no. |
|
||||
//| OUTPUT: no. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
void CSignalCrossEMA::~CSignalCrossEMA()
|
||||
{
|
||||
//---
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//| INPUT: no. |
|
||||
//| OUTPUT: true-if settings are correct, false otherwise. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCrossEMA::ValidationSettings()
|
||||
{
|
||||
if(m_fast_period>=m_slow_period)
|
||||
{
|
||||
printf(__FUNCTION__+": period of slow EMA must be greater than period of fast EMA");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//| INPUT: indicators -pointer of indicator collection. |
|
||||
//| OUTPUT: true-if successful, false otherwise. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCrossEMA::InitIndicators(CIndicators* indicators)
|
||||
{
|
||||
//--- check
|
||||
if(indicators==NULL) return(false);
|
||||
//--- create and initialize fast EMA indicator
|
||||
if(!InitFastEMA(indicators)) return(false);
|
||||
//--- create and initialize slow EMA indicator
|
||||
if(!InitSlowEMA(indicators)) return(false);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create fast EMA indicators. |
|
||||
//| INPUT: indicators -pointer of indicator collection. |
|
||||
//| OUTPUT: true-if successful, false otherwise. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCrossEMA::InitFastEMA(CIndicators* indicators)
|
||||
{
|
||||
//--- create fast EMA indicator
|
||||
if(m_FastEMA==NULL)
|
||||
if((m_FastEMA=new CiMA)==NULL)
|
||||
{
|
||||
printf(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add fast EMA indicator to collection
|
||||
if(!indicators.Add(m_FastEMA))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
delete m_FastEMA;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize fast EMA indicator
|
||||
if(!m_FastEMA.Create(m_symbol.Name(),m_period,m_fast_period,0,MODE_EMA,PRICE_CLOSE))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
m_FastEMA.BufferResize(1000);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create slow EMA indicators. |
|
||||
//| INPUT: indicators -pointer of indicator collection. |
|
||||
//| OUTPUT: true-if successful, false otherwise. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCrossEMA::InitSlowEMA(CIndicators* indicators)
|
||||
{
|
||||
//--- create slow EMA indicator
|
||||
if(m_SlowEMA==NULL)
|
||||
if((m_SlowEMA=new CiMA)==NULL)
|
||||
{
|
||||
printf(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add slow EMA indicator to collection
|
||||
if(!indicators.Add(m_SlowEMA))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
delete m_SlowEMA;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize slow EMA indicator
|
||||
if(!m_SlowEMA.Create(m_symbol.Name(),m_period,m_slow_period,0,MODE_EMA,PRICE_CLOSE))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
m_SlowEMA.BufferResize(1000);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check conditions for long position open. |
|
||||
//| INPUT: price - refernce for price, |
|
||||
//| sl - refernce for stop loss, |
|
||||
//| tp - refernce for take profit, |
|
||||
//| expiration - refernce for expiration. |
|
||||
//| OUTPUT: true-if condition performed, false otherwise. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCrossEMA::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
|
||||
{
|
||||
if(!(StateEMA(2)<0 && StateEMA(1)>0)) return(false);
|
||||
//---
|
||||
price=0.0;
|
||||
sl =0.0;
|
||||
tp =0.0;
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check conditions for long position close. |
|
||||
//| INPUT: price - refernce for price. |
|
||||
//| OUTPUT: true-if condition performed, false otherwise. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCrossEMA::CheckCloseLong(double& price)
|
||||
{
|
||||
if(!(StateEMA(2)>0 && StateEMA(1)<0)) return(false);
|
||||
//---
|
||||
price=0.0;
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check conditions for short position open. |
|
||||
//| INPUT: price - refernce for price, |
|
||||
//| sl - refernce for stop loss, |
|
||||
//| tp - refernce for take profit, |
|
||||
//| expiration - refernce for expiration. |
|
||||
//| OUTPUT: true-if condition performed, false otherwise. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCrossEMA::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
|
||||
{
|
||||
if(!(StateEMA(2)>0 && StateEMA(1)<0)) return(false);
|
||||
//---
|
||||
price=0.0;
|
||||
sl =0.0;
|
||||
tp =0.0;
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check conditions for short position close. |
|
||||
//| INPUT: price - refernce for price. |
|
||||
//| OUTPUT: true-if condition performed, false otherwise. |
|
||||
//| REMARK: no. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSignalCrossEMA::CheckCloseShort(double& price)
|
||||
{
|
||||
if(!(StateEMA(2)<0 && StateEMA(1)>0)) return(false);
|
||||
//---
|
||||
price=0.0;
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,132 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| TrailingFixedPips.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertTrailing.mqh>
|
||||
// wizard description start
|
||||
//+----------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Trailing Stop based on fixed Stop Level |
|
||||
//| Type=Trailing |
|
||||
//| Name=FixedPips |
|
||||
//| Class=CTrailingFixedPips |
|
||||
//| Page= |
|
||||
//| Parameter=StopLevel,int,30,Stop Loss trailing level (in points) |
|
||||
//| Parameter=ProfitLevel,int,50,Take Profit trailing level (in points) |
|
||||
//+----------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CTrailingFixedPips. |
|
||||
//| Purpose: Class of trailing stops with fixed stop level in pips. |
|
||||
//| Derives from class CExpertTrailing. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CTrailingFixedPips : public CExpertTrailing
|
||||
{
|
||||
protected:
|
||||
//--- input parameters
|
||||
int m_stop_level;
|
||||
int m_profit_level;
|
||||
|
||||
public:
|
||||
CTrailingFixedPips(void);
|
||||
~CTrailingFixedPips(void);
|
||||
//--- methods of initialization of protected data
|
||||
void StopLevel(int stop_level) { m_stop_level=stop_level; }
|
||||
void ProfitLevel(int profit_level) { m_profit_level=profit_level; }
|
||||
virtual bool ValidationSettings(void);
|
||||
//---
|
||||
virtual bool CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
|
||||
virtual bool CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CTrailingFixedPips::CTrailingFixedPips(void) : m_stop_level(30),
|
||||
m_profit_level(50)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CTrailingFixedPips::~CTrailingFixedPips(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTrailingFixedPips::ValidationSettings(void)
|
||||
{
|
||||
if(!CExpertTrailing::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_profit_level!=0 && m_profit_level*(m_adjusted_point/m_symbol.Point())<m_symbol.StopsLevel())
|
||||
{
|
||||
printf(__FUNCTION__+": trailing Profit Level must be 0 or greater than %d",m_symbol.StopsLevel());
|
||||
return(false);
|
||||
}
|
||||
if(m_stop_level!=0 && m_stop_level*(m_adjusted_point/m_symbol.Point())<m_symbol.StopsLevel())
|
||||
{
|
||||
printf(__FUNCTION__+": trailing Stop Level must be 0 or greater than %d",m_symbol.StopsLevel());
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking trailing stop and/or profit for long position. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTrailingFixedPips::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
|
||||
{
|
||||
//--- check
|
||||
if(position==NULL)
|
||||
return(false);
|
||||
if(m_stop_level==0)
|
||||
return(false);
|
||||
//---
|
||||
double delta;
|
||||
double pos_sl=position.StopLoss();
|
||||
double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
|
||||
double price =m_symbol.Bid();
|
||||
//---
|
||||
sl=EMPTY_VALUE;
|
||||
tp=EMPTY_VALUE;
|
||||
delta=m_stop_level*m_adjusted_point;
|
||||
if(price-base>delta)
|
||||
{
|
||||
sl=price-delta;
|
||||
if(m_profit_level!=0)
|
||||
tp=price+m_profit_level*m_adjusted_point;
|
||||
}
|
||||
//---
|
||||
return(sl!=EMPTY_VALUE);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking trailing stop and/or profit for short position. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTrailingFixedPips::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
|
||||
{
|
||||
//--- check
|
||||
if(position==NULL)
|
||||
return(false);
|
||||
if(m_stop_level==0)
|
||||
return(false);
|
||||
//---
|
||||
double delta;
|
||||
double pos_sl=position.StopLoss();
|
||||
double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
|
||||
double price =m_symbol.Ask();
|
||||
//---
|
||||
sl=EMPTY_VALUE;
|
||||
tp=EMPTY_VALUE;
|
||||
delta=m_stop_level*m_adjusted_point;
|
||||
if(base-price>delta)
|
||||
{
|
||||
sl=price+delta;
|
||||
if(m_profit_level!=0)
|
||||
tp=price-m_profit_level*m_adjusted_point;
|
||||
}
|
||||
//---
|
||||
return(sl!=EMPTY_VALUE);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,157 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| TrailingMA.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertTrailing.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Trailing Stop based on MA |
|
||||
//| Type=Trailing |
|
||||
//| Name=MA |
|
||||
//| Class=CTrailingMA |
|
||||
//| Page= |
|
||||
//| Parameter=Period,int,12,Period of MA |
|
||||
//| Parameter=Shift,int,0,Shift of MA |
|
||||
//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging |
|
||||
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CTrailingMA. |
|
||||
//| Purpose: Class of trailing stops based on MA. |
|
||||
//| Derives from class CExpertTrailing. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CTrailingMA : public CExpertTrailing
|
||||
{
|
||||
protected:
|
||||
CiMA *m_MA;
|
||||
//--- input parameters
|
||||
int m_ma_period;
|
||||
int m_ma_shift;
|
||||
ENUM_MA_METHOD m_ma_method;
|
||||
ENUM_APPLIED_PRICE m_ma_applied;
|
||||
|
||||
public:
|
||||
CTrailingMA(void);
|
||||
~CTrailingMA(void);
|
||||
//--- methods of initialization of protected data
|
||||
void Period(int period) { m_ma_period=period; }
|
||||
void Shift(int shift) { m_ma_shift=shift; }
|
||||
|
||||
void Method(ENUM_MA_METHOD method) { m_ma_method=method; }
|
||||
void Applied(ENUM_APPLIED_PRICE applied) { m_ma_applied=applied; }
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
virtual bool ValidationSettings(void);
|
||||
//---
|
||||
virtual bool CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
|
||||
virtual bool CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CTrailingMA::CTrailingMA(void) : m_MA(NULL),
|
||||
m_ma_period(12),
|
||||
m_ma_shift(0),
|
||||
m_ma_method(MODE_SMA),
|
||||
m_ma_applied(PRICE_CLOSE)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CTrailingMA::~CTrailingMA(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation settings protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTrailingMA::ValidationSettings(void)
|
||||
{
|
||||
if(!CExpertTrailing::ValidationSettings())
|
||||
return(false);
|
||||
//--- initial data checks
|
||||
if(m_ma_period<=0)
|
||||
{
|
||||
printf(__FUNCTION__+": period MA must be greater than 0");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking for input parameters and setting protected data. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTrailingMA::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- create MA indicator
|
||||
if(m_MA==NULL)
|
||||
if((m_MA=new CiMA)==NULL)
|
||||
{
|
||||
printf(__FUNCTION__+": error creating object");
|
||||
return(false);
|
||||
}
|
||||
//--- add MA indicator to collection
|
||||
if(!indicators.Add(m_MA))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
delete m_MA;
|
||||
return(false);
|
||||
}
|
||||
//--- initialize MA indicator
|
||||
if(!m_MA.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
m_MA.BufferResize(3+m_ma_shift);
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking trailing stop and/or profit for long position. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTrailingMA::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
|
||||
{
|
||||
//--- check
|
||||
if(position==NULL)
|
||||
return(false);
|
||||
//---
|
||||
double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
|
||||
double new_sl=NormalizeDouble(m_MA.Main(1),m_symbol.Digits());
|
||||
double pos_sl=position.StopLoss();
|
||||
double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
|
||||
//---
|
||||
sl=EMPTY_VALUE;
|
||||
tp=EMPTY_VALUE;
|
||||
if(new_sl>base && new_sl<level)
|
||||
sl=new_sl;
|
||||
//---
|
||||
return(sl!=EMPTY_VALUE);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking trailing stop and/or profit for short position. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTrailingMA::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
|
||||
{
|
||||
//--- check
|
||||
if(position==NULL)
|
||||
return(false);
|
||||
//---
|
||||
double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
|
||||
double new_sl=NormalizeDouble(m_MA.Main(1)+m_symbol.Spread()*m_symbol.Point(),m_symbol.Digits());
|
||||
double pos_sl=position.StopLoss();
|
||||
double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
|
||||
//---
|
||||
sl=EMPTY_VALUE;
|
||||
tp=EMPTY_VALUE;
|
||||
if(new_sl<base && new_sl>level)
|
||||
sl=new_sl;
|
||||
//---
|
||||
return(sl!=EMPTY_VALUE);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,40 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| TrailingNone.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertTrailing.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Trailing Stop not used |
|
||||
//| Type=Trailing |
|
||||
//| Name=None |
|
||||
//| Class=CTrailingNone |
|
||||
//| Page= |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CTrailingNone. |
|
||||
//| Appointment: Class no traling stops. |
|
||||
//| Derives from class CExpertTrailing. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CTrailingNone : public CExpertTrailing
|
||||
{
|
||||
public:
|
||||
CTrailingNone(void);
|
||||
~CTrailingNone(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CTrailingNone::CTrailingNone(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CTrailingNone::~CTrailingNone(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,123 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| TrailingParabolicSAR.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Expert\ExpertTrailing.mqh>
|
||||
// wizard description start
|
||||
//+------------------------------------------------------------------+
|
||||
//| Description of the class |
|
||||
//| Title=Trailing Stop based on Parabolic SAR |
|
||||
//| Type=Trailing |
|
||||
//| Name=ParabolicSAR |
|
||||
//| Class=CTrailingPSAR |
|
||||
//| Page= |
|
||||
//| Parameter=Step,double,0.02,Speed increment |
|
||||
//| Parameter=Maximum,double,0.2,Maximum rate |
|
||||
//+------------------------------------------------------------------+
|
||||
// wizard description end
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CTrailingPSAR. |
|
||||
//| Appointment: Class traling stops with Parabolic SAR. |
|
||||
//| Derives from class CExpertTrailing. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CTrailingPSAR : public CExpertTrailing
|
||||
{
|
||||
protected:
|
||||
CiSAR m_sar; // object-indicator
|
||||
//--- adjusted parameters
|
||||
double m_step; // the "speed increment" parameter of the indicator
|
||||
double m_maximum; // the "maximum rate" parameter of the indicator
|
||||
|
||||
public:
|
||||
CTrailingPSAR(void);
|
||||
~CTrailingPSAR(void);
|
||||
//--- methods of setting adjustable parameters
|
||||
void Step(double step) { m_step=step; }
|
||||
void Maximum(double maximum) { m_maximum=maximum; }
|
||||
//--- method of creating the indicator and timeseries
|
||||
virtual bool InitIndicators(CIndicators *indicators);
|
||||
//---
|
||||
virtual bool CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
|
||||
virtual bool CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CTrailingPSAR::CTrailingPSAR(void) : m_step(0.02),
|
||||
m_maximum(0.2)
|
||||
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CTrailingPSAR::~CTrailingPSAR(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create indicators. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTrailingPSAR::InitIndicators(CIndicators *indicators)
|
||||
{
|
||||
//--- check pointer
|
||||
if(indicators==NULL)
|
||||
return(false);
|
||||
//--- add object to collection
|
||||
if(!indicators.Add(GetPointer(m_sar)))
|
||||
{
|
||||
printf(__FUNCTION__+": error adding object");
|
||||
return(false);
|
||||
}
|
||||
//--- initialize object
|
||||
if(!m_sar.Create(m_symbol.Name(),m_period,m_step,m_maximum))
|
||||
{
|
||||
printf(__FUNCTION__+": error initializing object");
|
||||
return(false);
|
||||
}
|
||||
//--- ok
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking trailing stop and/or profit for long position. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTrailingPSAR::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
|
||||
{
|
||||
//--- check
|
||||
if(position==NULL)
|
||||
return(false);
|
||||
//---
|
||||
double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
|
||||
double new_sl=NormalizeDouble(m_sar.Main(1),m_symbol.Digits());
|
||||
double pos_sl=position.StopLoss();
|
||||
double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
|
||||
//---
|
||||
sl=EMPTY_VALUE;
|
||||
tp=EMPTY_VALUE;
|
||||
if(new_sl>base && new_sl<level)
|
||||
sl=new_sl;
|
||||
//---
|
||||
return(sl!=EMPTY_VALUE);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checking trailing stop and/or profit for short position. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTrailingPSAR::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
|
||||
{
|
||||
//--- check
|
||||
if(position==NULL)
|
||||
return(false);
|
||||
//---
|
||||
double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
|
||||
double new_sl=NormalizeDouble(m_sar.Main(1)+m_symbol.Spread()*m_symbol.Point(),m_symbol.Digits());
|
||||
double pos_sl=position.StopLoss();
|
||||
double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
|
||||
//---
|
||||
sl=EMPTY_VALUE;
|
||||
tp=EMPTY_VALUE;
|
||||
if(new_sl<base && new_sl>level)
|
||||
sl=new_sl;
|
||||
//---
|
||||
return(sl!=EMPTY_VALUE);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| File.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CFile. |
|
||||
//| Purpose: Base class of file operations. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CFile : public CObject
|
||||
{
|
||||
protected:
|
||||
int m_handle; // handle of file
|
||||
string m_name; // name of opened file
|
||||
int m_flags; // flags of opened file
|
||||
|
||||
public:
|
||||
CFile(void);
|
||||
~CFile(void);
|
||||
//--- methods of access to protected data
|
||||
int Handle(void) const { return(m_handle); };
|
||||
string FileName(void) const { return(m_name); };
|
||||
int Flags(void) const { return(m_flags); };
|
||||
void SetUnicode(const bool unicode);
|
||||
void SetCommon(const bool common);
|
||||
//--- general methods for working with files
|
||||
int Open(const string file_name,int open_flags,const short delimiter='\t');
|
||||
void Close(void);
|
||||
void Delete(void);
|
||||
ulong Size(void);
|
||||
ulong Tell(void);
|
||||
void Seek(const long offset,const ENUM_FILE_POSITION origin);
|
||||
void Flush(void);
|
||||
bool IsEnding(void);
|
||||
bool IsLineEnding(void);
|
||||
//--- general methods for working with files
|
||||
void Delete(const string file_name,const int common_flag=0);
|
||||
bool IsExist(const string file_name,const int common_flag=0);
|
||||
bool Copy(const string src_name,const int common_flag,const string dst_name,const int mode_flags);
|
||||
bool Move(const string src_name,const int common_flag,const string dst_name,const int mode_flags);
|
||||
//--- general methods of working with folders
|
||||
bool FolderCreate(const string folder_name);
|
||||
bool FolderDelete(const string folder_name);
|
||||
bool FolderClean(const string folder_name);
|
||||
//--- general methods of finding files
|
||||
long FileFindFirst(const string file_filter,string &returned_filename);
|
||||
bool FileFindNext(const long search_handle,string &returned_filename);
|
||||
void FileFindClose(const long search_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFile::CFile(void) : m_handle(INVALID_HANDLE),
|
||||
m_name(""),
|
||||
m_flags(FILE_ANSI)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFile::~CFile(void)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
Close();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the FILE_UNICODE flag |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFile::SetUnicode(const bool unicode)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle==INVALID_HANDLE)
|
||||
{
|
||||
if(unicode)
|
||||
m_flags|=FILE_UNICODE;
|
||||
else
|
||||
m_flags&=~FILE_UNICODE;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Common Folder" flag |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFile::SetCommon(const bool common)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle==INVALID_HANDLE)
|
||||
{
|
||||
if(common)
|
||||
m_flags|=FILE_COMMON;
|
||||
else
|
||||
m_flags&=~FILE_COMMON;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open the file |
|
||||
//+------------------------------------------------------------------+
|
||||
int CFile::Open(const string file_name,int open_flags,const short delimiter)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
Close();
|
||||
//--- action
|
||||
if((open_flags &(FILE_BIN|FILE_CSV))==0)
|
||||
open_flags|=FILE_TXT;
|
||||
//--- open
|
||||
m_handle=FileOpen(file_name,open_flags|m_flags,delimiter);
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
//--- store options of the opened file
|
||||
m_flags|=open_flags;
|
||||
m_name=file_name;
|
||||
}
|
||||
//--- result
|
||||
return(m_handle);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Close the file |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFile::Close(void)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
//--- closing the file and resetting all the variables to the initial state
|
||||
FileClose(m_handle);
|
||||
m_handle=INVALID_HANDLE;
|
||||
m_name="";
|
||||
//--- reset all flags except the text
|
||||
m_flags&=FILE_ANSI|FILE_UNICODE;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting an open file |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFile::Delete(void)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
string file_name=m_name;
|
||||
int common_flag=m_flags&FILE_COMMON;
|
||||
//--- close before deleting
|
||||
Close();
|
||||
//--- delete
|
||||
FileDelete(file_name,common_flag);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get size of opened file |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CFile::Size(void)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileSize(m_handle));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get current position of pointer in file |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CFile::Tell(void)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileTell(m_handle));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set position of pointer in file |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFile::Seek(const long offset,const ENUM_FILE_POSITION origin)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
FileSeek(m_handle,offset,origin);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Flush data from the file buffer of input-output to disk |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFile::Flush(void)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
FileFlush(m_handle);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detect the end of file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFile::IsEnding(void)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileIsEnding(m_handle));
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detect the end of string |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFile::IsLineEnding(void)
|
||||
{
|
||||
//--- checking
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
if((m_flags&FILE_BIN)==0)
|
||||
return(FileIsLineEnding(m_handle));
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting a file |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFile::Delete(const string file_name,const int common_flag)
|
||||
{
|
||||
//--- checking
|
||||
if(file_name==m_name)
|
||||
{
|
||||
int flag=m_flags&FILE_COMMON;
|
||||
if(flag==common_flag)
|
||||
Close();
|
||||
}
|
||||
//--- delete
|
||||
FileDelete(file_name,common_flag);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if file exists |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFile::IsExist(const string file_name,const int common_flag)
|
||||
{
|
||||
return(FileIsExist(file_name,common_flag));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copying file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFile::Copy(const string src_name,const int common_flag,const string dst_name,const int mode_flags)
|
||||
{
|
||||
return(FileCopy(src_name,common_flag,dst_name,mode_flags));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Move/rename file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFile::Move(const string src_name,const int common_flag,const string dst_name,const int mode_flags)
|
||||
{
|
||||
return(FileMove(src_name,common_flag,dst_name,mode_flags));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create folder |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFile::FolderCreate(const string folder_name)
|
||||
{
|
||||
return(::FolderCreate(folder_name,m_flags));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete folder |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFile::FolderDelete(const string folder_name)
|
||||
{
|
||||
return(::FolderDelete(folder_name,m_flags));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Clean folder |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFile::FolderClean(const string folder_name)
|
||||
{
|
||||
return(::FolderClean(folder_name,m_flags));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Start search of files |
|
||||
//+------------------------------------------------------------------+
|
||||
long CFile::FileFindFirst(const string file_filter,string &returned_filename)
|
||||
{
|
||||
return(::FileFindFirst(file_filter,returned_filename,m_flags));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Continue search of files |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFile::FileFindNext(const long search_handle,string &returned_filename)
|
||||
{
|
||||
return(::FileFindNext(search_handle,returned_filename));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| End search of files |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFile::FileFindClose(const long search_handle)
|
||||
{
|
||||
::FileFindClose(search_handle);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,183 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| FileBMP.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Bitmap headers |
|
||||
//+------------------------------------------------------------------+
|
||||
struct BITMAPFILEHEADER
|
||||
{
|
||||
ushort bfType;
|
||||
uint bfSize;
|
||||
ushort bfReserved1;
|
||||
ushort bfReserved2;
|
||||
uint bfOffBits;
|
||||
};
|
||||
struct BITMAPINFOHEADER
|
||||
{
|
||||
uint biSize;
|
||||
int biWidth;
|
||||
int biHeight;
|
||||
ushort biPlanes;
|
||||
ushort biBitCount;
|
||||
uint biCompression;
|
||||
uint biSizeImage;
|
||||
int biXPelsPerMeter;
|
||||
int biYPelsPerMeter;
|
||||
uint biClrUsed;
|
||||
uint biClrImportant;
|
||||
};
|
||||
#define BM 0x4D42
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CFileBMP |
|
||||
//| Purpose: Special class to read and write bmp file |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CFileBMP : public CObject
|
||||
{
|
||||
protected:
|
||||
int m_handle;
|
||||
BITMAPFILEHEADER m_file_header;
|
||||
BITMAPINFOHEADER m_info_header;
|
||||
|
||||
public:
|
||||
CFileBMP(void);
|
||||
~CFileBMP(void);
|
||||
int OpenWrite(const string file_name,bool common_flag=false);
|
||||
int OpenRead(const string file_name,bool common_flag=false);
|
||||
int Write32BitsArray(uint& uint_array[],const int width,const int height);
|
||||
int Read32BitsArray(uint& uint_array[],int& width,int& height);
|
||||
void Close(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFileBMP::CFileBMP(void) : m_handle(INVALID_HANDLE)
|
||||
{
|
||||
ZeroMemory(m_file_header);
|
||||
ZeroMemory(m_info_header);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFileBMP::~CFileBMP(void)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open the file |
|
||||
//+------------------------------------------------------------------+
|
||||
int CFileBMP::OpenWrite(const string file_name,bool common_flag)
|
||||
{
|
||||
Close();
|
||||
//--- action
|
||||
int open_flags=FILE_BIN|FILE_WRITE|FILE_SHARE_READ|FILE_SHARE_WRITE;
|
||||
if(common_flag)
|
||||
open_flags|=FILE_COMMON;
|
||||
//--- open
|
||||
m_handle=FileOpen(file_name,open_flags);
|
||||
//--- result
|
||||
return(m_handle);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open the file |
|
||||
//+------------------------------------------------------------------+
|
||||
int CFileBMP::OpenRead(const string file_name,bool common_flag)
|
||||
{
|
||||
Close();
|
||||
//--- action
|
||||
int open_flags=FILE_BIN|FILE_READ|FILE_SHARE_READ|FILE_SHARE_WRITE;
|
||||
if(common_flag)
|
||||
open_flags|=FILE_COMMON;
|
||||
//--- open
|
||||
m_handle=FileOpen(file_name,open_flags);
|
||||
//--- check bmp headers
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
uint fileheader_size=FileReadStruct(m_handle,m_file_header);
|
||||
uint infoheader_size=FileReadStruct(m_handle,m_info_header);
|
||||
//--- it should be a simple 32-bit bmp
|
||||
if(fileheader_size!=sizeof(m_file_header) ||
|
||||
infoheader_size!=sizeof(m_info_header) ||
|
||||
m_file_header.bfType!=BM ||
|
||||
m_file_header.bfOffBits!=sizeof(m_file_header)+sizeof(m_info_header) ||
|
||||
m_info_header.biBitCount!=32 ||
|
||||
m_info_header.biClrUsed!=0)
|
||||
Close();
|
||||
}
|
||||
//--- result
|
||||
return(m_handle);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write the file |
|
||||
//+------------------------------------------------------------------+
|
||||
int CFileBMP::Write32BitsArray(uint& uint_array[],const int width,const int height)
|
||||
{
|
||||
if(m_handle==INVALID_HANDLE)
|
||||
return(-1);
|
||||
//--- check size
|
||||
int size=width*height;
|
||||
if(size==0)
|
||||
return(0);
|
||||
if(size<0)
|
||||
size=-size;
|
||||
if(ArraySize(uint_array)<size)
|
||||
return(-2);
|
||||
//--- prepare headers
|
||||
ZeroMemory(m_file_header);
|
||||
ZeroMemory(m_info_header);
|
||||
m_file_header.bfType=BM;
|
||||
m_file_header.bfSize=sizeof(m_file_header)+sizeof(m_info_header)+size*sizeof(uint);
|
||||
m_file_header.bfOffBits=sizeof(m_file_header)+sizeof(m_info_header);
|
||||
m_info_header.biSize=sizeof(m_info_header);
|
||||
m_info_header.biWidth=width;
|
||||
m_info_header.biHeight=height;
|
||||
m_info_header.biPlanes=1;
|
||||
m_info_header.biBitCount=32;
|
||||
m_info_header.biSizeImage=size*32;
|
||||
//--- write bmp-file
|
||||
FileSeek(m_handle,0,SEEK_SET);
|
||||
FileWriteStruct(m_handle,m_file_header);
|
||||
FileWriteStruct(m_handle,m_info_header);
|
||||
uint written=FileWriteArray(m_handle,uint_array,0,size);
|
||||
//--- bytes written
|
||||
return((int)written*sizeof(uint));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read the file |
|
||||
//+------------------------------------------------------------------+
|
||||
int CFileBMP::Read32BitsArray(uint& uint_array[],int& width,int& height)
|
||||
{
|
||||
if(m_handle==INVALID_HANDLE)
|
||||
return(-1);
|
||||
//--- store dimensions from header
|
||||
width=m_info_header.biWidth;
|
||||
height=m_info_header.biHeight;
|
||||
//--- check size
|
||||
int size=width*height;
|
||||
if(size==0)
|
||||
return(0);
|
||||
if(size<0)
|
||||
size=-size;
|
||||
//--- read bmp-file
|
||||
FileSeek(m_handle,sizeof(m_file_header)+sizeof(m_info_header),SEEK_SET);
|
||||
uint read=FileReadArray(m_handle,uint_array,0,size);
|
||||
//--- bytes read
|
||||
return((int)read*sizeof(uint));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Close the file |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFileBMP::Close(void)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
FileClose(m_handle);
|
||||
m_handle=INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,517 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| FileBin.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "File.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CFileBin |
|
||||
//| Purpose: Class of operations with binary files |
|
||||
//| Derives from class CFile |
|
||||
//+------------------------------------------------------------------+
|
||||
class CFileBin : public CFile
|
||||
{
|
||||
public:
|
||||
CFileBin(void);
|
||||
~CFileBin(void);
|
||||
//--- methods for working with files
|
||||
int Open(const string file_name,const int open_flags);
|
||||
//--- methods for writing data
|
||||
uint WriteChar(const char value);
|
||||
uint WriteShort(const short value);
|
||||
uint WriteInteger(const int value);
|
||||
uint WriteLong(const long value);
|
||||
uint WriteFloat(const float value);
|
||||
uint WriteDouble(const double value);
|
||||
uint WriteString(const string value);
|
||||
uint WriteString(const string value,const int size);
|
||||
uint WriteCharArray(const char &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
uint WriteShortArray(const short& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
uint WriteIntegerArray(const int& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
uint WriteLongArray(const long &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
uint WriteFloatArray(const float &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
uint WriteDoubleArray(const double &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
template<typename T>
|
||||
uint WriteArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
template<typename T>
|
||||
uint WriteStruct(T &data);
|
||||
bool WriteObject(CObject *object);
|
||||
template<typename T>
|
||||
uint WriteEnum(const T value) { return(WriteInteger((int)value)); }
|
||||
//--- methods for reading data
|
||||
bool ReadChar(char &value);
|
||||
bool ReadShort(short &value);
|
||||
bool ReadInteger(int &value);
|
||||
bool ReadLong(long &value);
|
||||
bool ReadFloat(float &value);
|
||||
bool ReadDouble(double &value);
|
||||
bool ReadString(string &value);
|
||||
bool ReadString(string &value,const int size);
|
||||
uint ReadCharArray(char &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
uint ReadShortArray(short& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
uint ReadIntegerArray(int& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
uint ReadLongArray(long &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
uint ReadFloatArray(float &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
uint ReadDoubleArray(double &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
template<typename T>
|
||||
uint ReadArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
template<typename T>
|
||||
uint ReadStruct(T &data);
|
||||
bool ReadObject(CObject *object);
|
||||
template<typename T>
|
||||
bool ReadEnum(T &value);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFileBin::CFileBin(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFileBin::~CFileBin(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Opening a binary file |
|
||||
//+------------------------------------------------------------------+
|
||||
int CFileBin::Open(const string file_name,const int open_flags)
|
||||
{
|
||||
return(CFile::Open(file_name,open_flags|FILE_BIN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of char or uchar type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteChar(const char value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteInteger(m_handle,value,sizeof(char)));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of short or ushort type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteShort(const short value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteInteger(m_handle,value,sizeof(short)));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of int or uint type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteInteger(const int value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteInteger(m_handle,value,sizeof(int)));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of long or ulong type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteLong(const long value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteLong(m_handle,value));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of float type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteFloat(const float value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteFloat(m_handle,value));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of double type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteDouble(const double value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteDouble(m_handle,value));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of string type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteString(const string value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
//--- size of string
|
||||
int size=StringLen(value);
|
||||
//--- write
|
||||
if(FileWriteInteger(m_handle,size)==sizeof(int))
|
||||
return(FileWriteString(m_handle,value,size));
|
||||
}
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a part of string |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteString(const string value,const int size)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteString(m_handle,value,size));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write array variables of type char or uchar |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteCharArray(const char &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write an array of variables of short or ushort type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteShortArray(const short &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write an array of variables of int or uint type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteIntegerArray(const int &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write an array of variables of long or ulong type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteLongArray(const long &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write an array of variables of float type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteFloatArray(const float &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write an array of variables of double type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::WriteDoubleArray(const double &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write an array of variables of any type |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
uint CFileBin::WriteArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write an structure |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
uint CFileBin::WriteStruct(T &data)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteStruct(m_handle,data));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write data of an instance of the CObject class |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFileBin::WriteObject(CObject *object)
|
||||
{
|
||||
//--- check handle & object
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
if(CheckPointer(object))
|
||||
return(object.Save(m_handle));
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of char or uchar type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFileBin::ReadChar(char &value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
ResetLastError();
|
||||
value=(char)FileReadInteger(m_handle,sizeof(char));
|
||||
return(GetLastError()==0);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of short or ushort type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFileBin::ReadShort(short &value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
ResetLastError();
|
||||
value=(short)FileReadInteger(m_handle,sizeof(short));
|
||||
return(GetLastError()==0);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of int or uint type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFileBin::ReadInteger(int &value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
ResetLastError();
|
||||
value=FileReadInteger(m_handle,sizeof(int));
|
||||
return(GetLastError()==0);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of long or ulong type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFileBin::ReadLong(long &value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
ResetLastError();
|
||||
value=FileReadLong(m_handle);
|
||||
return(GetLastError()==0);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of float type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFileBin::ReadFloat(float &value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
ResetLastError();
|
||||
value=FileReadFloat(m_handle);
|
||||
return(GetLastError()==0);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of double type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFileBin::ReadDouble(double &value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
ResetLastError();
|
||||
value=FileReadDouble(m_handle);
|
||||
return(GetLastError()==0);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of string type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFileBin::ReadString(string &value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
ResetLastError();
|
||||
int size=FileReadInteger(m_handle);
|
||||
if(GetLastError()==0)
|
||||
{
|
||||
value=FileReadString(m_handle,size);
|
||||
return(size==StringLen(value));
|
||||
}
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a part of string |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFileBin::ReadString(string &value,const int size)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
value=FileReadString(m_handle,size);
|
||||
return(size==StringLen(value));
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read an array of variables of char or uchar type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::ReadCharArray(char &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileReadArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read an array of variables of short or ushort type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::ReadShortArray(short &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileReadArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read an array of variables of int or uint type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::ReadIntegerArray(int &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileReadArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read an array of variables of long or ulong type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::ReadLongArray(long &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileReadArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read an array of variables of float type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::ReadFloatArray(float &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileReadArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read an array of variables of double type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileBin::ReadDoubleArray(double &array[],const int start_item,const int items_count)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileReadArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read an array of variables of any type |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
uint CFileBin::ReadArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileReadArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read an structure |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
uint CFileBin::ReadStruct(T &data)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileReadStruct(m_handle,data));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read data of an instance of the CObject class |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFileBin::ReadObject(CObject *object)
|
||||
{
|
||||
//--- check handle & object
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
if(CheckPointer(object))
|
||||
return(object.Load(m_handle));
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of an enumeration type |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CFileBin::ReadEnum(T &value)
|
||||
{
|
||||
int val;
|
||||
if(!ReadInteger(val))
|
||||
return(false);
|
||||
//---
|
||||
value=(T)val;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,347 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| FilePipe.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "File.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CFilePipe |
|
||||
//| Purpose: Class of operations with binary files |
|
||||
//| Derives from class CFile |
|
||||
//+------------------------------------------------------------------+
|
||||
class CFilePipe : public CFile
|
||||
{
|
||||
public:
|
||||
CFilePipe(void);
|
||||
~CFilePipe(void);
|
||||
//--- methods for working with files
|
||||
int Open(const string file_name,const int open_flags);
|
||||
//--- wait for incoming data
|
||||
bool WaitForRead(const ulong size);
|
||||
//--- methods for writing data
|
||||
template<typename T>
|
||||
uint WriteInteger(const T value);
|
||||
uint WriteLong(const long value);
|
||||
uint WriteFloat(const float value);
|
||||
uint WriteDouble(const double value);
|
||||
uint WriteString(const string value);
|
||||
uint WriteString(const string value,const int size);
|
||||
template<typename T>
|
||||
uint WriteArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
template<typename T>
|
||||
uint WriteStruct(T &data);
|
||||
bool WriteObject(CObject *object);
|
||||
template<typename T>
|
||||
uint WriteEnum(const T value) { return(WriteInteger((int)value)); }
|
||||
//--- methods for reading data
|
||||
template<typename T>
|
||||
bool ReadInteger(T &value);
|
||||
bool ReadLong(long &value);
|
||||
bool ReadFloat(float &value);
|
||||
bool ReadDouble(double &value);
|
||||
bool ReadString(string &value);
|
||||
bool ReadString(string &value,const int size);
|
||||
template<typename T>
|
||||
uint ReadArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
|
||||
template<typename T>
|
||||
uint ReadStruct(T &data);
|
||||
bool ReadObject(CObject *object);
|
||||
template<typename T>
|
||||
bool ReadEnum(T &value);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFilePipe::CFilePipe(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFilePipe::~CFilePipe(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Opening a binary file |
|
||||
//+------------------------------------------------------------------+
|
||||
int CFilePipe::Open(const string file_name,const int open_flags)
|
||||
{
|
||||
return(CFile::Open(file_name,open_flags|FILE_BIN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Wait for incoming data |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFilePipe::WaitForRead(const ulong size)
|
||||
{
|
||||
//--- check handle and stop flag
|
||||
while(m_handle!=INVALID_HANDLE && !IsStopped())
|
||||
{
|
||||
//--- enought data?
|
||||
if(FileSize(m_handle)>=size)
|
||||
return(true);
|
||||
//--- wait a little
|
||||
Sleep(1);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of integer types |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
uint CFilePipe::WriteInteger(const T value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteInteger(m_handle,value,sizeof(T)));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of long or ulong type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFilePipe::WriteLong(const long value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteLong(m_handle,value));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of float type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFilePipe::WriteFloat(const float value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteFloat(m_handle,value));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of double type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFilePipe::WriteDouble(const double value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteDouble(m_handle,value));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a variable of string type |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFilePipe::WriteString(const string value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
{
|
||||
//--- size of string
|
||||
int size=StringLen(value);
|
||||
//--- write
|
||||
if(FileWriteInteger(m_handle,size)==sizeof(int))
|
||||
return(FileWriteString(m_handle,value,size));
|
||||
}
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write a part of string |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFilePipe::WriteString(const string value,const int size)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteString(m_handle,value,size));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write an array of variables of any type |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
uint CFilePipe::WriteArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write an structure |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
uint CFilePipe::WriteStruct(T &data)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteStruct(m_handle,data));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write data of an instance of the CObject class |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFilePipe::WriteObject(CObject *object)
|
||||
{
|
||||
//--- check handle & object
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
if(CheckPointer(object))
|
||||
return(object.Save(m_handle));
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of integer types |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CFilePipe::ReadInteger(T &value)
|
||||
{
|
||||
//--- check for data
|
||||
if(WaitForRead(sizeof(T)))
|
||||
{
|
||||
ResetLastError();
|
||||
value=FileReadInteger(m_handle,sizeof(T));
|
||||
return(GetLastError()==0);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of long or ulong type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFilePipe::ReadLong(long &value)
|
||||
{
|
||||
//--- check handle
|
||||
if(WaitForRead(sizeof(long)))
|
||||
{
|
||||
ResetLastError();
|
||||
value=FileReadLong(m_handle);
|
||||
return(GetLastError()==0);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of float type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFilePipe::ReadFloat(float &value)
|
||||
{
|
||||
//--- check for data
|
||||
if(WaitForRead(sizeof(float)))
|
||||
{
|
||||
ResetLastError();
|
||||
value=FileReadFloat(m_handle);
|
||||
return(GetLastError()==0);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of double type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFilePipe::ReadDouble(double &value)
|
||||
{
|
||||
//--- check for data
|
||||
if(WaitForRead(sizeof(double)))
|
||||
{
|
||||
ResetLastError();
|
||||
value=FileReadDouble(m_handle);
|
||||
return(GetLastError()==0);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of string type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFilePipe::ReadString(string &value)
|
||||
{
|
||||
//--- check for data
|
||||
if(WaitForRead(sizeof(int)))
|
||||
{
|
||||
ResetLastError();
|
||||
int size=FileReadInteger(m_handle);
|
||||
if(GetLastError()==0)
|
||||
{
|
||||
//--- check for data
|
||||
if(WaitForRead(size))
|
||||
{
|
||||
value=FileReadString(m_handle,size);
|
||||
return(size==StringLen(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a part of string |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFilePipe::ReadString(string &value,const int size)
|
||||
{
|
||||
//--- check for data
|
||||
if(WaitForRead(size))
|
||||
{
|
||||
value=FileReadString(m_handle,size);
|
||||
return(size==StringLen(value));
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read an array of variables of any type |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
uint CFilePipe::ReadArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY)
|
||||
{
|
||||
//--- calculate size
|
||||
uint size=ArraySize(array);
|
||||
if(items_count!=WHOLE_ARRAY) size=items_count;
|
||||
//--- check for data
|
||||
if(WaitForRead(size*sizeof(T)))
|
||||
return(FileReadArray(m_handle,array,start_item,items_count));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read an structure |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
uint CFilePipe::ReadStruct(T &data)
|
||||
{
|
||||
//--- check for data
|
||||
if(WaitForRead(sizeof(T)))
|
||||
return(FileReadStruct(m_handle,data));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read data of an instance of the CObject class |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFilePipe::ReadObject(CObject *object)
|
||||
{
|
||||
//--- check for object & data
|
||||
if(CheckPointer(object))
|
||||
if(WaitForRead(sizeof(int))) // only 4 bytes!
|
||||
return(object.Load(m_handle));
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read a variable of an enumeration type |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CFilePipe::ReadEnum(T &value)
|
||||
{
|
||||
int val;
|
||||
if(!ReadInteger(val))
|
||||
return(false);
|
||||
//---
|
||||
value=(T)val;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,64 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| FileTxt.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "File.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CFileTxt |
|
||||
//| Purpose: Class of operations with text files. |
|
||||
//| Derives from class CFile. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CFileTxt : public CFile
|
||||
{
|
||||
public:
|
||||
CFileTxt(void);
|
||||
~CFileTxt(void);
|
||||
//--- methods for working with files
|
||||
int Open(const string file_name,const int open_flags);
|
||||
//--- methods to access data
|
||||
uint WriteString(const string value);
|
||||
string ReadString(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFileTxt::CFileTxt(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFileTxt::~CFileTxt(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open the text file |
|
||||
//+------------------------------------------------------------------+
|
||||
int CFileTxt::Open(const string file_name,const int open_flags)
|
||||
{
|
||||
return(CFile::Open(file_name,open_flags|FILE_TXT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing string to file |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CFileTxt::WriteString(const string value)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileWriteString(m_handle,value));
|
||||
//--- failure
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading string from file |
|
||||
//+------------------------------------------------------------------+
|
||||
string CFileTxt::ReadString(void)
|
||||
{
|
||||
//--- check handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
return(FileReadString(m_handle));
|
||||
//--- failure
|
||||
return("");
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
@@ -0,0 +1,622 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HashMap.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IMap.mqh>
|
||||
#include <Generic\Interfaces\IEqualityComparer.mqh>
|
||||
#include <Generic\Internal\DefaultEqualityComparer.mqh>
|
||||
#include <Generic\Interfaces\IComparable.mqh>
|
||||
#include <Generic\Internal\CompareFunction.mqh>
|
||||
#include "HashSet.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Struct Entry<TKey, TValue>. |
|
||||
//| Usage: Internal structure for organization CHashMap<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
struct Entry: public Slot<TValue>
|
||||
{
|
||||
public:
|
||||
TKey key;
|
||||
Entry(void): key((TKey)NULL) {}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CKeyValuePair<TKey, TValue>. |
|
||||
//| Usage: Defines a key/value pair that can be set or retrieved. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
class CKeyValuePair: public IComparable<CKeyValuePair<TKey,TValue>*>
|
||||
{
|
||||
protected:
|
||||
TKey m_key;
|
||||
TValue m_value;
|
||||
|
||||
public:
|
||||
CKeyValuePair(void) { }
|
||||
CKeyValuePair(TKey key,TValue value): m_key(key), m_value(value) { }
|
||||
~CKeyValuePair(void) { }
|
||||
//--- methods to access protected data
|
||||
TKey Key(void) { return(m_key); }
|
||||
void Key(TKey key) { m_key=key; }
|
||||
TValue Value(void) { return(m_value); }
|
||||
void Value(TValue value) { m_value=value; }
|
||||
//--- method to create clone of current instance
|
||||
CKeyValuePair<TKey,TValue>*Clone(void) { return new CKeyValuePair<TKey,TValue>(m_key,m_value); }
|
||||
//--- method to compare keys
|
||||
int Compare(CKeyValuePair<TKey,TValue>*pair) { return ::Compare(m_key,pair.m_key); }
|
||||
//--- method for determining equality
|
||||
bool Equals(CKeyValuePair<TKey,TValue>*pair) { return ::Equals(m_key,pair.m_key); }
|
||||
//--- method to calculate hash code
|
||||
int HashCode(void) { return ::GetHashCode(m_key); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CKeyValuePairComparer<TKey, TValue>. |
|
||||
//| Usage: Provides a comparer class for convertation IComparer<TKey>|
|
||||
//| to the IComparer<CKeyValuePair<TKey, TValue>*> interface. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
class CKeyValuePairComparer: public IComparer<CKeyValuePair<TKey,TValue>*>
|
||||
{
|
||||
private:
|
||||
IComparer<TKey>*m_comparer;
|
||||
|
||||
public:
|
||||
CKeyValuePairComparer(IComparer<TKey>*comaprer) { m_comparer=comaprer; }
|
||||
int Compare(CKeyValuePair<TKey,TValue>* x,CKeyValuePair<TKey,TValue>* y) { return(m_comparer.Compare(x.Key(), y.Key())); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CHashMap<TKey, TValue>. |
|
||||
//| Usage: Represents a collection of keys and values. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
class CHashMap: public IMap<TKey,TValue>
|
||||
{
|
||||
protected:
|
||||
int m_buckets[];
|
||||
Entry<TKey,TValue>m_entries[];
|
||||
int m_count;
|
||||
int m_capacity;
|
||||
int m_free_list;
|
||||
int m_free_count;
|
||||
IEqualityComparer<TKey>*m_comparer;
|
||||
bool m_delete_comparer;
|
||||
|
||||
public:
|
||||
CHashMap(void);
|
||||
CHashMap(const int capacity);
|
||||
CHashMap(IEqualityComparer<TKey>*comparer);
|
||||
CHashMap(const int capacity,IEqualityComparer<TKey>*comparer);
|
||||
CHashMap(IMap<TKey,TValue>*map);
|
||||
CHashMap(IMap<TKey,TValue>*map,IEqualityComparer<TKey>*comparer);
|
||||
~CHashMap(void);
|
||||
//--- methods of filling data
|
||||
bool Add(CKeyValuePair<TKey,TValue>*pair);
|
||||
bool Add(TKey key,TValue value);
|
||||
//--- methods of access to protected data
|
||||
int Count(void) { return(m_count-m_free_count); }
|
||||
IEqualityComparer<TKey>*Comparer(void) const { return(m_comparer); }
|
||||
bool Contains(CKeyValuePair<TKey,TValue>*item);
|
||||
bool Contains(TKey key,TValue value);
|
||||
bool ContainsKey(TKey key);
|
||||
bool ContainsValue(TValue value);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(CKeyValuePair<TKey,TValue>*&dst_array[],const int dst_start=0);
|
||||
int CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0);
|
||||
//--- methods of cleaning and deleting
|
||||
void Clear(void);
|
||||
bool Remove(CKeyValuePair<TKey,TValue>*item);
|
||||
bool Remove(TKey key);
|
||||
//--- method of access to the data
|
||||
bool TryGetValue(TKey key,TValue &value);
|
||||
bool TrySetValue(TKey key,TValue value);
|
||||
|
||||
private:
|
||||
void Initialize(const int capacity);
|
||||
bool Resize(int new_size);
|
||||
int FindEntry(TKey key);
|
||||
bool Insert(TKey key,TValue value,const bool add);
|
||||
static int m_collision_threshold;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that is empty, has the default initial capacity, and uses the |
|
||||
//| default equality comparer for the key type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(void): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that is empty, has the specified initial capacity, and uses the |
|
||||
//| default equality comparer for the key type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(const int capacity): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
//--- set capacity
|
||||
if(capacity>0)
|
||||
Initialize(capacity);
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that is empty, has the default initial capacity, and uses the |
|
||||
//| specified IEqualityComparer<TKey>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(IEqualityComparer<TKey>*comparer): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified equality comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that is empty, has the specified initial capacity, and uses the |
|
||||
//| specified IEqualityComparer<TKey>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(const int capacity,IEqualityComparer<TKey>*comparer): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
if(capacity>0)
|
||||
Initialize(capacity);
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified equality comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that contains elements copied from the specified |
|
||||
//| IMap<TKey,TValue> and uses the default equality comparer for the |
|
||||
//| key type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(IMap<TKey,TValue>*map): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
//--- check map
|
||||
if(CheckPointer(map)!=POINTER_INVALID && map.Count()>0)
|
||||
{
|
||||
//--- set capacity
|
||||
Initialize(map.Count());
|
||||
TKey keys[];
|
||||
TValue values[];
|
||||
map.CopyTo(keys,values);
|
||||
//--- copy all keys and values from specified map to current map
|
||||
for(int i=0; i<map.Count(); i++)
|
||||
Add(keys[i],values[i]);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that contains elements copied from the specified |
|
||||
//| IMap<TKey,TValue> and uses the specified IEqualityComparer<TKey>.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(IMap<TKey,TValue>*map,IEqualityComparer<TKey>*comparer): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified equality comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
//--- check map
|
||||
if(CheckPointer(map)!=POINTER_INVALID && map.Count()>0)
|
||||
{
|
||||
//--- set capacity
|
||||
Initialize(map.Count());
|
||||
TKey keys[];
|
||||
TValue values[];
|
||||
map.CopyTo(keys,values);
|
||||
//--- copy all keys and values from specified map to current map
|
||||
for(int i=0; i<map.Count(); i++)
|
||||
Add(keys[i],values[i]);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::~CHashMap(void)
|
||||
{
|
||||
if(m_delete_comparer)
|
||||
delete m_comparer;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified key-value pair to the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Add(CKeyValuePair<TKey,TValue>*pair)
|
||||
{
|
||||
//--- check pair
|
||||
if(CheckPointer(pair)==POINTER_INVALID)
|
||||
return(false);
|
||||
return(Add(pair.Key(),pair.Value()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified key and value to the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Add(TKey key,TValue value)
|
||||
{
|
||||
return(Insert(key,value,true));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified key-value pair.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Contains(CKeyValuePair<TKey,TValue>*item)
|
||||
{
|
||||
//--- check pair
|
||||
if(CheckPointer(item)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- find pair with specified key
|
||||
int i=FindEntry(item.Key());
|
||||
//--- create default equality value comparer
|
||||
CDefaultEqualityComparer<TValue>comparer;
|
||||
//--- check value is equal value from the found pair
|
||||
if(i>=0 && comparer.Equals(m_entries[i].value,item.Value()))
|
||||
return(true);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified key with value.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Contains(TKey key,TValue value)
|
||||
{
|
||||
//--- find pair with specified key
|
||||
int i=FindEntry(key);
|
||||
//--- create default equality value comparer
|
||||
CDefaultEqualityComparer<TValue>comparer;
|
||||
//--- check value is equal value from the found pair
|
||||
if(i>=0 && comparer.Equals(m_entries[i].value,value))
|
||||
return(true);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::ContainsKey(TKey key)
|
||||
{
|
||||
return(FindEntry(key)>=0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::ContainsValue(TValue value)
|
||||
{
|
||||
//--- create default equality value comparer
|
||||
CDefaultEqualityComparer<TValue>comparer_value();
|
||||
//--- try to find pair contains specified value
|
||||
for(int i=0; i<m_count; i++)
|
||||
if(m_entries[i].hash_code>=0 && comparer_value.Equals(m_entries[i].value,value))
|
||||
return(true);
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the map to a compatible |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
int CHashMap::CopyTo(CKeyValuePair<TKey,TValue>*&dst_array[],const int dst_start=0)
|
||||
{
|
||||
//--- resize array
|
||||
if(dst_start+m_count>ArraySize(dst_array))
|
||||
ArrayResize(dst_array,dst_start+m_count);
|
||||
//--- start copy
|
||||
int index=0;
|
||||
for(int i=0; i<ArraySize(m_entries); i++)
|
||||
if(m_entries[i].hash_code>=0)
|
||||
{
|
||||
//--- check indexes
|
||||
if(dst_start+index>=ArraySize(dst_array) || index>=m_count)
|
||||
return(index);
|
||||
dst_array[dst_start+index++]=new CKeyValuePair<TKey,TValue>(m_entries[i].key,m_entries[i].value);
|
||||
}
|
||||
return(index);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the map to a compatible |
|
||||
//| one-dimensionals keys and values arrays. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
int CHashMap::CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0)
|
||||
{
|
||||
int count=m_count-m_free_count;
|
||||
//--- resize keys array
|
||||
if(dst_start+count>ArraySize(dst_keys))
|
||||
ArrayResize(dst_keys,dst_start+count);
|
||||
//--- resize values array
|
||||
if(dst_start+count>ArraySize(dst_values))
|
||||
ArrayResize(dst_values,MathMin(ArraySize(dst_keys),dst_start+count));
|
||||
//--- start copy
|
||||
int index=0;
|
||||
for(int i=0; i<ArraySize(m_entries); i++)
|
||||
if(m_entries[i].hash_code>=0)
|
||||
{
|
||||
//--- check indexes
|
||||
if(dst_start+index>=ArraySize(dst_keys) || dst_start+index>=ArraySize(dst_values) || index>=count)
|
||||
return(index);
|
||||
dst_keys[dst_start+index]=m_entries[i].key;
|
||||
dst_values[dst_start+index]=m_entries[i].value;
|
||||
index++;
|
||||
}
|
||||
return(index);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all keys and values from the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
void CHashMap::Clear(void)
|
||||
{
|
||||
//--- check count
|
||||
if(m_count>0)
|
||||
{
|
||||
ArrayFill(m_buckets,0,m_capacity,-1);
|
||||
ArrayFree(m_entries);
|
||||
m_count=0;
|
||||
m_free_list=-1;
|
||||
m_free_count=0;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the specified key-value pair from map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Remove(CKeyValuePair<TKey,TValue>*item)
|
||||
{
|
||||
//--- check pair
|
||||
if(CheckPointer(item)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- find pair with specified key
|
||||
int i=FindEntry(item.Key());
|
||||
//--- create default equality value comparer
|
||||
CDefaultEqualityComparer<TValue>comparer_value();
|
||||
//--- remove pair
|
||||
if(i>=0 && comparer_value.Equals(m_entries[i].value,item.Value()))
|
||||
return Remove(item.Key());
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the value with the specified key from the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Remove(TKey key)
|
||||
{
|
||||
if(m_capacity!=0)
|
||||
{
|
||||
int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF;
|
||||
int bucket=hash_code%m_capacity;
|
||||
int last=-1;
|
||||
//--- search pair with specified key
|
||||
for(int i=m_buckets[bucket]; i>=0; last=i,i=m_entries[i].next)
|
||||
{
|
||||
if(m_entries[i].hash_code==hash_code && m_comparer.Equals(m_entries[i].key,key))
|
||||
{
|
||||
if(last<0)
|
||||
m_buckets[bucket]=m_entries[i].next;
|
||||
else
|
||||
m_entries[last].next=m_entries[i].next;
|
||||
//--- remove pair
|
||||
m_entries[i].hash_code=-1;
|
||||
m_entries[i].next=m_free_list;
|
||||
m_entries[i].key=(TKey)NULL;
|
||||
m_entries[i].value=(TValue)NULL;
|
||||
//--- incremet free count
|
||||
m_free_list=i;
|
||||
m_free_count++;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets the value associated with the specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::TryGetValue(TKey key,TValue &value)
|
||||
{
|
||||
//--- find pair with specified key
|
||||
int i=FindEntry(key);
|
||||
//--- check index
|
||||
if(i>=0)
|
||||
{
|
||||
//--- get value
|
||||
value=m_entries[i].value;
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets the value associated with the specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::TrySetValue(TKey key,TValue value)
|
||||
{
|
||||
return(Insert(key, value, false));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize map with specified capacity. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
void CHashMap::Initialize(const int capacity)
|
||||
{
|
||||
m_capacity=CPrimeGenerator::GetPrime(capacity);
|
||||
ArrayResize(m_buckets,m_capacity);
|
||||
ArrayFill(m_buckets,0,m_capacity,-1);
|
||||
ArrayResize(m_entries,m_capacity);
|
||||
m_free_list=-1;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resize map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Resize(const int new_size)
|
||||
{
|
||||
//--- resize buckets
|
||||
if(ArrayResize(m_buckets,new_size)!=new_size)
|
||||
return(false);
|
||||
ArrayFill(m_buckets,0,new_size,-1);
|
||||
//--- resize entries
|
||||
if(ArrayResize(m_entries,new_size)!=new_size)
|
||||
return(false);
|
||||
//--- restore buckets
|
||||
for(int i=0; i<m_count; i++)
|
||||
if(m_entries[i].hash_code>=0)
|
||||
{
|
||||
int bucket=m_entries[i].hash_code%new_size;
|
||||
m_entries[i].next = m_buckets[bucket];
|
||||
m_buckets[bucket] = i;
|
||||
}
|
||||
//--- restore capacity
|
||||
m_capacity=new_size;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find index of entry with specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
int CHashMap::FindEntry(TKey key)
|
||||
{
|
||||
if(m_capacity!=NULL)
|
||||
{
|
||||
//--- get hash code from key
|
||||
int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF;
|
||||
//--- search pair with specified key
|
||||
for(int i=m_buckets[hash_code%m_capacity]; i>=0; i=m_entries[i].next)
|
||||
if(m_entries[i].hash_code==hash_code && m_comparer.Equals(m_entries[i].key,key))
|
||||
return(i);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Insert the value with the specified key from the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Insert(TKey key,TValue value,const bool add)
|
||||
{
|
||||
if(m_capacity==0)
|
||||
Initialize(0);
|
||||
//--- get hash code from key
|
||||
int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF;
|
||||
int target_bucket=hash_code%m_capacity;
|
||||
//--- collisions count in one bucket with different hashes
|
||||
int collision_count=0;
|
||||
//--- search pair with specified key
|
||||
for(int i=m_buckets[target_bucket]; i>=0; i=m_entries[i].next)
|
||||
{
|
||||
//--- hash compare
|
||||
if(m_entries[i].hash_code!=hash_code)
|
||||
{
|
||||
collision_count++;
|
||||
continue;
|
||||
}
|
||||
//--- value compare
|
||||
if(m_comparer.Equals(m_entries[i].key,key))
|
||||
{
|
||||
//--- adding duplicate
|
||||
if(add)
|
||||
return(false);
|
||||
m_entries[i].value=value;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
//--- check collision
|
||||
if(collision_count>=m_collision_threshold)
|
||||
{
|
||||
int new_size=CPrimeGenerator::ExpandPrime(m_count);
|
||||
if(!Resize(new_size))
|
||||
return(false);
|
||||
target_bucket=hash_code%new_size;
|
||||
}
|
||||
//--- calculate index
|
||||
int index;
|
||||
if(m_free_count>0)
|
||||
{
|
||||
index=m_free_list;
|
||||
m_free_list=m_entries[index].next;
|
||||
m_free_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_count==ArraySize(m_entries))
|
||||
{
|
||||
int new_size=CPrimeGenerator::ExpandPrime(m_count);
|
||||
if(!Resize(new_size))
|
||||
return(false);
|
||||
target_bucket=hash_code%new_size;
|
||||
}
|
||||
index=m_count;
|
||||
m_count++;
|
||||
}
|
||||
//--- set pair
|
||||
m_entries[index].hash_code=hash_code;
|
||||
m_entries[index].next=m_buckets[target_bucket];
|
||||
m_entries[index].key=key;
|
||||
m_entries[index].value=value;
|
||||
m_buckets[target_bucket]=index;
|
||||
return(true);
|
||||
}
|
||||
template<typename TKey,typename TValue>
|
||||
static int CHashMap::m_collision_threshold=8;
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,972 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HashSet.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include<Generic\Interfaces\ISet.mqh>
|
||||
#include <Generic\Internal\PrimeGenerator.mqh>
|
||||
#include <Generic\Interfaces\IEqualityComparer.mqh>
|
||||
#include <Generic\Internal\DefaultEqualityComparer.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Struct Slot<T>. |
|
||||
//| Usage: Internal structure for organization CHashSet<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
struct Slot
|
||||
{
|
||||
public:
|
||||
int hash_code;
|
||||
T value;
|
||||
int next;
|
||||
Slot(void): hash_code(0),value((T)NULL),next(0) {}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CHashSet<T>. |
|
||||
//| Usage: Represents a set of unique values. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CHashSet: public ISet<T>
|
||||
{
|
||||
protected:
|
||||
int m_buckets[];
|
||||
Slot<T> m_slots[];
|
||||
int m_count;
|
||||
int m_last_index;
|
||||
int m_free_list;
|
||||
IEqualityComparer<T>*m_comparer;
|
||||
bool m_delete_comparer;
|
||||
|
||||
public:
|
||||
CHashSet(void);
|
||||
CHashSet(IEqualityComparer<T>*comparer);
|
||||
CHashSet(ICollection<T>*collection);
|
||||
CHashSet(ICollection<T>*collection,IEqualityComparer<T>*comparer);
|
||||
CHashSet(T &array[]);
|
||||
CHashSet(T &array[],IEqualityComparer<T>*comparer);
|
||||
~CHashSet(void);
|
||||
//--- methods of filling data
|
||||
bool Add(T value);
|
||||
//--- methods of access to protected data
|
||||
int Count(void) { return(m_count); }
|
||||
IEqualityComparer<T>* Comparer(void) const { return(m_comparer); }
|
||||
bool Contains(T item);
|
||||
void TrimExcess(void);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(T &ds_array[],const int dst_start=0);
|
||||
//--- methods of cleaning and deleting
|
||||
void Clear(void);
|
||||
bool Remove(T item);
|
||||
//--- methods of changing sets
|
||||
void ExceptWith(ICollection<T>*collection);
|
||||
void ExceptWith(T &array[]);
|
||||
void IntersectWith(ICollection<T>*collection);
|
||||
void IntersectWith(T &array[]);
|
||||
void SymmetricExceptWith(ICollection<T>*collection);
|
||||
void SymmetricExceptWith(T &array[]);
|
||||
void UnionWith(ICollection<T>*collection);
|
||||
void UnionWith(T &array[]);
|
||||
//--- methods for determining the relationship between sets
|
||||
bool IsProperSubsetOf(ICollection<T>*collection);
|
||||
bool IsProperSubsetOf(T &array[]);
|
||||
bool IsProperSupersetOf(ICollection<T>*collection);
|
||||
bool IsProperSupersetOf(T &array[]);
|
||||
bool IsSubsetOf(ICollection<T>*collection);
|
||||
bool IsSubsetOf(T &array[]);
|
||||
bool IsSupersetOf(ICollection<T>*collection);
|
||||
bool IsSupersetOf(T &array[]);
|
||||
bool Overlaps(ICollection<T>*collection);
|
||||
bool Overlaps(T &array[]);
|
||||
bool SetEquals(ICollection<T>*collection);
|
||||
bool SetEquals(T &array[]);
|
||||
|
||||
private:
|
||||
void SetCapacity(const int new_size,bool new_hash_codes);
|
||||
bool AddIfNotPresent(T value);
|
||||
void Initialize(const int capacity);
|
||||
void InternalSymmetricExceptWith(CHashSet<T>*set);
|
||||
bool InternalIsSubsetOf(CHashSet<T>*set);
|
||||
bool InternalIsSupersetOf(CHashSet<T>*set);
|
||||
bool InternalIsProperSubsetOf(CHashSet<T>*set);
|
||||
bool InternalIsProperSupersetOf(CHashSet<T>*set);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that is empty|
|
||||
//| and uses the default equality comparer for the set type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(void): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that is empty|
|
||||
//| and uses the specified equality comparer for the set type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(IEqualityComparer<T>*comparer): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified equality comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that uses the|
|
||||
//| default equality comparer for the set type, contains elements |
|
||||
//| copied from the specified collection, and has sufficient capacity|
|
||||
//| to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(ICollection<T>*collection): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- set capacity for elements of the collection
|
||||
int count=collection.Count();
|
||||
Initialize(count);
|
||||
//--- add element from collection to the set
|
||||
this.UnionWith(collection);
|
||||
if((m_count==0 && ArraySize(m_slots)>3) ||
|
||||
(m_count>0 && ArraySize(m_slots)/m_count>3))
|
||||
TrimExcess();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that uses the|
|
||||
//| specified equality comparer for the set type, contains elements |
|
||||
//| copied from the specified collection, and has sufficient capacity|
|
||||
//| to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(ICollection<T>*collection,IEqualityComparer<T>*comparer): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- set capacity for elements of the collection
|
||||
int count=collection.Count();
|
||||
Initialize(count);
|
||||
//--- add element from collection to the set
|
||||
this.UnionWith(collection);
|
||||
if((m_count==0 && ArraySize(m_slots)>3) ||
|
||||
(m_count>0 && ArraySize(m_slots)/m_count>3))
|
||||
TrimExcess();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that uses the|
|
||||
//| default equality comparer for the set type, contains elements |
|
||||
//| copied from the specified array, and has sufficient capacity to |
|
||||
//| accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(T &array[]): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
//--- set capacity for elements of the array
|
||||
int count=ArraySize(array);
|
||||
Initialize(count);
|
||||
//--- add element from array to the set
|
||||
this.UnionWith(array);
|
||||
if((m_count==0 && ArraySize(m_slots)>3) ||
|
||||
(m_count>0 && ArraySize(m_slots)/m_count>3))
|
||||
TrimExcess();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that uses the|
|
||||
//| specified equality comparer for the set type, contains elements |
|
||||
//| copied from the specified array, and has sufficient capacity to |
|
||||
//| accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(T &array[],IEqualityComparer<T>*comparer): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
//--- set capacity for elements of the array
|
||||
int count=ArraySize(array);
|
||||
Initialize(count);
|
||||
//--- add element from array to the set
|
||||
this.UnionWith(array);
|
||||
if((m_count==0 && ArraySize(m_slots)>3) ||
|
||||
(m_count>0 && ArraySize(m_slots)/m_count>3))
|
||||
TrimExcess();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T> CHashSet::~CHashSet(void)
|
||||
{
|
||||
if(m_delete_comparer)
|
||||
delete m_comparer;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified element to a set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::Add(T value)
|
||||
{
|
||||
return AddIfNotPresent(value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set contains the specified element. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::Contains(T item)
|
||||
{
|
||||
//--- check buckets
|
||||
if(ArraySize(m_buckets)!=0)
|
||||
{
|
||||
//--- get hash code for item
|
||||
int hash_code=m_comparer.HashCode(item)&0x7FFFFFFF;
|
||||
//--- search item in the slots
|
||||
for(int i=m_buckets[hash_code%ArraySize(m_buckets)]-1; i>=0; i=m_slots[i].next)
|
||||
if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,item))
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets the capacity of a set to the actual number of elements it |
|
||||
//| contains, rounded up to a nearby, implementation-specific value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::TrimExcess(void)
|
||||
{
|
||||
if(m_count==0)
|
||||
{
|
||||
ArrayFree(m_buckets);
|
||||
ArrayFree(m_slots);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- calculate min prime size for current count
|
||||
int new_size=CPrimeGenerator::GetPrime(m_count);
|
||||
//--- resize buckets and slots
|
||||
ArrayResize(m_slots,new_size);
|
||||
ArrayResize(m_buckets,new_size);
|
||||
//--- restore buckets and slots
|
||||
int new_index=0;
|
||||
for(int i=0; i<m_last_index; i++)
|
||||
{
|
||||
if(m_slots[i].hash_code>=0)
|
||||
{
|
||||
m_slots[new_index]=m_slots[i];
|
||||
//--- rehash
|
||||
int bucket=m_slots[new_index].hash_code%new_size;
|
||||
m_slots[new_index].next=m_buckets[bucket]-1;
|
||||
m_buckets[bucket]=new_index+1;
|
||||
//--- increment index
|
||||
new_index++;
|
||||
}
|
||||
}
|
||||
m_last_index=new_index;
|
||||
m_free_list=-1;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the set to a compatible |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CHashSet::CopyTo(T &dst_array[],const int dst_start)
|
||||
{
|
||||
//--- resize array
|
||||
if(dst_start+m_count>ArraySize(dst_array))
|
||||
ArrayResize(dst_array,dst_start+m_count);
|
||||
//--- start copy
|
||||
int index=0;
|
||||
for(int i=0; i<ArraySize(m_slots); i++)
|
||||
if(m_slots[i].hash_code>=0)
|
||||
{
|
||||
if(dst_start+index>=ArraySize(dst_array) || index>=m_count)
|
||||
return(index);
|
||||
dst_array[dst_start+index++]=m_slots[i].value;
|
||||
}
|
||||
return(index);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all elements from a set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::Clear(void)
|
||||
{
|
||||
if(m_last_index>0)
|
||||
{
|
||||
ArrayFree(m_slots);
|
||||
ArrayFree(m_buckets);
|
||||
m_last_index=0;
|
||||
m_count=0;
|
||||
m_free_list=-1;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the specified element from a set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::Remove(T item)
|
||||
{
|
||||
if(ArraySize(m_buckets)!=0)
|
||||
{
|
||||
//--- get hash code for item
|
||||
int hash_code=m_comparer.HashCode(item)&0x7FFFFFFF;
|
||||
int bucket=hash_code%ArraySize(m_buckets);
|
||||
int last=-1;
|
||||
//--- search item
|
||||
for(int i=m_buckets[bucket]-1; i>=0; last=i,i=m_slots[i].next)
|
||||
{
|
||||
if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,item))
|
||||
{
|
||||
if(last<0)
|
||||
m_buckets[bucket]=m_slots[i].next+1;
|
||||
else
|
||||
m_slots[last].next=m_slots[i].next;
|
||||
//--- remove item
|
||||
m_slots[i].hash_code=-1;
|
||||
m_slots[i].value=(T)NULL;
|
||||
m_slots[i].next =m_free_list;
|
||||
//--- decrement count
|
||||
m_count--;
|
||||
if(m_count==0)
|
||||
{
|
||||
m_last_index= 0;
|
||||
m_free_list = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_free_list=i;
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all elements in the specified collection from the current|
|
||||
//| set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::ExceptWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- this is already the enpty set
|
||||
if(m_count==0)
|
||||
return;
|
||||
//--- special case if collecion is this
|
||||
//--- a set minus itself is the empty set
|
||||
if(collection==GetPointer(this))
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- copy collection to array
|
||||
T array[];
|
||||
collection.CopyTo(array,0);
|
||||
//--- remove every element in collection from this
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
Remove(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all elements in the specified array from the current set.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::ExceptWith(T &array[])
|
||||
{
|
||||
//--- this is already the enpty set
|
||||
if(m_count==0)
|
||||
return;
|
||||
//--- remove every element in collection from this
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
Remove(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present in that object and in the specified collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::IntersectWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- intersection of anything with empty set is empty set, so return if count is 0
|
||||
if(m_count==0)
|
||||
return;
|
||||
//--- if collection is empty, intersection is empty set
|
||||
if(collection.Count()==0)
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- intersect
|
||||
for(int i=0; i<m_last_index; i++)
|
||||
{
|
||||
if(m_slots[i].hash_code>=0)
|
||||
{
|
||||
T item=m_slots[i].value;
|
||||
if(!collection.Contains(item))
|
||||
Remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present in that object and in the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::IntersectWith(T &array[])
|
||||
{
|
||||
//--- intersection of anything with empty set is empty set, so return if count is 0
|
||||
if(m_count==0)
|
||||
return;
|
||||
//--- if collection is empty, intersection is empty set
|
||||
if(ArraySize(array)==0)
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- intersect
|
||||
CHashSet<T>set(array);
|
||||
for(int i=0; i<m_last_index; i++)
|
||||
{
|
||||
if(m_slots[i].hash_code>=0)
|
||||
{
|
||||
T item=m_slots[i].value;
|
||||
if(!set.Contains(item))
|
||||
Remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present either in that set or in the specified collection, but |
|
||||
//| not both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::SymmetricExceptWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- if set is empty, then symmetric difference is other
|
||||
if(m_count==0)
|
||||
{
|
||||
UnionWith(collection);
|
||||
return;
|
||||
}
|
||||
//--- special case this; the symmetric difference of a set with itself is the empty set
|
||||
if(collection==GetPointer(this))
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
InternalSymmetricExceptWith(ptr_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
InternalSymmetricExceptWith(GetPointer(set));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present either in that set or in the specified array, but not |
|
||||
//| both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::SymmetricExceptWith(T &array[])
|
||||
{
|
||||
//--- if set is empty, then symmetric difference is other
|
||||
if(m_count==0)
|
||||
{
|
||||
UnionWith(array);
|
||||
return;
|
||||
}
|
||||
//--- symmetric except
|
||||
CHashSet<T>set(array);
|
||||
InternalSymmetricExceptWith(GetPointer(set));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain all elements that are present|
|
||||
//| in itself, the specified collection, or both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::UnionWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- get array from collection
|
||||
T array[];
|
||||
collection.CopyTo(array);
|
||||
//--- union array with the current set
|
||||
UnionWith(array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain all elements that are present|
|
||||
//| in itself, the specified array, or both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::UnionWith(T &array[])
|
||||
{
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
AddIfNotPresent(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper subset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsProperSubsetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- the empty set is a proper subset of anything but the empty set
|
||||
if(m_count==0)
|
||||
return(collection.Count()>0);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return InternalIsProperSubsetOf(ptr_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return InternalIsProperSubsetOf(GetPointer(set));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper subset of the specified |
|
||||
//| array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsProperSubsetOf(T &array[])
|
||||
{
|
||||
//--- the empty set is a proper subset of anything but the empty set
|
||||
if(m_count==0)
|
||||
return(ArraySize(array)>0);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return InternalIsProperSubsetOf(GetPointer(set));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper superset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsProperSupersetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_count>0);
|
||||
//--- the empty set is a proper subset of anything but the empty set
|
||||
if(m_count==0)
|
||||
return(false);
|
||||
//--- if other is the empty set then this is a superset
|
||||
if(collection.Count()==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return InternalIsProperSupersetOf(ptr_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return InternalIsProperSupersetOf(GetPointer(set));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper superset of the specified |
|
||||
//| array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsProperSupersetOf(T &array[])
|
||||
{
|
||||
//--- the empty set is a proper subset of anything but the empty set
|
||||
if(m_count==0)
|
||||
return(false);
|
||||
//--- if other is the empty set then this is a superset
|
||||
if(ArraySize(array)==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return InternalIsProperSupersetOf(GetPointer(set));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a subset of the specified collection.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsSubsetOf(ICollection<T>*collection)
|
||||
{
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_count==0);
|
||||
//--- The empty set is a subset of any set
|
||||
if(m_count==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return InternalIsSubsetOf(ptr_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return InternalIsSubsetOf(GetPointer(set));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a subset of the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsSubsetOf(T &array[])
|
||||
{
|
||||
//--- The empty set is a subset of any set
|
||||
if(m_count==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return InternalIsSubsetOf(GetPointer(set));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a superset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsSupersetOf(ICollection<T>*collection)
|
||||
{
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_count>=0);
|
||||
//--- if other is the empty set then this is a superset
|
||||
if(collection.Count()==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return InternalIsSupersetOf(ptr_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return InternalIsSupersetOf(GetPointer(set));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a superset of the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsSupersetOf(T &array[])
|
||||
{
|
||||
//--- if other is the empty set then this is a superset
|
||||
if(ArraySize(array)==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return InternalIsSupersetOf(GetPointer(set));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the current set and a specified collection |
|
||||
//| share common elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::Overlaps(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- check current count
|
||||
if(m_count==0)
|
||||
return(false);
|
||||
//--- get array from collection
|
||||
T array[];
|
||||
collection.CopyTo(array);
|
||||
//--- check overlaps between current set and array
|
||||
return Overlaps(array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the current set and a specified array share |
|
||||
//| common elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::Overlaps(T &array[])
|
||||
{
|
||||
//--- check current count
|
||||
if(m_count==0)
|
||||
return(false);
|
||||
//--- try to find any elements from specified array in current set
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
if(Contains(array[i]))
|
||||
return(true);
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set and the specified collection contain the|
|
||||
//| same elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::SetEquals(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- check current set is equal specified collection
|
||||
if(collection==GetPointer(this))
|
||||
return(true);
|
||||
//--- get array from collection
|
||||
T array[];
|
||||
collection.CopyTo(array);
|
||||
//--- check current set is equal specified array
|
||||
return SetEquals(array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set and the specified array contain the same|
|
||||
//| elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::SetEquals(T &array[])
|
||||
{
|
||||
//--- check size
|
||||
if(ArraySize(array)!=m_count)
|
||||
return(false);
|
||||
//--- check current set is equal specified array
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
if(!Contains(array[i]))
|
||||
return(false);
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the underlying buckets array to size new_size and rehash. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::SetCapacity(const int new_size,bool new_hash_codes)
|
||||
{
|
||||
//--- resize slots
|
||||
ArrayResize(m_slots,new_size);
|
||||
//--- restore slots
|
||||
if(new_hash_codes)
|
||||
for(int i=0; i<m_last_index; i++)
|
||||
if(m_slots[i].hash_code!=-1)
|
||||
m_slots[i].hash_code=m_comparer.HashCode(m_slots[i].value)&0x7FFFFFFF;
|
||||
//--- resize buckets
|
||||
ArrayResize(m_buckets,new_size);
|
||||
ArrayFill(m_buckets,0,new_size,0);
|
||||
//--- restore buckets
|
||||
for(int i=0; i<m_last_index; i++)
|
||||
{
|
||||
int bucket=m_slots[i].hash_code%new_size;
|
||||
m_slots[i].next=m_buckets[bucket]-1;
|
||||
m_buckets[bucket]=i+1;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds value to set if not contained already. Returns true if added|
|
||||
//| and false if already present. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::AddIfNotPresent(T value)
|
||||
{
|
||||
//--- set minimum capacity
|
||||
if(ArraySize(m_buckets)==0)
|
||||
Initialize(0);
|
||||
//--- get hash code and bucket for value
|
||||
int hash_code=m_comparer.HashCode(value)&0x7FFFFFFF;
|
||||
int bucket=hash_code%ArraySize(m_buckets);
|
||||
//--- check value already in the set
|
||||
for(int i=m_buckets[hash_code%ArraySize(m_buckets)]-1; i>=0; i=m_slots[i].next)
|
||||
if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,value))
|
||||
return(false);
|
||||
//--- calculate index for value
|
||||
int index=0;
|
||||
if(m_free_list>=0)
|
||||
{
|
||||
index=m_free_list;
|
||||
m_free_list=m_slots[index].next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_last_index==ArraySize(m_slots))
|
||||
{
|
||||
int new_size=CPrimeGenerator::ExpandPrime(m_count);
|
||||
SetCapacity(new_size,false);
|
||||
bucket=hash_code%ArraySize(m_buckets);
|
||||
}
|
||||
index=m_last_index;
|
||||
m_last_index++;
|
||||
}
|
||||
//--- set value
|
||||
m_slots[index].hash_code=hash_code;
|
||||
m_slots[index].value=value;
|
||||
m_slots[index].next=m_buckets[bucket]-1;
|
||||
m_buckets[bucket]=index+1;
|
||||
//--- increase count
|
||||
m_count++;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize set with specified capacity. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::Initialize(const int capacity)
|
||||
{
|
||||
int size=CPrimeGenerator::GetPrime(capacity);
|
||||
ArrayResize(m_buckets,size);
|
||||
ArrayResize(m_slots,size);
|
||||
ZeroMemory(m_buckets);
|
||||
ZeroMemory(m_slots);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present either in that set or in the specified set, but not both.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::InternalSymmetricExceptWith(CHashSet<T>*set)
|
||||
{
|
||||
for(int i=0; i<ArraySize(set.m_slots); i++)
|
||||
{
|
||||
T item=set.m_slots[i].value;
|
||||
if(!Remove(item))
|
||||
AddIfNotPresent(item);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a subset of the specified set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::InternalIsSubsetOf(CHashSet<T>*set)
|
||||
{
|
||||
//--- if this has more elements then it can't be a subset
|
||||
if(m_count>set.m_count)
|
||||
return(false);
|
||||
//--- try to find any elements from current set in specified set
|
||||
for(int i=0; i<m_count; i++)
|
||||
{
|
||||
T item=m_slots[i].value;
|
||||
if(!set.Contains(item))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a superset of the specified set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::InternalIsSupersetOf(CHashSet<T>*set)
|
||||
{
|
||||
//--- if this has less elements then it can't be a superset
|
||||
if(set.m_count>m_count)
|
||||
return(false);
|
||||
//--- try to find any elements from specified set in current set
|
||||
for(int i=0; i<set.m_count; i++)
|
||||
{
|
||||
T item=set.m_slots[i].value;
|
||||
if(!Contains(item))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper subset of the specified set.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::InternalIsProperSubsetOf(CHashSet<T>*set)
|
||||
{
|
||||
//--- if this has more or equal elements then it can't be a proper subset
|
||||
if(m_count>=set.m_count)
|
||||
return(false);
|
||||
//--- try to find any elements from current set in specified set
|
||||
for(int i=0; i<m_count; i++)
|
||||
{
|
||||
T item=m_slots[i].value;
|
||||
if(!set.Contains(item))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper superset of the specified |
|
||||
//| set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::InternalIsProperSupersetOf(CHashSet<T>*set)
|
||||
{
|
||||
//--- if this has less or equal elements then it can't be a proper superset
|
||||
if(m_count<=set.m_count)
|
||||
return(false);
|
||||
//--- try to find any elements from specified set in current set
|
||||
for(int i=0; i<set.m_count; i++)
|
||||
{
|
||||
T item=set.m_slots[i].value;
|
||||
if(!Contains(item))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,24 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ICollection.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface ICollection<T>. |
|
||||
//| Usage: Defines methods to manipulate generic collections. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface ICollection
|
||||
{
|
||||
//--- methods of filling data
|
||||
bool Add(T value);
|
||||
//--- methods of access to protected data
|
||||
int Count(void);
|
||||
bool Contains(T item);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(T &dst_array[],const int dst_start=0);
|
||||
//--- methods of cleaning and removing
|
||||
void Clear(void);
|
||||
bool Remove(T item);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,19 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IComparable.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "IEqualityComparable.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IComparable<T>. |
|
||||
//| Usage: Defines a generalized comparison method to create a |
|
||||
//| type-specific comparison method for ordering or sorting |
|
||||
//| instances. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface IComparable: public IEqualityComparable<T>
|
||||
{
|
||||
//--- method for determining compare
|
||||
int Compare(T value);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,17 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IComparer.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IComparer<T>. |
|
||||
//| Usage: Defines a method that a type implements to compare two |
|
||||
//| values. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface IComparer
|
||||
{
|
||||
//--- compares two values and returns a value indicating whether one is less than, equal to, or greater than the other
|
||||
int Compare(T x,T y);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,19 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IEqualityComparable.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IEqualityComparable<T>. |
|
||||
//| Usage: Defines a generalized method to create a type-specific |
|
||||
//| method for determining equality of instances. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface IEqualityComparable
|
||||
{
|
||||
//--- method for determining equality
|
||||
bool Equals(T value);
|
||||
//--- method to calculate hash code
|
||||
int HashCode(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,19 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IEqualityComparer.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IEqualityComparer<T>. |
|
||||
//| Usage: Defines methods to support the comparison of values for |
|
||||
//| equality. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface IEqualityComparer
|
||||
{
|
||||
//--- determines whether the specified values are equal
|
||||
bool Equals(T x,T y);
|
||||
//--- returns a hash code for the specified object
|
||||
int HashCode(T value);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,26 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IList.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ICollection.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IList<T>. |
|
||||
//| Usage: Represents a collection of objects that can be |
|
||||
//| individually accessed by index. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface IList: public ICollection<T>
|
||||
{
|
||||
//--- method of access to the data
|
||||
bool TryGetValue(const int index,T &value);
|
||||
bool TrySetValue(const int index,T value);
|
||||
//--- methods of filling the array
|
||||
bool Insert(const int index,T item);
|
||||
//--- methods for searching index
|
||||
int IndexOf(T item);
|
||||
int LastIndexOf(T item);
|
||||
//--- methods of cleaning and deleting
|
||||
bool RemoveAt(const int index);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,27 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IMap.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ICollection.mqh"
|
||||
template<typename TKey,typename TValue>
|
||||
class CKeyValuePair;
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IMap<TKey,TValue>. |
|
||||
//| Usage: Represents a generic collection of key/value pairs. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
interface IMap: public ICollection<CKeyValuePair<TKey,TValue>*>
|
||||
{
|
||||
//--- methods of filling data
|
||||
bool Add(TKey key,TValue value);
|
||||
//--- methods of access to protected data
|
||||
bool Contains(TKey key,TValue value);
|
||||
bool Remove(TKey key);
|
||||
//--- method of access to the data
|
||||
bool TryGetValue(TKey key,TValue &value);
|
||||
bool TrySetValue(TKey key,TValue value);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,37 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ISet.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ICollection.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface ISet<T>. |
|
||||
//| Usage: Provides the base interface for the abstraction of sets. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface ISet: public ICollection<T>
|
||||
{
|
||||
//--- methods of changing sets
|
||||
void ExceptWith(ICollection<T>*collection);
|
||||
void ExceptWith(T &array[]);
|
||||
void IntersectWith(ICollection<T>*collection);
|
||||
void IntersectWith(T &array[]);
|
||||
void SymmetricExceptWith(ICollection<T>*collection);
|
||||
void SymmetricExceptWith(T &array[]);
|
||||
void UnionWith(ICollection<T>*collection);
|
||||
void UnionWith(T &array[]);
|
||||
//--- methods for determining the relationship between sets
|
||||
bool IsProperSubsetOf(ICollection<T>*collection);
|
||||
bool IsProperSubsetOf(T &array[]);
|
||||
bool IsProperSupersetOf(ICollection<T>*collection);
|
||||
bool IsProperSupersetOf(T &array[]);
|
||||
bool IsSubsetOf(ICollection<T>*collection);
|
||||
bool IsSubsetOf(T &array[]);
|
||||
bool IsSupersetOf(ICollection<T>*collection);
|
||||
bool IsSupersetOf(T &array[]);
|
||||
bool Overlaps(ICollection<T>*collection);
|
||||
bool Overlaps(T &array[]);
|
||||
bool SetEquals(ICollection<T>*collection);
|
||||
bool SetEquals(T &array[]);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,135 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayFunction.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "CompareFunction.mqh"
|
||||
#include <Generic\Interfaces\IComparer.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Searches an entire one-dimensional sorted array for a specific |
|
||||
//| element, using the IComparable<T> generic interface implemented |
|
||||
//| by each element of the array and by the specified object. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int ArrayBinarySearch(T &array[],const int start_index,const int count, T value,IComparer<T>*comparer)
|
||||
{
|
||||
int lo=start_index;
|
||||
int hi=start_index+count-1;
|
||||
int size=ArraySize(array);
|
||||
//--- check array size
|
||||
if(size==0)
|
||||
return(-1);
|
||||
//--- check comaparer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
return(-1);
|
||||
//--- check index
|
||||
if(start_index<0 || count<0 || size-start_index<count)
|
||||
return(-1);
|
||||
//--- bianry search value
|
||||
while(lo<=hi)
|
||||
{
|
||||
int i=lo+((hi-lo)>>1);
|
||||
int order=comparer.Compare(array[i],value);
|
||||
if(order==0)
|
||||
{
|
||||
return(i);
|
||||
}
|
||||
if(order<0)
|
||||
{
|
||||
lo=i+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hi=i-1;
|
||||
}
|
||||
}
|
||||
//--- returns the index of an element nearest in value
|
||||
if(lo>0)
|
||||
return(lo-1);
|
||||
return(lo);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Searches for the specified object and returns the index of its |
|
||||
//| first occurrence in a one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int ArrayIndexOf(T &array[],T value,const int start_index,const int count)
|
||||
{
|
||||
int size=ArraySize(array);
|
||||
//--- check array size
|
||||
if(size==0)
|
||||
return(-1);
|
||||
//--- check start index and count
|
||||
if(start_index<0 || start_index>size ||
|
||||
count<0 || count>size-start_index)
|
||||
return(-1);
|
||||
//--- search value
|
||||
int end_index=start_index+count;
|
||||
for(int i=start_index; i<end_index; i++)
|
||||
{
|
||||
//--- check the value in array is eqaul to specified value
|
||||
if(::Equals(array[i],value))
|
||||
{
|
||||
//--- return fist index
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
//--- return -1 if value not in array
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns the index of the last occurrence of a value in a |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int ArrayLastIndexOf(T &array[],T value,const int start_index,const int count)
|
||||
{
|
||||
int size=ArraySize(array);
|
||||
//--- check array size
|
||||
if(size==0)
|
||||
return(-1);
|
||||
//--- check start index and count
|
||||
if(start_index<0 || start_index>=size ||
|
||||
count<0 || count>start_index+1)
|
||||
return(-1);
|
||||
//--- search value
|
||||
int end_index=start_index-count+1;
|
||||
for(int i=start_index; i>=end_index; i--)
|
||||
{
|
||||
//--- check the value in array is eqaul to specified value
|
||||
if(::Equals(array[i],value))
|
||||
{
|
||||
//--- return fist index from the end
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
//--- return -1 if value not in array
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reverses the elements in a range of this array. Following a call |
|
||||
//| to this method, an element in the range given by index and count |
|
||||
//| which was previously located at index i will now be located at |
|
||||
//| index index + (index + count - i - 1). |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool ArrayReverse(T &array[],const int start_index,const int count)
|
||||
{
|
||||
int size=ArraySize(array);
|
||||
//--- check start index and count
|
||||
if(count<0 || size-start_index<count)
|
||||
return(false);
|
||||
//--- reverse elements
|
||||
int i = start_index;
|
||||
int j = start_index + count - 1;
|
||||
while(i<j)
|
||||
{
|
||||
T temp=array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
i++;
|
||||
j--;
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,209 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| CompareFunction.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IComparable.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const bool x,const bool y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const char x,const char y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const uchar x,const uchar y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const short x,const short y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const ushort x,const ushort y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const color x,const color y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const int x,const int y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const uint x,const uint y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const datetime x,const datetime y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const long x,const long y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const ulong x,const ulong y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const float x,const float y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const double x,const double y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const string x,const string y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int Compare(T x,T y)
|
||||
{
|
||||
//--- try to convert to comparable object
|
||||
IComparable<T>*comparable=dynamic_cast<IComparable<T>*>(x);
|
||||
if(comparable)
|
||||
{
|
||||
//--- use specied compare method
|
||||
return comparable.Compare(y);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- unknown compare function
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,22 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DefaultComparer.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IComparer.mqh>
|
||||
#include "CompareFunction.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CDefaultComparer<T>. |
|
||||
//| Usage: Provides a default class for implementations of the |
|
||||
//| IComparer<T> generic interface. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CDefaultComparer: public IComparer<T>
|
||||
{
|
||||
public:
|
||||
CDefaultComparer(void) { }
|
||||
~CDefaultComparer(void) { }
|
||||
//--- compares two values and returns a value describing relationship between them
|
||||
int Compare(T x,T y) { return ::Compare(x,y); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,25 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DefaultEqualityComparer.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IEqualityComparer.mqh>
|
||||
#include "EqualFunction.mqh"
|
||||
#include "HashFunction.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CDefaultEqualityComparer<T>. |
|
||||
//| Usage: Provides a default class for implementations of the |
|
||||
//| IEqualityComparer<T> generic interface. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CDefaultEqualityComparer: public IEqualityComparer<T>
|
||||
{
|
||||
public:
|
||||
CDefaultEqualityComparer(void) { }
|
||||
~CDefaultEqualityComparer(void) { }
|
||||
//--- determines whether the specified values are equal
|
||||
bool Equals(T x,T y) { return ::Equals(x,y); }
|
||||
//--- returns a hash code for the specified object
|
||||
int HashCode(T value) { return ::GetHashCode(value); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,26 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| EqualFunction.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IEqualityComparable.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Indicates whether x object is equal y object of the same type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool Equals(T x,T y)
|
||||
{
|
||||
//--- try to convert to equality comparable object
|
||||
IEqualityComparable<T>*equtable=dynamic_cast<IEqualityComparable<T>*>(x);
|
||||
if(equtable)
|
||||
{
|
||||
//--- use specied equality compare method
|
||||
return equtable.Equals(y);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use default equality comparer operator
|
||||
return(x==y);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,176 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HashFunction.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Unioun BitInterpreter. |
|
||||
//| Usage: Provides the ability to interpret the same bit sequence in|
|
||||
//| different types. |
|
||||
//+------------------------------------------------------------------+
|
||||
union BitInterpreter
|
||||
{
|
||||
bool bool_value;
|
||||
char char_value;
|
||||
uchar uchar_value;
|
||||
short short_value;
|
||||
ushort ushort_value;
|
||||
color color_value;
|
||||
int int_value;
|
||||
uint uint_value;
|
||||
datetime datetime_value;
|
||||
long long_value;
|
||||
ulong ulong_value;
|
||||
float float_value;
|
||||
double double_value;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for boolean. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const bool value)
|
||||
{
|
||||
return((value)?true:false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for character. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const char value)
|
||||
{
|
||||
return((int)value | ((int)value << 16));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for unsigned character. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const uchar value)
|
||||
{
|
||||
return((int)value | ((int)value << 16));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for short. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const short value)
|
||||
{
|
||||
return(((int)((ushort)value) | (((int)value) << 16)));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for unsigned short. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const ushort value)
|
||||
{
|
||||
return((int)value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for color. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const color value)
|
||||
{
|
||||
return((int)value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for integer. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const int value)
|
||||
{
|
||||
return(value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for unsigned integer. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const uint value)
|
||||
{
|
||||
return((int)value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for datetime. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const datetime value)
|
||||
{
|
||||
long ticks=(long)value;
|
||||
return(((int)ticks) ^ (int)(ticks >> 32));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for long. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const long value)
|
||||
{
|
||||
return(((int)((long)value)) ^ (int)(value >> 32));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for unsigned long. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const ulong value)
|
||||
{
|
||||
return(((int)value) ^ (int)(value >> 32));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for float. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const float value)
|
||||
{
|
||||
if(value==0)
|
||||
{
|
||||
//--- ensure that 0 and -0 have the same hash code
|
||||
return(0);
|
||||
}
|
||||
BitInterpreter convert;
|
||||
convert.float_value=value;
|
||||
return(convert.int_value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for string. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const double value)
|
||||
{
|
||||
if(value==0)
|
||||
{
|
||||
//--- ensure that 0 and -0 have the same hash code
|
||||
return(0);
|
||||
}
|
||||
BitInterpreter convert;
|
||||
convert.double_value=value;
|
||||
long lvalue=convert.long_value;
|
||||
return(((int)lvalue) ^ ((int)(lvalue >> 32)));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for string. |
|
||||
//| The hashcode for a string is computed as: |
|
||||
//| |
|
||||
//| s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] |
|
||||
//| |
|
||||
//| using int arithmetic, where s[i] is the ith character of the |
|
||||
//| string, n is the length of the string, and ^ indicates |
|
||||
//| exponentiation. (The hash value of the empty string is zero.) |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const string value)
|
||||
{
|
||||
int len=StringLen(value);
|
||||
int hash=0;
|
||||
//--- check length of string
|
||||
if(len>0)
|
||||
{
|
||||
//--- calculate a hash as a fucntion of each char
|
||||
for(int i=0; i<len; i++)
|
||||
hash=31*hash+value[i];
|
||||
}
|
||||
return(hash);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for custom object. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int GetHashCode(T value)
|
||||
{
|
||||
//--- try to convert to equality comparable object
|
||||
IEqualityComparable<T>*equtable=dynamic_cast<IEqualityComparable<T>*>(value);
|
||||
if(equtable)
|
||||
{
|
||||
//--- calculate hash by specied method
|
||||
return equtable.HashCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- calculate hash from name of object
|
||||
return GetHashCode(typename(value));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,244 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Introsort.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Struct Introsort<TKey,TItem>. |
|
||||
//| Usage: Used by the sort methods for instances of array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
struct Introsort
|
||||
{
|
||||
public:
|
||||
IComparer<TKey>* comparer;
|
||||
TKey keys[];
|
||||
TItem items[];
|
||||
|
||||
Introsort(void) {}
|
||||
~Introsort(void) {}
|
||||
//--- method for sort array
|
||||
void Sort(const int index,const int length);
|
||||
private:
|
||||
//--- methods for introspective sorting
|
||||
void IntroSort(const int lo,const int hi,int depthLimit);
|
||||
int PickPivotAndPartition(const int lo,const int hi);
|
||||
void InsertionSort(const int lo,const int hi);
|
||||
//--- methods for heap sorting
|
||||
void Heapsort(const int lo,const int hi);
|
||||
void DownHeap(const int i,const int n,const int lo);
|
||||
//--- swap methods
|
||||
void SwapIfGreaterWithItems(const int a,const int b);
|
||||
void Swap(const int i,const int j);
|
||||
//--- service methods
|
||||
int FloorLog2(int n) const;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| IntrospectiveSort is a hybrid sorting algorithm that provides |
|
||||
//| both fast average performance and (asymptotically) optimal |
|
||||
//| worst-case performance. It begins with quicksort and switches to |
|
||||
//| heapsort when the recursion depth exceeds a level based on the |
|
||||
//| number of elements being sorted. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::Sort(const int index,const int length)
|
||||
{
|
||||
if(length<2)
|
||||
return;
|
||||
IntroSort(index,length+index-1,2*FloorLog2(ArraySize(keys)));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Exchanges the values of a and b, if a greater b. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::SwapIfGreaterWithItems(const int a,const int b)
|
||||
{
|
||||
if(a!=b)
|
||||
{
|
||||
if(comparer.Compare(keys[a],keys[b])>0)
|
||||
{
|
||||
TKey key=keys[a];
|
||||
keys[a]=keys[b];
|
||||
keys[b]=key;
|
||||
if(ArraySize(items)!=NULL)
|
||||
{
|
||||
TItem item=items[a];
|
||||
items[a]=items[b];
|
||||
items[b]=item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Exchanges the values of a and b. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::Swap(const int i,const int j)
|
||||
{
|
||||
TKey key=keys[i];
|
||||
keys[i]=keys[j];
|
||||
keys[j]=key;
|
||||
if(ArraySize(items)!=NULL)
|
||||
{
|
||||
TItem item=items[i];
|
||||
items[i]=items[j];
|
||||
items[j]=item;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns the closest integer value less than or equal to the base |
|
||||
//| 2 log of the input value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
int Introsort::FloorLog2(int n) const
|
||||
{
|
||||
int result=0;
|
||||
while(n>=1)
|
||||
{
|
||||
result++;
|
||||
n=n/2;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Introspective sort. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::IntroSort(const int lo,int hi,int depthLimit)
|
||||
{
|
||||
const int IntrosortSizeThreshold=16;
|
||||
while(hi>lo)
|
||||
{
|
||||
int partitionSize = hi - lo + 1;
|
||||
if(partitionSize <= IntrosortSizeThreshold)
|
||||
{
|
||||
if(partitionSize==1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(partitionSize==2)
|
||||
{
|
||||
SwapIfGreaterWithItems(lo,hi);
|
||||
return;
|
||||
}
|
||||
if(partitionSize==3)
|
||||
{
|
||||
SwapIfGreaterWithItems(lo,hi-1);
|
||||
SwapIfGreaterWithItems(lo,hi);
|
||||
SwapIfGreaterWithItems(hi-1,hi);
|
||||
return;
|
||||
}
|
||||
InsertionSort(lo,hi);
|
||||
return;
|
||||
}
|
||||
if(depthLimit==0)
|
||||
{
|
||||
Heapsort(lo,hi);
|
||||
return;
|
||||
}
|
||||
depthLimit--;
|
||||
int p=PickPivotAndPartition(lo,hi);
|
||||
IntroSort(p+1,hi,depthLimit);
|
||||
hi=p-1;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Insertion sort. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::InsertionSort(const int lo,const int hi)
|
||||
{
|
||||
int i,j;
|
||||
TKey t;
|
||||
TItem dt;
|
||||
for(i=lo; i<hi; i++)
|
||||
{
|
||||
j = i;
|
||||
t = keys[i + 1];
|
||||
dt=(ArraySize(items)!=NULL) ? (TItem)items[i+1] : (TItem)NULL;
|
||||
while(j>=lo && comparer.Compare(t,keys[j])<0)
|
||||
{
|
||||
keys[j+1]=keys[j];
|
||||
if(ArraySize(items)!=NULL)
|
||||
{
|
||||
items[j+1]=items[j];
|
||||
}
|
||||
j--;
|
||||
}
|
||||
keys[j+1]=t;
|
||||
if(ArraySize(items)!=NULL)
|
||||
{
|
||||
items[j+1]=dt;
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Array partitioning by a quick sort algorithm. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
int Introsort::PickPivotAndPartition(const int lo,const int hi)
|
||||
{
|
||||
//--- Compute median-of-three. But also partition them, since we've done the comparison.
|
||||
int mid=lo+(hi-lo)/2;
|
||||
SwapIfGreaterWithItems(lo,mid);
|
||||
SwapIfGreaterWithItems(lo,hi);
|
||||
SwapIfGreaterWithItems(mid,hi);
|
||||
TKey pivot=keys[mid];
|
||||
Swap(mid,hi-1);
|
||||
int left=lo,right=hi-1;
|
||||
while(left<right)
|
||||
{
|
||||
while(comparer.Compare(keys[++left], pivot) < 0);
|
||||
while(comparer.Compare(pivot, keys[--right]) < 0);
|
||||
if(left>=right)
|
||||
break;
|
||||
Swap(left,right);
|
||||
}
|
||||
//--- Put pivot in the right location.
|
||||
Swap(left,(hi-1));
|
||||
return (left);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Heap sorting algorithm. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::Heapsort(const int lo,const int hi)
|
||||
{
|
||||
int n=hi-lo+1;
|
||||
for(int i=n/2; i>=1; i=i-1)
|
||||
{
|
||||
DownHeap(i,n,lo);
|
||||
}
|
||||
for(int i=n; i>1; i=i-1)
|
||||
{
|
||||
Swap(lo,lo+i-1);
|
||||
DownHeap(1,i-1,lo);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Downheap function for heapsort. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::DownHeap(int i,const int n,const int lo)
|
||||
{
|
||||
bool f=ArraySize(items)!=0;
|
||||
TKey d=keys[lo+i-1];
|
||||
TItem dt=f ? (TItem)items[lo+i-1] : (TItem)NULL;
|
||||
|
||||
while(i<=n/2)
|
||||
{
|
||||
int child=2*i;
|
||||
if(child<n && comparer.Compare(keys[lo+child-1],keys[lo+child])<0)
|
||||
child++;
|
||||
if(!(comparer.Compare(d,keys[lo+child-1])<0))
|
||||
break;
|
||||
keys[lo+i-1]=keys[lo+child-1];
|
||||
if(f)
|
||||
items[lo+i-1]=items[lo+child-1];
|
||||
i=child;
|
||||
}
|
||||
keys[lo+i-1]=d;
|
||||
if(f)
|
||||
items[lo+i-1]=dt;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,81 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| PrimeGenerator.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CPrimeGenrator. |
|
||||
//| Usage: Used to generate prime numbers. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CPrimeGenerator
|
||||
{
|
||||
private:
|
||||
const static int s_primes[]; // table of prime numbers
|
||||
const static int s_hash_prime;
|
||||
|
||||
public:
|
||||
static bool IsPrime(const int candidate);
|
||||
static int GetPrime(const int min);
|
||||
static int ExpandPrime(const int old_size);
|
||||
};
|
||||
const static int CPrimeGenerator::s_primes[]=
|
||||
{
|
||||
3,7,11,17,23,29,37,47,59,71,89,107,131,163,197,239,293,353,431,521,631,761,919,
|
||||
1103,1327,1597,1931,2333,2801,3371,4049,4861,5839,7013,8419,10103,12143,14591,
|
||||
17519,21023,25229,30293,36353,43627,52361,62851,75431,90523,108631,130363,156437,
|
||||
187751,225307,270371,324449,389357,467237,560689,672827,807403,968897,1162687,1395263,
|
||||
1674319,2009191,2411033,2893249,3471899,4166287,4999559,5999471,7199369,8332579,
|
||||
9999161,11998949,14398753,16665163,19998337,23997907,28797523,33330329,39996683,
|
||||
47995853,57595063,66660701,79993367,95991737,115190149,133321403,159986773,191983481,
|
||||
230380307,266642809,319973567,383966977,460760623,533285671,639947149,767933981,
|
||||
921521257,1066571383,1279894313,1535867969,1843042529,2133142771
|
||||
};
|
||||
const static int CPrimeGenerator::s_hash_prime=101;
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a value is prime. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPrimeGenerator::IsPrime(const int candidate)
|
||||
{
|
||||
if((candidate&1)!=0)
|
||||
{
|
||||
int limit=(int)MathSqrt(candidate);
|
||||
//--- check value is prime
|
||||
for(int divisor=3; divisor<=limit; divisor+=2)
|
||||
if((candidate%divisor)==0)
|
||||
return(false);
|
||||
return(true);
|
||||
}
|
||||
return(candidate==2);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Fast generator of prime value. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CPrimeGenerator::GetPrime(const int min)
|
||||
{
|
||||
//--- a typical resize algorithm would pick the smallest prime number in this array
|
||||
//--- that is larger than twice the previous capacity.
|
||||
//--- get next prime value from table
|
||||
for(int i=0; i<ArraySize(s_primes); i++)
|
||||
{
|
||||
int prime=s_primes[i];
|
||||
if(prime>=min)
|
||||
return(prime);
|
||||
}
|
||||
//--- outside of our predefined table
|
||||
for(int i=(min|1); i<=INT_MAX;i+=2)
|
||||
{
|
||||
if(IsPrime(i) && ((i-1)%s_hash_prime!=0))
|
||||
return(i);
|
||||
}
|
||||
return(min);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Generate a new prime value greater than old_size. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CPrimeGenerator::ExpandPrime(const int old_size)
|
||||
{
|
||||
if(old_size>=INT_MAX/2)
|
||||
return(INT_MAX);
|
||||
return(GetPrime(old_size*2));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,563 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| LinkedList.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\ICollection.mqh>
|
||||
#include <Generic\Internal\EqualFunction.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CLinkedListNode<T>. |
|
||||
//| Usage: Represents a node of linked list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CLinkedListNode
|
||||
{
|
||||
protected:
|
||||
CLinkedList<T>*m_list;
|
||||
CLinkedListNode<T>*m_next;
|
||||
CLinkedListNode<T>*m_prev;
|
||||
T m_item;
|
||||
|
||||
public:
|
||||
CLinkedListNode(T value): m_item(value) { }
|
||||
CLinkedListNode(CLinkedList<T>*list,T value): m_list(list),m_item(value) { }
|
||||
~CLinkedListNode(void) { }
|
||||
//--- methods of access to protected data
|
||||
CLinkedList<T>* List(void) { return(m_list); }
|
||||
void List(CLinkedList<T>*value) { m_list=value; }
|
||||
CLinkedListNode<T>*Next(void) { return(m_next); }
|
||||
void Next(CLinkedListNode<T>*value) { m_next=value; }
|
||||
CLinkedListNode<T>*Previous(void) { return(m_prev); }
|
||||
void Previous(CLinkedListNode<T>*value) { m_prev=value; }
|
||||
T Value(void) { return(m_item); }
|
||||
void Value(T value) { m_item=value; }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CLinkedList<T>. |
|
||||
//| Usage: Represents a doubly linked list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CLinkedList: public ICollection<T>
|
||||
{
|
||||
protected:
|
||||
CLinkedListNode<T>*m_head;
|
||||
int m_count;
|
||||
|
||||
public:
|
||||
CLinkedList(void);
|
||||
CLinkedList(ICollection<T>*collection);
|
||||
CLinkedList(T &array[]);
|
||||
~CLinkedList(void);
|
||||
//--- methods of filling data
|
||||
bool Add(T value);
|
||||
CLinkedListNode<T>*AddAfter(CLinkedListNode<T>*node,T value);
|
||||
bool AddAfter(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node);
|
||||
CLinkedListNode<T>*AddBefore(CLinkedListNode<T>*node,T value);
|
||||
bool AddBefore(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node);
|
||||
CLinkedListNode<T>*AddFirst(T value);
|
||||
bool AddFirst(CLinkedListNode<T>*node);
|
||||
CLinkedListNode<T>*AddLast(T value);
|
||||
bool AddLast(CLinkedListNode<T>*node);
|
||||
//--- methods of access to protected data
|
||||
int Count(void);
|
||||
CLinkedListNode<T>*Head(void) {return(m_head);}
|
||||
CLinkedListNode<T>*First(void);
|
||||
CLinkedListNode<T>*Last(void);
|
||||
bool Contains(T item);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(T &dst_array[],const int dst_start=0);
|
||||
//--- methods of cleaning and deleting
|
||||
void Clear(void);
|
||||
bool Remove(T item);
|
||||
bool Remove(CLinkedListNode<T>*node);
|
||||
bool RemoveFirst(void);
|
||||
bool RemoveLast(void);
|
||||
//--- method for searching
|
||||
CLinkedListNode<T>*Find(T value);
|
||||
CLinkedListNode<T>*FindLast(T value);
|
||||
|
||||
private:
|
||||
bool ValidateNode(CLinkedListNode<T>*node);
|
||||
bool ValidateNewNode(CLinkedListNode<T>*node);
|
||||
void InternalInsertNodeBefore(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node);
|
||||
void InternalInsertNodeToEmptyList(CLinkedListNode<T>*new_node);
|
||||
void InternalRemoveNode(CLinkedListNode<T>*node);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CLinkedList<T> class that is |
|
||||
//| empty. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedList::CLinkedList(void): m_count(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CLinkedList<T> class that |
|
||||
//| contains elements copied from the specified array and has |
|
||||
//| sufficient capacity to accommodate the number of elements copied.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedList::CLinkedList(T &array[]): m_count(0)
|
||||
{
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
AddLast(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CLinkedList<T> class that |
|
||||
//| contains elements copied from the specified collection and has |
|
||||
//| sufficient capacity to accommodate the number of elements copied.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedList::CLinkedList(ICollection<T>*collection): m_count(0)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)!=POINTER_INVALID)
|
||||
{
|
||||
T array[];
|
||||
int size=collection.CopyTo(array,0);
|
||||
for(int i=0; i<size; i++)
|
||||
AddLast(array[i]);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedList::~CLinkedList(void)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds an value to the end of the list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::Add(T value)
|
||||
{
|
||||
return(CheckPointer(AddLast(value))!=POINTER_INVALID);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds a new node containing the specified value after the |
|
||||
//| specified existing node in the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::AddAfter(CLinkedListNode<T>*node,T value)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNode(node))
|
||||
return(NULL);
|
||||
//--- create new node
|
||||
CLinkedListNode<T>*result=new CLinkedListNode<T>(node.List(),value);
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(node.Next(),result);
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified new node after the specified existing node in |
|
||||
//| the LinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::AddAfter(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNode(node))
|
||||
return(false);
|
||||
//--- check new node
|
||||
if(!ValidateNewNode(new_node))
|
||||
return(false);
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(node.Next(),new_node);
|
||||
//--- set the current list as list for new node
|
||||
new_node.List(GetPointer(this));
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds a new node containing the specified value before the |
|
||||
//| specified existing node in the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::AddBefore(CLinkedListNode<T>*node,T value)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNode(node))
|
||||
return(NULL);
|
||||
//--- create new node
|
||||
CLinkedListNode<T>*result=new CLinkedListNode<T>(node.List(),value);
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(node,result);
|
||||
if(node==m_head)
|
||||
m_head=result;
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified new node before the specified existing node in|
|
||||
//| the LinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::AddBefore(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNode(node))
|
||||
return(false);
|
||||
//--- check new node
|
||||
if(!ValidateNewNode(new_node))
|
||||
return(false);
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(node,new_node);
|
||||
//--- set the current list as list for new node
|
||||
new_node.List(GetPointer(this));
|
||||
if(node==m_head)
|
||||
m_head=new_node;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds a new node containing the specified value at the start of |
|
||||
//| the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::AddFirst(T value)
|
||||
{
|
||||
//--- create new node
|
||||
CLinkedListNode<T>*node=new CLinkedListNode<T>(GetPointer(this),value);
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
{
|
||||
//--- insert node to the empty list
|
||||
InternalInsertNodeToEmptyList(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(m_head,node);
|
||||
m_head=node;
|
||||
}
|
||||
return(node);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified new node at the start of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::AddFirst(CLinkedListNode<T>*node)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNewNode(node))
|
||||
return(false);
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
{
|
||||
//--- insert node to the empty list
|
||||
InternalInsertNodeToEmptyList(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(m_head,node);
|
||||
m_head=node;
|
||||
}
|
||||
//--- set the current list as list for node
|
||||
node.List(GetPointer(this));
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds a new node containing the specified value at the end of the |
|
||||
//| CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::AddLast(T value)
|
||||
{
|
||||
//--- create new node
|
||||
CLinkedListNode<T>*node=new CLinkedListNode<T>(GetPointer(this),value);
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
{
|
||||
//--- insert node to the empty list
|
||||
InternalInsertNodeToEmptyList(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(m_head,node);
|
||||
}
|
||||
return(node);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified new node at the end of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::AddLast(CLinkedListNode<T>*node)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNewNode(node))
|
||||
return(false);
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
{
|
||||
//--- insert node to the empty list
|
||||
InternalInsertNodeToEmptyList(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(m_head,node);
|
||||
}
|
||||
//--- set the current list as list for node
|
||||
node.List(GetPointer(this));
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether an element is in the linked list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CLinkedList::Count(void)
|
||||
{
|
||||
return(m_count);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets the first node of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::First(void)
|
||||
{
|
||||
return(m_head);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets the last node of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::Last(void)
|
||||
{
|
||||
return(CheckPointer(m_head)!=POINTER_INVALID ? m_head.Previous() : NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a value is in the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::Contains(T item)
|
||||
{
|
||||
return(CheckPointer(Find(item))!=POINTER_INVALID);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the linkedlist to a compatible |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CLinkedList::CopyTo(T &dst_array[],const int dst_start=0)
|
||||
{
|
||||
//--- resize array
|
||||
if(dst_start+m_count>ArraySize(dst_array))
|
||||
ArrayResize(dst_array,dst_start+m_count);
|
||||
//--- check start index
|
||||
if(dst_start>ArraySize(dst_array))
|
||||
return(0);
|
||||
//--- start copy
|
||||
CLinkedListNode<T>*node=m_head;
|
||||
if(CheckPointer(node)!=POINTER_INVALID)
|
||||
{
|
||||
int dst_index=dst_start;
|
||||
do
|
||||
{
|
||||
dst_array[dst_index++]=node.Value();
|
||||
node=node.Next();
|
||||
}
|
||||
while(dst_index<ArraySize(dst_array) && node!=m_head);
|
||||
return(dst_index-dst_start);
|
||||
}
|
||||
//--- list is empty
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all nodes from the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CLinkedList::Clear(void)
|
||||
{
|
||||
//--- check count
|
||||
if(m_count>0)
|
||||
{
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)!=POINTER_INVALID)
|
||||
{
|
||||
while(m_head.Next()!=m_head)
|
||||
{
|
||||
CLinkedListNode<T>*node=m_head.Next();
|
||||
m_head.Next(node.Next());
|
||||
delete node;
|
||||
}
|
||||
delete m_head;
|
||||
}
|
||||
//--- reset count
|
||||
m_count=0;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the first occurrence of the specified value from the |
|
||||
//| CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::Remove(T item)
|
||||
{
|
||||
//--- find node with specified value
|
||||
CLinkedListNode<T>*node=Find(item);
|
||||
if(CheckPointer(node)!=POINTER_INVALID)
|
||||
{
|
||||
//--- remove node
|
||||
InternalRemoveNode(node);
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the specified node from the LinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::Remove(CLinkedListNode<T>*node)
|
||||
{
|
||||
//--- check node
|
||||
if(ValidateNode(node))
|
||||
{
|
||||
//--- remove node
|
||||
InternalRemoveNode(node);
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the node at the start of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::RemoveFirst(void)
|
||||
{
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- remove head node
|
||||
InternalRemoveNode(m_head);
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the node at the end of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::RemoveLast(void)
|
||||
{
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- remove last node
|
||||
InternalRemoveNode(m_head.Previous());
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Finds the first node that contains the specified value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::Find(T value)
|
||||
{
|
||||
CLinkedListNode<T>*node=m_head;
|
||||
//--- start search specified value in the list
|
||||
if(CheckPointer(node)!=POINTER_INVALID)
|
||||
{
|
||||
do
|
||||
{
|
||||
//--- use default equals function
|
||||
if(::Equals(node.Value(),value))
|
||||
return(node);
|
||||
node=node.Next();
|
||||
}
|
||||
while(node!=m_head);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Finds the last node that contains the specified value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::FindLast(T value)
|
||||
{
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
return(NULL);
|
||||
//--- get last node
|
||||
CLinkedListNode<T> *last = m_head.Previous();
|
||||
CLinkedListNode<T> *node = last;
|
||||
//--- start search from the end of the list
|
||||
if(node!=NULL)
|
||||
{
|
||||
do
|
||||
{
|
||||
//--- use default equals function
|
||||
if(::Equals(node.Value(),value))
|
||||
return(node);
|
||||
node=node.Previous();
|
||||
}
|
||||
while(node!=last);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation of node on not null and belongs in the current list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::ValidateNode(CLinkedListNode<T>*node)
|
||||
{
|
||||
return(CheckPointer(node)!=POINTER_INVALID && node.List()==GetPointer(this));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation of new node on not null. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::ValidateNewNode(CLinkedListNode<T>*node)
|
||||
{
|
||||
return(CheckPointer(node)!=POINTER_INVALID && node.List()==NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Insert node before the specified node. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CLinkedList::InternalInsertNodeBefore(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node)
|
||||
{
|
||||
//--- set node befor the specified node
|
||||
new_node.Next(node);
|
||||
new_node.Previous(node.Previous());
|
||||
node.Previous().Next(new_node);
|
||||
node.Previous(new_node);
|
||||
//--- increment count
|
||||
m_count++;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add first node to the list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CLinkedList::InternalInsertNodeToEmptyList(CLinkedListNode<T>*new_node)
|
||||
{
|
||||
//--- set node as head of the list
|
||||
new_node.Next(new_node);
|
||||
new_node.Previous(new_node);
|
||||
m_head=new_node;
|
||||
//--- increment count
|
||||
m_count++;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Remove specified node from the list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CLinkedList::InternalRemoveNode(CLinkedListNode<T>*node)
|
||||
{
|
||||
//--- check node
|
||||
if(node.Next()==node)
|
||||
{
|
||||
//--- resets the head of the list
|
||||
m_head=NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- detach node from the list
|
||||
node.Next().Previous(node.Previous());
|
||||
node.Previous().Next(node.Next());
|
||||
if(m_head==node)
|
||||
m_head=node.Next();
|
||||
}
|
||||
//--- decrement count and delete node
|
||||
m_count--;
|
||||
delete node;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,341 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SortedMap.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IMap.mqh>
|
||||
#include <Generic\Interfaces\IComparer.mqh>
|
||||
#include <Generic\Internal\DefaultComparer.mqh>
|
||||
#include <Generic\Internal\CompareFunction.mqh>
|
||||
#include "HashMap.mqh"
|
||||
#include "SortedSet.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSortedMap<TKey, TValue>. |
|
||||
//| Usage: Represents a collection of key/value pairs that are sorted|
|
||||
//| on the key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
class CSortedMap: public IMap<TKey,TValue>
|
||||
{
|
||||
protected:
|
||||
CRedBlackTree<CKeyValuePair<TKey,TValue>*>*m_tree;
|
||||
IComparer<TKey>*m_comparer;
|
||||
bool m_delete_comparer;
|
||||
|
||||
public:
|
||||
CSortedMap(void);
|
||||
CSortedMap(IComparer<TKey>*comparer);
|
||||
CSortedMap(IMap<TKey,TValue>*map);
|
||||
CSortedMap(IMap<TKey,TValue>*map,IComparer<TKey>*comparer);
|
||||
~CSortedMap(void);
|
||||
//--- methods of filling data
|
||||
bool Add(CKeyValuePair<TKey,TValue>*value) { return m_tree.Add(value); }
|
||||
bool Add(TKey key,TValue value);
|
||||
//--- methods of access to protected data
|
||||
int Count(void) { return m_tree.Count(); }
|
||||
bool Contains(CKeyValuePair<TKey,TValue>*item) { return m_tree.Contains(item); }
|
||||
bool Contains(TKey key,TValue value);
|
||||
bool ContainsKey(TKey key);
|
||||
bool ContainsValue(TValue value);
|
||||
IComparer<TKey> *Comparer(void) const { return(m_comparer); }
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(CKeyValuePair<TKey,TValue>*&dst_array[],const int dst_start=0);
|
||||
int CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0);
|
||||
//--- methods of cleaning and deleting
|
||||
void Clear(void);
|
||||
bool Remove(CKeyValuePair<TKey,TValue>*item) { return m_tree.Remove(item); }
|
||||
bool Remove(TKey key);
|
||||
//--- method of access to the data
|
||||
bool TryGetValue(TKey key,TValue &value);
|
||||
bool TrySetValue(TKey key,TValue value);
|
||||
|
||||
private:
|
||||
static void ClearNodes(CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedMap<TKey,TValue> class |
|
||||
//| that is empty, has the default initial capacity, and uses the |
|
||||
//| default comparer for the key type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CSortedMap::CSortedMap(void)
|
||||
{
|
||||
//--- use default comaprer
|
||||
m_comparer=new CDefaultComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
m_tree=new CRedBlackTree<CKeyValuePair<TKey,TValue>*>(new CKeyValuePairComparer<TKey,TValue>(m_comparer));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedMap<TKey,TValue> class |
|
||||
//| that is empty, has the default initial capacity, and uses the |
|
||||
//| specified IComparer<TKey>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CSortedMap::CSortedMap(IComparer<TKey>*comparer)
|
||||
{
|
||||
//--- check comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default comaprer
|
||||
m_comparer=new CDefaultComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
m_tree=new CRedBlackTree<CKeyValuePair<TKey,TValue>*>(new CKeyValuePairComparer<TKey,TValue>(m_comparer));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedMap<TKey,TValue> class |
|
||||
//| that contains elements copied from the specified |
|
||||
//| IMap<TKey,TValue> and uses the default comparer for the key type.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CSortedMap::CSortedMap(IMap<TKey,TValue>*map)
|
||||
{
|
||||
//--- use default comaprer
|
||||
m_comparer=new CDefaultComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
m_tree=new CRedBlackTree<CKeyValuePair<TKey,TValue>*>(map,new CKeyValuePairComparer<TKey,TValue>(m_comparer));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedMap<TKey,TValue> class |
|
||||
//| that contains elements copied from the specified |
|
||||
//| IMap<TKey,TValue> and uses the specified IComparer<TKey>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CSortedMap::CSortedMap(IMap<TKey,TValue>*map,IComparer<TKey>*comparer)
|
||||
{
|
||||
//--- check comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default comaprer
|
||||
m_comparer=new CDefaultComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
m_tree=new CRedBlackTree<CKeyValuePair<TKey,TValue>*>(map,new CKeyValuePairComparer<TKey,TValue>(m_comparer));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CSortedMap::~CSortedMap(void)
|
||||
{
|
||||
//--- delete comparer
|
||||
if(m_delete_comparer)
|
||||
delete m_comparer;
|
||||
//--- delete tree comparer
|
||||
delete m_tree.Comparer();
|
||||
//--- delete nodes values
|
||||
ClearNodes(m_tree.Root());
|
||||
//--- delete tree and nodes
|
||||
delete m_tree;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Walk all nodes of tree and delete their value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
static void CSortedMap::ClearNodes(CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node)
|
||||
{
|
||||
//--- check node
|
||||
if(CheckPointer(node)==POINTER_INVALID)
|
||||
return;
|
||||
//--- walk of a right subtree
|
||||
if(!node.Right().IsLeaf())
|
||||
ClearNodes(node.Right());
|
||||
//--- delete value
|
||||
delete node.Value();
|
||||
//--- walk of a left subtree
|
||||
if(!node.Left().IsLeaf())
|
||||
ClearNodes(node.Left());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified key and value to the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CSortedMap::Add(TKey key,TValue value)
|
||||
{
|
||||
//--- create pair
|
||||
CKeyValuePair<TKey,TValue>*pair=new CKeyValuePair<TKey,TValue>(key,value);
|
||||
//--- add pair to tree
|
||||
bool success=m_tree.Add(pair);
|
||||
//--- if addition was not successful delte pair
|
||||
if(!success)
|
||||
delete pair;
|
||||
return(success);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified key with value.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CSortedMap::Contains(TKey key,TValue value)
|
||||
{
|
||||
//--- find node with specified key
|
||||
CKeyValuePair<TKey,TValue>pair(key,NULL);
|
||||
CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node=m_tree.Find(GetPointer(pair));
|
||||
//--- create value comparer
|
||||
CDefaultEqualityComparer<TValue>comaprer;
|
||||
//--- determine whether the finding node contains specified value
|
||||
if(CheckPointer(node)!=POINTER_INVALID && comaprer.Equals(value,node.Value().Value()))
|
||||
return(true);
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CSortedMap::ContainsKey(TKey key)
|
||||
{
|
||||
//--- crete pair
|
||||
CKeyValuePair<TKey,TValue>pair(key,NULL);
|
||||
//--- determines whether the tree contains the pair.
|
||||
return m_tree.Contains(GetPointer(pair));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CSortedMap::ContainsValue(TValue value)
|
||||
{
|
||||
//--- copy all pairs in array
|
||||
CKeyValuePair<TKey,TValue>*array[];
|
||||
int count=m_tree.CopyTo(array);
|
||||
//--- create value comparer
|
||||
CDefaultEqualityComparer<TValue>comaprer;
|
||||
//--- determines whether the array contains the specified value
|
||||
for(int i=0; i<count; i++)
|
||||
if(comaprer.Equals(value,array[i].Value()))
|
||||
return(true);
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the map to a compatible |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
int CSortedMap::CopyTo(CKeyValuePair<TKey,TValue>*&dst_array[],const int dst_start=0)
|
||||
{
|
||||
int result=m_tree.CopyTo(dst_array,dst_start);
|
||||
if(result>0)
|
||||
{
|
||||
//--- create clones for each pair
|
||||
for(int i=0; i<result; i++)
|
||||
dst_array[dst_start+i]=dst_array[dst_start+i].Clone();
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the map to a compatible |
|
||||
//| one-dimensionals keys and values arrays. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
int CSortedMap::CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0)
|
||||
{
|
||||
//--- create array and copy all values from tree to there
|
||||
CKeyValuePair<TKey,TValue>*array[];
|
||||
int count=m_tree.CopyTo(array);
|
||||
//--- check real cout
|
||||
if(count>0)
|
||||
{
|
||||
//--- resize keys array
|
||||
if(dst_start+count>ArraySize(dst_keys))
|
||||
ArrayResize(dst_keys,dst_start+count);
|
||||
//--- resize values array
|
||||
if(dst_start+count>ArraySize(dst_values))
|
||||
ArrayResize(dst_values,MathMin(ArraySize(dst_keys),dst_start+count));
|
||||
//--- start copy
|
||||
int index=0;
|
||||
while(index<count && dst_start+index<ArraySize(dst_keys) && dst_start+index<ArraySize(dst_values))
|
||||
{
|
||||
dst_keys[dst_start+index]=array[index].Key();
|
||||
dst_values[dst_start+index]=array[index].Value();
|
||||
index++;
|
||||
}
|
||||
return(index);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Clear and delete all values from map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
void CSortedMap::Clear(void)
|
||||
{
|
||||
//--- check count
|
||||
if(m_tree.Count()>0)
|
||||
{
|
||||
//--- delete nodes values
|
||||
ClearNodes(m_tree.Root());
|
||||
//--- claer th tree
|
||||
m_tree.Clear();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the value with the specified key from the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CSortedMap::Remove(TKey key)
|
||||
{
|
||||
//--- create pair with specified key
|
||||
CKeyValuePair<TKey,TValue>pair(key,NULL);
|
||||
//--- find node
|
||||
CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node=m_tree.Find(GetPointer(pair));
|
||||
//--- check node
|
||||
if(CheckPointer(node)!=POINTER_INVALID)
|
||||
{
|
||||
CKeyValuePair<TKey,TValue>*real_pair=node.Value();
|
||||
//--- remove node from tree
|
||||
if(m_tree.Remove(node))
|
||||
{
|
||||
//--- check and delete node value
|
||||
if(CheckPointer(real_pair)==POINTER_DYNAMIC)
|
||||
delete real_pair;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets the value associated with the specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CSortedMap::TryGetValue(TKey key,TValue &value)
|
||||
{
|
||||
//--- create pair with specified key
|
||||
CKeyValuePair<TKey,TValue>pair(key,NULL);
|
||||
//--- find node with specified pair in the tree
|
||||
CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node=m_tree.Find(GetPointer(pair));
|
||||
//--- check node
|
||||
if(CheckPointer(node)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- get value
|
||||
value=node.Value().Value();
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets the value associated with the specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CSortedMap::TrySetValue(TKey key,TValue value)
|
||||
{
|
||||
//--- create pair with specified key
|
||||
CKeyValuePair<TKey,TValue>pair(key,NULL);
|
||||
//--- find node with specified pair in the tree
|
||||
CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node=m_tree.Find(GetPointer(pair));
|
||||
//--- check node
|
||||
if(CheckPointer(node)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- set value
|
||||
node.Value().Value(value);
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,673 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SortedList.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\ISet.mqh>
|
||||
#include <Generic\Internal\Introsort.mqh>
|
||||
#include "RedBlackTree.mqh"
|
||||
#include "HashSet.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSortedSet<T>. |
|
||||
//| Usage: Represents a collection of objects that is maintained in |
|
||||
//| sorted order. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CSortedSet: public ISet<T>
|
||||
{
|
||||
protected:
|
||||
CRedBlackTree<T>*m_tree;
|
||||
|
||||
public:
|
||||
CSortedSet(void);
|
||||
CSortedSet(IComparer<T>*comparer);
|
||||
CSortedSet(ICollection<T>*collection);
|
||||
CSortedSet(ICollection<T>*collection,IComparer<T>*comparer);
|
||||
CSortedSet(T &array[]);
|
||||
CSortedSet(T &array[],IComparer<T>*comparer);
|
||||
~CSortedSet(void);
|
||||
//--- methods of filling data
|
||||
bool Add(T value) { return(m_tree.Add(value)); }
|
||||
//--- methods of access to protected data
|
||||
int Count(void) { return(m_tree.Count()); }
|
||||
bool Contains(T item) { return(m_tree.Contains(item)); }
|
||||
IComparer<T> *Comparer(void) const { return(m_tree.Comparer()); }
|
||||
bool TryGetMin(T &min) { return(m_tree.TryGetMin(min)); }
|
||||
bool TryGetMax(T &max) { return(m_tree.TryGetMax(max)); }
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(T &dst_array[],const int dst_start=0);
|
||||
//--- methods of cleaning and deleting
|
||||
void Clear(void) { m_tree.Clear(); }
|
||||
bool Remove(T item) { return(m_tree.Remove(item)); }
|
||||
//--- methods of changing sets
|
||||
void ExceptWith(ICollection<T>*collection);
|
||||
void ExceptWith(T &array[]);
|
||||
void IntersectWith(ICollection<T>*collection);
|
||||
void IntersectWith(T &array[]);
|
||||
void SymmetricExceptWith(ICollection<T>*collection);
|
||||
void SymmetricExceptWith(T &array[]);
|
||||
void UnionWith(ICollection<T>*collection);
|
||||
void UnionWith(T &array[]);
|
||||
//--- methods for determining the relationship between sets
|
||||
bool IsProperSubsetOf(ICollection<T>*collection);
|
||||
bool IsProperSubsetOf(T &array[]);
|
||||
bool IsProperSupersetOf(ICollection<T>*collection);
|
||||
bool IsProperSupersetOf(T &array[]);
|
||||
bool IsSubsetOf(ICollection<T>*collection);
|
||||
bool IsSubsetOf(T &array[]);
|
||||
bool IsSupersetOf(ICollection<T>*collection);
|
||||
bool IsSupersetOf(T &array[]);
|
||||
bool Overlaps(ICollection<T>*collection);
|
||||
bool Overlaps(T &array[]);
|
||||
bool SetEquals(ICollection<T>*collection);
|
||||
bool SetEquals(T &array[]);
|
||||
//--- methods for working with an ordered set
|
||||
bool GetViewBetween(T &array[],T lower_value,T upper_value);
|
||||
bool GetReverse(T &array[]);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that is |
|
||||
//| empty and uses the default equality comparer for the set type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(void)
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that is |
|
||||
//| empty and uses the specified equality comparer for the set type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(IComparer<T>*comparer)
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>(comparer);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that uses |
|
||||
//| the default equality comparer for the set type, contains elements|
|
||||
//| copied from the specified collection, and has sufficient capacity|
|
||||
//| to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(ICollection<T>*collection)
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>(collection);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that uses |
|
||||
//| the specified equality comparer for the set type, contains |
|
||||
//| elements copied from the specified collection, and has sufficient|
|
||||
//| capacity to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(ICollection<T>*collection,IComparer<T>*comparer)
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>(collection,comparer);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that uses |
|
||||
//| the default equality comparer for the set type, contains |
|
||||
//| elements copied from the specified array, and has sufficient |
|
||||
//| capacity to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(T &array[])
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>(array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that uses |
|
||||
//| the specified equality comparer for the set type, contains |
|
||||
//| elements copied from the specified array, and has sufficient |
|
||||
//| capacity to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(T &array[],IComparer<T>*comparer)
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>(array,comparer);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::~CSortedSet(void)
|
||||
{
|
||||
delete m_tree;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the set to a compatible |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CSortedSet::CopyTo(T &dst_array[],const int dst_start=0)
|
||||
{
|
||||
return(m_tree.CopyTo(dst_array, dst_start));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all elements in the specified collection from the current|
|
||||
//| set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::ExceptWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return;
|
||||
//--- special case if collection is this
|
||||
//--- a set minus itself is the empty set
|
||||
if(collection==GetPointer(this))
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- copy collection to array
|
||||
T array[];
|
||||
int size=collection.CopyTo(array);
|
||||
//--- find max and min value
|
||||
T max;
|
||||
T min;
|
||||
//--- get comaprer
|
||||
IComparer<T>*comparer=Comparer();
|
||||
if(!m_tree.TryGetMax(max))
|
||||
return;
|
||||
if(!m_tree.TryGetMin(min))
|
||||
return;
|
||||
//--- remove elements
|
||||
for(int i=0; i<size; i++)
|
||||
{
|
||||
T item=array[i];
|
||||
if(!(comparer.Compare(item,min)<0 || comparer.Compare(item,max)>0) && Contains(item))
|
||||
m_tree.Remove(item);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all elements in the specified array from the current set.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::ExceptWith(T &array[])
|
||||
{
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return;
|
||||
//--- get array size
|
||||
int size=ArraySize(array);
|
||||
//--- find max and min value
|
||||
T max;
|
||||
T min;
|
||||
//--- get comparer
|
||||
IComparer<T>*comparer=Comparer();
|
||||
if(!m_tree.TryGetMax(max))
|
||||
return;
|
||||
if(!m_tree.TryGetMin(min))
|
||||
return;
|
||||
//--- remove elements
|
||||
for(int i=0; i<size; i++)
|
||||
{
|
||||
T item=array[i];
|
||||
if(!(comparer.Compare(item,min)<0 || comparer.Compare(item,max)>0) && Contains(item))
|
||||
m_tree.Remove(item);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present in that object and in the specified collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::IntersectWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return;
|
||||
//--- special case if collection is this
|
||||
//--- a set minus itself is the empty set
|
||||
if(collection==GetPointer(this))
|
||||
return;
|
||||
//--- copy collection to array
|
||||
T array[];
|
||||
int size=collection.CopyTo(array);
|
||||
//--- create emty tree
|
||||
CRedBlackTree<T>*tree=new CRedBlackTree<T>();
|
||||
//--- store values conatin in tree and array
|
||||
for(int i=0; i<size; i++)
|
||||
if(m_tree.Contains(array[i]))
|
||||
tree.Add(array[i]);
|
||||
//--- overwrite tree
|
||||
delete m_tree;
|
||||
m_tree=tree;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present in that object and in the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::IntersectWith(T &array[])
|
||||
{
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return;
|
||||
//--- get array size
|
||||
int size=ArraySize(array);
|
||||
//--- create emty tree
|
||||
CRedBlackTree<T>*tree=new CRedBlackTree<T>();
|
||||
//--- store values conatin in tree and array
|
||||
for(int i=0; i<size; i++)
|
||||
if(m_tree.Contains(array[i]))
|
||||
tree.Add(array[i]);
|
||||
//--- overwrite tree
|
||||
delete m_tree;
|
||||
m_tree=tree;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present either in that set or in the specified collection, but |
|
||||
//| not both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::SymmetricExceptWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- check collection count
|
||||
if(collection.Count()==0)
|
||||
return;
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
{
|
||||
UnionWith(collection);
|
||||
return;
|
||||
}
|
||||
//--- special case if collection is this
|
||||
//--- a set minus itself is the empty set
|
||||
if(collection==GetPointer(this))
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- copy colleaction to array
|
||||
T array[];
|
||||
int size=collection.CopyTo(array);
|
||||
//--- get comparer
|
||||
IComparer<T>*comparer=m_tree.Comparer();
|
||||
//--- sort array
|
||||
Introsort<T,T>sort;
|
||||
ArrayCopy(sort.keys,array);
|
||||
sort.comparer=comparer;
|
||||
sort.Sort(0, size);
|
||||
ArrayCopy(array,sort.keys);
|
||||
//--- modify tree
|
||||
T last=array[0];
|
||||
for(int i=0; i<size; i++)
|
||||
{
|
||||
while(i<size && i!=0 && comparer.Compare(array[i],last)==0)
|
||||
i++;
|
||||
if(i>=size)
|
||||
break;
|
||||
|
||||
if(m_tree.Contains(array[i]))
|
||||
m_tree.Remove(array[i]);
|
||||
else
|
||||
m_tree.Add(array[i]);
|
||||
|
||||
last=array[i];
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present either in that set or in the specified array, but not |
|
||||
//| both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::SymmetricExceptWith(T &array[])
|
||||
{
|
||||
//--- check array size
|
||||
if(ArraySize(array)==0)
|
||||
return;
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
{
|
||||
UnionWith(array);
|
||||
return;
|
||||
}
|
||||
//--- get size
|
||||
int size=ArraySize(array);
|
||||
//--- get comparer
|
||||
IComparer<T>*comparer=m_tree.Comparer();
|
||||
//--- sort array
|
||||
Introsort<T,T>sort;
|
||||
ArrayCopy(sort.keys,array);
|
||||
sort.comparer=comparer;
|
||||
sort.Sort(0, size);
|
||||
ArrayReverse(sort.keys,0,ArraySize(sort.keys));
|
||||
//--- modify tree
|
||||
T last=sort.keys[0];
|
||||
for(int i=0; i<size; i++)
|
||||
{
|
||||
while(i<size && i!=0 && comparer.Compare(sort.keys[i],last)==0)
|
||||
i++;
|
||||
if(i>=size)
|
||||
break;
|
||||
|
||||
if(m_tree.Contains(sort.keys[i]))
|
||||
m_tree.Remove(sort.keys[i]);
|
||||
else
|
||||
m_tree.Add(sort.keys[i]);
|
||||
|
||||
last=sort.keys[i];
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain all elements that are present|
|
||||
//| in itself, the specified collection, or both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::UnionWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- copy all elements from collecton to array
|
||||
T array[];
|
||||
int size=collection.CopyTo(array);
|
||||
//--- add all elemets from array to set
|
||||
for(int i=0; i<size; i++)
|
||||
m_tree.Add(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain all elements that are present|
|
||||
//| in itself, the specified array, or both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::UnionWith(T &array[])
|
||||
{
|
||||
//--- get array size
|
||||
int size=ArraySize(array);
|
||||
//--- add all elemets from array to set
|
||||
for(int i=0; i<size; i++)
|
||||
m_tree.Add(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper subset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsProperSubsetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(collection.Count() > 0);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return(ptr_set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return(set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper subset of the specified |
|
||||
//| array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsProperSubsetOf(T &array[])
|
||||
{
|
||||
if(m_tree.Count()==0)
|
||||
return(ArraySize(array) > 0);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
if(m_tree.Count()>=set.Count())
|
||||
return(false);
|
||||
return(set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper superset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsProperSupersetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_tree.Count()>0);
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(false);
|
||||
//--- check collection count
|
||||
if(collection.Count()==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return(ptr_set.IsProperSubsetOf(m_tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return(set.IsProperSubsetOf(m_tree));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper superset of the specified |
|
||||
//| array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsProperSupersetOf(T &array[])
|
||||
{
|
||||
if(m_tree.Count()==0)
|
||||
return(false);
|
||||
if(ArraySize(array)==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return(set.IsProperSubsetOf(m_tree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a subset of the specified collection.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsSubsetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- cehck collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_tree.Count()==0);
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)==POINTER_DYNAMIC)
|
||||
{
|
||||
return(ptr_set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return(set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a subset of the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsSubsetOf(T &array[])
|
||||
{
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
if(m_tree.Count()>set.Count())
|
||||
return(false);
|
||||
return(set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a superset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsSupersetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_tree.Count()>=0);
|
||||
//--- check collection count
|
||||
if(collection.Count()==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return(ptr_set.IsSupersetOf(m_tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return(set.IsSupersetOf(m_tree));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a superset of the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsSupersetOf(T &array[])
|
||||
{
|
||||
//--- check array size
|
||||
if(ArraySize(array)==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return(set.IsSupersetOf(m_tree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the current set and a specified collection |
|
||||
//| share common elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::Overlaps(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(false);
|
||||
//--- check collection count
|
||||
if(collection.Count()==0)
|
||||
return(false);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return(ptr_set.Overlaps(m_tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return(set.Overlaps(m_tree));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the current set and a specified array share |
|
||||
//| common elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::Overlaps(T &array[])
|
||||
{
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(false);
|
||||
//--- check array size
|
||||
if(ArraySize(array)==0)
|
||||
return(false);
|
||||
//--- convert array to set
|
||||
CHashSet<T>set(array);
|
||||
return(set.Overlaps(m_tree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set and the specified collection contain the|
|
||||
//| same elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::SetEquals(ICollection<T>*collection)
|
||||
{
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- get array from collection
|
||||
T array[];
|
||||
collection.CopyTo(array);
|
||||
//--- check current set is equal specified array
|
||||
return SetEquals(array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set and the specified array contain the same|
|
||||
//| elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::SetEquals(T &array[])
|
||||
{
|
||||
//--- try find all elements in the tree
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
if(!m_tree.Contains(array[i]))
|
||||
return(false);
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copy a view of a subset in a CSortedSet<T> to array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::GetViewBetween(T &array[],T lower_value,T upper_value)
|
||||
{
|
||||
//--- get comparer
|
||||
IComparer<T>*comparer=m_tree.Comparer();
|
||||
if(comparer.Compare(lower_value,upper_value)>0)
|
||||
return(false);
|
||||
//--- copy all element from tree to array
|
||||
T buff[];
|
||||
int size=m_tree.CopyTo(buff);
|
||||
//--- check range
|
||||
if(size==0 || comparer.Compare(buff[0],upper_value)>0 || comparer.Compare(buff[size-1],lower_value)<0)
|
||||
return(false);
|
||||
//--- find first element greater than lower_value
|
||||
int index_lower=0;
|
||||
while(index_lower<size && comparer.Compare(buff[index_lower],lower_value)<0)
|
||||
index_lower++;
|
||||
//--- find first element less than upper_value
|
||||
int index_upper=size-1;
|
||||
while(index_upper>0 && comparer.Compare(buff[index_upper],upper_value)>0)
|
||||
index_upper--;
|
||||
//--- check indices
|
||||
if(index_lower>index_upper)
|
||||
return(false);
|
||||
//--- copy view between lower_value and upper_value to array
|
||||
return(ArrayCopy(array,buff,0,index_lower,index_upper-index_lower+1)>=0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copy the CSortedSet<T> in reverse order to array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::GetReverse(T &array[])
|
||||
{
|
||||
int size=m_tree.CopyTo(array);
|
||||
return ArrayReverse(array,0,size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,227 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Stack.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\ICollection.mqh>
|
||||
#include <Generic\Internal\ArrayFunction.mqh>
|
||||
#include <Generic\Internal\EqualFunction.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CStack<T>. |
|
||||
//| Usage: Represents a variable size last-in-first-out (LIFO) |
|
||||
//| collection of instances of the same specified type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CStack: public ICollection<T>
|
||||
{
|
||||
protected:
|
||||
T m_array[];
|
||||
int m_size;
|
||||
const int m_default_capacity;
|
||||
|
||||
public:
|
||||
CStack(void);
|
||||
CStack(const int capacity);
|
||||
CStack(ICollection<T>&collection[]);
|
||||
CStack(T &array[]);
|
||||
~CStack(void);
|
||||
//--- methods of filling data
|
||||
bool Add(T value);
|
||||
bool Push(T value);
|
||||
//--- methods of access to protected data
|
||||
int Count(void);
|
||||
bool Contains(T item);
|
||||
void TrimExcess(void);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(T &dst_array[],const int dst_start=0);
|
||||
//--- methods of cleaning and removing
|
||||
void Clear(void);
|
||||
bool Remove(T item);
|
||||
//--- methods of access to protected data
|
||||
T Peek(void);
|
||||
T Pop(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CStack<T> class that is empty |
|
||||
//| and has the default initial capacity. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CStack::CStack(void): m_default_capacity(4),
|
||||
m_size(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CStack<T> class that is empty |
|
||||
//| and has the specified initial capacity or the default initial |
|
||||
//| capacity, whichever is greater. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CStack::CStack(const int capacity): m_default_capacity(4),
|
||||
m_size(0)
|
||||
{
|
||||
ArrayResize(m_array,capacity);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CStack<T> class that contains |
|
||||
//| elements copied from the specified array and has sufficient |
|
||||
//| capacity to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CStack::CStack(T &array[]): m_default_capacity(4),
|
||||
m_size(0)
|
||||
{
|
||||
m_size=ArrayCopy(m_array,array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CStack<T> class that contains |
|
||||
//| elements copied from the specified collection and has sufficient |
|
||||
//| capacity to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CStack::CStack(ICollection<T>*collection): m_default_capacity(4),
|
||||
m_size(0)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)!=POINTER_INVALID)
|
||||
m_size=collection.CopyTo(m_array,0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CStack::~CStack(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserts an value at the top of the CStack<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CStack::Add(T value)
|
||||
{
|
||||
return Push(value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets the number of elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CStack::Count(void)
|
||||
{
|
||||
return(m_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all values from the CStack<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CStack::Contains(T item)
|
||||
{
|
||||
int count=m_size;
|
||||
//--- try to find item in array
|
||||
while(count-->0)
|
||||
{
|
||||
//--- use default equality function
|
||||
if(::Equals(m_array[count],item))
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the stack to a compatible |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CStack::CopyTo(T &dst_array[],const int dst_start=0)
|
||||
{
|
||||
//--- resize array
|
||||
if(dst_start+m_size>ArraySize(dst_array))
|
||||
ArrayResize(dst_array,dst_start+m_size);
|
||||
//--- start copy
|
||||
int src_index = m_size-1;
|
||||
int dst_index = dst_start;
|
||||
while(src_index>=0 && dst_index<ArraySize(dst_array))
|
||||
dst_array[dst_index++]=m_array[src_index--];
|
||||
return(dst_index-dst_start);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all values from the CStack<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CStack::Clear(void)
|
||||
{
|
||||
//--- check current size
|
||||
if(m_size>0)
|
||||
{
|
||||
ZeroMemory(m_array);
|
||||
m_size=0;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the first occurrence of a specific value from the stack. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CStack::Remove(T item)
|
||||
{
|
||||
//--- find index of item
|
||||
int index=ArrayIndexOf(m_array,item,0,m_size);
|
||||
//--- check index
|
||||
if(index==-1)
|
||||
return(false);
|
||||
//--- shift the values to the left
|
||||
ArrayCopy(m_array,m_array,index,index+1);
|
||||
//--- decrement size
|
||||
m_size--;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserts an values at the top of the CStack<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CStack::Push(T value)
|
||||
{
|
||||
int size=ArraySize(m_array);
|
||||
//--- check array size
|
||||
if(m_size==size)
|
||||
{
|
||||
//--- increase capacity
|
||||
if(size==0)
|
||||
ArrayResize(m_array,m_default_capacity);
|
||||
else
|
||||
ArrayResize(m_array,2*size);
|
||||
}
|
||||
//--- add value to the end
|
||||
m_array[m_size++]=value;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns the value at the top of the CStack<T> without removing. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
T CStack::Peek(void)
|
||||
{
|
||||
//--- return last value
|
||||
return(m_array[m_size-1]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes and returns the value at the top of the CStack<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
T CStack::Pop(void)
|
||||
{
|
||||
//--- return last value and decrement size
|
||||
T item=m_array[--m_size];
|
||||
return(item);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets the capacity to the actual number of elements in the |
|
||||
//| CStack<T>, if that number is less than 90 percent of current |
|
||||
//| capacity. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CStack::TrimExcess(void)
|
||||
{
|
||||
//--- calculate threshold value
|
||||
int threshold=(int)(((double)ArraySize(m_array)*0.9));
|
||||
//--- calculate resize array
|
||||
if(m_size<threshold)
|
||||
ArrayResize(m_array,m_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
@@ -0,0 +1,201 @@
|
||||
#include "String.mqh"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Структура для статистики торговли |
|
||||
//+------------------------------------------------------------------+
|
||||
struct ExpTradeSummarySingle
|
||||
{
|
||||
public:
|
||||
int Offset1[10];
|
||||
int bars;
|
||||
int ticks;
|
||||
STRING32 symbol;
|
||||
double initial_deposit; // начальный депозит
|
||||
double withdrawal; // снято средств
|
||||
double profit; // общая прибыль (+)
|
||||
double grossprofit; // общий плюс
|
||||
double grossloss; // общий минус
|
||||
double maxprofit; // максимально прибыльная сделка
|
||||
double minprofit; // максимально убыточная сделка
|
||||
double conprofitmax; // прибыль максимальной последовательности прибыльных сделок
|
||||
double maxconprofit; // максимальная прибыль среди последовательностей
|
||||
double conlossmax; // убыток максимальной последовательности убыточных сделок
|
||||
double maxconloss; // максимальный убыток среди последовательностей
|
||||
double balance_min; // минимальное значение баланса (для расчёта абсолютной просадки)
|
||||
double maxdrawdown; // максимальная просадка по балансу
|
||||
double drawdownpercent; // отношение максимальной просадки по балансу к её пику
|
||||
double reldrawdown; // максимальная относительная просадка по балансу в деньгах
|
||||
double reldrawdownpercent; // максимальная относительная просадка по балансу в процентах
|
||||
double equity_min; // минимальное значение equity (для расчёта абсолютной просадки по equity)
|
||||
double maxdrawdown_e; // максимальная просадка по equity
|
||||
double drawdownpercent_e; // отношение максимальной просадки по equity к её пику (+)
|
||||
double reldrawdown_e; // максимальная относительная просадка по equity в деньгах
|
||||
double reldrawdownpercnt_e; // максимальная относительная просадка по equity в процентах
|
||||
double expected_payoff; // матожидание выигрыша (+)
|
||||
double profit_factor; // показатель прибыльности (+)
|
||||
double recovery_factor; // фактор восстановления (+)
|
||||
double sharpe_ratio; // коэффициент Шарпа (+)
|
||||
double margin_level; // минимальный уровень маржи
|
||||
double custom_fitness; // пользовательский фитнесс - результат OnTester (+)
|
||||
int deals; // общее количество сделок
|
||||
int trades; // количество сделок out/inout
|
||||
int profittrades; // количество прибыльных
|
||||
int losstrades; // количество убыточных
|
||||
int shorttrades; // количество шортов
|
||||
int longtrades; // количество лонгов
|
||||
int winshorttrades; // количество прибыльных шортов
|
||||
int winlongtrades; // количество прибыльных лонгов
|
||||
int conprofitmax_trades; // максимальная последовательность прибыльных сделок
|
||||
int maxconprofit_trades; // последовательность максимальной прибыли
|
||||
int conlossmax_trades; // максимальная последовательность убыточных сделок
|
||||
int maxconloss_trades; // последовательность максимального убытка
|
||||
int avgconwinners; // среднее количество последовательных прибыльных сделок
|
||||
int avgconloosers; // среднее количество последовательных убыточных сделок
|
||||
|
||||
#define TOSTRING(A) #A + " = " + (string)(A) + "\n"
|
||||
#define TOSTRING3(A) #A + " = " + this.A[] + "\n"
|
||||
|
||||
string ToString( void ) const
|
||||
{
|
||||
return(
|
||||
TOSTRING(bars) +
|
||||
TOSTRING(ticks) +
|
||||
TOSTRING3(symbol) +
|
||||
TOSTRING(initial_deposit) + // начальный депозит
|
||||
TOSTRING(withdrawal) + // снято средств
|
||||
TOSTRING(profit) + // общая прибыль (+)
|
||||
TOSTRING(grossprofit) + // общий плюс
|
||||
TOSTRING(grossloss) + // общий минус
|
||||
TOSTRING(maxprofit) + // максимально прибыльная сделка
|
||||
TOSTRING(minprofit) + // максимально убыточная сделка
|
||||
TOSTRING(conprofitmax) + // прибыль максимальной последовательности прибыльных сделок
|
||||
TOSTRING(maxconprofit) + // максимальная прибыль среди последовательностей
|
||||
TOSTRING(conlossmax) + // убыток максимальной последовательности убыточных сделок
|
||||
TOSTRING(maxconloss) + // максимальный убыток среди последовательностей
|
||||
TOSTRING(balance_min) + // минимальное значение баланса (для расчёта абсолютной просадки)
|
||||
TOSTRING(maxdrawdown) + // максимальная просадка по балансу
|
||||
TOSTRING(drawdownpercent) + // отношение максимальной просадки по балансу к её пику
|
||||
TOSTRING(reldrawdown) + // максимальная относительная просадка по балансу в деньгах
|
||||
TOSTRING(reldrawdownpercent) + // максимальная относительная просадка по балансу в процентах
|
||||
TOSTRING(equity_min) + // минимальное значение equity (для расчёта абсолютной просадки по equity)
|
||||
TOSTRING(maxdrawdown_e) + // максимальная просадка по equity
|
||||
TOSTRING(drawdownpercent_e) + // отношение максимальной просадки по equity к её пику (+)
|
||||
TOSTRING(reldrawdown_e) + // максимальная относительная просадка по equity в деньгах
|
||||
TOSTRING(reldrawdownpercnt_e) + // максимальная относительная просадка по equity в процентах
|
||||
TOSTRING(expected_payoff) + // матожидание выигрыша (+)
|
||||
TOSTRING(profit_factor) + // показатель прибыльности (+)
|
||||
TOSTRING(recovery_factor) + // фактор восстановления (+)
|
||||
TOSTRING(sharpe_ratio) + // коэффициент Шарпа (+)
|
||||
TOSTRING(margin_level) + // минимальный уровень маржи
|
||||
TOSTRING(custom_fitness) + // пользовательский фитнесс - результат OnTester (+)
|
||||
TOSTRING(deals) + // общее количество сделок
|
||||
TOSTRING(trades) + // количество сделок out/inout
|
||||
TOSTRING(profittrades) + // количество прибыльных
|
||||
TOSTRING(losstrades) + // количество убыточных
|
||||
TOSTRING(shorttrades) + // количество шортов
|
||||
TOSTRING(longtrades) + // количество лонгов
|
||||
TOSTRING(winshorttrades) + // количество прибыльных шортов
|
||||
TOSTRING(winlongtrades) + // количество прибыльных лонгов
|
||||
TOSTRING(conprofitmax_trades) + // максимальная последовательность прибыльных сделок
|
||||
TOSTRING(maxconprofit_trades) + // последовательность максимальной прибыли
|
||||
TOSTRING(conlossmax_trades) + // максимальная последовательность убыточных сделок
|
||||
TOSTRING(maxconloss_trades) + // последовательность максимального убытка
|
||||
TOSTRING(avgconwinners) + // среднее количество последовательных прибыльных сделок
|
||||
TOSTRING(avgconloosers) // среднее количество последовательных убыточных сделок
|
||||
);
|
||||
}
|
||||
|
||||
#undef TOSTRING3
|
||||
#undef TOSTRING
|
||||
|
||||
double TesterStatistics( const ENUM_STATISTICS Statistic_ID ) const
|
||||
{
|
||||
switch (Statistic_ID)
|
||||
{
|
||||
case STAT_INITIAL_DEPOSIT:
|
||||
return(this.initial_deposit);
|
||||
case STAT_WITHDRAWAL:
|
||||
return(this.withdrawal);
|
||||
case STAT_PROFIT:
|
||||
return(this.profit);
|
||||
case STAT_GROSS_PROFIT:
|
||||
return(this.grossprofit);
|
||||
case STAT_GROSS_LOSS:
|
||||
return(-this.grossloss);
|
||||
case STAT_MAX_PROFITTRADE:
|
||||
return(this.maxprofit);
|
||||
case STAT_MAX_LOSSTRADE:
|
||||
return(-this.minprofit);
|
||||
case STAT_CONPROFITMAX:
|
||||
return(this.maxconprofit);
|
||||
case STAT_CONPROFITMAX_TRADES:
|
||||
return(this.maxconprofit_trades);
|
||||
case STAT_MAX_CONWINS:
|
||||
return(this.conprofitmax);
|
||||
case STAT_MAX_CONPROFIT_TRADES:
|
||||
return(this.conprofitmax_trades);
|
||||
case STAT_CONLOSSMAX:
|
||||
return(-this.conlossmax);
|
||||
case STAT_CONLOSSMAX_TRADES:
|
||||
return(this.conlossmax_trades);
|
||||
case STAT_MAX_CONLOSSES:
|
||||
return(-this.maxconloss);
|
||||
case STAT_MAX_CONLOSS_TRADES:
|
||||
return(this.maxconloss_trades);
|
||||
case STAT_BALANCEMIN:
|
||||
return(this.balance_min);
|
||||
case STAT_BALANCE_DD:
|
||||
return(this.maxdrawdown);
|
||||
case STAT_BALANCEDD_PERCENT:
|
||||
return(this.drawdownpercent);
|
||||
case STAT_BALANCE_DDREL_PERCENT:
|
||||
return(this.reldrawdownpercent);
|
||||
case STAT_BALANCE_DD_RELATIVE:
|
||||
return(this.reldrawdown);
|
||||
case STAT_EQUITYMIN:
|
||||
return(this.equity_min);
|
||||
case STAT_EQUITY_DD:
|
||||
return(this.maxdrawdown_e);
|
||||
case STAT_EQUITYDD_PERCENT:
|
||||
return(this.drawdownpercent_e);
|
||||
case STAT_EQUITY_DDREL_PERCENT:
|
||||
return(this.reldrawdownpercnt_e);
|
||||
case STAT_EQUITY_DD_RELATIVE:
|
||||
return(this.reldrawdown_e);
|
||||
case STAT_EXPECTED_PAYOFF:
|
||||
return(this.expected_payoff);
|
||||
case STAT_PROFIT_FACTOR:
|
||||
return(this.profit_factor);
|
||||
case STAT_RECOVERY_FACTOR:
|
||||
return(this.recovery_factor);
|
||||
case STAT_SHARPE_RATIO:
|
||||
return(this.sharpe_ratio);
|
||||
case STAT_MIN_MARGINLEVEL:
|
||||
return(this.margin_level);
|
||||
case STAT_CUSTOM_ONTESTER:
|
||||
return(this.custom_fitness);
|
||||
case STAT_DEALS:
|
||||
return(this.deals);
|
||||
case STAT_TRADES:
|
||||
return(this.trades);
|
||||
case STAT_PROFIT_TRADES:
|
||||
return(this.profittrades);
|
||||
case STAT_LOSS_TRADES:
|
||||
return(this.losstrades);
|
||||
case STAT_SHORT_TRADES:
|
||||
return(this.shorttrades);
|
||||
case STAT_LONG_TRADES:
|
||||
return(this.longtrades);
|
||||
case STAT_PROFIT_SHORTTRADES:
|
||||
return(this.winshorttrades);
|
||||
case STAT_PROFIT_LONGTRADES:
|
||||
return(this.winlongtrades);
|
||||
case STAT_PROFITTRADES_AVGCON:
|
||||
return(this.avgconwinners);
|
||||
case STAT_LOSSTRADES_AVGCON:
|
||||
return(this.avgconloosers);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
};
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,50 @@
|
||||
#ifndef __STRING__
|
||||
|
||||
#define __STRING__
|
||||
|
||||
#define NULL_CHAR (short)0xFFFF
|
||||
|
||||
#define DEFINE_STRING(A) \
|
||||
struct STRING##A \
|
||||
{ \
|
||||
public : \
|
||||
short Array[A]; \
|
||||
\
|
||||
public: \
|
||||
void operator =( const string &Str ) \
|
||||
{ \
|
||||
::ArrayInitialize(Array, 0); \
|
||||
this.Array[0] = NULL_CHAR; \
|
||||
::StringToShortArray(Str, this.Array); \
|
||||
\
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
template <typename T> \
|
||||
void operator =( const T &Str ) \
|
||||
{ \
|
||||
const string StrTmp = Str[]; \
|
||||
this = StrTmp; \
|
||||
\
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
string operator []( const int = 0 ) const \
|
||||
{ \
|
||||
return((this.Array[0] == NULL_CHAR) \
|
||||
? NULL : \
|
||||
::ShortArrayToString(this.Array)); \
|
||||
} \
|
||||
};
|
||||
|
||||
DEFINE_STRING(16)
|
||||
DEFINE_STRING(32)
|
||||
DEFINE_STRING(64)
|
||||
DEFINE_STRING(128)
|
||||
DEFINE_STRING(80)
|
||||
|
||||
#undef DEFINE_STRING
|
||||
|
||||
#undef NULL_CHAR
|
||||
|
||||
#endif // __STRING__
|
||||
@@ -0,0 +1,44 @@
|
||||
#define UINT64 ulong
|
||||
#define INT64 datetime
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Ñòðóêòóðà ðåçóëüòàòîâ äëÿ ïîçèöèè |
|
||||
//+------------------------------------------------------------------+
|
||||
struct TesterPositionProfit
|
||||
{
|
||||
private:
|
||||
string LengthToString( const datetime Length ) const
|
||||
{
|
||||
const int Days = (int)(Length / (24 * 3600));
|
||||
|
||||
return(((Days) ? (string)Days + "d ": "") + ::TimeToString(Length, TIME_SECONDS));
|
||||
}
|
||||
|
||||
public:
|
||||
UINT64 id; // id ïîçèöèè
|
||||
double mfe; // MFE
|
||||
double mae; // MAE
|
||||
double profit; // ïðèáûëü
|
||||
INT64 lifetime; // âðåìÿ æèçíè ïîçèöèè â ñåêóíäàõ
|
||||
UINT64 reserve[3];
|
||||
|
||||
#define TOSTRING(A) #A + " = " + (string)(this.A) + "\n"
|
||||
#define TOSTRING2(A) #A + " = " + this.LengthToString(A) + "\n"
|
||||
|
||||
string ToString( void ) const
|
||||
{
|
||||
return(
|
||||
TOSTRING(id) + // id ïîçèöèè
|
||||
TOSTRING(mfe) + // MFE
|
||||
TOSTRING(mae) + // MAE
|
||||
TOSTRING(profit) + // ïðèáûëü
|
||||
TOSTRING2(lifetime) // âðåìÿ æèçíè ïîçèöèè â ñåêóíäàõ
|
||||
);
|
||||
}
|
||||
|
||||
#undef TOSTRING2
|
||||
#undef TOSTRING
|
||||
};
|
||||
|
||||
#undef INT64
|
||||
#undef UINT64
|
||||
@@ -0,0 +1,29 @@
|
||||
#define __int64 datetime
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Ñòðóêòóðà äëÿ ãðàôèêà òåñòèðîâàíèÿ |
|
||||
//+------------------------------------------------------------------+
|
||||
struct TesterTradeState
|
||||
{
|
||||
// __int64 datetime; // òåêóùåå òåñòîâîå âðåìÿ
|
||||
__int64 time; // òåêóùåå òåñòîâîå âðåìÿ
|
||||
double balance; // òåêóùèé áàëàíñ
|
||||
double equity; // òåêóùèé equity
|
||||
double value; // òåêóùåå ðàññ÷èòàííîå çíà÷åíèå íàãðóçêè íà äåïîçèò
|
||||
|
||||
#define TOSTRING(A) #A + " = " + (string)(this.A) + "\n"
|
||||
|
||||
string ToString( void ) const
|
||||
{
|
||||
return(
|
||||
TOSTRING(time) + // òåêóùåå òåñòîâîå âðåìÿ
|
||||
TOSTRING(balance) + // òåêóùèé áàëàíñ
|
||||
TOSTRING(equity) + // òåêóùèé equity
|
||||
TOSTRING(value) // òåêóùåå ðàññ÷èòàííîå çíà÷åíèå íàãðóçêè íà äåïîçèò
|
||||
);
|
||||
}
|
||||
|
||||
#undef TOSTRING
|
||||
};
|
||||
|
||||
#undef __int64
|
||||
Binary file not shown.
@@ -0,0 +1,237 @@
|
||||
#include "String.mqh"
|
||||
|
||||
#define UINT64 ulong
|
||||
#define INT64 datetime
|
||||
#define UINT uint
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Ñòðóêòóðà òîðãîâîãî îðäåðà |
|
||||
//+------------------------------------------------------------------+
|
||||
struct TradeOrder
|
||||
{
|
||||
private:
|
||||
ENUM_ORDER_REASON ReasonToInteger( const ENUM_ORDER_REASON Reason ) const
|
||||
{
|
||||
int Res = 1;
|
||||
|
||||
switch (Reason)
|
||||
{
|
||||
case ORDER_REASON_SL:
|
||||
Res = 3;
|
||||
|
||||
break;
|
||||
case ORDER_REASON_TP:
|
||||
Res = 4;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return((ENUM_ORDER_REASON)Res);
|
||||
}
|
||||
|
||||
ENUM_ORDER_REASON IntegerToReason( const int Reason ) const
|
||||
{
|
||||
ENUM_ORDER_REASON Res = ORDER_REASON_CLIENT;
|
||||
|
||||
switch (Reason)
|
||||
{
|
||||
case 3:
|
||||
Res = ORDER_REASON_SL;
|
||||
|
||||
break;
|
||||
case 4:
|
||||
Res = ORDER_REASON_TP;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return((ENUM_ORDER_REASON)Res);
|
||||
}
|
||||
|
||||
public:
|
||||
UINT64 order; // óíèêàëüíûé èäåíòèôèêàòîð îðäåðà
|
||||
// wchar_t symbol[32]; // ñèìâîë ïî êîòîðîìó âûñòàâëåí îðäåð
|
||||
STRING32 symbol; // ñèìâîë ïî êîòîðîìó âûñòàâëåí îðäåð
|
||||
INT64 time_setup; // âðåìÿ ïðè¸ìà îðäåðà îò êëèåíòà â ñèñòåìó
|
||||
INT64 time_done; // âðåìÿ ñíÿòèÿ çàâêè
|
||||
ENUM_ORDER_TYPE type; // òèï îðäåðà
|
||||
ENUM_ORDER_REASON type_reason; // ïðè÷èíà ôîðìèðîâàíèÿ îðäåðà
|
||||
double price_order; // öåíà îðäåðà
|
||||
double price_trigger; // öåíà èñïîëíåíèÿ îðäåðà
|
||||
double price_sl; // öåíà SL â îðäåðå
|
||||
double price_tp; // öåíà TP â îðäåðå
|
||||
UINT64 volume_initial; // íà÷àëüíûé îáú¸ì çàÿâêè
|
||||
UINT64 volume_current; // òåêóùèé îáú¸ì çàÿâêè
|
||||
// wchar_t comment[32]; // êîììåíòàðèé ê îðäåðó
|
||||
STRING32 comment; // êîììåíòàðèé ê îðäåðó
|
||||
ENUM_ORDER_STATE state; // òåêóùåå ñîñòîÿíèå îðäåðà
|
||||
UINT digits; // êîëè÷åñòâî çíàêîâ ó òîðãîâîãî ñèìâîëà
|
||||
double contract_size; // ðàçìåð êîíòðàêòà
|
||||
|
||||
bool Set( const ulong Ticket )
|
||||
{
|
||||
const bool Res = (::HistoryOrderGetInteger(Ticket, ORDER_TICKET) == Ticket);
|
||||
|
||||
if (Res)
|
||||
{
|
||||
this.order = Ticket; // óíèêàëüíûé èäåíòèôèêàòîð îðäåðà
|
||||
|
||||
string Str = ::HistoryOrderGetString(Ticket, ORDER_SYMBOL);
|
||||
this.symbol = Str; // ñèìâîë ïî êîòîðîìó âûñòàâëåí îðäåð
|
||||
|
||||
this.contract_size = ::SymbolInfoDouble(Str, SYMBOL_TRADE_CONTRACT_SIZE); // ðàçìåð êîíòðàêòà
|
||||
this.digits = (UINT)::SymbolInfoInteger(Str, SYMBOL_DIGITS); // êîëè÷åñòâî çíàêîâ ó òîðãîâîãî ñèìâîëà
|
||||
|
||||
Str = ::HistoryOrderGetString(Ticket, ORDER_COMMENT);
|
||||
this.comment = Str; // êîììåíòàðèé ê îðäåðó
|
||||
|
||||
this.time_setup = (INT64)::HistoryOrderGetInteger(Ticket, ORDER_TIME_SETUP); // âðåìÿ ïðè¸ìà îðäåðà îò êëèåíòà â ñèñòåìó
|
||||
this.time_done = (INT64)::HistoryOrderGetInteger(Ticket, ORDER_TIME_DONE); // âðåìÿ ñíÿòèÿ çàâêè
|
||||
|
||||
this.type = (ENUM_ORDER_TYPE)::HistoryOrderGetInteger(Ticket, ORDER_TYPE); // òèï îðäåðà
|
||||
this.type_reason = this.ReasonToInteger((ENUM_ORDER_REASON)::HistoryOrderGetInteger(Ticket, ORDER_REASON)); // ïðè÷èíà ôîðìèðîâàíèÿ îðäåðà
|
||||
this.state = (ENUM_ORDER_STATE)::HistoryOrderGetInteger(Ticket, ORDER_STATE); // òåêóùåå ñîñòîÿíèå îðäåðà
|
||||
|
||||
this.price_order = ::HistoryOrderGetDouble(Ticket, ORDER_PRICE_OPEN); // öåíà îðäåðà
|
||||
this.price_trigger = 0; // öåíà èñïîëíåíèÿ îðäåðà
|
||||
this.price_sl = ::HistoryOrderGetDouble(Ticket, ORDER_SL); // öåíà SL â îðäåðå
|
||||
this.price_tp = ::HistoryOrderGetDouble(Ticket, ORDER_TP); // öåíà TP â îðäåðå
|
||||
|
||||
this.volume_initial = (UINT64)(::HistoryOrderGetDouble(Ticket, ORDER_VOLUME_INITIAL) * this.contract_size * 1000 + 0.1); // íà÷àëüíûé îáú¸ì çàÿâêè
|
||||
this.volume_current = (UINT64)(::HistoryOrderGetDouble(Ticket, ORDER_VOLUME_CURRENT) * this.contract_size * 1000 + 0.1); // òåêóùèé îáú¸ì çàÿâêè
|
||||
}
|
||||
|
||||
return(Res);
|
||||
}
|
||||
|
||||
long GetProperty( const ENUM_ORDER_PROPERTY_INTEGER Property ) const
|
||||
{
|
||||
long Res = 0;
|
||||
|
||||
switch (Property)
|
||||
{
|
||||
case ORDER_TICKET:
|
||||
Res = (long)this.order;
|
||||
|
||||
break;
|
||||
case ORDER_TIME_SETUP:
|
||||
Res = this.time_setup;
|
||||
|
||||
break;
|
||||
case ORDER_TYPE:
|
||||
Res = this.type;
|
||||
|
||||
break;
|
||||
case ORDER_STATE:
|
||||
Res = this.state;
|
||||
|
||||
break;
|
||||
case ORDER_TIME_DONE:
|
||||
Res = this.time_done;
|
||||
|
||||
break;
|
||||
case ORDER_TIME_SETUP_MSC:
|
||||
Res = (long)this.time_setup * 1000;
|
||||
|
||||
break;
|
||||
case ORDER_TIME_DONE_MSC:
|
||||
Res = (long)this.time_done * 1000;
|
||||
|
||||
break;
|
||||
case ORDER_REASON:
|
||||
Res = this.IntegerToReason(this.type_reason);
|
||||
|
||||
break;
|
||||
case ORDER_POSITION_ID:
|
||||
Res = (long)this.order;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return(Res);
|
||||
}
|
||||
|
||||
double GetProperty( const ENUM_ORDER_PROPERTY_DOUBLE Property ) const
|
||||
{
|
||||
double Res = 0;
|
||||
|
||||
switch (Property)
|
||||
{
|
||||
case ORDER_VOLUME_INITIAL:
|
||||
Res = (double)this.volume_initial / (this.contract_size ? this.contract_size * 1000 : 1e8);
|
||||
|
||||
break;
|
||||
case ORDER_VOLUME_CURRENT:
|
||||
Res = (double)this.volume_current / (this.contract_size ? this.contract_size * 1000 : 1e8);
|
||||
|
||||
break;
|
||||
case ORDER_PRICE_OPEN:
|
||||
Res = this.price_order;
|
||||
|
||||
break;
|
||||
case ORDER_SL:
|
||||
Res = this.price_sl;
|
||||
|
||||
break;
|
||||
case ORDER_TP:
|
||||
Res = this.price_tp;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return(Res);
|
||||
}
|
||||
|
||||
string GetProperty( const ENUM_ORDER_PROPERTY_STRING Property ) const
|
||||
{
|
||||
string Res = NULL;
|
||||
|
||||
switch (Property)
|
||||
{
|
||||
case ORDER_SYMBOL:
|
||||
Res = this.symbol[];
|
||||
|
||||
break;
|
||||
case ORDER_COMMENT:
|
||||
Res = this.comment[];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return(Res);
|
||||
}
|
||||
|
||||
#define TOSTRING(A) #A + " = " + (string)(this.A) + "\n"
|
||||
#define TOSTRING2(A) #A + " = " + ::EnumToString(this.A) + " (" + (string)(this.A) + ")\n"
|
||||
#define TOSTRING3(A) #A + " = " + this.A[] + "\n"
|
||||
|
||||
string ToString( void ) const
|
||||
{
|
||||
return(
|
||||
TOSTRING(order) + // óíèêàëüíûé èäåíòèôèêàòîð îðäåðà
|
||||
TOSTRING3(symbol) + // ñèìâîë ïî êîòîðîìó âûñòàâëåí îðäåð
|
||||
TOSTRING(time_setup) + // âðåìÿ ïðè¸ìà îðäåðà îò êëèåíòà â ñèñòåìó
|
||||
TOSTRING(time_done) + // âðåìÿ ñíÿòèÿ çàâêè
|
||||
TOSTRING2(type) + // òèï îðäåðà
|
||||
TOSTRING2(type_reason) + // ïðè÷èíà ôîðìèðîâàíèÿ îðäåðà
|
||||
TOSTRING(price_order) + // öåíà îðäåðà
|
||||
TOSTRING(price_trigger) + // öåíà èñïîëíåíèÿ îðäåðà
|
||||
TOSTRING(price_sl) + // öåíà SL â îðäåðå
|
||||
TOSTRING(price_tp) + // öåíà TP â îðäåðå
|
||||
TOSTRING(volume_initial) + // íà÷àëüíûé îáú¸ì çàÿâêè
|
||||
TOSTRING(volume_current) + // òåêóùèé îáú¸ì çàÿâêè
|
||||
TOSTRING3(comment) + // êîììåíòàðèé ê îðäåðó
|
||||
TOSTRING2(state) + // òåêóùåå ñîñòîÿíèå îðäåðà
|
||||
TOSTRING(digits) + // êîëè÷åñòâî çíàêîâ ó òîðãîâîãî ñèìâîëà
|
||||
TOSTRING(contract_size) // ðàçìåð êîíòðàêòà
|
||||
);
|
||||
}
|
||||
|
||||
#undef TOSTRING3
|
||||
#undef TOSTRING2
|
||||
#undef TOSTRING
|
||||
};
|
||||
|
||||
#undef UINT
|
||||
#undef INT64
|
||||
#undef UINT64
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user